Skip to content

Commit a9f536e

Browse files
authored
Merge pull request #166 from dbalsom/0.4.0/rfd
Merge RFD - native file dialog support
2 parents e597918 + dd88eba commit a9f536e

File tree

27 files changed

+961
-407
lines changed

27 files changed

+961
-407
lines changed

.cargo/config.toml

+5
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ rustflags = [
66
"-C", "link-arg=--max-memory=4294967296",
77
"--cfg", "getrandom_backend=\"wasm_js\""
88
]
9+
10+
[target.x86_64-pc-windows-msvc]
11+
rustflags = [
12+
"-C", "link-args=/STACK:8388608",
13+
]

Cargo.lock

+5-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/frontends/martypc_eframe/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ markdown = ["dep:egui_commonmark", "marty_egui/markdown"]
114114
# Use winit (disabled for wasm builds)
115115
use_winit = ["dep:egui-winit"]
116116
# Use the wgpu backend
117-
use_wgpu = ["eframe/wgpu", "marty_frontend_common/use_wgpu", "display_manager_eframe/use_wgpu"]
117+
use_wgpu = ["eframe/wgpu", "marty_frontend_common/use_wgpu", "display_manager_eframe/use_wgpu", "marty_egui/scaler_ui"]
118118
# Use the glow backend
119119
use_glow = ["eframe/glow", "display_manager_eframe/use_glow"]
120120
# Use serialport

crates/frontends/martypc_eframe/src/app.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
use crate::{
2828
emulator::Emulator,
2929
emulator_builder::EmulatorBuilder,
30-
event_loop::{egui_events::FileSelectionContext, thread_events::handle_thread_event},
30+
event_loop::thread_events::handle_thread_event,
3131
timestep_update::process_update,
3232
MARTY_ICON,
3333
};
@@ -42,6 +42,7 @@ use display_manager_eframe::{
4242
use marty_egui_eframe::{context::GuiRenderContext, EGUI_MENU_BAR_HEIGHT};
4343
use marty_frontend_common::{
4444
display_manager::{DisplayManager, DmGuiOptions},
45+
thread_events::*,
4546
timestep_manager::TimestepManager,
4647
};
4748
use marty_web_helpers::FetchResult;
@@ -72,12 +73,6 @@ use marty_web_helpers::console_writer::ConsoleWriter;
7273
#[cfg(target_arch = "wasm32")]
7374
use url::Url;
7475

75-
#[derive(Clone, Debug)]
76-
pub enum FileOpenContext {
77-
FloppyDiskImage { drive_select: usize, fsc: FileSelectionContext },
78-
CartridgeImage { slot_select: usize, fsc: FileSelectionContext },
79-
}
80-
8176
/// We derive Deserialize/Serialize so we can persist app state on shutdown.
8277
#[derive(serde::Deserialize, serde::Serialize)]
8378
#[serde(default)] // if we add new fields, give them default values when deserializing old state
@@ -610,11 +605,11 @@ impl eframe::App for MartyApp {
610605
let surface = dtc.surface().unwrap();
611606
let texture = surface.read().unwrap().backing_texture();
612607
let uv_rect = egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0));
613-
log::debug!(
614-
"Drawing main display with glow: {}x{}",
615-
texture.size()[0],
616-
texture.size()[1]
617-
);
608+
// log::trace!(
609+
// "Drawing main display with glow: {}x{}",
610+
// texture.size()[0],
611+
// texture.size()[1]
612+
// );
618613
ui.painter().image(texture.id(), rect, uv_rect, egui::Color32::WHITE);
619614

620615
// let _ = dm.with_surface_mut(DtHandle::MAIN, |backend, surface| {

crates/frontends/martypc_eframe/src/emulator/mod.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,22 @@ pub mod joystick_state;
3232
pub mod keyboard_state;
3333
pub mod mouse_state;
3434

35+
use anyhow::Error;
3536
use display_manager_eframe::EFrameDisplayManager;
37+
use fluxfox::DiskImage;
38+
use marty_config::ConfigFileParams;
3639
use std::{
3740
cell::RefCell,
3841
ffi::{OsStr, OsString},
3942
rc::Rc,
43+
sync::Arc,
4044
};
4145

42-
use anyhow::Error;
43-
use marty_config::ConfigFileParams;
44-
4546
#[cfg(target_arch = "wasm32")]
4647
use crate::wasm::file_open;
4748
use crate::{
48-
app::FileOpenContext,
4949
counter::Counter,
5050
emulator::{joystick_state::JoystickData, keyboard_state::KeyboardData, mouse_state::MouseData},
51-
event_loop::{egui_events::FileSelectionContext, thread_events::FrontendThreadEvent},
5251
input::HotkeyManager,
5352
sound::SoundInterface,
5453
};
@@ -64,6 +63,7 @@ use marty_frontend_common::{
6463
floppy_manager::FloppyManager,
6564
resource_manager::ResourceManager,
6665
rom_manager::RomManager,
66+
thread_events::{FileOpenContext, FileSelectionContext, FrontendThreadEvent},
6767
timestep_manager::PerfSnapshot,
6868
vhd_manager::VhdManager,
6969
};
@@ -98,8 +98,8 @@ pub struct Emulator {
9898
pub perf: PerfSnapshot,
9999
pub hkm: HotkeyManager,
100100
pub si: Option<SoundInterface>,
101-
pub receiver: crossbeam_channel::Receiver<FrontendThreadEvent>,
102-
pub sender: crossbeam_channel::Sender<FrontendThreadEvent>,
101+
pub receiver: crossbeam_channel::Receiver<FrontendThreadEvent<Arc<DiskImage>>>,
102+
pub sender: crossbeam_channel::Sender<FrontendThreadEvent<Arc<DiskImage>>>,
103103
}
104104

105105
impl Emulator {
@@ -287,7 +287,10 @@ impl Emulator {
287287
}
288288

289289
/// Insert floppy disks into floppy drives.
290-
pub fn insert_floppies(&mut self, sender: crossbeam_channel::Sender<FrontendThreadEvent>) -> Result<(), Error> {
290+
pub fn insert_floppies(
291+
&mut self,
292+
sender: crossbeam_channel::Sender<FrontendThreadEvent<Arc<DiskImage>>>,
293+
) -> Result<(), Error> {
291294
let floppy_max = self.machine.bus().floppy_drive_ct();
292295
let mut image_names: Vec<Option<String>> = vec![None; floppy_max];
293296

crates/frontends/martypc_eframe/src/emulator_builder/builder.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -720,8 +720,11 @@ impl EmulatorBuilder {
720720
// A DisplayManager is front-end specific, so we'll expect the front-end to create one
721721
// after we have built the emulator.
722722

723+
// Create a channel for receiving thread events (File open requests, etc.)
724+
let (sender, receiver) = crossbeam_channel::unbounded();
725+
723726
// Create a GUI state object
724-
let mut gui = GuiState::new(exec_control.clone());
727+
let mut gui = GuiState::new(exec_control.clone(), sender.clone());
725728

726729
// Set list of virtual serial ports
727730
gui.set_serial_ports(machine.bus().enumerate_serial_ports());
@@ -759,9 +762,6 @@ impl EmulatorBuilder {
759762
// TODO: This should probably be converted into a channel
760763
let machine_events = Vec::new();
761764

762-
// Create a channel for receiving background events
763-
let (sender, receiver) = crossbeam_channel::unbounded();
764-
765765
Ok(Emulator {
766766
rm: resource_manager,
767767
romm: rom_manager,

crates/frontends/martypc_eframe/src/event_loop/egui_events.rs

+90-48
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,13 @@ use std::{
3838
time::Duration,
3939
};
4040

41-
use crate::{
42-
app::FileOpenContext,
43-
emulator,
44-
emulator::Emulator,
45-
event_loop::thread_events::FrontendThreadEvent,
46-
floppy::load_floppy::handle_load_floppy,
47-
};
41+
use crate::{emulator, emulator::Emulator, floppy::load_floppy::handle_load_floppy};
4842
use display_manager_eframe::EFrameDisplayManager;
4943

5044
use marty_frontend_common::{
5145
constants::{LONG_NOTIFICATION_TIME, NORMAL_NOTIFICATION_TIME, SHORT_NOTIFICATION_TIME},
5246
floppy_manager::FloppyError,
47+
thread_events::{FileSelectionContext, FrontendThreadEvent},
5348
types::floppy::FloppyImageSource,
5449
};
5550

@@ -90,12 +85,6 @@ use std::thread::spawn;
9085
#[cfg(target_arch = "wasm32")]
9186
use crate::wasm::worker::spawn_closure_worker as spawn;
9287

93-
#[derive(Clone, Debug)]
94-
pub enum FileSelectionContext {
95-
Index(usize),
96-
Path(PathBuf),
97-
}
98-
9988
//noinspection RsBorrowChecker
10089
pub fn handle_egui_event(emu: &mut Emulator, dm: &mut EFrameDisplayManager, gui_event: &GuiEvent) {
10190
match gui_event {
@@ -380,41 +369,41 @@ pub fn handle_egui_event(emu: &mut Emulator, dm: &mut EFrameDisplayManager, gui_
380369
Some(name) => {
381370
log::info!("Loading cart image: {:?} into slot: {}", name, slot_select);
382371

383-
// match emu.cart_manager.load_cart_data(*item_idx, &emu.rm).await {
384-
// Ok(cart_image) => match cart_slot.insert_cart(*slot_select, cart_image) {
385-
// Ok(()) => {
386-
// log::info!("Cart image successfully loaded into slot: {}", slot_select);
387-
//
388-
// emu.gui.set_cart_selection(
389-
// *slot_select,
390-
// Some(*item_idx),
391-
// Some(name.clone().into()),
392-
// );
393-
//
394-
// emu.gui
395-
// .toasts()
396-
// .info(format!("Cartridge inserted: {:?}", name.clone()))
397-
// .duration(Some(NORMAL_NOTIFICATION_TIME));
398-
//
399-
// // Inserting a cartridge reboots the machine due to a switch in the cartridge slot.
400-
// reboot = true;
401-
// }
402-
// Err(err) => {
403-
// log::error!("Cart image failed to load into slot {}: {}", slot_select, err);
404-
// emu.gui
405-
// .toasts()
406-
// .error(format!("Cartridge load failed: {}", err))
407-
// .duration(Some(NORMAL_NOTIFICATION_TIME));
408-
// }
409-
// },
410-
// Err(err) => {
411-
// log::error!("Failed to load cart image: {:?} Error: {}", item_idx, err);
412-
// emu.gui
413-
// .toasts()
414-
// .error(format!("Cartridge load failed: {}", err))
415-
// .duration(Some(NORMAL_NOTIFICATION_TIME));
416-
// }
417-
// }
372+
match emu.cart_manager.load_cart_data(*item_idx, &mut emu.rm) {
373+
Ok(cart_image) => match cart_slot.insert_cart(*slot_select, cart_image) {
374+
Ok(()) => {
375+
log::info!("Cart image successfully loaded into slot: {}", slot_select);
376+
377+
emu.gui.set_cart_selection(
378+
*slot_select,
379+
Some(*item_idx),
380+
Some(name.clone().into()),
381+
);
382+
383+
emu.gui
384+
.toasts()
385+
.info(format!("Cartridge inserted: {:?}", name.clone()))
386+
.duration(Some(NORMAL_NOTIFICATION_TIME));
387+
388+
// Inserting a cartridge reboots the machine due to a switch in the cartridge slot.
389+
reboot = true;
390+
}
391+
Err(err) => {
392+
log::error!("Cart image failed to load into slot {}: {}", slot_select, err);
393+
emu.gui
394+
.toasts()
395+
.error(format!("Cartridge load failed: {}", err))
396+
.duration(Some(NORMAL_NOTIFICATION_TIME));
397+
}
398+
},
399+
Err(err) => {
400+
log::error!("Failed to load cart image: {:?} Error: {}", item_idx, err);
401+
emu.gui
402+
.toasts()
403+
.error(format!("Cartridge load failed: {}", err))
404+
.duration(Some(NORMAL_NOTIFICATION_TIME));
405+
}
406+
}
418407
}
419408
None => {
420409
emu.gui
@@ -453,13 +442,66 @@ pub fn handle_egui_event(emu: &mut Emulator, dm: &mut EFrameDisplayManager, gui_
453442
log::debug!("Requesting floppy load dialog for drive: {}", drive_select);
454443
#[cfg(target_arch = "wasm32")]
455444
{
445+
use marty_frontend_common::thread_events::FileOpenContext;
456446
let context = FileOpenContext::FloppyDiskImage {
457447
drive_select: *drive_select,
458448
fsc: FileSelectionContext::Path(PathBuf::new()),
459449
};
460450
file_open::open_file_dialog(context, emu.sender.clone());
461451
}
462452
}
453+
GuiEvent::RequestSaveFloppyDialog(drive_select, format) => {
454+
// User requested a file dialog to load a floppy image into the indicated drive slot.
455+
log::debug!(
456+
"Requesting floppy save dialog for drive: {}, format: {:?}",
457+
drive_select,
458+
format
459+
);
460+
// TODO: Implement save floppy image on web
461+
// ImageBuilder needs to be able to accept a Writer (`with_writer` perhaps?)
462+
#[cfg(target_arch = "wasm32")]
463+
{
464+
// if let Some(fdc) = emu.machine.fdc() {
465+
// let (disk_image_opt, _) = fdc.get_image(*drive_select);
466+
// if let Some(floppy_image) = disk_image_opt {
467+
// let mut image = floppy_image.write().unwrap();
468+
// match fluxfox::ImageWriter::new(&mut image)
469+
// .with_format(*format)
470+
// .with_path(filepath.clone())
471+
// .write()
472+
// {
473+
// Ok(_) => {
474+
// log::info!("Floppy image successfully saved: {:?}", filepath);
475+
//
476+
// emu.gui.set_floppy_selection(
477+
// *drive_select,
478+
// None,
479+
// FloppyDriveSelection::Image(filepath.clone()),
480+
// Some(*format),
481+
// image.compatible_formats(true),
482+
// None,
483+
// );
484+
//
485+
// emu.gui
486+
// .toasts()
487+
// .info(format!("Floppy saved: {:?}", filepath.file_name().unwrap_or_default()))
488+
// .duration(Some(NORMAL_NOTIFICATION_TIME));
489+
// }
490+
// Err(err) => {
491+
// log::error!("Floppy image failed to save: {}", err);
492+
//
493+
// emu.gui
494+
// .toasts()
495+
// .error(format!("Failed to save: {}", err))
496+
// .duration(Some(NORMAL_NOTIFICATION_TIME));
497+
// }
498+
// }
499+
// }
500+
// }
501+
502+
//file_save::save_file_dialog(context, emu.sender.clone());
503+
}
504+
}
463505
GuiEvent::LoadQuickFloppy(drive_select, item_idx) => {
464506
// User selected a floppy image from the quick access menu.
465507
log::debug!("Load floppy quick image: {:?} into drive: {}", item_idx, drive_select);

0 commit comments

Comments
 (0)