1use makepad_render::*;
2use crate::scrollview::*;
3
4#[derive(Clone, Default)]
5pub struct ListLogic {
6 pub list_items: Vec<ListItem>,
7 pub scroll_item_in_view: Option<usize>,
8 pub set_scroll_pos: Option<Vec2>,
9 pub start_item: usize,
11 pub end_item: usize,
12 pub end_fill: usize,
13 pub selection: Vec<usize>,
14 pub last_range: Option<(usize, usize)>,
15}
16
17#[derive(Clone)]
18pub struct ListItem {
19 pub animator: Animator,
20 pub is_selected: bool
21}
22
23pub enum ListLogicEvent {
24 Animate(AnimateEvent),
25 AnimEnded,
26 Select,
27 Deselect,
28 Cleanup,
29 Over,
30 Out
31}
32
33pub enum ListEvent {
34 SelectSingle(usize),
35 SelectMultiple,
36 None
37}
38
39#[derive(PartialEq)]
40pub enum ListSelect {
41 None,
42 Single(usize),
43 Range(usize),
44 Toggle(usize),
45 All
46}
47
48impl ListSelect {
49 pub fn item_index(&self) -> Option<usize> {
50 match self {
51 ListSelect::Single(index) => Some(*index),
52 _ => None
53 }
54 }
55}
56
57impl ListLogic {
58 pub fn set_list_len(&mut self, len: usize)
59 {
60 if self.list_items.len() < len {
61 for _ in self.list_items.len()..len {
62 self.list_items.push(ListItem {
63 animator: Animator::default(),
64 is_selected: false
65 })
66 }
67 }
68 else {
69 self.list_items.truncate(len);
70 }
71 }
72
73 pub fn handle_list_scroll_bars(&mut self, cx: &mut Cx, event: &mut Event, view: &mut ScrollView)
74 -> bool {
75 if view.handle_scroll_bars(cx, event) {
76 view.redraw_view_area(cx);
77 match &event {
78 Event::FingerScroll {..} => {
79 return true;
80 },
81 Event::FingerMove {..} => {
82 return true;
83 },
84 _ => ()
85 }
86 }
87 return false
88 }
89
90 pub fn begin_list(&mut self, cx: &mut Cx, view: &mut ScrollView, tail_list: bool, row_height: f32) -> Result<(), ()>
91 {
92 view.begin_view(cx, Layout {
93 direction: Direction::Down,
94 ..Layout::default()
95 }) ?;
96
97 self.set_visible_range_and_scroll(cx, view, tail_list, row_height);
98
99 Ok(())
100 }
101
102
103 pub fn walk_turtle_to_end(&mut self, cx: &mut Cx, row_height: f32) {
104 let left = (self.list_items.len() - self.end_item) as f32 * row_height;
105 cx.walk_turtle(Walk::wh(Width::Fill, Height::Fix(left)));
106 }
107
108
109 pub fn end_list(&mut self, cx: &mut Cx, view: &mut ScrollView) {
110 view.end_view(cx);
111 if let Some(set_scroll_pos) = self.set_scroll_pos {
112 view.set_scroll_pos(cx, set_scroll_pos);
113 }
114 }
115
116 pub fn set_visible_range_and_scroll(&mut self, cx: &mut Cx, view: &mut ScrollView, tail_list: bool, row_height: f32) {
117 let view_rect = cx.get_turtle_rect();
118
119 let max_scroll_y = ((self.list_items.len() + 1) as f32 * row_height - view_rect.h).max(0.);
121
122 let (scroll_pos, set_scroll_pos) = if tail_list {
124 (Vec2 {x: 0., y: max_scroll_y}, true)
125 }
126 else {
127 let sp = view.get_scroll_pos(cx);
128
129 if let Some(scroll_item_in_view) = self.scroll_item_in_view {
131 self.scroll_item_in_view = None;
132 let item_y = scroll_item_in_view as f32 * row_height;
133 let dy = (item_y + row_height) - (sp.y + view_rect.h);
134 if item_y < sp.y {
135 (Vec2 {x: 0., y: item_y}, true)
136 }
137 else if dy > 0. {
138 (Vec2 {x: 0., y: sp.y + dy}, true)
139 }
140 else {
141 (sp, false)
142 }
143 }
144 else {
145 if sp.y > max_scroll_y {
147 (Vec2 {x: 0., y: max_scroll_y}, false)
148 }
149 else {
150 (sp, false)
151 }
152 }
153 };
154
155 let start_item = (scroll_pos.y / row_height).floor() as usize;
156 let end_item = ((scroll_pos.y + view_rect.h + row_height) / row_height).ceil() as usize;
157
158 self.start_item = start_item.min(self.list_items.len());
159 self.end_fill = end_item;
160 self.end_item = end_item.min(self.list_items.len());
161
162 let start_scroll = (self.start_item as f32) * row_height;
163 if set_scroll_pos {
164 self.set_scroll_pos = Some(scroll_pos);
165 }
166 else {
167 self.set_scroll_pos = None;
168 }
169 cx.move_turtle(0., start_scroll);
171 }
172
173 pub fn get_next_single_selection(&self) -> ListSelect {
174 if let Some(last) = self.selection.last() {
175 let next = last + 1;
176 if next >= self.list_items.len() { ListSelect::Single(0)
178 }
179 else {
180 ListSelect::Single(next)
181 }
182 }
183 else {
184 ListSelect::Single(0)
185 }
186 }
187
188 pub fn get_prev_single_selection(&self) -> ListSelect {
189 if let Some(first) = self.selection.last() {
190 if *first == 0 { ListSelect::Single(self.list_items.len().max(1) - 1)
192 }
193 else {
194 ListSelect::Single(first - 1)
195 }
196 }
197 else {
198 ListSelect::Single(0)
199 }
200 }
201
202 pub fn handle_list_logic<F>(&mut self, cx: &mut Cx, event: &mut Event, select: ListSelect, mut cb: F) -> ListEvent
203 where F: FnMut(&mut Cx, ListLogicEvent, &mut ListItem, usize)
204 {
205 let mut select = select;
206
207 for counter in self.start_item..self.end_item {
208 if counter >= self.list_items.len() {
209 break;
210 }
211 let item = &mut self.list_items[counter];
212 match event.hits(cx, item.animator.area, HitOpt::default()) {
213 Event::Animate(ae) => {
214 cb(cx, ListLogicEvent::Animate(ae), item, counter)
215 },
216 Event::AnimEnded(_) => {
217 cb(cx, ListLogicEvent::AnimEnded, item, counter)
218 },
219 Event::FingerDown(fe) => {
220 cx.set_down_mouse_cursor(MouseCursor::Hand);
221 if fe.modifiers.logo || fe.modifiers.control {
222 select = ListSelect::Toggle(counter)
223 }
224 else if fe.modifiers.shift {
225 select = ListSelect::Range(counter)
226 }
227 else {
228 select = ListSelect::Single(counter)
229 }
230 },
231 Event::FingerUp(_fe) => {
232 },
233 Event::FingerMove(_fe) => {
234 },
235 Event::FingerHover(fe) => {
236 cx.set_hover_mouse_cursor(MouseCursor::Hand);
237 match fe.hover_state {
238 HoverState::In => {
239 cb(cx, ListLogicEvent::Over, item, counter);
240 },
241 HoverState::Out => {
242 cb(cx, ListLogicEvent::Out, item, counter);
243 },
244 _ => ()
245 }
246 },
247 _ => ()
248 }
249 };
250 if let Some(last_range) = self.last_range {
252 for counter in last_range.0..last_range.1 {
253 if counter >= self.list_items.len() {
254 break;
255 }
256 if counter < self.start_item || counter >= self.end_item {
257 let dm = &mut self.list_items[counter];
258 cb(cx, ListLogicEvent::Deselect, dm, counter);
259 }
260 }
261 }
262 self.last_range = Some((self.start_item, self.end_item));
263
264 match select {
265 ListSelect::Range(select_index) => {
266 if let Some(first) = self.selection.first() {
267 if let Some(last) = self.selection.last() {
268
269 let (start, end) = if select_index < *first {
270 (select_index, *last)
271 }
272 else if select_index > *last {
273 (*first, select_index)
274 }
275 else {
276 (select_index, select_index)
277 };
278
279 for counter in &self.selection {
280 if *counter >= self.list_items.len() || *counter >= start && *counter <= end {
281 continue;
282 }
283 let dm = &mut self.list_items[*counter];
284 if *counter != select_index {
285 dm.is_selected = false;
286 cb(cx, ListLogicEvent::Deselect, dm, select_index);
287 }
288 }
289 self.selection.truncate(0);
290 for i in start..= end {
291 let dm = &mut self.list_items[i];
292 dm.is_selected = true;
293 cb(cx, ListLogicEvent::Select, dm, i);
294 self.selection.push(i);
295 }
296
297 }
298 }
299 },
300 ListSelect::Toggle(select_index) => {
301 let dm = &mut self.list_items[select_index];
302 if dm.is_selected {
303 dm.is_selected = false;
304 cb(cx, ListLogicEvent::Deselect, dm, select_index);
305 if let Some(pos) = self.selection.iter().position( | v | *v == select_index) {
306 self.selection.remove(pos);
307 }
308 }
309 else {
310 self.selection.push(select_index);
311 dm.is_selected = true;
312 cb(cx, ListLogicEvent::Over, dm, select_index);
313 }
314 },
315 ListSelect::All => {
316 self.selection.truncate(0);
317 for i in 0..self.list_items.len() {
318 self.selection.push(i);
319 let dm = &mut self.list_items[i];
320 dm.is_selected = true;
321 cb(cx, ListLogicEvent::Over, dm, i);
322 }
323 },
324 ListSelect::Single(select_index) => {
325 for counter in &self.selection {
326 if *counter >= self.list_items.len() {
327 continue;
328 }
329 let dm = &mut self.list_items[*counter];
330 if *counter != select_index {
331 dm.is_selected = false;
332 cb(cx, ListLogicEvent::Cleanup, dm, *counter);
333 }
334 }
335 self.selection.truncate(0);
336 if select_index < self.list_items.len() {
337 self.selection.push(select_index);
338 let dm = &mut self.list_items[select_index];
339 dm.is_selected = true;
340 cb(cx, ListLogicEvent::Over, dm, select_index);
341
342 return ListEvent::SelectSingle(select_index)
343 }
344 },
345 _ => ()
346 }
347 match select {
348 ListSelect::Range(_) | ListSelect::Toggle(_) | ListSelect::All => {
349 ListEvent::SelectMultiple
350 },
351 _ => ListEvent::None
352 }
353
354 }
355
356}