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