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 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/// Trait for all UI controls in library.
80pub trait Control:
81    BaseControl + Deref<Target = Widget> + DerefMut + Reflect + Visit + ComponentProvider
82{
83    /// Brief debugging information about this node.
84    fn summary(&self) -> String {
85        use std::fmt::Write;
86        let mut result = String::new();
87        let type_name = BaseControl::type_name(self)
88            .strip_prefix("fyrox_ui::")
89            .unwrap_or(BaseControl::type_name(self));
90        write!(result, "{} {}<{}>", self.handle(), self.name(), type_name,).unwrap();
91        if self.children().len() == 1 {
92            result.push_str(" 1 child");
93        } else if self.children().len() > 1 {
94            write!(result, " {} children", self.children().len()).unwrap();
95        }
96        result
97    }
98
99    /// This method will be called before the widget is destroyed (dropped). At the moment, when this
100    /// method is called, the widget is still in the widget graph and can be accessed via handles. It
101    /// is guaranteed to be called once, and only if the widget is deleted via [`crate::widget::WidgetMessage::remove`].
102    fn on_remove(&self, #[allow(unused_variables)] sender: &Sender<UiMessage>) {}
103
104    /// This method is used to override measurement step of the layout system. It should return desired size of
105    /// the widget (how many space it wants to occupy).
106    ///
107    /// ## Example
108    ///
109    /// ```rust
110    /// # use fyrox_ui::{
111    /// #     core::algebra::Vector2, define_widget_deref, message::UiMessage, Control, UserInterface,
112    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
113    /// #     widget::Widget, UiNode
114    /// # };
115    /// # use std::{
116    /// #     any::{Any, TypeId},
117    /// #     ops::{Deref, DerefMut},
118    /// # };
119    /// # use fyrox_core::uuid_provider;
120    /// # use fyrox_graph::BaseSceneGraph;
121    /// #
122    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
123    /// #[reflect(derived_type = "UiNode")]
124    /// struct MyWidget {
125    ///     widget: Widget,
126    /// }
127    /// #
128    /// # define_widget_deref!(MyWidget);
129    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
130    /// impl Control for MyWidget {
131    ///     fn measure_override(
132    ///         &self,
133    ///         ui: &UserInterface,
134    ///         available_size: Vector2<f32>,
135    ///     ) -> Vector2<f32> {
136    ///         let mut size: Vector2<f32> = Vector2::default();
137    ///
138    ///         // Measure children nodes and find the largest size of them.
139    ///         for &child in self.children.iter() {
140    ///             // Recursively measure children nodes. Measured size will be put in `desired_size`
141    ///             // of the widget.
142    ///             ui.measure_node(child, available_size);
143    ///
144    ///             // Find max size across all the children widgets.
145    ///             size = size.sup(&ui.node(child).desired_size());
146    ///         }
147    ///
148    ///         size
149    ///     }
150    ///     #
151    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
152    ///     #     todo!()
153    ///     # }
154    /// }
155    /// ```
156    ///
157    /// The goal of this method is to supply the UI system with the size requirements of all descendants
158    /// of the widget. In this example we measure all descendants recursively and finding the max desired
159    /// size of across all the children widgets. This effectively does the following: size of this widget
160    /// will be the max size of children widgets. Some widgets (like [`crate::canvas::Canvas`]), can provide infinite
161    /// constraints to children nodes, to fetch unconstrained desired size.
162    ///
163    /// It is recommended to check implementation of this method of built-in widgets (such as [`crate::canvas::Canvas`],
164    /// [`crate::stack_panel::StackPanel`], [`crate::wrap_panel::WrapPanel`], [`crate::grid::Grid`]). It should help you to
165    /// understand measurement step better.
166    fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
167        self.deref().measure_override(ui, available_size)
168    }
169
170    /// This method is used to override arrangement step of the layout system. Arrangement step is used to
171    /// commit the final location and size of the widget in local coordinates. It is done after the measurement
172    /// step; when all desired sizes of every widget is known. This fact allows you to calculate final location
173    /// and size of every child widget, based in their desired size. Usually this method is used in some panel
174    /// widgets, that takes their children and arranges them in some specific way. For example, it may stack
175    /// widgets on top of each other, or put them in a line with wrapping, etc.
176    ///
177    /// ## Example
178    ///
179    /// ```rust
180    /// # use fyrox_ui::{
181    /// #     core::{algebra::Vector2, math::Rect},
182    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
183    /// #     define_widget_deref,
184    /// #     message::UiMessage,
185    /// #     Control, UserInterface, widget::Widget, UiNode
186    /// # };
187    /// # use std::{
188    /// #     any::{Any, TypeId},
189    /// #     ops::{Deref, DerefMut},
190    /// # };
191    /// # use fyrox_core::uuid_provider;
192    /// #
193    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
194    /// #[reflect(derived_type = "UiNode")]
195    /// struct MyWidget {
196    ///     widget: Widget,
197    /// }
198    /// #
199    /// # define_widget_deref!(MyWidget);
200    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
201    /// impl Control for MyWidget {
202    ///     fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
203    ///         let final_rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
204    ///
205    ///         // Commit final locations and size for each child node.
206    ///         for &child in self.children.iter() {
207    ///             ui.arrange_node(child, &final_rect);
208    ///         }
209    ///
210    ///         final_size
211    ///     }
212    ///     #
213    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
214    ///     #     todo!()
215    ///     # }
216    /// }
217    /// ```
218    ///
219    /// This example arranges all the children widgets using the given `final_size`, that comes from the
220    /// parent widget, so all children will have exactly the same size as the parent and be located at (0;0)
221    /// point in local coordinates.
222    ///
223    /// It is recommended to check implementation of this method of built-in widgets (such as [`crate::canvas::Canvas`],
224    /// [`crate::stack_panel::StackPanel`], [`crate::wrap_panel::WrapPanel`], [`crate::grid::Grid`]). It should help you to
225    /// understand arrangement step better.
226    fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
227        self.deref().arrange_override(ui, final_size)
228    }
229
230    /// This method is used to emit drawing commands that will be used later to draw your widget on screen.
231    /// Keep in mind that any emitted geometry (quads, lines, text, etc), will be used to perform hit test.
232    /// In other words, all the emitted geometry will make your widget "clickable". Widgets with no geometry
233    /// emitted by this method are mouse input transparent.
234    ///
235    /// ## Example
236    ///
237    /// ```rust
238    /// # use fyrox_ui::{
239    /// #     define_widget_deref,
240    /// #     draw::{CommandTexture, Draw, DrawingContext},
241    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
242    /// #     message::UiMessage,
243    /// #     Control, UserInterface, widget::Widget, UiNode
244    /// # };
245    /// # use std::{
246    /// #     any::{Any, TypeId},
247    /// #     ops::{Deref, DerefMut},
248    /// # };
249    /// # use fyrox_core::uuid_provider;
250    /// #
251    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
252    /// #[reflect(derived_type = "UiNode")]
253    /// struct MyWidget {
254    ///     widget: Widget,
255    /// }
256    /// #
257    /// # define_widget_deref!(MyWidget);
258    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
259    /// impl Control for MyWidget {
260    /// fn draw(&self, drawing_context: &mut DrawingContext) {
261    ///     let bounds = self.widget.bounding_rect();
262    ///
263    ///     // Push a rect.
264    ///     drawing_context.push_rect_filled(&bounds, None);
265    ///
266    ///     // Commit the geometry, it is mandatory step, otherwise your widget's geometry
267    ///     // will be "attached" to some other widget that will call `commit`.
268    ///     drawing_context.commit(
269    ///         self.clip_bounds(),
270    ///         self.widget.background(),
271    ///         CommandTexture::None,
272    ///         &self.material,
273    ///         None,
274    ///     );
275    /// }
276    ///     #
277    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
278    ///     #     todo!()
279    ///     # }
280    /// }
281    /// ```
282    ///
283    /// This example shows how to draw a simple quad using the background brush of the widget. See docs
284    /// for [`DrawingContext`] for more info.
285    fn draw(&self, #[allow(unused_variables)] drawing_context: &mut DrawingContext) {}
286
287    fn on_visual_transform_changed(
288        &self,
289        #[allow(unused_variables)] old_transform: &Matrix3<f32>,
290        #[allow(unused_variables)] new_transform: &Matrix3<f32>,
291    ) {
292    }
293
294    /// The same as [`Self::draw`], but it runs after all descendant widgets are rendered.
295    fn post_draw(&self, #[allow(unused_variables)] drawing_context: &mut DrawingContext) {}
296
297    /// This method is called every frame and can be used to update internal variables of the widget, that
298    /// can be used to animated your widget. Its main difference from other methods, is that it does **not**
299    /// provide access to any other widget in the UI. Instead, you can only send messages to widgets to
300    /// force them to change their state.
301    ///
302    /// ## Important notes
303    ///
304    /// Due to performance reasons, you **must** set `.with_need_update(true)` in widget builder to
305    /// force library to call `update` method!
306    fn update(
307        &mut self,
308        #[allow(unused_variables)] dt: f32,
309        #[allow(unused_variables)] ui: &mut UserInterface,
310    ) {
311    }
312
313    /// Performs event-specific actions. Must call widget.handle_message()!
314    ///
315    /// # Notes
316    ///
317    /// Do *not* try to borrow node by `self_handle` in UI - at this moment node has been moved
318    /// out of pool and attempt of borrowing will cause panic! `self_handle` should be used only
319    /// to check if event came from/for this node or to capture input on node.
320    fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage);
321
322    /// Used to react to a message (by producing another message) that was posted outside of current
323    /// hierarchy. In other words this method is used when you need to "peek" a message before it'll
324    /// be passed into bubbling router. Most common use case is to catch messages from popups: popup
325    /// in 99.9% cases is a child of root canvas and it **won't** receive a message from a its *logical*
326    /// parent during bubbling message routing. For example `preview_message` used in a dropdown list:
327    /// dropdown list has two separate parts - a field with selected value and a popup for all possible
328    /// options. Visual parent of the popup in this case is the root canvas, but logical parent is the
329    /// dropdown list. Because of this fact, the field won't receive any messages from popup, to solve
330    /// this we use `preview_message`. This method is much more restrictive - it does not allow you to
331    /// modify a node and ui, you can either *request* changes by sending a message or use internal
332    /// mutability (`Cell`, `RefCell`, etc).
333    ///
334    /// ## Important notes
335    ///
336    /// Due to performance reasons, you **must** set `.with_preview_messages(true)` in widget builder to
337    /// force library to call `preview_message`!
338    ///
339    /// The order of execution of this method is undefined! There is no guarantee that it will be called
340    /// hierarchically as widgets connected.
341    fn preview_message(
342        &self,
343        #[allow(unused_variables)] ui: &UserInterface,
344        #[allow(unused_variables)] message: &mut UiMessage,
345    ) {
346        // This method is optional.
347    }
348
349    /// Provides a way to respond to OS specific events. Can be useful to detect if a key or mouse
350    /// button was pressed. This method significantly differs from `handle_message` because os events
351    /// are not dispatched - they'll be passed to this method in any case.
352    ///
353    /// ## Important notes
354    ///
355    /// Due to performance reasons, you **must** set `.with_handle_os_messages(true)` in widget builder to
356    /// force library to call `handle_os_event`!
357    fn handle_os_event(
358        &mut self,
359        #[allow(unused_variables)] self_handle: Handle<UiNode>,
360        #[allow(unused_variables)] ui: &mut UserInterface,
361        #[allow(unused_variables)] event: &OsEvent,
362    ) {
363    }
364
365    /// Checks whether a `widget` will be accepted by the current widget or not when dropped. This
366    /// method is used only to switch the cursor icon. The default implementation returns `allow_drop`
367    /// flag of the widget, which, if set to `true`, basically allows unconditional drop of any content.
368    fn accepts_drop(
369        &self,
370        #[allow(unused_variables)] widget: Handle<UiNode>,
371        #[allow(unused_variables)] ui: &UserInterface,
372    ) -> bool {
373        *self.allow_drop
374    }
375}
376
377// Essentially implements ObjectOrVariant for Control types.
378// See ObjectOrVariantHelper for the cause of the indirection.
379impl<T: Control> ObjectOrVariantHelper<UiNode, T> for PhantomData<T> {
380    fn convert_to_dest_type_helper(node: &UiNode) -> Option<&T> {
381        ControlAsAny::as_any(node.0.deref()).downcast_ref()
382    }
383    fn convert_to_dest_type_helper_mut(node: &mut UiNode) -> Option<&mut T> {
384        ControlAsAny::as_any_mut(node.0.deref_mut()).downcast_mut()
385    }
386}