minivmac4ios/Mini vMac/SettingsMenu.swift

142 lines
4.3 KiB
Swift

//
// SettingsMenu.swift
// Mini vMac
//
// Created by Jesús A. Álvarez on 2024-02-10.
// Copyright © 2024 namedfork. All rights reserved.
//
import SwiftUI
#if os(visionOS)
struct SettingsMenu: View {
var body: some View {
Menu() {
Section("Settings") {
SpeedMenu()
MachineMenu()
DisplayScalingMenu()
}
} label: {
Image(systemName: "gear")
}.menuOrder(.fixed)
}
}
struct SpeedMenu: View {
@AppStorage("speedValue") var currentSpeed: EmulatorSpeed = .speed1x
@AppStorage("runInBackground") var runInBackground: Bool = false
private var currentSpeedImage: String {
switch currentSpeed {
case .speed1x:
"tortoise"
case .speedAllOut:
"hare"
case .speed2x:
"2.square"
case .speed4x:
"4.square"
case .speed8x:
"8.square"
case .speed16x:
"16.square"
case .speed32x:
"32.square"
@unknown default:
"hare"
}
}
var body: some View {
Menu("Speed", systemImage:currentSpeedImage) {
SpeedButton(label: "1x", speed: .speed1x)
SpeedButton(label: "2x", speed: .speed2x)
SpeedButton(label: "4x", speed: .speed4x)
SpeedButton(label: "8x", speed: .speed8x)
SpeedButton(label: "16x", speed: .speed16x)
SpeedButton(label: "32x", speed: .speed32x)
SpeedButton(label: "Unlimited", speed: .speedAllOut)
Divider()
Toggle("Run in Background", isOn: $runInBackground)
}.menuOrder(.fixed)
}
}
struct SpeedButton: View {
@AppStorage("speedValue") var currentSpeed: EmulatorSpeed = .speed1x
let label: LocalizedStringKey
let speed: EmulatorSpeed
var body: some View {
Toggle(label, isOn: Binding(get: {
currentSpeed == speed
}, set: { enable in
if enable {
currentSpeed = speed
}
}))
}
}
struct MachineMenu: View {
@AppStorage("machine") var currentMachine: String = "Plus4M"
let bundles = AppDelegate.shared.emulatorBundles?.sorted(by: { $0.bundleIdentifier! < $1.bundleIdentifier! }) ?? []
var body: some View {
Menu("Machine", systemImage: "desktopcomputer") {
ForEach(bundles, id: \.bundleIdentifier) { bundle in
MachineButton(bundle: bundle)
}
}.menuOrder(.fixed)
}
}
struct MachineButton: View {
@AppStorage("machine") var currentMachine: String = "Plus4M"
var bundle: Bundle
var body: some View {
Toggle(isOn: Binding(get: {
currentMachine == bundle.name
}, set: { enable in
if enable && !AppDelegate.emulator.anyDiskInserted {
currentMachine = bundle.name
AppDelegate.shared.loadAndStartEmulator()
}
}), label: {
Text("\(bundle.displayName ?? bundle.name)\n\(bundle.getInfoString ?? "")")
})
}
}
fileprivate extension Bundle {
var name: String { ((self.bundlePath as NSString).lastPathComponent as NSString).deletingPathExtension }
var displayName: String? { self.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String }
var getInfoString: String? { self.object(forInfoDictionaryKey: "CFBundleGetInfoString") as? String }
}
struct DisplayScalingMenu: View {
@AppStorage("screenFilter") var scalingFilter: CALayerContentsFilter = .nearest
static let filters = [
DisplayScalingFilter(filter: .nearest, name: "Nearest"),
DisplayScalingFilter(filter: .linear, name: "Linear"),
DisplayScalingFilter(filter: .trilinear, name: "Trilinear"),
]
var body: some View {
Menu("Display Scaling", systemImage: "rectangle.and.text.magnifyingglass") {
ForEach(DisplayScalingMenu.filters, id: \.filter) { filter in
Toggle(filter.name, isOn: Binding(get: {
scalingFilter == filter.filter
}, set: { enable in
if enable {
scalingFilter = filter.filter
}
}))
}
}.menuOrder(.fixed)
}
}
struct DisplayScalingFilter {
let filter: CALayerContentsFilter
let name: String
}
#endif