blockworx_tools/
selection_bounds.rs1use blockworx_doc::id::{PinId, RouteId};
6use blockworx_geom::Rect;
7use blockworx_paint::Renderer;
8
9use crate::{
10 grid::GRID_SIZE, shape::ShapeId, theme::Style, tool::Deletable, widget::drawing::Drawing,
11};
12
13pub(crate) fn shapes_bounds(data: &Drawing, ids: &[ShapeId]) -> Option<Rect> {
15 ids.iter()
16 .filter_map(|&id| Some(data.shape(id)?.gui_rect()))
17 .reduce(Rect::union)
18}
19
20pub(crate) fn pins_bounds(
23 data: &Drawing,
24 pins: &[PinId],
25 painter: &Style<'_, impl Renderer>,
26) -> Option<Rect> {
27 pins.iter()
28 .filter_map(|&anchor| {
29 let (shape, pin) = data.pin_on_shape(anchor)?;
30 let slot = crate::shape::pin::slot(pin);
31 Some(
32 crate::render::PinExtent {
33 bbox: shape.gui_rect(),
34 side: slot.side,
35 offset: slot.offset,
36 name: &pin.name,
37 type_label: &pin.type_name,
38 tag: &pin.tag,
39 }
40 .bbox(painter),
41 )
42 })
43 .reduce(Rect::union)
44}
45
46fn route_bounds(data: &Drawing, id: RouteId) -> Option<Rect> {
49 let pts = data.route_geometry(id)?.points();
50 (!pts.is_empty()).then(|| Rect::from_points(&pts).expand(GRID_SIZE / 2.0))
51}
52
53pub fn selection_world_bounds(
56 sel: &Deletable,
57 data: &Drawing,
58 painter: &Style<'_, impl Renderer>,
59) -> Option<Rect> {
60 match sel {
61 Deletable::Shape(id) => shapes_bounds(data, std::slice::from_ref(id)),
62 Deletable::Shapes(ids) => shapes_bounds(data, ids),
63 Deletable::Pins(pins) => pins_bounds(data, pins, painter),
64 Deletable::Route(id) => route_bounds(data, *id),
65 }
66}