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