mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21:16 +00:00
ComponentDefinition::create in C++
Note thate there is a hack so `ComponentHandle<ComponentInstance>` (which is binary compatible with `VRc<ComponentVTable, ErasedComponentBox>` works
This commit is contained in:
parent
3ad41a551b
commit
f2ffc0ebf6
2 changed files with 85 additions and 19 deletions
|
@ -15,6 +15,15 @@ LICENSE END */
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
namespace sixtyfps::cbindgen_private {
|
||||||
|
// This has to stay opaque, but VRc don't compile if it is just forward declared
|
||||||
|
struct ErasedComponentBox : vtable::Dyn {
|
||||||
|
~ErasedComponentBox() = delete;
|
||||||
|
ErasedComponentBox() = delete;
|
||||||
|
ErasedComponentBox(ErasedComponentBox&) = delete;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace sixtyfps::interpreter {
|
namespace sixtyfps::interpreter {
|
||||||
|
|
||||||
class Value;
|
class Value;
|
||||||
|
@ -349,21 +358,25 @@ inline void Struct::set_field(std::string_view name, const Value &value)
|
||||||
cbindgen_private::sixtyfps_interpreter_struct_set_field(&inner, name_view, &value.inner);
|
cbindgen_private::sixtyfps_interpreter_struct_set_field(&inner, name_view, &value.inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentInstance
|
class ComponentInstance : vtable::Dyn
|
||||||
{
|
{
|
||||||
cbindgen_private::ComponentInstance inner;
|
|
||||||
ComponentInstance() = delete;
|
ComponentInstance() = delete;
|
||||||
ComponentInstance(ComponentInstance &) = delete;
|
ComponentInstance(ComponentInstance &) = delete;
|
||||||
ComponentInstance &operator=(ComponentInstance &) = delete;
|
ComponentInstance &operator=(ComponentInstance &) = delete;
|
||||||
|
friend class ComponentDefinition;
|
||||||
|
|
||||||
|
// ComponentHandle<ComponentInstance> is in fact a VRc<ComponentVTable, ErasedComponentBox>
|
||||||
|
const cbindgen_private::ErasedComponentBox *inner() const
|
||||||
|
{ return reinterpret_cast<const cbindgen_private::ErasedComponentBox *>(this); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void show() const
|
void show() const
|
||||||
{
|
{
|
||||||
cbindgen_private::sixtyfps_interpreter_component_instance_show(&inner, true);
|
cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), true);
|
||||||
}
|
}
|
||||||
void hide() const
|
void hide() const
|
||||||
{
|
{
|
||||||
cbindgen_private::sixtyfps_interpreter_component_instance_show(&inner, false);
|
cbindgen_private::sixtyfps_interpreter_component_instance_show(inner(), false);
|
||||||
}
|
}
|
||||||
void run() const
|
void run() const
|
||||||
{
|
{
|
||||||
|
@ -376,14 +389,14 @@ public:
|
||||||
{
|
{
|
||||||
using namespace cbindgen_private;
|
using namespace cbindgen_private;
|
||||||
return sixtyfps_interpreter_component_instance_set_property(
|
return sixtyfps_interpreter_component_instance_set_property(
|
||||||
&inner, sixtyfps::private_api::string_to_slice(name), &value.inner);
|
inner(), sixtyfps::private_api::string_to_slice(name), &value.inner);
|
||||||
}
|
}
|
||||||
std::optional<Value> get_property(std::string_view name) const
|
std::optional<Value> get_property(std::string_view name) const
|
||||||
{
|
{
|
||||||
using namespace cbindgen_private;
|
using namespace cbindgen_private;
|
||||||
ValueOpaque out;
|
ValueOpaque out;
|
||||||
if (sixtyfps_interpreter_component_instance_get_property(
|
if (sixtyfps_interpreter_component_instance_get_property(
|
||||||
&inner, sixtyfps::private_api::string_to_slice(name), &out)) {
|
inner(), sixtyfps::private_api::string_to_slice(name), &out)) {
|
||||||
return Value(out);
|
return Value(out);
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
|
@ -396,7 +409,7 @@ public:
|
||||||
Slice<ValueOpaque> args_view { reinterpret_cast<ValueOpaque *>(args.ptr), args.len };
|
Slice<ValueOpaque> args_view { reinterpret_cast<ValueOpaque *>(args.ptr), args.len };
|
||||||
ValueOpaque out;
|
ValueOpaque out;
|
||||||
if (sixtyfps_interpreter_component_instance_invoke_callback(
|
if (sixtyfps_interpreter_component_instance_invoke_callback(
|
||||||
&inner, sixtyfps::private_api::string_to_slice(name), args_view, &out)) {
|
inner(), sixtyfps::private_api::string_to_slice(name), args_view, &out)) {
|
||||||
return Value(out);
|
return Value(out);
|
||||||
} else {
|
} else {
|
||||||
return {};
|
return {};
|
||||||
|
@ -413,7 +426,7 @@ public:
|
||||||
new (ret) Value(std::move(r));
|
new (ret) Value(std::move(r));
|
||||||
};
|
};
|
||||||
return cbindgen_private::sixtyfps_interpreter_component_instance_set_callback(
|
return cbindgen_private::sixtyfps_interpreter_component_instance_set_callback(
|
||||||
&inner, sixtyfps::private_api::string_to_slice(name), actual_cb,
|
inner(), sixtyfps::private_api::string_to_slice(name), actual_cb,
|
||||||
new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });
|
new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -447,6 +460,19 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
~ComponentDefinition() { sixtyfps_interpreter_component_definition_destructor(&inner); }
|
~ComponentDefinition() { sixtyfps_interpreter_component_definition_destructor(&inner); }
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentHandle<ComponentInstance> create() const {
|
||||||
|
union CI {
|
||||||
|
cbindgen_private::ComponentInstance i;
|
||||||
|
~CI() {
|
||||||
|
i.~ComponentInstance();
|
||||||
|
}
|
||||||
|
CI() {}
|
||||||
|
} u;
|
||||||
|
cbindgen_private::sixtyfps_interpreter_component_instance_create(&inner, &u.i);
|
||||||
|
return *reinterpret_cast<ComponentHandle<ComponentInstance> *>(&u.i);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ComponentCompiler
|
class ComponentCompiler
|
||||||
|
|
|
@ -765,6 +765,8 @@ pub mod testing {
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub(crate) mod ffi {
|
pub(crate) mod ffi {
|
||||||
|
use crate::dynamic_component::ErasedComponentBox;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use sixtyfps_corelib::model::{Model, ModelNotify, ModelPeer};
|
use sixtyfps_corelib::model::{Model, ModelNotify, ModelPeer};
|
||||||
use sixtyfps_corelib::slice::Slice;
|
use sixtyfps_corelib::slice::Slice;
|
||||||
|
@ -1073,11 +1075,13 @@ pub(crate) mod ffi {
|
||||||
/// to the resulting value. If this function returns false, out is unchanged
|
/// to the resulting value. If this function returns false, out is unchanged
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_get_property(
|
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_get_property(
|
||||||
inst: &ComponentInstance,
|
inst: &ErasedComponentBox,
|
||||||
name: Slice<u8>,
|
name: Slice<u8>,
|
||||||
out: *mut ValueOpaque,
|
out: *mut ValueOpaque,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match inst.get_property(std::str::from_utf8(&name).unwrap()) {
|
generativity::make_guard!(guard);
|
||||||
|
let comp = inst.unerase(guard);
|
||||||
|
match comp.description().get_property(comp.borrow(), std::str::from_utf8(&name).unwrap()) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
std::ptr::write(out as *mut Value, val);
|
std::ptr::write(out as *mut Value, val);
|
||||||
true
|
true
|
||||||
|
@ -1088,11 +1092,19 @@ pub(crate) mod ffi {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn sixtyfps_interpreter_component_instance_set_property(
|
pub extern "C" fn sixtyfps_interpreter_component_instance_set_property(
|
||||||
inst: &ComponentInstance,
|
inst: &ErasedComponentBox,
|
||||||
name: Slice<u8>,
|
name: Slice<u8>,
|
||||||
val: &ValueOpaque,
|
val: &ValueOpaque,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
inst.set_property(std::str::from_utf8(&name).unwrap(), val.as_value().clone()).is_ok()
|
generativity::make_guard!(guard);
|
||||||
|
let comp = inst.unerase(guard);
|
||||||
|
comp.description()
|
||||||
|
.set_property(
|
||||||
|
comp.borrow(),
|
||||||
|
std::str::from_utf8(&name).unwrap(),
|
||||||
|
val.as_value().clone(),
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invoke a callback.
|
/// Invoke a callback.
|
||||||
|
@ -1100,13 +1112,19 @@ pub(crate) mod ffi {
|
||||||
/// to the resulting value. If this function returns false, out is unchanged
|
/// to the resulting value. If this function returns false, out is unchanged
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_invoke_callback(
|
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_invoke_callback(
|
||||||
inst: &ComponentInstance,
|
inst: &ErasedComponentBox,
|
||||||
name: Slice<u8>,
|
name: Slice<u8>,
|
||||||
args: Slice<ValueOpaque>,
|
args: Slice<ValueOpaque>,
|
||||||
out: *mut ValueOpaque,
|
out: *mut ValueOpaque,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let args = std::mem::transmute::<Slice<ValueOpaque>, Slice<Value>>(args);
|
let args = std::mem::transmute::<Slice<ValueOpaque>, Slice<Value>>(args);
|
||||||
match inst.invoke_callback(std::str::from_utf8(&name).unwrap(), args.as_slice()) {
|
generativity::make_guard!(guard);
|
||||||
|
let comp = inst.unerase(guard);
|
||||||
|
match comp.description().invoke_callback(
|
||||||
|
comp.borrow(),
|
||||||
|
std::str::from_utf8(&name).unwrap(),
|
||||||
|
args.as_slice(),
|
||||||
|
) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
std::ptr::write(out as *mut Value, val);
|
std::ptr::write(out as *mut Value, val);
|
||||||
true
|
true
|
||||||
|
@ -1119,7 +1137,7 @@ pub(crate) mod ffi {
|
||||||
/// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function)
|
/// The `callback` function must initialize the `ret` (the `ret` passed to the callback is initialized and is assumed initialized after the function)
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_set_callback(
|
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_set_callback(
|
||||||
inst: &ComponentInstance,
|
inst: &ErasedComponentBox,
|
||||||
name: Slice<u8>,
|
name: Slice<u8>,
|
||||||
callback: extern "C" fn(
|
callback: extern "C" fn(
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
|
@ -1150,22 +1168,44 @@ pub(crate) mod ffi {
|
||||||
ret.assume_init()
|
ret.assume_init()
|
||||||
};
|
};
|
||||||
|
|
||||||
inst.set_callback(std::str::from_utf8(&name).unwrap(), callback).is_ok()
|
generativity::make_guard!(guard);
|
||||||
|
let comp = inst.unerase(guard);
|
||||||
|
comp.description()
|
||||||
|
.set_callback_handler(
|
||||||
|
comp.borrow(),
|
||||||
|
std::str::from_utf8(&name).unwrap(),
|
||||||
|
Box::new(callback),
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show or hide
|
/// Show or hide
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn sixtyfps_interpreter_component_instance_show(
|
pub extern "C" fn sixtyfps_interpreter_component_instance_show(
|
||||||
inst: &ComponentInstance,
|
inst: &ErasedComponentBox,
|
||||||
is_visible: bool,
|
is_visible: bool,
|
||||||
) {
|
) {
|
||||||
|
generativity::make_guard!(guard);
|
||||||
|
let comp = inst.unerase(guard);
|
||||||
if is_visible {
|
if is_visible {
|
||||||
inst.show();
|
comp.window().show();
|
||||||
} else {
|
} else {
|
||||||
inst.hide();
|
comp.window().hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instantiate an instance from a definition.
|
||||||
|
///
|
||||||
|
/// The `out` must be uninitialized and is going to be initialized after the call
|
||||||
|
/// and need to be destroyed with sixtyfps_interpreter_component_instance_destructor
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn sixtyfps_interpreter_component_instance_create(
|
||||||
|
def: &ComponentDefinitionOpaque,
|
||||||
|
out: *mut ComponentInstance,
|
||||||
|
) {
|
||||||
|
std::ptr::write(out, def.as_component_definition().create())
|
||||||
|
}
|
||||||
|
|
||||||
#[vtable::vtable]
|
#[vtable::vtable]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ModelAdaptorVTable {
|
pub struct ModelAdaptorVTable {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue