1use crate::color::Color;
16use crate::draw_ctx::DrawCtx;
17use crate::event::{Event, EventResult};
18use crate::geometry::{Rect, Size};
19use crate::widget::Widget;
20
21use super::registry::guides_snapshot;
22use super::SnapGuide;
23
24pub struct SnapOverlay {
27 bounds: Rect,
28 children: Vec<Box<dyn Widget>>, }
30
31impl SnapOverlay {
32 pub fn new() -> Self {
33 Self {
34 bounds: Rect::default(),
35 children: Vec::new(),
36 }
37 }
38
39 fn alignment_color() -> Color {
42 Color::rgba(0.15, 0.70, 0.95, 0.95)
43 }
44
45 fn spacing_color() -> Color {
49 Color::rgba(0.95, 0.35, 0.55, 0.95)
50 }
51}
52
53impl Default for SnapOverlay {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl Widget for SnapOverlay {
60 fn type_name(&self) -> &'static str {
61 "SnapOverlay"
62 }
63 fn bounds(&self) -> Rect {
64 self.bounds
65 }
66 fn set_bounds(&mut self, b: Rect) {
67 self.bounds = b;
68 }
69 fn children(&self) -> &[Box<dyn Widget>] {
70 &self.children
71 }
72 fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
73 &mut self.children
74 }
75 fn layout(&mut self, available: Size) -> Size {
76 self.bounds = Rect::new(0.0, 0.0, available.width, available.height);
80 available
81 }
82 fn paint(&mut self, _ctx: &mut dyn DrawCtx) {
83 }
85 fn paint_global_overlay(&mut self, ctx: &mut dyn DrawCtx) {
86 let guides = guides_snapshot();
87 if guides.is_empty() {
88 return;
89 }
90 ctx.set_line_width(1.0);
91 for guide in guides {
92 match guide {
93 SnapGuide::VLine { x, y0, y1 } => {
94 ctx.set_stroke_color(Self::alignment_color());
95 ctx.begin_path();
96 ctx.move_to(x.round() + 0.5, y0);
97 ctx.line_to(x.round() + 0.5, y1);
98 ctx.stroke();
99 }
100 SnapGuide::HLine { y, x0, x1 } => {
101 ctx.set_stroke_color(Self::alignment_color());
102 ctx.begin_path();
103 ctx.move_to(x0, y.round() + 0.5);
104 ctx.line_to(x1, y.round() + 0.5);
105 ctx.stroke();
106 }
107 SnapGuide::HSpacing { y, x0, x1 } => {
108 ctx.set_stroke_color(Self::spacing_color());
109 let yy = y.round() + 0.5;
110 ctx.begin_path();
111 ctx.move_to(x0, yy);
112 ctx.line_to(x1, yy);
113 ctx.stroke();
114 paint_tick_v(ctx, x0, yy, 4.0);
117 paint_tick_v(ctx, x1, yy, 4.0);
118 }
119 SnapGuide::VSpacing { x, y0, y1 } => {
120 ctx.set_stroke_color(Self::spacing_color());
121 let xx = x.round() + 0.5;
122 ctx.begin_path();
123 ctx.move_to(xx, y0);
124 ctx.line_to(xx, y1);
125 ctx.stroke();
126 paint_tick_h(ctx, xx, y0, 4.0);
127 paint_tick_h(ctx, xx, y1, 4.0);
128 }
129 }
130 }
131 }
132 fn on_event(&mut self, _event: &Event) -> EventResult {
133 EventResult::Ignored
134 }
135 fn hit_test(&self, _p: crate::geometry::Point) -> bool {
136 false
139 }
140}
141
142fn paint_tick_v(ctx: &mut dyn DrawCtx, x: f64, y: f64, half: f64) {
143 ctx.begin_path();
144 ctx.move_to(x, y - half);
145 ctx.line_to(x, y + half);
146 ctx.stroke();
147}
148
149fn paint_tick_h(ctx: &mut dyn DrawCtx, x: f64, y: f64, half: f64) {
150 ctx.begin_path();
151 ctx.move_to(x - half, y);
152 ctx.line_to(x + half, y);
153 ctx.stroke();
154}