Skip to main content

ferroui_base/markup_types/
plain.rs

1//! Markup metadata of the plain (non object-model) classes and of the
2//! collections of this crate that markup can name, construct or add to.
3//!
4//! A collection is a shared handle (the type itself); a plain class is held
5//! through `Rc`.
6
7use crate::utilities::CultureInfo;
8use crate::animation::{IAnimation, IAnimationSetter, ITransition, KeyFrame, KeyFrames, Transitions};
9use crate::collections::{FerroDictionary, FerroList};
10use crate::data::core::ValueTypes;
11use crate::data::{
12    BindingBase, BindingMode, BindingOperations, BindingPriority, CompiledBinding, CompiledBindingPath, MultiBinding, ReflectionBinding,
13    RelativeSource, RelativeSourceMode, TemplateBinding, TreeType, UpdateSourceTrigger,
14};
15use crate::ferro_markup_type;
16use crate::controls::{IResourceProvider, IThemeVariantProvider, ResourceKey};
17use crate::data::converters::{
18    BoolConverters, DefaultValueConverter, IMultiValueConverter, IValueConverter, ObjectConverters, StringConverters,
19    StringFormatMultiValueConverter, StringFormatValueConverter,
20};
21use crate::input::KeyBinding;
22use crate::input::gesture_recognizers::{GestureRecognizer, GestureRecognizerCollection};
23use crate::interactivity::{RoutedEvent, RoutingStrategies};
24use crate::media::{
25    Drawing, DrawingCollection, Geometry, GeometryCollection, GradientStop, GradientStops, MediaCollection,
26    PathFigure, PathFigures, PathSegment, PathSegments, Points, Transform, Transforms,
27};
28use crate::media::transformation::TransformOperations;
29use crate::metadata::{from_markup_value, MarkupType, MarkupTyped};
30use crate::styling::{
31    IStyle, ITemplate, Selector, Setter, SetterBase, SetterValue, StyleChildren, StyleQuery, ThemeVariant,
32};
33use crate::utilities::NumberFormatInfo;
34use crate::{BoxedValue, FerroProperty, Point, Ref, TypeInfo};
35use std::rc::Rc;
36
37/// The key of a resource from the untyped key markup gives: the managed
38/// original takes any object; the port has text keys, type keys and keys that
39/// already are a [`ResourceKey`] (a theme variant is used through its key).
40pub(super) fn resource_key(key: Option<BoxedValue>) -> Result<ResourceKey, String> {
41    let Some(key) = key else {
42        return Err("The key of a resource cannot be null.".to_string());
43    };
44    if let Some(text) = key.downcast_ref::<String>() {
45        Ok(ResourceKey::from(text.as_str()))
46    } else if let Some(type_) = key.downcast_ref::<&'static TypeInfo>() {
47        Ok(ResourceKey::from(*type_))
48    } else if let Some(key) = key.downcast_ref::<ResourceKey>() {
49        Ok(key.clone())
50    } else if let Some(variant) = key.downcast_ref::<crate::styling::ThemeVariant>() {
51        Ok(variant.key().clone())
52    } else {
53        Err(format!("A value of type '{}' cannot be the key of a resource.", key.type_name()))
54    }
55}
56
57/// The key of a resource as the object it is in the managed original: the text of a
58/// string key, the type of a type key, the key itself otherwise.
59pub(super) fn resource_key_value(key: &ResourceKey) -> Option<BoxedValue> {
60    Some(match key {
61        ResourceKey::String(text) => Rc::new(text.to_string()),
62        ResourceKey::Type(type_) => Rc::new(*type_),
63        ResourceKey::Object(_) => Rc::new(key.clone()),
64    })
65}
66
67/// An untyped value as a value of exactly the type of `property`, as the
68/// property system takes it. Only assignable values are accepted: converting
69/// (parsing, numeric conversion) is the business of the caller.
70pub(super) fn property_value(property: &'static FerroProperty, value: Option<BoxedValue>) -> Result<BoxedValue, String> {
71    let type_ = crate::data::core::ValueType::new(property.property_type(), property.property_type_name());
72    // The unset value is a value of every property.
73    if let Some(unset) = value.as_ref().filter(|value| value.is::<crate::UnsetValueType>()) {
74        return Ok(unset.clone());
75    }
76    let exact = match &value {
77        Some(value) => ValueTypes::try_cast(value, type_),
78        None => ValueTypes::null_value(type_),
79    };
80    exact.ok_or_else(|| format!("The value is not assignable to the property '{}' ({type_}).", property.name()))
81}
82
83/// The key for adding a resource to `dictionary`: adding a key twice is an
84/// error, as in the managed original.
85pub(super) fn new_resource_key(
86    dictionary: &Ref<crate::controls::ResourceDictionary>,
87    key: Option<BoxedValue>,
88) -> Result<ResourceKey, String> {
89    let key = resource_key(key)?;
90    if dictionary.contains_key(&key) {
91        return Err(format!("An item with the same key has already been added. Key: {key}"));
92    }
93    Ok(key)
94}
95
96/// `FerroList<T>.Capacity`.
97fn list_capacity<T: Clone>(list: &FerroList<T>) -> i32 {
98    i32::try_from(list.capacity()).unwrap_or(i32::MAX)
99}
100
101/// The setter of `FerroList<T>.Capacity`: a capacity below the number of
102/// items is an error, as in the managed original.
103fn set_list_capacity<T: Clone>(list: &FerroList<T>, capacity: i32) -> Result<(), &'static str> {
104    match usize::try_from(capacity) {
105        Ok(capacity) if capacity >= list.count() => Ok(list.set_capacity(capacity)),
106        _ => Err("capacity was less than the current size."),
107    }
108}
109
110// System
111
112// A runtime type: the `Type` of the managed original.
113ferro_markup_type!(class TypeInfo as "Type" {
114    this: &'static TypeInfo,
115    namespace: "System",
116    handles: [&'static TypeInfo, Option<&'static TypeInfo>],
117    properties: [
118        Name: String { get: |type_: &&'static TypeInfo| type_.name().to_string() },
119        Namespace: String { get: |type_: &&'static TypeInfo| type_.namespace().to_string() },
120        FullName: String { get: |type_: &&'static TypeInfo| type_.full_name() },
121        BaseType: Option<&'static TypeInfo> { get: |type_: &&'static TypeInfo| type_.base_type() },
122    ],
123});
124
125// System.Globalization
126
127// The mirror of the runtime library's number format, which markup creates as a resource for the
128// `NumberFormat` of numeric inputs (the colour view of the colour picker). Its numeric
129// properties are settable; the text properties are not declared.
130ferro_markup_type!(class NumberFormatInfo {
131    namespace: "System.Globalization",
132    handles: [Rc<NumberFormatInfo>, Option<Rc<NumberFormatInfo>>],
133    this: Rc<NumberFormatInfo>,
134    constructors: [() => || Rc::new(NumberFormatInfo::new())],
135    properties: [
136        CurrencyDecimalDigits: i32 {
137            get: |info: &Rc<NumberFormatInfo>| info.currency_decimal_digits(),
138            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_currency_decimal_digits(value)
139        },
140        CurrencyNegativePattern: i32 {
141            get: |info: &Rc<NumberFormatInfo>| info.currency_negative_pattern(),
142            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_currency_negative_pattern(value)
143        },
144        CurrencyPositivePattern: i32 {
145            get: |info: &Rc<NumberFormatInfo>| info.currency_positive_pattern(),
146            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_currency_positive_pattern(value)
147        },
148        NumberDecimalDigits: i32 {
149            get: |info: &Rc<NumberFormatInfo>| info.number_decimal_digits(),
150            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_number_decimal_digits(value)
151        },
152        NumberNegativePattern: i32 {
153            get: |info: &Rc<NumberFormatInfo>| info.number_negative_pattern(),
154            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_number_negative_pattern(value)
155        },
156        PercentDecimalDigits: i32 {
157            get: |info: &Rc<NumberFormatInfo>| info.percent_decimal_digits(),
158            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_percent_decimal_digits(value)
159        },
160        PercentNegativePattern: i32 {
161            get: |info: &Rc<NumberFormatInfo>| info.percent_negative_pattern(),
162            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_percent_negative_pattern(value)
163        },
164        PercentPositivePattern: i32 {
165            get: |info: &Rc<NumberFormatInfo>| info.percent_positive_pattern(),
166            set: |info: &Rc<NumberFormatInfo>, value: i32| info.set_percent_positive_pattern(value)
167        },
168    ],
169});
170
171// FerroUI
172
173ferro_markup_type!(class FerroProperty {
174    this: &'static FerroProperty,
175    namespace: "FerroUI",
176    handles: [&'static FerroProperty, Option<&'static FerroProperty>],
177    properties: [
178        Name: String { get: |property: &&'static FerroProperty| property.name().to_string() },
179        OwnerType: &'static TypeInfo { get: |property: &&'static FerroProperty| property.owner_type() },
180    ],
181    // The marker of an unset property value.
182    fields: [UnsetValue: crate::UnsetValueType => || crate::UnsetValueType],
183});
184
185// FerroUI.Data
186
187// The marker that tells a binding target to do nothing is any object in the managed original.
188ferro_markup_type!(static BindingOperations {
189    namespace: "FerroUI.Data",
190    fields: [DoNothing: Option<BoxedValue> => || Some(BindingOperations::do_nothing())],
191});
192
193// FerroUI.Interactivity
194
195// A routed event without the type of its arguments: what the typed handles
196// (`RoutedEvent<TappedEventArgs>`, the static values of the classes) denote.
197ferro_markup_type!(class RoutedEvent as "RoutedEvent" {
198    namespace: "FerroUI.Interactivity",
199    handles: [RoutedEvent, Option<RoutedEvent>],
200    properties: [
201        Name: String { get: |event: &RoutedEvent| event.name().to_string() },
202        OwnerType: &'static TypeInfo { get: RoutedEvent::owner_type },
203        RoutingStrategies: RoutingStrategies { get: RoutedEvent::routing_strategies },
204    ],
205});
206
207// FerroUI.Styling
208
209/// Whether a template is a value of `property` itself (`ITemplate` is
210/// assignable from the type of the property), as opposed to what builds
211/// its value.
212fn is_template_property(property: &'static FerroProperty) -> bool {
213    let type_ = crate::data::core::ValueType::new(property.property_type(), property.property_type_name());
214    ValueTypes::is_assignable(type_, crate::data::core::ValueType::of::<Option<Rc<dyn ITemplate>>>())
215}
216
217/// `Setter.Value` of the managed original holds any object; what the setter
218/// does with it follows from its type, as `Setter.Instance` decides there: a
219/// binding is bound, a template builds the value unless the property itself
220/// holds templates, anything else is the value. The object may arrive in
221/// any of its forms (its concrete handle, the handle of a contract, an "any
222/// value" box holding either).
223fn set_setter_value(setter: &Rc<Setter>, value: Option<BoxedValue>) {
224    let property = setter.property();
225    setter.set_value(value.map(|value| {
226        let object = match value.downcast_ref::<Option<BoxedValue>>() {
227            Some(contents) => contents.clone(),
228            None => Some(value.clone()),
229        };
230        if let Some(binding) = from_markup_value::<Rc<dyn BindingBase>>(&object) {
231            SetterValue::BindingBase(binding)
232        } else if let Some(template) =
233            from_markup_value::<Rc<dyn ITemplate>>(&object).filter(|_| !property.is_some_and(is_template_property))
234        {
235            SetterValue::Template(template)
236        } else {
237            // The value of the property: what is assignable to its type is held as a value
238            // of exactly that type (the setter requires it); anything else is kept as it
239            // is, and reported by the setter when the style is applied.
240            let exact = property.and_then(|property| {
241                property_value(property, Some(value.clone())).or_else(|_| property_value(property, object.clone())).ok()
242            });
243            SetterValue::Value(exact.unwrap_or(value))
244        }
245    }));
246}
247
248/// The value of a setter as the object it was set to. (A setter bound to a
249/// plain source of values, which markup cannot create, reads as null.)
250fn setter_value(setter: &Rc<Setter>) -> Option<BoxedValue> {
251    match setter.value()? {
252        SetterValue::Value(value) => Some(value),
253        SetterValue::BindingBase(binding) => Some(Rc::new(binding)),
254        SetterValue::Template(template) => Some(Rc::new(template)),
255        SetterValue::Binding(_) => None,
256    }
257}
258
259fn new_setter(property: &'static FerroProperty, value: Option<BoxedValue>) -> Rc<Setter> {
260    let setter = Setter::empty();
261    setter.set_property(Some(property));
262    set_setter_value(&setter, value);
263    setter
264}
265
266ferro_markup_type!(class Setter {
267    namespace: "FerroUI.Styling",
268    handles: [Rc<Setter>, Option<Rc<Setter>>],
269    this: Rc<Setter>,
270    base: Rc<dyn SetterBase>,
271    interfaces: [Rc<dyn IAnimationSetter>],
272    content: Value,
273    constructors: [
274        () => Setter::empty,
275        (&'static FerroProperty, Option<BoxedValue>) => new_setter,
276    ],
277    properties: [
278        Property: Option<&'static FerroProperty> { get: Setter::property, set: Setter::set_property },
279        Value: Option<BoxedValue> { get: setter_value, set: set_setter_value } [AssignBinding, DependsOn("Property")],
280    ],
281});
282
283ferro_markup_type!(class Selector {
284    namespace: "FerroUI.Styling",
285    handles: [Selector, Option<Selector>],
286});
287
288ferro_markup_type!(class StyleQuery {
289    namespace: "FerroUI.Styling",
290    handles: [StyleQuery, Option<StyleQuery>],
291});
292
293// The children of a style.
294ferro_markup_type!(class StyleChildren {
295    namespace: "FerroUI.Styling",
296    handles: [StyleChildren, Option<StyleChildren>],
297    properties: [Count: i32 { get: |children: &StyleChildren| children.count() as i32 }],
298    methods: [fn Add(Rc<dyn IStyle>) => |children: &StyleChildren, style: Rc<dyn IStyle>| children.add(style)],
299});
300
301// FerroUI.Data
302
303ferro_markup_type!(class RelativeSource {
304    namespace: "FerroUI.Data",
305    handles: [Rc<RelativeSource>, Option<Rc<RelativeSource>>],
306    this: Rc<RelativeSource>,
307    constructors: [
308        () => RelativeSource::empty,
309        (RelativeSourceMode) => RelativeSource::new,
310    ],
311    properties: [
312        AncestorLevel: i32 { get: RelativeSource::ancestor_level, set: RelativeSource::set_ancestor_level },
313        AncestorType: Option<&'static TypeInfo> {
314            get: RelativeSource::ancestor_type,
315            set: RelativeSource::set_ancestor_type
316        },
317        Mode: RelativeSourceMode { get: RelativeSource::mode, set: RelativeSource::set_mode },
318        Tree: TreeType { get: RelativeSource::tree, set: RelativeSource::set_tree },
319    ],
320});
321
322ferro_markup_type!(class CompiledBinding {
323    namespace: "FerroUI.Data",
324    handles: [Rc<CompiledBinding>, Option<Rc<CompiledBinding>>],
325    this: Rc<CompiledBinding>,
326    base: Rc<dyn BindingBase>,
327    constructors: [
328        () => CompiledBinding::empty,
329        (CompiledBindingPath) => CompiledBinding::new,
330    ],
331    properties: [
332        Delay: i32 { get: CompiledBinding::delay, set: CompiledBinding::set_delay },
333        Converter: Option<Rc<dyn IValueConverter>> { get: CompiledBinding::converter, set: CompiledBinding::set_converter },
334        ConverterCulture: Option<CultureInfo> {
335            get: CompiledBinding::converter_culture,
336            set: CompiledBinding::set_converter_culture
337        },
338        ConverterParameter: Option<BoxedValue> {
339            get: CompiledBinding::converter_parameter,
340            set: CompiledBinding::set_converter_parameter
341        },
342        FallbackValue: Option<BoxedValue> {
343            get: CompiledBinding::fallback_value,
344            set: CompiledBinding::set_fallback_value
345        },
346        Mode: BindingMode { get: CompiledBinding::mode, set: CompiledBinding::set_mode },
347        Path: Option<CompiledBindingPath> { get: CompiledBinding::path, set: CompiledBinding::set_path }
348            [ConstructorArgument("path")],
349        Priority: BindingPriority { get: CompiledBinding::priority, set: CompiledBinding::set_priority },
350        Source: Option<BoxedValue> { get: CompiledBinding::source, set: CompiledBinding::set_source },
351        StringFormat: Option<String> { get: CompiledBinding::string_format, set: CompiledBinding::set_string_format },
352        TargetNullValue: Option<BoxedValue> {
353            get: CompiledBinding::target_null_value,
354            set: CompiledBinding::set_target_null_value
355        },
356        UpdateSourceTrigger: UpdateSourceTrigger {
357            get: CompiledBinding::update_source_trigger,
358            set: CompiledBinding::set_update_source_trigger
359        },
360    ],
361});
362
363ferro_markup_type!(class ReflectionBinding {
364    namespace: "FerroUI.Data",
365    handles: [Rc<ReflectionBinding>, Option<Rc<ReflectionBinding>>],
366    this: Rc<ReflectionBinding>,
367    base: Rc<dyn BindingBase>,
368    constructors: [
369        () => ReflectionBinding::empty,
370        (String) => |path: String| ReflectionBinding::new(&path),
371    ],
372    properties: [
373        Delay: i32 { get: ReflectionBinding::delay, set: ReflectionBinding::set_delay },
374        Converter: Option<Rc<dyn IValueConverter>> {
375            get: ReflectionBinding::converter,
376            set: ReflectionBinding::set_converter
377        },
378        ConverterCulture: Option<CultureInfo> {
379            get: ReflectionBinding::converter_culture,
380            set: ReflectionBinding::set_converter_culture
381        },
382        ConverterParameter: Option<BoxedValue> {
383            get: ReflectionBinding::converter_parameter,
384            set: ReflectionBinding::set_converter_parameter
385        },
386        ElementName: Option<String> { get: ReflectionBinding::element_name, set: ReflectionBinding::set_element_name },
387        FallbackValue: Option<BoxedValue> {
388            get: ReflectionBinding::fallback_value,
389            set: ReflectionBinding::set_fallback_value
390        },
391        Mode: BindingMode { get: ReflectionBinding::mode, set: ReflectionBinding::set_mode },
392        Path: String { get: ReflectionBinding::path, set: ReflectionBinding::set_path } [ConstructorArgument("path")],
393        Priority: BindingPriority { get: ReflectionBinding::priority, set: ReflectionBinding::set_priority },
394        RelativeSource: Option<Rc<RelativeSource>> {
395            get: ReflectionBinding::relative_source,
396            set: ReflectionBinding::set_relative_source
397        },
398        Source: Option<BoxedValue> { get: ReflectionBinding::source, set: ReflectionBinding::set_source },
399        StringFormat: Option<String> {
400            get: ReflectionBinding::string_format,
401            set: ReflectionBinding::set_string_format
402        },
403        TargetNullValue: Option<BoxedValue> {
404            get: ReflectionBinding::target_null_value,
405            set: ReflectionBinding::set_target_null_value
406        },
407        UpdateSourceTrigger: UpdateSourceTrigger {
408            get: ReflectionBinding::update_source_trigger,
409            set: ReflectionBinding::set_update_source_trigger
410        },
411    ],
412});
413
414ferro_markup_type!(class MultiBinding {
415    namespace: "FerroUI.Data",
416    handles: [Rc<MultiBinding>, Option<Rc<MultiBinding>>],
417    this: Rc<MultiBinding>,
418    base: Rc<dyn BindingBase>,
419    content: Bindings,
420    constructors: [() => MultiBinding::new],
421    properties: [
422        Bindings: FerroList<Rc<dyn BindingBase>> { get: MultiBinding::bindings, set: MultiBinding::set_bindings }
423            [AssignBinding],
424        Converter: Option<Rc<dyn IMultiValueConverter>> { get: MultiBinding::converter, set: MultiBinding::set_converter },
425        ConverterCulture: Option<CultureInfo> {
426            get: MultiBinding::converter_culture,
427            set: MultiBinding::set_converter_culture
428        },
429        ConverterParameter: Option<BoxedValue> {
430            get: MultiBinding::converter_parameter,
431            set: MultiBinding::set_converter_parameter
432        },
433        FallbackValue: Option<BoxedValue> { get: MultiBinding::fallback_value, set: MultiBinding::set_fallback_value },
434        TargetNullValue: Option<BoxedValue> {
435            get: MultiBinding::target_null_value,
436            set: MultiBinding::set_target_null_value
437        },
438        Mode: BindingMode { get: MultiBinding::mode, set: MultiBinding::set_mode },
439        Priority: BindingPriority { get: MultiBinding::priority, set: MultiBinding::set_priority },
440        RelativeSource: Option<Rc<RelativeSource>> {
441            get: MultiBinding::relative_source,
442            set: MultiBinding::set_relative_source
443        },
444        StringFormat: Option<String> { get: MultiBinding::string_format, set: MultiBinding::set_string_format },
445    ],
446});
447
448ferro_markup_type!(class TemplateBinding {
449    namespace: "FerroUI.Data",
450    handles: [Rc<TemplateBinding>, Option<Rc<TemplateBinding>>],
451    this: Rc<TemplateBinding>,
452    base: Rc<dyn BindingBase>,
453    constructors: [
454        () => TemplateBinding::empty,
455        (property: &'static FerroProperty [InheritDataTypeFrom(2)]) => TemplateBinding::new,
456    ],
457    properties: [
458        Converter: Option<Rc<dyn IValueConverter>> { get: TemplateBinding::converter, set: TemplateBinding::set_converter },
459        ConverterCulture: Option<CultureInfo> {
460            get: TemplateBinding::converter_culture,
461            set: TemplateBinding::set_converter_culture
462        },
463        ConverterParameter: Option<BoxedValue> {
464            get: TemplateBinding::converter_parameter,
465            set: TemplateBinding::set_converter_parameter
466        },
467        Mode: BindingMode { get: TemplateBinding::mode, set: TemplateBinding::set_mode },
468        // The argument of `InheritDataTypeFrom` is `InheritDataTypeFromScopeKind.ControlTemplate` (2).
469        Property: Option<&'static FerroProperty> { get: TemplateBinding::property, set: TemplateBinding::set_property }
470            [ConstructorArgument("property"), InheritDataTypeFrom(2)],
471    ],
472    // The binding is its own markup extension: it provides itself, as a binding.
473    methods: [
474        fn ProvideValue() -> Rc<dyn BindingBase> =>
475            |this: &Rc<TemplateBinding>| -> Rc<dyn BindingBase> { this.clone() },
476    ],
477});
478
479// FerroUI.Data.Converters
480
481ferro_markup_type!(static ObjectConverters {
482    namespace: "FerroUI.Data.Converters",
483    fields: [
484        IsNull: Rc<dyn IValueConverter> => ObjectConverters::is_null,
485        IsNotNull: Rc<dyn IValueConverter> => ObjectConverters::is_not_null,
486        Equal: Rc<dyn IValueConverter> => ObjectConverters::equal,
487        NotEqual: Rc<dyn IValueConverter> => ObjectConverters::not_equal,
488        AreAllNull: Rc<dyn IMultiValueConverter> => ObjectConverters::are_all_null,
489        AreAnyNull: Rc<dyn IMultiValueConverter> => ObjectConverters::are_any_null,
490        AreAllEqual: Rc<dyn IMultiValueConverter> => ObjectConverters::are_all_equal,
491    ],
492});
493
494ferro_markup_type!(static BoolConverters {
495    namespace: "FerroUI.Data.Converters",
496    fields: [
497        And: Rc<dyn IMultiValueConverter> => BoolConverters::and,
498        Or: Rc<dyn IMultiValueConverter> => BoolConverters::or,
499        Not: Rc<dyn IValueConverter> => BoolConverters::not,
500    ],
501});
502
503ferro_markup_type!(static StringConverters {
504    namespace: "FerroUI.Data.Converters",
505    fields: [
506        IsNullOrEmpty: Rc<dyn IValueConverter> => StringConverters::is_null_or_empty,
507        IsNotNullOrEmpty: Rc<dyn IValueConverter> => StringConverters::is_not_null_or_empty,
508    ],
509});
510
511// The converter classes are reference types: an instance equals itself.
512impl PartialEq for DefaultValueConverter {
513    fn eq(&self, other: &Self) -> bool {
514        std::ptr::eq(self, other)
515    }
516}
517
518impl PartialEq for StringFormatValueConverter {
519    fn eq(&self, other: &Self) -> bool {
520        std::ptr::eq(self, other)
521    }
522}
523
524impl PartialEq for StringFormatMultiValueConverter {
525    fn eq(&self, other: &Self) -> bool {
526        std::ptr::eq(self, other)
527    }
528}
529
530// The static instance is held through the converter contract in this port.
531ferro_markup_type!(class DefaultValueConverter {
532    namespace: "FerroUI.Data.Converters",
533    handles: [Rc<DefaultValueConverter>, Option<Rc<DefaultValueConverter>>],
534    interfaces: [Rc<dyn IValueConverter>],
535    fields: [Instance: Rc<dyn IValueConverter> => DefaultValueConverter::instance],
536});
537
538ferro_markup_type!(class StringFormatValueConverter {
539    namespace: "FerroUI.Data.Converters",
540    handles: [Rc<StringFormatValueConverter>, Option<Rc<StringFormatValueConverter>>],
541    this: Rc<StringFormatValueConverter>,
542    interfaces: [Rc<dyn IValueConverter>],
543    constructors: [
544        (String, Option<Rc<dyn IValueConverter>>) => |format: String, inner: Option<Rc<dyn IValueConverter>>| {
545            Rc::new(StringFormatValueConverter::new(format, inner))
546        },
547    ],
548    properties: [
549        Inner: Option<Rc<dyn IValueConverter>> { get: |c: &Rc<StringFormatValueConverter>| c.inner().cloned() },
550        Format: String { get: |c: &Rc<StringFormatValueConverter>| c.format().to_string() },
551    ],
552});
553
554ferro_markup_type!(class StringFormatMultiValueConverter {
555    namespace: "FerroUI.Data.Converters",
556    handles: [Rc<StringFormatMultiValueConverter>, Option<Rc<StringFormatMultiValueConverter>>],
557    this: Rc<StringFormatMultiValueConverter>,
558    interfaces: [Rc<dyn IMultiValueConverter>],
559    constructors: [
560        (String, Option<Rc<dyn IMultiValueConverter>>) =>
561            |format: String, inner: Option<Rc<dyn IMultiValueConverter>>| {
562                Rc::new(StringFormatMultiValueConverter::new(format, inner))
563            },
564    ],
565    properties: [
566        Inner: Option<Rc<dyn IMultiValueConverter>> {
567            get: |c: &Rc<StringFormatMultiValueConverter>| c.inner().cloned()
568        },
569        Format: String { get: |c: &Rc<StringFormatMultiValueConverter>| c.format().to_string() },
570    ],
571});
572
573// FerroUI.Animation
574
575ferro_markup_type!(class KeyFrames {
576    namespace: "FerroUI.Animation",
577    handles: [KeyFrames, Option<KeyFrames>],
578    base: FerroList<Ref<KeyFrame>>,
579    constructors: [() => KeyFrames::new],
580    methods: [fn Add(Ref<KeyFrame>) => |frames: &KeyFrames, frame: Ref<KeyFrame>| frames.add(frame)],
581});
582
583ferro_markup_type!(class Transitions {
584    namespace: "FerroUI.Animation",
585    handles: [Transitions, Option<Transitions>],
586    base: FerroList<Rc<dyn ITransition>>,
587    constructors: [() => Transitions::new],
588    methods: [
589        fn Add(Rc<dyn ITransition>) => |transitions: &Transitions, item: Rc<dyn ITransition>| transitions.add(item),
590    ],
591});
592
593// FerroUI.Input.GestureRecognizers
594
595ferro_markup_type!(class GestureRecognizerCollection {
596    namespace: "FerroUI.Input.GestureRecognizers",
597    handles: [GestureRecognizerCollection, Option<GestureRecognizerCollection>],
598    methods: [
599        fn Add(Ref<GestureRecognizer>) =>
600            |recognizers: &GestureRecognizerCollection, item: Ref<GestureRecognizer>| recognizers.add(item),
601    ],
602});
603
604// FerroUI.Media
605
606ferro_markup_type!(class GradientStops {
607    namespace: "FerroUI.Media",
608    handles: [GradientStops, Option<GradientStops>],
609    base: FerroList<Ref<GradientStop>>,
610    constructors: [() => GradientStops::new],
611    methods: [fn Add(Ref<GradientStop>) => |stops: &GradientStops, item: Ref<GradientStop>| stops.add(item)],
612});
613
614ferro_markup_type!(class PathFigures {
615    namespace: "FerroUI.Media",
616    handles: [PathFigures, Option<PathFigures>],
617    base: FerroList<Ref<PathFigure>>,
618    parse: PathFigures::parse,
619    constructors: [() => PathFigures::new],
620    methods: [fn Add(Ref<PathFigure>) => |figures: &PathFigures, item: Ref<PathFigure>| figures.add(item)],
621});
622
623ferro_markup_type!(class PathSegments {
624    namespace: "FerroUI.Media",
625    handles: [PathSegments, Option<PathSegments>],
626    base: FerroList<Ref<PathSegment>>,
627    constructors: [() => PathSegments::new],
628    methods: [fn Add(Ref<PathSegment>) => |segments: &PathSegments, item: Ref<PathSegment>| segments.add(item)],
629});
630
631ferro_markup_type!(class Points {
632    namespace: "FerroUI",
633    handles: [Points, Option<Points>],
634    base: FerroList<Point>,
635    constructors: [() => Points::new],
636    methods: [fn Add(Point) => |points: &Points, item: Point| points.add(item)],
637});
638
639ferro_markup_type!(class GeometryCollection {
640    namespace: "FerroUI.Media",
641    handles: [GeometryCollection, Option<GeometryCollection>],
642    base: FerroList<Ref<Geometry>>,
643    constructors: [() => GeometryCollection::new],
644    methods: [
645        fn Add(Ref<Geometry>) => |geometries: &GeometryCollection, item: Ref<Geometry>| geometries.add(item),
646    ],
647});
648
649ferro_markup_type!(class Transforms {
650    namespace: "FerroUI.Media",
651    handles: [Transforms, Option<Transforms>],
652    base: FerroList<Ref<Transform>>,
653    constructors: [() => Transforms::new],
654    methods: [fn Add(Ref<Transform>) => |transforms: &Transforms, item: Ref<Transform>| transforms.add(item)],
655});
656
657ferro_markup_type!(class DrawingCollection {
658    namespace: "FerroUI.Media",
659    handles: [DrawingCollection, Option<DrawingCollection>],
660    base: FerroList<Ref<Drawing>>,
661    constructors: [() => DrawingCollection::new],
662    methods: [fn Add(Ref<Drawing>) => |drawings: &DrawingCollection, item: Ref<Drawing>| drawings.add(item)],
663});
664
665// The font manager: markup names the current one (`{x:Static FontManager.Current}`) and binds
666// to the fonts of the system.
667ferro_markup_type!(class crate::media::FontManager as "FontManager" {
668    namespace: "FerroUI.Media",
669    handles: [Rc<crate::media::FontManager>, Option<Rc<crate::media::FontManager>>],
670    this: Rc<crate::media::FontManager>,
671    properties: [
672        DefaultFontFamily: crate::media::FontFamily {
673            get: |font_manager: &Rc<crate::media::FontManager>| font_manager.default_font_family().clone()
674        },
675        SystemFonts: Rc<dyn crate::media::fonts::IFontCollection> {
676            get: |font_manager: &Rc<crate::media::FontManager>| font_manager.system_fonts()
677        },
678    ],
679    static_properties: [Current: Rc<crate::media::FontManager> { get: crate::media::FontManager::current }],
680});
681
682// FerroUI.Media.Transformation
683
684// A list of transform operations: the text content of an element is its text form.
685ferro_markup_type!(class TransformOperations {
686    namespace: "FerroUI.Media.Transformation",
687    handles: [Rc<TransformOperations>, Option<Rc<TransformOperations>>],
688    this: Rc<TransformOperations>,
689    interfaces: [Rc<dyn crate::media::ITransform>],
690    parse: TransformOperations::parse,
691    properties: [
692        IsIdentity: bool { get: |operations: &Rc<TransformOperations>| operations.is_identity() },
693        Value: crate::Matrix { get: |operations: &Rc<TransformOperations>| operations.value() },
694    ],
695    static_properties: [Identity: Rc<TransformOperations> { get: TransformOperations::identity }],
696});
697
698// FerroUI.Collections
699
700// The list of numbers of dash arrays and tick lists.
701ferro_markup_type!(class MediaCollection<f64> as "FerroList`1" {
702    namespace: "FerroUI.Collections",
703    handles: [MediaCollection<f64>, Option<MediaCollection<f64>>],
704    generic: "FerroList`1" [f64],
705    constructors: [() => MediaCollection::<f64>::new],
706    properties: [
707        Capacity: i32 {
708            get: |list: &MediaCollection<f64>| list_capacity(list.list()),
709            try_set: |list: &MediaCollection<f64>, capacity: i32| set_list_capacity(list.list(), capacity)
710        },
711        Count: i32 { get: |list: &MediaCollection<f64>| list.len() as i32 },
712    ],
713    methods: [fn Add(f64) => |list: &MediaCollection<f64>, item: f64| list.add(item)],
714});
715
716// The instantiations of the notifying list that are types of properties.
717
718ferro_markup_type!(class FerroList<Rc<dyn IAnimationSetter>> as "FerroList`1" {
719    namespace: "FerroUI.Collections",
720    handles: [FerroList<Rc<dyn IAnimationSetter>>, Option<FerroList<Rc<dyn IAnimationSetter>>>],
721    generic: "FerroList`1" [Rc<dyn IAnimationSetter>],
722    constructors: [() => FerroList::<Rc<dyn IAnimationSetter>>::new],
723    properties: [
724        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
725        Count: i32 { get: |list: &FerroList<Rc<dyn IAnimationSetter>>| list.count() as i32 },
726    ],
727    methods: [fn Add(Rc<dyn IAnimationSetter>) => |list: &FerroList<Rc<dyn IAnimationSetter>>, item: Rc<dyn IAnimationSetter>| list.add(item)],
728});
729
730ferro_markup_type!(class FerroList<Rc<dyn IResourceProvider>> as "FerroList`1" {
731    namespace: "FerroUI.Collections",
732    handles: [FerroList<Rc<dyn IResourceProvider>>, Option<FerroList<Rc<dyn IResourceProvider>>>],
733    generic: "FerroList`1" [Rc<dyn IResourceProvider>],
734    constructors: [() => FerroList::<Rc<dyn IResourceProvider>>::new],
735    properties: [
736        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
737        Count: i32 { get: |list: &FerroList<Rc<dyn IResourceProvider>>| list.count() as i32 },
738    ],
739    methods: [fn Add(Rc<dyn IResourceProvider>) => |list: &FerroList<Rc<dyn IResourceProvider>>, item: Rc<dyn IResourceProvider>| list.add(item)],
740});
741
742ferro_markup_type!(class FerroList<Ref<KeyBinding>> as "FerroList`1" {
743    namespace: "FerroUI.Collections",
744    handles: [FerroList<Ref<KeyBinding>>, Option<FerroList<Ref<KeyBinding>>>],
745    generic: "FerroList`1" [Ref<KeyBinding>],
746    constructors: [() => FerroList::<Ref<KeyBinding>>::new],
747    properties: [
748        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
749        Count: i32 { get: |list: &FerroList<Ref<KeyBinding>>| list.count() as i32 },
750    ],
751    methods: [fn Add(Ref<KeyBinding>) => |list: &FerroList<Ref<KeyBinding>>, item: Ref<KeyBinding>| list.add(item)],
752});
753
754ferro_markup_type!(class FerroList<Rc<dyn SetterBase>> as "FerroList`1" {
755    namespace: "FerroUI.Collections",
756    handles: [FerroList<Rc<dyn SetterBase>>, Option<FerroList<Rc<dyn SetterBase>>>],
757    generic: "FerroList`1" [Rc<dyn SetterBase>],
758    constructors: [() => FerroList::<Rc<dyn SetterBase>>::new],
759    properties: [
760        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
761        Count: i32 { get: |list: &FerroList<Rc<dyn SetterBase>>| list.count() as i32 },
762    ],
763    methods: [fn Add(Rc<dyn SetterBase>) => |list: &FerroList<Rc<dyn SetterBase>>, item: Rc<dyn SetterBase>| list.add(item)],
764});
765
766ferro_markup_type!(class FerroList<Rc<dyn IAnimation>> as "FerroList`1" {
767    namespace: "FerroUI.Collections",
768    handles: [FerroList<Rc<dyn IAnimation>>, Option<FerroList<Rc<dyn IAnimation>>>],
769    generic: "FerroList`1" [Rc<dyn IAnimation>],
770    constructors: [() => FerroList::<Rc<dyn IAnimation>>::new],
771    properties: [
772        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
773        Count: i32 { get: |list: &FerroList<Rc<dyn IAnimation>>| list.count() as i32 },
774    ],
775    methods: [fn Add(Rc<dyn IAnimation>) => |list: &FerroList<Rc<dyn IAnimation>>, item: Rc<dyn IAnimation>| list.add(item)],
776});
777
778ferro_markup_type!(class FerroList<Rc<dyn BindingBase>> as "FerroList`1" {
779    namespace: "FerroUI.Collections",
780    handles: [FerroList<Rc<dyn BindingBase>>, Option<FerroList<Rc<dyn BindingBase>>>],
781    generic: "FerroList`1" [Rc<dyn BindingBase>],
782    constructors: [() => FerroList::<Rc<dyn BindingBase>>::new],
783    properties: [
784        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
785        Count: i32 { get: |list: &FerroList<Rc<dyn BindingBase>>| list.count() as i32 },
786    ],
787    methods: [fn Add(Rc<dyn BindingBase>) => |list: &FerroList<Rc<dyn BindingBase>>, item: Rc<dyn BindingBase>| list.add(item)],
788});
789
790// The lists the named collections derive from.
791
792ferro_markup_type!(class FerroList<Point> as "FerroList`1" {
793    namespace: "FerroUI.Collections",
794    handles: [FerroList<Point>, Option<FerroList<Point>>],
795    generic: "FerroList`1" [Point],
796    constructors: [() => FerroList::<Point>::new],
797    properties: [
798        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
799        Count: i32 { get: |list: &FerroList<Point>| list.count() as i32 },
800    ],
801    methods: [fn Add(Point) => |list: &FerroList<Point>, item: Point| list.add(item)],
802});
803
804ferro_markup_type!(class FerroList<String> as "FerroList`1" {
805    namespace: "FerroUI.Collections",
806    handles: [FerroList<String>, Option<FerroList<String>>],
807    generic: "FerroList`1" [String],
808    constructors: [() => FerroList::<String>::new],
809    properties: [
810        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
811        Count: i32 { get: |list: &FerroList<String>| list.count() as i32 },
812    ],
813    methods: [fn Add(String) => |list: &FerroList<String>, item: String| list.add(item)],
814});
815
816ferro_markup_type!(class FerroList<Ref<GradientStop>> as "FerroList`1" {
817    namespace: "FerroUI.Collections",
818    handles: [FerroList<Ref<GradientStop>>, Option<FerroList<Ref<GradientStop>>>],
819    generic: "FerroList`1" [Ref<GradientStop>],
820    constructors: [() => FerroList::<Ref<GradientStop>>::new],
821    properties: [
822        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
823        Count: i32 { get: |list: &FerroList<Ref<GradientStop>>| list.count() as i32 },
824    ],
825    methods: [fn Add(Ref<GradientStop>) => |list: &FerroList<Ref<GradientStop>>, item: Ref<GradientStop>| list.add(item)],
826});
827
828ferro_markup_type!(class FerroList<Rc<dyn ITransition>> as "FerroList`1" {
829    namespace: "FerroUI.Collections",
830    handles: [FerroList<Rc<dyn ITransition>>, Option<FerroList<Rc<dyn ITransition>>>],
831    generic: "FerroList`1" [Rc<dyn ITransition>],
832    constructors: [() => FerroList::<Rc<dyn ITransition>>::new],
833    properties: [
834        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
835        Count: i32 { get: |list: &FerroList<Rc<dyn ITransition>>| list.count() as i32 },
836    ],
837    methods: [fn Add(Rc<dyn ITransition>) => |list: &FerroList<Rc<dyn ITransition>>, item: Rc<dyn ITransition>| list.add(item)],
838});
839
840ferro_markup_type!(class FerroList<Ref<KeyFrame>> as "FerroList`1" {
841    namespace: "FerroUI.Collections",
842    handles: [FerroList<Ref<KeyFrame>>, Option<FerroList<Ref<KeyFrame>>>],
843    generic: "FerroList`1" [Ref<KeyFrame>],
844    constructors: [() => FerroList::<Ref<KeyFrame>>::new],
845    properties: [
846        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
847        Count: i32 { get: |list: &FerroList<Ref<KeyFrame>>| list.count() as i32 },
848    ],
849    methods: [fn Add(Ref<KeyFrame>) => |list: &FerroList<Ref<KeyFrame>>, item: Ref<KeyFrame>| list.add(item)],
850});
851
852ferro_markup_type!(class FerroList<Ref<PathFigure>> as "FerroList`1" {
853    namespace: "FerroUI.Collections",
854    handles: [FerroList<Ref<PathFigure>>, Option<FerroList<Ref<PathFigure>>>],
855    generic: "FerroList`1" [Ref<PathFigure>],
856    constructors: [() => FerroList::<Ref<PathFigure>>::new],
857    properties: [
858        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
859        Count: i32 { get: |list: &FerroList<Ref<PathFigure>>| list.count() as i32 },
860    ],
861    methods: [fn Add(Ref<PathFigure>) => |list: &FerroList<Ref<PathFigure>>, item: Ref<PathFigure>| list.add(item)],
862});
863
864ferro_markup_type!(class FerroList<Ref<PathSegment>> as "FerroList`1" {
865    namespace: "FerroUI.Collections",
866    handles: [FerroList<Ref<PathSegment>>, Option<FerroList<Ref<PathSegment>>>],
867    generic: "FerroList`1" [Ref<PathSegment>],
868    constructors: [() => FerroList::<Ref<PathSegment>>::new],
869    properties: [
870        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
871        Count: i32 { get: |list: &FerroList<Ref<PathSegment>>| list.count() as i32 },
872    ],
873    methods: [fn Add(Ref<PathSegment>) => |list: &FerroList<Ref<PathSegment>>, item: Ref<PathSegment>| list.add(item)],
874});
875
876ferro_markup_type!(class FerroList<Ref<Drawing>> as "FerroList`1" {
877    namespace: "FerroUI.Collections",
878    handles: [FerroList<Ref<Drawing>>, Option<FerroList<Ref<Drawing>>>],
879    generic: "FerroList`1" [Ref<Drawing>],
880    constructors: [() => FerroList::<Ref<Drawing>>::new],
881    properties: [
882        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
883        Count: i32 { get: |list: &FerroList<Ref<Drawing>>| list.count() as i32 },
884    ],
885    methods: [fn Add(Ref<Drawing>) => |list: &FerroList<Ref<Drawing>>, item: Ref<Drawing>| list.add(item)],
886});
887
888ferro_markup_type!(class FerroList<Ref<Transform>> as "FerroList`1" {
889    namespace: "FerroUI.Collections",
890    handles: [FerroList<Ref<Transform>>, Option<FerroList<Ref<Transform>>>],
891    generic: "FerroList`1" [Ref<Transform>],
892    constructors: [() => FerroList::<Ref<Transform>>::new],
893    properties: [
894        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
895        Count: i32 { get: |list: &FerroList<Ref<Transform>>| list.count() as i32 },
896    ],
897    methods: [fn Add(Ref<Transform>) => |list: &FerroList<Ref<Transform>>, item: Ref<Transform>| list.add(item)],
898});
899
900ferro_markup_type!(class FerroList<Ref<Geometry>> as "FerroList`1" {
901    namespace: "FerroUI.Collections",
902    handles: [FerroList<Ref<Geometry>>, Option<FerroList<Ref<Geometry>>>],
903    generic: "FerroList`1" [Ref<Geometry>],
904    constructors: [() => FerroList::<Ref<Geometry>>::new],
905    properties: [
906        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
907        Count: i32 { get: |list: &FerroList<Ref<Geometry>>| list.count() as i32 },
908    ],
909    methods: [fn Add(Ref<Geometry>) => |list: &FerroList<Ref<Geometry>>, item: Ref<Geometry>| list.add(item)],
910});
911
912ferro_markup_type!(class FerroList<crate::media::FontFeature> as "FerroList`1" {
913    namespace: "FerroUI.Collections",
914    handles: [FerroList<crate::media::FontFeature>, Option<FerroList<crate::media::FontFeature>>],
915    generic: "FerroList`1" [crate::media::FontFeature],
916    constructors: [() => FerroList::<crate::media::FontFeature>::new],
917    properties: [
918        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
919        Count: i32 { get: |list: &FerroList<crate::media::FontFeature>| list.count() as i32 },
920    ],
921    methods: [fn Add(crate::media::FontFeature) => |list: &FerroList<crate::media::FontFeature>, item: crate::media::FontFeature| list.add(item)],
922});
923
924ferro_markup_type!(class FerroList<Ref<crate::media::TextDecoration>> as "FerroList`1" {
925    namespace: "FerroUI.Collections",
926    handles: [FerroList<Ref<crate::media::TextDecoration>>, Option<FerroList<Ref<crate::media::TextDecoration>>>],
927    generic: "FerroList`1" [Ref<crate::media::TextDecoration>],
928    constructors: [() => FerroList::<Ref<crate::media::TextDecoration>>::new],
929    properties: [
930        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
931        Count: i32 { get: |list: &FerroList<Ref<crate::media::TextDecoration>>| list.count() as i32 },
932    ],
933    methods: [fn Add(Ref<crate::media::TextDecoration>) => |list: &FerroList<Ref<crate::media::TextDecoration>>, item: Ref<crate::media::TextDecoration>| list.add(item)],
934});
935
936// The theme dictionaries of a resource dictionary.
937ferro_markup_type!(class FerroDictionary<ThemeVariant, Rc<dyn IThemeVariantProvider>> as "FerroDictionary`2" {
938    namespace: "FerroUI.Collections",
939    handles: [
940        FerroDictionary<ThemeVariant, Rc<dyn IThemeVariantProvider>>,
941        Option<FerroDictionary<ThemeVariant, Rc<dyn IThemeVariantProvider>>>,
942    ],
943    generic: "FerroDictionary`2" [ThemeVariant, Rc<dyn IThemeVariantProvider>],
944    properties: [
945        Count: i32 { get: |d: &FerroDictionary<ThemeVariant, Rc<dyn IThemeVariantProvider>>| d.count() as i32 },
946    ],
947    methods: [
948        // Adding a key twice is an error, as in the managed original.
949        try fn Add(ThemeVariant, Rc<dyn IThemeVariantProvider>) =>
950            |d: &FerroDictionary<ThemeVariant, Rc<dyn IThemeVariantProvider>>,
951             key: ThemeVariant,
952             value: Rc<dyn IThemeVariantProvider>| {
953                if d.contains_key(&key) {
954                    return Err(format!("An item with the same key has already been added. Key: {key}"));
955                }
956                Ok(d.add(key, value))
957            },
958    ],
959});
960
961/// The types declared in this file.
962pub(super) const TYPES: &[&MarkupType] = &[
963    <TypeInfo as MarkupTyped>::MARKUP,
964    <FerroProperty as MarkupTyped>::MARKUP,
965    <NumberFormatInfo as MarkupTyped>::MARKUP,
966    <BindingOperations as MarkupTyped>::MARKUP,
967    <RoutedEvent as MarkupTyped>::MARKUP,
968    <Setter as MarkupTyped>::MARKUP,
969    <Selector as MarkupTyped>::MARKUP,
970    <StyleQuery as MarkupTyped>::MARKUP,
971    <StyleChildren as MarkupTyped>::MARKUP,
972    <RelativeSource as MarkupTyped>::MARKUP,
973    <CompiledBinding as MarkupTyped>::MARKUP,
974    <ReflectionBinding as MarkupTyped>::MARKUP,
975    <MultiBinding as MarkupTyped>::MARKUP,
976    <TemplateBinding as MarkupTyped>::MARKUP,
977    <ObjectConverters as MarkupTyped>::MARKUP,
978    <BoolConverters as MarkupTyped>::MARKUP,
979    <StringConverters as MarkupTyped>::MARKUP,
980    <DefaultValueConverter as MarkupTyped>::MARKUP,
981    <StringFormatValueConverter as MarkupTyped>::MARKUP,
982    <StringFormatMultiValueConverter as MarkupTyped>::MARKUP,
983    <KeyFrames as MarkupTyped>::MARKUP,
984    <Transitions as MarkupTyped>::MARKUP,
985    <GestureRecognizerCollection as MarkupTyped>::MARKUP,
986    <GradientStops as MarkupTyped>::MARKUP,
987    <PathFigures as MarkupTyped>::MARKUP,
988    <PathSegments as MarkupTyped>::MARKUP,
989    <Points as MarkupTyped>::MARKUP,
990    <GeometryCollection as MarkupTyped>::MARKUP,
991    <Transforms as MarkupTyped>::MARKUP,
992    <DrawingCollection as MarkupTyped>::MARKUP,
993    <TransformOperations as MarkupTyped>::MARKUP,
994    <crate::media::FontManager as MarkupTyped>::MARKUP,
995    <MediaCollection<f64> as MarkupTyped>::MARKUP,
996    <FerroList<Rc<dyn IAnimationSetter>> as MarkupTyped>::MARKUP,
997    <FerroList<Rc<dyn IResourceProvider>> as MarkupTyped>::MARKUP,
998    <FerroList<Ref<KeyBinding>> as MarkupTyped>::MARKUP,
999    <FerroList<Rc<dyn SetterBase>> as MarkupTyped>::MARKUP,
1000    <FerroList<Rc<dyn IAnimation>> as MarkupTyped>::MARKUP,
1001    <FerroList<Rc<dyn BindingBase>> as MarkupTyped>::MARKUP,
1002    <FerroList<Point> as MarkupTyped>::MARKUP,
1003    <FerroList<String> as MarkupTyped>::MARKUP,
1004    <FerroList<Ref<GradientStop>> as MarkupTyped>::MARKUP,
1005    <FerroList<Rc<dyn ITransition>> as MarkupTyped>::MARKUP,
1006    <FerroList<Ref<KeyFrame>> as MarkupTyped>::MARKUP,
1007    <FerroList<Ref<PathFigure>> as MarkupTyped>::MARKUP,
1008    <FerroList<Ref<PathSegment>> as MarkupTyped>::MARKUP,
1009    <FerroList<Ref<Drawing>> as MarkupTyped>::MARKUP,
1010    <FerroList<Ref<Transform>> as MarkupTyped>::MARKUP,
1011    <FerroList<Ref<Geometry>> as MarkupTyped>::MARKUP,
1012    <FerroList<crate::media::FontFeature> as MarkupTyped>::MARKUP,
1013    <FerroList<Ref<crate::media::TextDecoration>> as MarkupTyped>::MARKUP,
1014    <FerroDictionary<ThemeVariant, Rc<dyn IThemeVariantProvider>> as MarkupTyped>::MARKUP,
1015];
1016
1017/// Registers the nullable forms of the types that can be held in untyped
1018/// values with the untyped value conversions of the current thread.
1019pub(super) fn register_value_types() {
1020    ValueTypes::register_nullable::<&'static TypeInfo>();
1021    ValueTypes::register_nullable::<&'static FerroProperty>();
1022    // The vectors of the element types markup has arrays of (the elements of the runtime
1023    // library and the values the markup compiler parses a list of): a property that holds
1024    // one is null without it (`Option<Vec<T>>`). The run-time XAML loader states the same
1025    // nine when its type system is created; a process that loads compiled markup alone
1026    // never creates one, and reads such a property all the same.
1027    ValueTypes::register_nullable::<Vec<bool>>();
1028    ValueTypes::register_nullable::<Vec<u8>>();
1029    ValueTypes::register_nullable::<Vec<i32>>();
1030    ValueTypes::register_nullable::<Vec<i64>>();
1031    ValueTypes::register_nullable::<Vec<f32>>();
1032    ValueTypes::register_nullable::<Vec<f64>>();
1033    ValueTypes::register_nullable::<Vec<String>>();
1034    ValueTypes::register_nullable::<Vec<Point>>();
1035    ValueTypes::register_nullable::<Vec<BoxedValue>>();
1036    ValueTypes::register_nullable::<Rc<NumberFormatInfo>>();
1037    ValueTypes::register_nullable::<Transitions>();
1038    ValueTypes::register_nullable::<GradientStops>();
1039    ValueTypes::register_nullable::<PathFigures>();
1040    ValueTypes::register_nullable::<PathSegments>();
1041    ValueTypes::register_nullable::<Points>();
1042    ValueTypes::register_nullable::<GeometryCollection>();
1043    ValueTypes::register_nullable::<Transforms>();
1044    ValueTypes::register_nullable::<DrawingCollection>();
1045    ValueTypes::register_nullable::<MediaCollection<f64>>();
1046    ValueTypes::register_nullable::<RoutedEvent>();
1047    ValueTypes::register_nullable::<FerroList<Point>>();
1048    ValueTypes::register_nullable::<FerroList<String>>();
1049    ValueTypes::register_nullable::<FerroList<Ref<GradientStop>>>();
1050    ValueTypes::register_nullable::<FerroList<Rc<dyn ITransition>>>();
1051    ValueTypes::register_nullable::<FerroList<Ref<KeyFrame>>>();
1052    ValueTypes::register_nullable::<FerroList<Ref<PathFigure>>>();
1053    ValueTypes::register_nullable::<FerroList<Ref<PathSegment>>>();
1054    ValueTypes::register_nullable::<FerroList<Ref<Drawing>>>();
1055    ValueTypes::register_nullable::<FerroList<Ref<Transform>>>();
1056    ValueTypes::register_nullable::<FerroList<Ref<Geometry>>>();
1057    ValueTypes::register_nullable::<Selector>();
1058    ValueTypes::register_nullable::<StyleQuery>();
1059    ValueTypes::register_nullable::<StyleChildren>();
1060    ValueTypes::register_nullable::<KeyFrames>();
1061    ValueTypes::register_nullable::<GestureRecognizerCollection>();
1062    ValueTypes::register_nullable::<Rc<Setter>>();
1063    ValueTypes::register_nullable::<Rc<RelativeSource>>();
1064    ValueTypes::register_nullable::<Rc<CompiledBinding>>();
1065    ValueTypes::register_nullable::<Rc<ReflectionBinding>>();
1066    ValueTypes::register_nullable::<Rc<MultiBinding>>();
1067    ValueTypes::register_nullable::<Rc<TemplateBinding>>();
1068    ValueTypes::register_nullable::<FerroDictionary<ThemeVariant, Rc<dyn IThemeVariantProvider>>>();
1069    ValueTypes::register_nullable::<FerroList<Rc<dyn IAnimationSetter>>>();
1070    ValueTypes::register_nullable::<FerroList<Rc<dyn IResourceProvider>>>();
1071    ValueTypes::register_nullable::<FerroList<Ref<KeyBinding>>>();
1072    ValueTypes::register_nullable::<FerroList<Rc<dyn SetterBase>>>();
1073    ValueTypes::register_nullable::<FerroList<Rc<dyn IAnimation>>>();
1074    ValueTypes::register_nullable::<FerroList<Rc<dyn BindingBase>>>();
1075    // A named collection is the list it derives from: the same list, so that the members
1076    // of the list (`Capacity`) are reached through the collection.
1077    ValueTypes::register_cast::<KeyFrames, FerroList<Ref<KeyFrame>>>(|c| (**c).clone());
1078    ValueTypes::register_cast::<Transitions, FerroList<Rc<dyn ITransition>>>(|c| (**c).clone());
1079    ValueTypes::register_cast::<GradientStops, FerroList<Ref<GradientStop>>>(|c| (**c.list()).clone());
1080    ValueTypes::register_cast::<PathFigures, FerroList<Ref<PathFigure>>>(|c| (**c.list()).clone());
1081    ValueTypes::register_cast::<PathSegments, FerroList<Ref<PathSegment>>>(|c| (**c.list()).clone());
1082    ValueTypes::register_cast::<Points, FerroList<Point>>(|c| (**c.list()).clone());
1083    ValueTypes::register_cast::<GeometryCollection, FerroList<Ref<Geometry>>>(|c| (**c.list()).clone());
1084    ValueTypes::register_cast::<Transforms, FerroList<Ref<Transform>>>(|c| (**c.list()).clone());
1085    ValueTypes::register_cast::<DrawingCollection, FerroList<Ref<Drawing>>>(|c| (**c.list()).clone());
1086    ValueTypes::register_cast::<crate::media::FontFeatureCollection, FerroList<crate::media::FontFeature>>(|c| {
1087        (**c.list()).clone()
1088    });
1089    ValueTypes::register_cast::<crate::media::TextDecorationCollection, FerroList<Ref<crate::media::TextDecoration>>>(
1090        |c| (**c.list()).clone(),
1091    );
1092    // The named collections whose Rust type dereferences to the list: generated code
1093    // passes a reference to such a collection where a member of the list takes the list.
1094    ValueTypes::register_deref::<KeyFrames, FerroList<Ref<KeyFrame>>>(|c| c);
1095    ValueTypes::register_deref::<Transitions, FerroList<Rc<dyn ITransition>>>(|c| c);
1096    ValueTypes::register_nullable::<FerroList<crate::media::FontFeature>>();
1097    ValueTypes::register_nullable::<FerroList<Ref<crate::media::TextDecoration>>>();
1098    // A list of transform operations is a transform.
1099    ValueTypes::register_nullable::<Rc<TransformOperations>>();
1100    ValueTypes::register_nullable::<Rc<crate::media::FontManager>>();
1101    ValueTypes::register_cast::<Rc<TransformOperations>, Rc<dyn crate::media::ITransform>>(|operations| operations.clone());
1102    // A converter is a converter contract.
1103    ValueTypes::register_nullable::<Rc<DefaultValueConverter>>();
1104    ValueTypes::register_nullable::<Rc<StringFormatValueConverter>>();
1105    ValueTypes::register_nullable::<Rc<StringFormatMultiValueConverter>>();
1106    ValueTypes::register_cast::<Rc<DefaultValueConverter>, Rc<dyn IValueConverter>>(|c| c.clone());
1107    ValueTypes::register_cast::<Rc<StringFormatValueConverter>, Rc<dyn IValueConverter>>(|c| c.clone());
1108    ValueTypes::register_cast::<Rc<StringFormatMultiValueConverter>, Rc<dyn IMultiValueConverter>>(|c| c.clone());
1109    // A setter is a setter base; a binding is a binding base.
1110    ValueTypes::register_cast::<Rc<Setter>, Rc<dyn SetterBase>>(|setter| setter.clone());
1111    // A setter is also the setter of a key frame.
1112    ValueTypes::register_cast::<Rc<Setter>, Rc<dyn IAnimationSetter>>(|setter| setter.clone());
1113    ValueTypes::register_cast::<Rc<CompiledBinding>, Rc<dyn BindingBase>>(|binding| binding.clone());
1114    ValueTypes::register_cast::<Rc<ReflectionBinding>, Rc<dyn BindingBase>>(|binding| binding.clone());
1115    ValueTypes::register_cast::<Rc<MultiBinding>, Rc<dyn BindingBase>>(|binding| binding.clone());
1116    ValueTypes::register_cast::<Rc<TemplateBinding>, Rc<dyn BindingBase>>(|binding| binding.clone());
1117}