fix: match controller card to Xbox layout
Realign the card to the physical controller face: trigger bars and bumper chips in the top corners, sticks side by side in the upper center (stick clicks light up their rings instead of separate chips), D-pad lower left, face buttons lower right, and the Guide button centered between the clusters flanked by Select and Start. Co-Authored-By: qwen3.8-27b@q3_k_xl: realigned card to Xbox layout
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ if(NOT CMAKE_GENERATOR MATCHES "^(Ninja|Xcode)$")
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
project(xone_macos VERSION 0.1.21 LANGUAGES CXX Swift)
|
||||
project(xone_macos VERSION 0.1.22 LANGUAGES CXX Swift)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import SwiftUI
|
||||
|
||||
// Card for one connected controller. The layout mirrors the physical Xbox
|
||||
// controller face: shoulders (triggers + bumpers) along the top, sticks side
|
||||
// by side below them, D-pad lower left, face buttons lower right, and the
|
||||
// Guide button centered between the two clusters flanked by Select and Start.
|
||||
|
||||
struct ControllerCardView: View {
|
||||
let controller: ControllerInput
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
VStack(alignment: .leading, spacing: 14) {
|
||||
header
|
||||
HStack(spacing: 28) {
|
||||
DPadView(controller: controller)
|
||||
FaceButtonsView(controller: controller)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
sticksAndTriggers
|
||||
systemButtons
|
||||
shoulders
|
||||
sticks
|
||||
clusters
|
||||
footer
|
||||
}
|
||||
.padding(14)
|
||||
@@ -34,27 +35,45 @@ struct ControllerCardView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var sticksAndTriggers: some View {
|
||||
HStack(alignment: .top, spacing: 12) {
|
||||
StickPadView(label: "L", x: controller.stickLeftX, y: controller.stickLeftY)
|
||||
Spacer()
|
||||
// Shoulder area: trigger bar above its bumper, in each top corner.
|
||||
private var shoulders: some View {
|
||||
HStack(alignment: .top) {
|
||||
VStack(spacing: 5) {
|
||||
TriggerBarView(label: "LT", value: controller.triggerLeft)
|
||||
TriggerBarView(label: "RT", value: controller.triggerRight)
|
||||
ButtonChip(button: .leftBumper, pressed: controller.isPressed(.leftBumper))
|
||||
}
|
||||
Spacer()
|
||||
StickPadView(label: "R", x: controller.stickRightX, y: controller.stickRightY)
|
||||
VStack(spacing: 5) {
|
||||
TriggerBarView(label: "RT", value: controller.triggerRight)
|
||||
ButtonChip(button: .rightBumper, pressed: controller.isPressed(.rightBumper))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var systemButtons: some View {
|
||||
HStack(spacing: 6) {
|
||||
ButtonChip(button: .guide, pressed: controller.guideDown)
|
||||
ButtonChip(button: .start, pressed: controller.isPressed(.start))
|
||||
ButtonChip(button: .select, pressed: controller.isPressed(.select))
|
||||
// Sticks sit side by side in the upper center of the face. A stick click
|
||||
// (LS/RS) lights up its ring.
|
||||
private var sticks: some View {
|
||||
HStack(spacing: 48) {
|
||||
StickPadView(label: "L", x: controller.stickLeftX, y: controller.stickLeftY,
|
||||
pressed: controller.isPressed(.leftStick))
|
||||
StickPadView(label: "R", x: controller.stickRightX, y: controller.stickRightY,
|
||||
pressed: controller.isPressed(.rightStick))
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
// Lower clusters with the system buttons centered between them.
|
||||
private var clusters: some View {
|
||||
HStack(alignment: .center, spacing: 12) {
|
||||
DPadView(controller: controller)
|
||||
Spacer()
|
||||
ButtonChip(button: .leftBumper, pressed: controller.isPressed(.leftBumper))
|
||||
ButtonChip(button: .rightBumper, pressed: controller.isPressed(.rightBumper))
|
||||
ButtonChip(button: .leftStick, pressed: controller.isPressed(.leftStick))
|
||||
ButtonChip(button: .rightStick, pressed: controller.isPressed(.rightStick))
|
||||
HStack(spacing: 10) {
|
||||
ButtonChip(button: .select, pressed: controller.isPressed(.select))
|
||||
GuideButtonView(pressed: controller.guideDown)
|
||||
ButtonChip(button: .start, pressed: controller.isPressed(.start))
|
||||
}
|
||||
Spacer()
|
||||
FaceButtonsView(controller: controller)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ struct StickPadView: View {
|
||||
let label: String
|
||||
let x: Int16
|
||||
let y: Int16
|
||||
// True while the stick is clicked in (LS/RS).
|
||||
var pressed = false
|
||||
|
||||
private let diameter: CGFloat = 64
|
||||
|
||||
@@ -71,8 +73,9 @@ struct StickPadView: View {
|
||||
Circle()
|
||||
.fill(Color.secondary.opacity(0.15))
|
||||
Circle()
|
||||
.stroke(Color.secondary.opacity(0.35), lineWidth: 1)
|
||||
.padding(6)
|
||||
.stroke(pressed ? Color.green : Color.secondary.opacity(0.35),
|
||||
lineWidth: pressed ? 2.5 : 1)
|
||||
.padding(4)
|
||||
Circle()
|
||||
.fill(Color.accentColor)
|
||||
.frame(width: 12, height: 12)
|
||||
@@ -122,6 +125,27 @@ struct TriggerBarView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// The large Guide button, centered between the D-pad and face buttons.
|
||||
struct GuideButtonView: View {
|
||||
let pressed: Bool
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 4) {
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(pressed ? Color.green : Color.secondary.opacity(0.25))
|
||||
Image(systemName: "gamecontroller.fill")
|
||||
.font(.system(size: 14))
|
||||
.foregroundStyle(pressed ? .white : .secondary)
|
||||
}
|
||||
.frame(width: 36, height: 36)
|
||||
Text("Guide")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ButtonChip: View {
|
||||
let button: XboxButton
|
||||
let pressed: Bool
|
||||
|
||||
Reference in New Issue
Block a user