mirror of https://codeberg.org/topola/topola.git
Add functional Undo/Redo buttons
This commit is contained in:
parent
2cc4c52a59
commit
ffa94cff82
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
|
||||
pub struct Actions {
|
||||
pub file: FileActions,
|
||||
pub edit: EditActions,
|
||||
pub run: RunActions,
|
||||
pub debug: DebugActions,
|
||||
}
|
||||
|
|
@ -20,6 +21,7 @@ impl Actions {
|
|||
pub fn new(tr: &Translator) -> Self {
|
||||
Self {
|
||||
file: FileActions::new(tr),
|
||||
edit: EditActions::new(tr),
|
||||
run: RunActions::new(tr),
|
||||
debug: DebugActions::new(tr),
|
||||
}
|
||||
|
|
@ -76,6 +78,48 @@ impl FileActions {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct EditActions {
|
||||
pub undo: Trigger,
|
||||
pub redo: Trigger,
|
||||
}
|
||||
|
||||
impl EditActions {
|
||||
pub fn new(tr: &Translator) -> Self {
|
||||
Self {
|
||||
undo: Action::new(
|
||||
tr.text("tr-menu-edit-undo"),
|
||||
egui::Modifiers::CTRL,
|
||||
egui::Key::Z,
|
||||
)
|
||||
.into_trigger(),
|
||||
redo: Action::new(
|
||||
tr.text("tr-menu-edit-redo"),
|
||||
egui::Modifiers::CTRL,
|
||||
egui::Key::Y,
|
||||
)
|
||||
.into_trigger(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_menu(
|
||||
&mut self,
|
||||
ctx: &Context,
|
||||
ui: &mut Ui,
|
||||
have_workspace: bool,
|
||||
can_undo: bool,
|
||||
can_redo: bool,
|
||||
) {
|
||||
ui.add_enabled_ui(have_workspace, |ui| {
|
||||
ui.add_enabled_ui(can_undo, |ui| {
|
||||
self.undo.button(ctx, ui);
|
||||
});
|
||||
ui.add_enabled_ui(can_redo, |ui| {
|
||||
self.redo.button(ctx, ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunActions {
|
||||
pub autoplace: Trigger,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub struct Controller {
|
|||
impl Controller {
|
||||
pub fn new(board: Board, tr: &Translator) -> Self {
|
||||
let appearance_panel = LayersPanel::new(&board);
|
||||
let workspace = Workspace::new_board(board);
|
||||
let workspace = Workspace::new(board);
|
||||
|
||||
Self {
|
||||
master_interactor: MasterInteractor::new(workspace.selection().clone()),
|
||||
|
|
@ -95,15 +95,13 @@ impl Controller {
|
|||
None
|
||||
};
|
||||
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
self.master_interactor.abort(&mut workspace.board);
|
||||
self.master_interactor.abort(self.workspace.board_mut());
|
||||
|
||||
if let Some(board_master) = board_master {
|
||||
self.master_interactor = MasterInteractor::Board(board_master);
|
||||
}
|
||||
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
if let Some(board_master) = board_master {
|
||||
self.master_interactor = MasterInteractor::Board(board_master);
|
||||
}
|
||||
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
}
|
||||
|
||||
let primary_pressed = ctx.input(|i| i.pointer.button_pressed(egui::PointerButton::Primary));
|
||||
|
|
@ -123,47 +121,44 @@ impl Controller {
|
|||
self.master_interactor = MasterInteractor::new(self.workspace.selection().clone());
|
||||
}
|
||||
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
if primary_down {
|
||||
self.master_interactor.hold(
|
||||
&mut workspace.board,
|
||||
self.appearance_panel.active,
|
||||
pointer_on_scene,
|
||||
if primary_down {
|
||||
self.master_interactor.hold(
|
||||
self.workspace.board_mut(),
|
||||
self.appearance_panel.active,
|
||||
pointer_on_scene,
|
||||
);
|
||||
|
||||
if let Some(select_interactor) = self.master_interactor.select_interactor().as_ref()
|
||||
{
|
||||
let origin = *select_interactor.origin();
|
||||
let drag_rect_scene = egui::Rect::from_min_max(
|
||||
egui::pos2(
|
||||
origin.x.min(pointer_on_scene.x) as f32,
|
||||
origin.y.min(pointer_on_scene.y) as f32,
|
||||
),
|
||||
egui::pos2(
|
||||
origin.x.max(pointer_on_scene.x) as f32,
|
||||
origin.y.max(pointer_on_scene.y) as f32,
|
||||
),
|
||||
);
|
||||
|
||||
if let Some(select_interactor) =
|
||||
self.master_interactor.select_interactor().as_ref()
|
||||
{
|
||||
let origin = *select_interactor.origin();
|
||||
let drag_rect_scene = egui::Rect::from_min_max(
|
||||
egui::pos2(
|
||||
origin.x.min(pointer_on_scene.x) as f32,
|
||||
origin.y.min(pointer_on_scene.y) as f32,
|
||||
),
|
||||
egui::pos2(
|
||||
origin.x.max(pointer_on_scene.x) as f32,
|
||||
origin.y.max(pointer_on_scene.y) as f32,
|
||||
),
|
||||
);
|
||||
let drag_rect_on_viewport = egui::Rect::from_min_max(
|
||||
scene_to_viewport * drag_rect_scene.min,
|
||||
scene_to_viewport * drag_rect_scene.max,
|
||||
);
|
||||
let boundary_color = if pointer_on_scene.x >= origin.x {
|
||||
egui::Color32::YELLOW
|
||||
} else {
|
||||
egui::Color32::from_rgb(80, 160, 255)
|
||||
};
|
||||
|
||||
let drag_rect_on_viewport = egui::Rect::from_min_max(
|
||||
scene_to_viewport * drag_rect_scene.min,
|
||||
scene_to_viewport * drag_rect_scene.max,
|
||||
);
|
||||
let boundary_color = if pointer_on_scene.x >= origin.x {
|
||||
egui::Color32::YELLOW
|
||||
} else {
|
||||
egui::Color32::from_rgb(80, 160, 255)
|
||||
};
|
||||
|
||||
ui.painter().rect(
|
||||
drag_rect_on_viewport,
|
||||
egui::CornerRadius::ZERO,
|
||||
egui::Color32::from_rgba_unmultiplied(80, 160, 255, 48),
|
||||
egui::Stroke::new(1.5, boundary_color),
|
||||
egui::StrokeKind::Outside,
|
||||
);
|
||||
}
|
||||
ui.painter().rect(
|
||||
drag_rect_on_viewport,
|
||||
egui::CornerRadius::ZERO,
|
||||
egui::Color32::from_rgba_unmultiplied(80, 160, 255, 48),
|
||||
egui::Stroke::new(1.5, boundary_color),
|
||||
egui::StrokeKind::Outside,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -177,18 +172,22 @@ impl Controller {
|
|||
.map(|select_interactor| *select_interactor.origin())
|
||||
.unwrap_or(Vector2::new(0, 0))
|
||||
});
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
self.master_interactor
|
||||
.release(&mut workspace.board, active, pointer_for_scene);
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
|
||||
if self
|
||||
.master_interactor
|
||||
.release(self.workspace.board_mut(), active, pointer_for_scene)
|
||||
.is_break()
|
||||
{
|
||||
self.workspace.commit();
|
||||
}
|
||||
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
}
|
||||
|
||||
if delete_pressed {
|
||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
||||
self.master_interactor.delete(&mut workspace.board);
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
}
|
||||
self.master_interactor.delete(self.workspace.board_mut());
|
||||
self.workspace.commit();
|
||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{controller::Controller, viewport::Viewport};
|
||||
use topola::{Orientation, Vector2, Workspace};
|
||||
use topola::{Orientation, Vector2};
|
||||
|
||||
pub struct DebugOverlay {}
|
||||
|
||||
|
|
@ -267,72 +267,10 @@ impl DebugOverlay {
|
|||
|
||||
fn display_navmeshes(
|
||||
&mut self,
|
||||
ctx: &egui::Context,
|
||||
ui: &egui::Ui,
|
||||
viewport: &Viewport,
|
||||
workspace: &Controller,
|
||||
_ctx: &egui::Context,
|
||||
_ui: &egui::Ui,
|
||||
_viewport: &Viewport,
|
||||
_workspace: &Controller,
|
||||
) {
|
||||
crate::profile_function!();
|
||||
let Workspace::Autorouter(autorouter_workspace) = &workspace.workspace else {
|
||||
return;
|
||||
};
|
||||
let autorouter = &autorouter_workspace.autorouter;
|
||||
|
||||
for layer in workspace
|
||||
.appearance_panel
|
||||
.layers_in_display_order(*workspace.workspace.board().layout().layer_count())
|
||||
{
|
||||
if workspace.appearance_panel.visible[layer.index()] {
|
||||
for navmesh in autorouter
|
||||
.router()
|
||||
.navmesher_board()
|
||||
.navmesher()
|
||||
.layer_navmeshers()[layer.index()]
|
||||
.navmeshes()
|
||||
{
|
||||
for edge_geom in navmesh
|
||||
.triangulation()
|
||||
.rtreed_dcel()
|
||||
.edges_rtree()
|
||||
.as_ref()
|
||||
.iter()
|
||||
{
|
||||
let (from_vertex, to_vertex) = navmesh
|
||||
.triangulation()
|
||||
.rtreed_dcel()
|
||||
.dcel()
|
||||
.edge_endpoints(edge_geom.data);
|
||||
let from = navmesh
|
||||
.triangulation()
|
||||
.rtreed_dcel()
|
||||
.dcel()
|
||||
.vertex_weight(from_vertex)
|
||||
.position();
|
||||
let to = navmesh
|
||||
.triangulation()
|
||||
.rtreed_dcel()
|
||||
.dcel()
|
||||
.vertex_weight(to_vertex)
|
||||
.position();
|
||||
ui.painter().line_segment(
|
||||
[
|
||||
egui::pos2(*from.x() as f32, *from.y() as f32),
|
||||
egui::pos2(*to.x() as f32, *to.y() as f32),
|
||||
],
|
||||
egui::Stroke::new(
|
||||
10.0,
|
||||
egui::Color32::WHITE,
|
||||
/*workspace
|
||||
.appearance_panel
|
||||
.colors(ctx)
|
||||
.layers
|
||||
.color(workspace.autorouter.navmesher_board().board().layer_name(layer))
|
||||
.normal,*/
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ use crate::{
|
|||
menu_bar::MenuBar,
|
||||
viewport::Viewport,
|
||||
};
|
||||
use topola::{
|
||||
Workspace,
|
||||
layout::primitives::{Joint, Poly, Seg, Via},
|
||||
};
|
||||
use topola::layout::primitives::{Joint, Poly, Seg, Via};
|
||||
|
||||
pub struct Display {}
|
||||
|
||||
|
|
@ -252,12 +249,8 @@ impl Display {
|
|||
workspace: &Controller,
|
||||
) {
|
||||
crate::profile_function!();
|
||||
let Workspace::Autorouter(autorouter_workspace) = &workspace.workspace else {
|
||||
return;
|
||||
};
|
||||
let autorouter = &autorouter_workspace.autorouter;
|
||||
|
||||
for ratline in autorouter.ratsnest().ratlines() {
|
||||
for ratline in workspace.workspace.ratsnest().ratlines() {
|
||||
let layers = *ratline.endpoint_layers();
|
||||
let endpoints = *ratline.endpoints();
|
||||
|
||||
|
|
@ -267,8 +260,6 @@ impl Display {
|
|||
continue;
|
||||
}
|
||||
|
||||
//let stroke_width = 2.0 / viewport.scale_factor().max(1e-6);
|
||||
|
||||
ui.painter().line_segment(
|
||||
[
|
||||
egui::pos2(endpoints[0].x as f32, endpoints[0].y as f32),
|
||||
|
|
|
|||
|
|
@ -65,6 +65,14 @@ impl MenuBar {
|
|||
crate::profile_function!();
|
||||
|
||||
let mut actions = Actions::new(tr);
|
||||
let mut controller = controller;
|
||||
|
||||
let can_undo = controller
|
||||
.as_ref()
|
||||
.is_some_and(|controller| !controller.workspace.history().done().is_empty());
|
||||
let can_redo = controller
|
||||
.as_ref()
|
||||
.is_some_and(|controller| !controller.workspace.history().undone().is_empty());
|
||||
|
||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||
egui::MenuBar::new().ui(ui, |ui| {
|
||||
|
|
@ -74,6 +82,14 @@ impl MenuBar {
|
|||
|
||||
ui.separator();
|
||||
|
||||
//ui.menu_button(tr.text("tr-menu-edit"), |ui| {
|
||||
actions
|
||||
.edit
|
||||
.render_menu(ctx, ui, controller.is_some(), can_undo, can_redo);
|
||||
//});
|
||||
|
||||
ui.separator();
|
||||
|
||||
actions.run.render_menu(ctx, ui, controller.is_some());
|
||||
|
||||
ui.separator();
|
||||
|
|
@ -132,8 +148,20 @@ impl MenuBar {
|
|||
});
|
||||
}
|
||||
|
||||
if can_undo && actions.edit.undo.consume_key_triggered(ctx, ui) {
|
||||
if let Some(controller) = controller.as_mut() {
|
||||
controller.workspace.undo();
|
||||
}
|
||||
}
|
||||
|
||||
if can_redo && actions.edit.redo.consume_key_triggered(ctx, ui) {
|
||||
if let Some(controller) = controller.as_mut() {
|
||||
controller.workspace.redo();
|
||||
}
|
||||
}
|
||||
|
||||
if actions.run.autoplace.consume_key_triggered(ctx, ui) {
|
||||
if let Some(controller) = controller {
|
||||
if let Some(controller) = controller.as_mut() {
|
||||
controller.master_interactor.autoplace(
|
||||
controller.workspace.board_mut(),
|
||||
AutoplacerSchedule {
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ impl Interactor for AutoplacerMasterInteractor {
|
|||
self.board_master.hold(board, layer, pointer);
|
||||
}
|
||||
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
self.board_master.release(board, layer, pointer);
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) -> ControlFlow<()> {
|
||||
self.board_master.release(board, layer, pointer)
|
||||
}
|
||||
|
||||
fn abort(&mut self, board: &mut Board) {
|
||||
|
|
|
|||
|
|
@ -4,21 +4,17 @@
|
|||
|
||||
use derive_getters::Getters;
|
||||
|
||||
use crate::{board::Board, ratsnest::Ratsnest, router::Router};
|
||||
use crate::{board::Board, router::Router};
|
||||
|
||||
#[derive(Clone, Debug, Getters)]
|
||||
pub struct Autorouter {
|
||||
ratsnest: Ratsnest,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
impl Autorouter {
|
||||
pub fn new(board: Board) -> Self {
|
||||
let ratsnest = Ratsnest::new(&board);
|
||||
|
||||
Self {
|
||||
router: Router::new(board),
|
||||
ratsnest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use derive_getters::Getters;
|
||||
use derive_more::Constructor;
|
||||
use undoredo::ResetDelta;
|
||||
|
|
@ -25,8 +27,9 @@ impl Interactor for DragMoveInteractor {
|
|||
board.move_components_by(self.selection.clone(), pointer - self.origin);
|
||||
}
|
||||
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) -> ControlFlow<()> {
|
||||
self.hold(board, layer, pointer);
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
|
||||
fn abort(&mut self, board: &mut Board) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use derive_getters::Getters;
|
||||
use derive_more::Constructor;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -185,8 +187,9 @@ impl Interactor for DragSelectInteractor {
|
|||
self.selection = combined_selection;
|
||||
}
|
||||
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) -> ControlFlow<()> {
|
||||
self.hold(board, layer, pointer);
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn abort(&mut self, _board: &mut Board) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use derive_getters::Getters;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -62,16 +64,21 @@ impl Interactor for BoardMasterInteractor {
|
|||
}
|
||||
}
|
||||
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
if let Some(drag_move_interactor) = self.drag_move_interactor.as_mut() {
|
||||
drag_move_interactor.release(board, layer, pointer);
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) -> ControlFlow<()> {
|
||||
let commit = if let Some(drag_move_interactor) = self.drag_move_interactor.as_mut() {
|
||||
drag_move_interactor.release(board, layer, pointer)
|
||||
} else if let Some(select_interactor) = self.select_interactor.as_mut() {
|
||||
select_interactor.release(board, layer, pointer);
|
||||
self.selection = select_interactor.selection().clone();
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
};
|
||||
|
||||
self.select_interactor = None;
|
||||
self.drag_move_interactor = None;
|
||||
|
||||
commit
|
||||
}
|
||||
|
||||
fn abort(&mut self, board: &mut Board) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use derive_getters::Getters;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -56,7 +58,7 @@ impl Interactor for SelectInteractor {
|
|||
self.selection = drag_selection_interactor.selection().clone();
|
||||
}
|
||||
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) -> ControlFlow<()> {
|
||||
if pointer == self.origin {
|
||||
let mut selection = self.original_selection.clone();
|
||||
let point = Vector3::new(pointer.x, pointer.y, layer.index() as i64);
|
||||
|
|
@ -76,10 +78,11 @@ impl Interactor for SelectInteractor {
|
|||
}
|
||||
|
||||
self.selection = selection;
|
||||
return;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
self.hold(board, layer, pointer);
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn abort(&mut self, _board: &mut Board) {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,19 @@ pub trait Interactor {
|
|||
fn step(&mut self, _board: &mut Board) -> ControlFlow<()> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
fn delete(&mut self, board: &mut Board) {}
|
||||
fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {}
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {}
|
||||
fn abort(&mut self, board: &mut Board) {}
|
||||
fn delete(&mut self, board: &mut Board) {
|
||||
let _ = board;
|
||||
}
|
||||
fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
let _ = (board, layer, pointer);
|
||||
}
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) -> ControlFlow<()> {
|
||||
let _ = (board, layer, pointer);
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
fn abort(&mut self, board: &mut Board) {
|
||||
let _ = board;
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MasterInteractor {
|
||||
|
|
@ -47,7 +56,6 @@ impl MasterInteractor {
|
|||
));
|
||||
}
|
||||
_ => (),
|
||||
//_ => panic!("autoplacement can be only started from board at rest"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +102,7 @@ impl Interactor for MasterInteractor {
|
|||
}
|
||||
}
|
||||
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {
|
||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) -> ControlFlow<()> {
|
||||
match self {
|
||||
Self::Board(interactor) => interactor.release(board, layer, pointer),
|
||||
Self::Autoplacer(interactor) => interactor.release(board, layer, pointer),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ mod specctra;
|
|||
mod vector;
|
||||
mod workspace;
|
||||
|
||||
pub use crate::board::BoardDelta;
|
||||
pub use crate::autoplacer::AutoplacerSchedule;
|
||||
pub use crate::autorouter::Autorouter;
|
||||
pub use crate::board::selections;
|
||||
|
|
@ -30,4 +31,4 @@ pub use crate::orientation::Orientation;
|
|||
pub use crate::ratsnest::{Ratline, Ratsnest};
|
||||
pub use crate::rect::{Rect2, Rect3};
|
||||
pub use crate::vector::{Vector2, Vector3};
|
||||
pub use crate::workspace::{AutorouterWorkspace, BoardWorkspace, Workspace};
|
||||
pub use crate::workspace::Workspace;
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ use serde::{Deserialize, Serialize};
|
|||
use spade::{DelaunayTriangulation, HasPosition, Triangulation, handles::FixedVertexHandle};
|
||||
|
||||
use crate::{
|
||||
board::Board,
|
||||
layout::{
|
||||
LayerId,
|
||||
compounds::NetId,
|
||||
primitives::{JointId, PolyId, PrimitiveId, SegId},
|
||||
Layout,
|
||||
},
|
||||
vector::Vector2,
|
||||
};
|
||||
|
|
@ -40,19 +40,19 @@ impl HasPosition for DelaunayVertex {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Getters, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Getters, Serialize)]
|
||||
pub struct Ratsnest {
|
||||
ratlines: Vec<Ratline>,
|
||||
}
|
||||
|
||||
impl Ratsnest {
|
||||
pub fn new(board: &Board) -> Self {
|
||||
pub fn new(layout: &Layout) -> Self {
|
||||
let mut ratlines = Vec::new();
|
||||
|
||||
let mut triangulations: BTreeMap<(NetId, LayerId), DelaunayTriangulation<DelaunayVertex>> =
|
||||
BTreeMap::new();
|
||||
|
||||
for (i, joint) in board.layout().joints().container().iter() {
|
||||
for (i, joint) in layout.joints().container().iter() {
|
||||
let Some(net) = joint.spec.net else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -68,7 +68,7 @@ impl Ratsnest {
|
|||
});
|
||||
}
|
||||
|
||||
for (i, seg) in board.layout().segs().container().iter() {
|
||||
for (i, seg) in layout.segs().container().iter() {
|
||||
let Some(net) = seg.net else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -85,7 +85,7 @@ impl Ratsnest {
|
|||
});
|
||||
}
|
||||
|
||||
for (i, poly) in board.layout().polys().container().iter() {
|
||||
for (i, poly) in layout.polys().container().iter() {
|
||||
let Some(net) = poly.spec.net else {
|
||||
continue;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,84 +2,67 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use undoredo::FlushDelta;
|
||||
use derive_getters::Getters;
|
||||
use undoredo::{FlushDelta, UndoRedo};
|
||||
|
||||
use crate::{autorouter::Autorouter, board::Board, selections::PersistableSelection};
|
||||
use crate::{
|
||||
board::{Board, BoardDelta, selections::PersistableSelection},
|
||||
ratsnest::Ratsnest,
|
||||
};
|
||||
|
||||
pub enum Workspace {
|
||||
Board(BoardWorkspace),
|
||||
Autorouter(AutorouterWorkspace),
|
||||
#[derive(Getters)]
|
||||
pub struct Workspace {
|
||||
board: Board,
|
||||
selection: PersistableSelection,
|
||||
history: UndoRedo<BoardDelta>,
|
||||
ratsnest: Ratsnest,
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
pub fn new_board(mut board: Board) -> Self {
|
||||
pub fn new(mut board: Board) -> Self {
|
||||
board.flush_delta();
|
||||
let ratsnest = Ratsnest::new(board.layout());
|
||||
|
||||
Self::Board(BoardWorkspace::new(board))
|
||||
}
|
||||
|
||||
pub fn new_autorouter(board: Board) -> Self {
|
||||
Self::Autorouter(AutorouterWorkspace::new(board))
|
||||
}
|
||||
|
||||
pub fn selection(&self) -> &PersistableSelection {
|
||||
match self {
|
||||
Workspace::Board(workspace) => &workspace.selection,
|
||||
Workspace::Autorouter(workspace) => &workspace.selection,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn selection_mut(&mut self) -> &mut PersistableSelection {
|
||||
match self {
|
||||
Workspace::Board(workspace) => &mut workspace.selection,
|
||||
Workspace::Autorouter(workspace) => &mut workspace.selection,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn board(&self) -> &Board {
|
||||
match self {
|
||||
Workspace::Board(workspace) => &workspace.board,
|
||||
Workspace::Autorouter(workspace) => {
|
||||
workspace.autorouter.router().navmesher_board().board()
|
||||
}
|
||||
Self {
|
||||
board,
|
||||
selection: PersistableSelection::new(),
|
||||
history: UndoRedo::new(),
|
||||
ratsnest,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn board_mut(&mut self) -> &mut Board {
|
||||
match self {
|
||||
Workspace::Board(workspace) => &mut workspace.board,
|
||||
Workspace::Autorouter(_workspace) => todo!(),
|
||||
/*Workspace::Autorouter(workspace) => {
|
||||
workspace.autorouter.router().navmesher_board().board()
|
||||
}*/
|
||||
&mut self.board
|
||||
}
|
||||
|
||||
pub fn selection_mut(&mut self) -> &mut PersistableSelection {
|
||||
&mut self.selection
|
||||
}
|
||||
|
||||
pub fn commit(&mut self) {
|
||||
self.history.commit(&mut self.board);
|
||||
self.rebuild_ratsnest();
|
||||
}
|
||||
|
||||
pub fn undo(&mut self) -> bool {
|
||||
if self.history.undo(&mut self.board).is_some() {
|
||||
self.rebuild_ratsnest();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BoardWorkspace {
|
||||
pub board: Board,
|
||||
pub selection: PersistableSelection,
|
||||
}
|
||||
|
||||
impl BoardWorkspace {
|
||||
pub fn new(board: Board) -> Self {
|
||||
Self {
|
||||
board,
|
||||
selection: PersistableSelection::new(),
|
||||
pub fn redo(&mut self) -> bool {
|
||||
if self.history.redo(&mut self.board).is_some() {
|
||||
self.rebuild_ratsnest();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AutorouterWorkspace {
|
||||
pub autorouter: Autorouter,
|
||||
pub selection: PersistableSelection,
|
||||
}
|
||||
|
||||
impl AutorouterWorkspace {
|
||||
pub fn new(board: Board) -> Self {
|
||||
Self {
|
||||
autorouter: Autorouter::new(board),
|
||||
selection: PersistableSelection::new(),
|
||||
}
|
||||
fn rebuild_ratsnest(&mut self) {
|
||||
self.ratsnest = Ratsnest::new(self.board.layout());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue