mirror of https://codeberg.org/topola/topola.git
feat(selection): BBox selection should span all currently visible layers
In Via, is_in_layer, `from_layer` and `to_layer` were swapped, this has been also fixed here.
This commit is contained in:
parent
a16eba8891
commit
ea6df23b95
|
|
@ -246,7 +246,9 @@ impl MenuBar {
|
|||
workspace.overlay.unselect_all();
|
||||
} else if actions.edit.select_all.consume_key_triggered(ctx, ui) {
|
||||
let board = workspace.interactor.invoker().autorouter().board();
|
||||
workspace.overlay.select_all(board);
|
||||
workspace
|
||||
.overlay
|
||||
.select_all(board, &workspace.appearance_panel);
|
||||
} else if actions.place.place_via.consume_key_enabled(
|
||||
ctx,
|
||||
ui,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ use topola::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::appearance_panel::AppearancePanel;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum SelectionMode {
|
||||
Addition,
|
||||
|
|
@ -55,9 +57,14 @@ impl Overlay {
|
|||
core::mem::replace(&mut self.selection, Selection::new())
|
||||
}
|
||||
|
||||
pub fn select_all(&mut self, board: &Board<impl AccessMesadata>) {
|
||||
pub fn select_all(
|
||||
&mut self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
appearance_panel: &AppearancePanel,
|
||||
) {
|
||||
self.select_all_in_bbox(
|
||||
board,
|
||||
appearance_panel,
|
||||
&AABB::from_corners([-INF, -INF], [INF, INF]),
|
||||
BboxSelectionKind::CompletelyInside,
|
||||
);
|
||||
|
|
@ -71,6 +78,7 @@ impl Overlay {
|
|||
pub fn drag_start(
|
||||
&mut self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
appearance_panel: &AppearancePanel,
|
||||
at: Point,
|
||||
modifiers: &egui::Modifiers,
|
||||
) {
|
||||
|
|
@ -87,7 +95,12 @@ impl Overlay {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn drag_stop(&mut self, board: &Board<impl AccessMesadata>, at: Point) {
|
||||
pub fn drag_stop(
|
||||
&mut self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
appearance_panel: &AppearancePanel,
|
||||
at: Point,
|
||||
) {
|
||||
if let Some((selmode, bsk, aabb)) = self.get_bbox_reselect(at) {
|
||||
// handle bounding box selection
|
||||
self.reselect_bbox = None;
|
||||
|
|
@ -95,25 +108,30 @@ impl Overlay {
|
|||
match selmode {
|
||||
SelectionMode::Substitution => {
|
||||
self.selection = Selection::new();
|
||||
self.select_all_in_bbox(board, &aabb, bsk);
|
||||
self.select_all_in_bbox(board, appearance_panel, &aabb, bsk);
|
||||
}
|
||||
SelectionMode::Addition => {
|
||||
self.select_all_in_bbox(board, &aabb, bsk);
|
||||
self.select_all_in_bbox(board, appearance_panel, &aabb, bsk);
|
||||
}
|
||||
SelectionMode::Toggling => {
|
||||
let old_selection = self.take_selection();
|
||||
self.select_all_in_bbox(board, &aabb, bsk);
|
||||
self.select_all_in_bbox(board, appearance_panel, &aabb, bsk);
|
||||
self.selection ^= &old_selection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn click(&mut self, board: &Board<impl AccessMesadata>, at: Point) {
|
||||
pub fn click(
|
||||
&mut self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
appearance_panel: &AppearancePanel,
|
||||
at: Point,
|
||||
) {
|
||||
if self.reselect_bbox.is_some() {
|
||||
// handle bounding box selection (takes precendence over other interactions)
|
||||
// this is mostly in order to allow the user to recover from a missed/dropped drag_stop event
|
||||
self.drag_stop(board, at);
|
||||
self.drag_stop(board, appearance_panel, at);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -141,11 +159,12 @@ impl Overlay {
|
|||
pub fn select_all_in_bbox(
|
||||
&mut self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
appearance_panel: &AppearancePanel,
|
||||
aabb: &AABB<[f64; 2]>,
|
||||
bsk: BboxSelectionKind,
|
||||
) {
|
||||
self.selection
|
||||
.select_all_in_bbox(board, aabb, self.active_layer, bsk);
|
||||
.select_all_in_bbox(board, aabb, &appearance_panel.visible[..], bsk);
|
||||
}
|
||||
|
||||
pub fn ratsnest(&self) -> &Ratsnest {
|
||||
|
|
|
|||
|
|
@ -90,16 +90,17 @@ impl Viewport {
|
|||
maybe_net: Some(1234),
|
||||
}));
|
||||
} else {
|
||||
overlay.click(board, latest_point);
|
||||
overlay.click(board, layers, latest_point);
|
||||
}
|
||||
} else if response.drag_started_by(egui::PointerButton::Primary) {
|
||||
overlay.drag_start(
|
||||
board,
|
||||
layers,
|
||||
latest_point,
|
||||
&response.ctx.input(|i| i.modifiers),
|
||||
);
|
||||
} else if response.drag_stopped_by(egui::PointerButton::Primary) {
|
||||
overlay.drag_stop(board, latest_point);
|
||||
overlay.drag_stop(board, layers, latest_point);
|
||||
} else if let Some((_, bsk, cur_bbox)) =
|
||||
overlay.get_bbox_reselect(latest_point)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ impl Selection {
|
|||
&mut self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
aabb: &AABB<[f64; 2]>,
|
||||
active_layer: usize,
|
||||
layers: &[bool],
|
||||
kind: BboxSelectionKind,
|
||||
) {
|
||||
const INF: f64 = f64::INFINITY;
|
||||
|
|
@ -208,7 +208,7 @@ impl Selection {
|
|||
&AABB::<[f64; 3]>::from_corners([-INF, -INF, -INF], [INF, INF, INF]),
|
||||
) {
|
||||
let node = geom.data;
|
||||
if layout.drawing().is_node_in_layer(node, active_layer) {
|
||||
if layout.drawing().is_node_in_any_layer_of(node, layers) {
|
||||
if let Some(rsel) = ResolvedSelector::try_from_node(board, node) {
|
||||
let rseli = selectors.entry(rsel).or_default();
|
||||
rseli.0.insert(node);
|
||||
|
|
@ -236,7 +236,7 @@ impl Selection {
|
|||
),
|
||||
) {
|
||||
let node = geom.data;
|
||||
if layout.drawing().is_node_in_layer(node, active_layer)
|
||||
if layout.drawing().is_node_in_any_layer_of(node, layers)
|
||||
&& kind.matches(aabb, &layout.node_shape(node))
|
||||
{
|
||||
if let Some(rsel) = ResolvedSelector::try_from_node(board, node) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use crate::{
|
|||
collect::Collect,
|
||||
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
|
||||
gear::{GearIndex, GetNextGear},
|
||||
graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight},
|
||||
graph::{GetLayer, GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight},
|
||||
guide::Guide,
|
||||
loose::{GetPrevNextLoose, Loose, LooseIndex},
|
||||
primitive::{
|
||||
|
|
@ -1039,6 +1039,24 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_node_in_any_layer_of(
|
||||
&self,
|
||||
index: GenericNode<PrimitiveIndex, GenericIndex<CW>>,
|
||||
layers: &[bool],
|
||||
) -> bool
|
||||
where
|
||||
CW: IsInLayer,
|
||||
{
|
||||
match index {
|
||||
GenericNode::Primitive(primitive) => {
|
||||
primitive.primitive(self).is_in_any_layer_of(layers)
|
||||
}
|
||||
GenericNode::Compound(compound) => {
|
||||
self.compound_weight(compound).is_in_any_layer_of(layers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
|
||||
if let (Some(node1_net_id), Some(node2_net_id)) = (
|
||||
node1.primitive(self).maybe_net(),
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ pub trait GetLayer {
|
|||
#[enum_dispatch]
|
||||
pub trait IsInLayer {
|
||||
fn is_in_layer(&self, layer: usize) -> bool;
|
||||
|
||||
fn is_in_any_layer_of(&self, layers: &[bool]) -> bool;
|
||||
}
|
||||
|
||||
impl<T: GetLayer> IsInLayer for T {
|
||||
|
|
@ -38,6 +40,10 @@ impl<T: GetLayer> IsInLayer for T {
|
|||
fn is_in_layer(&self, layer: usize) -> bool {
|
||||
self.layer() == layer
|
||||
}
|
||||
|
||||
fn is_in_any_layer_of(&self, layers: &[bool]) -> bool {
|
||||
*layers.get(self.layer()).unwrap_or(&false)
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
|
|
|
|||
|
|
@ -69,7 +69,14 @@ impl GetMaybeNet for ViaWeight {
|
|||
|
||||
impl IsInLayer for ViaWeight {
|
||||
fn is_in_layer(&self, layer: usize) -> bool {
|
||||
self.from_layer >= layer && self.to_layer <= layer
|
||||
(self.from_layer..=self.to_layer).contains(&layer)
|
||||
}
|
||||
|
||||
fn is_in_any_layer_of(&self, layers: &[bool]) -> bool {
|
||||
layers
|
||||
.get(self.from_layer..=core::cmp::min(self.to_layer, layers.len()))
|
||||
.map(|i| i.iter().any(|j| *j))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue