1use smol_str::{SmolStr, StrExt, ToSmolStr};
7use std::cell::RefCell;
8use std::collections::{BTreeMap, HashMap, HashSet};
9use std::rc::Rc;
10use std::sync::Arc;
11
12use crate::expression_tree::BuiltinFunction;
13use crate::langtype::{
14 BuiltinElement, BuiltinStruct, ElementType, Enumeration, Function, PropertyLookupResult,
15 Struct, Type,
16};
17use crate::object_tree::{Component, PropertyVisibility};
18use crate::typeloader;
19
20pub const RESERVED_GEOMETRY_PROPERTIES: &[(&str, Type)] = &[
21 ("x", Type::LogicalLength),
22 ("y", Type::LogicalLength),
23 ("width", Type::LogicalLength),
24 ("height", Type::LogicalLength),
25 ("z", Type::Float32),
26];
27
28pub const RESERVED_LAYOUT_PROPERTIES: &[(&str, Type)] = &[
29 ("min-width", Type::LogicalLength),
30 ("min-height", Type::LogicalLength),
31 ("max-width", Type::LogicalLength),
32 ("max-height", Type::LogicalLength),
33 ("padding", Type::LogicalLength),
34 ("padding-left", Type::LogicalLength),
35 ("padding-right", Type::LogicalLength),
36 ("padding-top", Type::LogicalLength),
37 ("padding-bottom", Type::LogicalLength),
38 ("preferred-width", Type::LogicalLength),
39 ("preferred-height", Type::LogicalLength),
40 ("horizontal-stretch", Type::Float32),
41 ("vertical-stretch", Type::Float32),
42];
43
44pub const RESERVED_GRIDLAYOUT_PROPERTIES: &[(&str, Type)] = &[
45 ("col", Type::Int32),
46 ("row", Type::Int32),
47 ("colspan", Type::Int32),
48 ("rowspan", Type::Int32),
49];
50
51pub const RESERVED_LAYOUT_CELL_PROPERTIES: &[(&str, Type)] = &[("layout-order", Type::Int32)];
55
56macro_rules! declare_enums {
57 ($( $(#[$enum_doc:meta])* $vis:vis enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => {
58 #[allow(non_snake_case)]
59 pub struct BuiltinEnums {
60 $(pub $Name : Arc<Enumeration>),*
61 }
62 impl BuiltinEnums {
63 fn new() -> Self {
64 Self { $($Name: enumeration(stringify!($Name), &[$(stringify!($Value)),*])),* }
65 }
66 fn all(&self) -> impl Iterator<Item = &Arc<Enumeration>> {
67 [$(&self.$Name),*].into_iter()
68 }
69 fn fill_register(&self, register: &mut TypeRegister) {
70 for e in self.all() {
71 if !matches!(e.name.as_str(), "PathEvent" | "BuiltInMouseCursor") {
72 register.insert_type_with_name(Type::Enumeration(e.clone()), e.name.clone());
73 }
74 }
75 }
76 }
77 };
78}
79
80i_slint_common::for_each_enums!(declare_enums);
81
82fn enumeration(name: &str, values: &[&str]) -> Arc<Enumeration> {
83 Arc::new(Enumeration {
84 name: name.into(),
85 values: values
86 .iter()
87 .map(|v| crate::generator::to_kebab_case(v.trim_start_matches("r#")).into())
88 .collect(),
89 default_value: 0,
90 node: None,
91 rust_attributes: Vec::new(),
92 })
93}
94
95pub struct BuiltinTypes {
96 pub enums: BuiltinEnums,
97 pub noarg_callback_type: Type,
98 pub strarg_callback_type: Type,
99 pub set_selection_offsets_callback_type: Type,
100 pub logical_point_type: Arc<Struct>,
101 pub logical_size_type: Arc<Struct>,
102 pub layout_info_type: Arc<Struct>,
103 pub state_info_type: Arc<Struct>,
104 pub gridlayout_input_data_type: Type,
105 pub path_element_type: Type,
106 pub layout_item_info_type: Type,
107 pub flexbox_layout_item_info_type: Type,
108 pub flex_item_props_type: Type,
109}
110
111impl BuiltinTypes {
112 fn new() -> Self {
113 let layout_info_type = Arc::new(Struct::new(
114 ["min", "max", "preferred"]
115 .iter()
116 .map(|s| (SmolStr::new_static(s), Type::LogicalLength))
117 .chain(
118 ["min_percent", "max_percent", "stretch"]
119 .iter()
120 .map(|s| (SmolStr::new_static(s), Type::Float32)),
121 )
122 .collect(),
123 BuiltinStruct::LayoutInfo,
124 ));
125 let enums = BuiltinEnums::new();
126 let align_self_type = Type::Enumeration(enums.CrossAxisAlignment.clone());
127 let flex_item_props_struct = Arc::new(Struct::new(
130 IntoIterator::into_iter([
131 ("cross-axis-self-alignment".into(), align_self_type),
132 ("layout-order".into(), Type::Int32),
133 ])
134 .collect(),
135 BuiltinStruct::FlexItemProps,
136 ));
137 Self {
138 logical_point_type: Arc::new(Struct::new(
139 IntoIterator::into_iter([
140 (SmolStr::new_static("x"), Type::LogicalLength),
141 (SmolStr::new_static("y"), Type::LogicalLength),
142 ])
143 .collect(),
144 BuiltinStruct::LogicalPosition,
145 )),
146 logical_size_type: Arc::new(Struct::new(
147 IntoIterator::into_iter([
148 (SmolStr::new_static("width"), Type::LogicalLength),
149 (SmolStr::new_static("height"), Type::LogicalLength),
150 ])
151 .collect(),
152 BuiltinStruct::LogicalSize,
153 )),
154 noarg_callback_type: Type::Callback(Arc::new(Function {
155 return_type: Type::Void,
156 args: Vec::new(),
157 arg_names: Vec::new(),
158 })),
159 strarg_callback_type: Type::Callback(Arc::new(Function {
160 return_type: Type::Void,
161 args: vec![Type::String],
162 arg_names: Vec::new(),
163 })),
164 set_selection_offsets_callback_type: Type::Callback(Arc::new(Function {
165 return_type: Type::Void,
166 args: vec![Type::Int32, Type::Int32],
167 arg_names: vec![SmolStr::new_static("anchor"), SmolStr::new_static("focus")],
168 })),
169 layout_info_type: layout_info_type.clone(),
170 state_info_type: Arc::new(Struct::new(
171 IntoIterator::into_iter([
172 (SmolStr::new_static("current-state"), Type::Int32),
173 (SmolStr::new_static("previous-state"), Type::Int32),
174 (SmolStr::new_static("change-time"), Type::Duration),
175 ])
176 .collect(),
177 BuiltinStruct::StateInfo,
178 )),
179 path_element_type: Type::Struct(Arc::new(Struct::new(
180 Default::default(),
181 BuiltinStruct::PathElement,
182 ))),
183 layout_item_info_type: Type::Struct(Arc::new(Struct::new(
184 IntoIterator::into_iter([
185 ("constraint".into(), layout_info_type.clone().into()),
186 (
187 "cross-axis-self-alignment".into(),
188 Type::Enumeration(enums.CrossAxisAlignment.clone()),
189 ),
190 ("layout-order".into(), Type::Int32),
191 ])
192 .collect(),
193 BuiltinStruct::LayoutItemInfo,
194 ))),
195 flexbox_layout_item_info_type: Type::Struct(Arc::new(Struct::new(
196 IntoIterator::into_iter([
197 ("constraint".into(), layout_info_type.into()),
198 ("props".into(), Type::Struct(flex_item_props_struct.clone())),
199 ])
200 .collect(),
201 BuiltinStruct::FlexboxLayoutItemInfo,
202 ))),
203 flex_item_props_type: Type::Struct(flex_item_props_struct),
204 gridlayout_input_data_type: Type::Struct(Arc::new(Struct::new(
205 IntoIterator::into_iter([
206 ("row".into(), Type::Int32),
207 ("column".into(), Type::Int32),
208 ("rowspan".into(), Type::Int32),
209 ("colspan".into(), Type::Int32),
210 ])
211 .collect(),
212 BuiltinStruct::GridLayoutInputData,
213 ))),
214 enums,
216 }
217 }
218}
219
220pub static BUILTIN: std::sync::LazyLock<BuiltinTypes> = std::sync::LazyLock::new(BuiltinTypes::new);
221
222const RESERVED_OTHER_PROPERTIES: &[(&str, Type)] = &[
223 ("clip", Type::Bool),
224 ("opacity", Type::Float32),
225 ("cache-rendering-hint", Type::Bool),
226 ("visible", Type::Bool), ];
228
229pub const RESERVED_DROP_SHADOW_PROPERTIES: &[(&str, Type)] = &[
230 ("drop-shadow-offset-x", Type::LogicalLength),
231 ("drop-shadow-offset-y", Type::LogicalLength),
232 ("drop-shadow-blur", Type::LogicalLength),
233 ("drop-shadow-spread", Type::LogicalLength),
234 ("drop-shadow-color", Type::Color),
235];
236
237pub const RESERVED_INNER_SHADOW_PROPERTIES: &[(&str, Type)] = &[
238 ("inner-shadow-offset-x", Type::LogicalLength),
239 ("inner-shadow-offset-y", Type::LogicalLength),
240 ("inner-shadow-blur", Type::LogicalLength),
241 ("inner-shadow-spread", Type::LogicalLength),
242 ("inner-shadow-color", Type::Color),
243];
244
245pub const RESERVED_TRANSFORM_PROPERTIES: &[(&str, Type)] = &[
246 ("transform-rotation", Type::Angle),
247 ("transform-scale-x", Type::Float32),
248 ("transform-scale-y", Type::Float32),
249 ("transform-scale", Type::Float32),
250];
251
252pub fn transform_origin_property() -> (&'static str, Arc<Struct>) {
253 ("transform-origin", logical_point_type())
254}
255
256pub const DEPRECATED_ROTATION_ORIGIN_PROPERTIES: [(&str, Type); 2] =
257 [("rotation-origin-x", Type::LogicalLength), ("rotation-origin-y", Type::LogicalLength)];
258
259pub fn noarg_callback_type() -> Type {
260 BUILTIN.noarg_callback_type.clone()
261}
262
263fn strarg_callback_type() -> Type {
264 BUILTIN.strarg_callback_type.clone()
265}
266
267fn set_selection_offsets_callback_type() -> Type {
268 BUILTIN.set_selection_offsets_callback_type.clone()
269}
270
271pub fn reserved_accessibility_properties() -> impl Iterator<Item = (&'static str, Type)> {
272 [
273 ("accessible-checkable", Type::Bool),
275 ("accessible-checked", Type::Bool),
276 ("accessible-delegate-focus", Type::Int32),
277 ("accessible-description", Type::String),
278 ("accessible-enabled", Type::Bool),
279 ("accessible-expandable", Type::Bool),
280 ("accessible-expanded", Type::Bool),
281 ("accessible-id", Type::String),
282 ("accessible-label", Type::String),
283 ("accessible-value", Type::String),
284 ("accessible-value-maximum", Type::Float32),
285 ("accessible-value-minimum", Type::Float32),
286 ("accessible-value-step", Type::Float32),
287 ("accessible-placeholder-text", Type::String),
288 ("accessible-action-default", noarg_callback_type()),
289 ("accessible-action-increment", noarg_callback_type()),
290 ("accessible-action-decrement", noarg_callback_type()),
291 ("accessible-action-set-value", strarg_callback_type()),
292 ("accessible-action-set-selection-offsets", set_selection_offsets_callback_type()),
293 ("accessible-action-expand", noarg_callback_type()),
294 ("accessible-item-selectable", Type::Bool),
295 ("accessible-item-selected", Type::Bool),
296 ("accessible-item-index", Type::Int32),
297 ("accessible-item-count", Type::Int32),
298 ("accessible-read-only", Type::Bool),
299 ]
300 .into_iter()
301}
302
303pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type, PropertyVisibility)> {
305 RESERVED_GEOMETRY_PROPERTIES
306 .iter()
307 .chain(RESERVED_LAYOUT_PROPERTIES.iter())
308 .chain(RESERVED_OTHER_PROPERTIES.iter())
309 .chain(RESERVED_DROP_SHADOW_PROPERTIES.iter())
310 .chain(RESERVED_INNER_SHADOW_PROPERTIES.iter())
311 .chain(RESERVED_TRANSFORM_PROPERTIES.iter())
312 .chain(DEPRECATED_ROTATION_ORIGIN_PROPERTIES.iter())
313 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input))
314 .chain(
315 std::iter::once(transform_origin_property())
316 .map(|(k, v)| (k, v.into(), PropertyVisibility::Input)),
317 )
318 .chain(reserved_accessibility_properties().map(|(k, v)| (k, v, PropertyVisibility::Input)))
319 .chain(
320 RESERVED_GRIDLAYOUT_PROPERTIES
321 .iter()
322 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
323 )
324 .chain(
325 RESERVED_LAYOUT_CELL_PROPERTIES
326 .iter()
327 .map(|(k, v)| (*k, v.clone(), PropertyVisibility::Input)),
328 )
329 .chain(std::iter::once((
332 "cross-axis-self-alignment",
333 Type::Enumeration(BUILTIN.enums.CrossAxisAlignment.clone()),
334 PropertyVisibility::Input,
335 )))
336 .chain(IntoIterator::into_iter([
337 ("absolute-position", logical_point_type().into(), PropertyVisibility::Output),
338 ("forward-focus", Type::ElementReference, PropertyVisibility::Constexpr),
339 (
340 "focus",
341 Type::Function(BuiltinFunction::SetFocusItem.ty()),
342 PropertyVisibility::Public,
343 ),
344 (
345 "clear-focus",
346 Type::Function(BuiltinFunction::ClearFocusItem.ty()),
347 PropertyVisibility::Public,
348 ),
349 (
350 "dialog-button-role",
351 Type::Enumeration(BUILTIN.enums.DialogButtonRole.clone()),
352 PropertyVisibility::Constexpr,
353 ),
354 (
355 "accessible-role",
356 Type::Enumeration(BUILTIN.enums.AccessibleRole.clone()),
357 PropertyVisibility::Constexpr,
358 ),
359 (
360 "accessible-orientation",
361 Type::Enumeration(BUILTIN.enums.Orientation.clone()),
362 PropertyVisibility::Input,
363 ),
364 (
365 "accessible-live-region",
366 Type::Enumeration(BUILTIN.enums.AccessibleLiveness.clone()),
367 PropertyVisibility::Input,
368 ),
369 ]))
370 .chain(std::iter::once(("init", noarg_callback_type(), PropertyVisibility::Private)))
371}
372
373pub fn reserved_property(name: std::borrow::Cow<'_, str>) -> PropertyLookupResult<'_> {
375 static RESERVED_PROPERTIES: std::sync::LazyLock<
376 HashMap<&'static str, (Type, PropertyVisibility, Option<BuiltinFunction>)>,
377 > = std::sync::LazyLock::new(|| {
378 reserved_properties()
379 .map(|(name, ty, visibility)| (name, (ty, visibility, reserved_member_function(name))))
380 .collect()
381 });
382 if let Some((ty, visibility, builtin_function)) =
383 RESERVED_PROPERTIES.get(name.as_ref()).cloned()
384 {
385 return PropertyLookupResult {
386 property_type: ty,
387 is_slint_sc: matches!(name.as_ref(), "x" | "y" | "width" | "height"),
388 resolved_name: name,
389 is_local_to_component: false,
390 is_in_direct_base: false,
391 is_shadowable: false,
392 property_visibility: visibility,
393 declared_pure: None,
394 builtin_function,
395 internal_name: None,
396 deprecated: None,
397 };
398 }
399
400 for pre in &["min", "max"] {
402 if let Some(a) = name.strip_prefix(pre) {
403 for suf in &["width", "height"] {
404 if let Some(b) = a.strip_suffix(suf)
405 && b == "imum-"
406 {
407 return PropertyLookupResult {
408 property_type: Type::LogicalLength,
409 resolved_name: format!("{pre}-{suf}").into(),
410 is_local_to_component: false,
411 is_in_direct_base: false,
412 is_shadowable: false,
413 property_visibility: crate::object_tree::PropertyVisibility::InOut,
414 declared_pure: None,
415 builtin_function: None,
416 is_slint_sc: false,
417 internal_name: None,
418 deprecated: None,
419 };
420 }
421 }
422 }
423 }
424 PropertyLookupResult::invalid(name)
425}
426
427pub fn reserved_member_function(name: &str) -> Option<BuiltinFunction> {
429 for (m, e) in [
430 ("focus", BuiltinFunction::SetFocusItem), ("clear-focus", BuiltinFunction::ClearFocusItem), ] {
433 if m == name {
434 return Some(e);
435 }
436 }
437 None
438}
439
440#[derive(Debug, Default)]
442pub struct TypeRegister {
443 types: HashMap<SmolStr, Type>,
445 elements: HashMap<SmolStr, ElementType>,
447 supported_property_animation_types: HashSet<String>,
448 pub(crate) property_animation_type: ElementType,
449 pub(crate) empty_type: ElementType,
450 pub(crate) context_restricted_types: HashMap<SmolStr, HashSet<SmolStr>>,
453 parent_registry: Option<Rc<RefCell<TypeRegister>>>,
454 pub(crate) expose_internal_types: bool,
456}
457
458impl TypeRegister {
459 pub(crate) fn snapshot(&self, snapshotter: &mut typeloader::Snapshotter) -> Self {
460 Self {
461 types: self.types.clone(),
462 elements: self
463 .elements
464 .iter()
465 .map(|(k, v)| (k.clone(), snapshotter.snapshot_element_type(v)))
466 .collect(),
467 supported_property_animation_types: self.supported_property_animation_types.clone(),
468 property_animation_type: snapshotter
469 .snapshot_element_type(&self.property_animation_type),
470 empty_type: snapshotter.snapshot_element_type(&self.empty_type),
471 context_restricted_types: self.context_restricted_types.clone(),
472 parent_registry: self
473 .parent_registry
474 .as_ref()
475 .map(|tr| snapshotter.snapshot_type_register(tr)),
476 expose_internal_types: self.expose_internal_types,
477 }
478 }
479
480 pub fn insert_type(&mut self, t: Type) -> bool {
484 self.types.insert(t.to_smolstr(), t).is_none()
485 }
486 pub fn insert_type_with_name(&mut self, t: Type, name: SmolStr) -> bool {
490 self.types.insert(name, t).is_none()
491 }
492
493 fn builtin_internal() -> Self {
494 let mut register = TypeRegister::default();
495
496 register.insert_type(Type::Float32);
497 register.insert_type(Type::Int32);
498 register.insert_type(Type::String);
499 register.insert_type(Type::PhysicalLength);
500 register.insert_type(Type::LogicalLength);
501 register.insert_type(Type::Color);
502 register.insert_type(Type::ComponentFactory);
503 register.insert_type(Type::Duration);
504 register.insert_type(Type::Image);
505 register.insert_type(Type::Bool);
506 register.insert_type(Type::Model);
507 register.insert_type(Type::Percent);
508 register.insert_type(Type::Easing);
509 register.insert_type(Type::Angle);
510 register.insert_type(Type::Brush);
511 register.insert_type(Type::Rem);
512 register.insert_type(Type::StyledText);
513 register.insert_type(Type::Keys);
514 register.insert_type(Type::DataTransfer);
515 register.insert_type(Type::MouseCursor);
516 register.types.insert("Point".into(), logical_point_type().into());
517 register.types.insert("Size".into(), logical_size_type().into());
518
519 BUILTIN.enums.fill_register(&mut register);
520
521 register.supported_property_animation_types.insert(Type::Float32.to_string());
522 register.supported_property_animation_types.insert(Type::Int32.to_string());
523 register.supported_property_animation_types.insert(Type::Color.to_string());
524 register.supported_property_animation_types.insert(Type::PhysicalLength.to_string());
525 register.supported_property_animation_types.insert(Type::LogicalLength.to_string());
526 register.supported_property_animation_types.insert(Type::Brush.to_string());
527 register.supported_property_animation_types.insert(Type::Angle.to_string());
528
529 macro_rules! register_builtin_structs {
530 ($(
531 $(#[$attr:meta])*
532 $vis:vis struct $Name:ident {
533 $( $(#[$field_attr:meta])* $field:ident : $field_type:ident $(= $field_default:expr)?, )*
534 }
535 )*) => { $(
536 register.insert_type_with_name(Type::Struct(builtin_structs::$Name()), SmolStr::new(stringify!($Name)));
537 )* };
538 }
539 i_slint_common::for_each_builtin_structs!(register_builtin_structs);
540
541 crate::builtin_elements::load(&mut register);
542
543 register
544 }
545
546 #[doc(hidden)]
547 pub fn builtin_experimental() -> Rc<RefCell<Self>> {
549 let register = Self::builtin_internal();
550 Rc::new(RefCell::new(register))
551 }
552
553 pub fn builtin() -> Rc<RefCell<Self>> {
554 let mut register = Self::builtin_internal();
555
556 register.elements.remove("ComponentContainer").unwrap();
557 register.types.remove("component-factory").unwrap();
558
559 Rc::new(RefCell::new(register))
560 }
561
562 pub fn new(parent: &Rc<RefCell<TypeRegister>>) -> Self {
563 Self {
564 parent_registry: Some(parent.clone()),
565 expose_internal_types: parent.borrow().expose_internal_types,
566 ..Default::default()
567 }
568 }
569
570 pub fn lookup(&self, name: &str) -> Type {
571 self.types
572 .get(name)
573 .cloned()
574 .or_else(|| self.parent_registry.as_ref().map(|r| r.borrow().lookup(name)))
575 .unwrap_or_default()
576 }
577
578 fn lookup_element_as_result(
579 &self,
580 name: &str,
581 ) -> Result<ElementType, HashMap<SmolStr, HashSet<SmolStr>>> {
582 match self.elements.get(name).cloned() {
583 Some(ty) => Ok(ty),
584 None => match &self.parent_registry {
585 Some(r) => r.borrow().lookup_element_as_result(name),
586 None => Err(self.context_restricted_types.clone()),
587 },
588 }
589 }
590
591 pub fn lookup_element(&self, name: &str) -> Result<ElementType, String> {
592 self.lookup_element_as_result(name).map_err(|context_restricted_types| {
593 if let Some(permitted_parent_types) = context_restricted_types.get(name) {
594 if permitted_parent_types.len() == 1 {
595 format!(
596 "{} can only be within a {} element",
597 name,
598 permitted_parent_types.iter().next().unwrap()
599 )
600 } else {
601 let mut elements = permitted_parent_types.iter().cloned().collect::<Vec<_>>();
602 elements.sort();
603 format!(
604 "{} can only be within the following elements: {}",
605 name,
606 elements.join(", ")
607 )
608 }
609 } else if let Some(ty) = self.types.get(name) {
610 format!("'{ty}' cannot be used as an element")
611 } else {
612 format!("Unknown element '{name}'")
613 }
614 })
615 }
616
617 pub fn lookup_builtin_element(&self, name: &str) -> Option<ElementType> {
618 self.parent_registry.as_ref().map_or_else(
619 || self.elements.get(name).cloned(),
620 |p| p.borrow().lookup_builtin_element(name),
621 )
622 }
623
624 pub fn lookup_qualified<Member: AsRef<str>>(&self, qualified: &[Member]) -> Type {
625 if qualified.len() != 1 {
626 return Type::Invalid;
627 }
628 self.lookup(qualified[0].as_ref())
629 }
630
631 pub fn add(&mut self, comp: Rc<Component>) -> bool {
635 self.add_with_name(comp.id.clone(), comp)
636 }
637
638 pub fn add_with_name(&mut self, name: SmolStr, comp: Rc<Component>) -> bool {
642 self.elements.insert(name, ElementType::Component(comp)).is_none()
643 }
644
645 pub fn add_builtin(&mut self, builtin: Rc<BuiltinElement>) {
646 self.elements.insert(builtin.name.clone(), ElementType::Builtin(builtin));
647 }
648
649 pub fn property_animation_type_for_property(&self, property_type: Type) -> ElementType {
650 if self.supported_property_animation_types.contains(&property_type.to_string()) {
651 self.property_animation_type.clone()
652 } else {
653 self.parent_registry
654 .as_ref()
655 .map(|registry| {
656 registry.borrow().property_animation_type_for_property(property_type)
657 })
658 .unwrap_or_default()
659 }
660 }
661
662 pub fn all_types(&self) -> HashMap<SmolStr, Type> {
664 let mut all =
665 self.parent_registry.as_ref().map(|r| r.borrow().all_types()).unwrap_or_default();
666 for (k, v) in &self.types {
667 all.insert(k.clone(), v.clone());
668 }
669 all
670 }
671
672 pub fn all_elements(&self) -> HashMap<SmolStr, ElementType> {
674 let mut all =
675 self.parent_registry.as_ref().map(|r| r.borrow().all_elements()).unwrap_or_default();
676 for (k, v) in &self.elements {
677 all.insert(k.clone(), v.clone());
678 }
679 all
680 }
681
682 pub fn empty_type(&self) -> ElementType {
683 match self.parent_registry.as_ref() {
684 Some(parent) => parent.borrow().empty_type(),
685 None => self.empty_type.clone(),
686 }
687 }
688}
689
690pub mod builtin_structs {
692 use super::*;
693 use crate::langtype::ConstantExpression;
694
695 pub static BUILTIN_STRUCTS: std::sync::LazyLock<BuiltinStructs> =
696 std::sync::LazyLock::new(BuiltinStructs::new);
697
698 #[rustfmt::skip]
699 macro_rules! map_type {
700 ($pub_type:ident, bool) => { Type::Bool };
701 ($pub_type:ident, i32) => { Type::Int32 };
702 ($pub_type:ident, f32) => { Type::Float32 };
703 ($pub_type:ident, SharedString) => { Type::String };
704 ($pub_type:ident, Image) => { Type::Image };
705 ($pub_type:ident, Coord) => { Type::LogicalLength };
706 ($pub_type:ident, Keys) => { Type::Keys };
707 ($pub_type:ident, DataTransfer) => { Type::DataTransfer };
708 ($pub_type:ident, LogicalPosition) => { Type::Struct(logical_point_type()) };
709 ($pub_type:ident, KeyboardModifiers) => { Type::Struct($pub_type.clone()) };
711 ($pub_type:ident, $enum:ident) => { Type::Enumeration(BUILTIN.enums.$enum.clone()) };
712 }
713
714 #[rustfmt::skip]
715 macro_rules! field_default {
716 () => { None };
717 (true) => { Some(ConstantExpression::BoolLiteral(true)) };
718 (false) => { Some(ConstantExpression::BoolLiteral(false)) };
719 ($enum:ident :: $value:ident) => {
720 Some(ConstantExpression::EnumerationValue(
721 BUILTIN.enums.$enum.clone()
722 .try_value_from_string(&crate::generator::to_kebab_case(stringify!($value)))
723 .expect(concat!("unknown enum variant in field default ", stringify!($enum), "::", stringify!($value))),
724 ))
725 };
726 (($($tt:tt)*)) => { field_default!($($tt)*) };
727 }
728
729 macro_rules! declare_builtin_structs {
730 ($(
731 $(#[$attr:meta])*
732 $vis:vis struct $Name:ident {
733 $( $(#[$field_attr:meta])* $field:ident : $field_type:ident $(= $field_default:tt)?, )*
734 }
735 )*) => {
736 pub struct BuiltinStructs {
737 $(
738 #[allow(non_snake_case)]
739 $Name: Arc<Struct>
740 ),*
741 }
742 impl BuiltinStructs {
743 pub fn new() -> Self {
744 $(
745 #[allow(non_snake_case)]
746 let $Name = build_struct(BuiltinStruct::$Name, &[$(
747 (stringify!($field), map_type!($field_type, $field_type), field_default!($($field_default)?)),
748 )*]);
749 )*
750 Self { $($Name),* }
751 }
752 }
753
754 impl Default for BuiltinStructs {
755 fn default() -> Self {
756 Self::new()
757 }
758 }
759
760 $(
761 #[allow(non_snake_case)]
762 pub fn $Name() -> Arc<Struct> {
763 BUILTIN_STRUCTS.$Name.clone()
764 }
765 )*
766 };
767 }
768 i_slint_common::for_each_builtin_structs!(declare_builtin_structs);
769
770 fn build_struct(
771 name: BuiltinStruct,
772 fields: &[(&str, Type, Option<ConstantExpression>)],
773 ) -> Arc<Struct> {
774 let mut s =
775 Struct { fields: BTreeMap::new(), field_defaults: BTreeMap::new(), name: name.into() };
776 for (field, ty, default) in fields {
777 let field = field.replace_smolstr("_", "-");
778 if let Some(default) = default {
779 s.field_defaults.insert(field.clone(), default.clone());
780 }
781 s.fields.insert(field, ty.clone());
782 }
783 Arc::new(s)
784 }
785}
786
787pub fn logical_point_type() -> Arc<Struct> {
788 BUILTIN.logical_point_type.clone()
789}
790
791pub fn logical_size_type() -> Arc<Struct> {
792 BUILTIN.logical_size_type.clone()
793}
794
795pub fn font_metrics_type() -> Type {
796 Type::Struct(builtin_structs::FontMetrics())
797}
798
799pub fn layout_info_type() -> Arc<Struct> {
801 BUILTIN.layout_info_type.clone()
802}
803
804pub fn path_element_type() -> Type {
806 BUILTIN.path_element_type.clone()
807}
808
809pub fn layout_item_info_type() -> Type {
811 BUILTIN.layout_item_info_type.clone()
812}
813
814pub fn flexbox_layout_item_info_type() -> Type {
816 BUILTIN.flexbox_layout_item_info_type.clone()
817}
818
819pub fn flex_item_props_type() -> Type {
821 BUILTIN.flex_item_props_type.clone()
822}