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 struct Actions {
|
||||||
pub file: FileActions,
|
pub file: FileActions,
|
||||||
|
pub edit: EditActions,
|
||||||
pub run: RunActions,
|
pub run: RunActions,
|
||||||
pub debug: DebugActions,
|
pub debug: DebugActions,
|
||||||
}
|
}
|
||||||
|
|
@ -20,6 +21,7 @@ impl Actions {
|
||||||
pub fn new(tr: &Translator) -> Self {
|
pub fn new(tr: &Translator) -> Self {
|
||||||
Self {
|
Self {
|
||||||
file: FileActions::new(tr),
|
file: FileActions::new(tr),
|
||||||
|
edit: EditActions::new(tr),
|
||||||
run: RunActions::new(tr),
|
run: RunActions::new(tr),
|
||||||
debug: DebugActions::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 struct RunActions {
|
||||||
pub autoplace: Trigger,
|
pub autoplace: Trigger,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub struct Controller {
|
||||||
impl Controller {
|
impl Controller {
|
||||||
pub fn new(board: Board, tr: &Translator) -> Self {
|
pub fn new(board: Board, tr: &Translator) -> Self {
|
||||||
let appearance_panel = LayersPanel::new(&board);
|
let appearance_panel = LayersPanel::new(&board);
|
||||||
let workspace = Workspace::new_board(board);
|
let workspace = Workspace::new(board);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
master_interactor: MasterInteractor::new(workspace.selection().clone()),
|
master_interactor: MasterInteractor::new(workspace.selection().clone()),
|
||||||
|
|
@ -95,15 +95,13 @@ impl Controller {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
self.master_interactor.abort(self.workspace.board_mut());
|
||||||
self.master_interactor.abort(&mut workspace.board);
|
|
||||||
|
|
||||||
if let Some(board_master) = board_master {
|
if let Some(board_master) = board_master {
|
||||||
self.master_interactor = MasterInteractor::Board(board_master);
|
self.master_interactor = MasterInteractor::Board(board_master);
|
||||||
}
|
|
||||||
|
|
||||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let primary_pressed = ctx.input(|i| i.pointer.button_pressed(egui::PointerButton::Primary));
|
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());
|
self.master_interactor = MasterInteractor::new(self.workspace.selection().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
if primary_down {
|
||||||
if primary_down {
|
self.master_interactor.hold(
|
||||||
self.master_interactor.hold(
|
self.workspace.board_mut(),
|
||||||
&mut workspace.board,
|
self.appearance_panel.active,
|
||||||
self.appearance_panel.active,
|
pointer_on_scene,
|
||||||
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) =
|
let drag_rect_on_viewport = egui::Rect::from_min_max(
|
||||||
self.master_interactor.select_interactor().as_ref()
|
scene_to_viewport * drag_rect_scene.min,
|
||||||
{
|
scene_to_viewport * drag_rect_scene.max,
|
||||||
let origin = *select_interactor.origin();
|
);
|
||||||
let drag_rect_scene = egui::Rect::from_min_max(
|
let boundary_color = if pointer_on_scene.x >= origin.x {
|
||||||
egui::pos2(
|
egui::Color32::YELLOW
|
||||||
origin.x.min(pointer_on_scene.x) as f32,
|
} else {
|
||||||
origin.y.min(pointer_on_scene.y) as f32,
|
egui::Color32::from_rgb(80, 160, 255)
|
||||||
),
|
};
|
||||||
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(
|
ui.painter().rect(
|
||||||
scene_to_viewport * drag_rect_scene.min,
|
drag_rect_on_viewport,
|
||||||
scene_to_viewport * drag_rect_scene.max,
|
egui::CornerRadius::ZERO,
|
||||||
);
|
egui::Color32::from_rgba_unmultiplied(80, 160, 255, 48),
|
||||||
let boundary_color = if pointer_on_scene.x >= origin.x {
|
egui::Stroke::new(1.5, boundary_color),
|
||||||
egui::Color32::YELLOW
|
egui::StrokeKind::Outside,
|
||||||
} 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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,18 +172,22 @@ impl Controller {
|
||||||
.map(|select_interactor| *select_interactor.origin())
|
.map(|select_interactor| *select_interactor.origin())
|
||||||
.unwrap_or(Vector2::new(0, 0))
|
.unwrap_or(Vector2::new(0, 0))
|
||||||
});
|
});
|
||||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
|
||||||
self.master_interactor
|
if self
|
||||||
.release(&mut workspace.board, active, pointer_for_scene);
|
.master_interactor
|
||||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
.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 delete_pressed {
|
||||||
if let Workspace::Board(workspace) = &mut self.workspace {
|
self.master_interactor.delete(self.workspace.board_mut());
|
||||||
self.master_interactor.delete(&mut workspace.board);
|
self.workspace.commit();
|
||||||
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
*self.workspace.selection_mut() = self.master_interactor.selection().clone();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
use crate::{controller::Controller, viewport::Viewport};
|
use crate::{controller::Controller, viewport::Viewport};
|
||||||
use topola::{Orientation, Vector2, Workspace};
|
use topola::{Orientation, Vector2};
|
||||||
|
|
||||||
pub struct DebugOverlay {}
|
pub struct DebugOverlay {}
|
||||||
|
|
||||||
|
|
@ -267,72 +267,10 @@ impl DebugOverlay {
|
||||||
|
|
||||||
fn display_navmeshes(
|
fn display_navmeshes(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &egui::Context,
|
_ctx: &egui::Context,
|
||||||
ui: &egui::Ui,
|
_ui: &egui::Ui,
|
||||||
viewport: &Viewport,
|
_viewport: &Viewport,
|
||||||
workspace: &Controller,
|
_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,
|
menu_bar::MenuBar,
|
||||||
viewport::Viewport,
|
viewport::Viewport,
|
||||||
};
|
};
|
||||||
use topola::{
|
use topola::layout::primitives::{Joint, Poly, Seg, Via};
|
||||||
Workspace,
|
|
||||||
layout::primitives::{Joint, Poly, Seg, Via},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Display {}
|
pub struct Display {}
|
||||||
|
|
||||||
|
|
@ -252,12 +249,8 @@ impl Display {
|
||||||
workspace: &Controller,
|
workspace: &Controller,
|
||||||
) {
|
) {
|
||||||
crate::profile_function!();
|
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 layers = *ratline.endpoint_layers();
|
||||||
let endpoints = *ratline.endpoints();
|
let endpoints = *ratline.endpoints();
|
||||||
|
|
||||||
|
|
@ -267,8 +260,6 @@ impl Display {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//let stroke_width = 2.0 / viewport.scale_factor().max(1e-6);
|
|
||||||
|
|
||||||
ui.painter().line_segment(
|
ui.painter().line_segment(
|
||||||
[
|
[
|
||||||
egui::pos2(endpoints[0].x as f32, endpoints[0].y as f32),
|
egui::pos2(endpoints[0].x as f32, endpoints[0].y as f32),
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,14 @@ impl MenuBar {
|
||||||
crate::profile_function!();
|
crate::profile_function!();
|
||||||
|
|
||||||
let mut actions = Actions::new(tr);
|
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::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||||
egui::MenuBar::new().ui(ui, |ui| {
|
egui::MenuBar::new().ui(ui, |ui| {
|
||||||
|
|
@ -74,6 +82,14 @@ impl MenuBar {
|
||||||
|
|
||||||
ui.separator();
|
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());
|
actions.run.render_menu(ctx, ui, controller.is_some());
|
||||||
|
|
||||||
ui.separator();
|
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 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.master_interactor.autoplace(
|
||||||
controller.workspace.board_mut(),
|
controller.workspace.board_mut(),
|
||||||
AutoplacerSchedule {
|
AutoplacerSchedule {
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,8 @@ impl Interactor for AutoplacerMasterInteractor {
|
||||||
self.board_master.hold(board, layer, pointer);
|
self.board_master.hold(board, layer, pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.board_master.release(board, layer, pointer);
|
self.board_master.release(board, layer, pointer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abort(&mut self, board: &mut Board) {
|
fn abort(&mut self, board: &mut Board) {
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,17 @@
|
||||||
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
|
|
||||||
use crate::{board::Board, ratsnest::Ratsnest, router::Router};
|
use crate::{board::Board, router::Router};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Getters)]
|
#[derive(Clone, Debug, Getters)]
|
||||||
pub struct Autorouter {
|
pub struct Autorouter {
|
||||||
ratsnest: Ratsnest,
|
|
||||||
router: Router,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Autorouter {
|
impl Autorouter {
|
||||||
pub fn new(board: Board) -> Self {
|
pub fn new(board: Board) -> Self {
|
||||||
let ratsnest = Ratsnest::new(&board);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
router: Router::new(board),
|
router: Router::new(board),
|
||||||
ratsnest,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use undoredo::ResetDelta;
|
use undoredo::ResetDelta;
|
||||||
|
|
@ -25,8 +27,9 @@ impl Interactor for DragMoveInteractor {
|
||||||
board.move_components_by(self.selection.clone(), pointer - self.origin);
|
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);
|
self.hold(board, layer, pointer);
|
||||||
|
ControlFlow::Break(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abort(&mut self, board: &mut Board) {
|
fn abort(&mut self, board: &mut Board) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -185,8 +187,9 @@ impl Interactor for DragSelectInteractor {
|
||||||
self.selection = combined_selection;
|
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);
|
self.hold(board, layer, pointer);
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abort(&mut self, _board: &mut Board) {
|
fn abort(&mut self, _board: &mut Board) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -62,16 +64,21 @@ impl Interactor for BoardMasterInteractor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 let Some(drag_move_interactor) = self.drag_move_interactor.as_mut() {
|
let commit = if let Some(drag_move_interactor) = self.drag_move_interactor.as_mut() {
|
||||||
drag_move_interactor.release(board, layer, pointer);
|
drag_move_interactor.release(board, layer, pointer)
|
||||||
} else if let Some(select_interactor) = self.select_interactor.as_mut() {
|
} else if let Some(select_interactor) = self.select_interactor.as_mut() {
|
||||||
select_interactor.release(board, layer, pointer);
|
select_interactor.release(board, layer, pointer);
|
||||||
self.selection = select_interactor.selection().clone();
|
self.selection = select_interactor.selection().clone();
|
||||||
}
|
ControlFlow::Continue(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
};
|
||||||
|
|
||||||
self.select_interactor = None;
|
self.select_interactor = None;
|
||||||
self.drag_move_interactor = None;
|
self.drag_move_interactor = None;
|
||||||
|
|
||||||
|
commit
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abort(&mut self, board: &mut Board) {
|
fn abort(&mut self, board: &mut Board) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -56,7 +58,7 @@ impl Interactor for SelectInteractor {
|
||||||
self.selection = drag_selection_interactor.selection().clone();
|
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 {
|
if pointer == self.origin {
|
||||||
let mut selection = self.original_selection.clone();
|
let mut selection = self.original_selection.clone();
|
||||||
let point = Vector3::new(pointer.x, pointer.y, layer.index() as i64);
|
let point = Vector3::new(pointer.x, pointer.y, layer.index() as i64);
|
||||||
|
|
@ -76,10 +78,11 @@ impl Interactor for SelectInteractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.selection = selection;
|
self.selection = selection;
|
||||||
return;
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.hold(board, layer, pointer);
|
self.hold(board, layer, pointer);
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abort(&mut self, _board: &mut Board) {
|
fn abort(&mut self, _board: &mut Board) {
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,19 @@ pub trait Interactor {
|
||||||
fn step(&mut self, _board: &mut Board) -> ControlFlow<()> {
|
fn step(&mut self, _board: &mut Board) -> ControlFlow<()> {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
fn delete(&mut self, board: &mut Board) {}
|
fn delete(&mut self, board: &mut Board) {
|
||||||
fn hold(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {}
|
let _ = board;
|
||||||
fn release(&mut self, board: &mut Board, layer: LayerId, pointer: Vector2<i64>) {}
|
}
|
||||||
fn abort(&mut self, board: &mut 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 {
|
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 {
|
match self {
|
||||||
Self::Board(interactor) => interactor.release(board, layer, pointer),
|
Self::Board(interactor) => interactor.release(board, layer, pointer),
|
||||||
Self::Autoplacer(interactor) => interactor.release(board, layer, pointer),
|
Self::Autoplacer(interactor) => interactor.release(board, layer, pointer),
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ mod specctra;
|
||||||
mod vector;
|
mod vector;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
|
pub use crate::board::BoardDelta;
|
||||||
pub use crate::autoplacer::AutoplacerSchedule;
|
pub use crate::autoplacer::AutoplacerSchedule;
|
||||||
pub use crate::autorouter::Autorouter;
|
pub use crate::autorouter::Autorouter;
|
||||||
pub use crate::board::selections;
|
pub use crate::board::selections;
|
||||||
|
|
@ -30,4 +31,4 @@ pub use crate::orientation::Orientation;
|
||||||
pub use crate::ratsnest::{Ratline, Ratsnest};
|
pub use crate::ratsnest::{Ratline, Ratsnest};
|
||||||
pub use crate::rect::{Rect2, Rect3};
|
pub use crate::rect::{Rect2, Rect3};
|
||||||
pub use crate::vector::{Vector2, Vector3};
|
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 spade::{DelaunayTriangulation, HasPosition, Triangulation, handles::FixedVertexHandle};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
board::Board,
|
|
||||||
layout::{
|
layout::{
|
||||||
LayerId,
|
LayerId,
|
||||||
compounds::NetId,
|
compounds::NetId,
|
||||||
primitives::{JointId, PolyId, PrimitiveId, SegId},
|
primitives::{JointId, PolyId, PrimitiveId, SegId},
|
||||||
|
Layout,
|
||||||
},
|
},
|
||||||
vector::Vector2,
|
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 {
|
pub struct Ratsnest {
|
||||||
ratlines: Vec<Ratline>,
|
ratlines: Vec<Ratline>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ratsnest {
|
impl Ratsnest {
|
||||||
pub fn new(board: &Board) -> Self {
|
pub fn new(layout: &Layout) -> Self {
|
||||||
let mut ratlines = Vec::new();
|
let mut ratlines = Vec::new();
|
||||||
|
|
||||||
let mut triangulations: BTreeMap<(NetId, LayerId), DelaunayTriangulation<DelaunayVertex>> =
|
let mut triangulations: BTreeMap<(NetId, LayerId), DelaunayTriangulation<DelaunayVertex>> =
|
||||||
BTreeMap::new();
|
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 {
|
let Some(net) = joint.spec.net else {
|
||||||
continue;
|
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 {
|
let Some(net) = seg.net else {
|
||||||
continue;
|
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 {
|
let Some(net) = poly.spec.net else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,84 +2,67 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// 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 {
|
#[derive(Getters)]
|
||||||
Board(BoardWorkspace),
|
pub struct Workspace {
|
||||||
Autorouter(AutorouterWorkspace),
|
board: Board,
|
||||||
|
selection: PersistableSelection,
|
||||||
|
history: UndoRedo<BoardDelta>,
|
||||||
|
ratsnest: Ratsnest,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Workspace {
|
impl Workspace {
|
||||||
pub fn new_board(mut board: Board) -> Self {
|
pub fn new(mut board: Board) -> Self {
|
||||||
board.flush_delta();
|
board.flush_delta();
|
||||||
|
let ratsnest = Ratsnest::new(board.layout());
|
||||||
|
|
||||||
Self::Board(BoardWorkspace::new(board))
|
Self {
|
||||||
}
|
board,
|
||||||
|
selection: PersistableSelection::new(),
|
||||||
pub fn new_autorouter(board: Board) -> Self {
|
history: UndoRedo::new(),
|
||||||
Self::Autorouter(AutorouterWorkspace::new(board))
|
ratsnest,
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn board_mut(&mut self) -> &mut Board {
|
pub fn board_mut(&mut self) -> &mut Board {
|
||||||
match self {
|
&mut self.board
|
||||||
Workspace::Board(workspace) => &mut workspace.board,
|
}
|
||||||
Workspace::Autorouter(_workspace) => todo!(),
|
|
||||||
/*Workspace::Autorouter(workspace) => {
|
pub fn selection_mut(&mut self) -> &mut PersistableSelection {
|
||||||
workspace.autorouter.router().navmesher_board().board()
|
&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 fn redo(&mut self) -> bool {
|
||||||
pub board: Board,
|
if self.history.redo(&mut self.board).is_some() {
|
||||||
pub selection: PersistableSelection,
|
self.rebuild_ratsnest();
|
||||||
}
|
true
|
||||||
|
} else {
|
||||||
impl BoardWorkspace {
|
false
|
||||||
pub fn new(board: Board) -> Self {
|
|
||||||
Self {
|
|
||||||
board,
|
|
||||||
selection: PersistableSelection::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AutorouterWorkspace {
|
fn rebuild_ratsnest(&mut self) {
|
||||||
pub autorouter: Autorouter,
|
self.ratsnest = Ratsnest::new(self.board.layout());
|
||||||
pub selection: PersistableSelection,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AutorouterWorkspace {
|
|
||||||
pub fn new(board: Board) -> Self {
|
|
||||||
Self {
|
|
||||||
autorouter: Autorouter::new(board),
|
|
||||||
selection: PersistableSelection::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue