1use crate::item_tree::ItemTreeVTable;
9use crate::item_tree::TraversalOrder;
10pub use crate::items::{StandardListViewItem, TableColumn};
11use crate::layout::Orientation;
12use crate::lengths::{LogicalLength, RectLengths};
13use crate::{Coord, Property, SharedString, SharedVector};
14pub use adapters::{FilterModel, MapModel, ReverseModel, SortModel};
15use alloc::boxed::Box;
16use alloc::rc::Rc;
17use alloc::vec::Vec;
18use core::cell::{Cell, RefCell};
19use core::pin::Pin;
20use euclid::num::Zero;
21#[allow(unused)]
22use euclid::num::{Ceil, Floor};
23pub use model_peer::*;
24use once_cell::unsync::OnceCell;
25use pin_project::pin_project;
26
27mod adapters;
28mod model_peer;
29
30type ItemTreeRc<C> = vtable::VRc<crate::item_tree::ItemTreeVTable, C>;
31
32pub trait ModelTracker {
36 fn attach_peer(&self, peer: ModelPeer);
38 fn track_row_count_changes(&self);
41 fn track_row_data_changes(&self, row: usize);
44}
45
46impl ModelTracker for () {
47 fn attach_peer(&self, _peer: ModelPeer) {}
48
49 fn track_row_count_changes(&self) {}
50 fn track_row_data_changes(&self, _row: usize) {}
51}
52
53pub trait Model {
122 type Data;
124 fn row_count(&self) -> usize;
126 fn row_data(&self, row: usize) -> Option<Self::Data>;
133 fn set_row_data(&self, _row: usize, _data: Self::Data) {
143 #[cfg(feature = "std")]
144 crate::debug_log!(
145 "Model::set_row_data called on a model of type {} which does not re-implement this method. \
146 This happens when trying to modify a read-only model",
147 core::any::type_name::<Self>(),
148 );
149 }
150
151 fn model_tracker(&self) -> &dyn ModelTracker;
155
156 fn iter(&self) -> ModelIterator<'_, Self::Data>
158 where
159 Self: Sized,
160 {
161 ModelIterator::new(self)
162 }
163
164 fn as_any(&self) -> &dyn core::any::Any {
231 &()
232 }
233}
234
235pub trait ModelExt: Model {
237 fn row_data_tracked(&self, row: usize) -> Option<Self::Data> {
244 self.model_tracker().track_row_data_changes(row);
245 self.row_data(row)
246 }
247
248 fn map<F, U>(self, map_function: F) -> MapModel<Self, F>
251 where
252 Self: Sized + 'static,
253 F: Fn(Self::Data) -> U + 'static,
254 {
255 MapModel::new(self, map_function)
256 }
257
258 fn filter<F>(self, filter_function: F) -> FilterModel<Self, F>
261 where
262 Self: Sized + 'static,
263 F: Fn(&Self::Data) -> bool + 'static,
264 {
265 FilterModel::new(self, filter_function)
266 }
267
268 #[must_use]
271 fn sort(self) -> SortModel<Self, adapters::AscendingSortHelper>
272 where
273 Self: Sized + 'static,
274 Self::Data: core::cmp::Ord,
275 {
276 SortModel::new_ascending(self)
277 }
278
279 fn sort_by<F>(self, sort_function: F) -> SortModel<Self, F>
282 where
283 Self: Sized + 'static,
284 F: FnMut(&Self::Data, &Self::Data) -> core::cmp::Ordering + 'static,
285 {
286 SortModel::new(self, sort_function)
287 }
288
289 fn reverse(self) -> ReverseModel<Self>
292 where
293 Self: Sized + 'static,
294 {
295 ReverseModel::new(self)
296 }
297}
298
299impl<T: Model> ModelExt for T {}
300
301pub struct ModelIterator<'a, T> {
304 model: &'a dyn Model<Data = T>,
305 row: usize,
306}
307
308impl<'a, T> ModelIterator<'a, T> {
309 pub fn new(model: &'a dyn Model<Data = T>) -> Self {
312 Self { model, row: 0 }
313 }
314}
315
316impl<T> Iterator for ModelIterator<'_, T> {
317 type Item = T;
318
319 fn next(&mut self) -> Option<Self::Item> {
320 if self.row >= self.model.row_count() {
321 return None;
322 }
323 let row = self.row;
324 self.row += 1;
325 self.model.row_data(row)
326 }
327
328 fn size_hint(&self) -> (usize, Option<usize>) {
329 let len = self.model.row_count();
330 (len, Some(len))
331 }
332
333 fn nth(&mut self, n: usize) -> Option<Self::Item> {
334 self.row = self.row.checked_add(n)?;
335 self.next()
336 }
337}
338
339impl<T> ExactSizeIterator for ModelIterator<'_, T> {}
340
341impl<M: Model> Model for Rc<M> {
342 type Data = M::Data;
343
344 fn row_count(&self) -> usize {
345 (**self).row_count()
346 }
347
348 fn row_data(&self, row: usize) -> Option<Self::Data> {
349 (**self).row_data(row)
350 }
351
352 fn model_tracker(&self) -> &dyn ModelTracker {
353 (**self).model_tracker()
354 }
355
356 fn as_any(&self) -> &dyn core::any::Any {
357 (**self).as_any()
358 }
359 fn set_row_data(&self, row: usize, data: Self::Data) {
360 (**self).set_row_data(row, data)
361 }
362}
363
364pub struct VecModel<T> {
366 array: RefCell<Vec<T>>,
367 notify: ModelNotify,
368}
369
370impl<T> Default for VecModel<T> {
371 fn default() -> Self {
372 Self { array: Default::default(), notify: Default::default() }
373 }
374}
375
376impl<T: 'static> VecModel<T> {
377 pub fn from_slice(slice: &[T]) -> ModelRc<T>
379 where
380 T: Clone,
381 {
382 ModelRc::new(Self::from(slice.to_vec()))
383 }
384
385 pub fn push(&self, value: T) {
387 self.array.borrow_mut().push(value);
388 self.notify.row_added(self.array.borrow().len() - 1, 1)
389 }
390
391 pub fn insert(&self, index: usize, value: T) {
394 self.array.borrow_mut().insert(index, value);
395 self.notify.row_added(index, 1)
396 }
397
398 pub fn remove(&self, index: usize) -> T {
402 let r = self.array.borrow_mut().remove(index);
403 self.notify.row_removed(index, 1);
404 r
405 }
406
407 pub fn set_vec(&self, new: impl Into<Vec<T>>) {
409 *self.array.borrow_mut() = new.into();
410 self.notify.reset();
411 }
412
413 pub fn extend<I: IntoIterator<Item = T>>(&self, iter: I) {
417 let mut array = self.array.borrow_mut();
418 let old_idx = array.len();
419 array.extend(iter);
420 let count = array.len() - old_idx;
421 drop(array);
422 self.notify.row_added(old_idx, count);
423 }
424
425 pub fn clear(&self) {
429 self.array.borrow_mut().clear();
430 self.notify.reset();
431 }
432
433 pub fn swap(&self, a: usize, b: usize) {
435 if a == b {
436 return;
437 }
438
439 self.array.borrow_mut().swap(a, b);
440 self.notify.row_changed(a);
441 self.notify.row_changed(b);
442 }
443}
444
445impl<T: Clone + 'static> VecModel<T> {
446 pub fn extend_from_slice(&self, src: &[T]) {
450 let mut array = self.array.borrow_mut();
451 let old_idx = array.len();
452
453 array.extend_from_slice(src);
454 drop(array);
455 self.notify.row_added(old_idx, src.len());
456 }
457}
458
459impl<T> From<Vec<T>> for VecModel<T> {
460 fn from(array: Vec<T>) -> Self {
461 VecModel { array: RefCell::new(array), notify: Default::default() }
462 }
463}
464
465impl<T> FromIterator<T> for VecModel<T> {
466 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
467 VecModel::from(Vec::from_iter(iter))
468 }
469}
470
471impl<T: Clone + 'static> Model for VecModel<T> {
472 type Data = T;
473
474 fn row_count(&self) -> usize {
475 self.array.borrow().len()
476 }
477
478 fn row_data(&self, row: usize) -> Option<Self::Data> {
479 self.array.borrow().get(row).cloned()
480 }
481
482 fn set_row_data(&self, row: usize, data: Self::Data) {
483 if row < self.row_count() {
484 self.array.borrow_mut()[row] = data;
485 self.notify.row_changed(row);
486 }
487 }
488
489 fn model_tracker(&self) -> &dyn ModelTracker {
490 &self.notify
491 }
492
493 fn as_any(&self) -> &dyn core::any::Any {
494 self
495 }
496}
497
498#[derive(Default)]
500pub struct SharedVectorModel<T> {
501 array: RefCell<SharedVector<T>>,
502 notify: ModelNotify,
503}
504
505impl<T: Clone + 'static> SharedVectorModel<T> {
506 pub fn push(&self, value: T) {
508 self.array.borrow_mut().push(value);
509 self.notify.row_added(self.array.borrow().len() - 1, 1)
510 }
511}
512
513impl<T> SharedVectorModel<T> {
514 pub fn shared_vector(&self) -> SharedVector<T> {
516 self.array.borrow_mut().clone()
517 }
518}
519
520impl<T> From<SharedVector<T>> for SharedVectorModel<T> {
521 fn from(array: SharedVector<T>) -> Self {
522 SharedVectorModel { array: RefCell::new(array), notify: Default::default() }
523 }
524}
525
526impl<T: Clone + 'static> Model for SharedVectorModel<T> {
527 type Data = T;
528
529 fn row_count(&self) -> usize {
530 self.array.borrow().len()
531 }
532
533 fn row_data(&self, row: usize) -> Option<Self::Data> {
534 self.array.borrow().get(row).cloned()
535 }
536
537 fn set_row_data(&self, row: usize, data: Self::Data) {
538 self.array.borrow_mut().make_mut_slice()[row] = data;
539 self.notify.row_changed(row);
540 }
541
542 fn model_tracker(&self) -> &dyn ModelTracker {
543 &self.notify
544 }
545
546 fn as_any(&self) -> &dyn core::any::Any {
547 self
548 }
549}
550
551impl Model for usize {
552 type Data = i32;
553
554 fn row_count(&self) -> usize {
555 *self
556 }
557
558 fn row_data(&self, row: usize) -> Option<Self::Data> {
559 (row < self.row_count()).then_some(row as i32)
560 }
561
562 fn as_any(&self) -> &dyn core::any::Any {
563 self
564 }
565
566 fn model_tracker(&self) -> &dyn ModelTracker {
567 &()
568 }
569}
570
571impl Model for bool {
572 type Data = ();
573
574 fn row_count(&self) -> usize {
575 if *self {
576 1
577 } else {
578 0
579 }
580 }
581
582 fn row_data(&self, row: usize) -> Option<Self::Data> {
583 (row < self.row_count()).then_some(())
584 }
585
586 fn as_any(&self) -> &dyn core::any::Any {
587 self
588 }
589
590 fn model_tracker(&self) -> &dyn ModelTracker {
591 &()
592 }
593}
594
595pub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);
707
708impl<T> core::fmt::Debug for ModelRc<T> {
709 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
710 write!(f, "ModelRc(dyn Model)")
711 }
712}
713
714impl<T> Clone for ModelRc<T> {
715 fn clone(&self) -> Self {
716 Self(self.0.clone())
717 }
718}
719
720impl<T> Default for ModelRc<T> {
721 fn default() -> Self {
723 Self(None)
724 }
725}
726
727impl<T> core::cmp::PartialEq for ModelRc<T> {
728 fn eq(&self, other: &Self) -> bool {
729 match (&self.0, &other.0) {
730 (None, None) => true,
731 (Some(a), Some(b)) => core::ptr::eq(
732 (&**a) as *const dyn Model<Data = T> as *const u8,
733 (&**b) as *const dyn Model<Data = T> as *const u8,
734 ),
735 _ => false,
736 }
737 }
738}
739
740impl<T> ModelRc<T> {
741 pub fn new(model: impl Model<Data = T> + 'static) -> Self {
742 Self(Some(Rc::new(model)))
743 }
744}
745
746impl<T, M: Model<Data = T> + 'static> From<Rc<M>> for ModelRc<T> {
747 fn from(model: Rc<M>) -> Self {
748 Self(Some(model))
749 }
750}
751
752impl<T> From<Rc<dyn Model<Data = T> + 'static>> for ModelRc<T> {
753 fn from(model: Rc<dyn Model<Data = T> + 'static>) -> Self {
754 Self(Some(model))
755 }
756}
757
758impl<T: Clone + 'static> From<&[T]> for ModelRc<T> {
759 fn from(slice: &[T]) -> Self {
760 VecModel::from_slice(slice)
761 }
762}
763
764impl<T: Clone + 'static, const N: usize> From<[T; N]> for ModelRc<T> {
765 fn from(array: [T; N]) -> Self {
766 VecModel::from_slice(&array)
767 }
768}
769
770impl<T> TryInto<Rc<dyn Model<Data = T>>> for ModelRc<T> {
771 type Error = ();
772
773 fn try_into(self) -> Result<Rc<dyn Model<Data = T>>, Self::Error> {
774 self.0.ok_or(())
775 }
776}
777
778impl<T> Model for ModelRc<T> {
779 type Data = T;
780
781 fn row_count(&self) -> usize {
782 self.0.as_ref().map_or(0, |model| model.row_count())
783 }
784
785 fn row_data(&self, row: usize) -> Option<Self::Data> {
786 self.0.as_ref().and_then(|model| model.row_data(row))
787 }
788
789 fn set_row_data(&self, row: usize, data: Self::Data) {
790 if let Some(model) = self.0.as_ref() {
791 model.set_row_data(row, data);
792 }
793 }
794
795 fn model_tracker(&self) -> &dyn ModelTracker {
796 self.0.as_ref().map_or(&(), |model| model.model_tracker())
797 }
798
799 fn as_any(&self) -> &dyn core::any::Any {
800 self.0.as_ref().map_or(&(), |model| model.as_any())
801 }
802}
803
804pub trait RepeatedItemTree:
806 crate::item_tree::ItemTree + vtable::HasStaticVTable<ItemTreeVTable> + 'static
807{
808 type Data: 'static;
810
811 fn update(&self, index: usize, data: Self::Data);
813
814 fn init(&self) {}
817
818 fn listview_layout(self: Pin<&Self>, _offset_y: &mut LogicalLength) -> LogicalLength {
825 LogicalLength::default()
826 }
827
828 fn box_layout_data(
830 self: Pin<&Self>,
831 _orientation: Orientation,
832 ) -> crate::layout::BoxLayoutCellData {
833 crate::layout::BoxLayoutCellData::default()
834 }
835}
836
837#[derive(Clone, Copy, PartialEq, Debug)]
838enum RepeatedInstanceState {
839 Clean,
841 Dirty,
843}
844struct RepeaterInner<C: RepeatedItemTree> {
845 instances: Vec<(RepeatedInstanceState, Option<ItemTreeRc<C>>)>,
846
847 offset: usize,
850 cached_item_height: LogicalLength,
852 previous_viewport_y: LogicalLength,
854 anchor_y: LogicalLength,
857}
858
859impl<C: RepeatedItemTree> Default for RepeaterInner<C> {
860 fn default() -> Self {
861 RepeaterInner {
862 instances: Default::default(),
863 offset: 0,
864 cached_item_height: Default::default(),
865 previous_viewport_y: Default::default(),
866 anchor_y: Default::default(),
867 }
868 }
869}
870
871#[pin_project]
874pub struct RepeaterTracker<T: RepeatedItemTree> {
875 inner: RefCell<RepeaterInner<T>>,
876 #[pin]
877 model: Property<ModelRc<T::Data>>,
878 #[pin]
879 is_dirty: Property<bool>,
880 #[pin]
882 listview_geometry_tracker: crate::properties::PropertyTracker,
883}
884
885impl<T: RepeatedItemTree> ModelChangeListener for RepeaterTracker<T> {
886 fn row_changed(self: Pin<&Self>, row: usize) {
888 let mut inner = self.inner.borrow_mut();
889 let inner = &mut *inner;
890 if let Some(c) = inner.instances.get_mut(row.wrapping_sub(inner.offset)) {
891 if !self.model.is_dirty() {
892 if let Some(comp) = c.1.as_ref() {
893 let model = self.project_ref().model.get_untracked();
894 if let Some(data) = model.row_data(row) {
895 comp.update(row, data);
896 }
897 c.0 = RepeatedInstanceState::Clean;
898 }
899 } else {
900 c.0 = RepeatedInstanceState::Dirty;
901 }
902 }
903 }
904 fn row_added(self: Pin<&Self>, mut index: usize, mut count: usize) {
906 let mut inner = self.inner.borrow_mut();
907 if index < inner.offset {
908 if index + count < inner.offset {
909 return;
910 }
911 count -= inner.offset - index;
912 index = 0;
913 } else {
914 index -= inner.offset;
915 }
916 if count == 0 || index > inner.instances.len() {
917 return;
918 }
919 self.is_dirty.set(true);
920 inner.instances.splice(
921 index..index,
922 core::iter::repeat((RepeatedInstanceState::Dirty, None)).take(count),
923 );
924 for c in inner.instances[index + count..].iter_mut() {
925 c.0 = RepeatedInstanceState::Dirty;
927 }
928 }
929 fn row_removed(self: Pin<&Self>, mut index: usize, mut count: usize) {
931 let mut inner = self.inner.borrow_mut();
932 if index < inner.offset {
933 if index + count < inner.offset {
934 return;
935 }
936 count -= inner.offset - index;
937 index = 0;
938 } else {
939 index -= inner.offset;
940 }
941 if count == 0 || index >= inner.instances.len() {
942 return;
943 }
944 if (index + count) > inner.instances.len() {
945 count = inner.instances.len() - index;
946 }
947 self.is_dirty.set(true);
948 inner.instances.drain(index..(index + count));
949 for c in inner.instances[index..].iter_mut() {
950 c.0 = RepeatedInstanceState::Dirty;
952 }
953 }
954
955 fn reset(self: Pin<&Self>) {
956 self.is_dirty.set(true);
957 self.inner.borrow_mut().instances.clear();
958 }
959}
960
961impl<C: RepeatedItemTree> Default for RepeaterTracker<C> {
962 fn default() -> Self {
963 Self {
964 inner: Default::default(),
965 model: Property::new_named(ModelRc::default(), "i_slint_core::Repeater::model"),
966 is_dirty: Property::new_named(false, "i_slint_core::Repeater::is_dirty"),
967 listview_geometry_tracker: Default::default(),
968 }
969 }
970}
971
972#[pin_project]
973pub struct Repeater<C: RepeatedItemTree>(#[pin] ModelChangeListenerContainer<RepeaterTracker<C>>);
974
975impl<C: RepeatedItemTree> Default for Repeater<C> {
976 fn default() -> Self {
977 Self(Default::default())
978 }
979}
980
981impl<C: RepeatedItemTree + 'static> Repeater<C> {
982 fn data(self: Pin<&Self>) -> Pin<&RepeaterTracker<C>> {
983 self.project_ref().0.get()
984 }
985
986 fn model(self: Pin<&Self>) -> ModelRc<C::Data> {
987 let model = self.data().project_ref().model;
988
989 if model.is_dirty() {
990 let old_model = model.get_internal();
991 let m = model.get();
992 if old_model != m {
993 *self.data().inner.borrow_mut() = RepeaterInner::default();
994 self.data().is_dirty.set(true);
995 let peer = self.project_ref().0.model_peer();
996 m.model_tracker().attach_peer(peer);
997 }
998 m
999 } else {
1000 model.get()
1001 }
1002 }
1003
1004 pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {
1007 let model = self.model();
1008 if self.data().project_ref().is_dirty.get() {
1009 self.ensure_updated_impl(init, &model, model.row_count());
1010 }
1011 }
1012
1013 fn ensure_updated_impl(
1015 self: Pin<&Self>,
1016 init: impl Fn() -> ItemTreeRc<C>,
1017 model: &ModelRc<C::Data>,
1018 count: usize,
1019 ) -> bool {
1020 let mut indices_to_init = Vec::new();
1021 let mut inner = self.0.inner.borrow_mut();
1022 inner.instances.resize_with(count, || (RepeatedInstanceState::Dirty, None));
1023 let offset = inner.offset;
1024 let mut any_items_created = false;
1025 for (i, c) in inner.instances.iter_mut().enumerate() {
1026 if c.0 == RepeatedInstanceState::Dirty {
1027 if c.1.is_none() {
1028 any_items_created = true;
1029 c.1 = Some(init());
1030 indices_to_init.push(i);
1031 };
1032 if let Some(data) = model.row_data(i + offset) {
1033 c.1.as_ref().unwrap().update(i + offset, data);
1034 }
1035 c.0 = RepeatedInstanceState::Clean;
1036 }
1037 }
1038 self.data().is_dirty.set(false);
1039
1040 drop(inner);
1041 let inner = self.0.inner.borrow();
1042 for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
1043 item.1.as_ref().unwrap().init();
1044 }
1045
1046 any_items_created
1047 }
1048
1049 pub fn ensure_updated_listview(
1051 self: Pin<&Self>,
1052 init: impl Fn() -> ItemTreeRc<C>,
1053 viewport_width: Pin<&Property<LogicalLength>>,
1054 viewport_height: Pin<&Property<LogicalLength>>,
1055 viewport_y: Pin<&Property<LogicalLength>>,
1056 listview_width: LogicalLength,
1057 listview_height: Pin<&Property<LogicalLength>>,
1058 ) {
1059 self.data().project_ref().is_dirty.get();
1061 self.data().project_ref().is_dirty.set(false);
1062
1063 let mut vp_width = listview_width;
1064 let model = self.model();
1065 let row_count = model.row_count();
1066 let zero = LogicalLength::zero();
1067 if row_count == 0 {
1068 self.0.inner.borrow_mut().instances.clear();
1069 viewport_height.set(zero);
1070 viewport_y.set(zero);
1071 viewport_width.set(vp_width);
1072 return;
1073 }
1074
1075 let listview_height = listview_height.get();
1076 let mut vp_y = viewport_y.get().min(zero);
1077
1078 let cached_item_height = self.data().inner.borrow_mut().cached_item_height;
1080 let element_height = if cached_item_height > zero {
1081 cached_item_height
1082 } else {
1083 let total_height = Cell::new(zero);
1084 let count = Cell::new(0);
1085 let get_height_visitor = |x: &ItemTreeRc<C>| {
1086 let height = x.as_pin_ref().item_geometry(0).height_length();
1087 count.set(count.get() + 1);
1088 total_height.set(total_height.get() + height);
1089 };
1090 for c in self.data().inner.borrow().instances.iter() {
1091 if let Some(x) = c.1.as_ref() {
1092 get_height_visitor(x);
1093 }
1094 }
1095
1096 if count.get() > 0 {
1097 total_height.get() / (count.get() as Coord)
1098 } else {
1099 {
1101 let mut inner = self.0.inner.borrow_mut();
1102 inner.offset = inner.offset.min(row_count - 1);
1103 }
1104
1105 self.ensure_updated_impl(&init, &model, 1);
1106 if let Some(c) = self.data().inner.borrow().instances.first() {
1107 if let Some(x) = c.1.as_ref() {
1108 get_height_visitor(x);
1109 }
1110 } else {
1111 panic!("Could not determine size of items");
1112 }
1113 total_height.get()
1114 }
1115 };
1116
1117 let data = self.data();
1118 let mut inner = data.inner.borrow_mut();
1119 if inner.offset >= row_count {
1120 inner.offset = row_count - 1;
1121 }
1122
1123 let one_and_a_half_screen = listview_height * 3 as Coord / 2 as Coord;
1124 let first_item_y = inner.anchor_y;
1125 let last_item_bottom = first_item_y + element_height * inner.instances.len() as Coord;
1126
1127 let mut indices_to_init = Vec::new();
1128
1129 let (mut new_offset, mut new_offset_y) = if first_item_y > -vp_y + one_and_a_half_screen
1130 || last_item_bottom + element_height < -vp_y
1131 {
1132 inner.instances.clear();
1134 inner.offset = ((-vp_y / element_height).get().floor() as usize).min(row_count - 1);
1135 (inner.offset, zero)
1136 } else if vp_y < inner.previous_viewport_y {
1137 let mut it_y = first_item_y + vp_y;
1139 let mut new_offset = inner.offset;
1140 debug_assert!(it_y <= zero); for (i, c) in inner.instances.iter_mut().enumerate() {
1142 if c.0 == RepeatedInstanceState::Dirty {
1143 if c.1.is_none() {
1144 c.1 = Some(init());
1145 indices_to_init.push(i);
1146 }
1147 if let Some(data) = model.row_data(new_offset) {
1148 c.1.as_ref().unwrap().update(new_offset, data);
1149 }
1150 c.0 = RepeatedInstanceState::Clean;
1151 }
1152 let h = c.1.as_ref().unwrap().as_pin_ref().item_geometry(0).height_length();
1153 if it_y + h > zero || new_offset + 1 >= row_count {
1154 break;
1155 }
1156 it_y += h;
1157 new_offset += 1;
1158 }
1159 (new_offset, it_y)
1160 } else {
1161 (inner.offset, first_item_y + vp_y)
1163 };
1164
1165 let mut loop_count = 0;
1166 loop {
1167 while new_offset > inner.offset && new_offset_y > zero {
1171 new_offset -= 1;
1172 new_offset_y -= inner.instances[new_offset - inner.offset]
1173 .1
1174 .as_ref()
1175 .unwrap()
1176 .as_pin_ref()
1177 .item_geometry(0)
1178 .height_length();
1179 }
1180 let mut new_instances = Vec::new();
1182 while new_offset > 0 && new_offset_y > zero {
1183 new_offset -= 1;
1184 let new_instance = init();
1185 if let Some(data) = model.row_data(new_offset) {
1186 new_instance.update(new_offset, data);
1187 }
1188 new_offset_y -= new_instance.as_pin_ref().item_geometry(0).height_length();
1189 new_instances.push(new_instance);
1190 }
1191 if !new_instances.is_empty() {
1192 for x in &mut indices_to_init {
1193 *x += new_instances.len();
1194 }
1195 indices_to_init.extend(0..new_instances.len());
1196 inner.instances.splice(
1197 0..0,
1198 new_instances
1199 .into_iter()
1200 .rev()
1201 .map(|c| (RepeatedInstanceState::Clean, Some(c))),
1202 );
1203 inner.offset = new_offset;
1204 }
1205 assert!(
1206 new_offset >= inner.offset && new_offset <= inner.offset + inner.instances.len()
1207 );
1208
1209 let mut y = new_offset_y;
1211 let mut idx = new_offset;
1212 let instances_begin = new_offset - inner.offset;
1213 for c in &mut inner.instances[instances_begin..] {
1214 if idx >= row_count {
1215 break;
1216 }
1217 if c.0 == RepeatedInstanceState::Dirty {
1218 if c.1.is_none() {
1219 c.1 = Some(init());
1220 indices_to_init.push(instances_begin + idx - new_offset)
1221 }
1222 if let Some(data) = model.row_data(idx) {
1223 c.1.as_ref().unwrap().update(idx, data);
1224 }
1225 c.0 = RepeatedInstanceState::Clean;
1226 }
1227 if let Some(x) = c.1.as_ref() {
1228 vp_width = vp_width.max(x.as_pin_ref().listview_layout(&mut y));
1229 }
1230 idx += 1;
1231 if y >= listview_height {
1232 break;
1233 }
1234 }
1235
1236 while y < listview_height && idx < row_count {
1238 let new_instance = init();
1239 if let Some(data) = model.row_data(idx) {
1240 new_instance.update(idx, data);
1241 }
1242 vp_width = vp_width.max(new_instance.as_pin_ref().listview_layout(&mut y));
1243 indices_to_init.push(inner.instances.len());
1244 inner.instances.push((RepeatedInstanceState::Clean, Some(new_instance)));
1245 idx += 1;
1246 }
1247 if y < listview_height && vp_y < zero && loop_count < 3 {
1248 assert!(idx >= row_count);
1249 vp_y += listview_height - y;
1251 loop_count += 1;
1252 continue;
1253 }
1254
1255 if new_offset != inner.offset {
1257 let instances_begin = new_offset - inner.offset;
1258 inner.instances.splice(0..instances_begin, core::iter::empty());
1259 indices_to_init.retain_mut(|idx| {
1260 if *idx < instances_begin {
1261 false
1262 } else {
1263 *idx -= instances_begin;
1264 true
1265 }
1266 });
1267 inner.offset = new_offset;
1268 }
1269 if inner.instances.len() != idx - new_offset {
1270 inner.instances.splice(idx - new_offset.., core::iter::empty());
1271 indices_to_init.retain(|x| *x < idx - new_offset);
1272 }
1273
1274 if inner.instances.is_empty() {
1275 break;
1276 }
1277
1278 inner.cached_item_height = (y - new_offset_y) / inner.instances.len() as Coord;
1280 inner.anchor_y = inner.cached_item_height * inner.offset as Coord;
1281 viewport_height.set(inner.cached_item_height * row_count as Coord);
1282 viewport_width.set(vp_width);
1283 let new_viewport_y = -inner.anchor_y + new_offset_y;
1284 viewport_y.set(new_viewport_y);
1285 inner.previous_viewport_y = new_viewport_y;
1286 break;
1287 }
1288 drop(inner);
1289 let inner = self.0.inner.borrow();
1290 for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
1291 item.1.as_ref().unwrap().init();
1292 }
1293 }
1294
1295 pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {
1297 let model = self.model();
1298 model.set_row_data(row, data);
1299 }
1300
1301 pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {
1303 self.0.model.set_binding(binding);
1304 }
1305
1306 pub fn visit(
1308 &self,
1309 order: TraversalOrder,
1310 mut visitor: crate::item_tree::ItemVisitorRefMut,
1311 ) -> crate::item_tree::VisitChildrenResult {
1312 let count = self.0.inner.borrow().instances.len() as u32;
1314 for i in 0..count {
1315 let i = if order == TraversalOrder::BackToFront { i } else { count - i - 1 };
1316 let c = self.0.inner.borrow().instances.get(i as usize).and_then(|c| c.1.clone());
1317 if let Some(c) = c {
1318 if c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted()
1319 {
1320 return crate::item_tree::VisitChildrenResult::abort(i, 0);
1321 }
1322 }
1323 }
1324 crate::item_tree::VisitChildrenResult::CONTINUE
1325 }
1326
1327 pub fn len(&self) -> usize {
1329 self.0.inner.borrow().instances.len()
1330 }
1331
1332 pub fn range(&self) -> core::ops::Range<usize> {
1337 let inner = self.0.inner.borrow();
1338 core::ops::Range { start: inner.offset, end: inner.offset + inner.instances.len() }
1339 }
1340
1341 pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {
1344 let inner = self.0.inner.borrow();
1345 inner
1346 .instances
1347 .get(index.checked_sub(inner.offset)?)
1348 .map(|c| c.1.clone().expect("That was updated before!"))
1349 }
1350
1351 pub fn is_empty(&self) -> bool {
1353 self.len() == 0
1354 }
1355
1356 pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {
1358 self.0.inner.borrow().instances.iter().flat_map(|x| x.1.clone()).collect()
1359 }
1360}
1361
1362#[pin_project]
1363pub struct Conditional<C: RepeatedItemTree> {
1364 #[pin]
1365 model: Property<bool>,
1366 instance: RefCell<Option<ItemTreeRc<C>>>,
1367}
1368
1369impl<C: RepeatedItemTree> Default for Conditional<C> {
1370 fn default() -> Self {
1371 Self {
1372 model: Property::new_named(false, "i_slint_core::Conditional::model"),
1373 instance: RefCell::new(None),
1374 }
1375 }
1376}
1377
1378impl<C: RepeatedItemTree + 'static> Conditional<C> {
1379 pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {
1382 let model = self.project_ref().model.get();
1383
1384 if !model {
1385 drop(self.instance.replace(None));
1386 } else if self.instance.borrow().is_none() {
1387 let i = init();
1388 self.instance.replace(Some(i.clone()));
1389 i.init();
1390 }
1391 }
1392
1393 pub fn set_model_binding(&self, binding: impl Fn() -> bool + 'static) {
1395 self.model.set_binding(binding);
1396 }
1397
1398 pub fn visit(
1400 &self,
1401 order: TraversalOrder,
1402 mut visitor: crate::item_tree::ItemVisitorRefMut,
1403 ) -> crate::item_tree::VisitChildrenResult {
1404 let instance = self.instance.borrow().clone();
1406 if let Some(c) = instance {
1407 if c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted() {
1408 return crate::item_tree::VisitChildrenResult::abort(0, 0);
1409 }
1410 }
1411
1412 crate::item_tree::VisitChildrenResult::CONTINUE
1413 }
1414
1415 pub fn len(&self) -> usize {
1417 self.instance.borrow().is_some() as usize
1418 }
1419
1420 pub fn range(&self) -> core::ops::Range<usize> {
1424 0..self.len()
1425 }
1426
1427 pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {
1430 if index != 0 {
1431 return None;
1432 }
1433 self.instance.borrow().clone()
1434 }
1435
1436 pub fn is_empty(&self) -> bool {
1438 self.len() == 0
1439 }
1440
1441 pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {
1443 self.instance.borrow().clone().into_iter().collect()
1444 }
1445}
1446
1447impl From<SharedString> for StandardListViewItem {
1448 fn from(value: SharedString) -> Self {
1449 StandardListViewItem { text: value }
1450 }
1451}
1452
1453impl From<&str> for StandardListViewItem {
1454 fn from(value: &str) -> Self {
1455 StandardListViewItem { text: value.into() }
1456 }
1457}
1458
1459#[cfg(test)]
1460mod tests {
1461 use super::*;
1462 use std::vec;
1463
1464 #[test]
1465 fn test_tracking_model_handle() {
1466 let model: Rc<VecModel<u8>> = Rc::new(Default::default());
1467 let handle = ModelRc::from(model.clone() as Rc<dyn Model<Data = u8>>);
1468 let tracker = Box::pin(crate::properties::PropertyTracker::default());
1469 assert_eq!(
1470 tracker.as_ref().evaluate(|| {
1471 handle.model_tracker().track_row_count_changes();
1472 handle.row_count()
1473 }),
1474 0
1475 );
1476 assert!(!tracker.is_dirty());
1477 model.push(42);
1478 model.push(100);
1479 assert!(tracker.is_dirty());
1480 assert_eq!(
1481 tracker.as_ref().evaluate(|| {
1482 handle.model_tracker().track_row_count_changes();
1483 handle.row_count()
1484 }),
1485 2
1486 );
1487 assert!(!tracker.is_dirty());
1488 model.set_row_data(0, 41);
1489 assert!(!tracker.is_dirty());
1490 model.remove(0);
1491 assert!(tracker.is_dirty());
1492 assert_eq!(
1493 tracker.as_ref().evaluate(|| {
1494 handle.model_tracker().track_row_count_changes();
1495 handle.row_count()
1496 }),
1497 1
1498 );
1499 assert!(!tracker.is_dirty());
1500 model.set_vec(vec![1, 2, 3]);
1501 assert!(tracker.is_dirty());
1502 }
1503
1504 #[test]
1505 fn test_data_tracking() {
1506 let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));
1507 let handle = ModelRc::from(model.clone());
1508 let tracker = Box::pin(crate::properties::PropertyTracker::default());
1509 assert_eq!(
1510 tracker.as_ref().evaluate(|| {
1511 handle.model_tracker().track_row_data_changes(1);
1512 handle.row_data(1).unwrap()
1513 }),
1514 1
1515 );
1516 assert!(!tracker.is_dirty());
1517
1518 model.set_row_data(2, 42);
1519 assert!(!tracker.is_dirty());
1520 model.set_row_data(1, 100);
1521 assert!(tracker.is_dirty());
1522
1523 assert_eq!(
1524 tracker.as_ref().evaluate(|| {
1525 handle.model_tracker().track_row_data_changes(1);
1526 handle.row_data(1).unwrap()
1527 }),
1528 100
1529 );
1530 assert!(!tracker.is_dirty());
1531
1532 model.push(200);
1535 assert!(tracker.is_dirty());
1536
1537 assert_eq!(tracker.as_ref().evaluate(|| { handle.row_data_tracked(1).unwrap() }), 100);
1538 assert!(!tracker.is_dirty());
1539
1540 model.insert(0, 255);
1541 assert!(tracker.is_dirty());
1542
1543 model.set_vec(vec![]);
1544 assert!(tracker.is_dirty());
1545 }
1546
1547 #[derive(Default)]
1548 struct TestView {
1549 changed_rows: RefCell<Vec<(usize, usize)>>,
1553 added_rows: RefCell<Vec<(usize, usize, usize)>>,
1554 removed_rows: RefCell<Vec<(usize, usize, usize)>>,
1555 reset: RefCell<usize>,
1556 model: RefCell<Option<std::rc::Weak<dyn Model<Data = i32>>>>,
1557 }
1558 impl TestView {
1559 fn clear(&self) {
1560 self.changed_rows.borrow_mut().clear();
1561 self.added_rows.borrow_mut().clear();
1562 self.removed_rows.borrow_mut().clear();
1563 *self.reset.borrow_mut() = 0;
1564 }
1565 fn row_count(&self) -> usize {
1566 self.model
1567 .borrow()
1568 .as_ref()
1569 .and_then(|model| model.upgrade())
1570 .map_or(0, |model| model.row_count())
1571 }
1572 }
1573 impl ModelChangeListener for TestView {
1574 fn row_changed(self: Pin<&Self>, row: usize) {
1575 self.changed_rows.borrow_mut().push((row, self.row_count()));
1576 }
1577
1578 fn row_added(self: Pin<&Self>, index: usize, count: usize) {
1579 self.added_rows.borrow_mut().push((index, count, self.row_count()));
1580 }
1581
1582 fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
1583 self.removed_rows.borrow_mut().push((index, count, self.row_count()));
1584 }
1585 fn reset(self: Pin<&Self>) {
1586 *self.reset.borrow_mut() += 1;
1587 }
1588 }
1589
1590 #[test]
1591 fn test_vecmodel_set_vec() {
1592 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1593
1594 let model = Rc::new(VecModel::from(vec![1i32, 2, 3, 4]));
1595 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1596 *view.model.borrow_mut() =
1597 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1598
1599 model.push(5);
1600 assert!(view.changed_rows.borrow().is_empty());
1601 assert_eq!(&*view.added_rows.borrow(), &[(4, 1, 5)]);
1602 assert!(view.removed_rows.borrow().is_empty());
1603 assert_eq!(*view.reset.borrow(), 0);
1604 view.clear();
1605
1606 model.set_vec(vec![6, 7, 8]);
1607 assert!(view.changed_rows.borrow().is_empty());
1608 assert!(view.added_rows.borrow().is_empty());
1609 assert!(view.removed_rows.borrow().is_empty());
1610 assert_eq!(*view.reset.borrow(), 1);
1611 view.clear();
1612
1613 model.extend_from_slice(&[9, 10, 11]);
1614 assert!(view.changed_rows.borrow().is_empty());
1615 assert_eq!(&*view.added_rows.borrow(), &[(3, 3, 6)]);
1616 assert!(view.removed_rows.borrow().is_empty());
1617 assert_eq!(*view.reset.borrow(), 0);
1618 view.clear();
1619
1620 model.extend([12, 13]);
1621 assert!(view.changed_rows.borrow().is_empty());
1622 assert_eq!(&*view.added_rows.borrow(), &[(6, 2, 8)]);
1623 assert!(view.removed_rows.borrow().is_empty());
1624 assert_eq!(*view.reset.borrow(), 0);
1625 view.clear();
1626
1627 assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 7, 8, 9, 10, 11, 12, 13]);
1628
1629 model.swap(1, 1);
1630 assert!(view.changed_rows.borrow().is_empty());
1631 assert!(view.added_rows.borrow().is_empty());
1632 assert!(view.removed_rows.borrow().is_empty());
1633 assert_eq!(*view.reset.borrow(), 0);
1634 view.clear();
1635
1636 model.swap(1, 2);
1637 assert_eq!(&*view.changed_rows.borrow(), &[(1, 8), (2, 8)]);
1638 assert!(view.added_rows.borrow().is_empty());
1639 assert!(view.removed_rows.borrow().is_empty());
1640 assert_eq!(*view.reset.borrow(), 0);
1641 view.clear();
1642
1643 assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 8, 7, 9, 10, 11, 12, 13]);
1644 }
1645
1646 #[test]
1647 fn test_vecmodel_clear() {
1648 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1649
1650 let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1651 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1652 *view.model.borrow_mut() =
1653 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1654
1655 model.clear();
1656 assert_eq!(*view.reset.borrow(), 1);
1657 assert_eq!(model.row_count(), 0);
1658 }
1659
1660 #[test]
1661 fn test_vecmodel_swap() {
1662 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1663
1664 let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1665 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1666 *view.model.borrow_mut() =
1667 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1668
1669 model.swap(1, 1);
1670 assert!(view.changed_rows.borrow().is_empty());
1671 assert!(view.added_rows.borrow().is_empty());
1672 assert!(view.removed_rows.borrow().is_empty());
1673 assert_eq!(*view.reset.borrow(), 0);
1674 view.clear();
1675
1676 model.swap(1, 2);
1677 assert_eq!(&*view.changed_rows.borrow(), &[(1, 4), (2, 4)]);
1678 assert!(view.added_rows.borrow().is_empty());
1679 assert!(view.removed_rows.borrow().is_empty());
1680 assert_eq!(*view.reset.borrow(), 0);
1681 view.clear();
1682 }
1683
1684 #[test]
1685 fn modeliter_in_bounds() {
1686 struct TestModel {
1687 length: usize,
1688 max_requested_row: Cell<usize>,
1689 notify: ModelNotify,
1690 }
1691
1692 impl Model for TestModel {
1693 type Data = usize;
1694
1695 fn row_count(&self) -> usize {
1696 self.length
1697 }
1698
1699 fn row_data(&self, row: usize) -> Option<usize> {
1700 self.max_requested_row.set(self.max_requested_row.get().max(row));
1701 (row < self.length).then_some(row)
1702 }
1703
1704 fn model_tracker(&self) -> &dyn ModelTracker {
1705 &self.notify
1706 }
1707 }
1708
1709 let model = Rc::new(TestModel {
1710 length: 10,
1711 max_requested_row: Cell::new(0),
1712 notify: Default::default(),
1713 });
1714
1715 assert_eq!(model.iter().max().unwrap(), 9);
1716 assert_eq!(model.max_requested_row.get(), 9);
1717 }
1718
1719 #[test]
1720 fn vecmodel_doesnt_require_default() {
1721 #[derive(Clone)]
1722 struct MyNoDefaultType {
1723 _foo: bool,
1724 }
1725 let model = VecModel::<MyNoDefaultType>::default();
1726 assert_eq!(model.row_count(), 0);
1727 model.push(MyNoDefaultType { _foo: true });
1728 }
1729}