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 eprintln!(
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 {
184 &()
185 }
186}
187
188pub trait ModelExt: Model {
190 fn row_data_tracked(&self, row: usize) -> Option<Self::Data> {
197 self.model_tracker().track_row_data_changes(row);
198 self.row_data(row)
199 }
200
201 fn map<F, U>(self, map_function: F) -> MapModel<Self, F>
204 where
205 Self: Sized + 'static,
206 F: Fn(Self::Data) -> U + 'static,
207 {
208 MapModel::new(self, map_function)
209 }
210
211 fn filter<F>(self, filter_function: F) -> FilterModel<Self, F>
214 where
215 Self: Sized + 'static,
216 F: Fn(&Self::Data) -> bool + 'static,
217 {
218 FilterModel::new(self, filter_function)
219 }
220
221 #[must_use]
224 fn sort(self) -> SortModel<Self, adapters::AscendingSortHelper>
225 where
226 Self: Sized + 'static,
227 Self::Data: core::cmp::Ord,
228 {
229 SortModel::new_ascending(self)
230 }
231
232 fn sort_by<F>(self, sort_function: F) -> SortModel<Self, F>
235 where
236 Self: Sized + 'static,
237 F: FnMut(&Self::Data, &Self::Data) -> core::cmp::Ordering + 'static,
238 {
239 SortModel::new(self, sort_function)
240 }
241
242 fn reverse(self) -> ReverseModel<Self>
245 where
246 Self: Sized + 'static,
247 {
248 ReverseModel::new(self)
249 }
250}
251
252impl<T: Model> ModelExt for T {}
253
254pub struct ModelIterator<'a, T> {
257 model: &'a dyn Model<Data = T>,
258 row: usize,
259}
260
261impl<'a, T> ModelIterator<'a, T> {
262 pub fn new(model: &'a dyn Model<Data = T>) -> Self {
265 Self { model, row: 0 }
266 }
267}
268
269impl<'a, T> Iterator for ModelIterator<'a, T> {
270 type Item = T;
271
272 fn next(&mut self) -> Option<Self::Item> {
273 if self.row >= self.model.row_count() {
274 return None;
275 }
276 let row = self.row;
277 self.row += 1;
278 self.model.row_data(row)
279 }
280
281 fn size_hint(&self) -> (usize, Option<usize>) {
282 let len = self.model.row_count();
283 (len, Some(len))
284 }
285
286 fn nth(&mut self, n: usize) -> Option<Self::Item> {
287 self.row = self.row.checked_add(n)?;
288 self.next()
289 }
290}
291
292impl<'a, T> ExactSizeIterator for ModelIterator<'a, T> {}
293
294impl<M: Model> Model for Rc<M> {
295 type Data = M::Data;
296
297 fn row_count(&self) -> usize {
298 (**self).row_count()
299 }
300
301 fn row_data(&self, row: usize) -> Option<Self::Data> {
302 (**self).row_data(row)
303 }
304
305 fn model_tracker(&self) -> &dyn ModelTracker {
306 (**self).model_tracker()
307 }
308
309 fn as_any(&self) -> &dyn core::any::Any {
310 (**self).as_any()
311 }
312 fn set_row_data(&self, row: usize, data: Self::Data) {
313 (**self).set_row_data(row, data)
314 }
315}
316
317#[derive(Default)]
319pub struct VecModel<T> {
320 array: RefCell<Vec<T>>,
321 notify: ModelNotify,
322}
323
324impl<T: 'static> VecModel<T> {
325 pub fn from_slice(slice: &[T]) -> ModelRc<T>
327 where
328 T: Clone,
329 {
330 ModelRc::new(Self::from(slice.to_vec()))
331 }
332
333 pub fn push(&self, value: T) {
335 self.array.borrow_mut().push(value);
336 self.notify.row_added(self.array.borrow().len() - 1, 1)
337 }
338
339 pub fn insert(&self, index: usize, value: T) {
342 self.array.borrow_mut().insert(index, value);
343 self.notify.row_added(index, 1)
344 }
345
346 pub fn remove(&self, index: usize) -> T {
350 let r = self.array.borrow_mut().remove(index);
351 self.notify.row_removed(index, 1);
352 r
353 }
354
355 pub fn set_vec(&self, new: impl Into<Vec<T>>) {
357 *self.array.borrow_mut() = new.into();
358 self.notify.reset();
359 }
360
361 pub fn extend<I: IntoIterator<Item = T>>(&self, iter: I) {
365 let mut array = self.array.borrow_mut();
366 let old_idx = array.len();
367 array.extend(iter);
368 let count = array.len() - old_idx;
369 drop(array);
370 self.notify.row_added(old_idx, count);
371 }
372
373 pub fn clear(&self) {
377 self.array.borrow_mut().clear();
378 self.notify.reset();
379 }
380
381 pub fn swap(&self, a: usize, b: usize) {
383 if a == b {
384 return;
385 }
386
387 self.array.borrow_mut().swap(a, b);
388 self.notify.row_changed(a);
389 self.notify.row_changed(b);
390 }
391}
392
393impl<T: Clone + 'static> VecModel<T> {
394 pub fn extend_from_slice(&self, src: &[T]) {
398 let mut array = self.array.borrow_mut();
399 let old_idx = array.len();
400
401 array.extend_from_slice(src);
402 drop(array);
403 self.notify.row_added(old_idx, src.len());
404 }
405}
406
407impl<T> From<Vec<T>> for VecModel<T> {
408 fn from(array: Vec<T>) -> Self {
409 VecModel { array: RefCell::new(array), notify: Default::default() }
410 }
411}
412
413impl<T> FromIterator<T> for VecModel<T> {
414 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
415 VecModel::from(Vec::from_iter(iter))
416 }
417}
418
419impl<T: Clone + 'static> Model for VecModel<T> {
420 type Data = T;
421
422 fn row_count(&self) -> usize {
423 self.array.borrow().len()
424 }
425
426 fn row_data(&self, row: usize) -> Option<Self::Data> {
427 self.array.borrow().get(row).cloned()
428 }
429
430 fn set_row_data(&self, row: usize, data: Self::Data) {
431 if row < self.row_count() {
432 self.array.borrow_mut()[row] = data;
433 self.notify.row_changed(row);
434 }
435 }
436
437 fn model_tracker(&self) -> &dyn ModelTracker {
438 &self.notify
439 }
440
441 fn as_any(&self) -> &dyn core::any::Any {
442 self
443 }
444}
445
446#[derive(Default)]
448pub struct SharedVectorModel<T> {
449 array: RefCell<SharedVector<T>>,
450 notify: ModelNotify,
451}
452
453impl<T: Clone + 'static> SharedVectorModel<T> {
454 pub fn push(&self, value: T) {
456 self.array.borrow_mut().push(value);
457 self.notify.row_added(self.array.borrow().len() - 1, 1)
458 }
459}
460
461impl<T> SharedVectorModel<T> {
462 pub fn shared_vector(&self) -> SharedVector<T> {
464 self.array.borrow_mut().clone()
465 }
466}
467
468impl<T> From<SharedVector<T>> for SharedVectorModel<T> {
469 fn from(array: SharedVector<T>) -> Self {
470 SharedVectorModel { array: RefCell::new(array), notify: Default::default() }
471 }
472}
473
474impl<T: Clone + 'static> Model for SharedVectorModel<T> {
475 type Data = T;
476
477 fn row_count(&self) -> usize {
478 self.array.borrow().len()
479 }
480
481 fn row_data(&self, row: usize) -> Option<Self::Data> {
482 self.array.borrow().get(row).cloned()
483 }
484
485 fn set_row_data(&self, row: usize, data: Self::Data) {
486 self.array.borrow_mut().make_mut_slice()[row] = data;
487 self.notify.row_changed(row);
488 }
489
490 fn model_tracker(&self) -> &dyn ModelTracker {
491 &self.notify
492 }
493
494 fn as_any(&self) -> &dyn core::any::Any {
495 self
496 }
497}
498
499impl Model for usize {
500 type Data = i32;
501
502 fn row_count(&self) -> usize {
503 *self
504 }
505
506 fn row_data(&self, row: usize) -> Option<Self::Data> {
507 (row < self.row_count()).then_some(row as i32)
508 }
509
510 fn as_any(&self) -> &dyn core::any::Any {
511 self
512 }
513
514 fn model_tracker(&self) -> &dyn ModelTracker {
515 &()
516 }
517}
518
519impl Model for bool {
520 type Data = ();
521
522 fn row_count(&self) -> usize {
523 if *self {
524 1
525 } else {
526 0
527 }
528 }
529
530 fn row_data(&self, row: usize) -> Option<Self::Data> {
531 (row < self.row_count()).then_some(())
532 }
533
534 fn as_any(&self) -> &dyn core::any::Any {
535 self
536 }
537
538 fn model_tracker(&self) -> &dyn ModelTracker {
539 &()
540 }
541}
542
543pub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);
617
618impl<T> core::fmt::Debug for ModelRc<T> {
619 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
620 write!(f, "ModelRc(dyn Model)")
621 }
622}
623
624impl<T> Clone for ModelRc<T> {
625 fn clone(&self) -> Self {
626 Self(self.0.clone())
627 }
628}
629
630impl<T> Default for ModelRc<T> {
631 fn default() -> Self {
633 Self(None)
634 }
635}
636
637impl<T> core::cmp::PartialEq for ModelRc<T> {
638 fn eq(&self, other: &Self) -> bool {
639 match (&self.0, &other.0) {
640 (None, None) => true,
641 (Some(a), Some(b)) => core::ptr::eq(
642 (&**a) as *const dyn Model<Data = T> as *const u8,
643 (&**b) as *const dyn Model<Data = T> as *const u8,
644 ),
645 _ => false,
646 }
647 }
648}
649
650impl<T> ModelRc<T> {
651 pub fn new(model: impl Model<Data = T> + 'static) -> Self {
652 Self(Some(Rc::new(model)))
653 }
654}
655
656impl<T, M: Model<Data = T> + 'static> From<Rc<M>> for ModelRc<T> {
657 fn from(model: Rc<M>) -> Self {
658 Self(Some(model))
659 }
660}
661
662impl<T> From<Rc<dyn Model<Data = T> + 'static>> for ModelRc<T> {
663 fn from(model: Rc<dyn Model<Data = T> + 'static>) -> Self {
664 Self(Some(model))
665 }
666}
667
668impl<T: Clone + 'static> From<&[T]> for ModelRc<T> {
669 fn from(slice: &[T]) -> Self {
670 VecModel::from_slice(slice)
671 }
672}
673
674impl<T: Clone + 'static, const N: usize> From<[T; N]> for ModelRc<T> {
675 fn from(array: [T; N]) -> Self {
676 VecModel::from_slice(&array)
677 }
678}
679
680impl<T> TryInto<Rc<dyn Model<Data = T>>> for ModelRc<T> {
681 type Error = ();
682
683 fn try_into(self) -> Result<Rc<dyn Model<Data = T>>, Self::Error> {
684 self.0.ok_or(())
685 }
686}
687
688impl<T> Model for ModelRc<T> {
689 type Data = T;
690
691 fn row_count(&self) -> usize {
692 self.0.as_ref().map_or(0, |model| model.row_count())
693 }
694
695 fn row_data(&self, row: usize) -> Option<Self::Data> {
696 self.0.as_ref().and_then(|model| model.row_data(row))
697 }
698
699 fn set_row_data(&self, row: usize, data: Self::Data) {
700 if let Some(model) = self.0.as_ref() {
701 model.set_row_data(row, data);
702 }
703 }
704
705 fn model_tracker(&self) -> &dyn ModelTracker {
706 self.0.as_ref().map_or(&(), |model| model.model_tracker())
707 }
708
709 fn as_any(&self) -> &dyn core::any::Any {
710 self.0.as_ref().map_or(&(), |model| model.as_any())
711 }
712}
713
714pub trait RepeatedItemTree:
716 crate::item_tree::ItemTree + vtable::HasStaticVTable<ItemTreeVTable> + 'static
717{
718 type Data: 'static;
720
721 fn update(&self, index: usize, data: Self::Data);
723
724 fn init(&self) {}
727
728 fn listview_layout(
733 self: Pin<&Self>,
734 _offset_y: &mut LogicalLength,
735 _viewport_width: Pin<&Property<LogicalLength>>,
736 ) {
737 }
738
739 fn box_layout_data(
741 self: Pin<&Self>,
742 _orientation: Orientation,
743 ) -> crate::layout::BoxLayoutCellData {
744 crate::layout::BoxLayoutCellData::default()
745 }
746}
747
748#[derive(Clone, Copy, PartialEq, Debug)]
749enum RepeatedInstanceState {
750 Clean,
752 Dirty,
754}
755struct RepeaterInner<C: RepeatedItemTree> {
756 instances: Vec<(RepeatedInstanceState, Option<ItemTreeRc<C>>)>,
757
758 offset: usize,
761 cached_item_height: LogicalLength,
763 previous_viewport_y: LogicalLength,
765 anchor_y: LogicalLength,
768}
769
770impl<C: RepeatedItemTree> Default for RepeaterInner<C> {
771 fn default() -> Self {
772 RepeaterInner {
773 instances: Default::default(),
774 offset: 0,
775 cached_item_height: Default::default(),
776 previous_viewport_y: Default::default(),
777 anchor_y: Default::default(),
778 }
779 }
780}
781
782#[pin_project]
785pub struct RepeaterTracker<T: RepeatedItemTree> {
786 inner: RefCell<RepeaterInner<T>>,
787 #[pin]
788 model: Property<ModelRc<T::Data>>,
789 #[pin]
790 is_dirty: Property<bool>,
791 #[pin]
793 listview_geometry_tracker: crate::properties::PropertyTracker,
794}
795
796impl<T: RepeatedItemTree> ModelChangeListener for RepeaterTracker<T> {
797 fn row_changed(self: Pin<&Self>, row: usize) {
799 let mut inner = self.inner.borrow_mut();
800 let inner = &mut *inner;
801 if let Some(c) = inner.instances.get_mut(row.wrapping_sub(inner.offset)) {
802 if !self.model.is_dirty() {
803 if let Some(comp) = c.1.as_ref() {
804 let model = self.project_ref().model.get_untracked();
805 if let Some(data) = model.row_data(row) {
806 comp.update(row, data);
807 }
808 c.0 = RepeatedInstanceState::Clean;
809 }
810 } else {
811 c.0 = RepeatedInstanceState::Dirty;
812 }
813 }
814 }
815 fn row_added(self: Pin<&Self>, mut index: usize, mut count: usize) {
817 let mut inner = self.inner.borrow_mut();
818 if index < inner.offset {
819 if index + count < inner.offset {
820 return;
821 }
822 count -= inner.offset - index;
823 index = 0;
824 } else {
825 index -= inner.offset;
826 }
827 if count == 0 || index > inner.instances.len() {
828 return;
829 }
830 self.is_dirty.set(true);
831 inner.instances.splice(
832 index..index,
833 core::iter::repeat((RepeatedInstanceState::Dirty, None)).take(count),
834 );
835 for c in inner.instances[index + count..].iter_mut() {
836 c.0 = RepeatedInstanceState::Dirty;
838 }
839 }
840 fn row_removed(self: Pin<&Self>, mut index: usize, mut count: usize) {
842 let mut inner = self.inner.borrow_mut();
843 if index < inner.offset {
844 if index + count < inner.offset {
845 return;
846 }
847 count -= inner.offset - index;
848 index = 0;
849 } else {
850 index -= inner.offset;
851 }
852 if count == 0 || index >= inner.instances.len() {
853 return;
854 }
855 if (index + count) > inner.instances.len() {
856 count = inner.instances.len() - index;
857 }
858 self.is_dirty.set(true);
859 inner.instances.drain(index..(index + count));
860 for c in inner.instances[index..].iter_mut() {
861 c.0 = RepeatedInstanceState::Dirty;
863 }
864 }
865
866 fn reset(self: Pin<&Self>) {
867 self.is_dirty.set(true);
868 self.inner.borrow_mut().instances.clear();
869 }
870}
871
872impl<C: RepeatedItemTree> Default for RepeaterTracker<C> {
873 fn default() -> Self {
874 Self {
875 inner: Default::default(),
876 model: Property::new_named(ModelRc::default(), "i_slint_core::Repeater::model"),
877 is_dirty: Property::new_named(false, "i_slint_core::Repeater::is_dirty"),
878 listview_geometry_tracker: Default::default(),
879 }
880 }
881}
882
883#[pin_project]
884pub struct Repeater<C: RepeatedItemTree>(#[pin] ModelChangeListenerContainer<RepeaterTracker<C>>);
885
886impl<C: RepeatedItemTree> Default for Repeater<C> {
887 fn default() -> Self {
888 Self(Default::default())
889 }
890}
891
892impl<C: RepeatedItemTree + 'static> Repeater<C> {
893 fn data(self: Pin<&Self>) -> Pin<&RepeaterTracker<C>> {
894 self.project_ref().0.get()
895 }
896
897 fn model(self: Pin<&Self>) -> ModelRc<C::Data> {
898 let model = self.data().project_ref().model;
900
901 if model.is_dirty() {
902 *self.data().inner.borrow_mut() = RepeaterInner::default();
903 self.data().is_dirty.set(true);
904 let m = model.get();
905 let peer = self.project_ref().0.model_peer();
906 m.model_tracker().attach_peer(peer);
907 m
908 } else {
909 model.get()
910 }
911 }
912
913 pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ItemTreeRc<C>) {
916 let model = self.model();
917 if self.data().project_ref().is_dirty.get() {
918 self.ensure_updated_impl(init, &model, model.row_count());
919 }
920 }
921
922 fn ensure_updated_impl(
924 self: Pin<&Self>,
925 init: impl Fn() -> ItemTreeRc<C>,
926 model: &ModelRc<C::Data>,
927 count: usize,
928 ) -> bool {
929 let mut indices_to_init = Vec::new();
930 let mut inner = self.0.inner.borrow_mut();
931 inner.instances.resize_with(count, || (RepeatedInstanceState::Dirty, None));
932 let offset = inner.offset;
933 let mut any_items_created = false;
934 for (i, c) in inner.instances.iter_mut().enumerate() {
935 if c.0 == RepeatedInstanceState::Dirty {
936 if c.1.is_none() {
937 any_items_created = true;
938 c.1 = Some(init());
939 indices_to_init.push(i);
940 };
941 if let Some(data) = model.row_data(i + offset) {
942 c.1.as_ref().unwrap().update(i + offset, data);
943 }
944 c.0 = RepeatedInstanceState::Clean;
945 }
946 }
947 self.data().is_dirty.set(false);
948
949 drop(inner);
950 let inner = self.0.inner.borrow();
951 for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
952 item.1.as_ref().unwrap().init();
953 }
954
955 any_items_created
956 }
957
958 pub fn ensure_updated_listview(
960 self: Pin<&Self>,
961 init: impl Fn() -> ItemTreeRc<C>,
962 viewport_width: Pin<&Property<LogicalLength>>,
963 viewport_height: Pin<&Property<LogicalLength>>,
964 viewport_y: Pin<&Property<LogicalLength>>,
965 listview_width: LogicalLength,
966 listview_height: Pin<&Property<LogicalLength>>,
967 ) {
968 self.data().project_ref().is_dirty.get();
970 self.data().project_ref().is_dirty.set(false);
971
972 viewport_width.set(listview_width);
973 let model = self.model();
974 let row_count = model.row_count();
975 if row_count == 0 {
976 self.0.inner.borrow_mut().instances.clear();
977 viewport_height.set(LogicalLength::zero());
978 viewport_y.set(LogicalLength::zero());
979
980 return;
981 }
982
983 let listview_height = listview_height.get();
984 let mut vp_y = viewport_y.get().min(LogicalLength::zero());
985
986 let cached_item_height = self.data().inner.borrow_mut().cached_item_height;
988 let element_height = if cached_item_height > LogicalLength::zero() {
989 cached_item_height
990 } else {
991 let total_height = Cell::new(LogicalLength::zero());
992 let count = Cell::new(0);
993 let get_height_visitor = |x: &ItemTreeRc<C>| {
994 let height = x.as_pin_ref().item_geometry(0).height_length();
995 count.set(count.get() + 1);
996 total_height.set(total_height.get() + height);
997 };
998 for c in self.data().inner.borrow().instances.iter() {
999 if let Some(x) = c.1.as_ref() {
1000 get_height_visitor(x);
1001 }
1002 }
1003
1004 if count.get() > 0 {
1005 total_height.get() / (count.get() as Coord)
1006 } else {
1007 {
1009 let mut inner = self.0.inner.borrow_mut();
1010 inner.offset = inner.offset.min(row_count - 1);
1011 }
1012
1013 self.ensure_updated_impl(&init, &model, 1);
1014 if let Some(c) = self.data().inner.borrow().instances.first() {
1015 if let Some(x) = c.1.as_ref() {
1016 get_height_visitor(x);
1017 }
1018 } else {
1019 panic!("Could not determine size of items");
1020 }
1021 total_height.get()
1022 }
1023 };
1024
1025 let data = self.data();
1026 let mut inner = data.inner.borrow_mut();
1027 if inner.offset >= row_count {
1028 inner.offset = row_count - 1;
1029 }
1030
1031 let one_and_a_half_screen = listview_height * 3 as Coord / 2 as Coord;
1032 let first_item_y = inner.anchor_y;
1033 let last_item_bottom = first_item_y + element_height * inner.instances.len() as Coord;
1034
1035 let mut indices_to_init = Vec::new();
1036
1037 let (mut new_offset, mut new_offset_y) = if first_item_y > -vp_y + one_and_a_half_screen
1038 || last_item_bottom + element_height < -vp_y
1039 {
1040 inner.instances.clear();
1042 inner.offset = ((-vp_y / element_height).get().floor() as usize).min(row_count - 1);
1043 (inner.offset, -vp_y)
1044 } else if vp_y < inner.previous_viewport_y {
1045 let mut it_y = first_item_y;
1047 let mut new_offset = inner.offset;
1048 debug_assert!(it_y <= -vp_y); for (i, c) in inner.instances.iter_mut().enumerate() {
1050 if c.0 == RepeatedInstanceState::Dirty {
1051 if c.1.is_none() {
1052 c.1 = Some(init());
1053 indices_to_init.push(i);
1054 }
1055 if let Some(data) = model.row_data(new_offset) {
1056 c.1.as_ref().unwrap().update(new_offset, data);
1057 }
1058 c.0 = RepeatedInstanceState::Clean;
1059 }
1060 let h = c.1.as_ref().unwrap().as_pin_ref().item_geometry(0).height_length();
1061 if it_y + h >= -vp_y || new_offset + 1 >= row_count {
1062 break;
1063 }
1064 it_y += h;
1065 new_offset += 1;
1066 }
1067 (new_offset, it_y)
1068 } else {
1069 (inner.offset, first_item_y)
1071 };
1072
1073 loop {
1074 while new_offset > inner.offset && new_offset_y > -vp_y {
1078 new_offset -= 1;
1079 new_offset_y -= inner.instances[new_offset - inner.offset]
1080 .1
1081 .as_ref()
1082 .unwrap()
1083 .as_pin_ref()
1084 .item_geometry(0)
1085 .height_length();
1086 }
1087 let mut new_instances = Vec::new();
1089 while new_offset > 0 && new_offset_y > -vp_y {
1090 new_offset -= 1;
1091 let new_instance = init();
1092 if let Some(data) = model.row_data(new_offset) {
1093 new_instance.update(new_offset, data);
1094 }
1095 new_offset_y -= new_instance.as_pin_ref().item_geometry(0).height_length();
1096 new_instances.push(new_instance);
1097 }
1098 if !new_instances.is_empty() {
1099 for x in &mut indices_to_init {
1100 *x += new_instances.len();
1101 }
1102 indices_to_init.extend(0..new_instances.len());
1103 inner.instances.splice(
1104 0..0,
1105 new_instances
1106 .into_iter()
1107 .rev()
1108 .map(|c| (RepeatedInstanceState::Clean, Some(c))),
1109 );
1110 inner.offset = new_offset;
1111 }
1112 assert!(
1113 new_offset >= inner.offset && new_offset <= inner.offset + inner.instances.len()
1114 );
1115
1116 let mut y = new_offset_y;
1118 let mut idx = new_offset;
1119 let instances_begin = new_offset - inner.offset;
1120 for c in &mut inner.instances[instances_begin..] {
1121 if idx >= row_count {
1122 break;
1123 }
1124 if c.0 == RepeatedInstanceState::Dirty {
1125 if c.1.is_none() {
1126 c.1 = Some(init());
1127 indices_to_init.push(instances_begin + idx - new_offset)
1128 }
1129 if let Some(data) = model.row_data(idx) {
1130 c.1.as_ref().unwrap().update(idx, data);
1131 }
1132 c.0 = RepeatedInstanceState::Clean;
1133 }
1134 if let Some(x) = c.1.as_ref() {
1135 x.as_pin_ref().listview_layout(&mut y, viewport_width);
1136 }
1137 idx += 1;
1138 if y >= -vp_y + listview_height {
1139 break;
1140 }
1141 }
1142
1143 while y < -vp_y + listview_height && idx < row_count {
1145 let new_instance = init();
1146 if let Some(data) = model.row_data(idx) {
1147 new_instance.update(idx, data);
1148 }
1149 new_instance.as_pin_ref().listview_layout(&mut y, viewport_width);
1150 indices_to_init.push(inner.instances.len());
1151 inner.instances.push((RepeatedInstanceState::Clean, Some(new_instance)));
1152 idx += 1;
1153 }
1154 if y < -vp_y + listview_height && vp_y < LogicalLength::zero() {
1155 assert!(idx >= row_count);
1156 vp_y = listview_height - y;
1158 continue;
1159 }
1160
1161 if new_offset != inner.offset {
1163 let instances_begin = new_offset - inner.offset;
1164 inner.instances.splice(0..instances_begin, core::iter::empty());
1165 indices_to_init.retain_mut(|idx| {
1166 if *idx < instances_begin {
1167 false
1168 } else {
1169 *idx -= instances_begin;
1170 true
1171 }
1172 });
1173 inner.offset = new_offset;
1174 }
1175 if inner.instances.len() != idx - new_offset {
1176 inner.instances.splice(idx - new_offset.., core::iter::empty());
1177 indices_to_init.retain(|x| *x < idx - new_offset);
1178 }
1179
1180 if inner.instances.is_empty() {
1181 break;
1182 }
1183
1184 inner.cached_item_height = (y - new_offset_y) / inner.instances.len() as Coord;
1186 inner.anchor_y = inner.cached_item_height * inner.offset as Coord;
1187 viewport_height.set(inner.cached_item_height * row_count as Coord);
1188 let new_viewport_y = -inner.anchor_y + vp_y + new_offset_y;
1189 viewport_y.set(new_viewport_y);
1190 inner.previous_viewport_y = new_viewport_y;
1191 break;
1192 }
1193 drop(inner);
1194 let inner = self.0.inner.borrow();
1195 for item in indices_to_init.into_iter().filter_map(|index| inner.instances.get(index)) {
1196 item.1.as_ref().unwrap().init();
1197 }
1198 }
1199
1200 pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {
1202 let model = self.model();
1203 model.set_row_data(row, data);
1204 }
1205
1206 pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {
1208 self.0.model.set_binding(binding);
1209 }
1210
1211 pub fn visit(
1213 &self,
1214 order: TraversalOrder,
1215 mut visitor: crate::item_tree::ItemVisitorRefMut,
1216 ) -> crate::item_tree::VisitChildrenResult {
1217 let count = self.0.inner.borrow().instances.len() as u32;
1219 for i in 0..count {
1220 let i = if order == TraversalOrder::BackToFront { i } else { count - i - 1 };
1221 let c = self.0.inner.borrow().instances.get(i as usize).and_then(|c| c.1.clone());
1222 if let Some(c) = c {
1223 if c.as_pin_ref().visit_children_item(-1, order, visitor.borrow_mut()).has_aborted()
1224 {
1225 return crate::item_tree::VisitChildrenResult::abort(i, 0);
1226 }
1227 }
1228 }
1229 crate::item_tree::VisitChildrenResult::CONTINUE
1230 }
1231
1232 pub fn len(&self) -> usize {
1234 self.0.inner.borrow().instances.len()
1235 }
1236
1237 pub fn range(&self) -> core::ops::Range<usize> {
1242 let inner = self.0.inner.borrow();
1243 core::ops::Range { start: inner.offset, end: inner.offset + inner.instances.len() }
1244 }
1245
1246 pub fn instance_at(&self, index: usize) -> Option<ItemTreeRc<C>> {
1249 let inner = self.0.inner.borrow();
1250 inner
1251 .instances
1252 .get(index - inner.offset)
1253 .map(|c| c.1.clone().expect("That was updated before!"))
1254 }
1255
1256 pub fn is_empty(&self) -> bool {
1258 self.len() == 0
1259 }
1260
1261 pub fn instances_vec(&self) -> Vec<ItemTreeRc<C>> {
1263 self.0.inner.borrow().instances.iter().flat_map(|x| x.1.clone()).collect()
1264 }
1265}
1266
1267impl From<SharedString> for StandardListViewItem {
1268 fn from(value: SharedString) -> Self {
1269 StandardListViewItem { text: value }
1270 }
1271}
1272
1273impl From<&str> for StandardListViewItem {
1274 fn from(value: &str) -> Self {
1275 StandardListViewItem { text: value.into() }
1276 }
1277}
1278
1279#[cfg(test)]
1280mod tests {
1281 use super::*;
1282
1283 #[test]
1284 fn test_tracking_model_handle() {
1285 let model: Rc<VecModel<u8>> = Rc::new(Default::default());
1286 let handle = ModelRc::from(model.clone() as Rc<dyn Model<Data = u8>>);
1287 let tracker = Box::pin(crate::properties::PropertyTracker::default());
1288 assert_eq!(
1289 tracker.as_ref().evaluate(|| {
1290 handle.model_tracker().track_row_count_changes();
1291 handle.row_count()
1292 }),
1293 0
1294 );
1295 assert!(!tracker.is_dirty());
1296 model.push(42);
1297 model.push(100);
1298 assert!(tracker.is_dirty());
1299 assert_eq!(
1300 tracker.as_ref().evaluate(|| {
1301 handle.model_tracker().track_row_count_changes();
1302 handle.row_count()
1303 }),
1304 2
1305 );
1306 assert!(!tracker.is_dirty());
1307 model.set_row_data(0, 41);
1308 assert!(!tracker.is_dirty());
1309 model.remove(0);
1310 assert!(tracker.is_dirty());
1311 assert_eq!(
1312 tracker.as_ref().evaluate(|| {
1313 handle.model_tracker().track_row_count_changes();
1314 handle.row_count()
1315 }),
1316 1
1317 );
1318 assert!(!tracker.is_dirty());
1319 model.set_vec(vec![1, 2, 3]);
1320 assert!(tracker.is_dirty());
1321 }
1322
1323 #[test]
1324 fn test_data_tracking() {
1325 let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));
1326 let handle = ModelRc::from(model.clone());
1327 let tracker = Box::pin(crate::properties::PropertyTracker::default());
1328 assert_eq!(
1329 tracker.as_ref().evaluate(|| {
1330 handle.model_tracker().track_row_data_changes(1);
1331 handle.row_data(1).unwrap()
1332 }),
1333 1
1334 );
1335 assert!(!tracker.is_dirty());
1336
1337 model.set_row_data(2, 42);
1338 assert!(!tracker.is_dirty());
1339 model.set_row_data(1, 100);
1340 assert!(tracker.is_dirty());
1341
1342 assert_eq!(
1343 tracker.as_ref().evaluate(|| {
1344 handle.model_tracker().track_row_data_changes(1);
1345 handle.row_data(1).unwrap()
1346 }),
1347 100
1348 );
1349 assert!(!tracker.is_dirty());
1350
1351 model.push(200);
1354 assert!(tracker.is_dirty());
1355
1356 assert_eq!(tracker.as_ref().evaluate(|| { handle.row_data_tracked(1).unwrap() }), 100);
1357 assert!(!tracker.is_dirty());
1358
1359 model.insert(0, 255);
1360 assert!(tracker.is_dirty());
1361
1362 model.set_vec(vec![]);
1363 assert!(tracker.is_dirty());
1364 }
1365
1366 #[derive(Default)]
1367 struct TestView {
1368 changed_rows: RefCell<Vec<(usize, usize)>>,
1372 added_rows: RefCell<Vec<(usize, usize, usize)>>,
1373 removed_rows: RefCell<Vec<(usize, usize, usize)>>,
1374 reset: RefCell<usize>,
1375 model: RefCell<Option<std::rc::Weak<dyn Model<Data = i32>>>>,
1376 }
1377 impl TestView {
1378 fn clear(&self) {
1379 self.changed_rows.borrow_mut().clear();
1380 self.added_rows.borrow_mut().clear();
1381 self.removed_rows.borrow_mut().clear();
1382 *self.reset.borrow_mut() = 0;
1383 }
1384 fn row_count(&self) -> usize {
1385 self.model
1386 .borrow()
1387 .as_ref()
1388 .and_then(|model| model.upgrade())
1389 .map_or(0, |model| model.row_count())
1390 }
1391 }
1392 impl ModelChangeListener for TestView {
1393 fn row_changed(self: Pin<&Self>, row: usize) {
1394 self.changed_rows.borrow_mut().push((row, self.row_count()));
1395 }
1396
1397 fn row_added(self: Pin<&Self>, index: usize, count: usize) {
1398 self.added_rows.borrow_mut().push((index, count, self.row_count()));
1399 }
1400
1401 fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
1402 self.removed_rows.borrow_mut().push((index, count, self.row_count()));
1403 }
1404 fn reset(self: Pin<&Self>) {
1405 *self.reset.borrow_mut() += 1;
1406 }
1407 }
1408
1409 #[test]
1410 fn test_vecmodel_set_vec() {
1411 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1412
1413 let model = Rc::new(VecModel::from(vec![1i32, 2, 3, 4]));
1414 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1415 *view.model.borrow_mut() =
1416 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1417
1418 model.push(5);
1419 assert!(view.changed_rows.borrow().is_empty());
1420 assert_eq!(&*view.added_rows.borrow(), &[(4, 1, 5)]);
1421 assert!(view.removed_rows.borrow().is_empty());
1422 assert_eq!(*view.reset.borrow(), 0);
1423 view.clear();
1424
1425 model.set_vec(vec![6, 7, 8]);
1426 assert!(view.changed_rows.borrow().is_empty());
1427 assert!(view.added_rows.borrow().is_empty());
1428 assert!(view.removed_rows.borrow().is_empty());
1429 assert_eq!(*view.reset.borrow(), 1);
1430 view.clear();
1431
1432 model.extend_from_slice(&[9, 10, 11]);
1433 assert!(view.changed_rows.borrow().is_empty());
1434 assert_eq!(&*view.added_rows.borrow(), &[(3, 3, 6)]);
1435 assert!(view.removed_rows.borrow().is_empty());
1436 assert_eq!(*view.reset.borrow(), 0);
1437 view.clear();
1438
1439 model.extend([12, 13]);
1440 assert!(view.changed_rows.borrow().is_empty());
1441 assert_eq!(&*view.added_rows.borrow(), &[(6, 2, 8)]);
1442 assert!(view.removed_rows.borrow().is_empty());
1443 assert_eq!(*view.reset.borrow(), 0);
1444 view.clear();
1445
1446 assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 7, 8, 9, 10, 11, 12, 13]);
1447
1448 model.swap(1, 1);
1449 assert!(view.changed_rows.borrow().is_empty());
1450 assert!(view.added_rows.borrow().is_empty());
1451 assert!(view.removed_rows.borrow().is_empty());
1452 assert_eq!(*view.reset.borrow(), 0);
1453 view.clear();
1454
1455 model.swap(1, 2);
1456 assert_eq!(&*view.changed_rows.borrow(), &[(1, 8), (2, 8)]);
1457 assert!(view.added_rows.borrow().is_empty());
1458 assert!(view.removed_rows.borrow().is_empty());
1459 assert_eq!(*view.reset.borrow(), 0);
1460 view.clear();
1461
1462 assert_eq!(model.iter().collect::<Vec<_>>(), vec![6, 8, 7, 9, 10, 11, 12, 13]);
1463 }
1464
1465 #[test]
1466 fn test_vecmodel_clear() {
1467 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1468
1469 let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1470 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1471 *view.model.borrow_mut() =
1472 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1473
1474 model.clear();
1475 assert_eq!(*view.reset.borrow(), 1);
1476 assert_eq!(model.row_count(), 0);
1477 }
1478
1479 #[test]
1480 fn test_vecmodel_swap() {
1481 let view = Box::pin(ModelChangeListenerContainer::<TestView>::default());
1482
1483 let model = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
1484 model.model_tracker().attach_peer(Pin::as_ref(&view).model_peer());
1485 *view.model.borrow_mut() =
1486 Some(std::rc::Rc::downgrade(&(model.clone() as Rc<dyn Model<Data = i32>>)));
1487
1488 model.swap(1, 1);
1489 assert!(view.changed_rows.borrow().is_empty());
1490 assert!(view.added_rows.borrow().is_empty());
1491 assert!(view.removed_rows.borrow().is_empty());
1492 assert_eq!(*view.reset.borrow(), 0);
1493 view.clear();
1494
1495 model.swap(1, 2);
1496 assert_eq!(&*view.changed_rows.borrow(), &[(1, 4), (2, 4)]);
1497 assert!(view.added_rows.borrow().is_empty());
1498 assert!(view.removed_rows.borrow().is_empty());
1499 assert_eq!(*view.reset.borrow(), 0);
1500 view.clear();
1501 }
1502
1503 #[test]
1504 fn modeliter_in_bounds() {
1505 struct TestModel {
1506 length: usize,
1507 max_requested_row: Cell<usize>,
1508 notify: ModelNotify,
1509 }
1510
1511 impl Model for TestModel {
1512 type Data = usize;
1513
1514 fn row_count(&self) -> usize {
1515 self.length
1516 }
1517
1518 fn row_data(&self, row: usize) -> Option<usize> {
1519 self.max_requested_row.set(self.max_requested_row.get().max(row));
1520 (row < self.length).then(|| row)
1521 }
1522
1523 fn model_tracker(&self) -> &dyn ModelTracker {
1524 &self.notify
1525 }
1526 }
1527
1528 let model = Rc::new(TestModel {
1529 length: 10,
1530 max_requested_row: Cell::new(0),
1531 notify: Default::default(),
1532 });
1533
1534 assert_eq!(model.iter().max().unwrap(), 9);
1535 assert_eq!(model.max_requested_row.get(), 9);
1536 }
1537}