emulator: use egui file pickers rather than native ones

TODO: Add file types when picking? This is a regression
This commit is contained in:
2025-06-22 02:12:26 +01:00
parent bbf893290f
commit 83259b9217
2 changed files with 128 additions and 45 deletions
+11 -2
View File
@@ -17,14 +17,23 @@ required-features = ["config"]
common = { path = "../common" }
assembler = { path = "../assembler" }
dsa_editor = { path = "../dsa_editor" }
eframe = "0.31.1"
eframe = { version = "0.31.1" }
egui = "0.31.1"
rfd = "0.15.3"
dirs = "6.0.0"
discord-presence = { version = "1.6.0", optional = true }
toml = { version = "0.8.23", optional = true }
serde = { version = "1.0.219", features = ["derive"], optional = true }
egui_file = "0.22.1"
# Add support for Android for the fun of it.
[target.'cfg(target_os = "android")'.dependencies]
winit = { version = "0.30.11", features = ["android-native-activity"] }
# jni = "0.21.1"
[target.'cfg(target_os = "android")'.dependencies.eframe]
version = "0.31.1"
features = ["android-native-activity"]
[features]
default = ["config"]
+117 -43
View File
@@ -1,10 +1,14 @@
use std::{ffi::OsStr, path::PathBuf, sync::mpsc::Sender};
use std::{
ffi::OsStr,
path::{Path, PathBuf},
sync::mpsc::Sender,
};
use common::prelude::Instruction;
use egui::{Align, Context, Key, Layout, Ui};
use rfd::FileDialog;
use dsa_editor::{CodeEditor, ColorTheme, Syntax};
use egui_file::FileDialog;
use crate::emulator::{
system::model::{Command, State},
@@ -29,6 +33,10 @@ pub struct Editor {
cursor_col: usize,
cursor_line: usize,
// file dialogs
open_file_dialog: Option<FileDialog>,
save_file_dialog: Option<FileDialog>,
// other
visible: bool,
sender: Sender<Command>,
@@ -98,6 +106,8 @@ impl Editor {
load_offset: 0,
offset_str: String::new(),
error: None,
open_file_dialog: None,
save_file_dialog: None,
}
}
@@ -130,36 +140,31 @@ impl Editor {
}
fn save(&mut self) {
let work_dir = std::env::current_dir().unwrap_or_else(|_| {
dirs::home_dir().expect(
"Couldn't get your current working directory or your home directory.",
)
});
if let Some(path) = &self.path {
if let Err(why) = std::fs::write(path, &self.text) {
self.error = Some(format!("Failed to save file: {why}"));
return;
}
self.buffer = self.text.clone();
self.unsaved = false;
return;
if self.open_file_dialog.is_some() {
// TODO: Flash an error stating you can only have one menu open at once.
self.open_file_dialog = None;
}
if let Some(path) = FileDialog::new()
.add_filter("Assembly Files or Binaries", &["dsa", "dsb"])
.add_filter("all", &["*"])
.set_directory(&work_dir)
.save_file()
{
if let Err(why) = std::fs::write(&path, &self.text) {
if let Some(path) = &self.path {
// Save to existing path
if let Err(why) = std::fs::write(path, &self.text) {
self.error = Some(format!("Failed to save file: {why}"));
} else {
self.path = Some(path);
self.buffer = self.text.clone();
self.unsaved = false;
}
} else {
// Open the save dialog.
let work_dir = std::env::current_dir().unwrap_or_else(|_| {
dirs::home_dir().expect(
"Couldn't get your current working directory or your home directory.",
)
});
if self.save_file_dialog.is_none() {
let mut dialog = FileDialog::save_file(Some(work_dir));
dialog.open();
self.save_file_dialog = Some(dialog);
}
}
}
@@ -170,26 +175,93 @@ impl Editor {
)
});
if let Some(path) = FileDialog::new()
.add_filter("Assembly Files or Binaries", &["dsa", "dsb"])
.add_filter("all", &["*"])
.set_directory(&work_dir)
.pick_file()
{
if let Ok(contents) = std::fs::read_to_string(&path) {
self.path = Some(path.clone());
self.text.clone_from(&contents);
self.buffer = contents;
self.unsaved = false;
}
if self.save_file_dialog.is_some() {
// TODO: Flash an error stating you can only have one menu open at once.
self.save_file_dialog = None;
}
std::env::set_current_dir(
path.parent().expect("A file should be in a directory!"),
)
.expect("ERROR: Failed to set current working directory.");
if self.open_file_dialog.is_none() {
if let Some(p) = &self.path {
let path = p.parent().map(Path::to_path_buf);
let mut dialog = FileDialog::open_file(path);
dialog.open();
self.open_file_dialog = Some(dialog);
} else {
let mut dialog = FileDialog::open_file(Some(work_dir));
dialog.open();
self.open_file_dialog = Some(dialog);
}
}
}
fn handle_file_dialogs(&mut self, ctx: &egui::Context) {
// Handle open dialog
if let Some(dialog) = &mut self.open_file_dialog {
if dialog.show(ctx).selected() {
if let Some(file) = dialog.path() {
match std::fs::read_to_string(file) {
Ok(content) => {
self.text = content;
self.path = Some(file.to_path_buf());
self.unsaved = false;
self.error = None;
}
Err(e) => {
self.error = Some(format!("Failed to read file: {e}"));
}
}
}
self.open_file_dialog = None;
}
}
// Handle save dialog
if let Some(dialog) = &mut self.save_file_dialog {
if dialog.show(ctx).selected() {
if let Some(file) = dialog.path() {
match std::fs::write(file, &self.text) {
Ok(()) => {
self.path = Some(file.to_path_buf());
self.unsaved = false;
self.error = None;
}
Err(e) => {
self.error = Some(format!("Failed to save file: {e}"));
}
}
}
self.save_file_dialog = None;
}
}
}
// fn open(&mut self) {
// let work_dir = std::env::current_dir().unwrap_or_else(|_| {
// dirs::home_dir().expect(
// "Couldn't get your current working directory or your home directory.",
// )
// });
// if let Some(path) = FileDialog::new()
// .add_filter("Assembly Files or Binaries", &["dsa", "dsb"])
// .add_filter("all", &["*"])
// .set_directory(&work_dir)
// .pick_file()
// {
// if let Ok(contents) = std::fs::read_to_string(&path) {
// self.path = Some(path.clone());
// self.text.clone_from(&contents);
// self.buffer = contents;
// self.unsaved = false;
// }
// std::env::set_current_dir(
// path.parent().expect("A file should be in a directory!"),
// )
// .expect("ERROR: Failed to set current working directory.");
// }
// }
fn render_output(&self, _state: &mut State, ui: &mut Ui, _ctx: &Context) {
// Output area with synchronized scrolling
egui::ScrollArea::vertical()
@@ -316,7 +388,9 @@ impl Editor {
});
}
fn render_toolbar(&mut self, _state: &mut State, ui: &mut Ui, _ctx: &Context) {
fn render_toolbar(&mut self, _state: &mut State, ui: &mut Ui, ctx: &Context) {
self.handle_file_dialogs(ctx);
ui.horizontal(|ui| {
ui.label(format!("File type: {}", self.extension()));
ui.label(format!("Filename: {}", self.filename()));