mirror of https://codeberg.org/topola/topola.git
feat: implement bounding box selection backend
This commit is contained in:
parent
bbf54c9eb5
commit
6fbdc8f738
|
|
@ -25,14 +25,19 @@ use topola::{
|
||||||
pub struct Overlay {
|
pub struct Overlay {
|
||||||
ratsnest: Ratsnest,
|
ratsnest: Ratsnest,
|
||||||
selection: Selection,
|
selection: Selection,
|
||||||
|
pub selected_bbox: AABB<[f64; 2]>,
|
||||||
|
reselect_bbox: Option<Option<Point>>,
|
||||||
active_layer: usize,
|
active_layer: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Overlay {
|
impl Overlay {
|
||||||
pub fn new(board: &Board<impl AccessMesadata>) -> Result<Self, InsertionError> {
|
pub fn new(board: &Board<impl AccessMesadata>) -> Result<Self, InsertionError> {
|
||||||
|
const INF: f64 = f64::INFINITY;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
ratsnest: Ratsnest::new(board.layout())?,
|
ratsnest: Ratsnest::new(board.layout())?,
|
||||||
selection: Selection::new(),
|
selection: Selection::new(),
|
||||||
|
selected_bbox: AABB::from_corners([-INF, -INF], [INF, INF]),
|
||||||
|
reselect_bbox: None,
|
||||||
active_layer: 0,
|
active_layer: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +50,29 @@ impl Overlay {
|
||||||
self.selection = Selection::new();
|
self.selection = Selection::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_selected_bbox(&mut self) {
|
||||||
|
const INF: f64 = f64::INFINITY;
|
||||||
|
self.selected_bbox = AABB::from_corners([-INF, -INF], [INF, INF]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_bbox_reselect(&mut self) {
|
||||||
|
self.reselect_bbox = Some(None);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn click(&mut self, board: &Board<impl AccessMesadata>, at: Point) {
|
pub fn click(&mut self, board: &Board<impl AccessMesadata>, at: Point) {
|
||||||
|
if let Some(rsbb) = self.reselect_bbox.take() {
|
||||||
|
// handle bounding box selection (takes precendence over other interactions)
|
||||||
|
use rstar::Point;
|
||||||
|
self.reselect_bbox = match rsbb {
|
||||||
|
None => Some(Some(at)),
|
||||||
|
Some(pt) => {
|
||||||
|
self.selected_bbox = AABB::from_corners([pt.x(), pt.y()], [at.x(), at.y()]);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let geoms: Vec<_> = board
|
let geoms: Vec<_> = board
|
||||||
.layout()
|
.layout()
|
||||||
.drawing()
|
.drawing()
|
||||||
|
|
@ -121,4 +148,12 @@ impl Overlay {
|
||||||
pub fn selection(&self) -> &Selection {
|
pub fn selection(&self) -> &Selection {
|
||||||
&self.selection
|
&self.selection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the currently selected bounding box of a bounding-box reselect
|
||||||
|
pub fn get_bbox_reselect(&self, at: Point) -> Option<AABB<[f64; 2]>> {
|
||||||
|
self.reselect_bbox
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|pt| *pt)
|
||||||
|
.map(|pt| AABB::from_corners([pt.x(), pt.y()], [at.x(), at.y()]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,10 @@ impl<'a> Painter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paint_bbox(&mut self, bbox: AABB<[f64; 2]>) {
|
pub fn paint_bbox(&mut self, bbox: AABB<[f64; 2]>) {
|
||||||
|
self.paint_bbox_with_color(bbox, egui::Color32::GRAY)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paint_bbox_with_color(&mut self, bbox: AABB<[f64; 2]>, color: egui::Color32) {
|
||||||
let rect = egui::epaint::Rect {
|
let rect = egui::epaint::Rect {
|
||||||
min: [bbox.lower()[0] as f32, -bbox.upper()[1] as f32].into(),
|
min: [bbox.lower()[0] as f32, -bbox.upper()[1] as f32].into(),
|
||||||
max: [bbox.upper()[0] as f32, -bbox.lower()[1] as f32].into(),
|
max: [bbox.upper()[0] as f32, -bbox.lower()[1] as f32].into(),
|
||||||
|
|
@ -66,7 +70,7 @@ impl<'a> Painter<'a> {
|
||||||
self.ui.painter().add(egui::Shape::rect_stroke(
|
self.ui.painter().add(egui::Shape::rect_stroke(
|
||||||
self.transform * rect,
|
self.transform * rect,
|
||||||
egui::Rounding::ZERO,
|
egui::Rounding::ZERO,
|
||||||
egui::Stroke::new(1.0, egui::Color32::GRAY),
|
egui::Stroke::new(1.0, color),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ impl Viewport {
|
||||||
if let Some(workspace) = maybe_workspace {
|
if let Some(workspace) = maybe_workspace {
|
||||||
let layers = &mut workspace.appearance_panel;
|
let layers = &mut workspace.appearance_panel;
|
||||||
let overlay = &mut workspace.overlay;
|
let overlay = &mut workspace.overlay;
|
||||||
|
let latest_point = point! {x: latest_pos.x as f64, y: -latest_pos.y as f64};
|
||||||
|
|
||||||
if ctx.input(|i| i.pointer.any_click()) {
|
if ctx.input(|i| i.pointer.any_click()) {
|
||||||
if menu_bar.is_placing_via {
|
if menu_bar.is_placing_via {
|
||||||
|
|
@ -71,7 +72,7 @@ impl Viewport {
|
||||||
from_layer: 0,
|
from_layer: 0,
|
||||||
to_layer: 0,
|
to_layer: 0,
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
|
pos: latest_point,
|
||||||
r: menu_bar.autorouter_options.router_options.routed_band_width / 2.0,
|
r: menu_bar.autorouter_options.router_options.routed_band_width / 2.0,
|
||||||
},
|
},
|
||||||
maybe_net: Some(1234),
|
maybe_net: Some(1234),
|
||||||
|
|
@ -80,9 +81,11 @@ impl Viewport {
|
||||||
} else {
|
} else {
|
||||||
overlay.click(
|
overlay.click(
|
||||||
workspace.interactor.invoker().autorouter().board(),
|
workspace.interactor.invoker().autorouter().board(),
|
||||||
point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
|
latest_point,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else if let Some(cur_bbox) = overlay.get_bbox_reselect(latest_point) {
|
||||||
|
painter.paint_bbox_with_color(cur_bbox, egui::Color32::RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
let board = workspace.interactor.invoker().autorouter().board();
|
let board = workspace.interactor.invoker().autorouter().board();
|
||||||
|
|
@ -207,11 +210,20 @@ impl Viewport {
|
||||||
if menu_bar.show_bboxes {
|
if menu_bar.show_bboxes {
|
||||||
let root_bbox3d = board.layout().drawing().rtree().root().envelope();
|
let root_bbox3d = board.layout().drawing().rtree().root().envelope();
|
||||||
|
|
||||||
let root_bbox = AABB::<[f64; 2]>::from_corners([root_bbox3d.lower()[0], root_bbox3d.lower()[1]].into(), [root_bbox3d.upper()[0], root_bbox3d.upper()[1]].into());
|
let root_bbox = AABB::<[f64; 2]>::from_corners(
|
||||||
|
[root_bbox3d.lower()[0], root_bbox3d.lower()[1]].into(),
|
||||||
|
[root_bbox3d.upper()[0], root_bbox3d.upper()[1]].into(),
|
||||||
|
);
|
||||||
painter.paint_bbox(root_bbox);
|
painter.paint_bbox(root_bbox);
|
||||||
|
|
||||||
|
let selected_bbox = overlay.selected_bbox;
|
||||||
|
const INF: f64 = f64::INFINITY;
|
||||||
|
if selected_bbox != AABB::from_corners([-INF, -INF], [INF, INF]) {
|
||||||
|
painter.paint_bbox_with_color(selected_bbox, egui::Color32::BLUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(activity) = &mut workspace.interactor.maybe_activity() {
|
if let Some(activity) = workspace.interactor.maybe_activity() {
|
||||||
for ghost in activity.ghosts().iter() {
|
for ghost in activity.ghosts().iter() {
|
||||||
painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150));
|
painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue