Save/load more config
This commit is contained in:
		
							parent
							
								
									6e2d70abd7
								
							
						
					
					
						commit
						e31269368d
					
				| 
						 | 
					@ -18,6 +18,16 @@ version = "0.1.8"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
 | 
					checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "accesskit"
 | 
				
			||||||
 | 
					version = "0.16.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "99b76d84ee70e30a4a7e39ab9018e2b17a6a09e31084176cc7c0b2dec036ba45"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "enumn",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "adler2"
 | 
					name = "adler2"
 | 
				
			||||||
version = "2.0.0"
 | 
					version = "2.0.0"
 | 
				
			||||||
| 
						 | 
					@ -33,6 +43,7 @@ dependencies = [
 | 
				
			||||||
 "cfg-if",
 | 
					 "cfg-if",
 | 
				
			||||||
 "getrandom",
 | 
					 "getrandom",
 | 
				
			||||||
 "once_cell",
 | 
					 "once_cell",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 "version_check",
 | 
					 "version_check",
 | 
				
			||||||
 "zerocopy",
 | 
					 "zerocopy",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					@ -923,6 +934,7 @@ checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "bytemuck",
 | 
					 "bytemuck",
 | 
				
			||||||
 "emath",
 | 
					 "emath",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -931,11 +943,13 @@ version = "0.29.1"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974"
 | 
					checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "accesskit",
 | 
				
			||||||
 "ahash",
 | 
					 "ahash",
 | 
				
			||||||
 "emath",
 | 
					 "emath",
 | 
				
			||||||
 "epaint",
 | 
					 "epaint",
 | 
				
			||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "nohash-hasher",
 | 
					 "nohash-hasher",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -1009,6 +1023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3"
 | 
					checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "bytemuck",
 | 
					 "bytemuck",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -1059,6 +1074,17 @@ dependencies = [
 | 
				
			||||||
 "syn 2.0.90",
 | 
					 "syn 2.0.90",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "enumn"
 | 
				
			||||||
 | 
					version = "0.1.14"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "proc-macro2",
 | 
				
			||||||
 | 
					 "quote",
 | 
				
			||||||
 | 
					 "syn 2.0.90",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "epaint"
 | 
					name = "epaint"
 | 
				
			||||||
version = "0.29.1"
 | 
					version = "0.29.1"
 | 
				
			||||||
| 
						 | 
					@ -1074,6 +1100,7 @@ dependencies = [
 | 
				
			||||||
 "log",
 | 
					 "log",
 | 
				
			||||||
 "nohash-hasher",
 | 
					 "nohash-hasher",
 | 
				
			||||||
 "parking_lot",
 | 
					 "parking_lot",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ bytemuck = { version = "1", features = ["derive"] }
 | 
				
			||||||
clap = { version = "4", features = ["derive"] }
 | 
					clap = { version = "4", features = ["derive"] }
 | 
				
			||||||
cpal = { git = "https://github.com/sidit77/cpal.git", rev = "66ed6be" }
 | 
					cpal = { git = "https://github.com/sidit77/cpal.git", rev = "66ed6be" }
 | 
				
			||||||
directories = "5"
 | 
					directories = "5"
 | 
				
			||||||
egui = "0.29"
 | 
					egui = { version = "0.29", features = ["serde"] }
 | 
				
			||||||
egui_extras = "0.29"
 | 
					egui_extras = "0.29"
 | 
				
			||||||
egui-toast = "0.15"
 | 
					egui-toast = "0.15"
 | 
				
			||||||
egui-winit = "0.29"
 | 
					egui-winit = "0.29"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/app.rs
								
								
								
								
							
							
						
						
									
										18
									
								
								src/app.rs
								
								
								
								
							| 
						 | 
					@ -38,6 +38,7 @@ pub struct Application {
 | 
				
			||||||
    proxy: EventLoopProxy<UserEvent>,
 | 
					    proxy: EventLoopProxy<UserEvent>,
 | 
				
			||||||
    mappings: MappingProvider,
 | 
					    mappings: MappingProvider,
 | 
				
			||||||
    controllers: ControllerManager,
 | 
					    controllers: ControllerManager,
 | 
				
			||||||
 | 
					    persistence: Persistence,
 | 
				
			||||||
    viewports: HashMap<ViewportId, Viewport>,
 | 
					    viewports: HashMap<ViewportId, Viewport>,
 | 
				
			||||||
    focused: Option<ViewportId>,
 | 
					    focused: Option<ViewportId>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -46,7 +47,7 @@ impl Application {
 | 
				
			||||||
    pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
 | 
					    pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
 | 
				
			||||||
        let icon = load_icon().ok().map(Arc::new);
 | 
					        let icon = load_icon().ok().map(Arc::new);
 | 
				
			||||||
        let persistence = Persistence::new();
 | 
					        let persistence = Persistence::new();
 | 
				
			||||||
        let mappings = MappingProvider::new(persistence);
 | 
					        let mappings = MappingProvider::new(persistence.clone());
 | 
				
			||||||
        let controllers = ControllerManager::new(client.clone(), &mappings);
 | 
					        let controllers = ControllerManager::new(client.clone(), &mappings);
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            let mappings = mappings.clone();
 | 
					            let mappings = mappings.clone();
 | 
				
			||||||
| 
						 | 
					@ -59,6 +60,7 @@ impl Application {
 | 
				
			||||||
            proxy,
 | 
					            proxy,
 | 
				
			||||||
            mappings,
 | 
					            mappings,
 | 
				
			||||||
            controllers,
 | 
					            controllers,
 | 
				
			||||||
 | 
					            persistence,
 | 
				
			||||||
            viewports: HashMap::new(),
 | 
					            viewports: HashMap::new(),
 | 
				
			||||||
            focused: None,
 | 
					            focused: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -78,7 +80,12 @@ impl Application {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ApplicationHandler<UserEvent> for Application {
 | 
					impl ApplicationHandler<UserEvent> for Application {
 | 
				
			||||||
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
 | 
					    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
 | 
				
			||||||
        let app = GameWindow::new(self.client.clone(), self.proxy.clone(), SimId::Player1);
 | 
					        let app = GameWindow::new(
 | 
				
			||||||
 | 
					            self.client.clone(),
 | 
				
			||||||
 | 
					            self.proxy.clone(),
 | 
				
			||||||
 | 
					            self.persistence.clone(),
 | 
				
			||||||
 | 
					            SimId::Player1,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        let wrapper = Viewport::new(event_loop, self.icon.clone(), Box::new(app));
 | 
					        let wrapper = Viewport::new(event_loop, self.icon.clone(), Box::new(app));
 | 
				
			||||||
        self.focused = Some(wrapper.id());
 | 
					        self.focused = Some(wrapper.id());
 | 
				
			||||||
        self.viewports.insert(wrapper.id(), wrapper);
 | 
					        self.viewports.insert(wrapper.id(), wrapper);
 | 
				
			||||||
| 
						 | 
					@ -177,7 +184,12 @@ impl ApplicationHandler<UserEvent> for Application {
 | 
				
			||||||
                self.open(event_loop, Box::new(input));
 | 
					                self.open(event_loop, Box::new(input));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            UserEvent::OpenPlayer2 => {
 | 
					            UserEvent::OpenPlayer2 => {
 | 
				
			||||||
                let p2 = GameWindow::new(self.client.clone(), self.proxy.clone(), SimId::Player2);
 | 
					                let p2 = GameWindow::new(
 | 
				
			||||||
 | 
					                    self.client.clone(),
 | 
				
			||||||
 | 
					                    self.proxy.clone(),
 | 
				
			||||||
 | 
					                    self.persistence.clone(),
 | 
				
			||||||
 | 
					                    SimId::Player2,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
                self.open(event_loop, Box::new(p2));
 | 
					                self.open(event_loop, Box::new(p2));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ use std::sync::mpsc;
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    app::UserEvent,
 | 
					    app::UserEvent,
 | 
				
			||||||
    emulator::{EmulatorClient, EmulatorCommand, SimId},
 | 
					    emulator::{EmulatorClient, EmulatorCommand, SimId},
 | 
				
			||||||
 | 
					    persistence::Persistence,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use egui::{
 | 
					use egui::{
 | 
				
			||||||
    ecolor::HexColor, menu, Align2, Button, CentralPanel, Color32, Context, Direction, Frame,
 | 
					    ecolor::HexColor, menu, Align2, Button, CentralPanel, Color32, Context, Direction, Frame,
 | 
				
			||||||
| 
						 | 
					@ -10,6 +11,7 @@ use egui::{
 | 
				
			||||||
    ViewportId, WidgetText, Window,
 | 
					    ViewportId, WidgetText, Window,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use egui_toast::{Toast, Toasts};
 | 
					use egui_toast::{Toast, Toasts};
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use winit::event_loop::EventLoopProxy;
 | 
					use winit::event_loop::EventLoopProxy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{
 | 
					use super::{
 | 
				
			||||||
| 
						 | 
					@ -35,22 +37,28 @@ const COLOR_PRESETS: [[Color32; 2]; 3] = [
 | 
				
			||||||
pub struct GameWindow {
 | 
					pub struct GameWindow {
 | 
				
			||||||
    client: EmulatorClient,
 | 
					    client: EmulatorClient,
 | 
				
			||||||
    proxy: EventLoopProxy<UserEvent>,
 | 
					    proxy: EventLoopProxy<UserEvent>,
 | 
				
			||||||
 | 
					    persistence: Persistence,
 | 
				
			||||||
    sim_id: SimId,
 | 
					    sim_id: SimId,
 | 
				
			||||||
    display_mode: DisplayMode,
 | 
					    config: GameConfig,
 | 
				
			||||||
    colors: [Color32; 2],
 | 
					 | 
				
			||||||
    screen: Option<GameScreen>,
 | 
					    screen: Option<GameScreen>,
 | 
				
			||||||
    messages: Option<mpsc::Receiver<Toast>>,
 | 
					    messages: Option<mpsc::Receiver<Toast>>,
 | 
				
			||||||
    color_picker: Option<ColorPickerState>,
 | 
					    color_picker: Option<ColorPickerState>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl GameWindow {
 | 
					impl GameWindow {
 | 
				
			||||||
    pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>, sim_id: SimId) -> Self {
 | 
					    pub fn new(
 | 
				
			||||||
 | 
					        client: EmulatorClient,
 | 
				
			||||||
 | 
					        proxy: EventLoopProxy<UserEvent>,
 | 
				
			||||||
 | 
					        persistence: Persistence,
 | 
				
			||||||
 | 
					        sim_id: SimId,
 | 
				
			||||||
 | 
					    ) -> Self {
 | 
				
			||||||
 | 
					        let config = load_config(&persistence, sim_id);
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            client,
 | 
					            client,
 | 
				
			||||||
            proxy,
 | 
					            proxy,
 | 
				
			||||||
 | 
					            persistence,
 | 
				
			||||||
            sim_id,
 | 
					            sim_id,
 | 
				
			||||||
            display_mode: DisplayMode::Anaglyph,
 | 
					            config,
 | 
				
			||||||
            colors: COLOR_PRESETS[0],
 | 
					 | 
				
			||||||
            screen: None,
 | 
					            screen: None,
 | 
				
			||||||
            messages: None,
 | 
					            messages: None,
 | 
				
			||||||
            color_picker: None,
 | 
					            color_picker: None,
 | 
				
			||||||
| 
						 | 
					@ -99,7 +107,7 @@ impl GameWindow {
 | 
				
			||||||
                    let label = format!("x{scale}");
 | 
					                    let label = format!("x{scale}");
 | 
				
			||||||
                    let scale = scale as f32;
 | 
					                    let scale = scale as f32;
 | 
				
			||||||
                    let dims = {
 | 
					                    let dims = {
 | 
				
			||||||
                        let Vec2 { x, y } = self.display_mode.proportions();
 | 
					                        let Vec2 { x, y } = self.config.display_mode.proportions();
 | 
				
			||||||
                        Vec2::new(x * scale, y * scale + 22.0)
 | 
					                        Vec2::new(x * scale, y * scale + 22.0)
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    if ui
 | 
					                    if ui
 | 
				
			||||||
| 
						 | 
					@ -113,49 +121,46 @@ impl GameWindow {
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ui.menu_button("Display Mode", |ui| {
 | 
					            ui.menu_button("Display Mode", |ui| {
 | 
				
			||||||
                let old_proportions = self.display_mode.proportions();
 | 
					                let old_proportions = self.config.display_mode.proportions();
 | 
				
			||||||
                if ui
 | 
					                let mut changed = false;
 | 
				
			||||||
                    .selectable_option(&mut self.display_mode, DisplayMode::Anaglyph, "Anaglyph")
 | 
					                let mut display_mode = self.config.display_mode;
 | 
				
			||||||
                    .clicked()
 | 
					                changed |= ui
 | 
				
			||||||
                {
 | 
					                    .selectable_option(&mut display_mode, DisplayMode::Anaglyph, "Anaglyph")
 | 
				
			||||||
                    ui.close_menu();
 | 
					                    .clicked();
 | 
				
			||||||
                }
 | 
					                changed |= ui
 | 
				
			||||||
                if ui
 | 
					                    .selectable_option(&mut display_mode, DisplayMode::LeftEye, "Left Eye")
 | 
				
			||||||
                    .selectable_option(&mut self.display_mode, DisplayMode::LeftEye, "Left Eye")
 | 
					                    .clicked();
 | 
				
			||||||
                    .clicked()
 | 
					                changed |= ui
 | 
				
			||||||
                {
 | 
					                    .selectable_option(&mut display_mode, DisplayMode::RightEye, "Right Eye")
 | 
				
			||||||
                    ui.close_menu();
 | 
					                    .clicked();
 | 
				
			||||||
                }
 | 
					                changed |= ui
 | 
				
			||||||
                if ui
 | 
					                    .selectable_option(&mut display_mode, DisplayMode::SideBySide, "Side by Side")
 | 
				
			||||||
                    .selectable_option(&mut self.display_mode, DisplayMode::RightEye, "Right Eye")
 | 
					                    .clicked();
 | 
				
			||||||
                    .clicked()
 | 
					
 | 
				
			||||||
                {
 | 
					                if !changed {
 | 
				
			||||||
                    ui.close_menu();
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if ui
 | 
					 | 
				
			||||||
                    .selectable_option(
 | 
					 | 
				
			||||||
                        &mut self.display_mode,
 | 
					 | 
				
			||||||
                        DisplayMode::SideBySide,
 | 
					 | 
				
			||||||
                        "Side by Side",
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                    .clicked()
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    ui.close_menu();
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let new_proportions = self.display_mode.proportions();
 | 
					                let current_dims = {
 | 
				
			||||||
 | 
					                    let viewport = ctx.input(|i| i.viewport().inner_rect.unwrap());
 | 
				
			||||||
 | 
					                    viewport.max - viewport.min
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let new_proportions = display_mode.proportions();
 | 
				
			||||||
                let scale = new_proportions / old_proportions;
 | 
					                let scale = new_proportions / old_proportions;
 | 
				
			||||||
                if scale != Vec2::new(1.0, 1.0) {
 | 
					                if scale != Vec2::new(1.0, 1.0) {
 | 
				
			||||||
                    let current_dims = ctx.input(|i| i.viewport().inner_rect.unwrap());
 | 
					 | 
				
			||||||
                    let current_dims = current_dims.max - current_dims.min;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    ctx.send_viewport_cmd(ViewportCommand::InnerSize(current_dims * scale));
 | 
					                    ctx.send_viewport_cmd(ViewportCommand::InnerSize(current_dims * scale));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.update_config(|c| {
 | 
				
			||||||
 | 
					                    c.display_mode = display_mode;
 | 
				
			||||||
 | 
					                    c.dimensions = current_dims * scale;
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                ui.close_menu();
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            ui.menu_button("Colors", |ui| {
 | 
					            ui.menu_button("Colors", |ui| {
 | 
				
			||||||
                for preset in COLOR_PRESETS {
 | 
					                for preset in COLOR_PRESETS {
 | 
				
			||||||
                    if ui.color_pair_button(preset[0], preset[1]).clicked() {
 | 
					                    if ui.color_pair_button(preset[0], preset[1]).clicked() {
 | 
				
			||||||
                        self.colors = preset;
 | 
					                        self.update_config(|c| c.colors = preset);
 | 
				
			||||||
                        ui.close_menu();
 | 
					                        ui.close_menu();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -168,8 +173,12 @@ impl GameWindow {
 | 
				
			||||||
                        if is_running {
 | 
					                        if is_running {
 | 
				
			||||||
                            self.client.send_command(EmulatorCommand::Pause);
 | 
					                            self.client.send_command(EmulatorCommand::Pause);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                        let color_codes = [
 | 
				
			||||||
 | 
					                            color_str(self.config.colors[0]),
 | 
				
			||||||
 | 
					                            color_str(self.config.colors[1]),
 | 
				
			||||||
 | 
					                        ];
 | 
				
			||||||
                        self.color_picker = Some(ColorPickerState {
 | 
					                        self.color_picker = Some(ColorPickerState {
 | 
				
			||||||
                            color_codes: [color_str(self.colors[0]), color_str(self.colors[1])],
 | 
					                            color_codes,
 | 
				
			||||||
                            just_opened: true,
 | 
					                            just_opened: true,
 | 
				
			||||||
                            unpause_on_close: is_running,
 | 
					                            unpause_on_close: is_running,
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
| 
						 | 
					@ -223,18 +232,21 @@ impl GameWindow {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn show_color_picker(&mut self, ui: &mut Ui) {
 | 
					    fn show_color_picker(&mut self, ui: &mut Ui) {
 | 
				
			||||||
 | 
					        let mut colors = self.config.colors;
 | 
				
			||||||
        let Some(state) = self.color_picker.as_mut() else {
 | 
					        let Some(state) = self.color_picker.as_mut() else {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let open = ui
 | 
					        let (open, updated) = ui
 | 
				
			||||||
            .horizontal(|ui| {
 | 
					            .horizontal(|ui| {
 | 
				
			||||||
                let left_color = ui.color_picker(&mut self.colors[0], &mut state.color_codes[0]);
 | 
					                let left_color = ui.color_picker(&mut colors[0], &mut state.color_codes[0]);
 | 
				
			||||||
                if state.just_opened {
 | 
					                if state.just_opened {
 | 
				
			||||||
                    left_color.request_focus();
 | 
					                    left_color.request_focus();
 | 
				
			||||||
                    state.just_opened = false;
 | 
					                    state.just_opened = false;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                let right_color = ui.color_picker(&mut self.colors[1], &mut state.color_codes[1]);
 | 
					                let right_color = ui.color_picker(&mut colors[1], &mut state.color_codes[1]);
 | 
				
			||||||
                left_color.has_focus() || right_color.has_focus()
 | 
					                let open = left_color.has_focus() || right_color.has_focus();
 | 
				
			||||||
 | 
					                let updated = left_color.changed() || right_color.changed();
 | 
				
			||||||
 | 
					                (open, updated)
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .inner;
 | 
					            .inner;
 | 
				
			||||||
        if !open {
 | 
					        if !open {
 | 
				
			||||||
| 
						 | 
					@ -243,6 +255,38 @@ impl GameWindow {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            self.color_picker = None;
 | 
					            self.color_picker = None;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if updated {
 | 
				
			||||||
 | 
					            self.update_config(|c| c.colors = colors);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn update_config(&mut self, update: impl FnOnce(&mut GameConfig)) {
 | 
				
			||||||
 | 
					        let mut new_config = self.config.clone();
 | 
				
			||||||
 | 
					        update(&mut new_config);
 | 
				
			||||||
 | 
					        if self.config != new_config {
 | 
				
			||||||
 | 
					            let _ = self
 | 
				
			||||||
 | 
					                .persistence
 | 
				
			||||||
 | 
					                .save_config(config_filename(self.sim_id), &new_config);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.config = new_config;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn config_filename(sim_id: SimId) -> &'static str {
 | 
				
			||||||
 | 
					    match sim_id {
 | 
				
			||||||
 | 
					        SimId::Player1 => "config_p1",
 | 
				
			||||||
 | 
					        SimId::Player2 => "config_p2",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn load_config(persistence: &Persistence, sim_id: SimId) -> GameConfig {
 | 
				
			||||||
 | 
					    if let Ok(config) = persistence.load_config(config_filename(sim_id)) {
 | 
				
			||||||
 | 
					        return config;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    GameConfig {
 | 
				
			||||||
 | 
					        display_mode: DisplayMode::Anaglyph,
 | 
				
			||||||
 | 
					        colors: COLOR_PRESETS[0],
 | 
				
			||||||
 | 
					        dimensions: DisplayMode::Anaglyph.proportions() + Vec2::new(0.0, 22.0),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -255,13 +299,18 @@ impl AppWindow for GameWindow {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn initial_viewport(&self) -> ViewportBuilder {
 | 
					    fn initial_viewport(&self) -> ViewportBuilder {
 | 
				
			||||||
        let dimensions = self.display_mode.proportions() + Vec2::new(0.0, 22.0);
 | 
					 | 
				
			||||||
        ViewportBuilder::default()
 | 
					        ViewportBuilder::default()
 | 
				
			||||||
            .with_title("Lemur")
 | 
					            .with_title("Lemur")
 | 
				
			||||||
            .with_inner_size(dimensions)
 | 
					            .with_inner_size(self.config.dimensions)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn show(&mut self, ctx: &Context) {
 | 
					    fn show(&mut self, ctx: &Context) {
 | 
				
			||||||
 | 
					        let dimensions = {
 | 
				
			||||||
 | 
					            let bounds = ctx.input(|i| i.viewport().inner_rect.unwrap());
 | 
				
			||||||
 | 
					            bounds.max - bounds.min
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        self.update_config(|c| c.dimensions = dimensions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut toasts = Toasts::new()
 | 
					        let mut toasts = Toasts::new()
 | 
				
			||||||
            .anchor(Align2::LEFT_BOTTOM, (10.0, 10.0))
 | 
					            .anchor(Align2::LEFT_BOTTOM, (10.0, 10.0))
 | 
				
			||||||
            .direction(Direction::BottomUp);
 | 
					            .direction(Direction::BottomUp);
 | 
				
			||||||
| 
						 | 
					@ -289,7 +338,7 @@ impl AppWindow for GameWindow {
 | 
				
			||||||
        let frame = Frame::central_panel(&ctx.style()).fill(Color32::BLACK);
 | 
					        let frame = Frame::central_panel(&ctx.style()).fill(Color32::BLACK);
 | 
				
			||||||
        CentralPanel::default().frame(frame).show(ctx, |ui| {
 | 
					        CentralPanel::default().frame(frame).show(ctx, |ui| {
 | 
				
			||||||
            if let Some(screen) = self.screen.as_mut() {
 | 
					            if let Some(screen) = self.screen.as_mut() {
 | 
				
			||||||
                screen.update(self.display_mode, self.colors);
 | 
					                screen.update(self.config.display_mode, self.config.colors);
 | 
				
			||||||
                ui.add(screen);
 | 
					                ui.add(screen);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
| 
						 | 
					@ -383,3 +432,10 @@ struct ColorPickerState {
 | 
				
			||||||
    just_opened: bool,
 | 
					    just_opened: bool,
 | 
				
			||||||
    unpause_on_close: bool,
 | 
					    unpause_on_close: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
 | 
				
			||||||
 | 
					struct GameConfig {
 | 
				
			||||||
 | 
					    display_mode: DisplayMode,
 | 
				
			||||||
 | 
					    colors: [Color32; 2],
 | 
				
			||||||
 | 
					    dimensions: Vec2,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
use std::{collections::HashMap, sync::Arc};
 | 
					use std::{collections::HashMap, sync::Arc};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use egui::{Color32, Rgba, Vec2, Widget};
 | 
					use egui::{Color32, Rgba, Vec2, Widget};
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use wgpu::{util::DeviceExt as _, BindGroup, BindGroupLayout, Buffer, RenderPipeline};
 | 
					use wgpu::{util::DeviceExt as _, BindGroup, BindGroupLayout, Buffer, RenderPipeline};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::graphics::TextureSink;
 | 
					use crate::graphics::TextureSink;
 | 
				
			||||||
| 
						 | 
					@ -260,7 +261,7 @@ impl Colors {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 | 
					#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
 | 
				
			||||||
pub enum DisplayMode {
 | 
					pub enum DisplayMode {
 | 
				
			||||||
    Anaglyph,
 | 
					    Anaglyph,
 | 
				
			||||||
    LeftEye,
 | 
					    LeftEye,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue