use smol_str::{SmolStr, StrExt, ToSmolStr};
use std::cell::RefCell;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::rc::Rc;
use crate::expression_tree::BuiltinFunction;
use crate::langtype::{
BuiltinElement, BuiltinPropertyDefault, BuiltinPropertyInfo, BuiltinStruct, ElementType,
Enumeration, Function, PropertyLookupResult, Struct, Type,
};
use crate::object_tree::{Component, PropertyVisibility};
use crate::typeloader;
pub const RESERVED_GEOMETRY_PROPERTIES: &[(&str, Type)] = &[
("x", Type::LogicalLength),
("y", Type::LogicalLength),
("width", Type::LogicalLength),
("height", Type::LogicalLength),
("z", Type::Float32),
];
pub const RESERVED_LAYOUT_PROPERTIES: &[(&str, Type)] = &[
("min-width", Type::LogicalLength),
("min-height", Type::LogicalLength),
("max-width", Type::LogicalLength),
("max-height", Type::LogicalLength),
("padding", Type::LogicalLength),
("padding-left", Type::LogicalLength),
("padding-right", Type::LogicalLength),
("padding-top", Type::LogicalLength),
("padding-bottom", Type::LogicalLength),
("preferred-width", Type::LogicalLength),
("preferred-height", Type::LogicalLength),
("horizontal-stretch", Type::Float32),
("vertical-stretch", Type::Float32),
];
pub const RESERVED_GRIDLAYOUT_PROPERTIES: &[(&str, Type)] = &[
("col", Type::Int32),
("row", Type::Int32),
("colspan", Type::Int32),
("rowspan", Type::Int32),
];
pub const RESERVED_FLEXBOXLAYOUT_PROPERTIES: &[(&str, Type)] = &[
("flex-grow", Type::Float32),
("flex-shrink", Type::Float32),
("flex-basis", Type::LogicalLength),
("flex-order", Type::Int32),
];
macro_rules! declare_enums {
($( $(#[$enum_doc:meta])* $vis:vis enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => {
#[allow(non_snake_case)]
pub struct BuiltinEnums {
$(pub $Name : Rc<Enumeration>),*
}
impl BuiltinEnums {
fn new() -> Self {
Self {
$($Name : Rc::new(Enumeration {
name: stringify!($Name).replace_smolstr("_", "-"),
values: vec![$(crate::generator::to_kebab_case(stringify!($Value).trim_start_matches("r#")).into()),*],
default_value: 0,
node: None,
})),*
}
}
fn fill_register(&self, register: &mut TypeRegister) {
$(if stringify!($Name) != "PathEvent" {
register.insert_type_with_name(
Type::Enumeration(self.$Name.clone()),
stringify!($Name).replace_smolstr("_", "-")
);
})*
}
}
};
}
i_slint_common::for_each_enums!(declare_enums);
pub struct BuiltinTypes {
pub enums: BuiltinEnums,
pub noarg_callback_type: Type,
pub strarg_callback_type: Type,
pub logical_point_type: Rc<Struct>,
pub logical_size_type: Rc<Struct>,
pub font_metrics_type: Type,
pub layout_info_type: Rc<Struct>,
pub state_info_type: Rc<Struct>,
pub gridlayout_input_data_type: Type,
pub path_element_type: Type,
pub layout_item_info_type: Type,
pub flexbox_layout_item_info_type: Type,
}
impl BuiltinTypes {
fn new() -> Self {
let layout_info_type = Rc::new(Struct {
fields: ["min", "max", "preferred"]
.iter()
.map(|s| (SmolStr::new_static(s), Type::LogicalLength))
.chain(
["min_percent", "max_percent", "stretch"]
.iter()
.map(|s| (SmolStr::new_static(s), Type::Float32)),
)
.collect(),
name: BuiltinStruct::LayoutInfo.into(),
});
let enums = BuiltinEnums::new();
let flex_align_self_type = Type::Enumeration(enums.FlexboxLayoutAlignSelf.clone());
Self {
enums,
logical_point_type: Rc::new(Struct {
fields: IntoIterator::into_iter([
(SmolStr::new_static("x"), Type::LogicalLength),
(SmolStr::new_static("y"), Type::LogicalLength),
])
.collect(),
name: BuiltinStruct::LogicalPosition.into(),
}),
logical_size_type: Rc::new(Struct {
fields: IntoIterator::into_iter([
(SmolStr::new_static("width"), Type::LogicalLength),
(SmolStr::new_static("height"), Type::LogicalLength),
])
.collect(),
name: BuiltinStruct::LogicalSize.into(),
}),
font_metrics_type: Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([
(SmolStr::new_static("ascent"), Type::LogicalLength),
(SmolStr::new_static("descent"), Type::LogicalLength),
(SmolStr::new_static("x-height"), Type::LogicalLength),
(SmolStr::new_static("cap-height"), Type::LogicalLength),
])
.collect(),
name: BuiltinStruct::FontMetrics.into(),
})),
noarg_callback_type: Type::Callback(Rc::new(Function {
return_type: Type::Void,
args: Vec::new(),
arg_names: Vec::new(),
})),
strarg_callback_type: Type::Callback(Rc::new(Function {
return_type: Type::Void,
args: vec![Type::String],
arg_names: Vec::new(),
})),
layout_info_type: layout_info_type.clone(),
state_info_type: Rc::new(Struct {
fields: IntoIterator::into_iter([
(SmolStr::new_static("current-state"), Type::Int32),
(SmolStr::new_static("previous-state"), Type::Int32),
(SmolStr::new_static("change-time"), Type::Duration),
])
.collect(),
name: BuiltinStruct::StateInfo.into(),
}),
path_element_type: Type::Struct(Rc::new(Struct {
fields: Default::default(),
name: BuiltinStruct::PathElement.into(),
})),
layout_item_info_type: Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([(
"constraint".into(),
layout_info_type.clone().into(),
)])
.collect(),
name: BuiltinStruct::LayoutItemInfo.into(),
})),
flexbox_layout_item_info_type: Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([
("constraint".into(), layout_info_type.into()),
("flex-grow".into(), Type::Float32),
("flex-shrink".into(), Type::Float32),
("flex-basis".into(), Type::Float32),
("flex-align-self".into(), flex_align_self_type),
("flex-order".into(), Type::Int32),
])
.collect(),
name: BuiltinStruct::FlexboxLayoutItemInfo.into(),
})),
gridlayout_input_data_type: Type::Struct(Rc::new(Struct {
fields: IntoIterator::into_iter([
("row".into(), Type::Int32),
("column".into(), Type::Int32),
("rowspan".into(), Type::Int32),
("colspan".into(), Type::Int32),
])
.collect(),
name: BuiltinStruct::GridLayoutInputData.into(),
})),
}
}
}
thread_local! {
pub static BUILTIN: BuiltinTypes = BuiltinTypes::new();
}
const RESERVED_OTHER_PROPERTIES: &[(&str, Type)] = &[
("clip", Type::Bool),
("opacity", Type::Float32),
("cache-rendering-hint", Type::Bool),
("visible", Type::Bool), ];
pub const RESERVED_DROP_SHADOW_PROPERTIES: &[(&str, Type)] = &[
("drop-shadow-offset-x", Type::LogicalLength),
("drop-shadow-offset-y", Type::LogicalLength),
("drop-shadow-blur", Type::LogicalLength),
("drop-shadow-spread", Type::LogicalLength),
("drop-shadow-color", Type::Color),
];
pub const RESERVED_INNER_SHADOW_PROPERTIES: &[(&str, Type)] = &[
("inner-shadow-offset-x", Type::LogicalLength),
("inner-shadow-offset-y", Type::LogicalLength),
("inner-shadow-blur", Type::LogicalLength),
("inner-shadow-spread", Type::LogicalLength),
("inner-shadow-color", Type::Color),
];
pub const RESERVED_TRANSFORM_PROPERTIES: &[(&str, Type)] = &[
("transform-rotation", Type::Angle),
("transform-scale-x", Type::Float32),
("transform-scale-y", Type::Float32),
("transform-scale", Type::Float32),
];
pub fn transform_origin_property() -> (&'static str, Rc<Struct>) {
("transform-origin", logical_point_type())
}
pub const DEPRECATED_ROTATION_ORIGIN_PROPERTIES: [(&str, Type); 2] =
[("rotation-origin-x", Type::LogicalLength), ("rotation-origin-y", Type::LogicalLength)];
pub fn noarg_callback_type() -> Type {
BUILTIN.with(|types| types.noarg_callback_type.clone())
}
fn strarg_callback_type() -> Type {
BUILTIN.with(|types| types.strarg_callback_type.clone())
}
pub fn reserved_accessibility_properties() -> impl Iterator<Item = (&'static str, Type)> {
[
("accessible-checkable", Type::Bool),
("accessible-checked", Type::Bool),
("accessible-delegate-focus", Type::Int32),
("accessible-description", Type::String),
("accessible-enabled", Type::Bool),
("accessible-expandable", Type::Bool),
("accessible-expanded", Type::Bool),
("accessible-id", Type::String),
("accessible-label", Type::String),
("accessible-value", Type::String),
("accessible-value-maximum", Type::Float32),
("accessible-value-minimum", Type::Float32),
("accessible-value-step", Type::Float32),
("accessible-placeholder-text", Type::String),
("accessible-action-default", noarg_callback_type()),
("accessible-action-increment", noarg_callback_type()),
("accessible-action-decrement", noarg_callback_type()),
("accessible-action-set-value", strarg_callback_type()),
("accessible-action-expand", noarg_callback_type()),
("accessible-item-selectable", Type::Bool),
("accessible-item-selected", Type::Bool),
("accessible-item-index", Type::Int32),
("accessible-item-count", Type::Int32),
("accessible-read-only", Type::Bool),
]
.into_iter()
}
pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type, PropertyVisibility)> {
RESERVED_GEOMETRY_PROPERTIES
.iter()
.chain(RESERVED_LAYOUT_PROPERTIES.iter())
.chain(RESERVED_OTHER_PROPERTIES.iter())
.chain(RESERVED_DROP_SHADOW_PROPERTIES.iter())
.chain(RESERVED_INNER_SHADOW_PROPERTIES.iter())
.chain(RESERVED_TRANSFORM_PROPERTIES.iter())
.chain(DEPRECATED_ROTATION_ORIGIN_PROPERTIES.iter())
.map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input))
.chain(
std::iter::once(transform_origin_property())
.map(|(k, v)| (k, v.into(), PropertyVisibility::Input)),
)
.chain(reserved_accessibility_properties().map(|(k, v)| (k, v, PropertyVisibility::Input)))
.chain(
RESERVED_GRIDLAYOUT_PROPERTIES
.iter()
.map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
)
.chain(
RESERVED_FLEXBOXLAYOUT_PROPERTIES
.iter()
.map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
)
.chain(std::iter::once((
"flex-align-self",
Type::Enumeration(BUILTIN.with(|e| e.enums.FlexboxLayoutAlignSelf.clone())),
PropertyVisibility::Input,
)))
.chain(IntoIterator::into_iter([
("absolute-position", logical_point_type().into(), PropertyVisibility::Output),
("forward-focus", Type::ElementReference, PropertyVisibility::Constexpr),
(
"focus",
Type::Function(BuiltinFunction::SetFocusItem.ty()),
PropertyVisibility::Public,
),
(
"clear-focus",
Type::Function(BuiltinFunction::ClearFocusItem.ty()),
PropertyVisibility::Public,
),
(
"dialog-button-role",
Type::Enumeration(BUILTIN.with(|e| e.enums.DialogButtonRole.clone())),
PropertyVisibility::Constexpr,
),
(
"accessible-role",
Type::Enumeration(BUILTIN.with(|e| e.enums.AccessibleRole.clone())),
PropertyVisibility::Constexpr,
),
(
"accessible-orientation",
Type::Enumeration(BUILTIN.with(|e| e.enums.Orientation.clone())),
PropertyVisibility::Input,
),
(
"accessible-live-region",
Type::Enumeration(BUILTIN.with(|e| e.enums.AccessibleLiveness.clone())),
PropertyVisibility::Input,
),
]))
.chain(std::iter::once(("init", noarg_callback_type(), PropertyVisibility::Private)))
}
pub fn reserved_property(name: std::borrow::Cow<'_, str>) -> PropertyLookupResult<'_> {
thread_local! {
static RESERVED_PROPERTIES: HashMap<&'static str, (Type, PropertyVisibility, Option<BuiltinFunction>)>
= reserved_properties().map(|(name, ty, visibility)| (name, (ty, visibility, reserved_member_function(name)))).collect();
}
if let Some((ty, visibility, builtin_function)) =
RESERVED_PROPERTIES.with(|reserved| reserved.get(name.as_ref()).cloned())
{
return PropertyLookupResult {
property_type: ty,
resolved_name: name,
is_local_to_component: false,
is_in_direct_base: false,
is_shadowable: false,
property_visibility: visibility,
declared_pure: None,
builtin_function,
};
}
for pre in &["min", "max"] {
if let Some(a) = name.strip_prefix(pre) {
for suf in &["width", "height"] {
if let Some(b) = a.strip_suffix(suf)
&& b == "imum-"
{
return PropertyLookupResult {
property_type: Type::LogicalLength,
resolved_name: format!("{pre}-{suf}").into(),
is_local_to_component: false,
is_in_direct_base: false,
is_shadowable: false,
property_visibility: crate::object_tree::PropertyVisibility::InOut,
declared_pure: None,
builtin_function: None,
};
}
}
}
}
PropertyLookupResult::invalid(name)
}
pub fn reserved_member_function(name: &str) -> Option<BuiltinFunction> {
for (m, e) in [
("focus", BuiltinFunction::SetFocusItem), ("clear-focus", BuiltinFunction::ClearFocusItem), ] {
if m == name {
return Some(e);
}
}
None
}
#[derive(Debug, Default)]
pub struct TypeRegister {
types: HashMap<SmolStr, Type>,
elements: HashMap<SmolStr, ElementType>,
supported_property_animation_types: HashSet<String>,
pub(crate) property_animation_type: ElementType,
pub(crate) empty_type: ElementType,
context_restricted_types: HashMap<SmolStr, HashSet<SmolStr>>,
parent_registry: Option<Rc<RefCell<TypeRegister>>>,
pub(crate) expose_internal_types: bool,
}
impl TypeRegister {
pub(crate) fn snapshot(&self, snapshotter: &mut typeloader::Snapshotter) -> Self {
Self {
types: self.types.clone(),
elements: self
.elements
.iter()
.map(|(k, v)| (k.clone(), snapshotter.snapshot_element_type(v)))
.collect(),
supported_property_animation_types: self.supported_property_animation_types.clone(),
property_animation_type: snapshotter
.snapshot_element_type(&self.property_animation_type),
empty_type: snapshotter.snapshot_element_type(&self.empty_type),
context_restricted_types: self.context_restricted_types.clone(),
parent_registry: self
.parent_registry
.as_ref()
.map(|tr| snapshotter.snapshot_type_register(tr)),
expose_internal_types: self.expose_internal_types,
}
}
pub fn insert_type(&mut self, t: Type) -> bool {
self.types.insert(t.to_smolstr(), t).is_none()
}
pub fn insert_type_with_name(&mut self, t: Type, name: SmolStr) -> bool {
self.types.insert(name, t).is_none()
}
fn builtin_internal() -> Self {
let mut register = TypeRegister::default();
register.insert_type(Type::Float32);
register.insert_type(Type::Int32);
register.insert_type(Type::String);
register.insert_type(Type::PhysicalLength);
register.insert_type(Type::LogicalLength);
register.insert_type(Type::Color);
register.insert_type(Type::ComponentFactory);
register.insert_type(Type::Duration);
register.insert_type(Type::Image);
register.insert_type(Type::Bool);
register.insert_type(Type::Model);
register.insert_type(Type::Percent);
register.insert_type(Type::Easing);
register.insert_type(Type::Angle);
register.insert_type(Type::Brush);
register.insert_type(Type::Rem);
register.insert_type(Type::StyledText);
register.insert_type(Type::Keys);
register.insert_type(Type::DataTransfer);
register.types.insert("Point".into(), logical_point_type().into());
register.types.insert("Size".into(), logical_size_type().into());
BUILTIN.with(|e| e.enums.fill_register(&mut register));
register.supported_property_animation_types.insert(Type::Float32.to_string());
register.supported_property_animation_types.insert(Type::Int32.to_string());
register.supported_property_animation_types.insert(Type::Color.to_string());
register.supported_property_animation_types.insert(Type::PhysicalLength.to_string());
register.supported_property_animation_types.insert(Type::LogicalLength.to_string());
register.supported_property_animation_types.insert(Type::Brush.to_string());
register.supported_property_animation_types.insert(Type::Angle.to_string());
macro_rules! register_builtin_structs {
($(
$(#[$attr:meta])*
$vis:vis struct $Name:ident {
$( $(#[$field_attr:meta])* $field:ident : $field_type:ident, )*
}
)*) => { $(
register.insert_type_with_name(Type::Struct(builtin_structs::$Name()), SmolStr::new(stringify!($Name)));
)* };
}
i_slint_common::for_each_builtin_structs!(register_builtin_structs);
crate::load_builtins::load_builtins(&mut register);
let mut visited: HashSet<SmolStr> = HashSet::new();
let mut to_visit: Vec<Rc<BuiltinElement>> = register
.elements
.values()
.filter_map(|e| match e {
ElementType::Builtin(b) => Some(b.clone()),
_ => None,
})
.collect();
while let Some(b) = to_visit.pop() {
let parent = b.native_class.class_name.clone();
if !visited.insert(parent.clone()) {
continue;
}
for (child_name, child_type) in &b.additional_accepted_child_types {
register
.context_restricted_types
.entry(child_name.clone())
.or_default()
.insert(parent.clone());
to_visit.push(child_type.clone());
}
if b.additional_accept_self {
register.context_restricted_types.entry(parent.clone()).or_default().insert(parent);
}
}
match &mut register.elements.get_mut("PopupWindow").unwrap() {
ElementType::Builtin(b) => {
let popup = Rc::get_mut(b).unwrap();
popup.properties.insert(
"show".into(),
BuiltinPropertyInfo::from(BuiltinFunction::ShowPopupWindow),
);
popup.properties.insert(
"close".into(),
BuiltinPropertyInfo::from(BuiltinFunction::ClosePopupWindow),
);
popup.properties.get_mut("close-on-click").unwrap().property_visibility =
PropertyVisibility::Constexpr;
popup.properties.get_mut("close-policy").unwrap().property_visibility =
PropertyVisibility::Constexpr;
}
_ => unreachable!(),
};
match &mut register.elements.get_mut("Timer").unwrap() {
ElementType::Builtin(b) => {
let timer = Rc::get_mut(b).unwrap();
for (name, func) in [
("start", BuiltinFunction::StartTimer),
("stop", BuiltinFunction::StopTimer),
("restart", BuiltinFunction::RestartTimer),
] {
let existing_docs = timer.properties.get(name).and_then(|p| p.docs.clone());
let mut info = BuiltinPropertyInfo::from(func);
info.docs = existing_docs;
timer.properties.insert(name.into(), info);
}
}
_ => unreachable!(),
}
let font_metrics_prop = crate::langtype::BuiltinPropertyInfo {
property_visibility: PropertyVisibility::Output,
default_value: BuiltinPropertyDefault::WithElement(|elem| {
crate::expression_tree::Expression::FunctionCall {
function: BuiltinFunction::ItemFontMetrics.into(),
arguments: vec![crate::expression_tree::Expression::ElementReference(
Rc::downgrade(elem),
)],
source_location: None,
}
}),
..crate::langtype::BuiltinPropertyInfo::new(font_metrics_type())
};
match &mut register.elements.get_mut("TextInput").unwrap() {
ElementType::Builtin(b) => {
let text_input = Rc::get_mut(b).unwrap();
let existing = text_input.properties.get("set-selection-offsets");
let existing_docs = existing.and_then(|p| p.docs.clone());
let arg_names = existing.and_then(|p| {
if let Type::Function(f) = &p.ty { Some(f.arg_names.clone()) } else { None }
});
let mut info = BuiltinPropertyInfo::from(BuiltinFunction::SetSelectionOffsets);
info.docs = existing_docs;
if let (Some(names), Type::Function(f)) = (arg_names, &info.ty) {
let mut func = (**f).clone();
func.arg_names =
std::iter::repeat_n(SmolStr::default(), func.args.len() - names.len())
.chain(names)
.collect();
info.ty = Type::Function(Rc::new(func));
}
text_input.properties.insert("set-selection-offsets".into(), info);
text_input.properties.insert("font-metrics".into(), font_metrics_prop.clone());
}
_ => unreachable!(),
};
match &mut register.elements.get_mut("Text").unwrap() {
ElementType::Builtin(b) => {
let text = Rc::get_mut(b).unwrap();
text.properties.insert("font-metrics".into(), font_metrics_prop);
}
_ => unreachable!(),
};
match &mut register.elements.get_mut("Path").unwrap() {
ElementType::Builtin(b) => {
let path = Rc::get_mut(b).unwrap();
path.properties.get_mut("commands").unwrap().property_visibility =
PropertyVisibility::Fake;
}
_ => unreachable!(),
};
match &mut register.elements.get_mut("TabWidget").unwrap() {
ElementType::Builtin(b) => {
let tabwidget = Rc::get_mut(b).unwrap();
tabwidget.properties.get_mut("orientation").unwrap().property_visibility =
PropertyVisibility::Constexpr;
}
_ => unreachable!(),
}
register
}
#[doc(hidden)]
pub fn builtin_experimental() -> Rc<RefCell<Self>> {
let register = Self::builtin_internal();
Rc::new(RefCell::new(register))
}
pub fn builtin() -> Rc<RefCell<Self>> {
let mut register = Self::builtin_internal();
register.elements.remove("ComponentContainer").unwrap();
register.types.remove("component-factory").unwrap();
register.elements.remove("FlexboxLayout").unwrap();
register.types.remove("FlexboxLayoutDirection").unwrap();
register.types.remove("FlexboxLayoutAlignContent").unwrap();
register.types.remove("FlexboxLayoutWrap").unwrap();
register.types.remove("FlexboxLayoutAlignSelf").unwrap();
Rc::new(RefCell::new(register))
}
pub fn new(parent: &Rc<RefCell<TypeRegister>>) -> Self {
Self {
parent_registry: Some(parent.clone()),
expose_internal_types: parent.borrow().expose_internal_types,
..Default::default()
}
}
pub fn lookup(&self, name: &str) -> Type {
self.types
.get(name)
.cloned()
.or_else(|| self.parent_registry.as_ref().map(|r| r.borrow().lookup(name)))
.unwrap_or_default()
}
fn lookup_element_as_result(
&self,
name: &str,
) -> Result<ElementType, HashMap<SmolStr, HashSet<SmolStr>>> {
match self.elements.get(name).cloned() {
Some(ty) => Ok(ty),
None => match &self.parent_registry {
Some(r) => r.borrow().lookup_element_as_result(name),
None => Err(self.context_restricted_types.clone()),
},
}
}
pub fn lookup_element(&self, name: &str) -> Result<ElementType, String> {
self.lookup_element_as_result(name).map_err(|context_restricted_types| {
if let Some(permitted_parent_types) = context_restricted_types.get(name) {
if permitted_parent_types.len() == 1 {
format!(
"{} can only be within a {} element",
name,
permitted_parent_types.iter().next().unwrap()
)
} else {
let mut elements = permitted_parent_types.iter().cloned().collect::<Vec<_>>();
elements.sort();
format!(
"{} can only be within the following elements: {}",
name,
elements.join(", ")
)
}
} else if let Some(ty) = self.types.get(name) {
format!("'{ty}' cannot be used as an element")
} else {
format!("Unknown element '{name}'")
}
})
}
pub fn lookup_builtin_element(&self, name: &str) -> Option<ElementType> {
self.parent_registry.as_ref().map_or_else(
|| self.elements.get(name).cloned(),
|p| p.borrow().lookup_builtin_element(name),
)
}
pub fn lookup_qualified<Member: AsRef<str>>(&self, qualified: &[Member]) -> Type {
if qualified.len() != 1 {
return Type::Invalid;
}
self.lookup(qualified[0].as_ref())
}
pub fn add(&mut self, comp: Rc<Component>) -> bool {
self.add_with_name(comp.id.clone(), comp)
}
pub fn add_with_name(&mut self, name: SmolStr, comp: Rc<Component>) -> bool {
self.elements.insert(name, ElementType::Component(comp)).is_none()
}
pub fn add_builtin(&mut self, builtin: Rc<BuiltinElement>) {
self.elements.insert(builtin.name.clone(), ElementType::Builtin(builtin));
}
pub fn property_animation_type_for_property(&self, property_type: Type) -> ElementType {
if self.supported_property_animation_types.contains(&property_type.to_string()) {
self.property_animation_type.clone()
} else {
self.parent_registry
.as_ref()
.map(|registry| {
registry.borrow().property_animation_type_for_property(property_type)
})
.unwrap_or_default()
}
}
pub fn all_types(&self) -> HashMap<SmolStr, Type> {
let mut all =
self.parent_registry.as_ref().map(|r| r.borrow().all_types()).unwrap_or_default();
for (k, v) in &self.types {
all.insert(k.clone(), v.clone());
}
all
}
pub fn all_elements(&self) -> HashMap<SmolStr, ElementType> {
let mut all =
self.parent_registry.as_ref().map(|r| r.borrow().all_elements()).unwrap_or_default();
for (k, v) in &self.elements {
all.insert(k.clone(), v.clone());
}
all
}
pub fn empty_type(&self) -> ElementType {
match self.parent_registry.as_ref() {
Some(parent) => parent.borrow().empty_type(),
None => self.empty_type.clone(),
}
}
}
pub mod builtin_structs {
use super::*;
thread_local! {
pub static BUILTIN_STRUCTS: BuiltinStructs = BuiltinStructs::new();
}
#[rustfmt::skip]
macro_rules! map_type {
($pub_type:ident, bool) => { Type::Bool };
($pub_type:ident, i32) => { Type::Int32 };
($pub_type:ident, f32) => { Type::Float32 };
($pub_type:ident, SharedString) => { Type::String };
($pub_type:ident, Image) => { Type::Image };
($pub_type:ident, Coord) => { Type::LogicalLength };
($pub_type:ident, Keys) => { Type::Keys };
($pub_type:ident, DataTransfer) => { Type::DataTransfer };
($pub_type:ident, LogicalPosition) => { Type::Struct(logical_point_type()) };
($pub_type:ident, LogicalSize) => { Type::Struct(logical_size_type()) };
($pub_type:ident, KeyboardModifiers) => {
Type::Struct($pub_type.clone())
};
($pub_type:ident, $_:ident) => {
BUILTIN.with(|e| Type::Enumeration(e.enums.$pub_type.clone()))
};
}
macro_rules! declare_builtin_structs {
($(
$(#[$attr:meta])*
$vis:vis struct $Name:ident {
$( $(#[$field_attr:meta])* $field:ident : $field_type:ident, )*
}
)*) => {
pub struct BuiltinStructs {
$(
#[allow(non_snake_case)]
$Name: Rc<Struct>
),*
}
impl BuiltinStructs {
pub fn new() -> Self {
$(
#[allow(non_snake_case)]
let $Name = Rc::new(Struct{
fields: BTreeMap::from([
$((stringify!($field).replace_smolstr("_", "-"), map_type!($field_type, $field_type))),*
]),
name: BuiltinStruct::$Name.into(),
});
)*
Self {
$($Name),*
}
}
}
impl Default for BuiltinStructs {
fn default() -> Self {
Self::new()
}
}
$(
#[allow(non_snake_case)]
pub fn $Name() -> Rc<Struct> {
BUILTIN_STRUCTS.with(|types| types.$Name.clone())
}
)*
};
}
i_slint_common::for_each_builtin_structs!(declare_builtin_structs);
}
pub fn logical_point_type() -> Rc<Struct> {
BUILTIN.with(|types| types.logical_point_type.clone())
}
pub fn logical_size_type() -> Rc<Struct> {
BUILTIN.with(|types| types.logical_size_type.clone())
}
pub fn font_metrics_type() -> Type {
BUILTIN.with(|types| types.font_metrics_type.clone())
}
pub fn layout_info_type() -> Rc<Struct> {
BUILTIN.with(|types| types.layout_info_type.clone())
}
pub fn path_element_type() -> Type {
BUILTIN.with(|types| types.path_element_type.clone())
}
pub fn layout_item_info_type() -> Type {
BUILTIN.with(|types| types.layout_item_info_type.clone())
}
pub fn flexbox_layout_item_info_type() -> Type {
BUILTIN.with(|types| types.flexbox_layout_item_info_type.clone())
}