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