diff --git a/dsa/emulator/emulator_ui/src/ui/controller.rs b/dsa/emulator/emulator_ui/src/ui/controller.rs index 64f451d..3e01d33 100644 --- a/dsa/emulator/emulator_ui/src/ui/controller.rs +++ b/dsa/emulator/emulator_ui/src/ui/controller.rs @@ -28,30 +28,26 @@ impl Controller { .show(ui, |ui| { ui.horizontal(|ui| { + use RunningState::*; let status = self.emulator.status(); - let padding = Vec2::new(14.0, 8.0); match status { - RunningState::Paused | RunningState::Breakpoint(_) => { + Paused | Breakpoint(_) => if PaddedWidget::button("▶ Run").color(Color32::GREEN).ui(ui).clicked() { self.emulator.request_resume() } - }, - - RunningState::Running | RunningState::Halted => { + Running | Halted => if PaddedWidget::button("⏸ Pause").color(Color32::YELLOW).ui(ui).clicked() { self.emulator.request_pause() } - } - - RunningState::Shutdown => { + Shutdown => { ui.add_enabled_ui(false, |ui| { PaddedWidget::button("▶ Run").color(Color32::GREEN).ui(ui); }); } } - if PaddedWidget::indicator(status).ui(ui).clicked() {} + PaddedWidget::indicator(status).ui(ui); if PaddedWidget::button("⟳ Reset All").color(Color32::ORANGE).ui(ui).clicked() { self.emulator.when_paused(|emu| emu.reset()); @@ -83,19 +79,16 @@ impl Controller { ui.separator(); - let pcx = self.emulator.get_register(Register::Pcx); let clock = self.emulator.clock(); - let time = self.emulator.time().as_micros(); - - let mips = if time != 0 { - clock as u128 / time - } else { - 0 - }; - PaddedWidget::label(format!("Clock: {clock}")).ui(ui); + + let pcx = self.emulator.get_register(Register::Pcx); PaddedWidget::label( format!("Pcx: 0x{pcx:08X}")).ui(ui); + + let time = self.emulator.time().as_micros(); PaddedWidget::label( format!("Elapsed: {} micros", time)).ui(ui); + + let mips = (clock as u128).checked_div(time).unwrap_or(0); PaddedWidget::label(format!("Freq: {}MHz", mips)).ui(ui); }); }); diff --git a/dsa/emulator/emulator_ui/src/ui/mod.rs b/dsa/emulator/emulator_ui/src/ui/mod.rs index 444ba9e..296a28d 100644 --- a/dsa/emulator/emulator_ui/src/ui/mod.rs +++ b/dsa/emulator/emulator_ui/src/ui/mod.rs @@ -85,6 +85,7 @@ pub struct DamnSimpleUI { tools: Vec, + show_process_manager: bool, process_manager: ProcessManager } @@ -119,7 +120,7 @@ impl eframe::App for DamnSimpleUI { // TODO: File Explorer! }); - Panel::bottom("bottom_panel").resizable(true).show(ui, |ui| { + Panel::bottom("bottom_panel").resizable(true).show_collapsible(ui, &mut self.show_process_manager,|ui| { self.process_manager.ui(ui); }); @@ -184,6 +185,7 @@ impl DamnSimpleUI { }) ], emulator, + show_process_manager: true, process_manager: ProcessManager::new() } } diff --git a/dsa/emulator/emulator_ui/src/ui/panels/editor/mod.rs b/dsa/emulator/emulator_ui/src/ui/panels/editor/mod.rs index 4617744..ef5bd44 100644 --- a/dsa/emulator/emulator_ui/src/ui/panels/editor/mod.rs +++ b/dsa/emulator/emulator_ui/src/ui/panels/editor/mod.rs @@ -1,17 +1,21 @@ use crate::ui::Action; use crate::ui::panels::TilePane; use common::process::{ProcessAgent, TraceableProcess}; -use egui::{Key, Ui}; -use egui_code_editor::CodeEditor; +use egui::{Color32, Key, Ui, Widget}; +use egui_code_editor::{CodeEditor, Completer, Syntax}; use egui_tiles::TileId; use std::any::Any; +use std::fs::File; use std::io::Error; use std::path::{Path, PathBuf}; use std::thread; use std::time::Duration; use assembler::prelude::Assembler; +use common::formats::binary_dse::DseExecutable; use theme::THEME; use crate::ui::DataSource::Data; +use crate::ui::panels::editor::syntax::SyntaxFrom; +use crate::ui::ui_helpers::PaddedWidget; mod syntax; mod theme; @@ -20,6 +24,8 @@ pub struct Editor { buffer: String, filename: Option, editor: CodeEditor, + syntax: Syntax, + completer: Completer, } impl Default for Editor { @@ -28,15 +34,22 @@ impl Default for Editor { buffer: String::new(), filename: None, editor: CodeEditor::default().with_fontsize(12.0).with_theme(THEME).with_numlines(true), + syntax: Syntax::default(), + completer: Completer::default().with_auto_indent().with_user_words(), } } } impl Editor { pub fn new_open(path: &Path) -> Self { + let syntax = Syntax::from_file(path).unwrap_or(syntax::dsa()); Self { buffer: std::fs::read_to_string(path).unwrap(), filename: Some(path.to_path_buf()), + syntax: syntax.clone(), + completer: Completer::new_with_syntax(&syntax) + .with_auto_indent() + .with_user_words(), ..Default::default() } } @@ -52,6 +65,21 @@ impl Editor { pub fn get_buffer(&mut self) -> &mut String { &mut self.buffer } + + pub fn build_cmd(&self, filename: PathBuf, on_complete: impl FnOnce(DseExecutable) -> Action + Send + 'static) -> Action { + Action::SpawnProcess(Box::new(move |pm| { + let builder = Assembler::new(filename); + pm.spawn( + builder.label(), + builder, + move |result| match result { + Ok(bin) => on_complete(bin), + Err(e) => Action::ShowError(e.to_string()), + + } + ); + })) + } } impl TilePane for Editor { @@ -62,56 +90,62 @@ impl TilePane for Editor { } fn ui(&mut self, ui: &mut Ui, tile_id: TileId) -> Option { + let mut action = Action::None; - let response = egui::Panel::top("panel").show(ui, |ui| { - let mut action = None; + egui::Panel::top("panel").show(ui, |ui| { + ui.horizontal(|ui| { - if let Some(filename) = self.filename.as_ref() { - ui.label(filename.display().to_string()); - } else { - ui.label("New File*"); - } + if PaddedWidget::button("Build & Load").ui(ui).clicked() { + let Some(filename) = self.filename.clone() else { + action = Action::ShowError("Error - no filename set".to_string()); + return; + }; - if ui.button("Build").clicked() { - - let Some(filename) = self.filename.clone() else { - println!("error!"); - return None; - }; - - action = Some(Action::SpawnProcess(Box::new(move |pm| { - pm.spawn( - "Assembler", - Assembler::new(filename), - move |result| { - return if let Ok(bin) = result { - Action::LoadBinary(Data(bin.to_memory_image())) - } else { - Action::None - } + action = self.build_cmd( + filename, |res| { + Action::LoadBinary(Data(res.to_memory_image())) } ); - }))); - }; + } - action + if PaddedWidget::button("Build").ui(ui).clicked() { + let Some(filename) = self.filename.clone() else { + action = Action::ShowError("Error - no filename set".to_string()); + return; + }; + + action = self.build_cmd( + filename.clone(), move |res| { + let filename = filename.with_extension("dsb"); + let mut writer = File::create(&filename).unwrap(); + res.write(&mut writer).unwrap(); + Action::OpenFile(filename) + } + ); + } + + + + PaddedWidget::label( + self.filename + .as_ref() + .map(|f| f.display().to_string()) + .unwrap_or_else(|| String::from("New File")) + ).color(Color32::DARK_GRAY).ui(ui); + }); }); - if let Some(action) = response.inner { - return Some(action); - } - - self.editor.show(ui, &mut self.buffer, &syntax::dsa()); + self.editor.show_with_completer(ui, &mut self.buffer, &self.syntax, &mut self.completer); if ui.input(|i| i.key_pressed(Key::S) && i.modifiers.ctrl) { - return if let Some(filename) = self.filename.clone() { - Some(Action::SaveFile(filename, tile_id)) + action = if let Some(filename) = self.filename.clone() { + Action::SaveFile(filename, tile_id) } else { - Some(Action::RequestSaveAs(tile_id)) + Action::RequestSaveAs(tile_id) } }; - None + Some(action) } fn as_any_mut(&mut self) -> &mut dyn Any { self } diff --git a/dsa/emulator/emulator_ui/src/ui/panels/editor/syntax.rs b/dsa/emulator/emulator_ui/src/ui/panels/editor/syntax.rs index 1755831..1c5a686 100644 --- a/dsa/emulator/emulator_ui/src/ui/panels/editor/syntax.rs +++ b/dsa/emulator/emulator_ui/src/ui/panels/editor/syntax.rs @@ -1,6 +1,21 @@ use std::collections::BTreeSet; - +use std::path::{Path, PathBuf}; use egui_code_editor::{Patch, Syntax}; + +pub trait SyntaxFrom { + fn from_file(f: &Path) -> Option; +} + +impl SyntaxFrom for Syntax { + fn from_file(f: &Path) -> Option { + match f.extension()?.to_str()? { + "dsa" => Some(dsa()), + "dsc" => Some(dsc()), + _ => None, + } + } +} + pub fn dsa() -> Syntax { Syntax { word_start: BTreeSet::new(), diff --git a/dsa/emulator/emulator_ui/src/ui/panels/mod.rs b/dsa/emulator/emulator_ui/src/ui/panels/mod.rs index 95248e1..c7fc067 100644 --- a/dsa/emulator/emulator_ui/src/ui/panels/mod.rs +++ b/dsa/emulator/emulator_ui/src/ui/panels/mod.rs @@ -9,8 +9,8 @@ pub mod registers; pub mod serial; use std::any::Any; -use eframe::epaint::Color32; -use egui::{Id, Response, Sense, TextStyle, Ui, WidgetInfo, WidgetType}; +use eframe::epaint::{Color32, CornerRadius}; +use egui::{Id, Response, Sense, Stroke, TextStyle, Ui, WidgetInfo, WidgetType}; use egui_tiles::{Behavior, Container, SimplificationOptions, TabState, Tile, TileId, Tiles, Tree, UiResponse}; use crate::ui::Action; use crate::ui::Action::RequestCloseTab; @@ -56,8 +56,9 @@ impl Behavior for TileBehavior { pane: &mut Box, ) -> UiResponse { egui::Frame::new() + .corner_radius(CornerRadius::same(4)) .inner_margin(egui::Margin::same(10)) - .stroke(ui.visuals().widgets.active.bg_stroke) + .stroke(Stroke::new(2.0, Color32::DARK_GRAY)) .show(ui, |ui| { if let Some(action) = pane.ui(ui, tile_id) { self.pending_action = Some(action); @@ -67,26 +68,6 @@ impl Behavior for TileBehavior { UiResponse::None } - fn tab_ui( - &mut self, - tiles: &mut Tiles, - ui: &mut Ui, - id: Id, - tile_id: TileId, - state: &TabState, - ) -> Response { - let title = self.tab_title_for_tile(tiles, tile_id); - let draggable = self.is_tile_draggable(tiles, tile_id); - - let tab = painted_tab(ui, id, title, state.active, state.closable, draggable); - - if tab.close_clicked && self.on_tab_close(tiles, tile_id) { - tiles.remove(tile_id); - } - - self.on_tab_button(tiles, tile_id, tab.response) - } - fn tab_title_for_pane(&mut self, pane: &Pane) -> egui::WidgetText { pane.title() } @@ -109,6 +90,26 @@ impl Behavior for TileBehavior { true } + fn tab_ui( + &mut self, + tiles: &mut Tiles, + ui: &mut Ui, + id: Id, + tile_id: TileId, + state: &TabState, + ) -> Response { + let title = self.tab_title_for_tile(tiles, tile_id); + let draggable = self.is_tile_draggable(tiles, tile_id); + + let tab = painted_tab(ui, id, title, state.active, state.closable, draggable); + + if tab.close_clicked && self.on_tab_close(tiles, tile_id) { + tiles.remove(tile_id); + } + + self.on_tab_button(tiles, tile_id, tab.response) + } + fn tab_bar_height(&self, _style: &egui::Style) -> f32 { 36.0 // taller tab row = more vertical padding around the label }