1use crate::{
2 border::{Border, BorderBuilder},
3 brush::{Brush, GradientPoint},
4 core::{algebra::Vector2, color::Color, pool::Handle},
5 define_constructor,
6 draw::DrawingContext,
7 message::{MessageDirection, UiMessage},
8 widget::{Widget, WidgetMessage},
9 BuildContext, Control, NodeHandleMapping, UiNode, UserInterface, BRUSH_BRIGHT, BRUSH_LIGHT,
10 BRUSH_LIGHTER, BRUSH_LIGHTEST, COLOR_DARKEST, COLOR_LIGHTEST,
11};
12use std::any::{Any, TypeId};
13use std::{
14 ops::{Deref, DerefMut},
15 sync::mpsc::Sender,
16};
17
18#[derive(Debug, Clone, PartialEq)]
19pub enum DecoratorMessage {
20 Select(bool),
21 HoverBrush(Brush),
22 NormalBrush(Brush),
23 PressedBrush(Brush),
24 SelectedBrush(Brush),
25}
26
27impl DecoratorMessage {
28 define_constructor!(DecoratorMessage:Select => fn select(bool), layout: false);
29 define_constructor!(DecoratorMessage:HoverBrush => fn hover_brush(Brush), layout: false);
30 define_constructor!(DecoratorMessage:NormalBrush => fn normal_brush(Brush), layout: false);
31 define_constructor!(DecoratorMessage:PressedBrush => fn pressed_brush(Brush), layout: false);
32 define_constructor!(DecoratorMessage:SelectedBrush => fn selected_brush(Brush), layout: false);
33}
34
35#[derive(Clone)]
46pub struct Decorator {
47 border: Border,
48 normal_brush: Brush,
49 hover_brush: Brush,
50 pressed_brush: Brush,
51 selected_brush: Brush,
52 disabled_brush: Brush,
53 is_selected: bool,
54 is_pressable: bool,
55}
56
57impl Decorator {
58 pub fn border(&self) -> &Border {
59 &self.border
60 }
61
62 pub fn normal_brush(&self) -> &Brush {
63 &self.normal_brush
64 }
65
66 pub fn hover_brush(&self) -> &Brush {
67 &self.hover_brush
68 }
69
70 pub fn pressed_brush(&self) -> &Brush {
71 &self.pressed_brush
72 }
73
74 pub fn selected_brush(&self) -> &Brush {
75 &self.selected_brush
76 }
77
78 pub fn disabled_brush(&self) -> &Brush {
79 &self.disabled_brush
80 }
81
82 pub fn is_pressable(&self) -> bool {
83 self.is_pressable
84 }
85
86 pub fn is_selected(&self) -> bool {
87 self.is_pressable
88 }
89}
90
91impl Deref for Decorator {
92 type Target = Widget;
93
94 fn deref(&self) -> &Self::Target {
95 &self.border
96 }
97}
98
99impl DerefMut for Decorator {
100 fn deref_mut(&mut self) -> &mut Self::Target {
101 &mut self.border
102 }
103}
104
105impl Control for Decorator {
106 fn query_component(&self, type_id: TypeId) -> Option<&dyn Any> {
107 self.border.query_component(type_id).or_else(|| {
108 if type_id == TypeId::of::<Self>() {
109 Some(self)
110 } else {
111 None
112 }
113 })
114 }
115
116 fn resolve(&mut self, node_map: &NodeHandleMapping) {
117 self.border.resolve(node_map)
118 }
119
120 fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
121 self.border.measure_override(ui, available_size)
122 }
123
124 fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
125 self.border.arrange_override(ui, final_size)
126 }
127
128 fn draw(&self, drawing_context: &mut DrawingContext) {
129 self.border.draw(drawing_context)
130 }
131
132 fn update(&mut self, dt: f32, sender: &Sender<UiMessage>) {
133 self.border.update(dt, sender)
134 }
135
136 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
137 self.border.handle_routed_message(ui, message);
138
139 if let Some(msg) = message.data::<DecoratorMessage>() {
140 match msg {
141 &DecoratorMessage::Select(value) => {
142 if self.is_selected != value {
143 self.is_selected = value;
144 if self.is_selected {
145 ui.send_message(WidgetMessage::background(
146 self.handle(),
147 MessageDirection::ToWidget,
148 self.selected_brush.clone(),
149 ));
150 } else {
151 ui.send_message(WidgetMessage::background(
152 self.handle(),
153 MessageDirection::ToWidget,
154 self.normal_brush.clone(),
155 ));
156 }
157 }
158 }
159 DecoratorMessage::HoverBrush(brush) => {
160 self.hover_brush = brush.clone();
161 if self.is_mouse_directly_over {
162 ui.send_message(WidgetMessage::background(
163 self.handle(),
164 MessageDirection::ToWidget,
165 self.hover_brush.clone(),
166 ));
167 }
168 }
169 DecoratorMessage::NormalBrush(brush) => {
170 self.normal_brush = brush.clone();
171 if !self.is_selected && !self.is_mouse_directly_over {
172 ui.send_message(WidgetMessage::background(
173 self.handle(),
174 MessageDirection::ToWidget,
175 self.normal_brush.clone(),
176 ));
177 }
178 }
179 DecoratorMessage::PressedBrush(brush) => {
180 self.pressed_brush = brush.clone();
181 }
182 DecoratorMessage::SelectedBrush(brush) => {
183 self.selected_brush = brush.clone();
184 if self.is_selected {
185 ui.send_message(WidgetMessage::background(
186 self.handle(),
187 MessageDirection::ToWidget,
188 self.selected_brush.clone(),
189 ));
190 }
191 }
192 }
193 } else if let Some(msg) = message.data::<WidgetMessage>() {
194 if message.destination() == self.handle()
195 || self.has_descendant(message.destination(), ui)
196 {
197 match msg {
198 WidgetMessage::MouseLeave => {
199 if self.is_selected {
200 ui.send_message(WidgetMessage::background(
201 self.handle(),
202 MessageDirection::ToWidget,
203 self.selected_brush.clone(),
204 ));
205 } else {
206 ui.send_message(WidgetMessage::background(
207 self.handle(),
208 MessageDirection::ToWidget,
209 self.normal_brush.clone(),
210 ));
211 }
212 }
213 WidgetMessage::MouseEnter => {
214 ui.send_message(WidgetMessage::background(
215 self.handle(),
216 MessageDirection::ToWidget,
217 self.hover_brush.clone(),
218 ));
219 }
220 WidgetMessage::MouseDown { .. } if self.is_pressable => {
221 ui.send_message(WidgetMessage::background(
222 self.handle(),
223 MessageDirection::ToWidget,
224 self.pressed_brush.clone(),
225 ));
226 }
227 WidgetMessage::MouseUp { .. } => {
228 if self.is_selected {
229 ui.send_message(WidgetMessage::background(
230 self.handle(),
231 MessageDirection::ToWidget,
232 self.selected_brush.clone(),
233 ));
234 } else {
235 ui.send_message(WidgetMessage::background(
236 self.handle(),
237 MessageDirection::ToWidget,
238 self.normal_brush.clone(),
239 ));
240 }
241 }
242 _ => {}
243 }
244 }
245 }
246 }
247}
248
249pub struct DecoratorBuilder {
250 border_builder: BorderBuilder,
251 normal_brush: Option<Brush>,
252 hover_brush: Option<Brush>,
253 pressed_brush: Option<Brush>,
254 selected_brush: Option<Brush>,
255 disabled_brush: Option<Brush>,
256 pressable: bool,
257}
258
259impl DecoratorBuilder {
260 pub fn new(border_builder: BorderBuilder) -> Self {
261 Self {
262 border_builder,
263 normal_brush: None,
264 hover_brush: None,
265 pressed_brush: None,
266 selected_brush: None,
267 disabled_brush: None,
268 pressable: true,
269 }
270 }
271
272 pub fn with_normal_brush(mut self, brush: Brush) -> Self {
273 self.normal_brush = Some(brush);
274 self
275 }
276
277 pub fn with_hover_brush(mut self, brush: Brush) -> Self {
278 self.hover_brush = Some(brush);
279 self
280 }
281
282 pub fn with_pressed_brush(mut self, brush: Brush) -> Self {
283 self.pressed_brush = Some(brush);
284 self
285 }
286
287 pub fn with_selected_brush(mut self, brush: Brush) -> Self {
288 self.selected_brush = Some(brush);
289 self
290 }
291
292 pub fn with_disabled_brush(mut self, brush: Brush) -> Self {
293 self.disabled_brush = Some(brush);
294 self
295 }
296
297 pub fn with_pressable(mut self, pressable: bool) -> Self {
298 self.pressable = pressable;
299 self
300 }
301
302 pub fn build(mut self, ui: &mut BuildContext) -> Handle<UiNode> {
303 let normal_brush = self.normal_brush.unwrap_or(BRUSH_LIGHT);
304
305 if self.border_builder.widget_builder.foreground.is_none() {
306 self.border_builder.widget_builder.foreground = Some(Brush::LinearGradient {
307 from: Vector2::new(0.5, 0.0),
308 to: Vector2::new(0.5, 1.0),
309 stops: vec![
310 GradientPoint {
311 stop: 0.0,
312 color: COLOR_LIGHTEST,
313 },
314 GradientPoint {
315 stop: 0.25,
316 color: COLOR_LIGHTEST,
317 },
318 GradientPoint {
319 stop: 1.0,
320 color: COLOR_DARKEST,
321 },
322 ],
323 });
324 }
325
326 let mut border = self.border_builder.build_border();
327
328 border.set_background(normal_brush.clone());
329
330 let node = UiNode::new(Decorator {
331 border,
332 normal_brush,
333 hover_brush: self.hover_brush.unwrap_or(BRUSH_LIGHTER),
334 pressed_brush: self.pressed_brush.unwrap_or(BRUSH_LIGHTEST),
335 selected_brush: self.selected_brush.unwrap_or(BRUSH_BRIGHT),
336 disabled_brush: self
337 .disabled_brush
338 .unwrap_or_else(|| Brush::Solid(Color::opaque(50, 50, 50))),
339 is_selected: false,
340 is_pressable: self.pressable,
341 });
342 ui.add_node(node)
343 }
344}