1use smol_str::{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, BuiltinPrivateStruct, BuiltinPropertyDefault, BuiltinPropertyInfo,
14 BuiltinPublicStruct, ElementType, Enumeration, 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: Rc<Struct>,
86 pub logical_size_type: Rc<Struct>,
87 pub font_metrics_type: Type,
88 pub layout_info_type: Rc<Struct>,
89 pub gridlayout_input_data_type: Type,
90 pub path_element_type: Type,
91 pub box_layout_cell_data_type: Type,
92}
93
94impl BuiltinTypes {
95 fn new() -> Self {
96 let layout_info_type = Rc::new(Struct {
97 fields: ["min", "max", "preferred"]
98 .iter()
99 .map(|s| (SmolStr::new_static(s), Type::LogicalLength))
100 .chain(
101 ["min_percent", "max_percent", "stretch"]
102 .iter()
103 .map(|s| (SmolStr::new_static(s), Type::Float32)),
104 )
105 .collect(),
106 name: BuiltinPrivateStruct::LayoutInfo.into(),
107 });
108 Self {
109 enums: BuiltinEnums::new(),
110 logical_point_type: 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: BuiltinPublicStruct::LogicalPosition.into(),
117 }),
118 logical_size_type: Rc::new(Struct {
119 fields: IntoIterator::into_iter([
120 (SmolStr::new_static("width"), Type::LogicalLength),
121 (SmolStr::new_static("height"), Type::LogicalLength),
122 ])
123 .collect(),
124 name: BuiltinPublicStruct::LogicalSize.into(),
125 }),
126 font_metrics_type: Type::Struct(Rc::new(Struct {
127 fields: IntoIterator::into_iter([
128 (SmolStr::new_static("ascent"), Type::LogicalLength),
129 (SmolStr::new_static("descent"), Type::LogicalLength),
130 (SmolStr::new_static("x-height"), Type::LogicalLength),
131 (SmolStr::new_static("cap-height"), Type::LogicalLength),
132 ])
133 .collect(),
134 name: BuiltinPrivateStruct::FontMetrics.into(),
135 })),
136 noarg_callback_type: Type::Callback(Rc::new(Function {
137 return_type: Type::Void,
138 args: Vec::new(),
139 arg_names: Vec::new(),
140 })),
141 strarg_callback_type: Type::Callback(Rc::new(Function {
142 return_type: Type::Void,
143 args: vec![Type::String],
144 arg_names: Vec::new(),
145 })),
146 layout_info_type: layout_info_type.clone(),
147 path_element_type: Type::Struct(Rc::new(Struct {
148 fields: Default::default(),
149 name: BuiltinPrivateStruct::PathElement.into(),
150 })),
151 box_layout_cell_data_type: Type::Struct(Rc::new(Struct {
152 fields: IntoIterator::into_iter([("constraint".into(), layout_info_type.into())])
153 .collect(),
154 name: BuiltinPrivateStruct::LayoutItemInfo.into(),
155 })),
156 gridlayout_input_data_type: Type::Struct(Rc::new(Struct {
157 fields: IntoIterator::into_iter([
158 ("row".into(), Type::Int32),
159 ("column".into(), Type::Int32),
160 ("rowspan".into(), Type::Int32),
161 ("colspan".into(), Type::Int32),
162 ])
163 .collect(),
164 name: BuiltinPrivateStruct::GridLayoutInputData.into(),
165 })),
166 }
167 }
168}
169
170thread_local! {
171 pub static BUILTIN: BuiltinTypes = BuiltinTypes::new();
172}
173
174const RESERVED_OTHER_PROPERTIES: &[(&str, Type)] = &[
175 ("clip", Type::Bool),
176 ("opacity", Type::Float32),
177 ("cache-rendering-hint", Type::Bool),
178 ("visible", Type::Bool), ];
180
181pub const RESERVED_DROP_SHADOW_PROPERTIES: &[(&str, Type)] = &[
182 ("drop-shadow-offset-x", Type::LogicalLength),
183 ("drop-shadow-offset-y", Type::LogicalLength),
184 ("drop-shadow-blur", Type::LogicalLength),
185 ("drop-shadow-color", Type::Color),
186];
187
188pub const RESERVED_TRANSFORM_PROPERTIES: &[(&str, Type)] = &[
189 ("transform-rotation", Type::Angle),
190 ("transform-scale-x", Type::Float32),
191 ("transform-scale-y", Type::Float32),
192 ("transform-scale", Type::Float32),
193];
194
195pub fn transform_origin_property() -> (&'static str, Rc<Struct>) {
196 ("transform-origin", logical_point_type())
197}
198
199pub const DEPRECATED_ROTATION_ORIGIN_PROPERTIES: [(&str, Type); 2] =
200 [("rotation-origin-x", Type::LogicalLength), ("rotation-origin-y", Type::LogicalLength)];
201
202pub fn noarg_callback_type() -> Type {
203 BUILTIN.with(|types| types.noarg_callback_type.clone())
204}
205
206fn strarg_callback_type() -> Type {
207 BUILTIN.with(|types| types.strarg_callback_type.clone())
208}
209
210pub fn reserved_accessibility_properties() -> impl Iterator<Item = (&'static str, Type)> {
211 [
212 ("accessible-checkable", Type::Bool),
214 ("accessible-checked", Type::Bool),
215 ("accessible-delegate-focus", Type::Int32),
216 ("accessible-description", Type::String),
217 ("accessible-enabled", Type::Bool),
218 ("accessible-expandable", Type::Bool),
219 ("accessible-expanded", Type::Bool),
220 ("accessible-id", Type::String),
221 ("accessible-label", Type::String),
222 ("accessible-value", Type::String),
223 ("accessible-value-maximum", Type::Float32),
224 ("accessible-value-minimum", Type::Float32),
225 ("accessible-value-step", Type::Float32),
226 ("accessible-placeholder-text", Type::String),
227 ("accessible-action-default", noarg_callback_type()),
228 ("accessible-action-increment", noarg_callback_type()),
229 ("accessible-action-decrement", noarg_callback_type()),
230 ("accessible-action-set-value", strarg_callback_type()),
231 ("accessible-action-expand", noarg_callback_type()),
232 ("accessible-item-selectable", Type::Bool),
233 ("accessible-item-selected", Type::Bool),
234 ("accessible-item-index", Type::Int32),
235 ("accessible-item-count", Type::Int32),
236 ("accessible-read-only", Type::Bool),
237 ]
238 .into_iter()
239}
240
241pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type, PropertyVisibility)> {
243 RESERVED_GEOMETRY_PROPERTIES
244 .iter()
245 .chain(RESERVED_LAYOUT_PROPERTIES.iter())
246 .chain(RESERVED_OTHER_PROPERTIES.iter())
247 .chain(RESERVED_DROP_SHADOW_PROPERTIES.iter())
248 .chain(RESERVED_TRANSFORM_PROPERTIES.iter())
249 .chain(DEPRECATED_ROTATION_ORIGIN_PROPERTIES.iter())
250 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input))
251 .chain(
252 std::iter::once(transform_origin_property())
253 .map(|(k, v)| (k, v.into(), PropertyVisibility::Input)),
254 )
255 .chain(reserved_accessibility_properties().map(|(k, v)| (k, v, PropertyVisibility::Input)))
256 .chain(
257 RESERVED_GRIDLAYOUT_PROPERTIES
258 .iter()
259 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
260 )
261 .chain(IntoIterator::into_iter([
262 ("absolute-position", logical_point_type().into(), PropertyVisibility::Output),
263 ("forward-focus", Type::ElementReference, PropertyVisibility::Constexpr),
264 (
265 "focus",
266 Type::Function(BuiltinFunction::SetFocusItem.ty()),
267 PropertyVisibility::Public,
268 ),
269 (
270 "clear-focus",
271 Type::Function(BuiltinFunction::ClearFocusItem.ty()),
272 PropertyVisibility::Public,
273 ),
274 (
275 "dialog-button-role",
276 Type::Enumeration(BUILTIN.with(|e| e.enums.DialogButtonRole.clone())),
277 PropertyVisibility::Constexpr,
278 ),
279 (
280 "accessible-role",
281 Type::Enumeration(BUILTIN.with(|e| e.enums.AccessibleRole.clone())),
282 PropertyVisibility::Constexpr,
283 ),
284 ]))
285 .chain(std::iter::once(("init", noarg_callback_type(), PropertyVisibility::Private)))
286}
287
288pub fn reserved_property(name: std::borrow::Cow<'_, str>) -> PropertyLookupResult<'_> {
290 thread_local! {
291 static RESERVED_PROPERTIES: HashMap<&'static str, (Type, PropertyVisibility, Option<BuiltinFunction>)>
292 = reserved_properties().map(|(name, ty, visibility)| (name, (ty, visibility, reserved_member_function(name)))).collect();
293 }
294 if let Some((ty, visibility, builtin_function)) =
295 RESERVED_PROPERTIES.with(|reserved| reserved.get(name.as_ref()).cloned())
296 {
297 return PropertyLookupResult {
298 property_type: ty,
299 resolved_name: name,
300 is_local_to_component: false,
301 is_in_direct_base: false,
302 property_visibility: visibility,
303 declared_pure: None,
304 builtin_function,
305 };
306 }
307
308 for pre in &["min", "max"] {
310 if let Some(a) = name.strip_prefix(pre) {
311 for suf in &["width", "height"] {
312 if let Some(b) = a.strip_suffix(suf)
313 && b == "imum-"
314 {
315 return PropertyLookupResult {
316 property_type: Type::LogicalLength,
317 resolved_name: format!("{pre}-{suf}").into(),
318 is_local_to_component: false,
319 is_in_direct_base: false,
320 property_visibility: crate::object_tree::PropertyVisibility::InOut,
321 declared_pure: None,
322 builtin_function: None,
323 };
324 }
325 }
326 }
327 }
328 PropertyLookupResult::invalid(name)
329}
330
331pub fn reserved_member_function(name: &str) -> Option<BuiltinFunction> {
333 for (m, e) in [
334 ("focus", BuiltinFunction::SetFocusItem), ("clear-focus", BuiltinFunction::ClearFocusItem), ] {
337 if m == name {
338 return Some(e);
339 }
340 }
341 None
342}
343
344#[derive(Debug, Default)]
346pub struct TypeRegister {
347 types: HashMap<SmolStr, Type>,
349 elements: HashMap<SmolStr, ElementType>,
351 supported_property_animation_types: HashSet<String>,
352 pub(crate) property_animation_type: ElementType,
353 pub(crate) empty_type: ElementType,
354 context_restricted_types: HashMap<SmolStr, HashSet<SmolStr>>,
357 parent_registry: Option<Rc<RefCell<TypeRegister>>>,
358 pub(crate) expose_internal_types: bool,
360}
361
362impl TypeRegister {
363 pub(crate) fn snapshot(&self, snapshotter: &mut typeloader::Snapshotter) -> Self {
364 Self {
365 types: self.types.clone(),
366 elements: self
367 .elements
368 .iter()
369 .map(|(k, v)| (k.clone(), snapshotter.snapshot_element_type(v)))
370 .collect(),
371 supported_property_animation_types: self.supported_property_animation_types.clone(),
372 property_animation_type: snapshotter
373 .snapshot_element_type(&self.property_animation_type),
374 empty_type: snapshotter.snapshot_element_type(&self.empty_type),
375 context_restricted_types: self.context_restricted_types.clone(),
376 parent_registry: self
377 .parent_registry
378 .as_ref()
379 .map(|tr| snapshotter.snapshot_type_register(tr)),
380 expose_internal_types: self.expose_internal_types,
381 }
382 }
383
384 pub fn insert_type(&mut self, t: Type) -> bool {
388 self.types.insert(t.to_smolstr(), t).is_none()
389 }
390 pub fn insert_type_with_name(&mut self, t: Type, name: SmolStr) -> bool {
394 self.types.insert(name, t).is_none()
395 }
396
397 fn builtin_internal() -> Self {
398 let mut register = TypeRegister::default();
399
400 register.insert_type(Type::Float32);
401 register.insert_type(Type::Int32);
402 register.insert_type(Type::String);
403 register.insert_type(Type::PhysicalLength);
404 register.insert_type(Type::LogicalLength);
405 register.insert_type(Type::Color);
406 register.insert_type(Type::ComponentFactory);
407 register.insert_type(Type::Duration);
408 register.insert_type(Type::Image);
409 register.insert_type(Type::Bool);
410 register.insert_type(Type::Model);
411 register.insert_type(Type::Percent);
412 register.insert_type(Type::Easing);
413 register.insert_type(Type::Angle);
414 register.insert_type(Type::Brush);
415 register.insert_type(Type::Rem);
416 register.insert_type(Type::StyledText);
417 register.types.insert("Point".into(), logical_point_type().into());
418 register.types.insert("Size".into(), logical_size_type().into());
419
420 BUILTIN.with(|e| e.enums.fill_register(&mut register));
421
422 register.supported_property_animation_types.insert(Type::Float32.to_string());
423 register.supported_property_animation_types.insert(Type::Int32.to_string());
424 register.supported_property_animation_types.insert(Type::Color.to_string());
425 register.supported_property_animation_types.insert(Type::PhysicalLength.to_string());
426 register.supported_property_animation_types.insert(Type::LogicalLength.to_string());
427 register.supported_property_animation_types.insert(Type::Brush.to_string());
428 register.supported_property_animation_types.insert(Type::Angle.to_string());
429
430 #[rustfmt::skip]
431 macro_rules! map_type {
432 ($pub_type:ident, bool) => { Type::Bool };
433 ($pub_type:ident, i32) => { Type::Int32 };
434 ($pub_type:ident, f32) => { Type::Float32 };
435 ($pub_type:ident, SharedString) => { Type::String };
436 ($pub_type:ident, Image) => { Type::Image };
437 ($pub_type:ident, Coord) => { Type::LogicalLength };
438 ($pub_type:ident, LogicalPosition) => { Type::Struct(logical_point_type()) };
439 ($pub_type:ident, LogicalSize) => { Type::Struct(logical_size_type()) };
440 ($pub_type:ident, KeyboardModifiers) => { $pub_type.clone() };
441 ($pub_type:ident, $_:ident) => {
442 BUILTIN.with(|e| Type::Enumeration(e.enums.$pub_type.clone()))
443 };
444 }
445 #[rustfmt::skip]
446 macro_rules! maybe_clone {
447 ($pub_type:ident, KeyboardModifiers) => { $pub_type.clone() };
448 ($pub_type:ident, $_:ident) => { $pub_type };
449 }
450 macro_rules! register_builtin_structs {
451 ($(
452 $(#[$attr:meta])*
453 struct $Name:ident {
454 @name = $inner_name:expr,
455 export {
456 $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ident, )*
457 }
458 private {
459 $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*
460 }
461 }
462 )*) => { $(
463 #[allow(non_snake_case)]
464 let $Name = Type::Struct(Rc::new(Struct{
465 fields: BTreeMap::from([
466 $((stringify!($pub_field).replace_smolstr("_", "-"), map_type!($pub_type, $pub_type))),*
467 ]),
468 name: $inner_name.into(),
469 }));
470 register.insert_type_with_name(maybe_clone!($Name, $Name), SmolStr::new(stringify!($Name)));
471 )* };
472 }
473 i_slint_common::for_each_builtin_structs!(register_builtin_structs);
474
475 crate::load_builtins::load_builtins(&mut register);
476
477 for e in register.elements.values() {
478 if let ElementType::Builtin(b) = e {
479 for accepted_child_type_name in b.additional_accepted_child_types.keys() {
480 register
481 .context_restricted_types
482 .entry(accepted_child_type_name.clone())
483 .or_default()
484 .insert(b.native_class.class_name.clone());
485 }
486 if b.additional_accept_self {
487 register
488 .context_restricted_types
489 .entry(b.native_class.class_name.clone())
490 .or_default()
491 .insert(b.native_class.class_name.clone());
492 }
493 }
494 }
495
496 match &mut register.elements.get_mut("PopupWindow").unwrap() {
497 ElementType::Builtin(b) => {
498 let popup = Rc::get_mut(b).unwrap();
499 popup.properties.insert(
500 "show".into(),
501 BuiltinPropertyInfo::from(BuiltinFunction::ShowPopupWindow),
502 );
503
504 popup.properties.insert(
505 "close".into(),
506 BuiltinPropertyInfo::from(BuiltinFunction::ClosePopupWindow),
507 );
508
509 popup.properties.get_mut("close-on-click").unwrap().property_visibility =
510 PropertyVisibility::Constexpr;
511
512 popup.properties.get_mut("close-policy").unwrap().property_visibility =
513 PropertyVisibility::Constexpr;
514 }
515 _ => unreachable!(),
516 };
517
518 match &mut register.elements.get_mut("Timer").unwrap() {
519 ElementType::Builtin(b) => {
520 let timer = Rc::get_mut(b).unwrap();
521 timer
522 .properties
523 .insert("start".into(), BuiltinPropertyInfo::from(BuiltinFunction::StartTimer));
524 timer
525 .properties
526 .insert("stop".into(), BuiltinPropertyInfo::from(BuiltinFunction::StopTimer));
527 timer.properties.insert(
528 "restart".into(),
529 BuiltinPropertyInfo::from(BuiltinFunction::RestartTimer),
530 );
531 }
532 _ => unreachable!(),
533 }
534
535 let font_metrics_prop = crate::langtype::BuiltinPropertyInfo {
536 ty: font_metrics_type(),
537 property_visibility: PropertyVisibility::Output,
538 default_value: BuiltinPropertyDefault::WithElement(|elem| {
539 crate::expression_tree::Expression::FunctionCall {
540 function: BuiltinFunction::ItemFontMetrics.into(),
541 arguments: vec![crate::expression_tree::Expression::ElementReference(
542 Rc::downgrade(elem),
543 )],
544 source_location: None,
545 }
546 }),
547 };
548
549 match &mut register.elements.get_mut("TextInput").unwrap() {
550 ElementType::Builtin(b) => {
551 let text_input = Rc::get_mut(b).unwrap();
552 text_input.properties.insert(
553 "set-selection-offsets".into(),
554 BuiltinPropertyInfo::from(BuiltinFunction::SetSelectionOffsets),
555 );
556 text_input.properties.insert("font-metrics".into(), font_metrics_prop.clone());
557 }
558
559 _ => unreachable!(),
560 };
561
562 match &mut register.elements.get_mut("Text").unwrap() {
563 ElementType::Builtin(b) => {
564 let text = Rc::get_mut(b).unwrap();
565 text.properties.insert("font-metrics".into(), font_metrics_prop);
566 }
567
568 _ => unreachable!(),
569 };
570
571 match &mut register.elements.get_mut("Path").unwrap() {
572 ElementType::Builtin(b) => {
573 let path = Rc::get_mut(b).unwrap();
574 path.properties.get_mut("commands").unwrap().property_visibility =
575 PropertyVisibility::Fake;
576 }
577
578 _ => unreachable!(),
579 };
580
581 match &mut register.elements.get_mut("TabWidget").unwrap() {
582 ElementType::Builtin(b) => {
583 let tabwidget = Rc::get_mut(b).unwrap();
584 tabwidget.properties.get_mut("orientation").unwrap().property_visibility =
585 PropertyVisibility::Constexpr;
586 }
587 _ => unreachable!(),
588 }
589
590 register
591 }
592
593 #[doc(hidden)]
594 pub fn builtin_experimental() -> Rc<RefCell<Self>> {
596 let register = Self::builtin_internal();
597 Rc::new(RefCell::new(register))
598 }
599
600 pub fn builtin() -> Rc<RefCell<Self>> {
601 let mut register = Self::builtin_internal();
602
603 register.elements.remove("ComponentContainer").unwrap();
604 register.types.remove("component-factory").unwrap();
605
606 register.elements.remove("DragArea").unwrap();
607 register.elements.remove("DropArea").unwrap();
608 register.types.remove("DropEvent").unwrap(); register.elements.remove("StyledText").unwrap();
611 register.types.remove("styled-text").unwrap();
612
613 match register.elements.get_mut("Window").unwrap() {
614 ElementType::Builtin(b) => {
615 Rc::get_mut(b)
616 .expect("Should not be shared at this point")
617 .properties
618 .remove("hide")
619 .unwrap();
620 }
621 _ => unreachable!(),
622 }
623
624 Rc::new(RefCell::new(register))
625 }
626
627 pub fn new(parent: &Rc<RefCell<TypeRegister>>) -> Self {
628 Self {
629 parent_registry: Some(parent.clone()),
630 expose_internal_types: parent.borrow().expose_internal_types,
631 ..Default::default()
632 }
633 }
634
635 pub fn lookup(&self, name: &str) -> Type {
636 self.types
637 .get(name)
638 .cloned()
639 .or_else(|| self.parent_registry.as_ref().map(|r| r.borrow().lookup(name)))
640 .unwrap_or_default()
641 }
642
643 fn lookup_element_as_result(
644 &self,
645 name: &str,
646 ) -> Result<ElementType, HashMap<SmolStr, HashSet<SmolStr>>> {
647 match self.elements.get(name).cloned() {
648 Some(ty) => Ok(ty),
649 None => match &self.parent_registry {
650 Some(r) => r.borrow().lookup_element_as_result(name),
651 None => Err(self.context_restricted_types.clone()),
652 },
653 }
654 }
655
656 pub fn lookup_element(&self, name: &str) -> Result<ElementType, String> {
657 self.lookup_element_as_result(name).map_err(|context_restricted_types| {
658 if let Some(permitted_parent_types) = context_restricted_types.get(name) {
659 if permitted_parent_types.len() == 1 {
660 format!(
661 "{} can only be within a {} element",
662 name,
663 permitted_parent_types.iter().next().unwrap()
664 )
665 } else {
666 let mut elements = permitted_parent_types.iter().cloned().collect::<Vec<_>>();
667 elements.sort();
668 format!(
669 "{} can only be within the following elements: {}",
670 name,
671 elements.join(", ")
672 )
673 }
674 } else if let Some(ty) = self.types.get(name) {
675 format!("'{ty}' cannot be used as an element")
676 } else {
677 format!("Unknown element '{name}'")
678 }
679 })
680 }
681
682 pub fn lookup_builtin_element(&self, name: &str) -> Option<ElementType> {
683 self.parent_registry.as_ref().map_or_else(
684 || self.elements.get(name).cloned(),
685 |p| p.borrow().lookup_builtin_element(name),
686 )
687 }
688
689 pub fn lookup_qualified<Member: AsRef<str>>(&self, qualified: &[Member]) -> Type {
690 if qualified.len() != 1 {
691 return Type::Invalid;
692 }
693 self.lookup(qualified[0].as_ref())
694 }
695
696 pub fn add(&mut self, comp: Rc<Component>) -> bool {
700 self.add_with_name(comp.id.clone(), comp)
701 }
702
703 pub fn add_with_name(&mut self, name: SmolStr, comp: Rc<Component>) -> bool {
707 self.elements.insert(name, ElementType::Component(comp)).is_none()
708 }
709
710 pub fn add_builtin(&mut self, builtin: Rc<BuiltinElement>) {
711 self.elements.insert(builtin.name.clone(), ElementType::Builtin(builtin));
712 }
713
714 pub fn property_animation_type_for_property(&self, property_type: Type) -> ElementType {
715 if self.supported_property_animation_types.contains(&property_type.to_string()) {
716 self.property_animation_type.clone()
717 } else {
718 self.parent_registry
719 .as_ref()
720 .map(|registry| {
721 registry.borrow().property_animation_type_for_property(property_type)
722 })
723 .unwrap_or_default()
724 }
725 }
726
727 pub fn all_types(&self) -> HashMap<SmolStr, Type> {
729 let mut all =
730 self.parent_registry.as_ref().map(|r| r.borrow().all_types()).unwrap_or_default();
731 for (k, v) in &self.types {
732 all.insert(k.clone(), v.clone());
733 }
734 all
735 }
736
737 pub fn all_elements(&self) -> HashMap<SmolStr, ElementType> {
739 let mut all =
740 self.parent_registry.as_ref().map(|r| r.borrow().all_elements()).unwrap_or_default();
741 for (k, v) in &self.elements {
742 all.insert(k.clone(), v.clone());
743 }
744 all
745 }
746
747 pub fn empty_type(&self) -> ElementType {
748 match self.parent_registry.as_ref() {
749 Some(parent) => parent.borrow().empty_type(),
750 None => self.empty_type.clone(),
751 }
752 }
753}
754
755pub fn logical_point_type() -> Rc<Struct> {
756 BUILTIN.with(|types| types.logical_point_type.clone())
757}
758
759pub fn logical_size_type() -> Rc<Struct> {
760 BUILTIN.with(|types| types.logical_size_type.clone())
761}
762
763pub fn font_metrics_type() -> Type {
764 BUILTIN.with(|types| types.font_metrics_type.clone())
765}
766
767pub fn layout_info_type() -> Rc<Struct> {
769 BUILTIN.with(|types| types.layout_info_type.clone())
770}
771
772pub fn path_element_type() -> Type {
774 BUILTIN.with(|types| types.path_element_type.clone())
775}
776
777pub fn box_layout_cell_data_type() -> Type {
779 BUILTIN.with(|types| types.box_layout_cell_data_type.clone())
780}