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}