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 { 1 } else { 0 }
576 }
577
578 fn row_data(&self, row: usize) -> Option<Self::Data> {
579 (row < self.row_count()).then_some(())
580 }
581
582 fn as_any(&self) -> &dyn core::any::Any {
583 self
584 }
585
586 fn model_tracker(&self) -> &dyn ModelTracker {
587 &()
588 }
589}
590
591pub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);
703
704impl<T> core::fmt::Debug for ModelRc<T> {
705 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
706 write!(f, "ModelRc(dyn Model)")
707 }
708}
709
710impl<T> Clone for ModelRc<T> {
711 fn clone(&self) -> Self {
712 Self(self.0.clone())
713 }
714}
715
716impl<T> Default for ModelRc<T> {
717 fn default() -> Self {
719 Self(None)
720 }
721}
722
723impl<T> core::cmp::PartialEq for ModelRc<T> {
724 fn eq(&self, other: &Self) -> bool {
725 match (&self.0, &other.0) {
726 (None, None) => true,
727 (Some(a), Some(b)) => core::ptr::eq(
728 (&**a) as *const dyn Model<Data = T> as *const u8,
729 (&**b) as *const dyn Model<Data = T> as *const u8,
730 ),
731 _ => false,
732 }
733 }
734}
735
736impl<T> ModelRc<T> {
737 pub fn new(model: impl Model<Data = T> + 'static) -> Self {
738 Self(Some(Rc::new(model)))
739 }
740}
741
742impl<T, M: Model<Data = T> + 'static> From<Rc<M>> for ModelRc<T> {
743 fn from(model: Rc<M>) -> Self {
744 Self(Some(model))
745 }
746}
747
748impl<T> From<Rc<dyn Model<Data = T> + 'static>> for ModelRc<T> {
749 fn from(model: Rc<dyn Model<Data = T> + 'static>) -> Self {
750 Self(Some(model))
751 }
752}
753
754impl<T: Clone + 'static> From<&[T]> for ModelRc<T> {
755 fn from(slice: &[T]) -> Self {
756 VecModel::from_slice(slice)
757 }
758}
759
760impl<T: Clone + 'static, const N: usize> From<[T; N]> for ModelRc<T> {
761 fn from(array: [T; N]) -> Self {
762 VecModel::from_slice(&array)
763 }
764}
765
766impl<T> TryInto<Rc<dyn Model<Data = T>>> for ModelRc<T> {
767 type Error = ();
768
769 fn try_into(self) -> Result<Rc<dyn Model<Data = T>>, Self::Error> {
770 self.0.ok_or(())
771 }
772}
773
774impl<T> Model for ModelRc<T> {
775 type Data = T;
776
777 fn row_count(&self) -> usize {
778 self.0.as_ref().map_or(0, |model| model.row_count())
779 }
780
781 fn row_data(&self, row: usize) -> Option<Self::Data> {
782 self.0.as_ref().and_then(|model| model.row_data(row))
783 }
784
785 fn set_row_data(&self, row: usize, data: Self::Data) {
786 if let Some(model) = self.0.as_ref() {
787 model.set_row_data(row, data);
788 }
789 }
790
791 fn model_tracker(&self) -> &dyn ModelTracker {
792 self.0.as_ref().map_or(&(), |model| model.model_tracker())
793 }
794
795 fn as_any(&self) -> &dyn core::any::Any {
796 self.0.as_ref().map_or(&(), |model| model.as_any())
797 }
798}
799
800pub trait RepeatedItemTree:
802 crate::item_tree::ItemTree + vtable::HasStaticVTable<ItemTreeVTable> + 'static
803{
804 type Data: Default + 'static;
806
807 fn update(&self, index: usize, data: Self::Data);
809
810 fn init(&self) {}
813
814 fn listview_layout(self: Pin<&Self>, _offset_y: &mut LogicalLength) -> LogicalLength {
821 LogicalLength::default()
822 }
823
824 fn layout_item_info(
827 self: Pin<&Self>,
828 _orientation: Orientation,
829 _child_index: Option<usize>,
830 ) -> crate::layout::LayoutItemInfo {
831 crate::layout::LayoutItemInfo::default()
832 }
833
834 fn grid_layout_input_data(
839 self: Pin<&Self>,
840 _new_row: bool,
841 _result: &mut [crate::layout::GridLayoutInputData],
842 ) {
843 crate::debug_log!(
844 "Internal error in Slint: RepeatedItemTree::grid_layout_input_data() not implemented for {}",
845 core::any::type_name::<Self>()
846 );
847 }
849}
850
851#[derive(Clone, Copy, PartialEq, Debug)]
852enum RepeatedInstanceState {
853 Clean,
855 Dirty,
857}
858struct RepeaterInner<C: RepeatedItemTree> {
859 instances: Vec<(RepeatedInstanceState, Option<ItemTreeRc<C>>)>,
860
861 offset: usize,
864 cached_item_height: LogicalLength,
866 previous_viewport_y: LogicalLength,
868 anchor_y: LogicalLength,
871}
872
873impl<C: RepeatedItemTree> Default for RepeaterInner<C> {
874 fn default() -> Self {
875 RepeaterInner {
876 instances: Default::default(),
877 offset: 0,
878 cached_item_height: Default::default(),
879 previous_viewport_y: Default::default(),
880 anchor_y: Default::default(),
881 }
882 }
883}
884
885#[pin_project]
888pub struct RepeaterTracker<T: RepeatedItemTree> {
889 inner: RefCell<RepeaterInner<T>>,
890 #[pin]
891 model: Property<ModelRc<T::Data>>,
892 #[pin]
893 is_dirty: Property<bool>,
895 #[pin]
897 listview_geometry_tracker: crate::properties::PropertyTracker,
898}
899
900impl<T: RepeatedItemTree> ModelChangeListener for RepeaterTracker<T> {
901 fn row_changed(self: Pin<&Self>, row: usize) {
903 let mut inner = self.inner.borrow_mut();
904 let inner = &mut *inner;
905 if let Some(c) = inner.instances.get_mut(row.wrapping_sub(inner.offset)) {
906 if !self.model.is_dirty() {
907 if let Some(comp) = c.1.as_ref() {
908 let model = self.project_ref().model.get_untracked();
909 comp.update(row, model.row_data(row).unwrap_or_default());
910 c.0 = RepeatedInstanceState::Clean;
911 }
912 } else {
913 c.0 = RepeatedInstanceState::Dirty;
914 }
915 }
916 }
917 fn row_added(self: Pin<&Self>, mut index: usize, mut count: usize) {
919 let mut inner = self.inner.borrow_mut();
920 if index < inner.offset {
921 if index + count < inner.offset {
922 return;
923 }
924 count -= inner.offset - index;
925 index = 0;
926 } else {
927 index -= inner.offset;
928 }
929 if count == 0 || index > inner.instances.len() {
930 return;
931 }
932 self.is_dirty.set(true);
933 inner.instances.splice(
934 index..index,
935 core::iter::repeat_n((RepeatedInstanceState::Dirty, None), count),
936 );
937 for c in inner.instances[index + count..].iter_mut() {
938 c.0 = RepeatedInstanceState::Dirty;
940 }
941 }
942 fn row_removed(self: Pin<&Self>, mut index: usize, mut count: usize) {
944 let mut inner = self.inner.borrow_mut();
945 if index < inner.offset {
946 if index + count < inner.offset {
947 return;
948 }
949 count -= inner.offset - index;
950 index = 0;
951 } else {
952 index -= inner.offset;
953 }
954 if count == 0 || index >= inner.instances.len() {
955 return;
956 }
957 if (index + count) > inner.instances.len() {
958 count = inner.instances.len() - index;
959 }
960 self.is_dirty.set(true);
961 inner.instances.drain(index..(index + count));
962 for c in inner.instances[index..].iter_mut() {
963 c.0 = RepeatedInstanceState::Dirty;
965 }
966 }
967
968 fn reset(self: Pin<&Self>) {
969 self.is_dirty.set(true);
970 self.inner.borrow_mut().instances.clear();
971 }
972}
973
974impl<C: RepeatedItemTree> Default for RepeaterTracker<C> {
975 fn default() -> Self {
976 Self {
977 inner: Default::default(),
978 model: Property::new_named(ModelRc::default(), "i_slint_core::Repeater::model"),
979 is_dirty: Property::new_named(false, "i_slint_core::Repeater::is_dirty"),
980 listview_geometry_tracker: Default::default(),
981 }
982 }
983}
984
985#[pin_project]
986pub struct Repeater<C: RepeatedItemTree>(#[pin] ModelChangeListenerContainer<RepeaterTracker<C>>);
987
988impl<C: RepeatedItemTree> Default for Repeater<C> {
989 fn default() -> Self {
990 Self(Default::default())
991 }
992}
993
994impl<C: RepeatedItemTree + 'static> Repeater<C> {
995 fn data(self: Pin<&Self>) -> Pin<&RepeaterTracker<C>> {
996 self.project_ref().0.get()
997 }
998
999 fn model(self: Pin<&Self>) -> ModelRc<C::Data> {
1000 let model = self.data().project_ref().model;
1001
1002 if model.is_dirty() {
1003 let old_model = model.get_internal();
1004 let m = model.get();
1005 if old_model != m {
1006 *self.data().inner.borrow_mut() = RepeaterInner::default();
1007 self.data().is_dirty.set(true);
1008 let peer = self.project_ref().0.model_peer();
1009 m.model_tracker().attach_peer(peer);
1010 }
1011 m
1012 } else {
1013 model.get()
1014 }
1015 }
1016
1017 pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {
1020 let model = self.model();
1021 if self.data().project_ref().is_dirty.get() {
1022 self.ensure_updated_impl(init, &model, model.row_count());
1023 }
1024 }
1025
1026 fn ensure_updated_impl(
1028 self: Pin<&Self>,
1029 init: impl Fn() -> ItemTreeRc<C>,
1030 model: &ModelRc<C::Data>,
1031 count: usize,
1032 ) -> bool {
1033 let mut indices_to_init = Vec::new();
1034 let mut inner = self.0.inner.borrow_mut();
1035 inner.instances.resize_with(count, || (RepeatedInstanceState::Dirty, None));
1036 let offset = inner.offset;
1037 let mut any_items_created = false;
1038 for (i, c) in inner.instances.iter_mut().enumerate() {
1039 if c.0 == RepeatedInstanceState::Dirty {
1040 if c.1.is_none() {
1041 any_items_created = true;
1042 c.1 = Some(init());
1043 indices_to_init.push(i);
1044 };
1045 c.1.as_ref()
1046 .unwrap()
1047 .update(i + offset, model.row_data(i + offset).unwrap_or_default());
1048 c.0 = RepeatedInstanceState::Clean;
1049 }
1050 }
1051 self.data().is_dirty.set(false);
1052
1053 drop(inner);
1054 let inner = self.0.inner.borrow();
1055 for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
1056 item.1.as_ref().unwrap().init();
1057 }
1058
1059 any_items_created
1060 }
1061
1062 pub fn ensure_updated_listview(
1064 self: Pin<&Self>,
1065 init: impl Fn() -> ItemTreeRc<C>,
1066 viewport_width: Pin<&Property<LogicalLength>>,
1067 viewport_height: Pin<&Property<LogicalLength>>,
1068 viewport_y: Pin<&Property<LogicalLength>>,
1069 listview_width: LogicalLength,
1070 listview_height: Pin<&Property<LogicalLength>>,
1071 ) {
1072 let _ = self.data().project_ref().is_dirty.get();
1074 self.data().project_ref().is_dirty.set(false);
1075
1076 let mut vp_width = listview_width;
1077 let model = self.model();
1078 let row_count = model.row_count();
1079 let zero = LogicalLength::zero();
1080 if row_count == 0 {
1081 self.0.inner.borrow_mut().instances.clear();
1082 viewport_height.set(zero);
1083 viewport_y.set(zero);
1084 viewport_width.set(vp_width);
1085 return;
1086 }
1087
1088 let listview_height = listview_height.get();
1089 let mut vp_y = viewport_y.get().min(zero);
1090
1091 let cached_item_height = self.data().inner.borrow_mut().cached_item_height;
1093 let element_height = if cached_item_height > zero {
1094 cached_item_height
1095 } else {
1096 let total_height = Cell::new(zero);
1097 let count = Cell::new(0);
1098 let get_height_visitor = |x: &ItemTreeRc<C>| {
1099 let height = x.as_pin_ref().item_geometry(0).height_length();
1100 count.set(count.get() + 1);
1101 total_height.set(total_height.get() + height);
1102 };
1103 for c in self.data().inner.borrow().instances.iter() {
1104 if let Some(x) = c.1.as_ref() {
1105 get_height_visitor(x);
1106 }
1107 }
1108
1109 if count.get() > 0 {
1110 total_height.get() / (count.get() as Coord)
1111 } else {
1112 {
1114 let mut inner = self.0.inner.borrow_mut();
1115 inner.offset = inner.offset.min(row_count - 1);
1116 }
1117
1118 self.ensure_updated_impl(&init, &model, 1);
1119 if let Some(c) = self.data().inner.borrow().instances.first() {
1120 if let Some(x) = c.1.as_ref() {
1121 get_height_visitor(x);
1122 }
1123 } else {
1124 panic!("Could not determine size of items");
1125 }
1126 total_height.get()
1127 }
1128 };
1129
1130 let data = self.data();
1131 let mut inner = data.inner.borrow_mut();
1132 if inner.offset >= row_count {
1133 inner.offset = row_count - 1;
1134 }
1135
1136 let one_and_a_half_screen = listview_height * 3 as Coord / 2 as Coord;
1137 let first_item_y = inner.anchor_y;
1138 let last_item_bottom = first_item_y + element_height * inner.instances.len() as Coord;
1139
1140 let mut indices_to_init = Vec::new();
1141
1142 let (mut new_offset, mut new_offset_y) = if first_item_y > -vp_y + one_and_a_half_screen
1143 || last_item_bottom + element_height < -vp_y
1144 {
1145 inner.instances.clear();
1147 inner.offset = ((-vp_y / element_height).get().floor() as usize).min(row_count - 1);
1148 (inner.offset, zero)
1149 } else if vp_y < inner.previous_viewport_y {
1150 let mut it_y = first_item_y + vp_y;
1152 let mut new_offset = inner.offset;
1153 debug_assert!(it_y <= zero); for (i, c) in inner.instances.iter_mut().enumerate() {
1155 if c.0 == RepeatedInstanceState::Dirty {
1156 if c.1.is_none() {
1157 c.1 = Some(init());
1158 indices_to_init.push(i);
1159 }
1160 c.1.as_ref()
1161 .unwrap()
1162 .update(new_offset, model.row_data(new_offset).unwrap_or_default());
1163 c.0 = RepeatedInstanceState::Clean;
1164 }
1165 let h = c.1.as_ref().unwrap().as_pin_ref().item_geometry(0).height_length();
1166 if it_y + h > zero || new_offset + 1 >= row_count {
1167 break;
1168 }
1169 it_y += h;
1170 new_offset += 1;
1171 }
1172 (new_offset, it_y)
1173 } else {
1174 (inner.offset, first_item_y + vp_y)
1176 };
1177
1178 let mut loop_count = 0;
1179 loop {
1180 while new_offset > inner.offset && new_offset_y > zero {
1184 new_offset -= 1;
1185 new_offset_y -= inner.instances[new_offset - inner.offset]
1186 .1
1187 .as_ref()
1188 .unwrap()
1189 .as_pin_ref()
1190 .item_geometry(0)
1191 .height_length();
1192 }
1193 let mut new_instances = Vec::new();
1195 while new_offset > 0 && new_offset_y > zero {
1196 new_offset -= 1;
1197 let new_instance = init();
1198 new_instance.update(new_offset, model.row_data(new_offset).unwrap_or_default());
1199 new_offset_y -= new_instance.as_pin_ref().item_geometry(0).height_length();
1200 new_instances.push(new_instance);
1201 }
1202 if !new_instances.is_empty() {
1203 for x in &mut indices_to_init {
1204 *x += new_instances.len();
1205 }
1206 indices_to_init.extend(0..new_instances.len());
1207 inner.instances.splice(
1208 0..0,
1209 new_instances
1210 .into_iter()
1211 .rev()
1212 .map(|c| (RepeatedInstanceState::Clean, Some(c))),
1213 );
1214 inner.offset = new_offset;
1215 }
1216 assert!(
1217 new_offset >= inner.offset && new_offset <= inner.offset + inner.instances.len()
1218 );
1219
1220 let mut y = new_offset_y;
1222 let mut idx = new_offset;
1223 let instances_begin = new_offset - inner.offset;
1224 for c in &mut inner.instances[instances_begin..] {
1225 if idx >= row_count {
1226 break;
1227 }
1228 if c.0 == RepeatedInstanceState::Dirty {
1229 if c.1.is_none() {
1230 c.1 = Some(init());
1231 indices_to_init.push(instances_begin + idx - new_offset)
1232 }
1233 c.1.as_ref().unwrap().update(idx, model.row_data(idx).unwrap_or_default());
1234 c.0 = RepeatedInstanceState::Clean;
1235 }
1236 if let Some(x) = c.1.as_ref() {
1237 vp_width = vp_width.max(x.as_pin_ref().listview_layout(&mut y));
1238 }
1239 idx += 1;
1240 if y >= listview_height {
1241 break;
1242 }
1243 }
1244
1245 while y < listview_height && idx < row_count {
1247 let new_instance = init();
1248 new_instance.update(idx, model.row_data(idx).unwrap_or_default());
1249 vp_width = vp_width.max(new_instance.as_pin_ref().listview_layout(&mut y));
1250 indices_to_init.push(inner.instances.len());
1251 inner.instances.push((RepeatedInstanceState::Clean, Some(new_instance)));
1252 idx += 1;
1253 }
1254 if y < listview_height && vp_y < zero && loop_count < 3 {
1255 assert!(idx >= row_count);
1256 vp_y += listview_height - y;
1258 loop_count += 1;
1259 continue;
1260 }
1261
1262 if new_offset != inner.offset {
1264 let instances_begin = new_offset - inner.offset;
1265 inner.instances.splice(0..instances_begin, core::iter::empty());
1266 indices_to_init.retain_mut(|idx| {
1267 if *idx < instances_begin {
1268 false
1269 } else {
1270 *idx -= instances_begin;
1271 true
1272 }
1273 });
1274 inner.offset = new_offset;
1275 }
1276 if inner.instances.len() != idx - new_offset {
1277 inner.instances.splice(idx - new_offset.., core::iter::empty());
1278 indices_to_init.retain(|x| *x < idx - new_offset);
1279 }
1280
1281 if inner.instances.is_empty() {
1282 break;
1283 }
1284
1285 inner.cached_item_height = (y - new_offset_y) / inner.instances.len() as Coord; inner.anchor_y = inner.cached_item_height * inner.offset as Coord;
1288 viewport_height.set(inner.cached_item_height * row_count as Coord);
1289 viewport_width.set(vp_width);
1290 let new_viewport_y = -inner.anchor_y + new_offset_y;
1291 if new_viewport_y != viewport_y.get() {
1292 viewport_y.set(new_viewport_y);
1294 }
1295 inner.previous_viewport_y = new_viewport_y;
1296 break;
1297 }
1298 drop(inner);
1299 let inner = self.0.inner.borrow();
1300 for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
1301 item.1.as_ref().unwrap().init();
1302 }
1303 }
1304
1305 pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {
1307 let model = self.model();
1308 model.set_row_data(row, data);
1309 }
1310
1311 pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {
1313 self.0.model.set_binding(binding);
1314 }
1315
1316 pub fn visit(
1318 &self,
1319 order: TraversalOrder,
1320 mut visitor: crate::item_tree::ItemVisitorRefMut,
1321 ) -> crate::item_tree::VisitChildrenResult {
1322 let count = self.0.inner.borrow().instances.len() as u32;
1324 for i in 0..count {
1325 let i = if order == TraversalOrder::BackToFront { i } else { count - i - 1 };
1326 let c = self.0.inner.borrow().instances.get(i as usize).and_then(|c| c.1.clone());
1327 if let Some(c) = c {
1328 if c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted()
1329 {
1330 return crate::item_tree::VisitChildrenResult::abort(i, 0);
1331 }
1332 }
1333 }
1334 crate::item_tree::VisitChildrenResult::CONTINUE
1335 }
1336
1337 pub fn len(&self) -> usize {
1339 self.0.inner.borrow().instances.len()
1340 }
1341
1342 pub fn range(&self) -> core::ops::Range<usize> {
1347 let inner = self.0.inner.borrow();
1348 core::ops::Range { start: inner.offset, end: inner.offset + inner.instances.len() }
1349 }
1350
1351 pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {
1354 let inner = self.0.inner.borrow();
1355 inner
1356 .instances
1357 .get(index.checked_sub(inner.offset)?)
1358 .map(|c| c.1.clone().expect("That was updated before!"))
1359 }
1360
1361 pub fn is_empty(&self) -> bool {
1363 self.len() == 0
1364 }
1365
1366 pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {
1368 self.0.inner.borrow().instances.iter().flat_map(|x| x.1.clone()).collect()
1369 }
1370}
1371
1372#[pin_project]
1373pub struct Conditional<C: RepeatedItemTree> {
1374 #[pin]
1375 model: Property<bool>,
1376 instance: RefCell<Option<ItemTreeRc<C>>>,
1377}
1378
1379impl<C: RepeatedItemTree> Default for Conditional<C> {
1380 fn default() -> Self {
1381 Self {
1382 model: Property::new_named(false, "i_slint_core::Conditional::model"),
1383 instance: RefCell::new(None),
1384 }
1385 }
1386}
1387
1388impl<C: RepeatedItemTree + 'static> Conditional<C> {
1389 pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {
1392 let model = self.project_ref().model.get();
1393
1394 if !model {
1395 drop(self.instance.replace(None));
1396 } else if self.instance.borrow().is_none() {
1397 let i = init();
1398 self.instance.replace(Some(i.clone()));
1399 i.init();
1400 }
1401 }
1402
1403 pub fn set_model_binding(&self, binding: impl Fn() -> bool + 'static) {
1405 self.model.set_binding(binding);
1406 }
1407
1408 pub fn visit(
1410 &self,
1411 order: TraversalOrder,
1412 mut visitor: crate::item_tree::ItemVisitorRefMut,
1413 ) -> crate::item_tree::VisitChildrenResult {
1414 let instance = self.instance.borrow().clone();
1416 if let Some(c) = instance {
1417 if c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted() {
1418 return crate::item_tree::VisitChildrenResult::abort(0, 0);
1419 }
1420 }
1421
1422 crate::item_tree::VisitChildrenResult::CONTINUE
1423 }
1424
1425 pub fn len(&self) -> usize {
1427 self.instance.borrow().is_some() as usize
1428 }
1429
1430 pub fn range(&self) -> core::ops::Range<usize> {
1434 0..self.len()
1435 }
1436
1437 pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {
1440 if index != 0 {
1441 return None;
1442 }
1443 self.instance.borrow().clone()
1444 }
1445
1446 pub fn is_empty(&self) -> bool {
1448 self.len() == 0
1449 }
1450
1451 pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {
1453 self.instance.borrow().clone().into_iter().collect()
1454 }
1455}
1456
1457impl From<SharedString> for StandardListViewItem {
1458 fn from(value: SharedString) -> Self {
1459 StandardListViewItem { text: value }
1460 }
1461}
1462
1463impl From<&str> for StandardListViewItem {
1464 fn from(value: &str) -> Self {
1465 StandardListViewItem { text: value.into() }
1466 }
1467}
1468
1469#[cfg(test)]
1470mod tests {
1471 use super::*;
1472 use std::vec;
1473
1474 #[test]
1475 fn test_tracking_model_handle() {
1476 let model: Rc<VecModel<u8>> = Rc::new(Default::default());
1477 let handle = ModelRc::from(model.clone() as Rc<dyn Model<Data = u8>>);
1478 let tracker = Box::pin(crate::properties::PropertyTracker::default());
1479 assert_eq!(
1480 tracker.as_ref().evaluate(|| {
1481 handle.model_tracker().track_row_count_changes();
1482 handle.row_count()
1483 }),
1484 0
1485 );
1486 assert!(!tracker.is_dirty());
1487 model.push(42);
1488 model.push(100);
1489 assert!(tracker.is_dirty());
1490 assert_eq!(
1491 tracker.as_ref().evaluate(|| {
1492 handle.model_tracker().track_row_count_changes();
1493 handle.row_count()
1494 }),
1495 2
1496 );
1497 assert!(!tracker.is_dirty());
1498 model.set_row_data(0, 41);
1499 assert!(!tracker.is_dirty());
1500 model.remove(0);
1501 assert!(tracker.is_dirty());
1502 assert_eq!(
1503 tracker.as_ref().evaluate(|| {
1504 handle.model_tracker().track_row_count_changes();
1505 handle.row_count()
1506 }),
1507 1
1508 );
1509 assert!(!tracker.is_dirty());
1510 model.set_vec(vec![1, 2, 3]);
1511 assert!(tracker.is_dirty());
1512 }
1513
1514 #[test]
1515 fn test_data_tracking() {
1516 let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));
1517 let handle = ModelRc::from(model.clone());
1518 let tracker = Box::pin(crate::properties::PropertyTracker::default());
1519 assert_eq!(
1520 tracker.as_ref().evaluate(|| {
1521 handle.model_tracker().track_row_data_changes(1);
1522 handle.row_data(1).unwrap()
1523 }),
1524 1
1525 );
1526 assert!(!tracker.is_dirty());
1527
1528 model.set_row_data(2, 42);
1529 assert!(!tracker.is_dirty());
1530 model.set_row_data(1, 100);
1531 assert!(tracker.is_dirty());
1532
1533 assert_eq!(
1534 tracker.as_ref().evaluate(|| {
1535 handle.model_tracker().track_row_data_changes(1);
1536 handle.row_data(1).unwrap()
1537 }),
1538 100
1539 );
1540 assert!(!tracker.is_dirty());
1541
1542 model.push(200);
1545 assert!(tracker.is_dirty());
1546
1547 assert_eq!(tracker.as_ref().evaluate(|| { handle.row_data_tracked(1).unwrap() }), 100);
1548 assert!(!tracker.is_dirty());
1549
1550 model.insert(0, 255);
1551 assert!(tracker.is_dirty());
1552
1553 model.set_vec(Vec::new());
1554 assert!(tracker.is_dirty());
1555 }
1556
1557 #[derive(Default)]
1558 struct TestView {
1559 changed_rows: RefCell<Vec<(usize, usize)>>,
1563 added_rows: RefCell<Vec<(usize, usize, usize)>>,
1564 removed_rows: RefCell<Vec<(usize, usize, usize)>>,
1565 reset: RefCell<usize>,
1566 model: RefCell<Option<std::rc::Weak<dyn Model<Data = i32>>>>,
1567 }
1568 impl TestView {
1569 fn clear(&self) {
1570 self.changed_rows.borrow_mut().clear();
1571 self.added_rows.borrow_mut().clear();
1572 self.removed_rows.borrow_mut().clear();
1573 *self.reset.borrow_mut() = 0;
1574 }
1575 fn row_count(&self) -> usize {
1576 self.model
1577 .borrow()
1578 .as_ref()
1579 .and_then(|model| model.upgrade())
1580 .map_or(0, |model| model.row_count())
1581 }
1582 }
1583 impl ModelChangeListener for TestView {
1584 fn row_changed(self: Pin<&Self>, row: usize) {
1585 self.changed_rows.borrow_mut().push((row, self.row_count()));
1586 }
1587
1588 fn row_added(self: Pin<&Self>, index: usize, count: usize) {
1589 self.added_rows.borrow_mut().push((index, count, self.row_count()));
1590 }
1591
1592 fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
1593 self.removed_rows.borrow_mut().push((index, count, self.row_count()));
1594 }
1595 fn reset(self: Pin<&Self>) {
1596 *self.reset.borrow_mut() += 1;
1597 }
1598 }
1599
1600 #[test]
1601 fn test_vecmodel_set_vec() {
1602 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1603
1604 let model = Rc::new(VecModel::from(vec![1i32, 2, 3, 4]));
1605 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1606 *view.model.borrow_mut() =
1607 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1608
1609 model.push(5);
1610 assert!(view.changed_rows.borrow().is_empty());
1611 assert_eq!(&*view.added_rows.borrow(), &[(4, 1, 5)]);
1612 assert!(view.removed_rows.borrow().is_empty());
1613 assert_eq!(*view.reset.borrow(), 0);
1614 view.clear();
1615
1616 model.set_vec(vec![6, 7, 8]);
1617 assert!(view.changed_rows.borrow().is_empty());
1618 assert!(view.added_rows.borrow().is_empty());
1619 assert!(view.removed_rows.borrow().is_empty());
1620 assert_eq!(*view.reset.borrow(), 1);
1621 view.clear();
1622
1623 model.extend_from_slice(&[9, 10, 11]);
1624 assert!(view.changed_rows.borrow().is_empty());
1625 assert_eq!(&*view.added_rows.borrow(), &[(3, 3, 6)]);
1626 assert!(view.removed_rows.borrow().is_empty());
1627 assert_eq!(*view.reset.borrow(), 0);
1628 view.clear();
1629
1630 model.extend([12, 13]);
1631 assert!(view.changed_rows.borrow().is_empty());
1632 assert_eq!(&*view.added_rows.borrow(), &[(6, 2, 8)]);
1633 assert!(view.removed_rows.borrow().is_empty());
1634 assert_eq!(*view.reset.borrow(), 0);
1635 view.clear();
1636
1637 assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 7, 8, 9, 10, 11, 12, 13]);
1638
1639 model.swap(1, 1);
1640 assert!(view.changed_rows.borrow().is_empty());
1641 assert!(view.added_rows.borrow().is_empty());
1642 assert!(view.removed_rows.borrow().is_empty());
1643 assert_eq!(*view.reset.borrow(), 0);
1644 view.clear();
1645
1646 model.swap(1, 2);
1647 assert_eq!(&*view.changed_rows.borrow(), &[(1, 8), (2, 8)]);
1648 assert!(view.added_rows.borrow().is_empty());
1649 assert!(view.removed_rows.borrow().is_empty());
1650 assert_eq!(*view.reset.borrow(), 0);
1651 view.clear();
1652
1653 assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 8, 7, 9, 10, 11, 12, 13]);
1654 }
1655
1656 #[test]
1657 fn test_vecmodel_clear() {
1658 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1659
1660 let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1661 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1662 *view.model.borrow_mut() =
1663 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1664
1665 model.clear();
1666 assert_eq!(*view.reset.borrow(), 1);
1667 assert_eq!(model.row_count(), 0);
1668 }
1669
1670 #[test]
1671 fn test_vecmodel_swap() {
1672 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1673
1674 let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1675 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1676 *view.model.borrow_mut() =
1677 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1678
1679 model.swap(1, 1);
1680 assert!(view.changed_rows.borrow().is_empty());
1681 assert!(view.added_rows.borrow().is_empty());
1682 assert!(view.removed_rows.borrow().is_empty());
1683 assert_eq!(*view.reset.borrow(), 0);
1684 view.clear();
1685
1686 model.swap(1, 2);
1687 assert_eq!(&*view.changed_rows.borrow(), &[(1, 4), (2, 4)]);
1688 assert!(view.added_rows.borrow().is_empty());
1689 assert!(view.removed_rows.borrow().is_empty());
1690 assert_eq!(*view.reset.borrow(), 0);
1691 view.clear();
1692 }
1693
1694 #[test]
1695 fn modeliter_in_bounds() {
1696 struct TestModel {
1697 length: usize,
1698 max_requested_row: Cell<usize>,
1699 notify: ModelNotify,
1700 }
1701
1702 impl Model for TestModel {
1703 type Data = usize;
1704
1705 fn row_count(&self) -> usize {
1706 self.length
1707 }
1708
1709 fn row_data(&self, row: usize) -> Option<usize> {
1710 self.max_requested_row.set(self.max_requested_row.get().max(row));
1711 (row < self.length).then_some(row)
1712 }
1713
1714 fn model_tracker(&self) -> &dyn ModelTracker {
1715 &self.notify
1716 }
1717 }
1718
1719 let model = Rc::new(TestModel {
1720 length: 10,
1721 max_requested_row: Cell::new(0),
1722 notify: Default::default(),
1723 });
1724
1725 assert_eq!(model.iter().max().unwrap(), 9);
1726 assert_eq!(model.max_requested_row.get(), 9);
1727 }
1728
1729 #[test]
1730 fn vecmodel_doesnt_require_default() {
1731 #[derive(Clone)]
1732 struct MyNoDefaultType {
1733 _foo: bool,
1734 }
1735 let model = VecModel::<MyNoDefaultType>::default();
1736 assert_eq!(model.row_count(), 0);
1737 model.push(MyNoDefaultType { _foo: true });
1738 }
1739}