slint/api/node/native/js_model.rs
Tobias Hunger de4e195280
Rename internal crates and add a README.md to them
The README.md contains the warning that used to be in lib.rs.

Add README.md files to all internal crates

... pointing to the official public crate to use instead.

Rename internal crates

fixup: README files

fixup rename
2022-02-07 13:12:48 +01:00

148 lines
5.1 KiB
Rust

// Copyright © SixtyFPS GmbH <info@sixtyfps.io>
// SPDX-License-Identifier: (GPL-3.0-only OR LicenseRef-SixtyFPS-commercial)
use i_slint_compiler::langtype::Type;
use i_slint_core::model::Model;
use neon::prelude::*;
use std::cell::Cell;
use std::rc::{Rc, Weak};
/// Model coming from JS
pub struct JsModel {
notify: i_slint_core::model::ModelNotify,
/// The index of the value in the PersistentContext
value_index: u32,
data_type: Type,
}
impl JsModel {
pub fn new<'cx>(
obj: Handle<'cx, JsObject>,
data_type: Type,
cx: &mut impl Context<'cx>,
persistent_context: &crate::persistent_context::PersistentContext<'cx>,
) -> NeonResult<Rc<Self>> {
let val = obj.as_value(cx);
let model = Rc::new(JsModel {
notify: Default::default(),
value_index: persistent_context.allocate(cx, val),
data_type,
});
let mut notify = SlintModelNotify::new::<_, JsValue, _>(cx, std::iter::empty())?;
cx.borrow_mut(&mut notify, |mut notify| notify.0 = Rc::downgrade(&model));
let notify = notify.as_value(cx);
obj.set(cx, "notify", notify)?;
Ok(model)
}
pub fn get_object<'cx>(
&self,
cx: &mut impl Context<'cx>,
persistent_context: &crate::persistent_context::PersistentContext<'cx>,
) -> JsResult<'cx, JsObject> {
persistent_context.get(cx, self.value_index)?.downcast_or_throw(cx)
}
}
impl Model for JsModel {
type Data = slint_interpreter::Value;
fn row_count(&self) -> usize {
let r = Cell::new(0usize);
crate::run_with_global_context(&|cx, persistent_context| {
let obj = self.get_object(cx, persistent_context).unwrap();
let _ = obj
.get(cx, "rowCount")
.ok()
.and_then(|func| func.downcast::<JsFunction>().ok())
.and_then(|func| func.call(cx, obj, std::iter::empty::<Handle<JsValue>>()).ok())
.and_then(|res| res.downcast::<JsNumber>().ok())
.map(|num| r.set(num.value() as _));
});
r.get()
}
fn row_data(&self, row: usize) -> Option<Self::Data> {
if row >= self.row_count() {
None
} else {
let r = Cell::new(slint_interpreter::Value::default());
crate::run_with_global_context(&|cx, persistent_context| {
let row = JsNumber::new(cx, row as f64);
let obj = self.get_object(cx, persistent_context).unwrap();
let _ = obj
.get(cx, "rowData")
.ok()
.and_then(|func| func.downcast::<JsFunction>().ok())
.and_then(|func| func.call(cx, obj, std::iter::once(row)).ok())
.and_then(|res| {
crate::to_eval_value(res, self.data_type.clone(), cx, persistent_context)
.ok()
})
.map(|res| r.set(res));
});
Some(r.into_inner())
}
}
fn model_tracker(&self) -> &dyn i_slint_core::model::ModelTracker {
&self.notify
}
fn set_row_data(&self, row: usize, data: Self::Data) {
crate::run_with_global_context(&|cx, persistent_context| {
let row = JsNumber::new(cx, row as f64).as_value(cx);
let data = crate::to_js_value(data.clone(), cx, persistent_context).unwrap();
let obj = self.get_object(cx, persistent_context).unwrap();
let _ = obj
.get(cx, "setRowData")
.ok()
.and_then(|func| func.downcast::<JsFunction>().ok())
.and_then(|func| func.call(cx, obj, [row, data].iter().cloned()).ok());
});
}
fn as_any(&self) -> &dyn core::any::Any {
self
}
}
struct WrappedJsModel(Weak<JsModel>);
declare_types! {
class SlintModelNotify for WrappedJsModel {
init(_) {
Ok(WrappedJsModel(Weak::default()))
}
method rowDataChanged(mut cx) {
let this = cx.this();
let row = cx.argument::<JsNumber>(0)?.value() as usize;
if let Some(model) = cx.borrow(&this, |x| x.0.upgrade()) {
model.notify.row_changed(row)
}
Ok(JsUndefined::new().as_value(&mut cx))
}
method rowAdded(mut cx) {
let this = cx.this();
let row = cx.argument::<JsNumber>(0)?.value() as usize;
let count = cx.argument::<JsNumber>(1)?.value() as usize;
if let Some(model) = cx.borrow(&this, |x| x.0.upgrade()) {
model.notify.row_added(row, count)
}
Ok(JsUndefined::new().as_value(&mut cx))
}
method rowRemoved(mut cx) {
let this = cx.this();
let row = cx.argument::<JsNumber>(0)?.value() as usize;
let count = cx.argument::<JsNumber>(1)?.value() as usize;
if let Some(model) = cx.borrow(&this, |x| x.0.upgrade()) {
model.notify.row_removed(row, count)
}
Ok(JsUndefined::new().as_value(&mut cx))
}
}
}