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
use crate::menu_systems::Menu;
use crate::{Events, VirtualKeyCode};
/// Te way that is used to select the menu when switching menus
///
/// Default is ByLocation(true, true)
pub enum MenuSelectionMethod {
/// Select by the closest point where the selection were when the menu got switched.
/// Including/Excluding x or y will mean that those distance values will be discarded when comparing distances.
///
/// (include_x, include_y)
ByLocation(bool, bool),
/// Select by the current select_idx. This is only rarely what you want.
ByIndex(),
}
impl Default for MenuSelectionMethod {
fn default() -> MenuSelectionMethod {
MenuSelectionMethod::ByLocation(true, true)
}
}
/// A very neat tool designed to be used in making ie. button grids
///
/// Allows the navigation between menus. Very useful if you have multiple rows of menus.
pub struct MenuSwitcher {
previous_selection_idx: u32,
select_idx: u32,
selection_method: MenuSelectionMethod,
focused: bool,
previous_button: VirtualKeyCode,
next_button: VirtualKeyCode,
}
impl Default for MenuSwitcher {
fn default() -> MenuSwitcher {
MenuSwitcher {
previous_selection_idx: 0,
select_idx: 0,
selection_method: Default::default(),
focused: true,
previous_button: VirtualKeyCode::Left,
next_button: VirtualKeyCode::Right,
}
}
}
impl MenuSwitcher {
/// Create a new MenuSwitcher
pub fn new(previous: VirtualKeyCode, next: VirtualKeyCode) -> MenuSwitcher {
MenuSwitcher {
previous_selection_idx: 0,
select_idx: 0,
selection_method: Default::default(),
focused: true,
previous_button: previous,
next_button: next,
}
}
/// Change the [`MenuSelectionMethod`](struct.MenuSelectionMethod.html). Default is ByLocation(true, true)
pub fn with_selection_method(mut self, selection_method: MenuSelectionMethod) -> MenuSwitcher {
self.selection_method = selection_method;
self
}
/// Change whether this switcher is focused, meaning if any of it's menus should be focused.
///
/// Default is true.
pub fn with_focus(mut self, focused: bool) -> MenuSwitcher {
self.focused = focused;
self
}
/// Change the [`MenuSelectionMethod`](struct.MenuSelectionMethod.html). Default is ByLocation(true, true)
pub fn set_selection_method(&mut self, selection_method: MenuSelectionMethod) {
self.selection_method = selection_method;
}
/// Change whether this switcher is focused, meaning if any of it's menus should be focused.
///
/// Default is true.
pub fn set_focus(&mut self, focused: bool) {
self.focused = focused;
}
/// Set the index of the Menu that is selected. At update, the idx will clamp between 0 and the max idx.
pub fn set_select_idx(&mut self, idx: u32) {
self.previous_selection_idx = self.select_idx;
self.select_idx = idx;
}
/// Update the menu switcher, change select indexes if necessary and handle events.
pub fn update(&mut self, events: &Events, list: &mut [&mut Menu]) {
let length = list.len() as u32;
// Nothing to update
if length == 0 {
self.select_idx = 0;
return;
}
self.select_idx = (self.select_idx as i32).min(length as i32 - 1).max(0) as u32;
if self.focused {
if events.keyboard.was_just_pressed(self.previous_button) {
self.previous_selection_idx = self.select_idx;
self.select_idx = (self.select_idx + length - 1) % length;
}
if events.keyboard.was_just_pressed(self.next_button) {
self.previous_selection_idx = self.select_idx;
self.select_idx = (self.select_idx + 1) % length;
}
}
for (idx, menu) in list.iter_mut().enumerate() {
menu.set_focused(idx as u32 == self.select_idx && self.focused);
}
if self.previous_selection_idx != self.select_idx {
let p_select_idx = list[self.previous_selection_idx as usize].get_select_idx();
let prev_menu = &list[self.previous_selection_idx as usize];
let curr_pos = prev_menu.get_cloned_list()[prev_menu.get_select_idx() as usize]
.get_base()
.get_pos();
match self.selection_method {
MenuSelectionMethod::ByLocation(include_x, include_y) => {
let mut closest_idx = 0;
let mut closest_distance = 100_000;
for (idx, item) in list[self.select_idx as usize]
.get_cloned_list()
.into_iter()
.enumerate()
{
let distance_x = if include_x {
(curr_pos.0 as i32 - item.get_base().get_pos().0 as i32).abs() as u32
} else {
0
};
let distance_y = if include_y {
(curr_pos.1 as i32 - item.get_base().get_pos().1 as i32).abs() as u32
} else {
0
};
let distance = distance_x + distance_y;
if distance < closest_distance {
closest_idx = idx as u32;
closest_distance = distance;
}
}
list[self.select_idx as usize].set_select_idx(closest_idx);
}
MenuSelectionMethod::ByIndex() => {
list[self.select_idx as usize].set_select_idx(p_select_idx);
}
}
}
self.previous_selection_idx = self.select_idx;
}
}