pushrod/render/
callbacks.rs

1// Pushrod Rendering Library
2// Widget Base Definition
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::render::layout_cache::LayoutContainer;
17use crate::render::widget::Widget;
18use crate::render::widget_cache::WidgetContainer;
19
20/// This is an `FnMut` type that takes no additional parameters, returning a mutable reference
21/// to the current `Widget`, and borrowing the `WidgetContainer` and `LayoutContainer` lists.
22pub type FunctionNoParametersType =
23    Option<Box<dyn FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer])>>;
24
25/// This is an `FnMut` that takes a `Point` as a `Vec<i32>` of points: X and Y, returning a mutable reference
26/// to the current `Widget`, and borrowing the `WidgetContainer` and `LayoutContainer` lists.
27pub type FunctionPointParametersType =
28    Option<Box<dyn FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer], Vec<i32>)>>;
29
30/// This is an `FnMut` that takes a button click ID, the number of clicks, the click state (`true` indicating
31/// the click was pressed, `false` otherwise), returning a mutable reference
32/// to the current `Widget`, and borrowing the `WidgetContainer` and `LayoutContainer` lists.
33pub type FunctionClickParametersType =
34    Option<Box<dyn FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer], u8, u8, bool)>>;
35
36/// This is a registry that contains a series of `FnMut` definitions for actions that can be applied
37/// to a `Widget`.  These can vary from a screen refresh (`tick`), to a mouse move event, etc.  Each
38/// callback gains access to the list of `WidgetContainer` objects stored by the cache.  This is
39/// important in case you wish to modify other `Widget`s on the screen as a result of some action
40/// that took place.
41///
42/// Keep in mind, however, that you _cannot_ re-borrow your own widget from the `WidgetContainer`
43/// list, as this will cause a runtime exception.  For that, use the top-level `Widget` object that
44/// was supplied.  This will allow you to make changes to the current `Widget` reference, since it
45/// is an active, `mutable` reference.
46#[derive(Default)]
47pub struct CallbackRegistry {
48    /// This is the function that is set when a screen refresh cycle occurs.  This function is
49    /// always guaranteed to be called, but there is no guarantee it will call it consistently
50    /// because of the screen refresh rate.  If there is a lot of activity on the screen, this
51    /// callback will be called less often.
52    pub on_tick: FunctionNoParametersType,
53
54    /// This function is called when a mouse enters the scope of a `Widget`.
55    pub on_mouse_entered: FunctionNoParametersType,
56
57    /// This function is called when a mouse exits the scope of a `Widget`.
58    pub on_mouse_exited: FunctionNoParametersType,
59
60    /// This function is called when a mouse moves inside the scope of a `Widget`.  It contains
61    /// the points as a `Vec<i32>` containing the X and Y coordinates of the position of the mouse
62    /// inside the `Widget`.
63    pub on_mouse_moved: FunctionPointParametersType,
64
65    /// This function is called when a mouse scroll occurs inside the scope of a `Widget`.  It
66    /// contains the points as a `Vec<u8>` indicating the amount of movement either horizontally or
67    /// vertically.
68    pub on_mouse_scrolled: FunctionPointParametersType,
69
70    /// This function is called when a mouse button is pressed or released.  It contains the mouse
71    /// button number, the number of clicks registered, and a boolean flag indicating whether or not
72    /// the mouse button was pressed (`true`) or released (`false`).
73    pub on_mouse_clicked: FunctionClickParametersType,
74
75    has_on_tick: bool,
76    has_on_mouse_entered: bool,
77    has_on_mouse_exited: bool,
78    has_on_mouse_moved: bool,
79    has_on_mouse_scrolled: bool,
80    has_on_mouse_clicked: bool,
81}
82
83/// Implementation of the `CallbackRegistry`.
84impl CallbackRegistry {
85    /// Creates a new instance of this object.
86    pub fn new() -> Self {
87        Self {
88            on_tick: None,
89            on_mouse_entered: None,
90            on_mouse_exited: None,
91            on_mouse_moved: None,
92            on_mouse_scrolled: None,
93            on_mouse_clicked: None,
94            has_on_tick: false,
95            has_on_mouse_entered: false,
96            has_on_mouse_exited: false,
97            has_on_mouse_moved: false,
98            has_on_mouse_scrolled: false,
99            has_on_mouse_clicked: false,
100        }
101    }
102
103    /// Assigns an `FnMut` that will be called when a screen `tick` refresh is performed.  If this
104    /// is not set, this function will be bypassed.
105    pub fn on_tick<F>(&mut self, callback: F)
106    where
107        F: FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer]) + 'static,
108    {
109        self.on_tick = Some(Box::new(callback));
110        self.has_on_tick = true;
111    }
112
113    /// Assigns an `FnMut` that will be called when the mouse enters the scope of a `Widget`.  If this
114    /// is not set, this function will be bypassed.
115    pub fn on_mouse_entered<F>(&mut self, callback: F)
116    where
117        F: FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer]) + 'static,
118    {
119        self.on_mouse_entered = Some(Box::new(callback));
120        self.has_on_mouse_entered = true;
121    }
122
123    /// Assigns an `FnMut` that will be called when the mouse exits the scope of a `Widget`.  If this
124    /// is not set, this function will be bypassed.
125    pub fn on_mouse_exited<F>(&mut self, callback: F)
126    where
127        F: FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer]) + 'static,
128    {
129        self.on_mouse_exited = Some(Box::new(callback));
130        self.has_on_mouse_exited = true;
131    }
132
133    /// Assigns an `FnMut` that will be called when the mouse moves within the scope of a `Widget`.  If this
134    /// is not set, this function will be bypassed.
135    pub fn on_mouse_moved<F>(&mut self, callback: F)
136    where
137        F: FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer], Vec<i32>) + 'static,
138    {
139        self.on_mouse_moved = Some(Box::new(callback));
140        self.has_on_mouse_moved = true;
141    }
142
143    /// Assigns an `FnMut` that will be called when the mouse scroll occurs within the scope of a
144    /// `Widget`.  If this is not set, this function will be bypassed.
145    pub fn on_mouse_scrolled<F>(&mut self, callback: F)
146    where
147        F: FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer], Vec<i32>) + 'static,
148    {
149        self.on_mouse_scrolled = Some(Box::new(callback));
150        self.has_on_mouse_scrolled = true;
151    }
152
153    /// Assigns an `FnMut` that will be called when the mouse click occurs within the scope of a
154    /// `Widget`.  If this is not set, this function will be bypassed.
155    pub fn on_mouse_clicked<F>(&mut self, callback: F)
156    where
157        F: FnMut(&mut dyn Widget, &[WidgetContainer], &[LayoutContainer], u8, u8, bool) + 'static,
158    {
159        self.on_mouse_clicked = Some(Box::new(callback));
160        self.has_on_mouse_clicked = true;
161    }
162
163    /// Tells the `Widget` whether or not an `on_tick` callback has been set.
164    pub fn has_on_tick(&mut self) -> bool {
165        self.has_on_tick
166    }
167
168    /// Tells the `Widget` whether or not an `on_mouse_entered` callback has been set.
169    pub fn has_on_mouse_entered(&mut self) -> bool {
170        self.has_on_mouse_entered
171    }
172
173    /// Tells the `Widget` whether or not an `on_mouse_exited` callback has been set.
174    pub fn has_on_mouse_exited(&mut self) -> bool {
175        self.has_on_mouse_exited
176    }
177
178    /// Tells the `Widget` whether or not an `on_mouse_moved` callback has been set.
179    pub fn has_on_mouse_moved(&mut self) -> bool {
180        self.has_on_mouse_moved
181    }
182
183    /// Tells the `Widget` whether or not an `on_mouse_scrolled` callback has been set.
184    pub fn has_on_mouse_scrolled(&mut self) -> bool {
185        self.has_on_mouse_scrolled
186    }
187
188    /// Tells the `Widget` whether or not an `on_mouse_clicked` callback has been set.
189    pub fn has_on_mouse_clicked(&mut self) -> bool {
190        self.has_on_mouse_clicked
191    }
192}
193
194pub fn widget_id_for_name(widgets: &[WidgetContainer], name: String) -> usize {
195    match widgets.iter().find(|x| x.get_widget_name() == name.clone()) {
196        Some(x) => x.get_widget_id() as usize,
197        None => 0 as usize,
198    }
199}