emulator: use egui file pickers rather than native ones
TODO: Add file types when picking? This is a regression
This commit is contained in:
+11
-2
@@ -17,14 +17,23 @@ required-features = ["config"]
|
|||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
assembler = { path = "../assembler" }
|
assembler = { path = "../assembler" }
|
||||||
dsa_editor = { path = "../dsa_editor" }
|
dsa_editor = { path = "../dsa_editor" }
|
||||||
eframe = "0.31.1"
|
eframe = { version = "0.31.1" }
|
||||||
egui = "0.31.1"
|
egui = "0.31.1"
|
||||||
rfd = "0.15.3"
|
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
discord-presence = { version = "1.6.0", optional = true }
|
discord-presence = { version = "1.6.0", optional = true }
|
||||||
toml = { version = "0.8.23", optional = true }
|
toml = { version = "0.8.23", optional = true }
|
||||||
serde = { version = "1.0.219", features = ["derive"], 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"] }
|
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]
|
[features]
|
||||||
default = ["config"]
|
default = ["config"]
|
||||||
|
|||||||
@@ -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 common::prelude::Instruction;
|
||||||
use egui::{Align, Context, Key, Layout, Ui};
|
use egui::{Align, Context, Key, Layout, Ui};
|
||||||
use rfd::FileDialog;
|
|
||||||
|
|
||||||
use dsa_editor::{CodeEditor, ColorTheme, Syntax};
|
use dsa_editor::{CodeEditor, ColorTheme, Syntax};
|
||||||
|
use egui_file::FileDialog;
|
||||||
|
|
||||||
use crate::emulator::{
|
use crate::emulator::{
|
||||||
system::model::{Command, State},
|
system::model::{Command, State},
|
||||||
@@ -29,6 +33,10 @@ pub struct Editor {
|
|||||||
cursor_col: usize,
|
cursor_col: usize,
|
||||||
cursor_line: usize,
|
cursor_line: usize,
|
||||||
|
|
||||||
|
// file dialogs
|
||||||
|
open_file_dialog: Option<FileDialog>,
|
||||||
|
save_file_dialog: Option<FileDialog>,
|
||||||
|
|
||||||
// other
|
// other
|
||||||
visible: bool,
|
visible: bool,
|
||||||
sender: Sender<Command>,
|
sender: Sender<Command>,
|
||||||
@@ -98,6 +106,8 @@ impl Editor {
|
|||||||
load_offset: 0,
|
load_offset: 0,
|
||||||
offset_str: String::new(),
|
offset_str: String::new(),
|
||||||
error: None,
|
error: None,
|
||||||
|
open_file_dialog: None,
|
||||||
|
save_file_dialog: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,35 +140,30 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn save(&mut self) {
|
fn save(&mut self) {
|
||||||
|
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) = &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.unsaved = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Open the save dialog.
|
||||||
let work_dir = std::env::current_dir().unwrap_or_else(|_| {
|
let work_dir = std::env::current_dir().unwrap_or_else(|_| {
|
||||||
dirs::home_dir().expect(
|
dirs::home_dir().expect(
|
||||||
"Couldn't get your current working directory or your home directory.",
|
"Couldn't get your current working directory or your home directory.",
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(path) = &self.path {
|
if self.save_file_dialog.is_none() {
|
||||||
if let Err(why) = std::fs::write(path, &self.text) {
|
let mut dialog = FileDialog::save_file(Some(work_dir));
|
||||||
self.error = Some(format!("Failed to save file: {why}"));
|
dialog.open();
|
||||||
return;
|
self.save_file_dialog = Some(dialog);
|
||||||
}
|
|
||||||
|
|
||||||
self.buffer = self.text.clone();
|
|
||||||
self.unsaved = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
self.error = Some(format!("Failed to save file: {why}"));
|
|
||||||
} else {
|
|
||||||
self.path = Some(path);
|
|
||||||
self.buffer = self.text.clone();
|
|
||||||
self.unsaved = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,25 +175,92 @@ impl Editor {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(path) = FileDialog::new()
|
if self.save_file_dialog.is_some() {
|
||||||
.add_filter("Assembly Files or Binaries", &["dsa", "dsb"])
|
// TODO: Flash an error stating you can only have one menu open at once.
|
||||||
.add_filter("all", &["*"])
|
self.save_file_dialog = None;
|
||||||
.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(
|
if self.open_file_dialog.is_none() {
|
||||||
path.parent().expect("A file should be in a directory!"),
|
if let Some(p) = &self.path {
|
||||||
)
|
let path = p.parent().map(Path::to_path_buf);
|
||||||
.expect("ERROR: Failed to set current working directory.");
|
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) {
|
fn render_output(&self, _state: &mut State, ui: &mut Ui, _ctx: &Context) {
|
||||||
// Output area with synchronized scrolling
|
// Output area with synchronized scrolling
|
||||||
@@ -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.horizontal(|ui| {
|
||||||
ui.label(format!("File type: {}", self.extension()));
|
ui.label(format!("File type: {}", self.extension()));
|
||||||
ui.label(format!("Filename: {}", self.filename()));
|
ui.label(format!("Filename: {}", self.filename()));
|
||||||
|
|||||||
Reference in New Issue
Block a user