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
//! Build context is used to decouple explicit UI state modification. See [`BuildContext`] docs for
//! more info.
use crate::{
core::pool::Handle, message::UiMessage, ttf::SharedFont, RestrictionEntry, UiNode,
UserInterface,
};
use std::{
ops::{Index, IndexMut},
sync::mpsc::Sender,
};
/// Build context is used to decouple explicit UI state modification. Its main use is in the various widget
/// builders. Internally, it is just a mutable reference to the UI state. UI can be modified (add nodes, clone,
/// link, etc.) via build context. This is needed to explicitly highlight that it used to modify the UI
/// state. It is **not recommended** to use BuildContext for mutable access to widgets at runtime! _Use message
/// passing_ to modify widgets at runtime, otherwise you will easily break invariant (inner state) of widgets.
/// The only place where it's allowed to directly mutate widget's state is at build stage (inside `build`
/// method of your widget builder).
///
/// ## Examples
///
/// ```rust
/// # use fyrox_ui::{
/// # core::pool::Handle,
/// # define_widget_deref,
/// # message::UiMessage,
/// # widget::{Widget, WidgetBuilder},
/// # BuildContext, Control, UiNode, UserInterface,
/// # };
/// # use std::{
/// # any::{Any, TypeId},
/// # ops::{Deref, DerefMut},
/// # };
/// #
/// #[derive(Clone)]
/// struct MyWidget {
/// widget: Widget,
/// }
/// #
/// # define_widget_deref!(MyWidget);
/// #
/// # impl Control for MyWidget {
/// # fn query_component(&self, type_id: TypeId) -> Option<&dyn Any> {
/// # todo!()
/// # }
/// #
/// # fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
/// # todo!()
/// # }
/// # }
///
/// struct MyWidgetBuilder {
/// widget_builder: WidgetBuilder,
/// }
///
/// impl MyWidgetBuilder {
/// pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
/// let my_widget = MyWidget {
/// widget: self.widget_builder.build(),
/// };
///
/// ctx.add_node(UiNode::new(my_widget))
/// }
/// }
/// ```
pub struct BuildContext<'a> {
ui: &'a mut UserInterface,
}
impl<'a> Index<Handle<UiNode>> for BuildContext<'a> {
type Output = UiNode;
fn index(&self, index: Handle<UiNode>) -> &Self::Output {
&self.ui.nodes[index]
}
}
impl<'a> IndexMut<Handle<UiNode>> for BuildContext<'a> {
fn index_mut(&mut self, index: Handle<UiNode>) -> &mut Self::Output {
&mut self.ui.nodes[index]
}
}
impl<'a> From<&'a mut UserInterface> for BuildContext<'a> {
fn from(ui: &'a mut UserInterface) -> Self {
Self { ui }
}
}
impl<'a> BuildContext<'a> {
/// Returns default font instance used by the UI.
pub fn default_font(&self) -> SharedFont {
self.ui.default_font.clone()
}
/// Returns current message sender of the UI, that is used for message passing mechanism. You can
/// send messages for your widgets inside your builders, however this has limited use and should
/// be avoided in the favor of explicit state modification to not overload message pipeline.
pub fn sender(&self) -> Sender<UiMessage> {
self.ui.sender()
}
/// Adds a new widget to the UI. See [`UiNode`] docs for more info, [`UiNode::new`] in particular.
pub fn add_node(&mut self, node: UiNode) -> Handle<UiNode> {
self.ui.add_node(node)
}
/// Links the child widget with the parent widget. Child widget's position and size will be restricted by
/// the new parent. When a widget is linked to other widget, its coordinates become relative to it parent.
pub fn link(&mut self, child: Handle<UiNode>, parent: Handle<UiNode>) {
self.ui.link_nodes_internal(child, parent, false)
}
/// Copies a widget, adds it to the UI, links it to the root node of the UI and returns the handle to it.
pub fn copy(&mut self, node: Handle<UiNode>) -> Handle<UiNode> {
self.ui.copy_node(node)
}
/// Tries to fetch the node by its handle. Returns `None` if the handle is invalid.
pub fn try_get_node(&self, node: Handle<UiNode>) -> Option<&UiNode> {
self.ui.try_get_node(node)
}
/// Tries to fetch the node by its handle. Returns `None` if the handle is invalid.
pub fn try_get_node_mut(&mut self, node: Handle<UiNode>) -> Option<&mut UiNode> {
self.ui.nodes.try_borrow_mut(node)
}
/// Pushes a new picking restriction to the picking-restriction stack. See [`UserInterface::push_picking_restriction`]
/// docs for more info.
pub fn push_picking_restriction(&mut self, restriction: RestrictionEntry) {
self.ui.push_picking_restriction(restriction)
}
/// Explicitly removes picking restriction for the given node from the picking-restriction stack. See
/// [`UserInterface::remove_picking_restriction`] docs for more info.
pub fn remove_picking_restriction(&mut self, node: Handle<UiNode>) {
self.ui.remove_picking_restriction(node)
}
}