1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore imum
5
6use smol_str::{format_smolstr, SmolStr, StrExt, ToSmolStr};
7use std::cell::RefCell;
8use std::collections::{BTreeMap, HashMap, HashSet};
9use std::rc::Rc;
10
11use crate::expression_tree::BuiltinFunction;
12use crate::langtype::{
13 BuiltinElement, BuiltinPropertyDefault, BuiltinPropertyInfo, ElementType, Enumeration,
14 Function, PropertyLookupResult, Struct, Type,
15};
16use crate::object_tree::{Component, PropertyVisibility};
17use crate::typeloader;
18
19pub const RESERVED_GEOMETRY_PROPERTIES: &[(&str, Type)] = &[
20 ("x", Type::LogicalLength),
21 ("y", Type::LogicalLength),
22 ("width", Type::LogicalLength),
23 ("height", Type::LogicalLength),
24 ("z", Type::Float32),
25];
26
27pub const RESERVED_LAYOUT_PROPERTIES: &[(&str, Type)] = &[
28 ("min-width", Type::LogicalLength),
29 ("min-height", Type::LogicalLength),
30 ("max-width", Type::LogicalLength),
31 ("max-height", Type::LogicalLength),
32 ("padding", Type::LogicalLength),
33 ("padding-left", Type::LogicalLength),
34 ("padding-right", Type::LogicalLength),
35 ("padding-top", Type::LogicalLength),
36 ("padding-bottom", Type::LogicalLength),
37 ("preferred-width", Type::LogicalLength),
38 ("preferred-height", Type::LogicalLength),
39 ("horizontal-stretch", Type::Float32),
40 ("vertical-stretch", Type::Float32),
41];
42
43pub const RESERVED_GRIDLAYOUT_PROPERTIES: &[(&str, Type)] = &[
44 ("col", Type::Int32),
45 ("row", Type::Int32),
46 ("colspan", Type::Int32),
47 ("rowspan", Type::Int32),
48];
49
50macro_rules! declare_enums {
51 ($( $(#[$enum_doc:meta])* enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => {
52 #[allow(non_snake_case)]
53 pub struct BuiltinEnums {
54 $(pub $Name : Rc<Enumeration>),*
55 }
56 impl BuiltinEnums {
57 fn new() -> Self {
58 Self {
59 $($Name : Rc::new(Enumeration {
60 name: stringify!($Name).replace_smolstr("_", "-"),
61 values: vec![$(crate::generator::to_kebab_case(stringify!($Value).trim_start_matches("r#")).into()),*],
62 default_value: 0,
63 node: None,
64 })),*
65 }
66 }
67 fn fill_register(&self, register: &mut TypeRegister) {
68 $(if stringify!($Name) != "PathEvent" {
69 register.insert_type_with_name(
70 Type::Enumeration(self.$Name.clone()),
71 stringify!($Name).replace_smolstr("_", "-")
72 );
73 })*
74 }
75 }
76 };
77}
78
79i_slint_common::for_each_enums!(declare_enums);
80
81pub struct BuiltinTypes {
82 pub enums: BuiltinEnums,
83 pub noarg_callback_type: Type,
84 pub strarg_callback_type: Type,
85 pub logical_point_type: Type,
86 pub font_metrics_type: Type,
87 pub layout_info_type: Rc<Struct>,
88 pub path_element_type: Type,
89 pub box_layout_cell_data_type: Type,
90}
91
92impl BuiltinTypes {
93 fn new() -> Self {
94 let layout_info_type = Rc::new(Struct {
95 fields: ["min", "max", "preferred"]
96 .iter()
97 .map(|s| (SmolStr::new_static(s), Type::LogicalLength))
98 .chain(
99 ["min_percent", "max_percent", "stretch"]
100 .iter()
101 .map(|s| (SmolStr::new_static(s), Type::Float32)),
102 )
103 .collect(),
104 name: Some("slint::private_api::LayoutInfo".into()),
105 node: None,
106 rust_attributes: None,
107 });
108 Self {
109 enums: BuiltinEnums::new(),
110 logical_point_type: Type::Struct(Rc::new(Struct {
111 fields: IntoIterator::into_iter([
112 (SmolStr::new_static("x"), Type::LogicalLength),
113 (SmolStr::new_static("y"), Type::LogicalLength),
114 ])
115 .collect(),
116 name: Some("slint::LogicalPosition".into()),
117 node: None,
118 rust_attributes: None,
119 })),
120 font_metrics_type: Type::Struct(Rc::new(Struct {
121 fields: IntoIterator::into_iter([
122 (SmolStr::new_static("ascent"), Type::LogicalLength),
123 (SmolStr::new_static("descent"), Type::LogicalLength),
124 (SmolStr::new_static("x-height"), Type::LogicalLength),
125 (SmolStr::new_static("cap-height"), Type::LogicalLength),
126 ])
127 .collect(),
128 name: Some("slint::private_api::FontMetrics".into()),
129 node: None,
130 rust_attributes: None,
131 })),
132 noarg_callback_type: Type::Callback(Rc::new(Function {
133 return_type: Type::Void,
134 args: vec![],
135 arg_names: vec![],
136 })),
137 strarg_callback_type: Type::Callback(Rc::new(Function {
138 return_type: Type::Void,
139 args: vec![Type::String],
140 arg_names: vec![],
141 })),
142 layout_info_type: layout_info_type.clone(),
143 path_element_type: Type::Struct(Rc::new(Struct {
144 fields: Default::default(),
145 name: Some("PathElement".into()),
146 node: None,
147 rust_attributes: None,
148 })),
149 box_layout_cell_data_type: Type::Struct(Rc::new(Struct {
150 fields: IntoIterator::into_iter([("constraint".into(), layout_info_type.into())])
151 .collect(),
152 name: Some("BoxLayoutCellData".into()),
153 node: None,
154 rust_attributes: None,
155 })),
156 }
157 }
158}
159
160thread_local! {
161 pub static BUILTIN: BuiltinTypes = BuiltinTypes::new();
162}
163
164const RESERVED_OTHER_PROPERTIES: &[(&str, Type)] = &[
165 ("clip", Type::Bool),
166 ("opacity", Type::Float32),
167 ("cache-rendering-hint", Type::Bool),
168 ("visible", Type::Bool), // ("enabled", Type::Bool),
169];
170
171pub const RESERVED_DROP_SHADOW_PROPERTIES: &[(&str, Type)] = &[
172 ("drop-shadow-offset-x", Type::LogicalLength),
173 ("drop-shadow-offset-y", Type::LogicalLength),
174 ("drop-shadow-blur", Type::LogicalLength),
175 ("drop-shadow-color", Type::Color),
176];
177
178pub const RESERVED_ROTATION_PROPERTIES: &[(&str, Type)] = &[
179 ("rotation-angle", Type::Angle),
180 ("rotation-origin-x", Type::LogicalLength),
181 ("rotation-origin-y", Type::LogicalLength),
182];
183
184pub fn noarg_callback_type() -> Type {
185 BUILTIN.with(|types: &BuiltinTypes| types.noarg_callback_type.clone())
186}
187
188fn strarg_callback_type() -> Type {
189 BUILTIN.with(|types: &BuiltinTypes| types.strarg_callback_type.clone())
190}
191
192pub fn reserved_accessibility_properties() -> impl Iterator<Item = (&'static str, Type)> {
193 [
194 //("accessible-role", ...)
195 ("accessible-checkable", Type::Bool),
196 ("accessible-checked", Type::Bool),
197 ("accessible-delegate-focus", Type::Int32),
198 ("accessible-description", Type::String),
199 ("accessible-enabled", Type::Bool),
200 ("accessible-expandable", Type::Bool),
201 ("accessible-expanded", Type::Bool),
202 ("accessible-label", Type::String),
203 ("accessible-value", Type::String),
204 ("accessible-value-maximum", Type::Float32),
205 ("accessible-value-minimum", Type::Float32),
206 ("accessible-value-step", Type::Float32),
207 ("accessible-placeholder-text", Type::String),
208 ("accessible-action-default", noarg_callback_type()),
209 ("accessible-action-increment", noarg_callback_type()),
210 ("accessible-action-decrement", noarg_callback_type()),
211 ("accessible-action-set-value", strarg_callback_type()),
212 ("accessible-action-expand", noarg_callback_type()),
213 ("accessible-item-selectable", Type::Bool),
214 ("accessible-item-selected", Type::Bool),
215 ("accessible-item-index", Type::Int32),
216 ("accessible-item-count", Type::Int32),
217 ("accessible-read-only", Type::Bool),
218 ]
219 .into_iter()
220}
221
222/// list of reserved property injected in every item
223pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type, PropertyVisibility)> {
224 RESERVED_GEOMETRY_PROPERTIES
225 .iter()
226 .chain(RESERVED_LAYOUT_PROPERTIES.iter())
227 .chain(RESERVED_OTHER_PROPERTIES.iter())
228 .chain(RESERVED_DROP_SHADOW_PROPERTIES.iter())
229 .chain(RESERVED_ROTATION_PROPERTIES.iter())
230 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input))
231 .chain(reserved_accessibility_properties().map(|(k, v)| (k, v, PropertyVisibility::Input)))
232 .chain(
233 RESERVED_GRIDLAYOUT_PROPERTIES
234 .iter()
235 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Constexpr)),
236 )
237 .chain(IntoIterator::into_iter([
238 ("absolute-position", logical_point_type(), PropertyVisibility::Output),
239 ("forward-focus", Type::ElementReference, PropertyVisibility::Constexpr),
240 (
241 "focus",
242 Type::Function(BuiltinFunction::SetFocusItem.ty()),
243 PropertyVisibility::Public,
244 ),
245 (
246 "clear-focus",
247 Type::Function(BuiltinFunction::ClearFocusItem.ty()),
248 PropertyVisibility::Public,
249 ),
250 (
251 "dialog-button-role",
252 Type::Enumeration(BUILTIN.with(|e| e.enums.DialogButtonRole.clone())),
253 PropertyVisibility::Constexpr,
254 ),
255 (
256 "accessible-role",
257 Type::Enumeration(BUILTIN.with(|e| e.enums.AccessibleRole.clone())),
258 PropertyVisibility::Constexpr,
259 ),
260 ]))
261 .chain(std::iter::once(("init", noarg_callback_type(), PropertyVisibility::Private)))
262}
263
264/// lookup reserved property injected in every item
265pub fn reserved_property(name: &str) -> PropertyLookupResult {
266 thread_local! {
267 static RESERVED_PROPERTIES: HashMap<&'static str, (Type, PropertyVisibility, Option<BuiltinFunction>)>
268 = reserved_properties().map(|(name, ty, visibility)| (name, (ty, visibility, reserved_member_function(name)))).collect();
269 }
270 if let Some(result) = RESERVED_PROPERTIES.with(|reserved| {
271 reserved.get(name).map(|(ty, visibility, builtin_function)| PropertyLookupResult {
272 property_type: ty.clone(),
273 resolved_name: name.into(),
274 is_local_to_component: false,
275 is_in_direct_base: false,
276 property_visibility: *visibility,
277 declared_pure: None,
278 builtin_function: builtin_function.clone(),
279 })
280 }) {
281 return result;
282 }
283
284 // Report deprecated known reserved properties (maximum_width, minimum_height, ...)
285 for pre in &["min", "max"] {
286 if let Some(a) = name.strip_prefix(pre) {
287 for suf in &["width", "height"] {
288 if let Some(b) = a.strip_suffix(suf) {
289 if b == "imum-" {
290 return PropertyLookupResult {
291 property_type: Type::LogicalLength,
292 resolved_name: format!("{pre}-{suf}").into(),
293 is_local_to_component: false,
294 is_in_direct_base: false,
295 property_visibility: crate::object_tree::PropertyVisibility::InOut,
296 declared_pure: None,
297 builtin_function: None,
298 };
299 }
300 }
301 }
302 }
303 }
304 PropertyLookupResult::invalid(name.into())
305}
306
307/// These member functions are injected in every time
308pub fn reserved_member_function(name: &str) -> Option<BuiltinFunction> {
309 for (m: &'static str, e: BuiltinFunction) in [
310 ("focus", BuiltinFunction::SetFocusItem), // match for callable "focus" property
311 ("clear-focus", BuiltinFunction::ClearFocusItem), // match for callable "clear-focus" property
312 ] {
313 if m == name {
314 return Some(e);
315 }
316 }
317 None
318}
319
320#[derive(Debug, Default)]
321pub struct TypeRegister {
322 /// The set of property types.
323 types: HashMap<SmolStr, Type>,
324 /// The set of element types
325 elements: HashMap<SmolStr, ElementType>,
326 supported_property_animation_types: HashSet<String>,
327 pub(crate) property_animation_type: ElementType,
328 pub(crate) empty_type: ElementType,
329 /// Map from a context restricted type to the list of contexts (parent type) it is allowed in. This is
330 /// used to construct helpful error messages, such as "Row can only be within a GridLayout element".
331 context_restricted_types: HashMap<SmolStr, HashSet<SmolStr>>,
332 parent_registry: Option<Rc<RefCell<TypeRegister>>>,
333 /// If the lookup function should return types that are marked as internal
334 pub(crate) expose_internal_types: bool,
335}
336
337impl TypeRegister {
338 pub(crate) fn snapshot(&self, snapshotter: &mut typeloader::Snapshotter) -> Self {
339 Self {
340 types: self.types.clone(),
341 elements: self
342 .elements
343 .iter()
344 .map(|(k, v)| (k.clone(), snapshotter.snapshot_element_type(v)))
345 .collect(),
346 supported_property_animation_types: self.supported_property_animation_types.clone(),
347 property_animation_type: snapshotter
348 .snapshot_element_type(&self.property_animation_type),
349 empty_type: snapshotter.snapshot_element_type(&self.empty_type),
350 context_restricted_types: self.context_restricted_types.clone(),
351 parent_registry: self
352 .parent_registry
353 .as_ref()
354 .map(|tr| snapshotter.snapshot_type_register(tr)),
355 expose_internal_types: self.expose_internal_types,
356 }
357 }
358
359 /// Insert a type into the type register with its builtin type name.
360 ///
361 /// Returns false if a it replaced an existing type.
362 pub fn insert_type(&mut self, t: Type) -> bool {
363 self.types.insert(t.to_smolstr(), t).is_none()
364 }
365 /// Insert a type into the type register with a specified name.
366 ///
367 /// Returns false if a it replaced an existing type.
368 pub fn insert_type_with_name(&mut self, t: Type, name: SmolStr) -> bool {
369 self.types.insert(name, t).is_none()
370 }
371
372 fn builtin_internal() -> Self {
373 let mut register = TypeRegister::default();
374
375 register.insert_type(Type::Float32);
376 register.insert_type(Type::Int32);
377 register.insert_type(Type::String);
378 register.insert_type(Type::PhysicalLength);
379 register.insert_type(Type::LogicalLength);
380 register.insert_type(Type::Color);
381 register.insert_type(Type::ComponentFactory);
382 register.insert_type(Type::Duration);
383 register.insert_type(Type::Image);
384 register.insert_type(Type::Bool);
385 register.insert_type(Type::Model);
386 register.insert_type(Type::Percent);
387 register.insert_type(Type::Easing);
388 register.insert_type(Type::Angle);
389 register.insert_type(Type::Brush);
390 register.insert_type(Type::Rem);
391 register.types.insert("Point".into(), logical_point_type());
392
393 BUILTIN.with(|e| e.enums.fill_register(&mut register));
394
395 register.supported_property_animation_types.insert(Type::Float32.to_string());
396 register.supported_property_animation_types.insert(Type::Int32.to_string());
397 register.supported_property_animation_types.insert(Type::Color.to_string());
398 register.supported_property_animation_types.insert(Type::PhysicalLength.to_string());
399 register.supported_property_animation_types.insert(Type::LogicalLength.to_string());
400 register.supported_property_animation_types.insert(Type::Brush.to_string());
401 register.supported_property_animation_types.insert(Type::Angle.to_string());
402
403 #[rustfmt::skip]
404 macro_rules! map_type {
405 ($pub_type:ident, bool) => { Type::Bool };
406 ($pub_type:ident, i32) => { Type::Int32 };
407 ($pub_type:ident, f32) => { Type::Float32 };
408 ($pub_type:ident, SharedString) => { Type::String };
409 ($pub_type:ident, Image) => { Type::Image };
410 ($pub_type:ident, Coord) => { Type::LogicalLength };
411 ($pub_type:ident, KeyboardModifiers) => { $pub_type.clone() };
412 ($pub_type:ident, $_:ident) => {
413 BUILTIN.with(|e| Type::Enumeration(e.enums.$pub_type.clone()))
414 };
415 }
416 #[rustfmt::skip]
417 macro_rules! maybe_clone {
418 ($pub_type:ident, KeyboardModifiers) => { $pub_type.clone() };
419 ($pub_type:ident, $_:ident) => { $pub_type };
420 }
421 macro_rules! register_builtin_structs {
422 ($(
423 $(#[$attr:meta])*
424 struct $Name:ident {
425 @name = $inner_name:literal
426 export {
427 $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ident, )*
428 }
429 private {
430 $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*
431 }
432 }
433 )*) => { $(
434 #[allow(non_snake_case)]
435 let $Name = Type::Struct(Rc::new(Struct{
436 fields: BTreeMap::from([
437 $((stringify!($pub_field).replace_smolstr("_", "-"), map_type!($pub_type, $pub_type))),*
438 ]),
439 name: Some(format_smolstr!("{}", $inner_name)),
440 node: None,
441 rust_attributes: None,
442 }));
443 register.insert_type_with_name(maybe_clone!($Name, $Name), SmolStr::new(stringify!($Name)));
444 )* };
445 }
446 i_slint_common::for_each_builtin_structs!(register_builtin_structs);
447
448 crate::load_builtins::load_builtins(&mut register);
449
450 for e in register.elements.values() {
451 if let ElementType::Builtin(b) = e {
452 for accepted_child_type_name in b.additional_accepted_child_types.keys() {
453 register
454 .context_restricted_types
455 .entry(accepted_child_type_name.clone())
456 .or_default()
457 .insert(b.native_class.class_name.clone());
458 }
459 if b.additional_accept_self {
460 register
461 .context_restricted_types
462 .entry(b.native_class.class_name.clone())
463 .or_default()
464 .insert(b.native_class.class_name.clone());
465 }
466 }
467 }
468
469 match &mut register.elements.get_mut("PopupWindow").unwrap() {
470 ElementType::Builtin(ref mut b) => {
471 let popup = Rc::get_mut(b).unwrap();
472 popup.properties.insert(
473 "show".into(),
474 BuiltinPropertyInfo::from(BuiltinFunction::ShowPopupWindow),
475 );
476
477 popup.properties.insert(
478 "close".into(),
479 BuiltinPropertyInfo::from(BuiltinFunction::ClosePopupWindow),
480 );
481
482 popup.properties.get_mut("close-on-click").unwrap().property_visibility =
483 PropertyVisibility::Constexpr;
484
485 popup.properties.get_mut("close-policy").unwrap().property_visibility =
486 PropertyVisibility::Constexpr;
487 }
488 _ => unreachable!(),
489 };
490
491 let font_metrics_prop = crate::langtype::BuiltinPropertyInfo {
492 ty: font_metrics_type(),
493 property_visibility: PropertyVisibility::Output,
494 default_value: BuiltinPropertyDefault::WithElement(|elem| {
495 crate::expression_tree::Expression::FunctionCall {
496 function: BuiltinFunction::ItemFontMetrics.into(),
497 arguments: vec![crate::expression_tree::Expression::ElementReference(
498 Rc::downgrade(elem),
499 )],
500 source_location: None,
501 }
502 }),
503 };
504
505 match &mut register.elements.get_mut("TextInput").unwrap() {
506 ElementType::Builtin(ref mut b) => {
507 let text_input = Rc::get_mut(b).unwrap();
508 text_input.properties.insert(
509 "set-selection-offsets".into(),
510 BuiltinPropertyInfo::from(BuiltinFunction::SetSelectionOffsets),
511 );
512 text_input.properties.insert("font-metrics".into(), font_metrics_prop.clone());
513 }
514
515 _ => unreachable!(),
516 };
517
518 match &mut register.elements.get_mut("Text").unwrap() {
519 ElementType::Builtin(ref mut b) => {
520 let text = Rc::get_mut(b).unwrap();
521 text.properties.insert("font-metrics".into(), font_metrics_prop);
522 }
523
524 _ => unreachable!(),
525 };
526
527 match &mut register.elements.get_mut("Path").unwrap() {
528 ElementType::Builtin(ref mut b) => {
529 let path = Rc::get_mut(b).unwrap();
530 path.properties.get_mut("commands").unwrap().property_visibility =
531 PropertyVisibility::Fake;
532 }
533
534 _ => unreachable!(),
535 };
536
537 register
538 }
539
540 #[doc(hidden)]
541 /// All builtins incl. experimental ones! Do not use in production code!
542 pub fn builtin_experimental() -> Rc<RefCell<Self>> {
543 let register = Self::builtin_internal();
544 Rc::new(RefCell::new(register))
545 }
546
547 pub fn builtin() -> Rc<RefCell<Self>> {
548 let mut register = Self::builtin_internal();
549
550 register.elements.remove("ComponentContainer");
551 register.types.remove("component-factory");
552
553 Rc::new(RefCell::new(register))
554 }
555
556 pub fn new(parent: &Rc<RefCell<TypeRegister>>) -> Self {
557 Self {
558 parent_registry: Some(parent.clone()),
559 expose_internal_types: parent.borrow().expose_internal_types,
560 ..Default::default()
561 }
562 }
563
564 pub fn lookup(&self, name: &str) -> Type {
565 self.types
566 .get(name)
567 .cloned()
568 .or_else(|| self.parent_registry.as_ref().map(|r| r.borrow().lookup(name)))
569 .unwrap_or_default()
570 }
571
572 fn lookup_element_as_result(
573 &self,
574 name: &str,
575 ) -> Result<ElementType, HashMap<SmolStr, HashSet<SmolStr>>> {
576 match self.elements.get(name).cloned() {
577 Some(ty) => Ok(ty),
578 None => match &self.parent_registry {
579 Some(r) => r.borrow().lookup_element_as_result(name),
580 None => Err(self.context_restricted_types.clone()),
581 },
582 }
583 }
584
585 pub fn lookup_element(&self, name: &str) -> Result<ElementType, String> {
586 self.lookup_element_as_result(name).map_err(|context_restricted_types| {
587 if let Some(permitted_parent_types) = context_restricted_types.get(name) {
588 if permitted_parent_types.len() == 1 {
589 format!(
590 "{} can only be within a {} element",
591 name,
592 permitted_parent_types.iter().next().unwrap()
593 )
594 } else {
595 let mut elements = permitted_parent_types.iter().cloned().collect::<Vec<_>>();
596 elements.sort();
597 format!(
598 "{} can only be within the following elements: {}",
599 name,
600 elements.join(", ")
601 )
602 }
603 } else if let Some(ty) = self.types.get(name) {
604 format!("'{ty}' cannot be used as an element")
605 } else {
606 format!("Unknown element '{name}'")
607 }
608 })
609 }
610
611 pub fn lookup_builtin_element(&self, name: &str) -> Option<ElementType> {
612 self.parent_registry.as_ref().map_or_else(
613 || self.elements.get(name).cloned(),
614 |p| p.borrow().lookup_builtin_element(name),
615 )
616 }
617
618 pub fn lookup_qualified<Member: AsRef<str>>(&self, qualified: &[Member]) -> Type {
619 if qualified.len() != 1 {
620 return Type::Invalid;
621 }
622 self.lookup(qualified[0].as_ref())
623 }
624
625 /// Add the component with it's defined name
626 ///
627 /// Returns false if there was already an element with the same name
628 pub fn add(&mut self, comp: Rc<Component>) -> bool {
629 self.add_with_name(comp.id.clone(), comp)
630 }
631
632 /// Add the component with a specified name
633 ///
634 /// Returns false if there was already an element with the same name
635 pub fn add_with_name(&mut self, name: SmolStr, comp: Rc<Component>) -> bool {
636 self.elements.insert(name, ElementType::Component(comp)).is_none()
637 }
638
639 pub fn add_builtin(&mut self, builtin: Rc<BuiltinElement>) {
640 self.elements.insert(builtin.name.clone(), ElementType::Builtin(builtin));
641 }
642
643 pub fn property_animation_type_for_property(&self, property_type: Type) -> ElementType {
644 if self.supported_property_animation_types.contains(&property_type.to_string()) {
645 self.property_animation_type.clone()
646 } else {
647 self.parent_registry
648 .as_ref()
649 .map(|registry| {
650 registry.borrow().property_animation_type_for_property(property_type)
651 })
652 .unwrap_or_default()
653 }
654 }
655
656 /// Return a hashmap with all the registered type
657 pub fn all_types(&self) -> HashMap<SmolStr, Type> {
658 let mut all =
659 self.parent_registry.as_ref().map(|r| r.borrow().all_types()).unwrap_or_default();
660 for (k, v) in &self.types {
661 all.insert(k.clone(), v.clone());
662 }
663 all
664 }
665
666 /// Return a hashmap with all the registered element type
667 pub fn all_elements(&self) -> HashMap<SmolStr, ElementType> {
668 let mut all =
669 self.parent_registry.as_ref().map(|r| r.borrow().all_elements()).unwrap_or_default();
670 for (k, v) in &self.elements {
671 all.insert(k.clone(), v.clone());
672 }
673 all
674 }
675
676 pub fn empty_type(&self) -> ElementType {
677 match self.parent_registry.as_ref() {
678 Some(parent) => parent.borrow().empty_type(),
679 None => self.empty_type.clone(),
680 }
681 }
682}
683
684pub fn logical_point_type() -> Type {
685 BUILTIN.with(|types: &BuiltinTypes| types.logical_point_type.clone())
686}
687
688pub fn font_metrics_type() -> Type {
689 BUILTIN.with(|types: &BuiltinTypes| types.font_metrics_type.clone())
690}
691
692/// The [`Type`] for a runtime LayoutInfo structure
693pub fn layout_info_type() -> Rc<Struct> {
694 BUILTIN.with(|types: &BuiltinTypes| types.layout_info_type.clone())
695}
696
697/// The [`Type`] for a runtime PathElement structure
698pub fn path_element_type() -> Type {
699 BUILTIN.with(|types: &BuiltinTypes| types.path_element_type.clone())
700}
701
702/// The [`Type`] for a runtime BoxLayoutCellData structure
703pub fn box_layout_cell_data_type() -> Type {
704 BUILTIN.with(|types: &BuiltinTypes| types.box_layout_cell_data_type.clone())
705}
706