blockworx/tools/
move_title.rs1use crate::theme::Style;
2use blockworx_geom::{Align, Vec2};
3use blockworx_paint::{Canvas, Cursor, Event, Interaction};
4
5use crate::{
6 grid::round_to_grid,
7 render::{clamp_label_offset, label_side_for_y},
8 shape::ShapeId,
9 state::RenderMode,
10 tools::{
11 names::ToolName,
12 resize_block::ResizeBlock,
13 tool::{Action, ToolTrait},
14 },
15 widget::{DrawingPasses, drawing::Drawing},
16};
17
18pub enum MoveTitle {
19 Idle,
20 Dragging { shape: ShapeId, delta_pos: Vec2 },
21}
22
23impl ToolTrait for MoveTitle {
24 fn name(&self) -> ToolName {
25 ToolName::MoveTitle
26 }
27
28 fn widget<C: Canvas>(
29 &mut self,
30 data: &mut Drawing,
31 interaction: &Interaction,
32 painter: &mut Style<'_, C>,
33 ) -> Option<Action> {
34 match self {
35 MoveTitle::Idle => {
36 crate::widget::display::widget(data, interaction, painter);
37 if let Some(Event::HoverAt(hover_pos)) = interaction.event {
38 if data.title_anchor_at_pos(hover_pos).is_some() {
39 painter.set_cursor(Cursor::PointingHand);
40 }
41 } else if let Some(Event::DragStarted { pos }) = interaction.event
42 && let Some(shape) = data.title_anchor_at_pos(pos)
43 {
44 *self = MoveTitle::Dragging {
45 shape,
46 delta_pos: Vec2::ZERO,
47 };
48 }
49 }
50 MoveTitle::Dragging { shape, delta_pos } => {
51 if let Some(Event::Dragging { delta, .. }) = interaction.event {
52 *delta_pos += delta;
53 }
54 if let Some(Event::DragStopped { .. }) = interaction.event {
55 let placement = data.shape(*shape).and_then(|shape_ref| {
56 let title = shape_ref.title()?;
57 let bbox = shape_ref.gui_rect();
58 let proposed = title.offset + round_to_grid(delta_pos.x);
59 let text_w = painter.text_size(title.name, &painter.theme().title_font).x;
62 Some(crate::widget::drawing::LabelPlacement {
63 offset: clamp_label_offset(bbox, text_w, proposed, Align::Center),
64 side: shape_ref
65 .title_anchor()
66 .map(|anchor| label_side_for_y(bbox, anchor.y + delta_pos.y)),
67 })
68 });
69 if let Some(placement) = placement {
70 data.place_title(*shape, placement);
71 }
72 crate::widget::display::widget(data, interaction, painter);
76 return Some(Action::SwitchTool(
78 ResizeBlock::Selected { shape: *shape }.into(),
79 ));
80 }
81 let dragged = *shape;
82 let delta = *delta_pos;
83 DrawingPasses::new(data)
84 .shape_mode(move |id| {
85 if id == dragged {
86 RenderMode::TitleDragged { delta }
87 } else {
88 RenderMode::Normal
89 }
90 })
91 .draw(painter);
92 }
93 }
94 None
95 }
96}