blockworx/tools/
multi_pin_select.rs1use crate::theme::Style;
2use blockworx_geom::WorldPx;
3use blockworx_paint::{Canvas, Event, Interaction};
4
5use crate::edit::naming::Authoring;
6use crate::{
7 theme::Role,
8 tools::{
9 MoveMultiPin,
10 names::ToolName,
11 tool::{Action, Deletable, ToolTrait},
12 },
13 widget::{drawing::Drawing, hit_target::HitTarget},
14};
15use blockworx_doc::id::PinId;
16
17pub enum MultiPinSelect {
22 Selected { pins: Vec<PinId> },
23}
24
25impl ToolTrait for MultiPinSelect {
26 fn name(&self) -> ToolName {
27 ToolName::MultiPinSelect
28 }
29
30 fn selection(&self) -> Option<Deletable> {
31 match self {
32 MultiPinSelect::Selected { pins } => Some(Deletable::Pins(pins.clone())),
33 }
34 }
35
36 fn widget<C: Canvas>(
37 &mut self,
38 data: &mut Drawing,
39 interaction: &Interaction,
40 painter: &mut Style<'_, C>,
41 ) -> Option<Action> {
42 let MultiPinSelect::Selected { pins } = self;
43 Self::render(data, pins, interaction, painter);
44 if interaction.delete_pressed {
45 return Some(Action::Delete(Deletable::Pins(pins.clone())));
46 }
47 match interaction.event {
48 Some(Event::DragStarted { pos }) => {
49 let on_pin = data.authoring() == Authoring::Offered
53 && matches!(
54 data.resolve_at_pos(pos, painter),
55 Some(HitTarget::Pin { anchor, .. }) if pins.contains(&anchor)
56 );
57 if on_pin {
58 Some(Action::SwitchTool(
59 MoveMultiPin::new(pins.clone(), pos).into(),
60 ))
61 } else {
62 Some(crate::tools::select_tool::drag_to_move(data, pos, painter))
63 }
64 }
65 Some(Event::Clicked { pos }) => Some(
66 crate::tools::select_tool::click_to_select(data, pos, painter).unwrap_or_default(),
67 ),
68 _ => None,
69 }
70 }
71}
72
73impl MultiPinSelect {
74 fn render<C: Canvas>(
75 data: &Drawing,
76 pins: &[PinId],
77 interaction: &Interaction,
78 painter: &mut Style<'_, C>,
79 ) {
80 crate::widget::display::widget(data, interaction, painter);
81 draw_pin_selection_frame(data, pins, painter);
82 }
83}
84
85pub(crate) const SELECTION_RING_ROUNDING: WorldPx = WorldPx::new(2.0);
90
91pub(crate) fn draw_pin_selection_frame<C: Canvas>(
95 data: &Drawing,
96 pins: &[PinId],
97 painter: &mut Style<'_, C>,
98) {
99 let bounds = crate::tools::selection_bounds::pins_bounds(data, pins, painter);
100 if let Some(bounds) = bounds {
101 painter.rect(
102 bounds.expand(2.0),
103 SELECTION_RING_ROUNDING,
104 Role::Transparent,
105 (1.5, Role::SelectionFrame),
106 );
107 }
108}