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}