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, Downcast, TypeUuidProvider},
24    draw::DrawingContext,
25    message::{OsEvent, UiMessage},
26    widget::Widget,
27    UiNode, UserInterface,
28};
29use std::{
30    any::Any,
31    ops::{Deref, DerefMut},
32    sync::mpsc::Sender,
33};
34
35/// Base trait for all UI widgets. It has auto-impl and you don't need to implement it manually. Your widget
36/// must implement [`Clone`] and [`Control`] traits for impl to be generated for you, also your widget must
37/// not contain any references (due to `'static` lifetime requirement).
38pub trait BaseControl: Send + Downcast {
39    /// Returns the exact copy of the widget in "type-erased" form.
40    fn clone_boxed(&self) -> Box<dyn Control>;
41
42    /// Returns type name of the widget.
43    fn type_name(&self) -> &'static str;
44
45    fn id(&self) -> Uuid;
46
47    /// Returns total amount of memory used by this widget (in bytes), in other words it returns
48    /// `size_of::<WidgetType>()`.
49    fn self_size(&self) -> usize;
50}
51
52impl<T> BaseControl for T
53where
54    T: Any + Clone + 'static + Control + TypeUuidProvider,
55{
56    fn clone_boxed(&self) -> Box<dyn Control> {
57        Box::new(self.clone())
58    }
59
60    fn type_name(&self) -> &'static str {
61        std::any::type_name::<T>()
62    }
63
64    fn id(&self) -> Uuid {
65        Self::type_uuid()
66    }
67
68    fn self_size(&self) -> usize {
69        size_of::<T>()
70    }
71}
72
73/// Trait for all UI controls in library.
74pub trait Control:
75    BaseControl + Deref<Target = Widget> + DerefMut + Reflect + Visit + ComponentProvider
76{
77    /// This method will be called before the widget is destroyed (dropped). At the moment, when this
78    /// method is called, the widget is still in the widget graph and can be accessed via handles. It
79    /// is guaranteed to be called once, and only if the widget is deleted via [`crate::widget::WidgetMessage::remove`].
80    fn on_remove(&self, #[allow(unused_variables)] sender: &Sender<UiMessage>) {}
81
82    /// This method is used to override measurement step of the layout system. It should return desired size of
83    /// the widget (how many space it wants to occupy).
84    ///
85    /// ## Example
86    ///
87    /// ```rust
88    /// # use fyrox_ui::{
89    /// #     core::algebra::Vector2, define_widget_deref, message::UiMessage, Control, UserInterface,
90    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
91    /// #     widget::Widget,
92    /// # };
93    /// # use std::{
94    /// #     any::{Any, TypeId},
95    /// #     ops::{Deref, DerefMut},
96    /// # };
97    /// # use fyrox_core::uuid_provider;
98    /// # use fyrox_graph::BaseSceneGraph;
99    /// #
100    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
101    /// struct MyWidget {
102    ///     widget: Widget,
103    /// }
104    /// #
105    /// # define_widget_deref!(MyWidget);
106    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
107    /// impl Control for MyWidget {
108    ///     fn measure_override(
109    ///         &self,
110    ///         ui: &UserInterface,
111    ///         available_size: Vector2<f32>,
112    ///     ) -> Vector2<f32> {
113    ///         let mut size: Vector2<f32> = Vector2::default();
114    ///
115    ///         // Measure children nodes and find the largest size of them.
116    ///         for &child in self.children.iter() {
117    ///             // Recursively measure children nodes. Measured size will be put in `desired_size`
118    ///             // of the widget.
119    ///             ui.measure_node(child, available_size);
120    ///
121    ///             // Find max size across all the children widgets.
122    ///             size = size.sup(&ui.node(child).desired_size());
123    ///         }
124    ///
125    ///         size
126    ///     }
127    ///     #
128    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
129    ///     #     todo!()
130    ///     # }
131    /// }
132    /// ```
133    ///
134    /// The goal of this method is to supply the UI system with the size requirements of all descendants
135    /// of the widget. In this example we measure all descendants recursively and finding the max desired
136    /// size of across all the children widgets. This effectively does the following: size of this widget
137    /// will be the max size of children widgets. Some widgets (like [`crate::canvas::Canvas`]), can provide infinite
138    /// constraints to children nodes, to fetch unconstrained desired size.
139    ///
140    /// It is recommended to check implementation of this method of built-in widgets (such as [`crate::canvas::Canvas`],
141    /// [`crate::stack_panel::StackPanel`], [`crate::wrap_panel::WrapPanel`], [`crate::grid::Grid`]). It should help you to
142    /// understand measurement step better.
143    fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
144        self.deref().measure_override(ui, available_size)
145    }
146
147    /// This method is used to override arrangement step of the layout system. Arrangement step is used to
148    /// commit the final location and size of the widget in local coordinates. It is done after the measurement
149    /// step; when all desired sizes of every widget is known. This fact allows you to calculate final location
150    /// and size of every child widget, based in their desired size. Usually this method is used in some panel
151    /// widgets, that takes their children and arranges them in some specific way. For example, it may stack
152    /// widgets on top of each other, or put them in a line with wrapping, etc.
153    ///
154    /// ## Example
155    ///
156    /// ```rust
157    /// # use fyrox_ui::{
158    /// #     core::{algebra::Vector2, math::Rect},
159    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
160    /// #     define_widget_deref,
161    /// #     message::UiMessage,
162    /// #     Control, UserInterface, widget::Widget,
163    /// # };
164    /// # use std::{
165    /// #     any::{Any, TypeId},
166    /// #     ops::{Deref, DerefMut},
167    /// # };
168    /// # use fyrox_core::uuid_provider;
169    /// #
170    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
171    /// struct MyWidget {
172    ///     widget: Widget,
173    /// }
174    /// #
175    /// # define_widget_deref!(MyWidget);
176    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
177    /// impl Control for MyWidget {
178    ///     fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
179    ///         let final_rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
180    ///
181    ///         // Commit final locations and size for each child node.
182    ///         for &child in self.children.iter() {
183    ///             ui.arrange_node(child, &final_rect);
184    ///         }
185    ///
186    ///         final_size
187    ///     }
188    ///     #
189    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
190    ///     #     todo!()
191    ///     # }
192    /// }
193    /// ```
194    ///
195    /// This example arranges all the children widgets using the given `final_size`, that comes from the
196    /// parent widget, so all children will have exactly the same size as the parent and be located at (0;0)
197    /// point in local coordinates.
198    ///
199    /// It is recommended to check implementation of this method of built-in widgets (such as [`crate::canvas::Canvas`],
200    /// [`crate::stack_panel::StackPanel`], [`crate::wrap_panel::WrapPanel`], [`crate::grid::Grid`]). It should help you to
201    /// understand arrangement step better.
202    fn arrange_override(&self, ui: &UserInterface, final_size: Vector2<f32>) -> Vector2<f32> {
203        self.deref().arrange_override(ui, final_size)
204    }
205
206    /// This method is used to emit drawing commands that will be used later to draw your widget on screen.
207    /// Keep in mind that any emitted geometry (quads, lines, text, etc), will be used to perform hit test.
208    /// In other words, all the emitted geometry will make your widget "clickable". Widgets with no geometry
209    /// emitted by this method are mouse input transparent.
210    ///
211    /// ## Example
212    ///
213    /// ```rust
214    /// # use fyrox_ui::{
215    /// #     define_widget_deref,
216    /// #     draw::{CommandTexture, Draw, DrawingContext},
217    /// #     core::{visitor::prelude::*, reflect::prelude::*, type_traits::prelude::*,},
218    /// #     message::UiMessage,
219    /// #     Control, UserInterface, widget::Widget,
220    /// # };
221    /// # use std::{
222    /// #     any::{Any, TypeId},
223    /// #     ops::{Deref, DerefMut},
224    /// # };
225    /// # use fyrox_core::uuid_provider;
226    /// #
227    /// #[derive(Clone, Visit, Reflect, Debug, ComponentProvider)]
228    /// struct MyWidget {
229    ///     widget: Widget,
230    /// }
231    /// #
232    /// # define_widget_deref!(MyWidget);
233    /// # uuid_provider!(MyWidget = "a93ec1b5-e7c8-4919-ac19-687d8c99f6bd");
234    /// impl Control for MyWidget {
235    /// fn draw(&self, drawing_context: &mut DrawingContext) {
236    ///     let bounds = self.widget.bounding_rect();
237    ///
238    ///     // Push a rect.
239    ///     drawing_context.push_rect_filled(&bounds, None);
240    ///
241    ///     // Commit the geometry, it is mandatory step, otherwise your widget's geometry
242    ///     // will be "attached" to some other widget that will call `commit`.
243    ///     drawing_context.commit(
244    ///         self.clip_bounds(),
245    ///         self.widget.background(),
246    ///         CommandTexture::None,
247    ///         None,
248    ///     );
249    /// }
250    ///     #
251    ///     # fn handle_routed_message(&mut self, _ui: &mut UserInterface, _message: &mut UiMessage) {
252    ///     #     todo!()
253    ///     # }
254    /// }
255    /// ```
256    ///
257    /// This example shows how to draw a simple quad using the background brush of the widget. See docs
258    /// for [`DrawingContext`] for more info.
259    fn draw(&self, #[allow(unused_variables)] drawing_context: &mut DrawingContext) {}
260
261    fn on_visual_transform_changed(&self) {}
262
263    /// The same as [`Self::draw`], but it runs after all descendant widgets are rendered.
264    fn post_draw(&self, #[allow(unused_variables)] drawing_context: &mut DrawingContext) {}
265
266    /// This method is called every frame and can be used to update internal variables of the widget, that
267    /// can be used to animated your widget. Its main difference from other methods, is that it does **not**
268    /// provide access to any other widget in the UI. Instead, you can only send messages to widgets to
269    /// force them to change their state.
270    ///
271    /// ## Important notes
272    ///
273    /// Due to performance reasons, you **must** set `.with_need_update(true)` in widget builder to
274    /// force library to call `update` method!
275    fn update(
276        &mut self,
277        #[allow(unused_variables)] dt: f32,
278        #[allow(unused_variables)] ui: &mut UserInterface,
279    ) {
280    }
281
282    /// Performs event-specific actions. Must call widget.handle_message()!
283    ///
284    /// # Notes
285    ///
286    /// Do *not* try to borrow node by `self_handle` in UI - at this moment node has been moved
287    /// out of pool and attempt of borrowing will cause panic! `self_handle` should be used only
288    /// to check if event came from/for this node or to capture input on node.
289    fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage);
290
291    /// Used to react to a message (by producing another message) that was posted outside of current
292    /// hierarchy. In other words this method is used when you need to "peek" a message before it'll
293    /// be passed into bubbling router. Most common use case is to catch messages from popups: popup
294    /// in 99.9% cases is a child of root canvas and it **won't** receive a message from a its *logical*
295    /// parent during bubbling message routing. For example `preview_message` used in a dropdown list:
296    /// dropdown list has two separate parts - a field with selected value and a popup for all possible
297    /// options. Visual parent of the popup in this case is the root canvas, but logical parent is the
298    /// dropdown list. Because of this fact, the field won't receive any messages from popup, to solve
299    /// this we use `preview_message`. This method is much more restrictive - it does not allow you to
300    /// modify a node and ui, you can either *request* changes by sending a message or use internal
301    /// mutability (`Cell`, `RefCell`, etc).
302    ///
303    /// ## Important notes
304    ///
305    /// Due to performance reasons, you **must** set `.with_preview_messages(true)` in widget builder to
306    /// force library to call `preview_message`!
307    ///
308    /// The order of execution of this method is undefined! There is no guarantee that it will be called
309    /// hierarchically as widgets connected.
310    fn preview_message(
311        &self,
312        #[allow(unused_variables)] ui: &UserInterface,
313        #[allow(unused_variables)] message: &mut UiMessage,
314    ) {
315        // This method is optional.
316    }
317
318    /// Provides a way to respond to OS specific events. Can be useful to detect if a key or mouse
319    /// button was pressed. This method significantly differs from `handle_message` because os events
320    /// are not dispatched - they'll be passed to this method in any case.
321    ///
322    /// ## Important notes
323    ///
324    /// Due to performance reasons, you **must** set `.with_handle_os_messages(true)` in widget builder to
325    /// force library to call `handle_os_event`!
326    fn handle_os_event(
327        &mut self,
328        #[allow(unused_variables)] self_handle: Handle<UiNode>,
329        #[allow(unused_variables)] ui: &mut UserInterface,
330        #[allow(unused_variables)] event: &OsEvent,
331    ) {
332    }
333}