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