Skip to content

Commit 6ef0dea

Browse files
feat(settings): add global controller overlay scale & opacity settings
- Add `controllerScale` key (0.5–2.0, default 1.0) to PVSettings - Apply `.scaleEffect()` and `.opacity()` to DefaultControllerSkinView for both portrait and landscape layouts - Add "Controller Scale" slider to SwiftUI OnScreenControllerSection - Add "Scale" slider to UIKit PVSettingsViewController Part of #2889 Closes #2890 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent dc18cc8 commit 6ef0dea

4 files changed

Lines changed: 36 additions & 0 deletions

File tree

PVSettings/Sources/PVSettings/Settings/Model/PVSettingsModel.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ public extension Defaults.Keys {
130130
static let allRightShoulders = Key<Bool>("allRightShoulders", default: false)
131131
#endif
132132
static let controllerOpacity = Key<Double>("controllerOpacity", default: 0.8)
133+
/// Scale multiplier for the on-screen controller overlay.
134+
/// Range: 0.5 (half size) – 2.0 (double size). Default 1.0 (normal size).
135+
static let controllerScale = Key<Double>("controllerScale", default: 1.0)
133136

134137
static let pauseButtonIsMenuButton = Key<Bool>("pauseButtonIsMenuButton", default: false)
135138
static let hapticFeedback = Key<Bool>("hapticFeedback", default: true)

PVUI/Sources/PVSwiftUI/Settings/SettingsSwiftUI.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,6 +2375,7 @@ private struct TestRumbleButton: View {
23752375
#if !os(tvOS)
23762376
private struct OnScreenControllerSection: View {
23772377
@Default(.controllerOpacity) var controllerOpacity
2378+
@Default(.controllerScale) var controllerScale
23782379
@Default(.buttonTints) var buttonTints
23792380
@Default(.allRightShoulders) var allRightShoulders
23802381
@Default(.buttonVibration) var buttonVibration
@@ -2408,6 +2409,24 @@ private struct OnScreenControllerSection: View {
24082409
.foregroundColor(RetroTheme.retroBlue)
24092410
})
24102411
}
2412+
HStack {
2413+
Text("Controller Scale")
2414+
RetroWaveSlider<Double>(value: $controllerScale,
2415+
in: 0.5...2.0,
2416+
step: 0.05,
2417+
onEditingChanged: { _ in },
2418+
label: { Text("Size of the on-screen controller overlay.") },
2419+
minimumValueLabel: { Text("") },
2420+
maximumValueLabel: { Text("") },
2421+
leadingIcon: {
2422+
Image(systemName: "minus.magnifyingglass")
2423+
.foregroundColor(RetroTheme.retroBlue)
2424+
},
2425+
trailingIcon: {
2426+
Image(systemName: "plus.magnifyingglass")
2427+
.foregroundColor(RetroTheme.retroBlue)
2428+
})
2429+
}
24112430
ThemedToggle(isOn: $buttonTints) {
24122431
SettingsRow(title: "Button Colors",
24132432
subtitle: "Show colored buttons matching original hardware.",

PVUI/Sources/PVUIBase/Settings/PVSettingsViewController.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,11 @@ public final class PVSettingsViewController: QuickTableViewController {
290290
valueLimits: (min: 0.0, max: 1.0),
291291
valueImages: (.sfSymbol("sun.min"), .sfSymbol("sun.max")),
292292
key: .controllerOpacity))
293+
controllerRows.append(PVSettingsSliderRow(text: NSLocalizedString("Scale", comment: "Scale"),
294+
detailText: .subtitle("Size of the on-screen controller overlay."),
295+
valueLimits: (min: 0.5, max: 2.0),
296+
valueImages: (.sfSymbol("minus.magnifyingglass"), .sfSymbol("plus.magnifyingglass")),
297+
key: .controllerScale))
293298

294299
controllerRows.append(contentsOf: [
295300
PVSettingsSwitchRow(text: NSLocalizedString("Button Colors", comment: "Button Colors"),

PVUI/Sources/PVUIBase/SwiftUI/DeltaSkins/Views/Display/EmulatorWithSkinView+DefaultSkin.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import PVThemes
1818
import PVLogging
1919
import PVUIBase
2020
import PVSettings
21+
import Defaults
2122

2223
// MARK: - Retrowave Styling Components
2324

@@ -179,6 +180,10 @@ struct DefaultControllerSkinView: View {
179180
// Bridge to protocol system (replaces notification system)
180181
@State private var viewportBridge: ViewportLayoutProviderBridge?
181182

183+
// User-configurable overlay scale and opacity
184+
@Default(.controllerScale) private var controllerScale
185+
@Default(.controllerOpacity) private var controllerOpacity
186+
182187
init(useJoystick: Bool, inputHandler: DeltaSkinInputHandler, systemId: SystemIdentifier?, coreInstance: PVEmulatorCore) {
183188
self._useJoystickInternal = State(initialValue: useJoystick)
184189
self.inputHandler = inputHandler
@@ -231,6 +236,8 @@ struct DefaultControllerSkinView: View {
231236
if isLandscape {
232237
// Landscape layout - controls positioned at edges with safe area awareness
233238
dynamicLandscapeControllerSkin
239+
.scaleEffect(controllerScale)
240+
.opacity(controllerOpacity)
234241
.onAppear {
235242
loadControlLayoutData()
236243
// Ensure input handler has the core set
@@ -247,6 +254,8 @@ struct DefaultControllerSkinView: View {
247254

248255
// Controller area - constrained to bottom portion
249256
dynamicControllerSkin
257+
.scaleEffect(controllerScale)
258+
.opacity(controllerOpacity)
250259
.frame(maxHeight: geometry.size.height * 0.35)
251260
.clipped()
252261
.onAppear {

0 commit comments

Comments
 (0)