Skip to main content

i_slint_compiler/
typeregister.rs

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::{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), // ("enabled", Type::Bool),
179];
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-role", ...)
213        ("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
241/// list of reserved property injected in every item
242pub 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
288/// lookup reserved property injected in every item
289pub 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    // Report deprecated known reserved properties (maximum_width, minimum_height, ...)
309    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
331/// These member functions are injected in every time
332pub fn reserved_member_function(name: &str) -> Option<BuiltinFunction> {
333    for (m, e) in [
334        ("focus", BuiltinFunction::SetFocusItem), // match for callable "focus" property
335        ("clear-focus", BuiltinFunction::ClearFocusItem), // match for callable "clear-focus" property
336    ] {
337        if m == name {
338            return Some(e);
339        }
340    }
341    None
342}
343
344/// All types (datatypes, internal elements, properties, ...) are stored in this type
345#[derive(Debug, Default)]
346pub struct TypeRegister {
347    /// The set of property types.
348    types: HashMap<SmolStr, Type>,
349    /// The set of element types
350    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    /// Map from a context restricted type to the list of contexts (parent type) it is allowed in. This is
355    /// used to construct helpful error messages, such as "Row can only be within a GridLayout element".
356    context_restricted_types: HashMap<SmolStr, HashSet<SmolStr>>,
357    parent_registry: Option<Rc<RefCell<TypeRegister>>>,
358    /// If the lookup function should return types that are marked as internal
359    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    /// Insert a type into the type register with its builtin type name.
385    ///
386    /// Returns false if it replaced an existing type.
387    pub fn insert_type(&mut self, t: Type) -> bool {
388        self.types.insert(t.to_smolstr(), t).is_none()
389    }
390    /// Insert a type into the type register with a specified name.
391    ///
392    /// Returns false if it replaced an existing type.
393    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    /// All builtins incl. experimental ones! Do not use in production code!
595    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(); // Also removed in xtask/src/slintdocs.rs
609
610        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    /// Add the component with its defined name
697    ///
698    /// Returns false if there was already an element with the same name
699    pub fn add(&mut self, comp: Rc<Component>) -> bool {
700        self.add_with_name(comp.id.clone(), comp)
701    }
702
703    /// Add the component with a specified name
704    ///
705    /// Returns false if there was already an element with the same name
706    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    /// Return a hashmap with all the registered type
728    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    /// Return a hashmap with all the registered element type
738    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
767/// The [`Type`] for a runtime LayoutInfo structure
768pub fn layout_info_type() -> Rc<Struct> {
769    BUILTIN.with(|types| types.layout_info_type.clone())
770}
771
772/// The [`Type`] for a runtime PathElement structure
773pub fn path_element_type() -> Type {
774    BUILTIN.with(|types| types.path_element_type.clone())
775}
776
777/// The [`Type`] for a runtime LayoutItemInfo structure
778pub fn box_layout_cell_data_type() -> Type {
779    BUILTIN.with(|types| types.box_layout_cell_data_type.clone())
780}