1#![warn(missing_docs)]
25
26use crate::style::resource::StyleResourceExt;
27use crate::style::{Style, StyledProperty};
28use crate::widget::WidgetBuilder;
29use crate::{
30 border::{Border, BorderBuilder},
31 brush::Brush,
32 core::{
33 algebra::Vector2, pool::Handle, reflect::prelude::*, type_traits::prelude::*,
34 visitor::prelude::*,
35 },
36 define_constructor,
37 draw::DrawingContext,
38 message::{MessageDirection, UiMessage},
39 widget::{Widget, WidgetMessage},
40 BuildContext, Control, UiNode, UserInterface,
41};
42
43use fyrox_core::uuid_provider;
44use fyrox_core::variable::InheritableVariable;
45use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
46use std::ops::{Deref, DerefMut};
47
48#[derive(Debug, Clone, PartialEq)]
50pub enum DecoratorMessage {
51 Select(bool),
53 HoverBrush(StyledProperty<Brush>),
55 NormalBrush(StyledProperty<Brush>),
57 PressedBrush(StyledProperty<Brush>),
59 SelectedBrush(StyledProperty<Brush>),
61}
62
63impl DecoratorMessage {
64 define_constructor!(
65 DecoratorMessage:Select => fn select(bool), layout: false
67 );
68 define_constructor!(
69 DecoratorMessage:HoverBrush => fn hover_brush(StyledProperty<Brush>), layout: false
71 );
72 define_constructor!(
73 DecoratorMessage:NormalBrush => fn normal_brush(StyledProperty<Brush>), layout: false
75 );
76 define_constructor!(
77 DecoratorMessage:PressedBrush => fn pressed_brush(StyledProperty<Brush>), layout: false
79 );
80 define_constructor!(
81 DecoratorMessage:SelectedBrush => fn selected_brush(StyledProperty<Brush>), layout: false
83 );
84}
85
86#[derive(Default, Clone, Visit, Reflect, Debug, ComponentProvider)]
116#[reflect(derived_type = "UiNode")]
117pub struct Decorator {
118 #[component(include)]
120 pub border: Border,
121 pub normal_brush: InheritableVariable<StyledProperty<Brush>>,
123 pub hover_brush: InheritableVariable<StyledProperty<Brush>>,
125 pub pressed_brush: InheritableVariable<StyledProperty<Brush>>,
127 pub selected_brush: InheritableVariable<StyledProperty<Brush>>,
129 pub is_selected: InheritableVariable<bool>,
131 pub is_pressable: InheritableVariable<bool>,
133}
134
135impl ConstructorProvider<UiNode, UserInterface> for Decorator {
136 fn constructor() -> GraphNodeConstructor<UiNode, UserInterface> {
137 GraphNodeConstructor::new::<Self>()
138 .with_variant("Decorator", |ui| {
139 DecoratorBuilder::new(BorderBuilder::new(
140 WidgetBuilder::new().with_name("Decorator"),
141 ))
142 .build(&mut ui.build_ctx())
143 .into()
144 })
145 .with_group("Visual")
146 }
147}
148
149impl Deref for Decorator {
150 type Target = Widget;
151
152 fn deref(&self) -> &Self::Target {
153 &self.border
154 }
155}
156
157impl DerefMut for Decorator {
158 fn deref_mut(&mut self) -> &mut Self::Target {
159 &mut self.border
160 }
161}
162
163uuid_provider!(Decorator = "bb4b60aa-c657-4ed6-8db6-d7f374397c73");
164
165impl Control for Decorator {
166 fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
167 self.border.measure_override(ui, available_size)
168 }
169
170 fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
171 self.border.arrange_override(ui, final_size)
172 }
173
174 fn draw(&self, drawing_context: &mut DrawingContext) {
175 self.border.draw(drawing_context)
176 }
177
178 fn update(&mut self, dt: f32, ui: &mut UserInterface) {
179 self.border.update(dt, ui)
180 }
181
182 fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
183 self.border.handle_routed_message(ui, message);
184
185 if let Some(msg) = message.data::<DecoratorMessage>() {
186 match msg {
187 &DecoratorMessage::Select(value) => {
188 if *self.is_selected != value {
189 self.is_selected.set_value_and_mark_modified(value);
190
191 ui.send_message(WidgetMessage::background(
192 self.handle(),
193 MessageDirection::ToWidget,
194 if *self.is_selected {
195 (*self.selected_brush).clone()
196 } else {
197 (*self.normal_brush).clone()
198 },
199 ));
200 }
201 }
202 DecoratorMessage::HoverBrush(brush) => {
203 self.hover_brush.set_value_and_mark_modified(brush.clone());
204 if self.has_descendant(ui.picked_node, ui) {
205 ui.send_message(WidgetMessage::background(
206 self.handle(),
207 MessageDirection::ToWidget,
208 (*self.hover_brush).clone(),
209 ));
210 }
211 }
212 DecoratorMessage::NormalBrush(brush) => {
213 self.normal_brush.set_value_and_mark_modified(brush.clone());
214 if !*self.is_selected && !self.has_descendant(ui.picked_node, ui) {
215 ui.send_message(WidgetMessage::background(
216 self.handle(),
217 MessageDirection::ToWidget,
218 (*self.normal_brush).clone(),
219 ));
220 }
221 }
222 DecoratorMessage::PressedBrush(brush) => {
223 self.pressed_brush
224 .set_value_and_mark_modified(brush.clone());
225 }
226 DecoratorMessage::SelectedBrush(brush) => {
227 self.selected_brush
228 .set_value_and_mark_modified(brush.clone());
229 if *self.is_selected {
230 ui.send_message(WidgetMessage::background(
231 self.handle(),
232 MessageDirection::ToWidget,
233 (*self.selected_brush).clone(),
234 ));
235 }
236 }
237 }
238 } else if let Some(msg) = message.data::<WidgetMessage>() {
239 if message.destination() == self.handle()
240 || self.has_descendant(message.destination(), ui)
241 {
242 match msg {
243 WidgetMessage::MouseLeave => {
244 ui.send_message(WidgetMessage::background(
245 self.handle(),
246 MessageDirection::ToWidget,
247 if *self.is_selected {
248 (*self.selected_brush).clone()
249 } else {
250 (*self.normal_brush).clone()
251 },
252 ));
253 }
254 WidgetMessage::MouseEnter => {
255 ui.send_message(WidgetMessage::background(
256 self.handle(),
257 MessageDirection::ToWidget,
258 if *self.is_selected {
259 (*self.selected_brush).clone()
260 } else {
261 (*self.hover_brush).clone()
262 },
263 ));
264 }
265 WidgetMessage::MouseDown { .. } if *self.is_pressable => {
266 ui.send_message(WidgetMessage::background(
267 self.handle(),
268 MessageDirection::ToWidget,
269 (*self.pressed_brush).clone(),
270 ));
271 }
272 WidgetMessage::MouseUp { .. } => {
273 if *self.is_selected {
274 ui.send_message(WidgetMessage::background(
275 self.handle(),
276 MessageDirection::ToWidget,
277 (*self.selected_brush).clone(),
278 ));
279 } else {
280 ui.send_message(WidgetMessage::background(
281 self.handle(),
282 MessageDirection::ToWidget,
283 (*self.normal_brush).clone(),
284 ));
285 }
286 }
287 WidgetMessage::ResetVisual => {
288 self.is_selected.set_value_and_mark_modified(false);
289 ui.send_message(WidgetMessage::background(
290 self.handle(),
291 MessageDirection::ToWidget,
292 (*self.normal_brush).clone(),
293 ));
294 }
295 _ => {}
296 }
297 }
298
299 if message.destination() == self.handle() {
300 if let WidgetMessage::Style(style) = msg {
301 self.normal_brush.update(style);
302 self.hover_brush.update(style);
303 self.pressed_brush.update(style);
304 self.selected_brush.update(style);
305 }
306 }
307 }
308 }
309}
310
311pub struct DecoratorBuilder {
313 border_builder: BorderBuilder,
314 normal_brush: Option<StyledProperty<Brush>>,
315 hover_brush: Option<StyledProperty<Brush>>,
316 pressed_brush: Option<StyledProperty<Brush>>,
317 selected_brush: Option<StyledProperty<Brush>>,
318 pressable: bool,
319 selected: bool,
320}
321
322impl DecoratorBuilder {
323 pub fn new(border_builder: BorderBuilder) -> Self {
325 Self {
326 normal_brush: None,
327 hover_brush: None,
328 pressed_brush: None,
329 selected_brush: None,
330 pressable: true,
331 selected: false,
332 border_builder,
333 }
334 }
335
336 pub fn with_normal_brush(mut self, brush: StyledProperty<Brush>) -> Self {
338 self.normal_brush = Some(brush);
339 self
340 }
341
342 pub fn with_hover_brush(mut self, brush: StyledProperty<Brush>) -> Self {
344 self.hover_brush = Some(brush);
345 self
346 }
347
348 pub fn with_pressed_brush(mut self, brush: StyledProperty<Brush>) -> Self {
350 self.pressed_brush = Some(brush);
351 self
352 }
353
354 pub fn with_selected_brush(mut self, brush: StyledProperty<Brush>) -> Self {
356 self.selected_brush = Some(brush);
357 self
358 }
359
360 pub fn with_pressable(mut self, pressable: bool) -> Self {
362 self.pressable = pressable;
363 self
364 }
365
366 pub fn with_selected(mut self, selected: bool) -> Self {
368 self.selected = selected;
369 self
370 }
371
372 pub fn build(mut self, ctx: &mut BuildContext) -> Handle<UiNode> {
374 let normal_brush = self
375 .normal_brush
376 .unwrap_or_else(|| ctx.style.property::<Brush>(Style::BRUSH_LIGHT));
377 let hover_brush = self
378 .hover_brush
379 .unwrap_or_else(|| ctx.style.property::<Brush>(Style::BRUSH_LIGHTER));
380 let pressed_brush = self
381 .pressed_brush
382 .unwrap_or_else(|| ctx.style.property::<Brush>(Style::BRUSH_LIGHTEST));
383 let selected_brush = self
384 .selected_brush
385 .unwrap_or_else(|| ctx.style.property::<Brush>(Style::BRUSH_BRIGHT));
386
387 if self.border_builder.widget_builder.foreground.is_none() {
388 let brush = ctx.style.property(Style::BRUSH_DARKER);
389 self.border_builder.widget_builder.foreground = Some(brush);
390 }
391
392 let mut border = self.border_builder.build_border(ctx);
393
394 if self.selected {
395 *border.background = selected_brush.clone();
396 } else {
397 *border.background = normal_brush.clone();
398 }
399
400 let node = UiNode::new(Decorator {
401 border,
402 normal_brush: normal_brush.into(),
403 hover_brush: hover_brush.into(),
404 pressed_brush: pressed_brush.into(),
405 selected_brush: selected_brush.into(),
406 is_selected: self.selected.into(),
407 is_pressable: self.pressable.into(),
408 });
409 ctx.add_node(node)
410 }
411}
412
413#[cfg(test)]
414mod test {
415 use crate::border::BorderBuilder;
416 use crate::decorator::DecoratorBuilder;
417 use crate::{test::test_widget_deletion, widget::WidgetBuilder};
418
419 #[test]
420 fn test_deletion() {
421 test_widget_deletion(|ctx| {
422 DecoratorBuilder::new(BorderBuilder::new(WidgetBuilder::new())).build(ctx)
423 });
424 }
425}