mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-30 23:27:22 +00:00
Rename ModelHandle to SharedModel
This patch is mostly a rename now, but also contains a few small cleanups. SharedModel implements the Model trait itself and gracefully falls back to an empty model is no Model was provided. This allows for some small simplifications. Also make sure to use the same comparision for SharedModels everywhere. This fixes the last remaining clippy errors we had.
This commit is contained in:
parent
afb3f269c1
commit
018c1a6666
22 changed files with 88 additions and 112 deletions
|
@ -21,6 +21,7 @@ as well as the [Rust migration guide for the `sixtyfps` crate](api/sixtyfps-rs/m
|
||||||
- In Rust and C++, `sixtyfps::Image::size()` now returns an integer size type.
|
- In Rust and C++, `sixtyfps::Image::size()` now returns an integer size type.
|
||||||
- `sixtyfps::interpreter::CallCallbackError` was renamed to `sixtyfps::interpreter::InvokeCallbackError`
|
- `sixtyfps::interpreter::CallCallbackError` was renamed to `sixtyfps::interpreter::InvokeCallbackError`
|
||||||
- Some deprecation warning in .60 became hard errors
|
- Some deprecation warning in .60 became hard errors
|
||||||
|
- Replace `ModelHandle` with `ModelRc`
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use core::cell::RefCell;
|
||||||
use neon::prelude::*;
|
use neon::prelude::*;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use sixtyfps_compilerlib::langtype::Type;
|
use sixtyfps_compilerlib::langtype::Type;
|
||||||
use sixtyfps_corelib::model::{Model, ModelHandle};
|
use sixtyfps_corelib::model::{Model, ModelRc};
|
||||||
use sixtyfps_corelib::window::WindowHandleAccess;
|
use sixtyfps_corelib::window::WindowHandleAccess;
|
||||||
use sixtyfps_corelib::{ImageInner, SharedVector};
|
use sixtyfps_corelib::{ImageInner, SharedVector};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -182,21 +182,20 @@ fn to_eval_value<'cx>(
|
||||||
Type::Array(a) => match val.downcast::<JsArray>() {
|
Type::Array(a) => match val.downcast::<JsArray>() {
|
||||||
Ok(arr) => {
|
Ok(arr) => {
|
||||||
let vec = arr.to_vec(cx)?;
|
let vec = arr.to_vec(cx)?;
|
||||||
Ok(Value::Model(ModelHandle::new(Rc::new(
|
Ok(Value::Model(ModelRc::new(Rc::new(
|
||||||
sixtyfps_corelib::model::SharedVectorModel::from(
|
sixtyfps_corelib::model::SharedVectorModel::from(
|
||||||
vec.into_iter()
|
vec.into_iter()
|
||||||
.map(|i| to_eval_value(i, (*a).clone(), cx, persistent_context))
|
.map(|i| to_eval_value(i, (*a).clone(), cx, persistent_context))
|
||||||
.collect::<Result<SharedVector<_>, _>>()?,
|
.collect::<Result<SharedVector<_>, _>>()?,
|
||||||
),
|
),
|
||||||
)
|
))))
|
||||||
as Rc<dyn sixtyfps_corelib::model::Model<Data = Value>>)))
|
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let obj = val.downcast_or_throw::<JsObject, _>(cx)?;
|
let obj = val.downcast_or_throw::<JsObject, _>(cx)?;
|
||||||
obj.get(cx, "rowCount")?.downcast_or_throw::<JsFunction, _>(cx)?;
|
obj.get(cx, "rowCount")?.downcast_or_throw::<JsFunction, _>(cx)?;
|
||||||
obj.get(cx, "rowData")?.downcast_or_throw::<JsFunction, _>(cx)?;
|
obj.get(cx, "rowData")?.downcast_or_throw::<JsFunction, _>(cx)?;
|
||||||
let m = js_model::JsModel::new(obj, *a, cx, persistent_context)?;
|
let m = js_model::JsModel::new(obj, *a, cx, persistent_context)?;
|
||||||
Ok(Value::Model(ModelHandle::new(m)))
|
Ok(Value::Model(ModelRc::new(m)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Type::Image => {
|
Type::Image => {
|
||||||
|
|
|
@ -181,7 +181,7 @@ The follow table summarizes the entire mapping:
|
||||||
| `duration` | `i64` | At run-time, durations are always represented as signed 64-bit integers with millisecond precision. |
|
| `duration` | `i64` | At run-time, durations are always represented as signed 64-bit integers with millisecond precision. |
|
||||||
| `angle` | `f32` | The value in degrees |
|
| `angle` | `f32` | The value in degrees |
|
||||||
| structure | `struct` of the same name | |
|
| structure | `struct` of the same name | |
|
||||||
| array | [`ModelHandle`] | |
|
| array | [`ModelRc`] | |
|
||||||
|
|
||||||
For user defined structures in the .60, an extra struct is generated.
|
For user defined structures in the .60, an extra struct is generated.
|
||||||
For example, if the `.60` contains
|
For example, if the `.60` contains
|
||||||
|
@ -233,7 +233,7 @@ pub use sixtyfps_corelib::graphics::{
|
||||||
Brush, Color, Image, LoadImageError, Rgb8Pixel, Rgba8Pixel, RgbaColor, SharedPixelBuffer,
|
Brush, Color, Image, LoadImageError, Rgb8Pixel, Rgba8Pixel, RgbaColor, SharedPixelBuffer,
|
||||||
};
|
};
|
||||||
pub use sixtyfps_corelib::model::{
|
pub use sixtyfps_corelib::model::{
|
||||||
Model, ModelHandle, ModelNotify, ModelPeer, ModelTracker, StandardListViewItem, VecModel,
|
Model, ModelNotify, ModelPeer, ModelRc, ModelTracker, StandardListViewItem, VecModel,
|
||||||
};
|
};
|
||||||
pub use sixtyfps_corelib::sharedvector::SharedVector;
|
pub use sixtyfps_corelib::sharedvector::SharedVector;
|
||||||
pub use sixtyfps_corelib::string::SharedString;
|
pub use sixtyfps_corelib::string::SharedString;
|
||||||
|
|
|
@ -62,3 +62,6 @@ fn model_tracker(&self) -> &dyn ModelTracker {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Minor changes to `Model`
|
||||||
|
|
||||||
|
`ModelRc` replaces `ModelHandle`.
|
||||||
|
|
|
@ -20,7 +20,7 @@ fn main() {
|
||||||
// ANCHOR: game_logic
|
// ANCHOR: game_logic
|
||||||
// Assign the shuffled Vec to the model property
|
// Assign the shuffled Vec to the model property
|
||||||
let tiles_model = std::rc::Rc::new(sixtyfps::VecModel::from(tiles));
|
let tiles_model = std::rc::Rc::new(sixtyfps::VecModel::from(tiles));
|
||||||
main_window.set_memory_tiles(sixtyfps::ModelHandle::new(tiles_model.clone()));
|
main_window.set_memory_tiles(sixtyfps::ModelRc::new(tiles_model.clone()));
|
||||||
|
|
||||||
let main_window_weak = main_window.as_weak();
|
let main_window_weak = main_window.as_weak();
|
||||||
main_window.on_check_if_pair_solved(move || {
|
main_window.on_check_if_pair_solved(move || {
|
||||||
|
|
|
@ -20,7 +20,7 @@ fn main() {
|
||||||
|
|
||||||
// Assign the shuffled Vec to the model property
|
// Assign the shuffled Vec to the model property
|
||||||
let tiles_model = std::rc::Rc::new(sixtyfps::VecModel::from(tiles));
|
let tiles_model = std::rc::Rc::new(sixtyfps::VecModel::from(tiles));
|
||||||
main_window.set_memory_tiles(sixtyfps::ModelHandle::new(tiles_model));
|
main_window.set_memory_tiles(sixtyfps::ModelRc::new(tiles_model));
|
||||||
|
|
||||||
main_window.run();
|
main_window.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ pub fn main() {
|
||||||
]);
|
]);
|
||||||
let filters = Rc::new(filters);
|
let filters = Rc::new(filters);
|
||||||
|
|
||||||
main_window.set_filters(sixtyfps::ModelHandle::new(filters.clone()));
|
main_window.set_filters(sixtyfps::ModelRc::new(filters.clone()));
|
||||||
|
|
||||||
main_window.on_filter_image(move |filter_index| {
|
main_window.on_filter_image(move |filter_index| {
|
||||||
let filter_fn = filters.0[filter_index as usize].apply_function;
|
let filter_fn = filters.0[filter_index as usize].apply_function;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
|
// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
|
||||||
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
|
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
|
||||||
|
|
||||||
use sixtyfps::{Model, ModelHandle, Timer, VecModel};
|
use sixtyfps::{Model, ModelRc, Timer, VecModel};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ pub fn main() {
|
||||||
|
|
||||||
let tiles_model = Rc::new(VecModel::from(tiles));
|
let tiles_model = Rc::new(VecModel::from(tiles));
|
||||||
|
|
||||||
main_window.set_memory_tiles(ModelHandle::new(tiles_model.clone()));
|
main_window.set_memory_tiles(ModelRc::new(tiles_model.clone()));
|
||||||
|
|
||||||
let main_window_weak = main_window.as_weak();
|
let main_window_weak = main_window.as_weak();
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub fn main() {
|
||||||
});
|
});
|
||||||
main_window
|
main_window
|
||||||
.global::<PrinterQueue>()
|
.global::<PrinterQueue>()
|
||||||
.set_printer_queue(sixtyfps::ModelHandle::new(printer_queue.data.clone()));
|
.set_printer_queue(sixtyfps::ModelRc::new(printer_queue.data.clone()));
|
||||||
|
|
||||||
main_window.on_quit(move || {
|
main_window.on_quit(move || {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
|
|
@ -180,7 +180,7 @@ pub fn main() {
|
||||||
finished: false,
|
finished: false,
|
||||||
}));
|
}));
|
||||||
state.borrow_mut().randomize();
|
state.borrow_mut().randomize();
|
||||||
main_window.set_pieces(sixtyfps::ModelHandle::new(state.borrow().pieces.clone()));
|
main_window.set_pieces(sixtyfps::ModelRc::new(state.borrow().pieces.clone()));
|
||||||
|
|
||||||
let state_copy = state.clone();
|
let state_copy = state.clone();
|
||||||
main_window.on_piece_clicked(move |p| {
|
main_window.on_piece_clicked(move |p| {
|
||||||
|
|
|
@ -45,7 +45,7 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
main_window.set_todo_model(sixtyfps::ModelHandle::new(todo_model));
|
main_window.set_todo_model(sixtyfps::ModelRc::new(todo_model));
|
||||||
|
|
||||||
main_window.run();
|
main_window.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ fn rust_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
|
||||||
Type::Struct { name: Some(name), .. } => Some(struct_name_to_tokens(name)),
|
Type::Struct { name: Some(name), .. } => Some(struct_name_to_tokens(name)),
|
||||||
Type::Array(o) => {
|
Type::Array(o) => {
|
||||||
let inner = rust_type(o)?;
|
let inner = rust_type(o)?;
|
||||||
Some(quote!(sixtyfps::re_exports::ModelHandle<#inner>))
|
Some(quote!(sixtyfps::re_exports::ModelRc<#inner>))
|
||||||
}
|
}
|
||||||
Type::Enumeration(e) => {
|
Type::Enumeration(e) => {
|
||||||
let e = ident(&e.name);
|
let e = ident(&e.name);
|
||||||
|
@ -536,7 +536,7 @@ fn generate_sub_component(
|
||||||
|
|
||||||
let mut model = compile_expression(&repeated.model, &ctx);
|
let mut model = compile_expression(&repeated.model, &ctx);
|
||||||
if repeated.model.ty(&ctx) == Type::Bool {
|
if repeated.model.ty(&ctx) == Type::Bool {
|
||||||
model = quote!(sixtyfps::re_exports::ModelHandle::new(sixtyfps::re_exports::Rc::<bool>::new(#model)))
|
model = quote!(sixtyfps::re_exports::ModelRc::new(sixtyfps::re_exports::Rc::<bool>::new(#model)))
|
||||||
}
|
}
|
||||||
|
|
||||||
init.push(quote! {
|
init.push(quote! {
|
||||||
|
@ -1273,7 +1273,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
(Type::Float32, Type::Model) | (Type::Int32, Type::Model) => {
|
(Type::Float32, Type::Model) | (Type::Int32, Type::Model) => {
|
||||||
quote!(sixtyfps::re_exports::ModelHandle::new(sixtyfps::re_exports::Rc::<usize>::new(#f as usize)))
|
quote!(sixtyfps::re_exports::ModelRc::new(sixtyfps::re_exports::Rc::<usize>::new(#f as usize)))
|
||||||
}
|
}
|
||||||
(Type::Float32, Type::Color) => {
|
(Type::Float32, Type::Color) => {
|
||||||
quote!(sixtyfps::re_exports::Color::from_argb_encoded(#f as u32))
|
quote!(sixtyfps::re_exports::Color::from_argb_encoded(#f as u32))
|
||||||
|
@ -1446,7 +1446,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
|
||||||
let base_e = compile_expression(array, ctx);
|
let base_e = compile_expression(array, ctx);
|
||||||
let index_e = compile_expression(index, ctx);
|
let index_e = compile_expression(index, ctx);
|
||||||
let value_e = compile_expression(value, ctx);
|
let value_e = compile_expression(value, ctx);
|
||||||
quote!((#base_e).set_row_data(#index_e as usize, #value_e as _);)
|
quote!((#base_e).set_row_data(#index_e as usize, #value_e as _))
|
||||||
}
|
}
|
||||||
Expression::BinaryExpression { lhs, rhs, op } => {
|
Expression::BinaryExpression { lhs, rhs, op } => {
|
||||||
let (conv1, conv2) = match crate::expression_tree::operator_class(*op) {
|
let (conv1, conv2) = match crate::expression_tree::operator_class(*op) {
|
||||||
|
@ -1536,7 +1536,7 @@ fn compile_expression(expr: &Expression, ctx: &EvaluationContext) -> TokenStream
|
||||||
let val = values.iter().map(|e| compile_expression(e, ctx));
|
let val = values.iter().map(|e| compile_expression(e, ctx));
|
||||||
if *as_model {
|
if *as_model {
|
||||||
let rust_element_ty = rust_type(element_ty).unwrap();
|
let rust_element_ty = rust_type(element_ty).unwrap();
|
||||||
quote!(sixtyfps::re_exports::ModelHandle::new(
|
quote!(sixtyfps::re_exports::ModelRc::new(
|
||||||
sixtyfps::re_exports::Rc::new(sixtyfps::re_exports::VecModel::<#rust_element_ty>::from(
|
sixtyfps::re_exports::Rc::new(sixtyfps::re_exports::VecModel::<#rust_element_ty>::from(
|
||||||
sixtyfps::re_exports::vec![#(#val as _),*]
|
sixtyfps::re_exports::vec![#(#val as _),*]
|
||||||
))
|
))
|
||||||
|
|
|
@ -239,14 +239,14 @@ pub trait Model {
|
||||||
|
|
||||||
/// Return something that can be downcast'ed (typically self)
|
/// Return something that can be downcast'ed (typically self)
|
||||||
///
|
///
|
||||||
/// This is useful to get back to the actual model from a ModelHandle stored
|
/// This is useful to get back to the actual model from a `ModelRc` stored
|
||||||
/// in a component.
|
/// in a component.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use sixtyfps_corelib::model::*;
|
/// # use sixtyfps_corelib::model::*;
|
||||||
/// # use std::rc::Rc;
|
/// # use std::rc::Rc;
|
||||||
/// let vec_model = Rc::new(VecModel::from(vec![1i32, 2, 3]));
|
/// let vec_model = Rc::new(VecModel::from(vec![1i32, 2, 3]));
|
||||||
/// let handle = ModelHandle::from(vec_model as Rc<dyn Model<Data = i32>>);
|
/// let handle = ModelRc::new(vec_model as Rc<dyn Model<Data = i32>>);
|
||||||
/// // later:
|
/// // later:
|
||||||
/// handle.as_any().downcast_ref::<VecModel<i32>>().unwrap().push(4);
|
/// handle.as_any().downcast_ref::<VecModel<i32>>().unwrap().push(4);
|
||||||
/// assert_eq!(handle.row_data(3).unwrap(), 4);
|
/// assert_eq!(handle.row_data(3).unwrap(), 4);
|
||||||
|
@ -305,11 +305,11 @@ pub struct VecModel<T> {
|
||||||
|
|
||||||
impl<T: 'static> VecModel<T> {
|
impl<T: 'static> VecModel<T> {
|
||||||
/// Allocate a new model from a slice
|
/// Allocate a new model from a slice
|
||||||
pub fn from_slice(slice: &[T]) -> ModelHandle<T>
|
pub fn from_slice(slice: &[T]) -> ModelRc<T>
|
||||||
where
|
where
|
||||||
T: Clone,
|
T: Clone,
|
||||||
{
|
{
|
||||||
ModelHandle(Some(Rc::<Self>::new(slice.to_vec().into())))
|
ModelRc::new(Rc::<Self>::new(slice.to_vec().into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a row at the end of the model
|
/// Add a row at the end of the model
|
||||||
|
@ -462,56 +462,49 @@ impl Model for bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Properties of type array in the .60 language are represented as
|
/// Properties of type Array in the .60 language are represented as
|
||||||
/// an [`Option`] of an [`Rc`] of something implemented the [`Model`] trait
|
/// a `ModelRc` that implements the `Model` trait.
|
||||||
#[derive(derive_more::Deref, derive_more::DerefMut, derive_more::From, derive_more::Into)]
|
#[derive(derive_more::Deref, derive_more::DerefMut, derive_more::From, derive_more::Into)]
|
||||||
pub struct ModelHandle<T>(pub Option<Rc<dyn Model<Data = T>>>);
|
pub struct ModelRc<T>(Option<Rc<dyn Model<Data = T>>>);
|
||||||
|
|
||||||
impl<T> core::fmt::Debug for ModelHandle<T> {
|
impl<T> core::fmt::Debug for ModelRc<T> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "ModelHandle({:?})", self.0.as_ref().map(|_| "dyn Model"))
|
write!(f, "ModelRc(dyn Model)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for ModelHandle<T> {
|
impl<T> Clone for ModelRc<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self(self.0.clone())
|
Self(self.0.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> Default for ModelHandle<T> {
|
|
||||||
|
impl<T> Default for ModelRc<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(None)
|
Self(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> core::cmp::PartialEq for ModelHandle<T> {
|
impl<T> core::cmp::PartialEq for ModelRc<T> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match (&self.0, &other.0) {
|
match (&self.0, &other.0) {
|
||||||
(None, None) => true,
|
(None, None) => true,
|
||||||
(None, Some(_)) => false,
|
|
||||||
(Some(_), None) => false,
|
|
||||||
(Some(a), Some(b)) => core::ptr::eq(
|
(Some(a), Some(b)) => core::ptr::eq(
|
||||||
(&**a) as *const dyn Model<Data = T> as *const u8,
|
(&**a) as *const dyn Model<Data = T> as *const u8,
|
||||||
(&**b) as *const dyn Model<Data = T> as *const u8,
|
(&**b) as *const dyn Model<Data = T> as *const u8,
|
||||||
),
|
),
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<Rc<dyn Model<Data = T>>> for ModelHandle<T> {
|
impl<T> ModelRc<T> {
|
||||||
fn from(x: Rc<dyn Model<Data = T>>) -> Self {
|
|
||||||
Self(Some(x))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ModelHandle<T> {
|
|
||||||
/// Create a new handle wrapping the given model
|
|
||||||
pub fn new(model: Rc<dyn Model<Data = T>>) -> Self {
|
pub fn new(model: Rc<dyn Model<Data = T>>) -> Self {
|
||||||
Self(Some(model))
|
Self(Some(model))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Model for ModelHandle<T> {
|
impl<T> Model for ModelRc<T> {
|
||||||
type Data = T;
|
type Data = T;
|
||||||
|
|
||||||
fn row_count(&self) -> usize {
|
fn row_count(&self) -> usize {
|
||||||
|
@ -524,7 +517,7 @@ impl<T> Model for ModelHandle<T> {
|
||||||
|
|
||||||
fn set_row_data(&self, row: usize, data: Self::Data) {
|
fn set_row_data(&self, row: usize, data: Self::Data) {
|
||||||
if let Some(model) = self.0.as_ref() {
|
if let Some(model) = self.0.as_ref() {
|
||||||
model.set_row_data(row, data)
|
model.set_row_data(row, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,7 +649,7 @@ impl<C: RepeatedComponent> ErasedRepeater for Repeater<C> {
|
||||||
pub struct Repeater<C: RepeatedComponent> {
|
pub struct Repeater<C: RepeatedComponent> {
|
||||||
inner: RefCell<RepeaterInner<C>>,
|
inner: RefCell<RepeaterInner<C>>,
|
||||||
#[pin]
|
#[pin]
|
||||||
model: Property<ModelHandle<C::Data>>,
|
model: Property<ModelRc<C::Data>>,
|
||||||
#[pin]
|
#[pin]
|
||||||
is_dirty: Property<bool>,
|
is_dirty: Property<bool>,
|
||||||
/// Only used for the list view to track if the scrollbar has changed and item needs to be layed out again.
|
/// Only used for the list view to track if the scrollbar has changed and item needs to be layed out again.
|
||||||
|
@ -694,24 +687,22 @@ impl<C: RepeatedComponent> PinnedDrop for Repeater<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: RepeatedComponent + 'static> Repeater<C> {
|
impl<C: RepeatedComponent + 'static> Repeater<C> {
|
||||||
fn model(self: Pin<&Self>) -> ModelHandle<C::Data> {
|
fn model(self: Pin<&Self>) -> ModelRc<C::Data> {
|
||||||
// Safety: Repeater does not implement drop and never let access model as mutable
|
// Safety: Repeater does not implement drop and never allows access to model as mutable
|
||||||
let model = self.project_ref().model;
|
let model = self.project_ref().model;
|
||||||
|
|
||||||
if model.is_dirty() {
|
if model.is_dirty() {
|
||||||
*self.inner.borrow_mut() = RepeaterInner::default();
|
*self.inner.borrow_mut() = RepeaterInner::default();
|
||||||
self.is_dirty.set(true);
|
self.is_dirty.set(true);
|
||||||
if let ModelHandle(Some(m)) = model.get() {
|
let m = model.get();
|
||||||
let peer = self.peer.get_or_init(|| {
|
let peer = self.peer.get_or_init(|| {
|
||||||
//Safety: we will reset it when we Drop the Repeater
|
//Safety: we will reset it when we Drop the Repeater
|
||||||
Rc::pin(DependencyNode::new(
|
Rc::pin(DependencyNode::new(
|
||||||
self.get_ref() as &dyn ErasedRepeater as *const dyn ErasedRepeater
|
self.get_ref() as &dyn ErasedRepeater as *const dyn ErasedRepeater
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
m.model_tracker()
|
m.model_tracker().attach_peer(ModelPeer { inner: PinWeak::downgrade(peer.clone()) });
|
||||||
.attach_peer(ModelPeer { inner: PinWeak::downgrade(peer.clone()) });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
model.get()
|
model.get()
|
||||||
}
|
}
|
||||||
|
@ -719,12 +710,9 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
||||||
/// Call this function to make sure that the model is updated.
|
/// Call this function to make sure that the model is updated.
|
||||||
/// The init function is the function to create a component
|
/// The init function is the function to create a component
|
||||||
pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ComponentRc<C>) {
|
pub fn ensure_updated(self: Pin<&Self>, init: impl Fn() -> ComponentRc<C>) {
|
||||||
if let ModelHandle(Some(model)) = self.model() {
|
let model = self.model();
|
||||||
if self.project_ref().is_dirty.get() {
|
if self.project_ref().is_dirty.get() {
|
||||||
self.ensure_updated_impl(init, &model, model.row_count());
|
self.ensure_updated_impl(init, &model, model.row_count());
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.inner.borrow_mut().components.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +720,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
||||||
fn ensure_updated_impl(
|
fn ensure_updated_impl(
|
||||||
self: Pin<&Self>,
|
self: Pin<&Self>,
|
||||||
init: impl Fn() -> ComponentRc<C>,
|
init: impl Fn() -> ComponentRc<C>,
|
||||||
model: &Rc<dyn Model<Data = C::Data>>,
|
model: &ModelRc<C::Data>,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
@ -769,11 +757,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
||||||
viewport_y.set(0.);
|
viewport_y.set(0.);
|
||||||
};
|
};
|
||||||
|
|
||||||
let model = if let ModelHandle(Some(model)) = self.model() {
|
let model = self.model();
|
||||||
model
|
|
||||||
} else {
|
|
||||||
return empty_model();
|
|
||||||
};
|
|
||||||
let row_count = model.row_count();
|
let row_count = model.row_count();
|
||||||
if row_count == 0 {
|
if row_count == 0 {
|
||||||
return empty_model();
|
return empty_model();
|
||||||
|
@ -785,8 +769,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
||||||
let geometry_updated = listview_geometry_tracker
|
let geometry_updated = listview_geometry_tracker
|
||||||
.evaluate_if_dirty(|| {
|
.evaluate_if_dirty(|| {
|
||||||
// Fetch the model again to make sure that it is a dependency of this geometry tracker.
|
// Fetch the model again to make sure that it is a dependency of this geometry tracker.
|
||||||
// invariant: model existence was checked earlier, so unwrap() should be safe.
|
let model = self.model();
|
||||||
let model = self.model().0.unwrap();
|
|
||||||
// Also register a dependency to "is_dirty"
|
// Also register a dependency to "is_dirty"
|
||||||
let _ = self.project_ref().is_dirty.get();
|
let _ = self.project_ref().is_dirty.get();
|
||||||
|
|
||||||
|
@ -904,14 +887,13 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
||||||
|
|
||||||
/// Sets the data directly in the model
|
/// Sets the data directly in the model
|
||||||
pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {
|
pub fn model_set_row_data(self: Pin<&Self>, row: usize, data: C::Data) {
|
||||||
if let ModelHandle(Some(model)) = self.model() {
|
let model = self.model();
|
||||||
model.set_row_data(row, data);
|
model.set_row_data(row, data);
|
||||||
if let Some(c) = self.inner.borrow_mut().components.get_mut(row) {
|
if let Some(c) = self.inner.borrow_mut().components.get_mut(row) {
|
||||||
if c.0 == RepeatedComponentState::Dirty {
|
if c.0 == RepeatedComponentState::Dirty {
|
||||||
if let Some(comp) = c.1.as_ref() {
|
if let Some(comp) = c.1.as_ref() {
|
||||||
comp.update(row, model.row_data(row).unwrap());
|
comp.update(row, model.row_data(row).unwrap());
|
||||||
c.0 = RepeatedComponentState::Clean;
|
c.0 = RepeatedComponentState::Clean;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -920,7 +902,7 @@ impl<C: RepeatedComponent + 'static> Repeater<C> {
|
||||||
|
|
||||||
impl<C: RepeatedComponent> Repeater<C> {
|
impl<C: RepeatedComponent> Repeater<C> {
|
||||||
/// Set the model binding
|
/// Set the model binding
|
||||||
pub fn set_model_binding(&self, binding: impl Fn() -> ModelHandle<C::Data> + 'static) {
|
pub fn set_model_binding(&self, binding: impl Fn() -> ModelRc<C::Data> + 'static) {
|
||||||
self.model.set_binding(binding);
|
self.model.set_binding(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,7 +973,7 @@ pub struct StandardListViewItem {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tracking_model_handle() {
|
fn test_tracking_model_handle() {
|
||||||
let model: Rc<VecModel<u8>> = Rc::new(Default::default());
|
let model: Rc<VecModel<u8>> = Rc::new(Default::default());
|
||||||
let handle = ModelHandle::new(model.clone());
|
let handle = ModelRc::new(model.clone());
|
||||||
let tracker = Box::pin(crate::properties::PropertyTracker::default());
|
let tracker = Box::pin(crate::properties::PropertyTracker::default());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tracker.as_ref().evaluate(|| {
|
tracker.as_ref().evaluate(|| {
|
||||||
|
@ -1028,7 +1010,7 @@ fn test_tracking_model_handle() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_data_tracking() {
|
fn test_data_tracking() {
|
||||||
let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));
|
let model: Rc<VecModel<u8>> = Rc::new(VecModel::from(vec![0, 1, 2, 3, 4]));
|
||||||
let handle = ModelHandle::new(model.clone());
|
let handle = ModelRc::new(model.clone());
|
||||||
let tracker = Box::pin(crate::properties::PropertyTracker::default());
|
let tracker = Box::pin(crate::properties::PropertyTracker::default());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tracker.as_ref().evaluate(|| {
|
tracker.as_ref().evaluate(|| {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use sixtyfps_compilerlib::langtype::Type as LangType;
|
use sixtyfps_compilerlib::langtype::Type as LangType;
|
||||||
use sixtyfps_corelib::graphics::Image;
|
use sixtyfps_corelib::graphics::Image;
|
||||||
use sixtyfps_corelib::model::{Model, ModelHandle};
|
use sixtyfps_corelib::model::{Model, ModelRc};
|
||||||
use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector};
|
use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -92,7 +92,7 @@ pub enum Value {
|
||||||
/// Correspond to the `image` type in .60
|
/// Correspond to the `image` type in .60
|
||||||
Image(Image),
|
Image(Image),
|
||||||
/// A model (that includes array in .60)
|
/// A model (that includes array in .60)
|
||||||
Model(ModelHandle<Value>),
|
Model(ModelRc<Value>),
|
||||||
/// An object
|
/// An object
|
||||||
Struct(Struct),
|
Struct(Struct),
|
||||||
/// Correspond to `brush` or `color` type in .60. For color, this is then a [`Brush::SolidColor`]
|
/// Correspond to `brush` or `color` type in .60. For color, this is then a [`Brush::SolidColor`]
|
||||||
|
@ -144,11 +144,7 @@ impl PartialEq for Value {
|
||||||
Value::Image(lhs) => matches!(other, Value::Image(rhs) if lhs == rhs),
|
Value::Image(lhs) => matches!(other, Value::Image(rhs) if lhs == rhs),
|
||||||
Value::Model(lhs) => {
|
Value::Model(lhs) => {
|
||||||
if let Value::Model(rhs) = other {
|
if let Value::Model(rhs) = other {
|
||||||
match (&lhs.0, &rhs.0) {
|
lhs == rhs
|
||||||
(None, None) => true,
|
|
||||||
(None, Some(_)) | (Some(_), None) => false,
|
|
||||||
(Some(a), Some(b)) => Rc::ptr_eq(a, b),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -1364,13 +1360,13 @@ fn component_definition_model_properties() {
|
||||||
|
|
||||||
let instance = comp_def.create();
|
let instance = comp_def.create();
|
||||||
|
|
||||||
let int_model = Value::Model(ModelHandle::new(Rc::new(VecModel::from_slice(&[
|
let int_model = Value::Model(ModelRc::new(Rc::new(VecModel::from_slice(&[
|
||||||
Value::Number(14.),
|
Value::Number(14.),
|
||||||
Value::Number(15.),
|
Value::Number(15.),
|
||||||
Value::Number(16.),
|
Value::Number(16.),
|
||||||
]))));
|
]))));
|
||||||
let empty_model = Value::Model(ModelHandle::new(Rc::new(VecModel::<Value>::default())));
|
let empty_model = Value::Model(ModelRc::new(Rc::new(VecModel::<Value>::default())));
|
||||||
let model_with_string = Value::Model(ModelHandle::new(Rc::new(VecModel::from_slice(&[
|
let model_with_string = Value::Model(ModelRc::new(Rc::new(VecModel::from_slice(&[
|
||||||
Value::Number(1000.),
|
Value::Number(1000.),
|
||||||
Value::String("foo".into()),
|
Value::String("foo".into()),
|
||||||
Value::Number(1111.),
|
Value::Number(1111.),
|
||||||
|
|
|
@ -1355,9 +1355,7 @@ pub fn instantiate(
|
||||||
InstanceRef::from_pin_ref(c, guard)
|
InstanceRef::from_pin_ref(c, guard)
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
sixtyfps_corelib::model::ModelHandle(Some(Rc::new(
|
sixtyfps_corelib::model::ModelRc::new(Rc::new(crate::value_model::ValueModel::new(m)))
|
||||||
crate::value_model::ValueModel::new(m),
|
|
||||||
)))
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use core::convert::TryInto;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use corelib::graphics::{GradientStop, LinearGradientBrush, PathElement};
|
use corelib::graphics::{GradientStop, LinearGradientBrush, PathElement};
|
||||||
use corelib::items::{ItemRef, PropertyAnimation};
|
use corelib::items::{ItemRef, PropertyAnimation};
|
||||||
use corelib::model::{Model, ModelHandle};
|
use corelib::model::{Model, ModelRc};
|
||||||
use corelib::rtti::AnimatedBindingKind;
|
use corelib::rtti::AnimatedBindingKind;
|
||||||
use corelib::window::{WindowHandleAccess, WindowRc};
|
use corelib::window::{WindowHandleAccess, WindowRc};
|
||||||
use corelib::{Brush, Color, PathData, SharedString, SharedVector};
|
use corelib::{Brush, Color, PathData, SharedString, SharedVector};
|
||||||
|
@ -568,10 +568,10 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Array { values, .. } => Value::Model(
|
Expression::Array { values, .. } => Value::Model(
|
||||||
ModelHandle::new(Rc::new(corelib::model::SharedVectorModel::from(
|
ModelRc::new(Rc::new(corelib::model::SharedVectorModel::from(
|
||||||
values.iter().map(|e| eval_expression(e, local_context)).collect::<SharedVector<_>>()
|
values.iter().map(|e| eval_expression(e, local_context)).collect::<SharedVector<_>>()
|
||||||
)) as Rc<dyn corelib::model::Model<Data = Value>>)
|
)
|
||||||
),
|
))),
|
||||||
Expression::Struct { values, .. } => Value::Struct(
|
Expression::Struct { values, .. } => Value::Struct(
|
||||||
values
|
values
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -85,7 +85,7 @@ pub unsafe extern "C" fn sixtyfps_interpreter_value_new_array_model(
|
||||||
let vec = std::mem::transmute::<SharedVector<ValueOpaque>, SharedVector<Value>>(a.clone());
|
let vec = std::mem::transmute::<SharedVector<ValueOpaque>, SharedVector<Value>>(a.clone());
|
||||||
std::ptr::write(
|
std::ptr::write(
|
||||||
val as *mut Value,
|
val as *mut Value,
|
||||||
Value::Model(ModelHandle::new(Rc::new(SharedVectorModel::<Value>::from(vec)))),
|
Value::Model(ModelRc::new(Rc::new(SharedVectorModel::<Value>::from(vec)))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ pub unsafe extern "C" fn sixtyfps_interpreter_value_new_model(
|
||||||
) {
|
) {
|
||||||
std::ptr::write(
|
std::ptr::write(
|
||||||
val as *mut Value,
|
val as *mut Value,
|
||||||
Value::Model(ModelHandle::new(Rc::new(ModelAdaptorWrapper(model)))),
|
Value::Model(ModelRc::new(Rc::new(ModelAdaptorWrapper(model)))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ assert(!instance.get_hover());
|
||||||
use sixtyfps::Model;
|
use sixtyfps::Model;
|
||||||
let instance = TestCase::new();
|
let instance = TestCase::new();
|
||||||
let vec_model = std::rc::Rc::new(sixtyfps::VecModel::from(vec![1i32, 2i32]));
|
let vec_model = std::rc::Rc::new(sixtyfps::VecModel::from(vec![1i32, 2i32]));
|
||||||
instance.set_model(sixtyfps::ModelHandle::from(vec_model.clone() as std::rc::Rc<dyn Model<Data = i32>>));
|
instance.set_model(sixtyfps::ModelRc::new(vec_model.clone() as std::rc::Rc<dyn Model<Data = i32>>));
|
||||||
instance.on_clicked(move || dbg!(vec_model.remove(vec_model.row_count() - 1)));
|
instance.on_clicked(move || dbg!(vec_model.remove(vec_model.row_count() - 1)));
|
||||||
sixtyfps::testing::send_mouse_click(&instance, 95., 5.);
|
sixtyfps::testing::send_mouse_click(&instance, 95., 5.);
|
||||||
assert_eq!(instance.get_model().row_count(), 1);
|
assert_eq!(instance.get_model().row_count(), 1);
|
||||||
|
|
|
@ -43,7 +43,7 @@ assert_eq!(instance.get_n(), 4);
|
||||||
assert_eq!(instance.get_third_int(), 3);
|
assert_eq!(instance.get_third_int(), 3);
|
||||||
|
|
||||||
let model: std::rc::Rc<sixtyfps::VecModel<i32>> = std::rc::Rc::new(vec![1, 2, 3, 4, 5, 6, 7].into());
|
let model: std::rc::Rc<sixtyfps::VecModel<i32>> = std::rc::Rc::new(vec![1, 2, 3, 4, 5, 6, 7].into());
|
||||||
instance.set_ints(sixtyfps::ModelHandle::new(model.clone()));
|
instance.set_ints(sixtyfps::ModelRc::new(model.clone()));
|
||||||
assert_eq!(instance.get_num_ints(), 7);
|
assert_eq!(instance.get_num_ints(), 7);
|
||||||
assert_eq!(instance.get_third_int(), 3);
|
assert_eq!(instance.get_third_int(), 3);
|
||||||
model.push(8);
|
model.push(8);
|
||||||
|
|
|
@ -62,7 +62,7 @@ let another_model = std::rc::Rc::new(sixtyfps::VecModel::<ModelData>::from(
|
||||||
("a3".into(), "world".into(), 333.),
|
("a3".into(), "world".into(), 333.),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
instance.set_model(sixtyfps::ModelHandle::new(another_model.clone()));
|
instance.set_model(sixtyfps::ModelRc::new(another_model.clone()));
|
||||||
|
|
||||||
sixtyfps::testing::send_mouse_click(&instance, 25., 5.);
|
sixtyfps::testing::send_mouse_click(&instance, 25., 5.);
|
||||||
assert_eq!(instance.get_clicked_score(), 333000);
|
assert_eq!(instance.get_clicked_score(), 333000);
|
||||||
|
|
|
@ -61,7 +61,7 @@ let another_model = std::rc::Rc::new(sixtyfps::VecModel::<ModelData>::from(
|
||||||
("a3".into(), "world".into(), 333.),
|
("a3".into(), "world".into(), 333.),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
instance.set_model(sixtyfps::ModelHandle::new(another_model.clone()));
|
instance.set_model(sixtyfps::ModelRc::new(another_model.clone()));
|
||||||
|
|
||||||
sixtyfps::testing::send_mouse_click(&instance, 25., 5.);
|
sixtyfps::testing::send_mouse_click(&instance, 25., 5.);
|
||||||
assert_eq!(instance.get_clicked_score(), 336);
|
assert_eq!(instance.get_clicked_score(), 336);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#![doc = include_str!("README.md")]
|
#![doc = include_str!("README.md")]
|
||||||
|
|
||||||
use sixtyfps_corelib::model::{Model, ModelHandle};
|
use sixtyfps_corelib::model::{Model, ModelRc};
|
||||||
use sixtyfps_corelib::SharedVector;
|
use sixtyfps_corelib::SharedVector;
|
||||||
use sixtyfps_interpreter::{ComponentInstance, SharedString, Value};
|
use sixtyfps_interpreter::{ComponentInstance, SharedString, Value};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
@ -268,12 +268,9 @@ fn load_data(instance: &ComponentInstance, data_path: &std::path::Path) -> Resul
|
||||||
}
|
}
|
||||||
serde_json::Value::String(s) => SharedString::from(s.as_str()).into(),
|
serde_json::Value::String(s) => SharedString::from(s.as_str()).into(),
|
||||||
serde_json::Value::Array(array) => sixtyfps_interpreter::Value::Model(
|
serde_json::Value::Array(array) => sixtyfps_interpreter::Value::Model(
|
||||||
ModelHandle::new(Rc::new(sixtyfps_corelib::model::SharedVectorModel::from(
|
ModelRc::new(Rc::new(sixtyfps_corelib::model::SharedVectorModel::from(
|
||||||
array.iter().map(from_json).collect::<SharedVector<Value>>(),
|
array.iter().map(from_json).collect::<SharedVector<Value>>(),
|
||||||
))
|
))),
|
||||||
as Rc<
|
|
||||||
dyn sixtyfps_corelib::model::Model<Data = sixtyfps_interpreter::Value>,
|
|
||||||
>),
|
|
||||||
),
|
),
|
||||||
serde_json::Value::Object(obj) => obj
|
serde_json::Value::Object(obj) => obj
|
||||||
.iter()
|
.iter()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue