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, BuiltinPropertyDefault, BuiltinPropertyInfo, BuiltinStruct, ElementType,
14 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])* $vis:vis 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: BuiltinStruct::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: BuiltinStruct::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: BuiltinStruct::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: BuiltinStruct::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: BuiltinStruct::StateInfo.into(),
168 }),
169 path_element_type: Type::Struct(Rc::new(Struct {
170 fields: Default::default(),
171 name: BuiltinStruct::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: BuiltinStruct::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: BuiltinStruct::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: BuiltinStruct::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-spread", Type::LogicalLength),
223 ("drop-shadow-color", Type::Color),
224];
225
226pub const RESERVED_INNER_SHADOW_PROPERTIES: &[(&str, Type)] = &[
227 ("inner-shadow-offset-x", Type::LogicalLength),
228 ("inner-shadow-offset-y", Type::LogicalLength),
229 ("inner-shadow-blur", Type::LogicalLength),
230 ("inner-shadow-spread", Type::LogicalLength),
231 ("inner-shadow-color", Type::Color),
232];
233
234pub const RESERVED_TRANSFORM_PROPERTIES: &[(&str, Type)] = &[
235 ("transform-rotation", Type::Angle),
236 ("transform-scale-x", Type::Float32),
237 ("transform-scale-y", Type::Float32),
238 ("transform-scale", Type::Float32),
239];
240
241pub fn transform_origin_property() -> (&'static str, Rc<Struct>) {
242 ("transform-origin", logical_point_type())
243}
244
245pub const DEPRECATED_ROTATION_ORIGIN_PROPERTIES: [(&str, Type); 2] =
246 [("rotation-origin-x", Type::LogicalLength), ("rotation-origin-y", Type::LogicalLength)];
247
248pub fn noarg_callback_type() -> Type {
249 BUILTIN.with(|types| types.noarg_callback_type.clone())
250}
251
252fn strarg_callback_type() -> Type {
253 BUILTIN.with(|types| types.strarg_callback_type.clone())
254}
255
256pub fn reserved_accessibility_properties() -> impl Iterator<Item = (&'static str, Type)> {
257 [
258 ("accessible-checkable", Type::Bool),
260 ("accessible-checked", Type::Bool),
261 ("accessible-delegate-focus", Type::Int32),
262 ("accessible-description", Type::String),
263 ("accessible-enabled", Type::Bool),
264 ("accessible-expandable", Type::Bool),
265 ("accessible-expanded", Type::Bool),
266 ("accessible-id", Type::String),
267 ("accessible-label", Type::String),
268 ("accessible-value", Type::String),
269 ("accessible-value-maximum", Type::Float32),
270 ("accessible-value-minimum", Type::Float32),
271 ("accessible-value-step", Type::Float32),
272 ("accessible-placeholder-text", Type::String),
273 ("accessible-action-default", noarg_callback_type()),
274 ("accessible-action-increment", noarg_callback_type()),
275 ("accessible-action-decrement", noarg_callback_type()),
276 ("accessible-action-set-value", strarg_callback_type()),
277 ("accessible-action-expand", noarg_callback_type()),
278 ("accessible-item-selectable", Type::Bool),
279 ("accessible-item-selected", Type::Bool),
280 ("accessible-item-index", Type::Int32),
281 ("accessible-item-count", Type::Int32),
282 ("accessible-read-only", Type::Bool),
283 ]
284 .into_iter()
285}
286
287pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type, PropertyVisibility)> {
289 RESERVED_GEOMETRY_PROPERTIES
290 .iter()
291 .chain(RESERVED_LAYOUT_PROPERTIES.iter())
292 .chain(RESERVED_OTHER_PROPERTIES.iter())
293 .chain(RESERVED_DROP_SHADOW_PROPERTIES.iter())
294 .chain(RESERVED_INNER_SHADOW_PROPERTIES.iter())
295 .chain(RESERVED_TRANSFORM_PROPERTIES.iter())
296 .chain(DEPRECATED_ROTATION_ORIGIN_PROPERTIES.iter())
297 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input))
298 .chain(
299 std::iter::once(transform_origin_property())
300 .map(|(k, v)| (k, v.into(), PropertyVisibility::Input)),
301 )
302 .chain(reserved_accessibility_properties().map(|(k, v)| (k, v, PropertyVisibility::Input)))
303 .chain(
304 RESERVED_GRIDLAYOUT_PROPERTIES
305 .iter()
306 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
307 )
308 .chain(
309 RESERVED_FLEXBOXLAYOUT_PROPERTIES
310 .iter()
311 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
312 )
313 .chain(std::iter::once((
316 "flex-align-self",
317 Type::Enumeration(BUILTIN.with(|e| e.enums.FlexboxLayoutAlignSelf.clone())),
318 PropertyVisibility::Input,
319 )))
320 .chain(IntoIterator::into_iter([
321 ("absolute-position", logical_point_type().into(), PropertyVisibility::Output),
322 ("forward-focus", Type::ElementReference, PropertyVisibility::Constexpr),
323 (
324 "focus",
325 Type::Function(BuiltinFunction::SetFocusItem.ty()),
326 PropertyVisibility::Public,
327 ),
328 (
329 "clear-focus",
330 Type::Function(BuiltinFunction::ClearFocusItem.ty()),
331 PropertyVisibility::Public,
332 ),
333 (
334 "dialog-button-role",
335 Type::Enumeration(BUILTIN.with(|e| e.enums.DialogButtonRole.clone())),
336 PropertyVisibility::Constexpr,
337 ),
338 (
339 "accessible-role",
340 Type::Enumeration(BUILTIN.with(|e| e.enums.AccessibleRole.clone())),
341 PropertyVisibility::Constexpr,
342 ),
343 (
344 "accessible-orientation",
345 Type::Enumeration(BUILTIN.with(|e| e.enums.Orientation.clone())),
346 PropertyVisibility::Input,
347 ),
348 (
349 "accessible-live-region",
350 Type::Enumeration(BUILTIN.with(|e| e.enums.AccessibleLiveness.clone())),
351 PropertyVisibility::Input,
352 ),
353 ]))
354 .chain(std::iter::once(("init", noarg_callback_type(), PropertyVisibility::Private)))
355}
356
357pub fn reserved_property(name: std::borrow::Cow<'_, str>) -> PropertyLookupResult<'_> {
359 thread_local! {
360 static RESERVED_PROPERTIES: HashMap<&'static str, (Type, PropertyVisibility, Option<BuiltinFunction>)>
361 = reserved_properties().map(|(name, ty, visibility)| (name, (ty, visibility, reserved_member_function(name)))).collect();
362 }
363 if let Some((ty, visibility, builtin_function)) =
364 RESERVED_PROPERTIES.with(|reserved| reserved.get(name.as_ref()).cloned())
365 {
366 return PropertyLookupResult {
367 property_type: ty,
368 resolved_name: name,
369 is_local_to_component: false,
370 is_in_direct_base: false,
371 is_shadowable: false,
372 property_visibility: visibility,
373 declared_pure: None,
374 builtin_function,
375 };
376 }
377
378 for pre in &["min", "max"] {
380 if let Some(a) = name.strip_prefix(pre) {
381 for suf in &["width", "height"] {
382 if let Some(b) = a.strip_suffix(suf)
383 && b == "imum-"
384 {
385 return PropertyLookupResult {
386 property_type: Type::LogicalLength,
387 resolved_name: format!("{pre}-{suf}").into(),
388 is_local_to_component: false,
389 is_in_direct_base: false,
390 is_shadowable: false,
391 property_visibility: crate::object_tree::PropertyVisibility::InOut,
392 declared_pure: None,
393 builtin_function: None,
394 };
395 }
396 }
397 }
398 }
399 PropertyLookupResult::invalid(name)
400}
401
402pub fn reserved_member_function(name: &str) -> Option<BuiltinFunction> {
404 for (m, e) in [
405 ("focus", BuiltinFunction::SetFocusItem), ("clear-focus", BuiltinFunction::ClearFocusItem), ] {
408 if m == name {
409 return Some(e);
410 }
411 }
412 None
413}
414
415#[derive(Debug, Default)]
417pub struct TypeRegister {
418 types: HashMap<SmolStr, Type>,
420 elements: HashMap<SmolStr, ElementType>,
422 supported_property_animation_types: HashSet<String>,
423 pub(crate) property_animation_type: ElementType,
424 pub(crate) empty_type: ElementType,
425 context_restricted_types: HashMap<SmolStr, HashSet<SmolStr>>,
428 parent_registry: Option<Rc<RefCell<TypeRegister>>>,
429 pub(crate) expose_internal_types: bool,
431}
432
433impl TypeRegister {
434 pub(crate) fn snapshot(&self, snapshotter: &mut typeloader::Snapshotter) -> Self {
435 Self {
436 types: self.types.clone(),
437 elements: self
438 .elements
439 .iter()
440 .map(|(k, v)| (k.clone(), snapshotter.snapshot_element_type(v)))
441 .collect(),
442 supported_property_animation_types: self.supported_property_animation_types.clone(),
443 property_animation_type: snapshotter
444 .snapshot_element_type(&self.property_animation_type),
445 empty_type: snapshotter.snapshot_element_type(&self.empty_type),
446 context_restricted_types: self.context_restricted_types.clone(),
447 parent_registry: self
448 .parent_registry
449 .as_ref()
450 .map(|tr| snapshotter.snapshot_type_register(tr)),
451 expose_internal_types: self.expose_internal_types,
452 }
453 }
454
455 pub fn insert_type(&mut self, t: Type) -> bool {
459 self.types.insert(t.to_smolstr(), t).is_none()
460 }
461 pub fn insert_type_with_name(&mut self, t: Type, name: SmolStr) -> bool {
465 self.types.insert(name, t).is_none()
466 }
467
468 fn builtin_internal() -> Self {
469 let mut register = TypeRegister::default();
470
471 register.insert_type(Type::Float32);
472 register.insert_type(Type::Int32);
473 register.insert_type(Type::String);
474 register.insert_type(Type::PhysicalLength);
475 register.insert_type(Type::LogicalLength);
476 register.insert_type(Type::Color);
477 register.insert_type(Type::ComponentFactory);
478 register.insert_type(Type::Duration);
479 register.insert_type(Type::Image);
480 register.insert_type(Type::Bool);
481 register.insert_type(Type::Model);
482 register.insert_type(Type::Percent);
483 register.insert_type(Type::Easing);
484 register.insert_type(Type::Angle);
485 register.insert_type(Type::Brush);
486 register.insert_type(Type::Rem);
487 register.insert_type(Type::StyledText);
488 register.insert_type(Type::Keys);
489 register.insert_type(Type::DataTransfer);
490 register.types.insert("Point".into(), logical_point_type().into());
491 register.types.insert("Size".into(), logical_size_type().into());
492
493 BUILTIN.with(|e| e.enums.fill_register(&mut register));
494
495 register.supported_property_animation_types.insert(Type::Float32.to_string());
496 register.supported_property_animation_types.insert(Type::Int32.to_string());
497 register.supported_property_animation_types.insert(Type::Color.to_string());
498 register.supported_property_animation_types.insert(Type::PhysicalLength.to_string());
499 register.supported_property_animation_types.insert(Type::LogicalLength.to_string());
500 register.supported_property_animation_types.insert(Type::Brush.to_string());
501 register.supported_property_animation_types.insert(Type::Angle.to_string());
502
503 macro_rules! register_builtin_structs {
504 ($(
505 $(#[$attr:meta])*
506 $vis:vis struct $Name:ident {
507 $( $(#[$field_attr:meta])* $field:ident : $field_type:ident, )*
508 }
509 )*) => { $(
510 register.insert_type_with_name(Type::Struct(builtin_structs::$Name()), SmolStr::new(stringify!($Name)));
511 )* };
512 }
513 i_slint_common::for_each_builtin_structs!(register_builtin_structs);
514
515 crate::load_builtins::load_builtins(&mut register);
516
517 let mut visited: HashSet<SmolStr> = HashSet::new();
521 let mut to_visit: Vec<Rc<BuiltinElement>> = register
522 .elements
523 .values()
524 .filter_map(|e| match e {
525 ElementType::Builtin(b) => Some(b.clone()),
526 _ => None,
527 })
528 .collect();
529 while let Some(b) = to_visit.pop() {
530 let parent = b.native_class.class_name.clone();
531 if !visited.insert(parent.clone()) {
532 continue;
533 }
534 for (child_name, child_type) in &b.additional_accepted_child_types {
535 register
536 .context_restricted_types
537 .entry(child_name.clone())
538 .or_default()
539 .insert(parent.clone());
540 to_visit.push(child_type.clone());
541 }
542 if b.additional_accept_self {
543 register.context_restricted_types.entry(parent.clone()).or_default().insert(parent);
544 }
545 }
546
547 match &mut register.elements.get_mut("PopupWindow").unwrap() {
548 ElementType::Builtin(b) => {
549 let popup = Rc::get_mut(b).unwrap();
550 popup.properties.insert(
551 "show".into(),
552 BuiltinPropertyInfo::from(BuiltinFunction::ShowPopupWindow),
553 );
554
555 popup.properties.insert(
556 "close".into(),
557 BuiltinPropertyInfo::from(BuiltinFunction::ClosePopupWindow),
558 );
559
560 popup.properties.get_mut("close-on-click").unwrap().property_visibility =
561 PropertyVisibility::Constexpr;
562
563 popup.properties.get_mut("close-policy").unwrap().property_visibility =
564 PropertyVisibility::Constexpr;
565 }
566 _ => unreachable!(),
567 };
568
569 match &mut register.elements.get_mut("Timer").unwrap() {
570 ElementType::Builtin(b) => {
571 let timer = Rc::get_mut(b).unwrap();
572 for (name, func) in [
578 ("start", BuiltinFunction::StartTimer),
579 ("stop", BuiltinFunction::StopTimer),
580 ("restart", BuiltinFunction::RestartTimer),
581 ] {
582 let existing_docs = timer.properties.get(name).and_then(|p| p.docs.clone());
583 let mut info = BuiltinPropertyInfo::from(func);
584 info.docs = existing_docs;
585 timer.properties.insert(name.into(), info);
586 }
587 }
588 _ => unreachable!(),
589 }
590
591 let font_metrics_prop = crate::langtype::BuiltinPropertyInfo {
592 property_visibility: PropertyVisibility::Output,
593 default_value: BuiltinPropertyDefault::WithElement(|elem| {
594 crate::expression_tree::Expression::FunctionCall {
595 function: BuiltinFunction::ItemFontMetrics.into(),
596 arguments: vec![crate::expression_tree::Expression::ElementReference(
597 Rc::downgrade(elem),
598 )],
599 source_location: None,
600 }
601 }),
602 ..crate::langtype::BuiltinPropertyInfo::new(font_metrics_type())
603 };
604
605 match &mut register.elements.get_mut("TextInput").unwrap() {
606 ElementType::Builtin(b) => {
607 let text_input = Rc::get_mut(b).unwrap();
608 let existing = text_input.properties.get("set-selection-offsets");
611 let existing_docs = existing.and_then(|p| p.docs.clone());
612 let arg_names = existing.and_then(|p| {
613 if let Type::Function(f) = &p.ty { Some(f.arg_names.clone()) } else { None }
614 });
615 let mut info = BuiltinPropertyInfo::from(BuiltinFunction::SetSelectionOffsets);
616 info.docs = existing_docs;
617 if let (Some(names), Type::Function(f)) = (arg_names, &info.ty) {
618 let mut func = (**f).clone();
619 func.arg_names =
622 std::iter::repeat_n(SmolStr::default(), func.args.len() - names.len())
623 .chain(names)
624 .collect();
625 info.ty = Type::Function(Rc::new(func));
626 }
627 text_input.properties.insert("set-selection-offsets".into(), info);
628 text_input.properties.insert("font-metrics".into(), font_metrics_prop.clone());
629 }
630
631 _ => unreachable!(),
632 };
633
634 match &mut register.elements.get_mut("Text").unwrap() {
635 ElementType::Builtin(b) => {
636 let text = Rc::get_mut(b).unwrap();
637 text.properties.insert("font-metrics".into(), font_metrics_prop);
638 }
639
640 _ => unreachable!(),
641 };
642
643 match &mut register.elements.get_mut("Path").unwrap() {
644 ElementType::Builtin(b) => {
645 let path = Rc::get_mut(b).unwrap();
646 path.properties.get_mut("commands").unwrap().property_visibility =
647 PropertyVisibility::Fake;
648 }
649
650 _ => unreachable!(),
651 };
652
653 match &mut register.elements.get_mut("TabWidget").unwrap() {
654 ElementType::Builtin(b) => {
655 let tabwidget = Rc::get_mut(b).unwrap();
656 tabwidget.properties.get_mut("orientation").unwrap().property_visibility =
657 PropertyVisibility::Constexpr;
658 }
659 _ => unreachable!(),
660 }
661
662 register
663 }
664
665 #[doc(hidden)]
666 pub fn builtin_experimental() -> Rc<RefCell<Self>> {
668 let register = Self::builtin_internal();
669 Rc::new(RefCell::new(register))
670 }
671
672 pub fn builtin() -> Rc<RefCell<Self>> {
673 let mut register = Self::builtin_internal();
674
675 register.elements.remove("ComponentContainer").unwrap();
676 register.types.remove("component-factory").unwrap();
677
678 register.elements.remove("FlexboxLayout").unwrap();
679 register.types.remove("FlexboxLayoutDirection").unwrap();
680 register.types.remove("FlexboxLayoutAlignContent").unwrap();
681 register.types.remove("FlexboxLayoutWrap").unwrap();
682 register.types.remove("FlexboxLayoutAlignSelf").unwrap();
683
684 Rc::new(RefCell::new(register))
685 }
686
687 pub fn new(parent: &Rc<RefCell<TypeRegister>>) -> Self {
688 Self {
689 parent_registry: Some(parent.clone()),
690 expose_internal_types: parent.borrow().expose_internal_types,
691 ..Default::default()
692 }
693 }
694
695 pub fn lookup(&self, name: &str) -> Type {
696 self.types
697 .get(name)
698 .cloned()
699 .or_else(|| self.parent_registry.as_ref().map(|r| r.borrow().lookup(name)))
700 .unwrap_or_default()
701 }
702
703 fn lookup_element_as_result(
704 &self,
705 name: &str,
706 ) -> Result<ElementType, HashMap<SmolStr, HashSet<SmolStr>>> {
707 match self.elements.get(name).cloned() {
708 Some(ty) => Ok(ty),
709 None => match &self.parent_registry {
710 Some(r) => r.borrow().lookup_element_as_result(name),
711 None => Err(self.context_restricted_types.clone()),
712 },
713 }
714 }
715
716 pub fn lookup_element(&self, name: &str) -> Result<ElementType, String> {
717 self.lookup_element_as_result(name).map_err(|context_restricted_types| {
718 if let Some(permitted_parent_types) = context_restricted_types.get(name) {
719 if permitted_parent_types.len() == 1 {
720 format!(
721 "{} can only be within a {} element",
722 name,
723 permitted_parent_types.iter().next().unwrap()
724 )
725 } else {
726 let mut elements = permitted_parent_types.iter().cloned().collect::<Vec<_>>();
727 elements.sort();
728 format!(
729 "{} can only be within the following elements: {}",
730 name,
731 elements.join(", ")
732 )
733 }
734 } else if let Some(ty) = self.types.get(name) {
735 format!("'{ty}' cannot be used as an element")
736 } else {
737 format!("Unknown element '{name}'")
738 }
739 })
740 }
741
742 pub fn lookup_builtin_element(&self, name: &str) -> Option<ElementType> {
743 self.parent_registry.as_ref().map_or_else(
744 || self.elements.get(name).cloned(),
745 |p| p.borrow().lookup_builtin_element(name),
746 )
747 }
748
749 pub fn lookup_qualified<Member: AsRef<str>>(&self, qualified: &[Member]) -> Type {
750 if qualified.len() != 1 {
751 return Type::Invalid;
752 }
753 self.lookup(qualified[0].as_ref())
754 }
755
756 pub fn add(&mut self, comp: Rc<Component>) -> bool {
760 self.add_with_name(comp.id.clone(), comp)
761 }
762
763 pub fn add_with_name(&mut self, name: SmolStr, comp: Rc<Component>) -> bool {
767 self.elements.insert(name, ElementType::Component(comp)).is_none()
768 }
769
770 pub fn add_builtin(&mut self, builtin: Rc<BuiltinElement>) {
771 self.elements.insert(builtin.name.clone(), ElementType::Builtin(builtin));
772 }
773
774 pub fn property_animation_type_for_property(&self, property_type: Type) -> ElementType {
775 if self.supported_property_animation_types.contains(&property_type.to_string()) {
776 self.property_animation_type.clone()
777 } else {
778 self.parent_registry
779 .as_ref()
780 .map(|registry| {
781 registry.borrow().property_animation_type_for_property(property_type)
782 })
783 .unwrap_or_default()
784 }
785 }
786
787 pub fn all_types(&self) -> HashMap<SmolStr, Type> {
789 let mut all =
790 self.parent_registry.as_ref().map(|r| r.borrow().all_types()).unwrap_or_default();
791 for (k, v) in &self.types {
792 all.insert(k.clone(), v.clone());
793 }
794 all
795 }
796
797 pub fn all_elements(&self) -> HashMap<SmolStr, ElementType> {
799 let mut all =
800 self.parent_registry.as_ref().map(|r| r.borrow().all_elements()).unwrap_or_default();
801 for (k, v) in &self.elements {
802 all.insert(k.clone(), v.clone());
803 }
804 all
805 }
806
807 pub fn empty_type(&self) -> ElementType {
808 match self.parent_registry.as_ref() {
809 Some(parent) => parent.borrow().empty_type(),
810 None => self.empty_type.clone(),
811 }
812 }
813}
814
815pub mod builtin_structs {
817 use super::*;
818
819 thread_local! {
820 pub static BUILTIN_STRUCTS: BuiltinStructs = BuiltinStructs::new();
821 }
822
823 #[rustfmt::skip]
824 macro_rules! map_type {
825 ($pub_type:ident, bool) => { Type::Bool };
826 ($pub_type:ident, i32) => { Type::Int32 };
827 ($pub_type:ident, f32) => { Type::Float32 };
828 ($pub_type:ident, SharedString) => { Type::String };
829 ($pub_type:ident, Image) => { Type::Image };
830 ($pub_type:ident, Coord) => { Type::LogicalLength };
831 ($pub_type:ident, Keys) => { Type::Keys };
832 ($pub_type:ident, DataTransfer) => { Type::DataTransfer };
833 ($pub_type:ident, LogicalPosition) => { Type::Struct(logical_point_type()) };
834 ($pub_type:ident, LogicalSize) => { Type::Struct(logical_size_type()) };
835 ($pub_type:ident, KeyboardModifiers) => {
837 Type::Struct($pub_type.clone())
839 };
840 ($pub_type:ident, $_:ident) => {
842 BUILTIN.with(|e| Type::Enumeration(e.enums.$pub_type.clone()))
843 };
844 }
845
846 macro_rules! declare_builtin_structs {
847 ($(
848 $(#[$attr:meta])*
849 $vis:vis struct $Name:ident {
850 $( $(#[$field_attr:meta])* $field:ident : $field_type:ident, )*
851 }
852 )*) => {
853 pub struct BuiltinStructs {
854 $(
855 #[allow(non_snake_case)]
856 $Name: Rc<Struct>
857 ),*
858 }
859 impl BuiltinStructs {
860 pub fn new() -> Self {
861 $(
862 #[allow(non_snake_case)]
863 let $Name = Rc::new(Struct{
864 fields: BTreeMap::from([
865 $((stringify!($field).replace_smolstr("_", "-"), map_type!($field_type, $field_type))),*
866 ]),
867 name: BuiltinStruct::$Name.into(),
868 });
869 )*
870
871 Self {
872 $($Name),*
873 }
874 }
875 }
876
877 impl Default for BuiltinStructs {
878 fn default() -> Self {
879 Self::new()
880 }
881 }
882
883 $(
884 #[allow(non_snake_case)]
885 pub fn $Name() -> Rc<Struct> {
886 BUILTIN_STRUCTS.with(|types| types.$Name.clone())
887 }
888 )*
889 };
890 }
891 i_slint_common::for_each_builtin_structs!(declare_builtin_structs);
892}
893
894pub fn logical_point_type() -> Rc<Struct> {
895 BUILTIN.with(|types| types.logical_point_type.clone())
896}
897
898pub fn logical_size_type() -> Rc<Struct> {
899 BUILTIN.with(|types| types.logical_size_type.clone())
900}
901
902pub fn font_metrics_type() -> Type {
903 BUILTIN.with(|types| types.font_metrics_type.clone())
904}
905
906pub fn layout_info_type() -> Rc<Struct> {
908 BUILTIN.with(|types| types.layout_info_type.clone())
909}
910
911pub fn path_element_type() -> Type {
913 BUILTIN.with(|types| types.path_element_type.clone())
914}
915
916pub fn layout_item_info_type() -> Type {
918 BUILTIN.with(|types| types.layout_item_info_type.clone())
919}
920
921pub fn flexbox_layout_item_info_type() -> Type {
923 BUILTIN.with(|types| types.flexbox_layout_item_info_type.clone())
924}