first pass preferences
This commit is contained in:
parent
76a3260001
commit
1c313530e9
8 changed files with 604 additions and 8 deletions
Cargo.lock
gb-emu
167
Cargo.lock
generated
167
Cargo.lock
generated
|
@ -371,6 +371,16 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitmask-enum"
|
||||||
|
version = "2.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49fb8528abca6895a5ada33d62aedd538a5c33e77068256483b44a3230270163"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.38",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3"
|
name = "blake3"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -439,6 +449,25 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cacao"
|
||||||
|
version = "0.4.0-beta2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6de2bcb2324367ffb6ea53f977fab8234fa59e9a57e88f0f7be1ad7cb425c7b9"
|
||||||
|
dependencies = [
|
||||||
|
"bitmask-enum",
|
||||||
|
"block",
|
||||||
|
"core-foundation 0.9.3",
|
||||||
|
"core-graphics 0.23.1",
|
||||||
|
"dispatch",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"objc",
|
||||||
|
"objc_id",
|
||||||
|
"os_info",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cache-padded"
|
name = "cache-padded"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
@ -593,7 +622,7 @@ dependencies = [
|
||||||
"block",
|
"block",
|
||||||
"core-foundation 0.7.0",
|
"core-foundation 0.7.0",
|
||||||
"core-graphics 0.19.2",
|
"core-graphics 0.19.2",
|
||||||
"foreign-types",
|
"foreign-types 0.3.2",
|
||||||
"libc",
|
"libc",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
@ -609,7 +638,7 @@ dependencies = [
|
||||||
"cocoa-foundation",
|
"cocoa-foundation",
|
||||||
"core-foundation 0.9.3",
|
"core-foundation 0.9.3",
|
||||||
"core-graphics 0.22.3",
|
"core-graphics 0.22.3",
|
||||||
"foreign-types",
|
"foreign-types 0.3.2",
|
||||||
"libc",
|
"libc",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
@ -712,7 +741,7 @@ checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation 0.7.0",
|
"core-foundation 0.7.0",
|
||||||
"foreign-types",
|
"foreign-types 0.3.2",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -725,7 +754,20 @@ dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation 0.9.3",
|
"core-foundation 0.9.3",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types",
|
"foreign-types 0.3.2",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-graphics"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation 0.9.3",
|
||||||
|
"core-graphics-types",
|
||||||
|
"foreign-types 0.5.0",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1134,7 +1176,28 @@ version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foreign-types-shared",
|
"foreign-types-shared 0.1.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-macros",
|
||||||
|
"foreign-types-shared 0.3.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-macros"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.38",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1143,6 +1206,21 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "form_urlencoded"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.29"
|
version = "0.3.29"
|
||||||
|
@ -1246,6 +1324,7 @@ name = "gb-emu"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"cacao",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"cpal",
|
"cpal",
|
||||||
|
@ -1255,6 +1334,7 @@ dependencies = [
|
||||||
"gilrs",
|
"gilrs",
|
||||||
"image",
|
"image",
|
||||||
"nokhwa",
|
"nokhwa",
|
||||||
|
"objc",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"send_wrapper",
|
"send_wrapper",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -1527,6 +1607,16 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.24.7"
|
version = "0.24.7"
|
||||||
|
@ -1989,7 +2079,7 @@ dependencies = [
|
||||||
"block",
|
"block",
|
||||||
"cocoa 0.20.2",
|
"cocoa 0.20.2",
|
||||||
"core-graphics 0.19.2",
|
"core-graphics 0.19.2",
|
||||||
"foreign-types",
|
"foreign-types 0.3.2",
|
||||||
"log",
|
"log",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
@ -2003,7 +2093,7 @@ dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"block",
|
"block",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types",
|
"foreign-types 0.3.2",
|
||||||
"log",
|
"log",
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
@ -2499,6 +2589,15 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc_id"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||||
|
dependencies = [
|
||||||
|
"objc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.1"
|
version = "0.32.1"
|
||||||
|
@ -2552,6 +2651,17 @@ dependencies = [
|
||||||
"redox_syscall 0.3.5",
|
"redox_syscall 0.3.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_info"
|
||||||
|
version = "3.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owned_ttf_parser"
|
name = "owned_ttf_parser"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
|
@ -3391,6 +3501,21 @@ dependencies = [
|
||||||
"strict-num",
|
"strict-num",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.7.8"
|
version = "0.7.8"
|
||||||
|
@ -3454,12 +3579,27 @@ dependencies = [
|
||||||
"wide",
|
"wide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
|
@ -3478,6 +3618,17 @@ version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -3792,7 +3943,7 @@ dependencies = [
|
||||||
"block",
|
"block",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"d3d12",
|
"d3d12",
|
||||||
"foreign-types",
|
"foreign-types 0.3.2",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
"glow",
|
"glow",
|
||||||
"gpu-alloc",
|
"gpu-alloc",
|
||||||
|
|
|
@ -6,6 +6,10 @@ description = "TWINC Game Boy (CGB/DMG) emulator"
|
||||||
|
|
||||||
[package.metadata.bundle]
|
[package.metadata.bundle]
|
||||||
identifier = "com.alexjanka.TWINC"
|
identifier = "com.alexjanka.TWINC"
|
||||||
|
[package.metadata.bundle.bin.cli]
|
||||||
|
identifier = "com.alexjanka.TWINC.cli"
|
||||||
|
[package.metadata.bundle.bin.gui]
|
||||||
|
identifier = "com.alexjanka.TWINC.gui"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["vulkan-static"]
|
default = ["vulkan-static"]
|
||||||
|
@ -36,3 +40,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
image = { version = "0.24", default-features = false, features = ["png"] }
|
image = { version = "0.24", default-features = false, features = ["png"] }
|
||||||
bytemuck = "1.14"
|
bytemuck = "1.14"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "macos"))'.dependencies]
|
||||||
|
cacao = "0.4.0-beta2"
|
||||||
|
objc = "0.2"
|
||||||
|
|
7
gb-emu/src/bin/gui.rs
Normal file
7
gb-emu/src/bin/gui.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
mod macos;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
cacao::appkit::App::new("com.alexjanka.cacao-test", macos::TwincUiApp::default()).run();
|
||||||
|
}
|
113
gb-emu/src/bin/macos/mod.rs
Normal file
113
gb-emu/src/bin/macos/mod.rs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
use cacao::appkit::menu::{Menu, MenuItem};
|
||||||
|
use cacao::appkit::window::{Window, WindowConfig, WindowStyle, WindowToolbarStyle};
|
||||||
|
use cacao::appkit::{App, AppDelegate};
|
||||||
|
use cacao::notification_center::Dispatcher;
|
||||||
|
|
||||||
|
use self::preferences::{PreferencesMessage, PreferencesUi};
|
||||||
|
|
||||||
|
mod preferences;
|
||||||
|
|
||||||
|
pub(crate) enum AppMessage {
|
||||||
|
Core(CoreMessage),
|
||||||
|
Preferences(PreferencesMessage),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum CoreMessage {
|
||||||
|
Open,
|
||||||
|
OpenPreferences,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TwincUiApp {
|
||||||
|
preferences: Window<PreferencesUi>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TwincUiApp {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
preferences: Window::with(
|
||||||
|
{
|
||||||
|
let mut config = WindowConfig::default();
|
||||||
|
config.set_initial_dimensions(100., 100., 400., 400.);
|
||||||
|
|
||||||
|
config.set_styles(&[
|
||||||
|
WindowStyle::Resizable,
|
||||||
|
WindowStyle::Miniaturizable,
|
||||||
|
WindowStyle::Closable,
|
||||||
|
WindowStyle::Titled,
|
||||||
|
]);
|
||||||
|
|
||||||
|
config.toolbar_style = WindowToolbarStyle::Preferences;
|
||||||
|
config
|
||||||
|
},
|
||||||
|
PreferencesUi::new(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppDelegate for TwincUiApp {
|
||||||
|
fn did_finish_launching(&self) {
|
||||||
|
App::set_menu(menu());
|
||||||
|
App::activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dispatcher for TwincUiApp {
|
||||||
|
type Message = AppMessage;
|
||||||
|
|
||||||
|
fn on_ui_message(&self, message: Self::Message) {
|
||||||
|
match message {
|
||||||
|
AppMessage::Core(CoreMessage::Open) => println!("open"),
|
||||||
|
AppMessage::Core(CoreMessage::OpenPreferences) => {
|
||||||
|
self.preferences.show();
|
||||||
|
}
|
||||||
|
AppMessage::Preferences(prefs_message) => {
|
||||||
|
if let Some(delegate) = &self.preferences.delegate {
|
||||||
|
delegate.message(prefs_message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn menu() -> Vec<Menu> {
|
||||||
|
vec![
|
||||||
|
Menu::new(
|
||||||
|
"",
|
||||||
|
vec![
|
||||||
|
MenuItem::About("Cacao Test".to_string()),
|
||||||
|
MenuItem::Separator,
|
||||||
|
MenuItem::new("Preferences")
|
||||||
|
.key(",")
|
||||||
|
.action(|| dispatch(AppMessage::Core(CoreMessage::OpenPreferences))),
|
||||||
|
MenuItem::Separator,
|
||||||
|
MenuItem::Services,
|
||||||
|
MenuItem::Separator,
|
||||||
|
MenuItem::Hide,
|
||||||
|
MenuItem::HideOthers,
|
||||||
|
MenuItem::ShowAll,
|
||||||
|
MenuItem::Separator,
|
||||||
|
MenuItem::Quit,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Menu::new(
|
||||||
|
"File",
|
||||||
|
vec![MenuItem::new("Open")
|
||||||
|
.key("o")
|
||||||
|
.action(|| dispatch(AppMessage::Core(CoreMessage::Open)))],
|
||||||
|
),
|
||||||
|
Menu::new(
|
||||||
|
"Window",
|
||||||
|
vec![
|
||||||
|
MenuItem::Minimize,
|
||||||
|
MenuItem::Separator,
|
||||||
|
MenuItem::new("Bring All to Front"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Menu::new("Help", vec![]),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dispatch(message: AppMessage) {
|
||||||
|
App::<TwincUiApp, AppMessage>::dispatch_main(message);
|
||||||
|
}
|
80
gb-emu/src/bin/macos/preferences.rs
Normal file
80
gb-emu/src/bin/macos/preferences.rs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
use cacao::{
|
||||||
|
appkit::{
|
||||||
|
toolbar::Toolbar,
|
||||||
|
window::{Window, WindowDelegate},
|
||||||
|
},
|
||||||
|
view::ViewController,
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::{
|
||||||
|
toolbar::PreferencesToolbar,
|
||||||
|
views::{
|
||||||
|
CorePreferencesContentView, StandalonePreferencesContentView, VstPreferencesContentView,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod toolbar;
|
||||||
|
mod views;
|
||||||
|
|
||||||
|
pub(crate) enum PreferencesMessage {
|
||||||
|
SwitchPane(PreferencesPane),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum PreferencesPane {
|
||||||
|
Core,
|
||||||
|
Standalone,
|
||||||
|
Vst,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct PreferencesUi {
|
||||||
|
pub(crate) toolbar: Toolbar<PreferencesToolbar>,
|
||||||
|
pub(crate) core_prefs: ViewController<CorePreferencesContentView>,
|
||||||
|
pub(crate) standalone_prefs: ViewController<StandalonePreferencesContentView>,
|
||||||
|
pub(crate) vst_prefs: ViewController<VstPreferencesContentView>,
|
||||||
|
window: Option<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PreferencesUi {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
toolbar: Toolbar::new("PreferencesToolbar", PreferencesToolbar::default()),
|
||||||
|
core_prefs: ViewController::new(CorePreferencesContentView::default()),
|
||||||
|
standalone_prefs: ViewController::new(StandalonePreferencesContentView::default()),
|
||||||
|
vst_prefs: ViewController::new(VstPreferencesContentView::default()),
|
||||||
|
window: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn message(&self, message: PreferencesMessage) {
|
||||||
|
let window = self.window.as_ref().unwrap();
|
||||||
|
|
||||||
|
match message {
|
||||||
|
PreferencesMessage::SwitchPane(PreferencesPane::Core) => {
|
||||||
|
window.set_title("Core");
|
||||||
|
window.set_content_view_controller(&self.core_prefs);
|
||||||
|
}
|
||||||
|
PreferencesMessage::SwitchPane(PreferencesPane::Standalone) => {
|
||||||
|
window.set_title("Standalone");
|
||||||
|
window.set_content_view_controller(&self.standalone_prefs);
|
||||||
|
}
|
||||||
|
PreferencesMessage::SwitchPane(PreferencesPane::Vst) => {
|
||||||
|
window.set_title("VST");
|
||||||
|
window.set_content_view_controller(&self.vst_prefs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowDelegate for PreferencesUi {
|
||||||
|
const NAME: &'static str = "PreferencesUi";
|
||||||
|
|
||||||
|
fn did_load(&mut self, window: Window) {
|
||||||
|
window.set_autosave_name("PreferencesWindow");
|
||||||
|
window.set_movable_by_background(true);
|
||||||
|
window.set_toolbar(&self.toolbar);
|
||||||
|
|
||||||
|
self.window = Some(window);
|
||||||
|
|
||||||
|
self.message(PreferencesMessage::SwitchPane(PreferencesPane::Core));
|
||||||
|
}
|
||||||
|
}
|
109
gb-emu/src/bin/macos/preferences/toolbar.rs
Normal file
109
gb-emu/src/bin/macos/preferences/toolbar.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
use cacao::{
|
||||||
|
appkit::toolbar::{ItemIdentifier, ToolbarDelegate, ToolbarItem},
|
||||||
|
image::{Image, MacSystemIcon},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::macos::{dispatch, AppMessage};
|
||||||
|
|
||||||
|
use super::{PreferencesMessage, PreferencesPane};
|
||||||
|
|
||||||
|
pub(crate) struct PreferencesToolbar {
|
||||||
|
core: ToolbarItem,
|
||||||
|
standalone: ToolbarItem,
|
||||||
|
vst: ToolbarItem,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PreferencesToolbar {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
core: {
|
||||||
|
let mut item = ToolbarItem::new("core");
|
||||||
|
item.set_title("Core");
|
||||||
|
|
||||||
|
let icon = Image::toolbar_icon(MacSystemIcon::PreferencesGeneral, "Core");
|
||||||
|
item.set_image(icon);
|
||||||
|
|
||||||
|
item.set_action(|_| {
|
||||||
|
dispatch(AppMessage::Preferences(PreferencesMessage::SwitchPane(
|
||||||
|
PreferencesPane::Core,
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
|
||||||
|
item
|
||||||
|
},
|
||||||
|
standalone: {
|
||||||
|
let mut item = ToolbarItem::new("standalone");
|
||||||
|
item.set_title("Standalone");
|
||||||
|
|
||||||
|
let icon = Image::toolbar_icon(MacSystemIcon::PreferencesGeneral, "Standalone");
|
||||||
|
item.set_image(icon);
|
||||||
|
|
||||||
|
item.set_action(|_| {
|
||||||
|
dispatch(AppMessage::Preferences(PreferencesMessage::SwitchPane(
|
||||||
|
PreferencesPane::Standalone,
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
|
||||||
|
item
|
||||||
|
},
|
||||||
|
vst: {
|
||||||
|
let mut item = ToolbarItem::new("vst");
|
||||||
|
item.set_title("VST");
|
||||||
|
|
||||||
|
let icon = Image::toolbar_icon(MacSystemIcon::PreferencesGeneral, "VST");
|
||||||
|
item.set_image(icon);
|
||||||
|
|
||||||
|
item.set_action(|_| {
|
||||||
|
dispatch(AppMessage::Preferences(PreferencesMessage::SwitchPane(
|
||||||
|
PreferencesPane::Vst,
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
|
||||||
|
item
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToolbarDelegate for PreferencesToolbar {
|
||||||
|
const NAME: &'static str = "PreferencesToolbar";
|
||||||
|
|
||||||
|
fn did_load(&mut self, toolbar: cacao::appkit::toolbar::Toolbar) {
|
||||||
|
toolbar.set_selected("core")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allowed_item_identifiers(&self) -> Vec<cacao::appkit::toolbar::ItemIdentifier> {
|
||||||
|
vec![
|
||||||
|
ItemIdentifier::Custom("core"),
|
||||||
|
ItemIdentifier::Custom("standalone"),
|
||||||
|
ItemIdentifier::Custom("vst"),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_item_identifiers(&self) -> Vec<cacao::appkit::toolbar::ItemIdentifier> {
|
||||||
|
vec![
|
||||||
|
ItemIdentifier::Custom("core"),
|
||||||
|
ItemIdentifier::Custom("standalone"),
|
||||||
|
ItemIdentifier::Custom("vst"),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selectable_item_identifiers(&self) -> Vec<ItemIdentifier> {
|
||||||
|
vec![
|
||||||
|
ItemIdentifier::Custom("core"),
|
||||||
|
ItemIdentifier::Custom("standalone"),
|
||||||
|
ItemIdentifier::Custom("vst"),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn item_for(&self, identifier: &str) -> &cacao::appkit::toolbar::ToolbarItem {
|
||||||
|
match identifier {
|
||||||
|
"core" => &self.core,
|
||||||
|
"standalone" => &self.standalone,
|
||||||
|
"vst" => &self.vst,
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
gb-emu/src/bin/macos/preferences/views.rs
Normal file
65
gb-emu/src/bin/macos/preferences/views.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use cacao::{
|
||||||
|
layout::{Layout, LayoutConstraint},
|
||||||
|
view::{View, ViewDelegate},
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::widgets::ToggleOptionView;
|
||||||
|
|
||||||
|
mod widgets;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct CorePreferencesContentView {
|
||||||
|
pub example_option: ToggleOptionView,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewDelegate for CorePreferencesContentView {
|
||||||
|
const NAME: &'static str = "CorePreferencesContentView";
|
||||||
|
|
||||||
|
fn did_load(&mut self, view: View) {
|
||||||
|
self.example_option.configure(
|
||||||
|
"An example preference",
|
||||||
|
"This can be true, or it can be false.",
|
||||||
|
false, // initial value
|
||||||
|
|_v| {},
|
||||||
|
);
|
||||||
|
|
||||||
|
view.add_subview(&self.example_option.view);
|
||||||
|
|
||||||
|
LayoutConstraint::activate(&[
|
||||||
|
self.example_option
|
||||||
|
.view
|
||||||
|
.top
|
||||||
|
.constraint_equal_to(&view.top)
|
||||||
|
.offset(22.),
|
||||||
|
self.example_option
|
||||||
|
.view
|
||||||
|
.leading
|
||||||
|
.constraint_equal_to(&view.leading)
|
||||||
|
.offset(22.),
|
||||||
|
self.example_option
|
||||||
|
.view
|
||||||
|
.trailing
|
||||||
|
.constraint_equal_to(&view.trailing)
|
||||||
|
.offset(-22.),
|
||||||
|
self.example_option
|
||||||
|
.view
|
||||||
|
.bottom
|
||||||
|
.constraint_equal_to(&view.bottom)
|
||||||
|
.offset(-22.),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct StandalonePreferencesContentView {}
|
||||||
|
|
||||||
|
impl ViewDelegate for StandalonePreferencesContentView {
|
||||||
|
const NAME: &'static str = "StandalonePreferencesContentView";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct VstPreferencesContentView {}
|
||||||
|
|
||||||
|
impl ViewDelegate for VstPreferencesContentView {
|
||||||
|
const NAME: &'static str = "VstPreferencesContentView";
|
||||||
|
}
|
63
gb-emu/src/bin/macos/preferences/views/widgets.rs
Normal file
63
gb-emu/src/bin/macos/preferences/views/widgets.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use cacao::layout::{Layout, LayoutConstraint};
|
||||||
|
use cacao::switch::Switch;
|
||||||
|
use cacao::text::Label;
|
||||||
|
use cacao::view::View;
|
||||||
|
use objc::runtime::Object;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ToggleOptionView {
|
||||||
|
pub view: View,
|
||||||
|
pub switch: Switch,
|
||||||
|
pub title: Label,
|
||||||
|
pub subtitle: Label,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ToggleOptionView {
|
||||||
|
fn default() -> Self {
|
||||||
|
let view = View::new();
|
||||||
|
|
||||||
|
let switch = Switch::new("");
|
||||||
|
view.add_subview(&switch);
|
||||||
|
|
||||||
|
let title = Label::new();
|
||||||
|
view.add_subview(&title);
|
||||||
|
|
||||||
|
let subtitle = Label::new();
|
||||||
|
view.add_subview(&subtitle);
|
||||||
|
|
||||||
|
LayoutConstraint::activate(&[
|
||||||
|
switch.top.constraint_equal_to(&view.top),
|
||||||
|
switch.leading.constraint_equal_to(&view.leading),
|
||||||
|
switch.width.constraint_equal_to_constant(24.),
|
||||||
|
title.top.constraint_equal_to(&view.top),
|
||||||
|
title.leading.constraint_equal_to(&switch.trailing),
|
||||||
|
title.trailing.constraint_equal_to(&view.trailing),
|
||||||
|
subtitle.top.constraint_equal_to(&title.bottom),
|
||||||
|
subtitle.leading.constraint_equal_to(&switch.trailing),
|
||||||
|
subtitle.trailing.constraint_equal_to(&view.trailing),
|
||||||
|
subtitle.bottom.constraint_equal_to(&view.bottom),
|
||||||
|
subtitle
|
||||||
|
.width
|
||||||
|
.constraint_greater_than_or_equal_to_constant(200.),
|
||||||
|
]);
|
||||||
|
|
||||||
|
ToggleOptionView {
|
||||||
|
view,
|
||||||
|
switch,
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToggleOptionView {
|
||||||
|
pub fn configure<F>(&mut self, text: &str, subtitle: &str, state: bool, handler: F)
|
||||||
|
where
|
||||||
|
F: Fn(*const Object) + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
self.title.set_text(text);
|
||||||
|
self.subtitle.set_text(subtitle);
|
||||||
|
self.switch.set_action(handler);
|
||||||
|
self.switch.set_checked(state);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue