blockworx/tools/
move_label.rs1use crate::render::{RouteRenderMode, render_route_label_at, route_text_color};
2use crate::theme::Style;
3use blockworx_doc::id::{RouteId, RouteLabelId};
4use blockworx_paint::{Canvas, Cursor, Event, Interaction};
5
6use crate::{
7 tools::{
8 names::ToolName,
9 tool::{Action, ToolTrait},
10 },
11 widget::{DrawingPasses, drawing::Drawing},
12};
13
14pub enum MoveLabel {
15 Idle,
16 Dragging {
17 route_id: RouteId,
18 label_id: RouteLabelId,
19 preview: blockworx_doc::geometry::FracVal,
23 },
24}
25
26impl MoveLabel {
27 pub(crate) fn drag_from(
30 data: &Drawing,
31 route_id: RouteId,
32 label_id: RouteLabelId,
33 ) -> Option<Self> {
34 let preview = data.auto_route(route_id).and_then(|wire| {
35 wire.labels
36 .iter()
37 .find(|(id, _)| *id == label_id)
38 .map(|&(_, dist)| dist)
39 })?;
40 Some(MoveLabel::Dragging {
41 route_id,
42 label_id,
43 preview,
44 })
45 }
46}
47
48impl ToolTrait for MoveLabel {
49 fn name(&self) -> ToolName {
50 ToolName::MoveLabel
51 }
52
53 fn widget<C: Canvas>(
54 &mut self,
55 data: &mut Drawing,
56 interaction: &Interaction,
57 painter: &mut Style<'_, C>,
58 ) -> Option<Action> {
59 match self {
60 MoveLabel::Idle => {
61 crate::widget::display::widget(data, interaction, painter);
62 if let Some(Event::HoverAt(pos)) = interaction.event {
63 if data.route_label_at_pos(pos, painter).is_some() {
64 painter.set_cursor(Cursor::Grab);
65 }
66 } else if let Some(Event::DragStarted { pos }) = interaction.event
67 && let Some((route_id, label_id)) = data.route_label_at_pos(pos, painter)
68 && let Some(dragging) = MoveLabel::drag_from(data, route_id, label_id)
69 {
70 *self = dragging;
71 }
72 }
73 MoveLabel::Dragging {
74 route_id,
75 label_id,
76 preview,
77 } => {
78 render_dragging(data, painter, *route_id, *preview);
79 painter.set_cursor(Cursor::Grabbing);
80 if let Some(Event::DragStopped { .. }) = interaction.event {
81 data.place_route_label(*label_id, *preview);
82 return Some(Action::default());
83 }
84 if let Some(Event::Dragging { delta, .. }) = interaction.event
85 && let Some(geometry) = data.route_geometry(*route_id)
86 {
87 *preview = geometry.slide_along(*preview, delta);
88 }
89 }
90 }
91 None
92 }
93}
94
95fn render_dragging<C: Canvas>(
98 data: &Drawing,
99 painter: &mut Style<'_, C>,
100 route_id: RouteId,
101 preview: blockworx_doc::geometry::FracVal,
102) {
103 DrawingPasses::new(data)
104 .route_mode(move |id| {
105 if id == route_id {
106 RouteRenderMode::Highlighted
107 } else {
108 RouteRenderMode::Normal
109 }
110 })
111 .suppress_route_label(route_id)
112 .overlay(move |painter| {
113 if let (Some(wire), Some(geometry)) =
114 (data.auto_route(route_id), data.route_geometry(route_id))
115 {
116 let at = geometry.map_linear_distance_to_position(preview);
117 render_route_label_at(
118 painter,
119 wire.route,
120 at,
121 route_text_color(wire.route, RouteRenderMode::Highlighted),
122 );
123 }
124 })
125 .draw(painter);
126}