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)
    }
}