From 823b4f22d268f1c2c0c8de581e7f2fb03981cb9a Mon Sep 17 00:00:00 2001 From: portersky Date: Sat, 29 Aug 2026 15:04:46 +0200 Subject: [PATCH] fix: square, grid-aligned D-pad and face buttons Give both clusters a shared 100x100 footprint so they align on the same grid: D-pad cells are now square (30x30 with 5pt gaps) and the ABXY diamond is positioned on its diagonals instead of stacked rows. Drops the height-matching frame hack from the card layout. Co-Authored-By: qwen3.8-27b@q3_k_xl: squared and aligned the clusters --- CMakeLists.txt | 2 +- src/app/ControllerCardView.swift | 2 -- src/app/GamepadViews.swift | 43 ++++++++++++++++++-------------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f363891..9dd094f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if(NOT CMAKE_GENERATOR MATCHES "^(Ninja|Xcode)$") endif() cmake_minimum_required(VERSION 3.21) -project(xone_macos VERSION 0.1.23 LANGUAGES CXX Swift) +project(xone_macos VERSION 0.1.24 LANGUAGES CXX Swift) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/src/app/ControllerCardView.swift b/src/app/ControllerCardView.swift index 7927404..0ce2540 100644 --- a/src/app/ControllerCardView.swift +++ b/src/app/ControllerCardView.swift @@ -63,7 +63,6 @@ struct ControllerCardView: View { StickPadView(label: "L", x: controller.stickLeftX, y: controller.stickLeftY, pressed: controller.isPressed(.leftStick)) DPadView(controller: controller) - .frame(height: 104) } .frame(maxWidth: .infinity) @@ -79,7 +78,6 @@ struct ControllerCardView: View { StickPadView(label: "R", x: controller.stickRightX, y: controller.stickRightY, pressed: controller.isPressed(.rightStick)) FaceButtonsView(controller: controller) - .frame(height: 104) } .frame(maxWidth: .infinity) } diff --git a/src/app/GamepadViews.swift b/src/app/GamepadViews.swift index 4c69c2b..90f894b 100644 --- a/src/app/GamepadViews.swift +++ b/src/app/GamepadViews.swift @@ -4,28 +4,34 @@ import SwiftUI // buttons on top, stick pads and triggers below, mirroring the physical // layout of an Xbox controller. +// Both clusters (D-pad and face buttons) share a 100x100 footprint so they +// align on the same grid in the card layout. + struct DPadView: View { let controller: ControllerInput + private let cell: CGFloat = 30 + private let gap: CGFloat = 5 + var body: some View { - VStack(spacing: 3) { - cell(.dPadUp) - HStack(spacing: 3) { - cell(.dPadLeft) - RoundedRectangle(cornerRadius: 5) + VStack(spacing: gap) { + cellView(.dPadUp) + HStack(spacing: gap) { + cellView(.dPadLeft) + RoundedRectangle(cornerRadius: 6) .fill(Color.secondary.opacity(0.28)) - .frame(width: 30, height: 26) - cell(.dPadRight) + .frame(width: cell, height: cell) + cellView(.dPadRight) } - cell(.dPadDown) + cellView(.dPadDown) } } - private func cell(_ button: XboxButton) -> some View { + private func cellView(_ button: XboxButton) -> some View { let pressed = controller.isPressed(button) - return RoundedRectangle(cornerRadius: 5) + return RoundedRectangle(cornerRadius: 6) .fill(pressed ? Color.green : Color.secondary.opacity(0.18)) - .frame(width: 30, height: 26) + .frame(width: cell, height: cell) .overlay( Image(systemName: button.dPadSymbol ?? "") .font(.system(size: 9)) @@ -38,21 +44,20 @@ struct FaceButtonsView: View { let controller: ControllerInput var body: some View { - VStack(spacing: 4) { - faceButton(.y) - HStack(spacing: 10) { - faceButton(.x) - faceButton(.b) - } - faceButton(.a) + ZStack { + faceButton(.y).offset(y: -35) + faceButton(.x).offset(x: -35) + faceButton(.b).offset(x: 35) + faceButton(.a).offset(y: 35) } + .frame(width: 100, height: 100) } private func faceButton(_ button: XboxButton) -> some View { let pressed = controller.isPressed(button) return Text(button.label) .font(.callout.weight(.semibold)) - .frame(width: 32, height: 32) + .frame(width: 30, height: 30) .background(Circle().fill(pressed ? Color.green : Color.secondary.opacity(0.18))) .foregroundStyle(pressed ? .white : .primary) }