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