first pass preferences
This commit is contained in:
parent
76a3260001
commit
1c313530e9
8 changed files with 604 additions and 8 deletions
167
Cargo.lock
generated
167
Cargo.lock
generated
|
@ -371,6 +371,16 @@ dependencies = [
|
|||
"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]]
|
||||
name = "blake3"
|
||||
version = "1.5.0"
|
||||
|
@ -439,6 +449,25 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "cache-padded"
|
||||
version = "1.3.0"
|
||||
|
@ -593,7 +622,7 @@ dependencies = [
|
|||
"block",
|
||||
"core-foundation 0.7.0",
|
||||
"core-graphics 0.19.2",
|
||||
"foreign-types",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
@ -609,7 +638,7 @@ dependencies = [
|
|||
"cocoa-foundation",
|
||||
"core-foundation 0.9.3",
|
||||
"core-graphics 0.22.3",
|
||||
"foreign-types",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
@ -712,7 +741,7 @@ checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
|
|||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation 0.7.0",
|
||||
"foreign-types",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
@ -725,7 +754,20 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.3",
|
||||
"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",
|
||||
]
|
||||
|
||||
|
@ -1134,7 +1176,28 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
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]]
|
||||
|
@ -1143,6 +1206,21 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "futures"
|
||||
version = "0.3.29"
|
||||
|
@ -1246,6 +1324,7 @@ name = "gb-emu"
|
|||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cacao",
|
||||
"chrono",
|
||||
"clap",
|
||||
"cpal",
|
||||
|
@ -1255,6 +1334,7 @@ dependencies = [
|
|||
"gilrs",
|
||||
"image",
|
||||
"nokhwa",
|
||||
"objc",
|
||||
"raw-window-handle",
|
||||
"send_wrapper",
|
||||
"serde",
|
||||
|
@ -1527,6 +1607,16 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "image"
|
||||
version = "0.24.7"
|
||||
|
@ -1989,7 +2079,7 @@ dependencies = [
|
|||
"block",
|
||||
"cocoa 0.20.2",
|
||||
"core-graphics 0.19.2",
|
||||
"foreign-types",
|
||||
"foreign-types 0.3.2",
|
||||
"log",
|
||||
"objc",
|
||||
]
|
||||
|
@ -2003,7 +2093,7 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"block",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"foreign-types 0.3.2",
|
||||
"log",
|
||||
"objc",
|
||||
]
|
||||
|
@ -2499,6 +2589,15 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.1"
|
||||
|
@ -2552,6 +2651,17 @@ dependencies = [
|
|||
"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]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.19.0"
|
||||
|
@ -3391,6 +3501,21 @@ dependencies = [
|
|||
"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]]
|
||||
name = "toml"
|
||||
version = "0.7.8"
|
||||
|
@ -3454,12 +3579,27 @@ dependencies = [
|
|||
"wide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
|
@ -3478,6 +3618,17 @@ version = "0.2.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
|
@ -3792,7 +3943,7 @@ dependencies = [
|
|||
"block",
|
||||
"core-graphics-types",
|
||||
"d3d12",
|
||||
"foreign-types",
|
||||
"foreign-types 0.3.2",
|
||||
"fxhash",
|
||||
"glow",
|
||||
"gpu-alloc",
|
||||
|
|
|
@ -6,6 +6,10 @@ description = "TWINC Game Boy (CGB/DMG) emulator"
|
|||
|
||||
[package.metadata.bundle]
|
||||
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]
|
||||
default = ["vulkan-static"]
|
||||
|
@ -36,3 +40,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||
image = { version = "0.24", default-features = false, features = ["png"] }
|
||||
bytemuck = "1.14"
|
||||
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