1use kas::layout::solve_size_rules;
9use kas::prelude::*;
10use std::collections::hash_map::{Entry, HashMap};
11use std::fmt::Debug;
12use std::ops::{Index, IndexMut};
13
14pub type BoxStack<Data> = Stack<Box<dyn Widget<Data = Data>>>;
18
19#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
20enum State {
21 #[default]
22 None,
23 Configured,
24 Sized,
25}
26impl State {
27 fn is_configured(self) -> bool {
28 self != State::None
29 }
30}
31
32impl_scope! {
33 #[autoimpl(Default)]
46 #[derive(Clone, Debug)]
47 #[widget]
48 pub struct Stack<W: Widget> {
49 core: widget_core!(),
50 align_hints: AlignHints,
51 widgets: Vec<(W, State)>,
52 active: usize,
53 size_limit: usize,
54 next: usize,
55 id_map: HashMap<usize, usize>, }
57
58 impl Widget for Self {
59 type Data = W::Data;
60
61 fn for_child_node(
62 &mut self,
63 data: &W::Data,
64 index: usize,
65 closure: Box<dyn FnOnce(Node<'_>) + '_>,
66 ) {
67 if let Some((w, _)) = self.widgets.get_mut(index) {
68 closure(w.as_node(data));
69 }
70 }
71 }
72
73 impl Layout for Self {
74 #[inline]
75 fn num_children(&self) -> usize {
76 self.widgets.len()
77 }
78 fn get_child(&self, index: usize) -> Option<&dyn Layout> {
79 self.widgets.get(index).map(|(w, _)| w.as_layout())
80 }
81
82 fn find_child_index(&self, id: &Id) -> Option<usize> {
83 id.next_key_after(self.id_ref())
84 .and_then(|k| self.id_map.get(&k).cloned())
85 }
86
87 fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
88 let mut rules = SizeRules::EMPTY;
89 let mut index = 0;
90 let end = self.widgets.len().min(self.size_limit);
91 loop {
92 if index == end {
93 if self.active >= end {
94 index = self.active;
95 } else {
96 break rules;
97 }
98 } else if index > end {
99 break rules;
100 }
101
102 if let Some(entry) = self.widgets.get_mut(index) {
103 if entry.1.is_configured() {
104 rules = rules.max(entry.0.size_rules(sizer.re(), axis));
105 entry.1 = State::Sized;
106 }
107 }
108
109 index += 1;
110 }
111 }
112
113 fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
114 self.core.rect = rect;
115 self.align_hints = hints;
116 if let Some(entry) = self.widgets.get_mut(self.active) {
117 debug_assert_eq!(entry.1, State::Sized);
118 entry.0.set_rect(cx, rect, hints);
119 }
120 }
121
122 fn nav_next(&self, _: bool, from: Option<usize>) -> Option<usize> {
123 match from {
124 None => Some(self.active),
125 Some(active) if active != self.active => Some(self.active),
126 _ => None,
127 }
128 }
129
130 fn find_id(&mut self, coord: Coord) -> Option<Id> {
131 if let Some(entry) = self.widgets.get_mut(self.active) {
132 debug_assert_eq!(entry.1, State::Sized);
133 return entry.0.find_id(coord);
134 }
135 None
136 }
137
138 fn draw(&mut self, mut draw: DrawCx) {
139 if let Some(entry) = self.widgets.get_mut(self.active) {
140 debug_assert_eq!(entry.1, State::Sized);
141 draw.recurse(&mut entry.0);
142 }
143 }
144 }
145
146 impl Events for Self {
147 fn make_child_id(&mut self, index: usize) -> Id {
148 if let Some((child, state)) = self.widgets.get(index) {
149 if state.is_configured() {
150 debug_assert!(child.id_ref().is_valid());
151 if let Some(key) = child.id_ref().next_key_after(self.id_ref()) {
152 debug_assert_eq!(self.id_map.get(&key), Some(&index));
153 } else {
154 debug_assert!(false);
155 }
156 return child.id();
157 }
158
159 if child.id_ref().is_valid() {
161 if let Some(key) = child.id_ref().next_key_after(self.id_ref()) {
162 self.id_map.insert(key, index);
163 return child.id();
164 }
165 }
166 }
167
168 loop {
169 let key = self.next;
170 self.next += 1;
171 if let Entry::Vacant(entry) = self.id_map.entry(key) {
172 entry.insert(index);
173 return self.id_ref().make_child(key);
174 }
175 }
176 }
177
178 fn configure(&mut self, _: &mut ConfigCx) {
179 self.id_map.clear();
180 }
181
182 fn configure_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
183 let mut index = 0;
184 let end = self.widgets.len().min(self.size_limit);
185 loop {
186 if index == end {
187 if self.active >= end {
188 index = self.active;
189 } else {
190 break;
191 }
192 } else if index > end {
193 break;
194 }
195
196 let id = self.make_child_id(index);
197 if let Some(entry) = self.widgets.get_mut(index) {
198 cx.configure(entry.0.as_node(data), id);
199 if entry.1 == State::None {
200 entry.1 = State::Configured;
201 }
202 }
203
204 index += 1;
205 }
206 }
207
208 fn update_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
209 if let Some((w, _)) = self.widgets.get_mut(self.active) {
210 cx.update(w.as_node(data));
211 }
212 }
213 }
214
215 impl Index<usize> for Self {
216 type Output = W;
217
218 fn index(&self, index: usize) -> &Self::Output {
219 &self.widgets[index].0
220 }
221 }
222
223 impl IndexMut<usize> for Self {
224 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
225 &mut self.widgets[index].0
226 }
227 }
228}
229
230impl<W: Widget> Stack<W> {
231 pub fn new() -> Self {
235 Stack::default()
236 }
237
238 pub fn set_size_limit(&mut self, limit: usize) {
246 self.size_limit = limit;
247 }
248
249 pub fn with_size_limit(mut self, limit: usize) -> Self {
257 self.size_limit = limit;
258 self
259 }
260
261 #[inline]
263 pub fn active(&self) -> usize {
264 self.active
265 }
266
267 #[inline]
272 pub fn with_active(mut self, active: usize) -> Self {
273 self.active = active;
274 self
275 }
276
277 pub fn set_active(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize) {
279 let old_index = self.active;
280 if old_index == index {
281 return;
282 }
283 self.active = index;
284
285 let id = self.make_child_id(index);
286 if let Some(entry) = self.widgets.get_mut(index) {
287 let node = entry.0.as_node(data);
288
289 if entry.1 == State::None {
290 cx.configure(node, id);
291 entry.1 = State::Configured;
292 } else {
293 cx.update(node);
294 }
295
296 if entry.1 == State::Configured {
297 cx.resize(self);
298 } else {
299 debug_assert_eq!(entry.1, State::Sized);
300 entry.0.set_rect(cx, self.core.rect, self.align_hints);
301 cx.region_moved();
302 }
303 } else {
304 if old_index < self.widgets.len() {
305 cx.region_moved();
306 }
307 }
308 }
309
310 pub fn get_active(&self) -> Option<&W> {
312 if self.active < self.widgets.len() {
313 Some(&self.widgets[self.active].0)
314 } else {
315 None
316 }
317 }
318
319 pub fn is_empty(&self) -> bool {
321 self.widgets.is_empty()
322 }
323
324 pub fn len(&self) -> usize {
326 self.widgets.len()
327 }
328
329 pub fn clear(&mut self) {
333 self.widgets.clear();
334 }
335
336 pub fn get(&self, index: usize) -> Option<&W> {
338 self.widgets.get(index).map(|e| &e.0)
339 }
340
341 pub fn get_mut(&mut self, index: usize) -> Option<&mut W> {
343 self.widgets.get_mut(index).map(|e| &mut e.0)
344 }
345
346 fn configure_and_size(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize) {
348 let id = self.make_child_id(index);
349 if let Some(entry) = self.widgets.get_mut(index) {
350 cx.configure(entry.0.as_node(data), id);
351 let Size(w, h) = self.core.rect.size;
352 solve_size_rules(&mut entry.0, cx.size_cx(), Some(w), Some(h));
353 entry.1 = State::Sized;
354 }
355 }
356
357 pub fn push(&mut self, cx: &mut ConfigCx, data: &W::Data, widget: W) -> usize {
364 let index = self.widgets.len();
365 if index == self.active {
366 self.active = usize::MAX;
367 }
368 self.widgets.push((widget, State::None));
369
370 if index < self.size_limit {
371 self.configure_and_size(cx, data, index);
372 }
373 index
374 }
375
376 pub fn pop(&mut self, cx: &mut EventState) -> Option<W> {
381 let result = self.widgets.pop().map(|(w, _)| w);
382 if let Some(w) = result.as_ref() {
383 if self.active > 0 && self.active == self.widgets.len() {
384 cx.region_moved();
385 }
386
387 if w.id_ref().is_valid() {
388 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
389 self.id_map.remove(&key);
390 }
391 }
392 }
393 result
394 }
395
396 pub fn insert(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize, widget: W) {
402 if self.active >= index {
403 self.active = self.active.saturating_add(1);
404 }
405
406 self.widgets.insert(index, (widget, State::None));
407
408 for v in self.id_map.values_mut() {
409 if *v >= index {
410 *v += 1;
411 }
412 }
413
414 if index < self.size_limit {
415 self.configure_and_size(cx, data, index);
416 }
417 }
418
419 pub fn remove(&mut self, cx: &mut EventState, index: usize) -> W {
426 let (w, _) = self.widgets.remove(index);
427 if w.id_ref().is_valid() {
428 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
429 self.id_map.remove(&key);
430 }
431 }
432
433 if self.active == index {
434 self.active = usize::MAX;
435 cx.region_moved();
436 }
437
438 for v in self.id_map.values_mut() {
439 if *v > index {
440 *v -= 1;
441 }
442 }
443 w
444 }
445
446 pub fn replace(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize, mut widget: W) -> W {
452 let entry = &mut self.widgets[index];
453 std::mem::swap(&mut widget, &mut entry.0);
454 entry.1 = State::None;
455
456 if widget.id_ref().is_valid() {
457 if let Some(key) = widget.id_ref().next_key_after(self.id_ref()) {
458 self.id_map.remove(&key);
459 }
460 }
461
462 if index < self.size_limit || index == self.active {
463 self.configure_and_size(cx, data, index);
464 }
465
466 if index == self.active {
467 cx.resize(self);
468 }
469
470 widget
471 }
472
473 pub fn extend<T: IntoIterator<Item = W>>(
478 &mut self,
479 cx: &mut ConfigCx,
480 data: &W::Data,
481 iter: T,
482 ) {
483 let old_len = self.widgets.len();
484 let iter = iter.into_iter();
485 if let Some(ub) = iter.size_hint().1 {
486 self.widgets.reserve(ub);
487 }
488 for w in iter {
489 let index = self.widgets.len();
490 self.widgets.push((w, State::None));
491 if index < self.size_limit {
492 self.configure_and_size(cx, data, index);
493 }
494 }
495
496 if (old_len..self.widgets.len()).contains(&self.active) {
497 self.active = usize::MAX;
498 }
499 }
500
501 pub fn resize_with<F: Fn(usize) -> W>(
506 &mut self,
507 cx: &mut ConfigCx,
508 data: &W::Data,
509 len: usize,
510 f: F,
511 ) {
512 let old_len = self.widgets.len();
513
514 if len < old_len {
515 loop {
516 let (w, _) = self.widgets.pop().unwrap();
517 if w.id_ref().is_valid() {
518 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
519 self.id_map.remove(&key);
520 }
521 }
522 if len == self.widgets.len() {
523 return;
524 }
525 }
526 }
527
528 if len > old_len {
529 self.widgets.reserve(len - old_len);
530 for index in old_len..len {
531 self.widgets.push((f(index), State::None));
532 if index < self.size_limit {
533 self.configure_and_size(cx, data, index);
534 }
535 }
536
537 if (old_len..len).contains(&self.active) {
538 self.active = usize::MAX;
539 }
540 }
541 }
542}
543
544impl<W: Widget, I> From<I> for Stack<W>
545where
546 I: IntoIterator<Item = W>,
547{
548 #[inline]
549 fn from(iter: I) -> Self {
550 Self {
551 widgets: iter.into_iter().map(|w| (w, State::None)).collect(),
552 ..Default::default()
553 }
554 }
555}