mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
Print an warning in stderr when modifying read-only model
... and improve the documentation of Model
This commit is contained in:
parent
ab522eb147
commit
e1be599bc0
3 changed files with 92 additions and 12 deletions
|
@ -431,11 +431,17 @@ public:
|
||||||
/// Returns the data for a particular row. This function should be called with `row <
|
/// Returns the data for a particular row. This function should be called with `row <
|
||||||
/// row_count()`.
|
/// row_count()`.
|
||||||
virtual ModelData row_data(int i) const = 0;
|
virtual ModelData row_data(int i) const = 0;
|
||||||
/// Sets the data for a particular row. This function should be called with `row < row_count()`.
|
/// Sets the data for a particular row.
|
||||||
/// If the model cannot support data changes, then it is ok to do nothing (default
|
///
|
||||||
/// implementation). If the model can update the data, the implementation should also call
|
/// This function should only be called with `row < row_count()`.
|
||||||
/// row_changed.
|
///
|
||||||
virtual void set_row_data(int, const ModelData &) {};
|
/// If the model cannot support data changes, then it is ok to do nothing.
|
||||||
|
/// The default implementation will print a warning to stderr.
|
||||||
|
///
|
||||||
|
/// If the model can update the data, it should also call `row_changed`
|
||||||
|
virtual void set_row_data(int, const ModelData &) {
|
||||||
|
std::cerr << "Model::set_row_data was called on a read-only model" << std::endl;
|
||||||
|
};
|
||||||
|
|
||||||
/// \private
|
/// \private
|
||||||
/// Internal function called by the view to register itself
|
/// Internal function called by the view to register itself
|
||||||
|
|
|
@ -64,6 +64,68 @@ impl ModelNotify {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Model is providing Data for the Repeater or ListView elements of the `.60` language
|
/// A Model is providing Data for the Repeater or ListView elements of the `.60` language
|
||||||
|
///
|
||||||
|
/// If the model can be changed, the type implementing the Model trait should holds
|
||||||
|
/// a [`ModelNotify`], and is responsible to call functions on it to let the UI know that
|
||||||
|
/// something has changed.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// As an example, let's see the implementation of [`VecModel`].
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use sixtyfps_corelib::model::{Model, ModelNotify, ModelPeer};
|
||||||
|
/// pub struct VecModel<T> {
|
||||||
|
/// // the backing data, stored in a `RefCell` as this model can be modified
|
||||||
|
/// array: std::cell::RefCell<Vec<T>>,
|
||||||
|
/// // the ModelNotify will allow to notify the UI that the model changes
|
||||||
|
/// notify: ModelNotify,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl<T: Clone + 'static> Model for VecModel<T> {
|
||||||
|
/// type Data = T;
|
||||||
|
///
|
||||||
|
/// fn row_count(&self) -> usize {
|
||||||
|
/// self.array.borrow().len()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn row_data(&self, row: usize) -> Self::Data {
|
||||||
|
/// self.array.borrow()[row].clone()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn set_row_data(&self, row: usize, data: Self::Data) {
|
||||||
|
/// self.array.borrow_mut()[row] = data;
|
||||||
|
/// // don't forget to call row_changed
|
||||||
|
/// self.notify.row_changed(row);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn attach_peer(&self, peer: ModelPeer) {
|
||||||
|
/// // simply forward to ModelNotify::attach
|
||||||
|
/// self.notify.attach(peer);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn as_any(&self) -> &dyn core::any::Any {
|
||||||
|
/// // a typical implementation just return `self`
|
||||||
|
/// self
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // when modifying the model, we call the corresponding function in
|
||||||
|
/// // the ModelNotify
|
||||||
|
/// impl<T> VecModel<T> {
|
||||||
|
/// /// Add a row at the end of the model
|
||||||
|
/// pub fn push(&self, value: T) {
|
||||||
|
/// self.array.borrow_mut().push(value);
|
||||||
|
/// self.notify.row_added(self.array.borrow().len() - 1, 1)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// /// Remove the row at the given index from the model
|
||||||
|
/// pub fn remove(&self, index: usize) {
|
||||||
|
/// self.array.borrow_mut().remove(index);
|
||||||
|
/// self.notify.row_removed(index, 1)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub trait Model {
|
pub trait Model {
|
||||||
/// The model data: A model is a set of row and each row has this data
|
/// The model data: A model is a set of row and each row has this data
|
||||||
type Data;
|
type Data;
|
||||||
|
@ -71,11 +133,23 @@ pub trait Model {
|
||||||
fn row_count(&self) -> usize;
|
fn row_count(&self) -> usize;
|
||||||
/// Returns the data for a particular row. This function should be called with `row < row_count()`.
|
/// Returns the data for a particular row. This function should be called with `row < row_count()`.
|
||||||
fn row_data(&self, row: usize) -> Self::Data;
|
fn row_data(&self, row: usize) -> Self::Data;
|
||||||
/// Sets the data for a particular row. This function should be called with `row < row_count()`.
|
/// Sets the data for a particular row.
|
||||||
/// If the model cannot support data changes, then it is ok to do nothing (default implementation).
|
///
|
||||||
/// If the model can update the data, it should also call row_changed on its internal `ModelNotify`.
|
/// This function should be called with `row < row_count()`, otherwise the implementation can panic.
|
||||||
fn set_row_data(&self, _row: usize, _data: Self::Data) {}
|
///
|
||||||
/// Should forward to the internal [`ModelNotify::attach`]
|
/// If the model cannot support data changes, then it is ok to do nothing.
|
||||||
|
/// The default implementation will print a warning to stderr.
|
||||||
|
///
|
||||||
|
/// If the model can update the data, it should also call [`ModelNofity::row_changed`] on its
|
||||||
|
/// internal [`ModelNotify`].
|
||||||
|
fn set_row_data(&self, _row: usize, _data: Self::Data) {
|
||||||
|
eprintln!(
|
||||||
|
"Model::set_row_data called on a model of type {} which does not re-implement this method. \
|
||||||
|
This happens when trying to modify a read-only model",
|
||||||
|
core::any::type_name::<Self>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/// The implementation should forward to [`ModelNotify::attach`]
|
||||||
fn attach_peer(&self, peer: ModelPeer);
|
fn attach_peer(&self, peer: ModelPeer);
|
||||||
|
|
||||||
/// Returns an iterator visiting all elements of the model.
|
/// Returns an iterator visiting all elements of the model.
|
||||||
|
@ -139,7 +213,7 @@ impl<'a, T> Iterator for ModelIterator<'a, T> {
|
||||||
|
|
||||||
impl<'a, T> ExactSizeIterator for ModelIterator<'a, T> {}
|
impl<'a, T> ExactSizeIterator for ModelIterator<'a, T> {}
|
||||||
|
|
||||||
/// A model backed by a SharedVector
|
/// A model backed by a `Vec<T>`
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct VecModel<T> {
|
pub struct VecModel<T> {
|
||||||
array: RefCell<Vec<T>>,
|
array: RefCell<Vec<T>>,
|
||||||
|
|
|
@ -67,7 +67,7 @@ impl Model for ValueModel {
|
||||||
self.notify.row_changed(row)
|
self.notify.row_changed(row)
|
||||||
}
|
}
|
||||||
Value::Model(model_ptr) => model_ptr.set_row_data(row, data),
|
Value::Model(model_ptr) => model_ptr.set_row_data(row, data),
|
||||||
_ => println!("Value of model cannot be change"),
|
_ => eprintln!("Trying to change the value of a read-only integer model."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue