visionOS: native settings menu
This commit is contained in:
parent
ed99d1bbfb
commit
632f01f169
|
@ -61,6 +61,7 @@
|
||||||
28D3C6152B7681420079E915 /* VisionSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D3C6142B7681420079E915 /* VisionSupport.swift */; };
|
28D3C6152B7681420079E915 /* VisionSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D3C6142B7681420079E915 /* VisionSupport.swift */; };
|
||||||
28D3C6172B76B8970079E915 /* DefaultSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D3C6162B76B8970079E915 /* DefaultSceneDelegate.swift */; };
|
28D3C6172B76B8970079E915 /* DefaultSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D3C6162B76B8970079E915 /* DefaultSceneDelegate.swift */; };
|
||||||
28D3C61B2B7781700079E915 /* KeyboardSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D3C61A2B7781700079E915 /* KeyboardSceneDelegate.swift */; };
|
28D3C61B2B7781700079E915 /* KeyboardSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D3C61A2B7781700079E915 /* KeyboardSceneDelegate.swift */; };
|
||||||
|
28D3C61D2B7795060079E915 /* SettingsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D3C61C2B7795060079E915 /* SettingsMenu.swift */; };
|
||||||
28D5A3FD1CD6868F001A33F6 /* TouchScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D5A3FC1CD6868E001A33F6 /* TouchScreen.m */; };
|
28D5A3FD1CD6868F001A33F6 /* TouchScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D5A3FC1CD6868E001A33F6 /* TouchScreen.m */; };
|
||||||
28E3B7DF251D0F13007C273F /* MOUSEMDV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28E3B7CC251D0F12007C273F /* MOUSEMDV.c */; };
|
28E3B7DF251D0F13007C273F /* MOUSEMDV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28E3B7CC251D0F12007C273F /* MOUSEMDV.c */; };
|
||||||
28E3B7E0251D0F13007C273F /* MOUSEMDV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28E3B7CC251D0F12007C273F /* MOUSEMDV.c */; };
|
28E3B7E0251D0F13007C273F /* MOUSEMDV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28E3B7CC251D0F12007C273F /* MOUSEMDV.c */; };
|
||||||
|
@ -289,6 +290,7 @@
|
||||||
28D3C6142B7681420079E915 /* VisionSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisionSupport.swift; sourceTree = "<group>"; };
|
28D3C6142B7681420079E915 /* VisionSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisionSupport.swift; sourceTree = "<group>"; };
|
||||||
28D3C6162B76B8970079E915 /* DefaultSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSceneDelegate.swift; sourceTree = "<group>"; };
|
28D3C6162B76B8970079E915 /* DefaultSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
28D3C61A2B7781700079E915 /* KeyboardSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSceneDelegate.swift; sourceTree = "<group>"; };
|
28D3C61A2B7781700079E915 /* KeyboardSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
28D3C61C2B7795060079E915 /* SettingsMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsMenu.swift; sourceTree = "<group>"; };
|
||||||
28D5A3FB1CD6868E001A33F6 /* TouchScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TouchScreen.h; sourceTree = "<group>"; };
|
28D5A3FB1CD6868E001A33F6 /* TouchScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TouchScreen.h; sourceTree = "<group>"; };
|
||||||
28D5A3FC1CD6868E001A33F6 /* TouchScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TouchScreen.m; sourceTree = "<group>"; };
|
28D5A3FC1CD6868E001A33F6 /* TouchScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TouchScreen.m; sourceTree = "<group>"; };
|
||||||
28E3B7CC251D0F12007C273F /* MOUSEMDV.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = MOUSEMDV.c; sourceTree = "<group>"; };
|
28E3B7CC251D0F12007C273F /* MOUSEMDV.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = MOUSEMDV.c; sourceTree = "<group>"; };
|
||||||
|
@ -619,6 +621,7 @@
|
||||||
28F676C61CD15E0B00FC6FA6 /* ViewController.h */,
|
28F676C61CD15E0B00FC6FA6 /* ViewController.h */,
|
||||||
28F676C71CD15E0B00FC6FA6 /* ViewController.m */,
|
28F676C71CD15E0B00FC6FA6 /* ViewController.m */,
|
||||||
28D3C6142B7681420079E915 /* VisionSupport.swift */,
|
28D3C6142B7681420079E915 /* VisionSupport.swift */,
|
||||||
|
28D3C61C2B7795060079E915 /* SettingsMenu.swift */,
|
||||||
28848B601CDE97D600B86C45 /* InsertDiskViewController.h */,
|
28848B601CDE97D600B86C45 /* InsertDiskViewController.h */,
|
||||||
28848B611CDE97D600B86C45 /* InsertDiskViewController.m */,
|
28848B611CDE97D600B86C45 /* InsertDiskViewController.m */,
|
||||||
28848B631CDE97E900B86C45 /* SettingsViewController.h */,
|
28848B631CDE97E900B86C45 /* SettingsViewController.h */,
|
||||||
|
@ -1308,6 +1311,7 @@
|
||||||
28BA89881CE73FBC00A98104 /* MNVMApplication.m in Sources */,
|
28BA89881CE73FBC00A98104 /* MNVMApplication.m in Sources */,
|
||||||
28F6B4CF1CF77099002D76D0 /* compat.m in Sources */,
|
28F6B4CF1CF77099002D76D0 /* compat.m in Sources */,
|
||||||
28F6B4521CF07C48002D76D0 /* UIImage+DiskImageIcon.m in Sources */,
|
28F6B4521CF07C48002D76D0 /* UIImage+DiskImageIcon.m in Sources */,
|
||||||
|
28D3C61D2B7795060079E915 /* SettingsMenu.swift in Sources */,
|
||||||
28BA897F1CE7315400A98104 /* KBKeyboardLayout.m in Sources */,
|
28BA897F1CE7315400A98104 /* KBKeyboardLayout.m in Sources */,
|
||||||
28D3C61B2B7781700079E915 /* KeyboardSceneDelegate.swift in Sources */,
|
28D3C61B2B7781700079E915 /* KeyboardSceneDelegate.swift in Sources */,
|
||||||
28848B621CDE97D600B86C45 /* InsertDiskViewController.m in Sources */,
|
28848B621CDE97D600B86C45 /* InsertDiskViewController.m in Sources */,
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
@import CoreGraphics;
|
@import CoreGraphics;
|
||||||
@import QuartzCore;
|
@import QuartzCore;
|
||||||
|
|
||||||
typedef enum : NSInteger {
|
typedef NS_ENUM(NSInteger, EmulatorSpeed) {
|
||||||
EmulatorSpeedAllOut = -1,
|
EmulatorSpeedAllOut = -1,
|
||||||
EmulatorSpeed1x = 0,
|
EmulatorSpeed1x = 0,
|
||||||
EmulatorSpeed2x = 1,
|
EmulatorSpeed2x = 1,
|
||||||
|
@ -18,7 +18,7 @@ typedef enum : NSInteger {
|
||||||
EmulatorSpeed8x = 3,
|
EmulatorSpeed8x = 3,
|
||||||
EmulatorSpeed16x = 4,
|
EmulatorSpeed16x = 4,
|
||||||
EmulatorSpeed32x = 5
|
EmulatorSpeed32x = 5
|
||||||
} EmulatorSpeed;
|
};
|
||||||
|
|
||||||
@protocol Emulator <NSObject>
|
@protocol Emulator <NSObject>
|
||||||
|
|
||||||
|
|
|
@ -4,5 +4,6 @@
|
||||||
|
|
||||||
#import "ViewController.h"
|
#import "ViewController.h"
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
#import "EmulatorProtocol.h"
|
||||||
#import "KBKeyboardView.h"
|
#import "KBKeyboardView.h"
|
||||||
#import "KBKeyboardLayout.h"
|
#import "KBKeyboardLayout.h"
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
//
|
||||||
|
// SettingsMenu.swift
|
||||||
|
// Mini vMac
|
||||||
|
//
|
||||||
|
// Created by Jesús A. Álvarez on 2024-02-10.
|
||||||
|
// Copyright © 2024 namedfork. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
}.menuOrder(.fixed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SpeedButton: View {
|
||||||
|
@AppStorage("speedValue") var currentSpeed: EmulatorSpeed = .speed1x
|
||||||
|
let label: LocalizedStringKey
|
||||||
|
let speed: EmulatorSpeed
|
||||||
|
var body: some View {
|
||||||
|
if currentSpeed == speed {
|
||||||
|
Button(label, systemImage: "checkmark") {}
|
||||||
|
} else {
|
||||||
|
Button {
|
||||||
|
currentSpeed = speed
|
||||||
|
} label: {
|
||||||
|
Text(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
if currentMachine == bundle.name {
|
||||||
|
Label {
|
||||||
|
Text("\(bundle.displayName ?? bundle.name)\n\(bundle.getInfoString ?? "")")
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Button {
|
||||||
|
if !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
|
||||||
|
if scalingFilter == filter.filter {
|
||||||
|
Label {
|
||||||
|
Text(filter.name)
|
||||||
|
} icon: {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Button(filter.name) {
|
||||||
|
scalingFilter = filter.filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.menuOrder(.fixed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DisplayScalingFilter {
|
||||||
|
let filter: CALayerContentsFilter
|
||||||
|
let name: String
|
||||||
|
}
|
|
@ -20,11 +20,7 @@ extension ViewController {
|
||||||
VStack {
|
VStack {
|
||||||
Spacer(minLength: 80.0)
|
Spacer(minLength: 80.0)
|
||||||
HStack {
|
HStack {
|
||||||
Button(action: {
|
SettingsMenu().glassBackgroundEffect()
|
||||||
AppDelegate.shared.showSettings(self)
|
|
||||||
}, label: {
|
|
||||||
Image(systemName: "gear")
|
|
||||||
}).glassBackgroundEffect()
|
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
AppDelegate.shared.showInsertDisk(self)
|
AppDelegate.shared.showInsertDisk(self)
|
||||||
|
|
Loading…
Reference in New Issue