Add master interactor to rule all interactors (WIP, not used yet)

This commit is contained in:
Mikolaj Wielgus 2026-05-27 17:07:18 +02:00
parent 623dc967ca
commit da7585b135
16 changed files with 200 additions and 60 deletions

View File

@ -85,7 +85,7 @@ impl Viewport {
let _ = interactor.update(
workspace.autorouter.router().navmesher_board().board(),
workspace.appearance_panel.active,
InteractiveInput::new(pointer_on_scene, false, false),
InteractiveInput::new(pointer_on_scene, false, false, false),
);
}
}
@ -98,7 +98,7 @@ impl Viewport {
let _ = interactor.update(
workspace.autorouter.router().navmesher_board().board(),
workspace.appearance_panel.active,
InteractiveInput::new(pointer_for_scene, true, false),
InteractiveInput::new(pointer_for_scene, true, false, false),
);
workspace.selection = interactor.selection().clone();

View File

@ -1,26 +0,0 @@
// SPDX-FileCopyrightText: 2026 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{
board::Board,
primitives::{JointId, PolygonId, SegmentId, ViaId},
};
impl Board {
pub fn delete_joint(&mut self, joint_id: JointId) {
self.layout.delete_joint(joint_id);
}
pub fn delete_segment(&mut self, segment_id: SegmentId) {
self.layout.delete_segment(segment_id);
}
pub fn delete_via(&mut self, via_id: ViaId) {
self.layout.delete_via(via_id);
}
pub fn delete_polygon(&mut self, polygon_id: PolygonId) {
self.layout.delete_polygon(polygon_id);
}
}

View File

@ -15,13 +15,13 @@ use crate::{
},
};
#[derive(Clone, Constructor, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(Clone, Constructor, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct DragSelectionOptions {
combine: SelectionCombineMode,
contain: SelectionContainMode,
}
#[derive(Clone, Debug, Eq, Getters, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Debug, Eq, Getters, PartialEq)]
pub struct DragSelectionInteractor {
origin: Vector2<i64>,
original_selection: PersistableSelection,

View File

@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: 2026 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use derive_getters::Getters;
use derive_more::Constructor;
use crate::{
InteractiveInput,
board::{
Board,
interactors::{SelectionCombineMode, SelectionInteractor},
selections::PersistableSelection,
},
layout::LayerId,
};
#[derive(Clone, Constructor, Debug, Eq, Getters, PartialEq)]
pub struct MasterInteractor {
selection: PersistableSelection,
selection_interactor: Option<SelectionInteractor>,
}
impl MasterInteractor {
pub fn update(&mut self, board: &mut Board, input: InteractiveInput) {
if input.delete {
board.delete_net_free_primitives(self.selection.nets.clone());
}
if self.selection_interactor.is_none() {
self.selection_interactor = Some(SelectionInteractor::new(
input.pointer,
self.selection.clone(),
SelectionCombineMode::Additive,
));
}
if let Some(selection_interactor) = self.selection_interactor.as_mut() {
if let Some(selection) =
selection_interactor.update(board, LayerId::new(0), input.clone())
{
self.selection = selection;
}
}
if input.release || input.cancel {
self.selection_interactor = None;
}
}
}

View File

@ -3,31 +3,24 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
mod drag_selection;
mod master;
mod selection;
use derive_more::Constructor;
pub use drag_selection::{DragSelectionInteractor, DragSelectionOptions};
pub use selection::SelectionInteractor;
use serde::{Deserialize, Serialize};
use crate::Vector2;
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(Clone, Constructor, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct InteractiveInput {
pointer: Vector2<i64>,
released: bool,
release: bool,
delete: bool,
cancel: bool,
}
impl InteractiveInput {
pub fn new(pointer: Vector2<i64>, released: bool, cancel: bool) -> Self {
Self {
pointer,
released,
cancel,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub enum SelectionCombineMode {
Replace,

View File

@ -17,7 +17,7 @@ use crate::{
layout::LayerId,
};
#[derive(Clone, Debug, Eq, Getters, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Debug, Eq, Getters, PartialEq)]
pub struct SelectionInteractor {
origin: Vector2<i64>,
original_selection: PersistableSelection,
@ -50,7 +50,7 @@ impl SelectionInteractor {
return Some(self.selection.clone());
}
if input.released && input.pointer == self.origin {
if input.release && input.pointer == self.origin {
let mut selection = self.original_selection.clone();
// Pins have intentional precedence over nets and components.

View File

@ -2,7 +2,6 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
mod delete;
mod insert;
pub mod interactors;
mod layer;

View File

@ -5,15 +5,91 @@
use crate::{
board::{Board, selections::ComponentSelection},
layout::compounds::ComponentId,
primitives::{JointId, PolygonId, SegmentId, ViaId},
selections::NetSelection,
};
impl Board {
pub fn resolve_components(&self, selection: ComponentSelection) -> Vec<ComponentId> {
pub fn resolve_components(
&self,
selection: ComponentSelection,
) -> impl Iterator<Item = ComponentId> {
selection
.0
.clone()
.into_iter()
.filter_map(|selector| self.component_id(&selector.component))
.collect()
}
pub fn resolve_net_joints(&self, selection: NetSelection) -> impl Iterator<Item = JointId> {
let mut resolved_joints = Vec::new();
for (index, _) in self.layout.joints().container() {
let joint_id = JointId::new(index);
let Some(selector) = self.joint_net_selector(joint_id) else {
continue;
};
if selection.0.contains(&selector) {
resolved_joints.push(joint_id);
}
}
resolved_joints.into_iter()
}
pub fn resolve_net_segments(&self, selection: NetSelection) -> impl Iterator<Item = SegmentId> {
let mut resolved_segments = Vec::new();
for (index, _) in self.layout.segments().container() {
let segment_id = SegmentId::new(index);
let Some(selector) = self.segment_net_selector(segment_id) else {
continue;
};
if selection.0.contains(&selector) {
resolved_segments.push(segment_id);
}
}
resolved_segments.into_iter()
}
pub fn resolve_net_vias(&self, selection: NetSelection) -> impl Iterator<Item = ViaId> {
let mut resolved_vias = Vec::new();
for (index, _) in self.layout.vias().container() {
let via_id = ViaId::new(index);
let Some(selector) = self.via_net_selector(via_id) else {
continue;
};
if selection.0.contains(&selector) {
resolved_vias.push(via_id);
}
}
resolved_vias.into_iter()
}
pub fn resolve_net_polygons(&self, selection: NetSelection) -> impl Iterator<Item = PolygonId> {
let mut resolved_polygons = Vec::new();
for (index, _) in self.layout.polygons().container() {
let polygon_id = PolygonId::new(index);
let Some(selector) = self.polygon_net_selector(polygon_id) else {
continue;
};
if selection.0.contains(&selector) {
resolved_polygons.push(polygon_id);
}
}
resolved_polygons.into_iter()
}
}

View File

@ -4,7 +4,7 @@
use std::collections::BTreeSet;
use derive_more::Constructor;
use derive_more::{Constructor, IntoIterator};
use serde::{Deserialize, Serialize};
#[derive(Clone, Constructor, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
@ -12,7 +12,9 @@ pub struct ComponentSelector {
pub component: String,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(
Clone, Debug, Default, Deserialize, Eq, IntoIterator, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct ComponentSelection(pub BTreeSet<ComponentSelector>);
impl ComponentSelection {

View File

@ -4,6 +4,7 @@
use std::collections::BTreeSet;
use derive_more::IntoIterator;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
@ -17,7 +18,9 @@ impl NetSelector {
}
}
#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(
Clone, Debug, Default, Deserialize, Eq, IntoIterator, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct NetSelection(pub BTreeSet<NetSelector>);
impl NetSelection {

View File

@ -4,7 +4,7 @@
use std::collections::BTreeSet;
use derive_more::Constructor;
use derive_more::{Constructor, IntoIterator};
use serde::{Deserialize, Serialize};
#[derive(
@ -15,7 +15,9 @@ pub struct PinSelector {
pub layer: String,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(
Clone, Debug, Default, Deserialize, Eq, IntoIterator, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct PinSelection(pub BTreeSet<PinSelector>);
impl PinSelection {

View File

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2026 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{Board, selections::NetSelection};
impl Board {
pub fn delete_net_free_primitives(&mut self, selection: NetSelection) {
for joint_id in self
.resolve_net_joints(selection.clone())
.collect::<Vec<_>>()
.clone()
{
self.layout.delete_joint(joint_id);
}
for segment_id in self
.resolve_net_segments(selection.clone())
.collect::<Vec<_>>()
.clone()
{
self.layout.delete_segment(segment_id);
}
for via_id in self
.resolve_net_vias(selection.clone())
.collect::<Vec<_>>()
.clone()
{
self.layout.delete_via(via_id);
}
for polygon_id in self
.resolve_net_polygons(selection.clone())
.collect::<Vec<_>>()
.clone()
{
self.layout.delete_polygon(polygon_id);
}
}
}

View File

@ -2,4 +2,5 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
mod delete;
mod move_by;

View File

@ -5,12 +5,11 @@
use crate::{Board, Vector2, layout::compounds::ComponentId, selections::ComponentSelection};
impl Board {
pub fn move_components_by(
&mut self,
selection: &ComponentSelection,
translation: Vector2<i64>,
) {
self.move_resolved_components_by(&self.resolve_components(selection.clone()), translation);
pub fn move_components_by(&mut self, selection: ComponentSelection, translation: Vector2<i64>) {
self.move_resolved_components_by(
&self.resolve_components(selection).collect::<Vec<_>>(),
translation,
);
}
pub fn move_resolved_components_by(

View File

@ -9,8 +9,7 @@ use serde::{Deserialize, Serialize};
use crate::layout::LayerId;
use crate::layout::compounds::{ComponentId, NetId, PinId};
use crate::math::Vector2;
use super::{SegmentId, ViaId};
use crate::primitives::{SegmentId, ViaId};
#[derive(
Clone,

View File

@ -18,5 +18,6 @@ pub use via::*;
pub enum PrimitiveId {
Joint(JointId),
Segment(SegmentId),
Via(ViaId),
Polygon(PolygonId),
}