kas_widgets/list.rs
1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4// https://www.apache.org/licenses/LICENSE-2.0
5
6//! A row or column with run-time adjustable contents
7
8use kas::Collection;
9use kas::dir::{Down, Right};
10use kas::layout::{
11 DynRowStorage, RowPositionSolver, RowSetter, RowSolver, RowStorage, RulesSetter, RulesSolver,
12};
13use kas::prelude::*;
14use std::collections::hash_map::{Entry, HashMap};
15use std::ops::{Index, IndexMut};
16
17/// Make a [`Row`] widget
18///
19/// # Syntax
20///
21/// > _Collection_ :\
22/// > `row!` `[` _Items_<sup>\?</sup> `]`
23/// >
24/// > _Items_ :\
25/// > (_Item_ `,`)<sup>\*</sup> _Item_ `,`<sup>\?</sup>
26///
27/// ## Stand-alone usage
28///
29/// When used as a stand-alone macro, `row! [/* ... */]` is just syntactic sugar
30/// for `Row::new(kas::collection! [/* ... */])`.
31///
32/// In this case, _Item_ may be:
33///
34/// - A string literal (interpreted as a label widget), optionally followed by
35/// any of the following method calls: [`align`], [`pack`], [`with_stretch`]
36/// - An expression yielding an object implementing `Widget<Data = _A>`
37///
38/// In case all _Item_ instances are a string literal, the data type of the
39/// `row!` widget will be `()`; otherwise the data type of the widget is `_A`
40/// where `_A` is a generic type parameter of the widget.
41///
42/// ## Usage within widget layout syntax
43///
44/// When called within [widget layout syntax], `row!` may be evaluated as a
45/// recursive macro and the result does not have a specified type, except that
46/// methods [`map_any`], [`align`], [`pack`] and [`with_stretch`] are supported via
47/// emulation.
48///
49/// In this case, _Item_ is evaluated using [widget layout syntax]. This is
50/// broadly similar to the above with a couple of exceptions:
51///
52/// - Supported layout macros do not need to be imported to the module scope
53/// - An _Item_ may be a `#[widget]` field of the widget
54///
55/// # Example
56///
57/// ```
58/// let my_widget = kas_widgets::row!["one", "two"];
59/// ```
60///
61/// [widget layout syntax]: macro@kas::layout
62/// [`map_any`]: crate::AdaptWidgetAny::map_any
63/// [`align`]: crate::AdaptWidget::align
64/// [`pack`]: crate::AdaptWidget::pack
65/// [`with_stretch`]: crate::AdaptWidget::with_stretch
66#[macro_export]
67macro_rules! row {
68 ( $( $ee:expr ),* ) => {
69 $crate::Row::new( ::kas::collection! [ $( $ee ),* ] )
70 };
71 ( $( $ee:expr ),+ , ) => {
72 $crate::Row::new( ::kas::collection! [ $( $ee ),+ ] )
73 };
74}
75
76/// Make a [`Column`] widget
77///
78/// # Syntax
79///
80/// > _Collection_ :\
81/// > `column!` `[` _Items_<sup>\?</sup> `]`
82/// >
83/// > _Items_ :\
84/// > (_Item_ `,`)<sup>\*</sup> _Item_ `,`<sup>\?</sup>
85///
86/// ## Stand-alone usage
87///
88/// When used as a stand-alone macro, `column! [/* ... */]` is just syntactic sugar
89/// for `Column::new(kas::collection! [/* ... */])`.
90///
91/// In this case, _Item_ may be:
92///
93/// - A string literal (interpreted as a label widget), optionally followed by
94/// any of the following method calls: [`align`], [`pack`], [`with_stretch`]
95/// - An expression yielding an object implementing `Widget<Data = _A>`
96///
97/// In case all _Item_ instances are a string literal, the data type of the
98/// `column!` widget will be `()`; otherwise the data type of the widget is `_A`
99/// where `_A` is a generic type parameter of the widget.
100///
101/// ## Usage within widget layout syntax
102///
103/// When called within [widget layout syntax], `column!` may be evaluated as a
104/// recursive macro and the result does not have a specified type, except that
105/// methods [`map_any`], [`align`], [`pack`] and [`with_stretch`] are supported via
106/// emulation.
107///
108/// In this case, _Item_ is evaluated using [widget layout syntax]. This is
109/// broadly similar to the above with a couple of exceptions:
110///
111/// - Supported layout macros do not need to be imported to the module scope
112/// - An _Item_ may be a `#[widget]` field of the widget
113///
114/// # Example
115///
116/// ```
117/// let my_widget = kas_widgets::column! [
118/// "one",
119/// "two",
120/// ];
121/// ```
122///
123/// [widget layout syntax]: macro@kas::layout
124/// [`map_any`]: crate::AdaptWidgetAny::map_any
125/// [`align`]: crate::AdaptWidget::align
126/// [`pack`]: crate::AdaptWidget::pack
127/// [`with_stretch`]: crate::AdaptWidget::with_stretch
128#[macro_export]
129macro_rules! column {
130 ( $( $ee:expr ),* ) => {
131 $crate::Column::new( ::kas::collection! [ $( $ee ),* ] )
132 };
133 ( $( $ee:expr ),+ , ) => {
134 $crate::Column::new( ::kas::collection! [ $( $ee ),+ ] )
135 };
136}
137
138/// Make a [`List`] widget
139///
140/// # Syntax
141///
142/// > _Collection_ :\
143/// > `list!` `[` _Items_<sup>\?</sup> `]`
144/// >
145/// > _Items_ :\
146/// > (_Item_ `,`)<sup>\*</sup> _Item_ `,`<sup>\?</sup>
147///
148/// ## Stand-alone usage
149///
150/// When used as a stand-alone macro, `list! [/* ... */]` is just syntactic sugar
151/// for `List::new(kas::collection! [/* ... */])`.
152///
153/// In this case, _Item_ may be:
154///
155/// - A string literal (interpreted as a label widget), optionally followed by
156/// any of the following method calls: [`align`], [`pack`], [`with_stretch`]
157/// - An expression yielding an object implementing `Widget<Data = _A>`
158///
159/// In case all _Item_ instances are a string literal, the data type of the
160/// `list!` widget will be `()`; otherwise the data type of the widget is `_A`
161/// where `_A` is a generic type parameter of the widget.
162///
163/// ## Usage within widget layout syntax
164///
165/// When called within [widget layout syntax], `list!` may be evaluated as a
166/// recursive macro and the result does not have a specified type, except that
167/// methods [`map_any`], [`align`], [`pack`], [`with_stretch`] and [`with_direction`] are
168/// supported via emulation. In this case, calling [`with_direction`] is
169/// required. Note that the argument passed to [`with_direction`] is expanded
170/// at the use site, so for example `.with_direction(self.dir)` will read
171/// `self.dir` whenever layout is computed.
172///
173/// In this case, _Item_ is evaluated using [widget layout syntax]. This is
174/// broadly similar to the above with a couple of exceptions:
175///
176/// - Supported layout macros do not need to be imported to the module scope
177/// - An _Item_ may be a `#[widget]` field of the widget
178///
179/// # Example
180///
181/// ```
182/// let my_widget = kas_widgets::list! ["one", "two"]
183/// .with_direction(kas::dir::Left);
184/// ```
185///
186/// [widget layout syntax]: macro@kas::layout
187/// [`map_any`]: crate::AdaptWidgetAny::map_any
188/// [`align`]: crate::AdaptWidget::align
189/// [`pack`]: crate::AdaptWidget::pack
190/// [`with_stretch`]: crate::AdaptWidget::with_stretch
191/// [`with_direction`]: List::with_direction
192#[macro_export]
193macro_rules! list {
194 ( $( $ee:expr ),* ) => {
195 $crate::List::new( ::kas::collection! [ $( $ee ),* ] )
196 };
197 ( $( $ee:expr ),+ , ) => {
198 $crate::List::new( ::kas::collection! [ $( $ee ),+ ] )
199 };
200}
201
202/// A generic row widget
203///
204/// See documentation of [`List`] type.
205pub type Row<C> = List<C, Right>;
206
207/// A generic column widget
208///
209/// See documentation of [`List`] type.
210pub type Column<C> = List<C, Down>;
211
212#[impl_self]
213mod List {
214 /// A generic row/column widget
215 ///
216 /// A linear widget over a [`Collection`] of widgets.
217 ///
218 /// When the collection uses [`Vec`], various methods to insert/remove
219 /// elements are available.
220 ///
221 /// The layout direction `D` may be compile-time fixed (e.g. [`Right`]) or
222 /// run-time mutable ([`Direction`]); in the latter case
223 /// [`set_direction`] is available.
224 ///
225 /// ## See also
226 ///
227 /// [`Row`] and [`Column`] are type-defs to `List` which fix the direction `D`.
228 ///
229 /// The macros [`row!`] and [`column!`] also create row/column
230 /// layouts, but are not fully equivalent:
231 ///
232 /// - `row!` and `column!` generate anonymous layout widgets (or objects).
233 /// These do not have a [`set_direction`] method or support adding or
234 /// removing elements.
235 /// - `row!` and `column!` generate layout objects which, when used within
236 /// a custom widget, may refer to that widget's fields.
237 ///
238 /// ## Performance
239 ///
240 /// Configuring and resizing elements is O(n) in the number of children.
241 /// Drawing and event handling is O(log n) in the number of children (assuming
242 /// only a small number are visible at any one time).
243 ///
244 /// ## Example
245 ///
246 /// ```
247 /// use kas::collection;
248 /// # use kas_widgets::{CheckBox, List};
249 ///
250 /// let list = List::right(collection![
251 /// "A checkbox",
252 /// CheckBox::new(|_, state: &bool| *state),
253 /// ]);
254 /// ```
255 ///
256 /// [`row!`]: crate::row
257 /// [`column!`]: crate::column
258 /// [`set_direction`]: List::set_direction
259 #[autoimpl(Default where C: Default, D: Default)]
260 #[widget]
261 pub struct List<C: Collection, D: Directional> {
262 pub(crate) core: widget_core!(),
263 pub(crate) layout: DynRowStorage,
264 #[collection]
265 pub(crate) widgets: C,
266 pub(crate) direction: D,
267 next: usize,
268 id_map: HashMap<usize, usize>, // map key of Id to index
269 }
270
271 impl Layout for Self {
272 fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
273 let dim = (self.direction, self.widgets.len());
274 let mut solver = RowSolver::new(axis, dim, &mut self.layout);
275 for n in 0..self.widgets.len() {
276 if let Some(child) = self.widgets.get_mut_tile(n) {
277 solver.for_child(&mut self.layout, n, |axis| child.size_rules(cx, axis));
278 }
279 }
280 solver.finish(&mut self.layout)
281 }
282
283 fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
284 self.core.set_rect(rect);
285 let dim = (self.direction, self.widgets.len());
286 let mut setter = RowSetter::<D, Vec<i32>, _>::new(rect, dim, &mut self.layout);
287
288 for n in 0..self.widgets.len() {
289 if let Some(child) = self.widgets.get_mut_tile(n) {
290 child.set_rect(cx, setter.child_rect(&mut self.layout, n), hints);
291 }
292 }
293 }
294
295 fn draw(&self, mut draw: DrawCx) {
296 let solver = RowPositionSolver::new(self.direction);
297 solver.for_children(&self.widgets, draw.get_clip_rect(), |w| w.draw(draw.re()));
298 }
299 }
300
301 impl Tile for Self {
302 fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
303 Role::None
304 }
305
306 fn find_child_index(&self, id: &Id) -> Option<usize> {
307 id.next_key_after(self.id_ref())
308 .and_then(|k| self.id_map.get(&k).cloned())
309 }
310 }
311
312 impl Events for Self {
313 type Data = C::Data;
314
315 /// Make a fresh id based on `self.next` then insert into `self.id_map`
316 fn make_child_id(&mut self, index: usize) -> Id {
317 if let Some(child) = self.widgets.get_tile(index) {
318 // Use the widget's existing identifier, if valid
319 if child.id_ref().is_valid() {
320 if let Some(key) = child.id_ref().next_key_after(self.id_ref()) {
321 if let Entry::Vacant(entry) = self.id_map.entry(key) {
322 entry.insert(index);
323 return child.id();
324 }
325 }
326 }
327 }
328
329 loop {
330 let key = self.next;
331 self.next += 1;
332 if let Entry::Vacant(entry) = self.id_map.entry(key) {
333 entry.insert(index);
334 return self.id_ref().make_child(key);
335 }
336 }
337 }
338
339 fn probe(&self, coord: Coord) -> Id {
340 let solver = RowPositionSolver::new(self.direction);
341 solver
342 .find_child(&self.widgets, coord)
343 .and_then(|child| child.try_probe(coord))
344 .unwrap_or_else(|| self.id())
345 }
346
347 fn configure(&mut self, _: &mut ConfigCx) {
348 // All children will be re-configured which will rebuild id_map
349 self.id_map.clear();
350 }
351 }
352
353 impl Self
354 where
355 D: Default,
356 {
357 /// Construct a new instance with default-constructed direction
358 ///
359 /// This constructor is available where the direction is determined by the
360 /// type: for `D: Directional + Default`. In other cases, use
361 /// [`Self::new_dir`].
362 ///
363 /// # Examples
364 ///
365 /// Where widgets have the same type and the length is fixed, an array
366 /// may be used:
367 /// ```
368 /// use kas_widgets::{Label, Row};
369 /// let _ = Row::new([Label::new("left"), Label::new("right")]);
370 /// ```
371 ///
372 /// To support run-time insertion/deletion, use [`Vec`]:
373 /// ```
374 /// use kas_widgets::{AdaptWidget, Button, Row};
375 ///
376 /// #[derive(Clone, Debug)]
377 /// enum Msg {
378 /// Add,
379 /// Remove,
380 /// }
381 ///
382 /// let _ = Row::new(vec![Button::label_msg("Add", Msg::Add)])
383 /// .on_messages(|cx, row, data| {
384 /// if let Some(msg) = cx.try_pop() {
385 /// match msg {
386 /// Msg::Add => {
387 /// let button = if row.len() % 2 == 0 {
388 /// Button::label_msg("Add", Msg::Add)
389 /// } else {
390 /// Button::label_msg("Remove", Msg::Remove)
391 /// };
392 /// row.push(cx, data, button);
393 /// }
394 /// Msg::Remove => {
395 /// let _ = row.pop(cx);
396 /// }
397 /// }
398 /// }
399 /// });
400 /// ```
401 #[inline]
402 pub fn new(widgets: C) -> Self {
403 Self::new_dir(widgets, D::default())
404 }
405 }
406
407 impl<C: Collection> List<C, kas::dir::Left> {
408 /// Construct a new instance with fixed direction
409 #[inline]
410 pub fn left(widgets: C) -> Self {
411 Self::new(widgets)
412 }
413 }
414 impl<C: Collection> List<C, kas::dir::Right> {
415 /// Construct a new instance with fixed direction
416 #[inline]
417 pub fn right(widgets: C) -> Self {
418 Self::new(widgets)
419 }
420 }
421 impl<C: Collection> List<C, kas::dir::Up> {
422 /// Construct a new instance with fixed direction
423 #[inline]
424 pub fn up(widgets: C) -> Self {
425 Self::new(widgets)
426 }
427 }
428 impl<C: Collection> List<C, kas::dir::Down> {
429 /// Construct a new instance with fixed direction
430 #[inline]
431 pub fn down(widgets: C) -> Self {
432 Self::new(widgets)
433 }
434 }
435
436 impl<C: Collection, D: Directional + Eq> List<C, D> {
437 /// Set the direction of contents
438 pub fn set_direction(&mut self, cx: &mut ConfigCx, direction: D) {
439 if direction == self.direction {
440 return;
441 }
442
443 self.direction = direction;
444 cx.resize();
445 }
446 }
447
448 impl Self {
449 /// Construct a new instance with explicit direction
450 #[inline]
451 pub fn new_dir(widgets: C, direction: D) -> Self {
452 List {
453 core: Default::default(),
454 layout: Default::default(),
455 widgets,
456 direction,
457 next: 0,
458 id_map: Default::default(),
459 }
460 }
461
462 /// Get the direction of contents
463 pub fn direction(&self) -> Direction {
464 self.direction.as_direction()
465 }
466
467 /// Set the direction of contents (inline)
468 #[inline]
469 pub fn with_direction(mut self, direction: D) -> Self {
470 self.direction = direction;
471 self
472 }
473
474 /// Access layout storage
475 ///
476 /// The number of columns/rows is [`Self::len`].
477 #[inline]
478 pub fn layout_storage(&mut self) -> &mut (impl RowStorage + use<C, D>) {
479 &mut self.layout
480 }
481
482 /// True if there are no child widgets
483 pub fn is_empty(&self) -> bool {
484 self.widgets.is_empty()
485 }
486
487 /// Returns the number of child widgets
488 pub fn len(&self) -> usize {
489 self.widgets.len()
490 }
491 }
492
493 impl<W: Widget, D: Directional> List<Vec<W>, D> {
494 /// Returns a reference to the child, if any
495 pub fn get(&self, index: usize) -> Option<&W> {
496 self.widgets.get(index)
497 }
498
499 /// Returns a mutable reference to the child, if any
500 pub fn get_mut(&mut self, index: usize) -> Option<&mut W> {
501 self.widgets.get_mut(index)
502 }
503
504 /// Remove all child widgets
505 pub fn clear(&mut self) {
506 self.widgets.clear();
507 }
508
509 /// Append a child widget
510 ///
511 /// The new child is configured immediately. Triggers a resize.
512 ///
513 /// Returns the new element's index.
514 pub fn push(&mut self, cx: &mut ConfigCx, data: &W::Data, mut widget: W) -> usize {
515 let index = self.widgets.len();
516 let id = self.make_child_id(index);
517 cx.configure(widget.as_node(data), id);
518 self.widgets.push(widget);
519
520 cx.resize();
521 index
522 }
523
524 /// Remove the last child widget (if any) and return
525 ///
526 /// Triggers a resize.
527 pub fn pop(&mut self, cx: &mut ConfigCx) -> Option<W> {
528 let result = self.widgets.pop();
529 if let Some(w) = result.as_ref() {
530 cx.resize();
531
532 if w.id_ref().is_valid() {
533 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
534 self.id_map.remove(&key);
535 }
536 }
537 }
538 result
539 }
540
541 /// Inserts a child widget position `index`
542 ///
543 /// Panics if `index > len`.
544 ///
545 /// The new child is configured immediately. Triggers a resize.
546 pub fn insert(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize, mut widget: W) {
547 for v in self.id_map.values_mut() {
548 if *v >= index {
549 *v += 1;
550 }
551 }
552
553 let id = self.make_child_id(index);
554 cx.configure(widget.as_node(data), id);
555 self.widgets.insert(index, widget);
556 cx.resize();
557 }
558
559 /// Removes the child widget at position `index`
560 ///
561 /// Panics if `index` is out of bounds.
562 ///
563 /// Triggers a resize.
564 pub fn remove(&mut self, cx: &mut ConfigCx, index: usize) -> W {
565 let w = self.widgets.remove(index);
566 if w.id_ref().is_valid() {
567 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
568 self.id_map.remove(&key);
569 }
570 }
571
572 cx.resize();
573
574 for v in self.id_map.values_mut() {
575 if *v > index {
576 *v -= 1;
577 }
578 }
579 w
580 }
581
582 /// Removes all children at positions ≥ `len`
583 ///
584 /// Does nothing if `self.len() < len`.
585 ///
586 /// Triggers a resize.
587 pub fn truncate(&mut self, cx: &mut ConfigCx, len: usize) {
588 if len < self.len() {
589 cx.resize();
590 loop {
591 let w = self.widgets.pop().unwrap();
592 if w.id_ref().is_valid() {
593 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
594 self.id_map.remove(&key);
595 }
596 }
597 if len == self.widgets.len() {
598 return;
599 }
600 }
601 }
602 }
603
604 /// Replace the child at `index`
605 ///
606 /// Panics if `index` is out of bounds.
607 ///
608 /// The new child is configured immediately. Triggers a resize.
609 pub fn replace(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize, mut w: W) -> W {
610 let id = self.make_child_id(index);
611 cx.configure(w.as_node(data), id);
612 std::mem::swap(&mut w, &mut self.widgets[index]);
613
614 if w.id_ref().is_valid() {
615 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
616 self.id_map.remove(&key);
617 }
618 }
619
620 cx.resize();
621
622 w
623 }
624
625 /// Append child widgets from an iterator
626 ///
627 /// New children are configured immediately. Triggers a resize.
628 pub fn extend<T>(&mut self, cx: &mut ConfigCx, data: &W::Data, iter: T)
629 where
630 T: IntoIterator<Item = W>,
631 {
632 let iter = iter.into_iter();
633 if let Some(ub) = iter.size_hint().1 {
634 self.widgets.reserve(ub);
635 }
636 for mut w in iter {
637 let id = self.make_child_id(self.widgets.len());
638 cx.configure(w.as_node(data), id);
639 self.widgets.push(w);
640 }
641
642 cx.resize();
643 }
644
645 /// Resize, using the given closure to construct new widgets
646 ///
647 /// New children are configured immediately. Triggers a resize.
648 pub fn resize_with<F>(&mut self, cx: &mut ConfigCx, data: &W::Data, len: usize, f: F)
649 where
650 F: Fn(usize) -> W,
651 {
652 let old_len = self.widgets.len();
653
654 if len < old_len {
655 cx.resize();
656 loop {
657 let w = self.widgets.pop().unwrap();
658 if w.id_ref().is_valid() {
659 if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
660 self.id_map.remove(&key);
661 }
662 }
663 if len == self.widgets.len() {
664 return;
665 }
666 }
667 }
668
669 if len > old_len {
670 self.widgets.reserve(len - old_len);
671 for index in old_len..len {
672 let id = self.make_child_id(index);
673 let mut w = f(index);
674 cx.configure(w.as_node(data), id);
675 self.widgets.push(w);
676 }
677 cx.resize();
678 }
679 }
680
681 /// Iterate over childern
682 pub fn iter(&self) -> impl Iterator<Item = &W> {
683 ListIter {
684 list: &self.widgets,
685 }
686 }
687
688 /// Mutably iterate over childern
689 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut W> {
690 ListIterMut {
691 list: &mut self.widgets,
692 }
693 }
694 }
695
696 impl<W: Widget, D: Directional> Index<usize> for List<Vec<W>, D> {
697 type Output = W;
698
699 fn index(&self, index: usize) -> &Self::Output {
700 &self.widgets[index]
701 }
702 }
703
704 impl<W: Widget, D: Directional> IndexMut<usize> for List<Vec<W>, D> {
705 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
706 &mut self.widgets[index]
707 }
708 }
709}
710
711struct ListIter<'a, W: Widget> {
712 list: &'a [W],
713}
714impl<'a, W: Widget> Iterator for ListIter<'a, W> {
715 type Item = &'a W;
716 fn next(&mut self) -> Option<Self::Item> {
717 if let Some((first, rest)) = self.list.split_first() {
718 self.list = rest;
719 Some(first)
720 } else {
721 None
722 }
723 }
724 fn size_hint(&self) -> (usize, Option<usize>) {
725 let len = self.len();
726 (len, Some(len))
727 }
728}
729impl<'a, W: Widget> ExactSizeIterator for ListIter<'a, W> {
730 fn len(&self) -> usize {
731 self.list.len()
732 }
733}
734
735struct ListIterMut<'a, W: Widget> {
736 list: &'a mut [W],
737}
738impl<'a, W: Widget> Iterator for ListIterMut<'a, W> {
739 type Item = &'a mut W;
740 fn next(&mut self) -> Option<Self::Item> {
741 let list = std::mem::take(&mut self.list);
742 if let Some((first, rest)) = list.split_first_mut() {
743 self.list = rest;
744 Some(first)
745 } else {
746 None
747 }
748 }
749 fn size_hint(&self) -> (usize, Option<usize>) {
750 let len = self.len();
751 (len, Some(len))
752 }
753}
754impl<'a, W: Widget> ExactSizeIterator for ListIterMut<'a, W> {
755 fn len(&self) -> usize {
756 self.list.len()
757 }
758}