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}