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}