mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 20:31:27 +00:00
Change component factory API
... to avoid winit panicing on us when embedding some item tree.
This commit is contained in:
parent
3ab98a7596
commit
d6ec7f23a1
5 changed files with 62 additions and 29 deletions
|
|
@ -5,13 +5,22 @@
|
|||
|
||||
//! This module defines a `ComponentFactory` and related code.
|
||||
use crate::api::ComponentHandle;
|
||||
use crate::item_tree::{ItemTreeRc, ItemTreeVTable};
|
||||
use crate::item_tree::{ItemTreeRc, ItemTreeVTable, ItemTreeWeak};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::fmt::Debug;
|
||||
|
||||
/// The `FactoryContext` provides extra information to the ComponentFactory
|
||||
pub struct FactoryContext {
|
||||
/// The item tree to embed the factory product into
|
||||
pub parent_item_tree: ItemTreeWeak,
|
||||
/// The index in the parent item tree with the dynamic node to connect
|
||||
/// the factories product to.
|
||||
pub parent_item_tree_index: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ComponentFactoryInner(Rc<dyn Fn() -> Option<ItemTreeRc> + 'static>);
|
||||
struct ComponentFactoryInner(Rc<dyn Fn(FactoryContext) -> Option<ItemTreeRc> + 'static>);
|
||||
|
||||
impl PartialEq for ComponentFactoryInner {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
|
|
@ -26,8 +35,9 @@ impl Debug for ComponentFactoryInner {
|
|||
}
|
||||
|
||||
/// A `ComponentFactory` can be used to create new Components at runtime,
|
||||
/// taking a factory function with no arguments and returning
|
||||
/// a [`ComponentHandle`].
|
||||
/// taking a factory function returning a [`ComponentHandle`].
|
||||
///
|
||||
/// The `FactoryContext` is passed to that factory function.
|
||||
///
|
||||
/// A `ComponentFactory` implements the `component-factory` type for
|
||||
/// properties in the Slint language.
|
||||
|
|
@ -40,20 +50,22 @@ pub struct ComponentFactory(Option<ComponentFactoryInner>);
|
|||
|
||||
impl ComponentFactory {
|
||||
/// Create a new `ComponentFactory`
|
||||
pub fn new<T: ComponentHandle + 'static>(factory: impl Fn() -> Option<T> + 'static) -> Self
|
||||
pub fn new<T: ComponentHandle + 'static>(
|
||||
factory: impl Fn(FactoryContext) -> Option<T> + 'static,
|
||||
) -> Self
|
||||
where
|
||||
T::Inner: vtable::HasStaticVTable<ItemTreeVTable> + 'static,
|
||||
{
|
||||
let factory = Box::new(factory) as Box<dyn Fn() -> Option<T> + 'static>;
|
||||
let factory = Box::new(factory) as Box<dyn Fn(FactoryContext) -> Option<T> + 'static>;
|
||||
|
||||
Self(Some(ComponentFactoryInner(Rc::new(move || -> Option<ItemTreeRc> {
|
||||
let product = (factory)();
|
||||
Self(Some(ComponentFactoryInner(Rc::new(move |ctx| -> Option<ItemTreeRc> {
|
||||
let product = (factory)(ctx);
|
||||
product.map(|p| vtable::VRc::into_dyn(p.as_weak().inner().upgrade().unwrap()))
|
||||
}))))
|
||||
}
|
||||
|
||||
/// Build a `Component`
|
||||
pub(crate) fn build(&self) -> Option<ItemTreeRc> {
|
||||
self.0.as_ref().and_then(|b| (b.0)())
|
||||
pub(crate) fn build(&self, ctx: FactoryContext) -> Option<ItemTreeRc> {
|
||||
self.0.as_ref().and_then(move |b| (b.0)(ctx))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ When adding an item or a property, it needs to be kept in sync with different pl
|
|||
Lookup the [`crate::items`] module documentation.
|
||||
*/
|
||||
use super::{Item, ItemConsts, ItemRc, Rectangle, RenderingResult};
|
||||
use crate::component_factory::ComponentFactory;
|
||||
use crate::component_factory::{ComponentFactory, FactoryContext};
|
||||
use crate::input::{
|
||||
FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent,
|
||||
KeyEventResult, MouseEvent,
|
||||
|
|
@ -77,15 +77,12 @@ impl ComponentContainer {
|
|||
return;
|
||||
};
|
||||
|
||||
let product = factory.build().and_then(|rc| {
|
||||
vtable::VRc::borrow_pin(&rc)
|
||||
.as_ref()
|
||||
.embed_component(
|
||||
self.my_component.get().unwrap(),
|
||||
*self.embedding_item_tree_index.get().unwrap(),
|
||||
)
|
||||
.then_some(rc)
|
||||
});
|
||||
let factory_context = FactoryContext {
|
||||
parent_item_tree: self.my_component.get().unwrap().clone(),
|
||||
parent_item_tree_index: *self.embedding_item_tree_index.get().unwrap(),
|
||||
};
|
||||
|
||||
let product = factory.build(factory_context);
|
||||
|
||||
if let Some(rc) = &product {
|
||||
// The change resulted in a new component to set up:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use core::convert::TryFrom;
|
||||
use i_slint_compiler::langtype::Type as LangType;
|
||||
use i_slint_core::component_factory::ComponentFactory;
|
||||
use i_slint_core::component_factory::{ComponentFactory, FactoryContext};
|
||||
use i_slint_core::graphics::Image;
|
||||
use i_slint_core::model::{Model, ModelRc};
|
||||
use i_slint_core::window::WindowInner;
|
||||
|
|
@ -668,6 +668,17 @@ impl ComponentDefinition {
|
|||
})
|
||||
}
|
||||
|
||||
/// Creates a new instance of the component and returns a shared handle to it.
|
||||
pub fn create_embedded(&self, ctx: FactoryContext) -> Result<ComponentInstance, PlatformError> {
|
||||
generativity::make_guard!(guard);
|
||||
Ok(ComponentInstance {
|
||||
inner: self.inner.unerase(guard).clone().create(WindowOptions::Embed {
|
||||
parent_item_tree: ctx.parent_item_tree,
|
||||
parent_item_tree_index: ctx.parent_item_tree_index,
|
||||
})?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Instantiate the component for wasm using the given canvas id
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn create_with_canvas_id(
|
||||
|
|
|
|||
|
|
@ -392,6 +392,10 @@ pub enum WindowOptions {
|
|||
UseExistingWindow(WindowAdapterRc),
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
CreateWithCanvasId(String),
|
||||
Embed {
|
||||
parent_item_tree: ItemTreeWeak,
|
||||
parent_item_tree_index: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'id> ItemTreeDescription<'id> {
|
||||
|
|
@ -1265,10 +1269,18 @@ pub fn instantiate(
|
|||
instance_ref.self_weak().set(self_weak.clone()).ok();
|
||||
let description = comp.description();
|
||||
|
||||
let root = root
|
||||
.or_else(|| instance_ref.parent_instance().map(|parent| parent.root_weak().clone()))
|
||||
.unwrap_or_else(|| self_weak.clone());
|
||||
description.root_offset.apply(instance_ref.as_ref()).set(root).ok().unwrap();
|
||||
if let Some(WindowOptions::Embed { parent_item_tree, parent_item_tree_index }) = window_options
|
||||
{
|
||||
vtable::VRc::borrow_pin(&self_rc)
|
||||
.as_ref()
|
||||
.embed_component(parent_item_tree, *parent_item_tree_index);
|
||||
description.root_offset.apply(instance_ref.as_ref()).set(self_weak.clone()).ok().unwrap();
|
||||
} else {
|
||||
let root = root
|
||||
.or_else(|| instance_ref.parent_instance().map(|parent| parent.root_weak().clone()))
|
||||
.unwrap_or_else(|| self_weak.clone());
|
||||
description.root_offset.apply(instance_ref.as_ref()).set(root).ok().unwrap();
|
||||
}
|
||||
|
||||
if !description.original.is_global() {
|
||||
let maybe_window_adapter =
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@ export component TestCase inherits Rectangle {
|
|||
```
|
||||
|
||||
```rust
|
||||
let factory = slint::ComponentFactory::new(|| {
|
||||
let mut compiler = slint_interpreter::ComponentCompiler::new();
|
||||
let e = spin_on::spin_on(compiler.build_from_source(
|
||||
let factory = slint::ComponentFactory::new(|ctx| {
|
||||
|
||||
let mut compiler = slint_interpreter::ComponentCompiler::new();
|
||||
let e = spin_on::spin_on(compiler.build_from_source(
|
||||
r#"import { Button } from "std-widgets.slint";
|
||||
|
||||
export component E1 inherits Rectangle {
|
||||
|
|
@ -39,7 +40,7 @@ export component E1 inherits Rectangle {
|
|||
}"#.into(),
|
||||
std::path::PathBuf::from("embedded.slint"),
|
||||
)).unwrap();
|
||||
e.create().ok()
|
||||
e.create_embedded(ctx).ok()
|
||||
});
|
||||
|
||||
let instance = TestCase::new().unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue