Skip to main content

fyrox_ui/
control.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use crate::{
22    core::{algebra::Vector2, pool::Handle, reflect::Reflect, uuid::Uuid, visitor::Visit},
23    core::{ComponentProvider, TypeUuidProvider},
24    draw::DrawingContext,
25    message::{OsEvent, UiMessage},
26    widget::Widget,
27    UiNode, UserInterface,
28};
29use fyrox_core::{define_as_any_trait, pool::ObjectOrVariantHelper};
30
31use fyrox_core::algebra::Matrix3;
32use std::{
33    any::Any,
34    marker::PhantomData,
35    ops::{Deref, DerefMut},
36    sync::mpsc::Sender,
37};
38
39define_as_any_trait!(ControlAsAny => BaseControl);
40
41/// Base trait for all UI widgets. It has auto-impl, and you don't need to implement it manually. Your widget
42/// must implement [`Clone`] and [`Control`] traits for impl to be generated for you, also your widget must
43/// not contain any references (due to `'static` lifetime requirement).
44pub trait BaseControl: Send + ControlAsAny {
45    /// Returns the exact copy of the widget in "type-erased" form.
46    fn clone_boxed(&self) -> Box<dyn Control>;
47
48    /// Returns type name of the widget.
49    fn type_name(&self) -> &'static str;
50
51    fn id(&self) -> Uuid;
52
53    /// Returns the total amount of memory used by this widget (in bytes), in other words, it returns
54    /// `size_of::<WidgetType>()`.
55    fn self_size(&self) -> usize;
56}
57
58impl<T> BaseControl for T
59where
60    T: Any + Clone + 'static + Control + TypeUuidProvider,
61{
62    fn clone_boxed(&self) -> Box<dyn Control> {
63        Box::new(self.clone())
64    }
65
66    fn type_name(&self) -> &'static str {
67        std::any::type_name::<T>()
68    }
69
70    fn id(&self) -> Uuid {
71        Self::type_uuid()
72    }
73
74    fn self_size(&self) -> usize {
75        size_of::<T>()
76    }
77}
78
79/// Proxies all the [`Control`] trait methods (except [`Control::handle_routed_message`]) to the
80/// specified struct member. This macro can be used to reduce boilerplate code for derived widgets.
81#[macro_export]
82macro_rules! control_trait_proxy_impls {
83    ($target:ident) => {
84        fn summary(&self) -> String {
85            self.$target.summary()
86        }
87
88        fn on_remove(&self, sender: &std::sync::mpsc::Sender<$crate::message::UiMessage>) {
89            self.$target.on_remove(sender)
90        }
91
92        fn measure_override(
93            &self,
94            ui: &$crate::UserInterface,
95            available_size: $crate::core::algebra::Vector2<f32>,
96        ) -> $crate::core::algebra::Vector2<f32> {
97            self.$target.measure_override(ui, available_size)
98        }
99
100        fn arrange_override(
101            &self,
102            ui: &$crate::UserInterface,
103            final_size: $crate::core::algebra::Vector2<f32>,
104        ) -> $crate::core::algebra::Vector2<f32> {
105            self.$target.arrange_override(ui, final_size)
106        }
107
108        fn draw(&self, drawing_context: &mut $crate::draw::DrawingContext) {
109            self.$target.draw(drawing_context)
110        }
111
112        fn on_visual_transform_changed(
113            &self,
114            old_transform: &$crate::core::algebra::Matrix3<f32>,
115            new_transform: &$crate::core::algebra::Matrix3<f32>,
116        ) {
117            self.$target
118                .on_visual_transform_changed(old_transform, new_transform)
119        }
120
121        fn post_draw(&self, drawing_context: &mut $crate::draw::DrawingContext) {
122            self.$target.post_draw(drawing_context)
123        }
124
125        fn update(&mut self, dt: f32, ui: &mut $crate::UserInterface) {
126            self.$target.update(dt, ui)
127        }
128
129        fn preview_message(
130            &self,
131            ui: &$crate::UserInterface,
132            message: &mut $crate::message::UiMessage,
133        ) {
134            self.$target.preview_message(ui, message)
135        }
136
137        fn handle_os_event(
138            &mut self,
139            self_handle: $crate::core::pool::Handle<$crate::UiNode>,
140            ui: &mut $crate::UserInterface,
141            event: &$crate::message::OsEvent,
142        ) {
143            self.$target.handle_os_event(self_handle, ui, event)
144        }
145
146        fn accepts_drop(
147            &self,
148            widget: $crate::core::pool::Handle<$crate::UiNode>,
149            ui: &$crate::UserInterface,
150        ) -> bool {
151            self.$target.accepts_drop(widget, ui)
152        }
153    };
154}
155
156/// Trait for all UI controls in library.
157pub trait Control:
158    BaseControl + Deref<Target = Widget> + DerefMut + Reflect + Visit + ComponentProvider
159{
160    /// Brief debugging information about this node.
161    fn summary(&self) -> String {
162        use std::fmt::Write;
163        let mut result = String::new();
164        let type_name = BaseControl::type_name(self)
165            .strip_prefix("fyrox_ui::")
166            .unwrap_or(BaseControl::type_name(self));
167        write!(result, "{} {}<{}>", self.handle(), self.name(), type_name,).unwrap();
168        if self.children().len() == 1 {
169            result.push_str(" 1 child");
170        } else if self.children().len() > 1 {
171            write!(result, " {} children", self.children().len()).unwrap();
172        }
173        result
174    }
175
176    /// This method will be called before the widget is destroyed (dropped). At the moment, when this
177    /// method is called, the widget is still in the widget graph and can be accessed via handles. It
178    /// is guaranteed to be called once, and only if the widget is deleted via [`crate::widget::WidgetMessage::Remove`].
179    fn on_remove(&self, #[allow(unused_variables)] sender: &Sender<UiMessage>) {}
180
181    /// This method is used to override measurement step of the layout system. It should return the desired size of
182    /// the widget (how much space it wants to occupy).
183    ///
184    /// ## Example
185    ///
186    /// ```rust
187    /// # use fyrox_ui::{
188    /// #     core::algebra::Vector2, define_widget_deref, message::UiMessage, Control, UserInterface,
189    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
190    /// #     widget::Widget, UiNode
191    /// # };
192    /// # use std::{
193    /// #     any::{Any, TypeId},
194    /// #     ops::{Deref, DerefMut},
195    /// # };
196    /// # use fyrox_core::uuid_provider;
197    /// # use fyrox_graph::SceneGraph;
198    /// #
199    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
200    /// #[reflect(derived_type = "UiNode")]
201    /// struct MyWidget {
202    ///     widget: Widget,
203    /// }
204    /// #
205    /// # define_widget_deref!(MyWidget);
206    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
207    /// impl Control for MyWidget {
208    ///     fn measure_override(
209    ///         &self,
210    ///         ui: &UserInterface,
211    ///         available_size: Vector2<f32>,
212    ///     ) -> Vector2<f32> {
213    ///         let mut size: Vector2<f32> = Vector2::default();
214    ///
215    ///         // Measure children nodes and find the largest size of them.
216    ///         for &child in self.children.iter() {
217    ///             // Recursively measure children nodes. Measured size will be put in `desired_size`
218    ///             // of the widget.
219    ///             ui.measure_node(child, available_size);
220    ///
221    ///             // Find max size across all the children widgets.
222    ///             size = size.sup(&ui.node(child).desired_size());
223    ///         }
224    ///
225    ///         size
226    ///     }
227    ///     #
228    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
229    ///     #     todo!()
230    ///     # }
231    /// }
232    /// ```
233    ///
234    /// The goal of this method is to supply the UI system with the size requirements of all descendants
235    /// of the widget. In this example, we measure all descendants recursively and find the max desired
236    /// size of across all the children's widgets. This effectively does the following: the size of this widget
237    /// will be the max size of children's widgets. Some widgets (like [`crate::canvas::Canvas`]), can provide infinite
238    /// constraints to children nodes, to fetch unconstrained desired size.
239    ///
240    /// It is recommended to check the implementation of this method of built-in widgets (such as [`crate::canvas::Canvas`],
241    /// [`crate::stack_panel::StackPanel`], [`crate::wrap_panel::WrapPanel`], [`crate::grid::Grid`]). It should help you to
242    /// understand measurement step better.
243    fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
244        self.deref().measure_override(ui, available_size)
245    }
246
247    /// This method is used to override arrangement step of the layout system. Arrangement step is used to
248    /// commit the final location and size of the widget in local coordinates. It is done after the measurement
249    /// step; when all desired sizes of every widget is known. This fact allows you to calculate the final location
250    /// and size of every child widget, based on their desired size. Usually, this method is used in some panel
251    /// widgets that take their children and arrange them in some specific way. For example, it may stack
252    /// widgets on top of each other, or put them in a line with wrapping, etc.
253    ///
254    /// ## Example
255    ///
256    /// ```rust
257    /// # use fyrox_ui::{
258    /// #     core::{algebra::Vector2, math::Rect},
259    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
260    /// #     define_widget_deref,
261    /// #     message::UiMessage,
262    /// #     Control, UserInterface, widget::Widget, UiNode
263    /// # };
264    /// # use std::{
265    /// #     any::{Any, TypeId},
266    /// #     ops::{Deref, DerefMut},
267    /// # };
268    /// # use fyrox_core::uuid_provider;
269    /// #
270    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
271    /// #[reflect(derived_type = "UiNode")]
272    /// struct MyWidget {
273    ///     widget: Widget,
274    /// }
275    /// #
276    /// # define_widget_deref!(MyWidget);
277    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
278    /// impl Control for MyWidget {
279    ///     fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
280    ///         let final_rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
281    ///
282    ///         // Commit final locations and size for each child node.
283    ///         for &child in self.children.iter() {
284    ///             ui.arrange_node(child, &final_rect);
285    ///         }
286    ///
287    ///         final_size
288    ///     }
289    ///     #
290    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
291    ///     #     todo!()
292    ///     # }
293    /// }
294    /// ```
295    ///
296    /// This example arranges all the children widgets using the given `final_size`, that comes from the
297    /// parent widget, so all children will have exactly the same size as the parent and be located at (0;0)
298    /// point in local coordinates.
299    ///
300    /// It is recommended to check the implementation of this method of built-in widgets (such as [`crate::canvas::Canvas`],
301    /// [`crate::stack_panel::StackPanel`], [`crate::wrap_panel::WrapPanel`], [`crate::grid::Grid`]). It should help you to
302    ///  understand the arrangement step better.
303    fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
304        self.deref().arrange_override(ui, final_size)
305    }
306
307    /// This method is used to emit drawing commands that will be used later to draw your widget on screen.
308    /// Keep in mind that any emitted geometry (quads, lines, text, etc.), will be used to perform hit test.
309    /// In other words, all the emitted geometry will make your widget "clickable". Widgets with no geometry
310    /// emitted by this method are mouse input transparent.
311    ///
312    /// ## Example
313    ///
314    /// ```rust
315    /// # use fyrox_ui::{
316    /// #     define_widget_deref,
317    /// #     draw::{CommandTexture, Draw, DrawingContext},
318    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
319    /// #     message::UiMessage,
320    /// #     Control, UserInterface, widget::Widget, UiNode
321    /// # };
322    /// # use std::{
323    /// #     any::{Any, TypeId},
324    /// #     ops::{Deref, DerefMut},
325    /// # };
326    /// # use fyrox_core::uuid_provider;
327    /// #
328    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
329    /// #[reflect(derived_type = "UiNode")]
330    /// struct MyWidget {
331    ///     widget: Widget,
332    /// }
333    /// #
334    /// # define_widget_deref!(MyWidget);
335    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
336    /// impl Control for MyWidget {
337    /// fn draw(&self, drawing_context: &mut DrawingContext) {
338    ///     let bounds = self.widget.bounding_rect();
339    ///
340    ///     // Push a rect.
341    ///     drawing_context.push_rect_filled(&bounds, None);
342    ///
343    ///     // Commit the geometry, it is a mandatory step, otherwise your widget's geometry
344    ///     // will be "attached" to some other widget that will call `commit`.
345    ///     drawing_context.commit(
346    ///         self.clip_bounds(),
347    ///         self.widget.background(),
348    ///         CommandTexture::None,
349    ///         &self.material,
350    ///         None,
351    ///     );
352    /// }
353    ///
354    /// fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
355    ///     // You may need to call the following method if your widget uses custom properties
356    ///     // for rendering to force it to be re-drawn. See `Widget::invalidate_visual` docs
357    ///     // for more info.
358    ///     self.invalidate_visual();
359    /// }
360    /// }
361    /// ```
362    ///
363    /// This example shows how to draw a simple quad using the background brush of the widget. See docs
364    /// for [`DrawingContext`] for more info.
365    fn draw(&self, #[allow(unused_variables)] drawing_context: &mut DrawingContext) {}
366
367    fn on_visual_transform_changed(
368        &self,
369        #[allow(unused_variables)] old_transform: &Matrix3<f32>,
370        #[allow(unused_variables)] new_transform: &Matrix3<f32>,
371    ) {
372    }
373
374    /// The same as [`Self::draw`], but it runs after all descendant widgets are rendered.
375    fn post_draw(&self, #[allow(unused_variables)] drawing_context: &mut DrawingContext) {}
376
377    /// This method is called every frame and can be used to update internal variables of the widget, that
378    /// can be used to animated your widget. Its main difference from other methods is that it does **not**
379    /// provide access to any other widget in the UI. Instead, you can only send messages to widgets to
380    /// force them to change their state.
381    ///
382    /// ## Important notes
383    ///
384    /// Due to performance reasons, you **must** set `.with_need_update(true)` in widget builder to
385    /// force library to call `update` method!
386    fn update(
387        &mut self,
388        #[allow(unused_variables)] dt: f32,
389        #[allow(unused_variables)] ui: &mut UserInterface,
390    ) {
391    }
392
393    /// Performs event-specific actions. Must call widget.handle_message()!
394    ///
395    /// # Notes
396    ///
397    /// Do *not* try to borrow node by `self_handle` in UI - at this moment node has been moved
398    /// out of the pool and attempt of borrowing will cause panic! `self_handle` should be used only
399    /// to check if event came from/for this node or to capture input on node.
400    fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage);
401
402    /// Used to react to a message (by producing another message) that was posted outside the current
403    /// hierarchy. In other words, this method is used when you need to "peek" a message before it'll
404    /// be passed into bubbling router. The Most common use case is to catch messages from popups: popup
405    /// in 99.9% cases is a child of root canvas and it **won't** receive a message from a *logical*
406    /// parent during bubbling message routing. For example, `preview_message` used in a dropdown list:
407    /// dropdown list has two separate parts - a field with selected value and a popup for all possible
408    /// options. Visual parent of the popup in this case is the root canvas, but logical parent is the
409    /// dropdown list. Because of this fact, the field won't receive any messages from the popup, to solve
410    /// this we use `preview_message`. This method is much more restrictive - it does not allow you to
411    /// modify a node and ui, you can either *request* changes by sending a message or use internal
412    /// mutability (`Cell`, `RefCell`, etc.).
413    ///
414    /// ## Important notes
415    ///
416    /// Due to performance reasons, you **must** set `.with_preview_messages(true)` in widget builder to
417    /// force library to call `preview_message`!
418    ///
419    /// The order of execution of this method is undefined! There is no guarantee that it will be called
420    /// hierarchically as widgets connected.
421    fn preview_message(
422        &self,
423        #[allow(unused_variables)] ui: &UserInterface,
424        #[allow(unused_variables)] message: &mut UiMessage,
425    ) {
426        // This method is optional.
427    }
428
429    /// Provides a way to respond to OS specific events. Can be useful to detect if a key or mouse
430    /// button was pressed. This method significantly differs from `handle_message` because os events
431    /// are not dispatched - they'll be passed to this method in any case.
432    ///
433    /// ## Important notes
434    ///
435    /// Due to performance reasons, you **must** set `.with_handle_os_messages(true)` in widget builder to
436    /// force library to call `handle_os_event`!
437    fn handle_os_event(
438        &mut self,
439        #[allow(unused_variables)] self_handle: Handle<UiNode>,
440        #[allow(unused_variables)] ui: &mut UserInterface,
441        #[allow(unused_variables)] event: &OsEvent,
442    ) {
443    }
444
445    /// Checks whether a `widget` will be accepted by the current widget or not when dropped. This
446    /// method is used only to switch the cursor icon. The default implementation returns `allow_drop`
447    /// flag of the widget, which, if set to `true`, basically allows unconditional drop of any content.
448    fn accepts_drop(
449        &self,
450        #[allow(unused_variables)] widget: Handle<UiNode>,
451        #[allow(unused_variables)] ui: &UserInterface,
452    ) -> bool {
453        *self.allow_drop
454    }
455}
456
457// Essentially implements ObjectOrVariant for Control types.
458// See ObjectOrVariantHelper for the cause of the indirection.
459impl<T: Control> ObjectOrVariantHelper<UiNode, T> for PhantomData<T> {
460    fn convert_to_dest_type_helper(node: &UiNode) -> Option<&T> {
461        (node.0.deref() as &dyn ComponentProvider).component_ref()
462    }
463
464    fn convert_to_dest_type_helper_mut(node: &mut UiNode) -> Option<&mut T> {
465        (node.0.deref_mut() as &mut dyn ComponentProvider).component_mut()
466    }
467}