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