fix: compact, aligned controller face layout
Group each stick above its cluster (L over D-pad, R over face buttons) in equal-height columns so the rows line up, cap the face at a natural controller proportion so wide cards do not stretch it, and replace the Select/Start chips with small round icon buttons flanking the centered Guide button. Co-Authored-By: qwen3.8-27b@q3_k_xl: compacted and aligned the face
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ if(NOT CMAKE_GENERATOR MATCHES "^(Ninja|Xcode)$")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.21)
|
cmake_minimum_required(VERSION 3.21)
|
||||||
project(xone_macos VERSION 0.1.22 LANGUAGES CXX Swift)
|
project(xone_macos VERSION 0.1.23 LANGUAGES CXX Swift)
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
// Card for one connected controller. The layout mirrors the physical Xbox
|
// Card for one connected controller. The face mirrors the physical Xbox
|
||||||
// controller face: shoulders (triggers + bumpers) along the top, sticks side
|
// controller: shoulders (triggers + bumpers) along the top, left stick above
|
||||||
// by side below them, D-pad lower left, face buttons lower right, and the
|
// the D-pad, right stick above the face buttons, and the Guide button
|
||||||
// Guide button centered between the two clusters flanked by Select and Start.
|
// centered between the two columns flanked by Select and Start. The face is
|
||||||
|
// capped at a natural controller proportion so wide cards do not stretch it.
|
||||||
|
|
||||||
struct ControllerCardView: View {
|
struct ControllerCardView: View {
|
||||||
let controller: ControllerInput
|
let controller: ControllerInput
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 14) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
header
|
header
|
||||||
shoulders
|
VStack(spacing: 12) {
|
||||||
sticks
|
shoulders
|
||||||
clusters
|
face
|
||||||
|
}
|
||||||
|
.frame(maxWidth: 420)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
footer
|
footer
|
||||||
}
|
}
|
||||||
.padding(14)
|
.padding(14)
|
||||||
@@ -50,30 +54,34 @@ struct ControllerCardView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sticks sit side by side in the upper center of the face. A stick click
|
// The face: two equal-width columns (stick over cluster) with the system
|
||||||
// (LS/RS) lights up its ring.
|
// buttons centered between them. Both columns are the same height, so
|
||||||
private var sticks: some View {
|
// sticks line up and clusters line up.
|
||||||
HStack(spacing: 48) {
|
private var face: some View {
|
||||||
StickPadView(label: "L", x: controller.stickLeftX, y: controller.stickLeftY,
|
HStack(alignment: .center, spacing: 0) {
|
||||||
pressed: controller.isPressed(.leftStick))
|
VStack(spacing: 12) {
|
||||||
StickPadView(label: "R", x: controller.stickRightX, y: controller.stickRightY,
|
StickPadView(label: "L", x: controller.stickLeftX, y: controller.stickLeftY,
|
||||||
pressed: controller.isPressed(.rightStick))
|
pressed: controller.isPressed(.leftStick))
|
||||||
}
|
DPadView(controller: controller)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(height: 104)
|
||||||
}
|
|
||||||
|
|
||||||
// Lower clusters with the system buttons centered between them.
|
|
||||||
private var clusters: some View {
|
|
||||||
HStack(alignment: .center, spacing: 12) {
|
|
||||||
DPadView(controller: controller)
|
|
||||||
Spacer()
|
|
||||||
HStack(spacing: 10) {
|
|
||||||
ButtonChip(button: .select, pressed: controller.isPressed(.select))
|
|
||||||
GuideButtonView(pressed: controller.guideDown)
|
|
||||||
ButtonChip(button: .start, pressed: controller.isPressed(.start))
|
|
||||||
}
|
}
|
||||||
Spacer()
|
.frame(maxWidth: .infinity)
|
||||||
FaceButtonsView(controller: controller)
|
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
SystemButtonView(button: .select, symbol: "square.on.square",
|
||||||
|
pressed: controller.isPressed(.select))
|
||||||
|
GuideButtonView(pressed: controller.guideDown)
|
||||||
|
SystemButtonView(button: .start, symbol: "line.3.horizontal",
|
||||||
|
pressed: controller.isPressed(.start))
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(spacing: 12) {
|
||||||
|
StickPadView(label: "R", x: controller.stickRightX, y: controller.stickRightY,
|
||||||
|
pressed: controller.isPressed(.rightStick))
|
||||||
|
FaceButtonsView(controller: controller)
|
||||||
|
.frame(height: 104)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,29 @@ struct TriggerBarView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Small round system buttons flanking the Guide button (Select and Start).
|
||||||
|
struct SystemButtonView: View {
|
||||||
|
let button: XboxButton
|
||||||
|
let symbol: String
|
||||||
|
let pressed: Bool
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 4) {
|
||||||
|
ZStack {
|
||||||
|
Circle()
|
||||||
|
.fill(pressed ? Color.green : Color.secondary.opacity(0.25))
|
||||||
|
Image(systemName: symbol)
|
||||||
|
.font(.system(size: 10, weight: .medium))
|
||||||
|
.foregroundStyle(pressed ? .white : .secondary)
|
||||||
|
}
|
||||||
|
.frame(width: 24, height: 24)
|
||||||
|
Text(button.label)
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The large Guide button, centered between the D-pad and face buttons.
|
// The large Guide button, centered between the D-pad and face buttons.
|
||||||
struct GuideButtonView: View {
|
struct GuideButtonView: View {
|
||||||
let pressed: Bool
|
let pressed: Bool
|
||||||
|
|||||||
Reference in New Issue
Block a user