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