C++ live-reload: support getting the model back

This commit is contained in:
Olivier Goffart 2025-07-09 09:12:09 +02:00
parent 43b436a89f
commit 01850e0b82
4 changed files with 67 additions and 18 deletions

View file

@ -82,13 +82,9 @@ inline interpreter::Value into_slint_value(const long int &val)
} }
template<typename ModelData> template<typename ModelData>
inline std::shared_ptr<slint::Model<ModelData>> std::shared_ptr<slint::Model<ModelData>>
from_slint_value(const slint::interpreter::Value &, from_slint_value(const slint::interpreter::Value &,
const std::shared_ptr<slint::Model<ModelData>> *) const std::shared_ptr<slint::Model<ModelData>> *);
{
std::cout << "NOT IMPLEMENTED " << __PRETTY_FUNCTION__ << std::endl;
return {};
}
template<typename ModelData> template<typename ModelData>
slint::interpreter::Value into_slint_value(const std::shared_ptr<slint::Model<ModelData>> &val); slint::interpreter::Value into_slint_value(const std::shared_ptr<slint::Model<ModelData>> &val);
@ -297,11 +293,28 @@ protected:
return interpreter::Value(cbindgen_private::slint_interpreter_value_new_model( return interpreter::Value(cbindgen_private::slint_interpreter_value_new_model(
reinterpret_cast<uint8_t *>(wrapper.get()), vtable())); reinterpret_cast<uint8_t *>(wrapper.get()), vtable()));
} }
public:
// get the model wrapper from a value (or nullptr if the value don't contain a model)
static const LiveReloadModelWrapperBase *get(const slint::interpreter::Value &value)
{
if (auto model =
cbindgen_private::slint_interpreter_value_to_model(value.inner, vtable())) {
return reinterpret_cast<const LiveReloadModelWrapperBase *>(model);
} else {
return nullptr;
}
}
}; };
template<typename ModelData> template<typename ModelData>
class LiveReloadModelWrapper : public LiveReloadModelWrapperBase class LiveReloadModelWrapper : public LiveReloadModelWrapperBase
{ {
public:
LiveReloadModelWrapper(std::shared_ptr<slint::Model<ModelData>> model) : model(std::move(model))
{
}
std::shared_ptr<slint::Model<ModelData>> model = nullptr; std::shared_ptr<slint::Model<ModelData>> model = nullptr;
int row_count() const override { return model->row_count(); } int row_count() const override { return model->row_count(); }
@ -319,11 +332,6 @@ class LiveReloadModelWrapper : public LiveReloadModelWrapperBase
model->set_row_data(i, from_slint_value<ModelData>(value)); model->set_row_data(i, from_slint_value<ModelData>(value));
} }
public:
LiveReloadModelWrapper(std::shared_ptr<slint::Model<ModelData>> model) : model(std::move(model))
{
}
static slint::interpreter::Value wrap(std::shared_ptr<slint::Model<ModelData>> model) static slint::interpreter::Value wrap(std::shared_ptr<slint::Model<ModelData>> model)
{ {
auto self = std::make_shared<LiveReloadModelWrapper<ModelData>>(model); auto self = std::make_shared<LiveReloadModelWrapper<ModelData>>(model);
@ -342,6 +350,19 @@ slint::interpreter::Value into_slint_value(const std::shared_ptr<slint::Model<Mo
return LiveReloadModelWrapper<ModelData>::wrap(val); return LiveReloadModelWrapper<ModelData>::wrap(val);
} }
template<typename ModelData>
std::shared_ptr<slint::Model<ModelData>>
from_slint_value(const slint::interpreter::Value &value,
const std::shared_ptr<slint::Model<ModelData>> *)
{
if (const LiveReloadModelWrapperBase *base = LiveReloadModelWrapperBase::get(value)) {
if (auto wrapper = dynamic_cast<const LiveReloadModelWrapper<ModelData> *>(base)) {
return wrapper->model;
}
}
return {};
}
} // namespace slint::private_api::live_reload } // namespace slint::private_api::live_reload
#endif // SLINT_FEATURE_LIVE_RELOAD #endif // SLINT_FEATURE_LIVE_RELOAD

View file

@ -441,6 +441,12 @@ fn convert_to_value_fn(ty: &Type) -> String {
}); });
format!("([](const auto &tuple) {{ slint::interpreter::Struct s; {}return slint::interpreter::Value(s); }})", init.join("")) format!("([](const auto &tuple) {{ slint::interpreter::Struct s; {}return slint::interpreter::Value(s); }})", init.join(""))
} }
// Array of anonymous struct
Type::Array(a) if matches!(a.as_ref(), Type::Struct(s) if s.name.is_none()) => {
let conf_fn = convert_to_value_fn(&a);
let aty = a.cpp_type().unwrap();
format!("([](const auto &model) {{ return slint::interpreter::Value(std::make_shared<slint::MapModel<{aty}, slint::interpreter::Value>>(model, {conf_fn})); }})")
}
_ => "into_slint_value".into(), _ => "into_slint_value".into(),
} }
} }

View file

@ -91,6 +91,24 @@ pub unsafe extern "C" fn slint_interpreter_value_new_model(
))))) )))))
} }
/// If the value contains a model set from [`slint_interpreter_value_new_model]` with the same vtable pointer,
/// return the model that was set.
/// Returns a null ptr otherwise
#[unsafe(no_mangle)]
pub extern "C" fn slint_interpreter_value_to_model(
val: &Value,
vtable: &ModelAdaptorVTable,
) -> *const u8 {
if let Value::Model(m) = val {
if let Some(m) = m.as_any().downcast_ref::<ModelAdaptorWrapper>() {
if core::ptr::eq(m.0.get_vtable() as *const _, vtable as *const _) {
return m.0.as_ptr();
}
}
}
core::ptr::null()
}
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub unsafe extern "C" fn slint_interpreter_value_type(val: &Value) -> ValueType { pub unsafe extern "C" fn slint_interpreter_value_type(val: &Value) -> ValueType {
val.value_type() val.value_type()
@ -575,6 +593,10 @@ impl Model for ModelAdaptorWrapper {
let val = Box::new(data); let val = Box::new(data);
self.0.set_row_data(row, val); self.0.set_row_data(row, val);
} }
fn as_any(&self) -> &dyn core::any::Any {
self
}
} }
#[repr(C)] #[repr(C)]

View file

@ -312,7 +312,7 @@ mod ffi {
use i_slint_core::{slice::Slice, SharedString, SharedVector}; use i_slint_core::{slice::Slice, SharedString, SharedVector};
type LiveReloadingComponentInner = RefCell<LiveReloadingComponent>; type LiveReloadingComponentInner = RefCell<LiveReloadingComponent>;
#[no_mangle] #[unsafe(no_mangle)]
/// LibraryPath is an array of string that have in the form `lib=...` /// LibraryPath is an array of string that have in the form `lib=...`
pub extern "C" fn slint_live_reload_new( pub extern "C" fn slint_live_reload_new(
file_name: Slice<u8>, file_name: Slice<u8>,
@ -345,19 +345,19 @@ mod ffi {
) )
} }
#[no_mangle] #[unsafe(no_mangle)]
pub unsafe extern "C" fn slint_live_reload_clone( pub unsafe extern "C" fn slint_live_reload_clone(
component: *const LiveReloadingComponentInner, component: *const LiveReloadingComponentInner,
) { ) {
Rc::increment_strong_count(component); Rc::increment_strong_count(component);
} }
#[no_mangle] #[unsafe(no_mangle)]
pub unsafe extern "C" fn slint_live_reload_drop(component: *const LiveReloadingComponentInner) { pub unsafe extern "C" fn slint_live_reload_drop(component: *const LiveReloadingComponentInner) {
Rc::decrement_strong_count(component); Rc::decrement_strong_count(component);
} }
#[no_mangle] #[unsafe(no_mangle)]
pub extern "C" fn slint_live_reload_set_property( pub extern "C" fn slint_live_reload_set_property(
component: &LiveReloadingComponentInner, component: &LiveReloadingComponentInner,
property: Slice<u8>, property: Slice<u8>,
@ -371,7 +371,7 @@ mod ffi {
} }
} }
#[no_mangle] #[unsafe(no_mangle)]
pub extern "C" fn slint_live_reload_get_property( pub extern "C" fn slint_live_reload_get_property(
component: &LiveReloadingComponentInner, component: &LiveReloadingComponentInner,
property: Slice<u8>, property: Slice<u8>,
@ -385,7 +385,7 @@ mod ffi {
Box::into_raw(Box::new(val)) Box::into_raw(Box::new(val))
} }
#[no_mangle] #[unsafe(no_mangle)]
pub extern "C" fn slint_live_reload_invoke( pub extern "C" fn slint_live_reload_invoke(
component: &LiveReloadingComponentInner, component: &LiveReloadingComponentInner,
callback: Slice<u8>, callback: Slice<u8>,
@ -401,7 +401,7 @@ mod ffi {
Box::into_raw(Box::new(val)) Box::into_raw(Box::new(val))
} }
#[no_mangle] #[unsafe(no_mangle)]
pub unsafe extern "C" fn slint_live_reload_set_callback( pub unsafe extern "C" fn slint_live_reload_set_callback(
component: &LiveReloadingComponentInner, component: &LiveReloadingComponentInner,
callback: Slice<u8>, callback: Slice<u8>,