Surface error notifications
This commit is contained in:
		
							parent
							
								
									25b88c622c
								
							
						
					
					
						commit
						ae04f9f73b
					
				| 
						 | 
					@ -908,6 +908,15 @@ dependencies = [
 | 
				
			||||||
 "nohash-hasher",
 | 
					 "nohash-hasher",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "egui-toast"
 | 
				
			||||||
 | 
					version = "0.15.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "95d58a44bf48161fe6a3f12386722e99bf86b2c16d23c2d04f6a48a95a5923d2"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "egui",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "egui-wgpu"
 | 
					name = "egui-wgpu"
 | 
				
			||||||
version = "0.29.1"
 | 
					version = "0.29.1"
 | 
				
			||||||
| 
						 | 
					@ -1711,6 +1720,7 @@ dependencies = [
 | 
				
			||||||
 "clap",
 | 
					 "clap",
 | 
				
			||||||
 "cpal",
 | 
					 "cpal",
 | 
				
			||||||
 "egui",
 | 
					 "egui",
 | 
				
			||||||
 | 
					 "egui-toast",
 | 
				
			||||||
 "egui-wgpu",
 | 
					 "egui-wgpu",
 | 
				
			||||||
 "egui-winit",
 | 
					 "egui-winit",
 | 
				
			||||||
 "egui_extras",
 | 
					 "egui_extras",
 | 
				
			||||||
| 
						 | 
					@ -1732,9 +1742,9 @@ dependencies = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "libc"
 | 
					name = "libc"
 | 
				
			||||||
version = "0.2.167"
 | 
					version = "0.2.168"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
 | 
					checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "libloading"
 | 
					name = "libloading"
 | 
				
			||||||
| 
						 | 
					@ -2690,15 +2700,15 @@ dependencies = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "rustix"
 | 
					name = "rustix"
 | 
				
			||||||
version = "0.38.41"
 | 
					version = "0.38.42"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
 | 
					checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "bitflags 2.6.0",
 | 
					 "bitflags 2.6.0",
 | 
				
			||||||
 "errno",
 | 
					 "errno",
 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
 "linux-raw-sys",
 | 
					 "linux-raw-sys",
 | 
				
			||||||
 "windows-sys 0.52.0",
 | 
					 "windows-sys 0.59.0",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ 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" }
 | 
				
			||||||
egui = "0.29"
 | 
					egui = "0.29"
 | 
				
			||||||
egui_extras = "0.29"
 | 
					egui_extras = "0.29"
 | 
				
			||||||
 | 
					egui-toast = "0.15"
 | 
				
			||||||
egui-winit = "0.29"
 | 
					egui-winit = "0.29"
 | 
				
			||||||
egui-wgpu = { version = "0.29", features = ["winit"] }
 | 
					egui-wgpu = { version = "0.29", features = ["winit"] }
 | 
				
			||||||
gilrs = "0.11"
 | 
					gilrs = "0.11"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ use std::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use anyhow::Result;
 | 
					use anyhow::Result;
 | 
				
			||||||
 | 
					use egui_toast::{Toast, ToastKind, ToastOptions};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{audio::Audio, graphics::TextureSink};
 | 
					use crate::{audio::Audio, graphics::TextureSink};
 | 
				
			||||||
pub use shrooms_vb_core::VBKey;
 | 
					pub use shrooms_vb_core::VBKey;
 | 
				
			||||||
| 
						 | 
					@ -139,6 +140,7 @@ pub struct Emulator {
 | 
				
			||||||
    audio_on: Arc<[AtomicBool; 2]>,
 | 
					    audio_on: Arc<[AtomicBool; 2]>,
 | 
				
			||||||
    linked: Arc<AtomicBool>,
 | 
					    linked: Arc<AtomicBool>,
 | 
				
			||||||
    renderers: HashMap<SimId, TextureSink>,
 | 
					    renderers: HashMap<SimId, TextureSink>,
 | 
				
			||||||
 | 
					    messages: HashMap<SimId, mpsc::Sender<Toast>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Emulator {
 | 
					impl Emulator {
 | 
				
			||||||
| 
						 | 
					@ -161,6 +163,7 @@ impl Emulator {
 | 
				
			||||||
            audio_on,
 | 
					            audio_on,
 | 
				
			||||||
            linked,
 | 
					            linked,
 | 
				
			||||||
            renderers: HashMap::new(),
 | 
					            renderers: HashMap::new(),
 | 
				
			||||||
 | 
					            messages: HashMap::new(),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -330,28 +333,35 @@ impl Emulator {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn handle_command(&mut self, command: EmulatorCommand) {
 | 
					    fn handle_command(&mut self, command: EmulatorCommand) {
 | 
				
			||||||
        match command {
 | 
					        match command {
 | 
				
			||||||
            EmulatorCommand::SetRenderer(sim_id, renderer) => {
 | 
					            EmulatorCommand::ConnectToSim(sim_id, renderer, messages) => {
 | 
				
			||||||
                self.renderers.insert(sim_id, renderer);
 | 
					                self.renderers.insert(sim_id, renderer);
 | 
				
			||||||
 | 
					                self.messages.insert(sim_id, messages);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            EmulatorCommand::LoadGame(sim_id, path) => {
 | 
					            EmulatorCommand::LoadGame(sim_id, path) => {
 | 
				
			||||||
                if let Err(error) = self.load_cart(sim_id, &path) {
 | 
					                if let Err(error) = self.load_cart(sim_id, &path) {
 | 
				
			||||||
                    eprintln!("error loading rom: {}", error);
 | 
					                    self.report_error(sim_id, format!("Error loading rom: {error}"));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            EmulatorCommand::StartSecondSim(path) => {
 | 
					            EmulatorCommand::StartSecondSim(path) => {
 | 
				
			||||||
                if let Err(error) = self.start_second_sim(path) {
 | 
					                if let Err(error) = self.start_second_sim(path) {
 | 
				
			||||||
                    eprintln!("error starting second sim: {}", error);
 | 
					                    self.report_error(
 | 
				
			||||||
 | 
					                        SimId::Player2,
 | 
				
			||||||
 | 
					                        format!("Error starting second sim: {error}"),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            EmulatorCommand::StopSecondSim => {
 | 
					            EmulatorCommand::StopSecondSim => {
 | 
				
			||||||
                if let Err(error) = self.stop_second_sim() {
 | 
					                if let Err(error) = self.stop_second_sim() {
 | 
				
			||||||
                    eprintln!("error stopping second sim: {}", error);
 | 
					                    self.report_error(
 | 
				
			||||||
 | 
					                        SimId::Player2,
 | 
				
			||||||
 | 
					                        format!("Error stopping second sim: {error}"),
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            EmulatorCommand::Pause => {
 | 
					            EmulatorCommand::Pause => {
 | 
				
			||||||
                for sim_id in SimId::values() {
 | 
					                for sim_id in SimId::values() {
 | 
				
			||||||
                    if let Err(error) = self.pause_sim(sim_id) {
 | 
					                    if let Err(error) = self.pause_sim(sim_id) {
 | 
				
			||||||
                        eprintln!("error pausing: {}", error);
 | 
					                        self.report_error(sim_id, format!("Error pausing: {error}"));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -375,7 +385,7 @@ impl Emulator {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            EmulatorCommand::Reset(sim_id) => {
 | 
					            EmulatorCommand::Reset(sim_id) => {
 | 
				
			||||||
                if let Err(error) = self.reset_sim(sim_id, None) {
 | 
					                if let Err(error) = self.reset_sim(sim_id, None) {
 | 
				
			||||||
                    eprintln!("error resetting sim: {}", error);
 | 
					                    self.report_error(sim_id, format!("Error resetting sim: {error}"));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            EmulatorCommand::SetKeys(sim_id, keys) => {
 | 
					            EmulatorCommand::SetKeys(sim_id, keys) => {
 | 
				
			||||||
| 
						 | 
					@ -386,18 +396,35 @@ impl Emulator {
 | 
				
			||||||
            EmulatorCommand::Exit(done) => {
 | 
					            EmulatorCommand::Exit(done) => {
 | 
				
			||||||
                for sim_id in SimId::values() {
 | 
					                for sim_id in SimId::values() {
 | 
				
			||||||
                    if let Err(error) = self.save_sram(sim_id) {
 | 
					                    if let Err(error) = self.save_sram(sim_id) {
 | 
				
			||||||
                        eprintln!("error saving sram on exit: {}", error);
 | 
					                        self.report_error(sim_id, format!("Error saving sram on exit: {error}"));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                let _ = done.send(());
 | 
					                let _ = done.send(());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn report_error(&self, sim_id: SimId, message: String) {
 | 
				
			||||||
 | 
					        let messages = self
 | 
				
			||||||
 | 
					            .messages
 | 
				
			||||||
 | 
					            .get(&sim_id)
 | 
				
			||||||
 | 
					            .or_else(|| self.messages.get(&SimId::Player1));
 | 
				
			||||||
 | 
					        if let Some(msg) = messages {
 | 
				
			||||||
 | 
					            let toast = Toast::new()
 | 
				
			||||||
 | 
					                .kind(ToastKind::Error)
 | 
				
			||||||
 | 
					                .options(ToastOptions::default().duration_in_seconds(5.0))
 | 
				
			||||||
 | 
					                .text(&message);
 | 
				
			||||||
 | 
					            if msg.send(toast).is_ok() {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        eprintln!("{}", message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub enum EmulatorCommand {
 | 
					pub enum EmulatorCommand {
 | 
				
			||||||
    SetRenderer(SimId, TextureSink),
 | 
					    ConnectToSim(SimId, TextureSink, mpsc::Sender<Toast>),
 | 
				
			||||||
    LoadGame(SimId, PathBuf),
 | 
					    LoadGame(SimId, PathBuf),
 | 
				
			||||||
    StartSecondSim(Option<PathBuf>),
 | 
					    StartSecondSim(Option<PathBuf>),
 | 
				
			||||||
    StopSecondSim,
 | 
					    StopSecondSim,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,15 @@
 | 
				
			||||||
 | 
					use std::sync::mpsc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    app::UserEvent,
 | 
					    app::UserEvent,
 | 
				
			||||||
    emulator::{EmulatorClient, EmulatorCommand, SimId},
 | 
					    emulator::{EmulatorClient, EmulatorCommand, SimId},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use egui::{
 | 
					use egui::{
 | 
				
			||||||
    ecolor::HexColor, menu, Align2, Button, CentralPanel, Color32, Context, Frame, Layout,
 | 
					    ecolor::HexColor, menu, Align2, Button, CentralPanel, Color32, Context, Direction, Frame,
 | 
				
			||||||
    Response, Sense, TopBottomPanel, Ui, Vec2, ViewportBuilder, ViewportCommand, ViewportId,
 | 
					    Layout, Response, Sense, TopBottomPanel, Ui, Vec2, ViewportBuilder, ViewportCommand,
 | 
				
			||||||
    WidgetText, Window,
 | 
					    ViewportId, WidgetText, Window,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					use egui_toast::{Toast, Toasts};
 | 
				
			||||||
use winit::event_loop::EventLoopProxy;
 | 
					use winit::event_loop::EventLoopProxy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{
 | 
					use super::{
 | 
				
			||||||
| 
						 | 
					@ -36,6 +39,7 @@ pub struct GameWindow {
 | 
				
			||||||
    display_mode: DisplayMode,
 | 
					    display_mode: DisplayMode,
 | 
				
			||||||
    colors: [Color32; 2],
 | 
					    colors: [Color32; 2],
 | 
				
			||||||
    screen: Option<GameScreen>,
 | 
					    screen: Option<GameScreen>,
 | 
				
			||||||
 | 
					    messages: Option<mpsc::Receiver<Toast>>,
 | 
				
			||||||
    color_picker: Option<ColorPickerState>,
 | 
					    color_picker: Option<ColorPickerState>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,6 +52,7 @@ impl GameWindow {
 | 
				
			||||||
            display_mode: DisplayMode::Anaglyph,
 | 
					            display_mode: DisplayMode::Anaglyph,
 | 
				
			||||||
            colors: COLOR_PRESETS[0],
 | 
					            colors: COLOR_PRESETS[0],
 | 
				
			||||||
            screen: None,
 | 
					            screen: None,
 | 
				
			||||||
 | 
					            messages: None,
 | 
				
			||||||
            color_picker: None,
 | 
					            color_picker: None,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -257,6 +262,14 @@ impl AppWindow for GameWindow {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn show(&mut self, ctx: &Context) {
 | 
					    fn show(&mut self, ctx: &Context) {
 | 
				
			||||||
 | 
					        let mut toasts = Toasts::new()
 | 
				
			||||||
 | 
					            .anchor(Align2::LEFT_BOTTOM, (10.0, 10.0))
 | 
				
			||||||
 | 
					            .direction(Direction::BottomUp);
 | 
				
			||||||
 | 
					        if let Some(messages) = self.messages.as_mut() {
 | 
				
			||||||
 | 
					            while let Ok(toast) = messages.try_recv() {
 | 
				
			||||||
 | 
					                toasts.add(toast);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        TopBottomPanel::top("menubar")
 | 
					        TopBottomPanel::top("menubar")
 | 
				
			||||||
            .exact_height(22.0)
 | 
					            .exact_height(22.0)
 | 
				
			||||||
            .show(ctx, |ui| {
 | 
					            .show(ctx, |ui| {
 | 
				
			||||||
| 
						 | 
					@ -280,13 +293,19 @@ impl AppWindow for GameWindow {
 | 
				
			||||||
                ui.add(screen);
 | 
					                ui.add(screen);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					        toasts.show(ctx);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn on_init(&mut self, render_state: &egui_wgpu::RenderState) {
 | 
					    fn on_init(&mut self, render_state: &egui_wgpu::RenderState) {
 | 
				
			||||||
        let (screen, sink) = GameScreen::init(render_state);
 | 
					        let (screen, sink) = GameScreen::init(render_state);
 | 
				
			||||||
        self.client
 | 
					        let (message_sink, message_source) = mpsc::channel();
 | 
				
			||||||
            .send_command(EmulatorCommand::SetRenderer(self.sim_id, sink));
 | 
					        self.client.send_command(EmulatorCommand::ConnectToSim(
 | 
				
			||||||
        self.screen = Some(screen)
 | 
					            self.sim_id,
 | 
				
			||||||
 | 
					            sink,
 | 
				
			||||||
 | 
					            message_sink,
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        self.screen = Some(screen);
 | 
				
			||||||
 | 
					        self.messages = Some(message_source);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn on_destroy(&mut self) {
 | 
					    fn on_destroy(&mut self) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue