Skip to main content

i_slint_core/
model.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore vecmodel
5
6//! Model and Repeater
7
8use 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
32/// This trait defines the interface that users of a model can use to track changes
33/// to a model. It is supplied via [`Model::model_tracker`] and implementation usually
34/// return a reference to its field of [`ModelNotify`].
35pub trait ModelTracker {
36    /// Attach one peer. The peer will be notified when the model changes
37    fn attach_peer(&self, peer: ModelPeer);
38    /// Register the model as a dependency to the current binding being evaluated, so
39    /// that it will be notified when the model changes its size.
40    fn track_row_count_changes(&self);
41    /// Register a row as a dependency to the current binding being evaluated, so that
42    /// it will be notified when the value of that row changes.
43    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
53/// A Model is providing Data for the repeated elements with `for` in the `.slint` language
54///
55/// If the model can be changed, the type implementing the Model trait should hold
56/// a [`ModelNotify`], and is responsible to call functions on it to let the UI know that
57/// something has changed.
58///
59/// Properties of type array will be mapped to a [`ModelRc<T>`], which wraps a `Rc<Model<Data = T>>.`
60/// The [`ModelRc`] documentation has examples on how to set models to array properties.
61///
62/// It is more efficient to operate on the model and send changes through the `ModelNotify` rather than
63/// resetting the property with a different model.
64///
65/// ## Example
66///
67/// As an example, let's see the implementation of [`VecModel`].
68///
69/// ```
70/// # use i_slint_core::model::{Model, ModelNotify, ModelPeer, ModelTracker};
71/// pub struct VecModel<T> {
72///     // the backing data, stored in a `RefCell` as this model can be modified
73///     array: std::cell::RefCell<Vec<T>>,
74///     // the ModelNotify will allow to notify the UI that the model changes
75///     notify: ModelNotify,
76/// }
77///
78/// impl<T: Clone + 'static> Model for VecModel<T> {
79///     type Data = T;
80///
81///     fn row_count(&self) -> usize {
82///         self.array.borrow().len()
83///     }
84///
85///     fn row_data(&self, row: usize) -> Option<Self::Data> {
86///         self.array.borrow().get(row).cloned()
87///     }
88///
89///     fn set_row_data(&self, row: usize, data: Self::Data) {
90///         self.array.borrow_mut()[row] = data;
91///         // don't forget to call row_changed
92///         self.notify.row_changed(row);
93///     }
94///
95///     fn model_tracker(&self) -> &dyn ModelTracker {
96///         &self.notify
97///     }
98///
99///     fn as_any(&self) -> &dyn core::any::Any {
100///         // a typical implementation just return `self`
101///         self
102///     }
103/// }
104///
105/// // when modifying the model, we call the corresponding function in
106/// // the ModelNotify
107/// impl<T> VecModel<T> {
108///     /// Add a row at the end of the model
109///     pub fn push(&self, value: T) {
110///         self.array.borrow_mut().push(value);
111///         self.notify.row_added(self.array.borrow().len() - 1, 1)
112///     }
113///
114///     /// Remove the row at the given index from the model
115///     pub fn remove(&self, index: usize) {
116///         self.array.borrow_mut().remove(index);
117///         self.notify.row_removed(index, 1)
118///     }
119/// }
120/// ```
121pub trait Model {
122    /// The model data: A model is a set of rows and each row has this data
123    type Data;
124    /// The number of rows in the model
125    fn row_count(&self) -> usize;
126    /// Returns the data for a particular row.
127    ///
128    /// This function should normally be called with `row < row_count()` and should return None otherwise.
129    ///
130    /// This function does not register dependencies on the current binding. For an equivalent
131    /// function that tracks dependencies, see [`ModelExt::row_data_tracked`]
132    fn row_data(&self, row: usize) -> Option<Self::Data>;
133    /// Sets the data for a particular row.
134    ///
135    /// This function should be called with `row < row_count()`, otherwise the implementation can panic.
136    ///
137    /// If the model cannot support data changes, then it is ok to do nothing.
138    /// The default implementation will print a warning to stderr.
139    ///
140    /// If the model can update the data, it should also call [`ModelNotify::row_changed`] on its
141    /// internal [`ModelNotify`].
142    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    /// The implementation should return a reference to its [`ModelNotify`] field.
152    ///
153    /// You can return `&()` if you your `Model` is constant and does not have a ModelNotify field.
154    fn model_tracker(&self) -> &dyn ModelTracker;
155
156    /// Returns an iterator visiting all elements of the model.
157    fn iter(&self) -> ModelIterator<'_, Self::Data>
158    where
159        Self: Sized,
160    {
161        ModelIterator::new(self)
162    }
163
164    /// Return something that can be downcast'ed (typically self).
165    ///
166    /// Use this to retrieve the concrete model from a [`ModelRc`] stored
167    /// in your tree of UI elements.
168    ///
169    /// ```
170    /// # use i_slint_core::model::*;
171    /// # use std::rc::Rc;
172    /// let handle = ModelRc::new(VecModel::from(vec![1i32, 2, 3]));
173    /// // later:
174    /// handle.as_any().downcast_ref::<VecModel<i32>>().unwrap().push(4);
175    /// assert_eq!(handle.row_data(3).unwrap(), 4);
176    /// ```
177    ///
178    /// Note: Custom models must implement this method for the cast to succeed.
179    /// A valid implementation is to return `self`:
180    /// ```ignore
181    ///     fn as_any(&self) -> &dyn core::any::Any { self }
182    /// ```
183    ///
184    /// ## Troubleshooting
185    /// A common reason why the dowcast fails at run-time is because of a type-mismatch
186    /// between the model created and the model downcasted. To debug this at compile time,
187    /// try matching the model type used for the downcast explicitly at model creation time.
188    /// In the following example, the downcast fails at run-time:
189    ///
190    /// ```
191    /// # use i_slint_core::model::*;
192    /// # use std::rc::Rc;
193    /// let model = VecModel::from_slice(&[3i32, 2, 1])
194    ///     .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);
195    /// let model_rc = ModelRc::new(model);
196    /// assert!(model_rc.as_any()
197    ///     .downcast_ref::<FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>>()
198    ///     .is_none());
199    /// ```
200    ///
201    /// To debug this, let's make the type explicit. It fails to compile.
202    ///
203    /// ```compile_fail
204    /// # use i_slint_core::model::*;
205    /// # use std::rc::Rc;
206    /// let model: FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>
207    ///     = VecModel::from_slice(&[3i32, 2, 1])
208    ///       .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);
209    /// let model_rc = ModelRc::new(model);
210    /// assert!(model_rc.as_any()
211    ///     .downcast_ref::<FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>>()
212    ///     .is_none());
213    /// ```
214    ///
215    /// The compiler tells us that the type of model is not `FilterModel<VecModel<..>>`,
216    /// but instead `from_slice()` already returns a `ModelRc`, so the correct type to
217    /// use for the downcast is wrapped in `ModelRc`:
218    ///
219    /// ```
220    /// # use i_slint_core::model::*;
221    /// # use std::rc::Rc;
222    /// let model: FilterModel<ModelRc<i32>, Box<dyn Fn(&i32) -> bool>>
223    ///     = VecModel::from_slice(&[3i32, 2, 1])
224    ///       .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);
225    /// let model_rc = ModelRc::new(model);
226    /// assert!(model_rc.as_any()
227    ///     .downcast_ref::<FilterModel<ModelRc<i32>, Box<dyn Fn(&i32) -> bool>>>()
228    ///     .is_some());
229    /// ```
230    fn as_any(&self) -> &dyn core::any::Any {
231        &()
232    }
233}
234
235/// Extension trait with extra methods implemented on types that implement [`Model`]
236pub trait ModelExt: Model {
237    /// Convenience function that calls [`ModelTracker::track_row_data_changes`]
238    /// before returning [`Model::row_data`].
239    ///
240    /// Calling [`row_data(row)`](Model::row_data) does not register the row as a dependency when calling it while
241    /// evaluating a property binding. This function calls [`track_row_data_changes(row)`](ModelTracker::track_row_data_changes)
242    /// on the [`self.model_tracker()`](Model::model_tracker) to enable tracking.
243    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    /// Returns a new Model where all elements are mapped by the function `map_function`.
249    /// This is a shortcut for [`MapModel::new()`].
250    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    /// Returns a new Model where the elements are filtered by the function `filter_function`.
259    /// This is a shortcut for [`FilterModel::new()`].
260    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    /// Returns a new Model where the elements are sorted ascending.
269    /// This is a shortcut for [`SortModel::new_ascending()`].
270    #[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    /// Returns a new Model where the elements are sorted by the function `sort_function`.
280    /// This is a shortcut for [`SortModel::new()`].
281    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    /// Returns a new Model where the elements are reversed.
290    /// This is a shortcut for [`ReverseModel::new()`].
291    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
301/// An iterator over the elements of a model.
302/// This struct is created by the [`Model::iter()`] trait function.
303pub struct ModelIterator<'a, T> {
304    model: &'a dyn Model<Data = T>,
305    row: usize,
306}
307
308impl<'a, T> ModelIterator<'a, T> {
309    /// Creates a new model iterator for a model reference.
310    /// This is the same as calling [`model.iter()`](Model::iter)
311    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
364/// A [`Model`] backed by a `Vec<T>`, using interior mutability.
365pub 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    /// Allocate a new model from a slice
378    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    /// Add a row at the end of the model
386    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    /// Inserts a row at position index. All rows after that are shifted.
392    /// This function panics if index is > row_count().
393    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    /// Remove the row at the given index from the model
399    ///
400    /// Returns the removed row
401    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    /// Replace inner Vec with new data
408    pub fn set_vec(&self, new: impl Into<Vec<T>>) {
409        *self.array.borrow_mut() = new.into();
410        self.notify.reset();
411    }
412
413    /// Extend the model with the content of the iterator
414    ///
415    /// Similar to [`Vec::extend`]
416    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    /// Clears the model, removing all values
426    ///
427    /// Similar to [`Vec::clear`]
428    pub fn clear(&self) {
429        self.array.borrow_mut().clear();
430        self.notify.reset();
431    }
432
433    /// Swaps two elements in the model.
434    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    /// Appends all the elements in the slice to the model
447    ///
448    /// Similar to [`Vec::extend_from_slice`]
449    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/// A model backed by a `SharedVector<T>`
499#[derive(Default)]
500pub struct SharedVectorModel<T> {
501    array: RefCell<SharedVector<T>>,
502    notify: ModelNotify,
503}
504
505impl<T: Clone + 'static> SharedVectorModel<T> {
506    /// Add a row at the end of the model
507    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    /// Returns a clone of the model's backing shared vector.
515    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
591/// ModelRc is a type wrapper for a reference counted implementation of the [`Model`] trait.
592///
593/// Models are used to represent sequences of the same data type. In `.slint` code those
594/// are represented using the `[T]` array syntax and typically used in `for` expressions,
595/// array properties, and array struct fields.
596///
597/// For example, a `property <[string]> foo` will be of type `ModelRc<SharedString>`
598/// and, behind the scenes, wraps a `Rc<dyn Model<Data = SharedString>>.`
599///
600/// An array struct field will also be of type `ModelRc`:
601///
602/// ```slint,no-preview
603/// export struct AddressBook {
604///     names: [string]
605/// }
606/// ```
607///
608/// When accessing `AddressBook` from Rust, the `names` field will be of type `ModelRc<SharedString>`.
609///
610/// There are several ways of constructing a ModelRc in Rust:
611///
612/// * An empty ModelRc can be constructed with [`ModelRc::default()`].
613/// * A `ModelRc` can be constructed from a slice or an array using the [`From`] trait.
614///   This allocates a [`VecModel`].
615/// * Use [`ModelRc::new()`] to construct a `ModelRc` from a type that implements the
616///   [`Model`] trait, such as [`VecModel`] or your own implementation.
617/// * If you have your model already in an `Rc`, then you can use the [`From`] trait
618///   to convert from `Rc<dyn Model<Data = T>>` to `ModelRc`.
619///
620/// ## Example
621///
622/// ```rust
623/// # i_slint_backend_testing::init_no_event_loop();
624/// use slint::{slint, SharedString, ModelRc, Model, VecModel};
625/// use std::rc::Rc;
626/// slint!{
627///     import { Button } from "std-widgets.slint";
628///     export component Example {
629///         callback add_item <=> btn.clicked;
630///         in property <[string]> the_model;
631///         HorizontalLayout {
632///             for it in the_model : Text { text: it; }
633///             btn := Button { text: "Add"; }
634///         }
635///     }
636/// }
637/// let ui = Example::new().unwrap();
638/// // Create a VecModel and put it in an Rc.
639/// let the_model : Rc<VecModel<SharedString>> =
640///         Rc::new(VecModel::from(vec!["Hello".into(), "World".into()]));
641/// // Convert it to a ModelRc.
642/// let the_model_rc = ModelRc::from(the_model.clone());
643/// // Pass the model to the ui: The generated set_the_model setter from the
644/// // the_model property takes a ModelRc.
645/// ui.set_the_model(the_model_rc);
646///
647/// // We have kept a strong reference to the_model, to modify it in a callback.
648/// ui.on_add_item(move || {
649///     // Use VecModel API: VecModel uses the Model notification mechanism to let Slint
650///     // know it needs to refresh the UI.
651///     the_model.push("SomeValue".into());
652/// });
653///
654/// // Alternative: we can re-use a getter.
655/// let ui_weak = ui.as_weak();
656/// ui.on_add_item(move || {
657///     let ui = ui_weak.unwrap();
658///     let the_model_rc = ui.get_the_model();
659///     let the_model = the_model_rc.as_any().downcast_ref::<VecModel<SharedString>>()
660///         .expect("We know we set a VecModel earlier");
661///     the_model.push("An Item".into());
662/// });
663/// ```
664///
665/// ### Updating the Model from a Thread
666///
667/// `ModelRc` is not `Send` and can only be used in the main thread.
668/// If you want to update the model based on data coming from another thread, you need to send back the data to the main thread
669/// using [`invoke_from_event_loop`](crate::api::invoke_from_event_loop) or
670/// [`Weak::upgrade_in_event_loop`](crate::api::Weak::upgrade_in_event_loop).
671///
672/// ```rust
673/// # i_slint_backend_testing::init_integration_test_with_mock_time();
674/// use slint::Model;
675/// slint::slint!{
676///     export component TestCase inherits Window {
677///         in property <[string]> the_model;
678///         //...
679///     }
680/// }
681/// let ui = TestCase::new().unwrap();
682/// // set a model (a VecModel)
683/// let model = std::rc::Rc::new(slint::VecModel::<slint::SharedString>::default());
684/// ui.set_the_model(model.clone().into());
685///
686/// // do some work in a thread
687/// let ui_weak = ui.as_weak();
688/// let thread = std::thread::spawn(move || {
689///     // do some work
690///     let new_strings = vec!["foo".into(), "bar".into()];
691///     // send the data back to the main thread
692///     ui_weak.upgrade_in_event_loop(move |ui| {
693///         let model = ui.get_the_model();
694///         let model = model.as_any().downcast_ref::<slint::VecModel<slint::SharedString>>()
695///             .expect("We know we set a VecModel earlier");
696///         model.set_vec(new_strings);
697/// #       slint::quit_event_loop().unwrap();
698///     });
699/// });
700/// ui.run().unwrap();
701/// ```
702pub 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    /// Construct an empty model
718    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
800/// ItemTree that can be instantiated by a repeater.
801pub trait RepeatedItemTree:
802    crate::item_tree::ItemTree + vtable::HasStaticVTable<ItemTreeVTable> + 'static
803{
804    /// The data corresponding to the model
805    type Data: Default + 'static;
806
807    /// Update this ItemTree at the given index and the given data
808    fn update(&self, index: usize, data: Self::Data);
809
810    /// Called once after the ItemTree has been instantiated and update()
811    /// was called once.
812    fn init(&self) {}
813
814    /// Layout this item in the listview
815    ///
816    /// offset_y is the `y` position where this item should be placed.
817    /// it should be updated to be to the y position of the next item.
818    ///
819    /// Returns the minimum item width which will be used to compute the listview's viewport width
820    fn listview_layout(self: Pin<&Self>, _offset_y: &mut LogicalLength) -> LogicalLength {
821        LogicalLength::default()
822    }
823
824    /// Returns what's needed to perform the layout if this ItemTree is in a layout
825    /// In case of repeated Rows, the index of a child item is set
826    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    /// Fills in the grid layout input data for this ItemTree if it is in a grid layout.
835    /// This will be a single GridLayoutInputData if the repeated item is a single cell,
836    /// or multiple GridLayoutInputData if the repeated item is a full Row.
837    /// The slice must have the exact size required (known at compile time).
838    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        // the actual implementation is in the code generated by generate_repeated_component()
848    }
849}
850
851#[derive(Clone, Copy, PartialEq, Debug)]
852enum RepeatedInstanceState {
853    /// The item is in a clean state
854    Clean,
855    /// The model data is stale and needs to be refreshed
856    Dirty,
857}
858struct RepeaterInner<C: RepeatedItemTree> {
859    instances: Vec<(RepeatedInstanceState, Option<ItemTreeRc<C>>)>,
860
861    // The remaining properties only make sense for ListView
862    /// The model row (index) of the first ItemTree in the `instances` vector.
863    offset: usize,
864    /// The average visible item height.
865    cached_item_height: LogicalLength,
866    /// The viewport_y last time the layout of the ListView was done
867    previous_viewport_y: LogicalLength,
868    /// the position of the item in the row `offset` (which corresponds to `instances[0]`).
869    /// We will try to keep this constant when re-layouting items
870    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/// This struct is put in a component when using the `for` syntax
886/// It helps instantiating the ItemTree `T`
887#[pin_project]
888pub struct RepeaterTracker<T: RepeatedItemTree> {
889    inner: RefCell<RepeaterInner<T>>,
890    #[pin]
891    model: Property<ModelRc<T::Data>>,
892    #[pin]
893    /// Set to true when the model becomes dirty.
894    is_dirty: Property<bool>,
895    /// Only used for the list view to track if the scrollbar has changed and item needs to be laid out again.
896    #[pin]
897    listview_geometry_tracker: crate::properties::PropertyTracker,
898}
899
900impl<T: RepeatedItemTree> ModelChangeListener for RepeaterTracker<T> {
901    /// Notify the peers that a specific row was changed
902    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    /// Notify the peers that rows were added
918    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            // Because all the indexes are dirty
939            c.0 = RepeatedInstanceState::Dirty;
940        }
941    }
942    /// Notify the peers that rows were removed
943    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            // Because all the indexes are dirty
964            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    /// Call this function to make sure that the model is updated.
1018    /// The init function is the function to create a ItemTree
1019    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    // returns true if new items were created
1027    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    /// Same as `Self::ensure_updated` but for a ListView
1063    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        // Query is_dirty to track model changes
1073        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        // We need some sort of estimation of the element height
1092        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                // There seems to be currently no items. Just instantiate one item.
1113                {
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            // We are jumping more than 1.5 screens, consider this as a random seek.
1146            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            // we scrolled down, try to find out the new offset.
1151            let mut it_y = first_item_y + vp_y;
1152            let mut new_offset = inner.offset;
1153            debug_assert!(it_y <= zero); // we scrolled down, the anchor should be hidden
1154            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            // We scrolled up, we'll instantiate items before offset in the loop
1175            (inner.offset, first_item_y + vp_y)
1176        };
1177
1178        let mut loop_count = 0;
1179        loop {
1180            // If there is a gap before the new_offset and the beginning of the visible viewport,
1181            // try to fill it with items. First look at items that are before new_offset in the
1182            // inner.instances, if any.
1183            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            // If there is still a gap, fill it with new instances before
1194            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            // Now we will layout items until we fit the view, starting with the ones that are already instantiated
1221            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            // create more items until there is no more room.
1246            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                // we reached the end of the model, and we still have room. scroll a bit up.
1257                vp_y += listview_height - y;
1258                loop_count += 1;
1259                continue;
1260            }
1261
1262            // Let's cleanup the instances that are not shown.
1263            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            // Now re-compute some coordinate such a way that the scrollbar are adjusted.
1286            inner.cached_item_height = (y - new_offset_y) / inner.instances.len() as Coord; // mean over all instance heights
1287            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                // If the new value gets set, all bindings are removed which means also an animation gets removed
1293                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    /// Sets the data directly in the model
1306    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    /// Set the model binding
1312    pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {
1313        self.0.model.set_binding(binding);
1314    }
1315
1316    /// Call the visitor for the root of each instance
1317    pub fn visit(
1318        &self,
1319        order: TraversalOrder,
1320        mut visitor: crate::item_tree::ItemVisitorRefMut,
1321    ) -> crate::item_tree::VisitChildrenResult {
1322        // We can't keep self.inner borrowed because the event might modify the model
1323        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    /// Return the amount of instances currently in the repeater
1338    pub fn len(&self) -> usize {
1339        self.0.inner.borrow().instances.len()
1340    }
1341
1342    /// Return the range of indices used by this Repeater.
1343    ///
1344    /// Two values are necessary here since the Repeater can start to insert the data from its
1345    /// model at an offset.
1346    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    /// Return the instance for the given model index.
1352    /// The index should be within [`Self::range()`]
1353    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    /// Return true if the Repeater as empty
1362    pub fn is_empty(&self) -> bool {
1363        self.len() == 0
1364    }
1365
1366    /// Returns a vector containing all instances
1367    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    /// Call this function to make sure that the model is updated.
1390    /// The init function is the function to create a ItemTree
1391    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    /// Set the model binding
1404    pub fn set_model_binding(&self, binding: impl Fn() -> bool + 'static) {
1405        self.model.set_binding(binding);
1406    }
1407
1408    /// Call the visitor for the root of each instance
1409    pub fn visit(
1410        &self,
1411        order: TraversalOrder,
1412        mut visitor: crate::item_tree::ItemVisitorRefMut,
1413    ) -> crate::item_tree::VisitChildrenResult {
1414        // We can't keep self.inner borrowed because the event might modify the model
1415        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    /// Return the amount of instances (1 if the conditional is active, 0 otherwise)
1426    pub fn len(&self) -> usize {
1427        self.instance.borrow().is_some() as usize
1428    }
1429
1430    /// Return the range of indices used by this Conditional.
1431    ///
1432    /// Similar to Repeater::range, but the range is always [0, 1] if the Conditional is active.
1433    pub fn range(&self) -> core::ops::Range<usize> {
1434        0..self.len()
1435    }
1436
1437    /// Return the instance for the given model index.
1438    /// The index should be within [`Self::range()`]
1439    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    /// Return true if the Repeater as empty
1447    pub fn is_empty(&self) -> bool {
1448        self.len() == 0
1449    }
1450
1451    /// Returns a vector containing all instances
1452    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        // Any changes to rows (even if after tracked rows) for now also marks watched rows as dirty, to
1543        // keep the logic simple.
1544        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        // Track the parameters reported by the model (row counts, indices, etc.).
1560        // The last field in the tuple is the row size the model reports at the time
1561        // of callback
1562        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}