Skip to content

Commit 97f9494

Browse files
committed
Polish iOS layout editor controls
- Replace crowded text-heavy toolbar with a compact icon-based toolbar: Cancel (xmark.circle), Undo (arrow.uturn.backward.circle, disabled when empty), Portrait/Landscape picker, Skin picker (paintpalette), Options menu (ellipsis), Save (checkmark.circle). - Remove the permanent horizontal visibility scroll row and reset button row from the canvas. Move both into a compact Options menu with two sections: Visibility (group + per-button action toggles) and Reset (Action, D-Pad, All, Visibility). Each option still pushes an undo snapshot before mutation. - Skin picker remains a separate compact menu. Selected skin checkmark is still shown. Changing skin updates editor button art immediately. - Toolbar background is black at 50% opacity to stay readable over the game. - No gameplay, layout, or touch target behavior changed. Phase 1 and 2A logic is preserved.
1 parent 3084282 commit 97f9494

1 file changed

Lines changed: 74 additions & 125 deletions

File tree

app/src/main/swift/Views/Settings/PadLayoutEditView.swift

Lines changed: 74 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,8 @@ struct PadLayoutEditView: View {
7777
editorContent(areaW: geo.size.width, areaH: geo.size.height)
7878

7979
VStack {
80-
floatingToolbar
80+
compactToolbar
8181
Spacer()
82-
visibilityRow
83-
resetButtons(isLandscape: true)
8482
}
8583
}
8684
.contentShape(Rectangle())
@@ -102,7 +100,7 @@ struct PadLayoutEditView: View {
102100
}
103101

104102
VStack {
105-
floatingToolbar
103+
compactToolbar
106104
Spacer()
107105
}
108106
}
@@ -134,102 +132,76 @@ struct PadLayoutEditView: View {
134132
}
135133

136134
VStack {
137-
HStack {
138-
Button("Cancel") {
139-
if let snapshot = originalSnapshot {
140-
restore(snapshot: snapshot)
141-
}
142-
onDismiss()
143-
}
144-
.padding(8)
145-
.background(.black.opacity(0.5), in: Capsule())
146-
Spacer()
147-
Button("Undo") {
148-
guard let snapshot = undoStack.popLast() else { return }
149-
restore(snapshot: snapshot)
150-
}
151-
.disabled(undoStack.isEmpty)
152-
.font(.caption.weight(.semibold))
153-
.padding(.horizontal, 10)
154-
.padding(.vertical, 6)
155-
.background(.black.opacity(0.5), in: Capsule())
156-
Spacer()
157-
Picker("", selection: $editLandscape) {
158-
Text("Portrait").tag(false)
159-
Text("Landscape").tag(true)
160-
}
161-
.pickerStyle(.segmented)
162-
.frame(width: 168)
163-
.background(.black.opacity(0.3), in: RoundedRectangle(cornerRadius: 8))
164-
Spacer()
165-
skinPickerMenu
166-
Spacer()
167-
Button("Save") {
168-
NSLog("@@PAD_LAYOUT@@ save portrait=%d landscape=%d", layout.portrait.count, layout.landscape.count)
169-
layout.save()
170-
undoStack.removeAll()
171-
originalSnapshot = nil
172-
onDismiss()
173-
}
174-
.fontWeight(.semibold)
175-
.padding(8)
176-
.background(.black.opacity(0.5), in: Capsule())
177-
}
178-
.padding(.horizontal)
179-
.padding(.top, 4)
135+
compactToolbar
180136
Spacer()
181-
visibilityRow
182-
resetButtons(isLandscape: false)
183137
}
184138
}
185139
.contentShape(Rectangle())
186140
}
187141
}
188142

189-
private var floatingToolbar: some View {
190-
HStack {
191-
Button("Cancel") {
143+
// MARK: - Compact toolbar
144+
private var compactToolbar: some View {
145+
HStack(spacing: 12) {
146+
// Cancel
147+
Button {
192148
if let snapshot = originalSnapshot {
193149
restore(snapshot: snapshot)
194150
}
195151
onDismiss()
152+
} label: {
153+
Image(systemName: "xmark.circle.fill")
154+
.font(.title2)
155+
.foregroundStyle(.white)
196156
}
197-
.padding(8)
198-
.background(.black.opacity(0.5), in: Capsule())
199-
Spacer()
200-
Button("Undo") {
157+
158+
// Undo
159+
Button {
201160
guard let snapshot = undoStack.popLast() else { return }
202161
restore(snapshot: snapshot)
162+
} label: {
163+
Image(systemName: "arrow.uturn.backward.circle")
164+
.font(.title2)
165+
.foregroundStyle(undoStack.isEmpty ? .white.opacity(0.3) : .white)
203166
}
204167
.disabled(undoStack.isEmpty)
205-
.font(.caption.weight(.semibold))
206-
.padding(.horizontal, 10)
207-
.padding(.vertical, 6)
208-
.background(.black.opacity(0.5), in: Capsule())
168+
209169
Spacer()
170+
171+
// Portrait / Landscape
210172
Picker("", selection: $editLandscape) {
211173
Text("Portrait").tag(false)
212174
Text("Landscape").tag(true)
213175
}
214176
.pickerStyle(.segmented)
215-
.frame(width: 168)
177+
.frame(width: 140)
216178
.background(.black.opacity(0.3), in: RoundedRectangle(cornerRadius: 8))
179+
217180
Spacer()
181+
182+
// Skin picker
218183
skinPickerMenu
219-
Spacer()
220-
Button("Save") {
184+
185+
// Options (visibility + reset)
186+
optionsMenu
187+
188+
// Save
189+
Button {
221190
NSLog("@@PAD_LAYOUT@@ save portrait=%d landscape=%d", layout.portrait.count, layout.landscape.count)
222191
layout.save()
223192
undoStack.removeAll()
224193
originalSnapshot = nil
225194
onDismiss()
195+
} label: {
196+
Image(systemName: "checkmark.circle.fill")
197+
.font(.title2)
198+
.foregroundStyle(.green)
226199
}
227-
.fontWeight(.semibold)
228-
.padding(8)
229-
.background(.black.opacity(0.5), in: Capsule())
230200
}
231201
.padding(.horizontal)
232202
.padding(.top, 4)
203+
.padding(.bottom, 8)
204+
.background(.black.opacity(0.5))
233205
}
234206

235207
private var skinPickerMenu: some View {
@@ -243,81 +215,58 @@ struct PadLayoutEditView: View {
243215
}
244216
} label: {
245217
Image(systemName: "paintpalette.fill")
246-
.font(.callout)
218+
.font(.title2)
247219
.foregroundStyle(.white)
248-
.frame(width: 34, height: 34)
249-
.background(.black.opacity(0.5), in: Circle())
250220
}
251221
}
252222

253-
private func resetButtons(isLandscape: Bool) -> some View {
254-
HStack(spacing: 12) {
255-
Button("Reset Action") {
256-
pushSnapshot()
257-
layout.resetPerButtonActionButtons(isLandscape: isLandscape)
258-
}
259-
.font(.caption)
260-
.foregroundStyle(.red.opacity(0.7))
261-
262-
Button("Reset D-Pad") {
263-
pushSnapshot()
264-
layout.resetPerButtonDPad(isLandscape: isLandscape)
265-
}
266-
.font(.caption)
267-
.foregroundStyle(.red.opacity(0.7))
268-
269-
Button("Reset All") {
270-
pushSnapshot()
271-
layout.resetAll()
223+
private var optionsMenu: some View {
224+
Menu {
225+
// Visibility section
226+
Section("Visibility") {
227+
ForEach(PadLayoutStore.groupIDs.filter { $0 != "action" }, id: \.self) { (id: String) in
228+
visibilityMenuItem(id: id)
229+
}
230+
visibilityMenuItem(id: "cross", label: "X")
231+
visibilityMenuItem(id: "circle", label: "O")
232+
visibilityMenuItem(id: "triangle", label: "Triangle")
233+
visibilityMenuItem(id: "square", label: "Square")
272234
}
273-
.font(.caption)
274-
.foregroundStyle(.red.opacity(0.7))
275235

276-
Button("Reset Visibility") {
277-
pushSnapshot()
278-
layout.resetControlVisibility()
279-
}
280-
.font(.caption)
281-
.foregroundStyle(.red.opacity(0.7))
282-
}
283-
.padding(.bottom, 6)
284-
}
285-
286-
private var visibilityRow: some View {
287-
ScrollView(.horizontal, showsIndicators: false) {
288-
HStack(spacing: 10) {
289-
// Group toggles (excluding the combined action group)
290-
ForEach(PadLayoutStore.groupIDs.filter { $0 != "action" }, id: \.self) { (id: String) in
291-
visibilityButton(id: id)
236+
// Reset section
237+
Section("Reset") {
238+
Button("Reset Action", role: .destructive) {
239+
pushSnapshot()
240+
layout.resetPerButtonActionButtons(isLandscape: editLandscape)
241+
}
242+
Button("Reset D-Pad", role: .destructive) {
243+
pushSnapshot()
244+
layout.resetPerButtonDPad(isLandscape: editLandscape)
245+
}
246+
Button("Reset All", role: .destructive) {
247+
pushSnapshot()
248+
layout.resetAll()
249+
}
250+
Button("Reset Visibility", role: .destructive) {
251+
pushSnapshot()
252+
layout.resetControlVisibility()
292253
}
293-
// Per-button action toggles
294-
visibilityButton(id: "cross", label: "Toggle: X")
295-
visibilityButton(id: "circle", label: "Toggle: O")
296-
visibilityButton(id: "triangle", label: "Toggle: Triangle")
297-
visibilityButton(id: "square", label: "Toggle: Square")
298254
}
299-
.padding(.horizontal, 12)
255+
} label: {
256+
Image(systemName: "ellipsis.circle")
257+
.font(.title2)
258+
.foregroundStyle(.white)
300259
}
301-
.frame(height: 32)
302-
.padding(.bottom, 4)
303260
}
304261

305-
private func visibilityButton(id: String, label: String? = nil) -> some View {
262+
private func visibilityMenuItem(id: String, label: String? = nil) -> some View {
306263
let visible = layout.isControlVisible(id)
307264
return Button {
308265
pushSnapshot()
309266
layout.setControlVisible(id, visible: !visible)
310267
} label: {
311-
HStack(spacing: 4) {
312-
Image(systemName: visible ? "eye" : "eye.slash")
313-
.font(.caption2)
314-
Text(label ?? id.uppercased())
315-
.font(.caption2.weight(.semibold))
316-
}
317-
.foregroundStyle(visible ? Color.primary : Color.red)
318-
.padding(.horizontal, 8)
319-
.padding(.vertical, 4)
320-
.background(visible ? Color.white.opacity(0.08) : Color.red.opacity(0.12), in: Capsule())
268+
let name = label ?? id.uppercased()
269+
Label(name, systemImage: visible ? "eye" : "eye.slash")
321270
}
322271
}
323272

0 commit comments

Comments
 (0)