mod.rs moment
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -85,6 +85,7 @@ pub struct DamnSimpleUI {
|
||||
|
||||
tools: Vec<PanelFactory>,
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<PathBuf>,
|
||||
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<Action> {
|
||||
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 }
|
||||
|
||||
@@ -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<Syntax>;
|
||||
}
|
||||
|
||||
impl SyntaxFrom for Syntax {
|
||||
fn from_file(f: &Path) -> Option<Syntax> {
|
||||
match f.extension()?.to_str()? {
|
||||
"dsa" => Some(dsa()),
|
||||
"dsc" => Some(dsc()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dsa() -> Syntax {
|
||||
Syntax {
|
||||
word_start: BTreeSet::new(),
|
||||
|
||||
@@ -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<Pane> for TileBehavior {
|
||||
pane: &mut Box<dyn TilePane>,
|
||||
) -> 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<Pane> for TileBehavior {
|
||||
UiResponse::None
|
||||
}
|
||||
|
||||
fn tab_ui(
|
||||
&mut self,
|
||||
tiles: &mut Tiles<Pane>,
|
||||
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<Pane> for TileBehavior {
|
||||
true
|
||||
}
|
||||
|
||||
fn tab_ui(
|
||||
&mut self,
|
||||
tiles: &mut Tiles<Pane>,
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user