Skip to main content

ferroui_controls/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 is the handle.
5
6use crate::documents::{Inline, InlineCollection};
7use crate::primitives::popup_positioning::{
8    CustomPopupPlacement, PopupAnchor, PopupGravity, PopupPositionerConstraintAdjustment,
9};
10use crate::primitives::CustomPopupPlacementCallbackValue;
11use crate::templates::{DataTemplates, IDataTemplate};
12use crate::{NativeMenuItemBase, Page, TableViewColumn};
13use ferroui_base::collections::FerroList;
14use crate::{
15    ColumnDefinition, ColumnDefinitions, Control, Controls, ItemCollection, RowDefinition, RowDefinitions, TrayIcon,
16    TrayIcons, WindowIcon,
17};
18use super::classes::RoutedEventOf;
19use crate::ScrollChangedEventArgs;
20use ferroui_base::data::core::ValueTypes;
21use ferroui_base::interactivity::{IRoutedEventArgs, RoutedEvent};
22use ferroui_base::Vector;
23use ferroui_base::ferro_markup_type;
24use ferroui_base::metadata::{MarkupDelegate, MarkupType, MarkupTyped};
25use ferroui_base::{BoxedValue, Point, Rect, Ref, Size, Thickness, Visual};
26use std::cell::RefCell;
27use std::rc::Rc;
28
29/// `FerroList<T>.Capacity`.
30fn list_capacity<T: Clone>(list: &FerroList<T>) -> i32 {
31    i32::try_from(list.capacity()).unwrap_or(i32::MAX)
32}
33
34/// The setter of `FerroList<T>.Capacity`: a capacity below the number of
35/// items is an error, as in the managed original.
36fn set_list_capacity<T: Clone>(list: &FerroList<T>, capacity: i32) -> Result<(), &'static str> {
37    match usize::try_from(capacity) {
38        Ok(capacity) if capacity >= list.count() => Ok(list.set_capacity(capacity)),
39        _ => Err("capacity was less than the current size."),
40    }
41}
42
43// FerroUI.Controls
44
45ferro_markup_type!(class Controls {
46    namespace: "FerroUI.Controls",
47    handles: [Controls, Option<Controls>],
48    base: FerroList<Ref<Control>>,
49    constructors: [() => Controls::new],
50    methods: [fn Add(Ref<Control>) => |controls: &Controls, item: Ref<Control>| controls.add(item)],
51});
52
53ferro_markup_type!(class RowDefinitions {
54    namespace: "FerroUI.Controls",
55    handles: [RowDefinitions, Option<RowDefinitions>],
56    base: FerroList<Ref<RowDefinition>>,
57    parse: RowDefinitions::parse,
58    constructors: [
59        () => RowDefinitions::new,
60        try (String) => |s: String| RowDefinitions::parse(&s),
61    ],
62    methods: [fn Add(Ref<RowDefinition>) => |definitions: &RowDefinitions, item: Ref<RowDefinition>| definitions.add(item)],
63    // Declared on the base class of the definition lists in the managed original.
64    attributes: [FerroList(Separators = [",", " "])],
65});
66
67ferro_markup_type!(class ColumnDefinitions {
68    namespace: "FerroUI.Controls",
69    handles: [ColumnDefinitions, Option<ColumnDefinitions>],
70    base: FerroList<Ref<ColumnDefinition>>,
71    parse: ColumnDefinitions::parse,
72    constructors: [
73        () => ColumnDefinitions::new,
74        try (String) => |s: String| ColumnDefinitions::parse(&s),
75    ],
76    methods: [
77        fn Add(Ref<ColumnDefinition>) =>
78            |definitions: &ColumnDefinitions, item: Ref<ColumnDefinition>| definitions.add(item),
79    ],
80    // Declared on the base class of the definition lists in the managed original.
81    attributes: [FerroList(Separators = [",", " "])],
82});
83
84ferro_markup_type!(class ItemCollection {
85    namespace: "FerroUI.Controls",
86    handles: [ItemCollection, Option<ItemCollection>],
87    methods: [fn Add(Option<BoxedValue>) -> i32 => |items: &ItemCollection, item: Option<BoxedValue>| items.add(item)],
88});
89
90// The tray icons of an application (the value of `TrayIcon.Icons`).
91ferro_markup_type!(class TrayIcons {
92    namespace: "FerroUI.Controls",
93    handles: [Rc<TrayIcons>, Option<Rc<TrayIcons>>],
94    this: Rc<TrayIcons>,
95    base: FerroList<Ref<TrayIcon>>,
96    constructors: [() => TrayIcons::new],
97    methods: [fn Add(Ref<TrayIcon>) => |icons: &Rc<TrayIcons>, item: Ref<TrayIcon>| icons.add(item)],
98});
99
100ferro_markup_type!(class WindowIcon {
101    namespace: "FerroUI.Controls",
102    handles: [Rc<WindowIcon>, Option<Rc<WindowIcon>>],
103});
104
105// FerroUI.Controls.Documents
106
107ferro_markup_type!(class InlineCollection {
108    namespace: "FerroUI.Controls.Documents",
109    handles: [InlineCollection, Option<InlineCollection>],
110    base: FerroList<Ref<Inline>>,
111    constructors: [() => InlineCollection::new],
112    methods: [
113        fn Add(Ref<Inline>) => |inlines: &InlineCollection, inline: Ref<Inline>| inlines.add(inline),
114        fn Add(String) => |inlines: &InlineCollection, text: String| inlines.add_text(&text),
115        fn Add(Ref<Control>) => |inlines: &InlineCollection, control: Ref<Control>| inlines.add_control(control),
116    ],
117    attributes: [WhitespaceSignificantCollection],
118});
119
120// FerroUI.Controls.Templates
121
122ferro_markup_type!(class DataTemplates {
123    namespace: "FerroUI.Controls.Templates",
124    handles: [DataTemplates, Option<DataTemplates>],
125    base: FerroList<Rc<dyn IDataTemplate>>,
126    constructors: [() => DataTemplates::new],
127    methods: [
128        // A typed template without a data type is an error, as in the managed original.
129        try fn Add(Rc<dyn IDataTemplate>) => |templates: &DataTemplates, item: Rc<dyn IDataTemplate>| {
130            if item.as_typed_data_template().is_some_and(|typed| typed.data_type().is_none()) {
131                return Err(
132                    "DataTemplate inside of DataTemplates must have a DataType set. Set DataType property or use \
133                     ItemTemplate with single template instead.",
134                );
135            }
136            Ok(templates.add(item))
137        },
138    ],
139});
140
141// FerroUI.Controls.Primitives.PopupPositioning
142
143// The parameters of a custom placement as a method named in markup receives them: one shared
144// object, which the method changes (the record of the managed original is a reference type).
145ferro_markup_type!(class CustomPopupPlacement {
146    namespace: "FerroUI.Controls.Primitives.PopupPositioning",
147    handles: [Rc<RefCell<CustomPopupPlacement>>, Option<Rc<RefCell<CustomPopupPlacement>>>],
148    this: Rc<RefCell<CustomPopupPlacement>>,
149    properties: [
150        PopupSize: Size { get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().popup_size() },
151        Deflate: Thickness { get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().deflate() },
152        Target: Ref<Visual> { get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().target() },
153        AnchorRectangle: Rect {
154            get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().anchor_rectangle,
155            set: |placement: &Rc<RefCell<CustomPopupPlacement>>, value: Rect| placement.borrow_mut().anchor_rectangle = value
156        },
157        Anchor: PopupAnchor {
158            get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().anchor(),
159            set: |placement: &Rc<RefCell<CustomPopupPlacement>>, value: PopupAnchor| placement.borrow_mut().set_anchor(value)
160        },
161        Gravity: PopupGravity {
162            get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().gravity(),
163            set: |placement: &Rc<RefCell<CustomPopupPlacement>>, value: PopupGravity| placement.borrow_mut().set_gravity(value)
164        },
165        ConstraintAdjustment: PopupPositionerConstraintAdjustment {
166            get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().constraint_adjustment,
167            set: |placement: &Rc<RefCell<CustomPopupPlacement>>, value: PopupPositionerConstraintAdjustment| {
168                placement.borrow_mut().constraint_adjustment = value
169            }
170        },
171        Offset: Point {
172            get: |placement: &Rc<RefCell<CustomPopupPlacement>>| placement.borrow().offset,
173            set: |placement: &Rc<RefCell<CustomPopupPlacement>>, value: Point| placement.borrow_mut().offset = value
174        },
175    ],
176});
177
178// The delegate type of the `CustomPopupPlacementCallback` properties: a delegate with one
179// `Invoke` method, so that markup accepts the name of a method of the root object with that
180// signature as the value of such a property.
181ferro_markup_type!(class CustomPopupPlacementCallbackValue as "CustomPopupPlacementCallback" {
182    namespace: "FerroUI.Controls.Primitives.PopupPositioning",
183    handles: [CustomPopupPlacementCallbackValue, Option<CustomPopupPlacementCallbackValue>],
184    base: MarkupDelegate,
185    methods: [
186        fn Invoke(Rc<RefCell<CustomPopupPlacement>>) =>
187            |callback: &CustomPopupPlacementCallbackValue, placement: Rc<RefCell<CustomPopupPlacement>>| {
188                (callback.0)(&mut placement.borrow_mut())
189            },
190    ],
191});
192
193/// The callback that calls a method named in markup: the method receives the parameters as
194/// one shared object, and what it leaves in them is the placement.
195fn custom_popup_placement_callback(method: &MarkupDelegate) -> CustomPopupPlacementCallbackValue {
196    let method = method.clone();
197    CustomPopupPlacementCallbackValue(Rc::new(move |placement: &mut CustomPopupPlacement| {
198        let shared = Rc::new(RefCell::new(placement.clone()));
199        method.invoke(&[Some(Rc::new(shared.clone()) as BoxedValue)]);
200        *placement = shared.borrow().clone();
201    }))
202}
203
204// FerroUI.Collections
205
206/// Carries the metadata of the notifying list of items of this crate (the
207/// list type belongs to the base crate).
208#[doc(hidden)]
209pub struct FerroListOf<T>(std::marker::PhantomData<T>);
210
211// The lists the named collections of this crate derive from.
212
213ferro_markup_type!(class FerroListOf<Ref<Control>> as "FerroList`1" {
214    namespace: "FerroUI.Collections",
215    handles: [FerroList<Ref<Control>>, Option<FerroList<Ref<Control>>>],
216    this: FerroList<Ref<Control>>,
217    generic: "FerroList`1" [Ref<Control>],
218    constructors: [() => FerroList::<Ref<Control>>::new],
219    properties: [
220        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
221        Count: i32 { get: |list: &FerroList<Ref<Control>>| list.count() as i32 },
222    ],
223    methods: [fn Add(Ref<Control>) => |list: &FerroList<Ref<Control>>, item: Ref<Control>| list.add(item)],
224});
225
226ferro_markup_type!(class FerroListOf<Ref<Inline>> as "FerroList`1" {
227    namespace: "FerroUI.Collections",
228    handles: [FerroList<Ref<Inline>>, Option<FerroList<Ref<Inline>>>],
229    this: FerroList<Ref<Inline>>,
230    generic: "FerroList`1" [Ref<Inline>],
231    constructors: [() => FerroList::<Ref<Inline>>::new],
232    properties: [
233        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
234        Count: i32 { get: |list: &FerroList<Ref<Inline>>| list.count() as i32 },
235    ],
236    methods: [fn Add(Ref<Inline>) => |list: &FerroList<Ref<Inline>>, item: Ref<Inline>| list.add(item)],
237});
238
239ferro_markup_type!(class FerroListOf<Rc<dyn IDataTemplate>> as "FerroList`1" {
240    namespace: "FerroUI.Collections",
241    handles: [FerroList<Rc<dyn IDataTemplate>>, Option<FerroList<Rc<dyn IDataTemplate>>>],
242    this: FerroList<Rc<dyn IDataTemplate>>,
243    generic: "FerroList`1" [Rc<dyn IDataTemplate>],
244    constructors: [() => FerroList::<Rc<dyn IDataTemplate>>::new],
245    properties: [
246        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
247        Count: i32 { get: |list: &FerroList<Rc<dyn IDataTemplate>>| list.count() as i32 },
248    ],
249    methods: [fn Add(Rc<dyn IDataTemplate>) => |list: &FerroList<Rc<dyn IDataTemplate>>, item: Rc<dyn IDataTemplate>| list.add(item)],
250});
251
252ferro_markup_type!(class FerroListOf<Ref<RowDefinition>> as "FerroList`1" {
253    namespace: "FerroUI.Collections",
254    handles: [FerroList<Ref<RowDefinition>>, Option<FerroList<Ref<RowDefinition>>>],
255    this: FerroList<Ref<RowDefinition>>,
256    generic: "FerroList`1" [Ref<RowDefinition>],
257    constructors: [() => FerroList::<Ref<RowDefinition>>::new],
258    properties: [
259        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
260        Count: i32 { get: |list: &FerroList<Ref<RowDefinition>>| list.count() as i32 },
261    ],
262    methods: [fn Add(Ref<RowDefinition>) => |list: &FerroList<Ref<RowDefinition>>, item: Ref<RowDefinition>| list.add(item)],
263});
264
265ferro_markup_type!(class FerroListOf<Ref<ColumnDefinition>> as "FerroList`1" {
266    namespace: "FerroUI.Collections",
267    handles: [FerroList<Ref<ColumnDefinition>>, Option<FerroList<Ref<ColumnDefinition>>>],
268    this: FerroList<Ref<ColumnDefinition>>,
269    generic: "FerroList`1" [Ref<ColumnDefinition>],
270    constructors: [() => FerroList::<Ref<ColumnDefinition>>::new],
271    properties: [
272        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
273        Count: i32 { get: |list: &FerroList<Ref<ColumnDefinition>>| list.count() as i32 },
274    ],
275    methods: [fn Add(Ref<ColumnDefinition>) => |list: &FerroList<Ref<ColumnDefinition>>, item: Ref<ColumnDefinition>| list.add(item)],
276});
277
278ferro_markup_type!(class FerroListOf<Ref<TrayIcon>> as "FerroList`1" {
279    namespace: "FerroUI.Collections",
280    handles: [FerroList<Ref<TrayIcon>>, Option<FerroList<Ref<TrayIcon>>>],
281    this: FerroList<Ref<TrayIcon>>,
282    generic: "FerroList`1" [Ref<TrayIcon>],
283    constructors: [() => FerroList::<Ref<TrayIcon>>::new],
284    properties: [
285        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
286        Count: i32 { get: |list: &FerroList<Ref<TrayIcon>>| list.count() as i32 },
287    ],
288    methods: [fn Add(Ref<TrayIcon>) => |list: &FerroList<Ref<TrayIcon>>, item: Ref<TrayIcon>| list.add(item)],
289});
290
291// The commands of a command bar.
292ferro_markup_type!(interface dyn crate::ICommandBarElement as "ICommandBarElement" {
293    namespace: "FerroUI.Controls",
294    handles: [Rc<dyn crate::ICommandBarElement>, Option<Rc<dyn crate::ICommandBarElement>>],
295});
296
297ferro_markup_type!(class FerroListOf<Rc<dyn crate::ICommandBarElement>> as "FerroList`1" {
298    namespace: "FerroUI.Collections",
299    handles: [FerroList<Rc<dyn crate::ICommandBarElement>>, Option<FerroList<Rc<dyn crate::ICommandBarElement>>>],
300    this: FerroList<Rc<dyn crate::ICommandBarElement>>,
301    generic: "FerroList`1" [Rc<dyn crate::ICommandBarElement>],
302    constructors: [() => FerroList::<Rc<dyn crate::ICommandBarElement>>::new],
303    properties: [
304        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
305        Count: i32 { get: |list: &FerroList<Rc<dyn crate::ICommandBarElement>>| list.count() as i32 },
306    ],
307    methods: [
308        fn Add(Rc<dyn crate::ICommandBarElement>) =>
309            |list: &FerroList<Rc<dyn crate::ICommandBarElement>>, item: Rc<dyn crate::ICommandBarElement>| list.add(item),
310    ],
311});
312
313// The items of a native menu.
314ferro_markup_type!(class FerroListOf<Ref<NativeMenuItemBase>> as "FerroList`1" {
315    namespace: "FerroUI.Collections",
316    handles: [FerroList<Ref<NativeMenuItemBase>>, Option<FerroList<Ref<NativeMenuItemBase>>>],
317    this: FerroList<Ref<NativeMenuItemBase>>,
318    generic: "FerroList`1" [Ref<NativeMenuItemBase>],
319    constructors: [() => FerroList::<Ref<NativeMenuItemBase>>::new],
320    properties: [
321        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
322        Count: i32 { get: |list: &FerroList<Ref<NativeMenuItemBase>>| list.count() as i32 },
323    ],
324    methods: [
325        fn Add(Ref<NativeMenuItemBase>) =>
326            |list: &FerroList<Ref<NativeMenuItemBase>>, item: Ref<NativeMenuItemBase>| list.add(item),
327    ],
328});
329
330// The pages of a multi page (`MultiPage.Pages`).
331ferro_markup_type!(class FerroListOf<Ref<Page>> as "FerroList`1" {
332    namespace: "FerroUI.Collections",
333    handles: [FerroList<Ref<Page>>, Option<FerroList<Ref<Page>>>],
334    this: FerroList<Ref<Page>>,
335    generic: "FerroList`1" [Ref<Page>],
336    constructors: [() => FerroList::<Ref<Page>>::new],
337    properties: [
338        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
339        Count: i32 { get: |list: &FerroList<Ref<Page>>| list.count() as i32 },
340    ],
341    methods: [fn Add(Ref<Page>) => |list: &FerroList<Ref<Page>>, item: Ref<Page>| list.add(item)],
342});
343
344// The columns of a table view (`TableView.Columns`).
345ferro_markup_type!(class FerroListOf<Ref<TableViewColumn>> as "FerroList`1" {
346    namespace: "FerroUI.Collections",
347    handles: [FerroList<Ref<TableViewColumn>>, Option<FerroList<Ref<TableViewColumn>>>],
348    this: FerroList<Ref<TableViewColumn>>,
349    generic: "FerroList`1" [Ref<TableViewColumn>],
350    constructors: [() => FerroList::<Ref<TableViewColumn>>::new],
351    properties: [
352        Capacity: i32 { get: list_capacity, try_set: set_list_capacity },
353        Count: i32 { get: |list: &FerroList<Ref<TableViewColumn>>| list.count() as i32 },
354    ],
355    methods: [fn Add(Ref<TableViewColumn>) => |list: &FerroList<Ref<TableViewColumn>>, item: Ref<TableViewColumn>| list.add(item)],
356});
357
358// The arguments of `ScrollViewer.ScrollChanged` and the type of its routed event. `classes.rs`
359// declares the arguments of the routed events of the classes whose `markup:` part it generates;
360// the scroll viewer declares its part in its own file (with its public methods), so the two
361// declarations its event needs are written here.
362
363ferro_markup_type!(class RoutedEventOf<ScrollChangedEventArgs> as "RoutedEvent`1" {
364    namespace: "FerroUI.Interactivity",
365    handles: [RoutedEvent<ScrollChangedEventArgs>, Option<RoutedEvent<ScrollChangedEventArgs>>],
366    base: RoutedEvent,
367    generic: "RoutedEvent`1" [ScrollChangedEventArgs],
368});
369
370/// The arguments of a routed event as the arguments of `ScrollChanged`.
371fn scroll_changed_event_args<R>(
372    e: &Rc<dyn IRoutedEventArgs>,
373    f: impl FnOnce(&ScrollChangedEventArgs) -> R,
374) -> Result<R, String> {
375    match e
376        .query_args(std::any::TypeId::of::<ScrollChangedEventArgs>())
377        .and_then(|args| args.downcast_ref::<ScrollChangedEventArgs>())
378    {
379        Some(args) => Ok(f(args)),
380        None => Err(format!("The arguments are not {}.", std::any::type_name::<ScrollChangedEventArgs>())),
381    }
382}
383
384ferro_markup_type!(class ScrollChangedEventArgs {
385    namespace: "FerroUI.Controls",
386    handles: [ScrollChangedEventArgs],
387    this: Rc<dyn IRoutedEventArgs>,
388    base: Rc<dyn IRoutedEventArgs>,
389    properties: [
390        ExtentDelta: Vector {
391            try_get: |e: &Rc<dyn IRoutedEventArgs>| scroll_changed_event_args(e, |e| e.extent_delta())
392        },
393        OffsetDelta: Vector {
394            try_get: |e: &Rc<dyn IRoutedEventArgs>| scroll_changed_event_args(e, |e| e.offset_delta())
395        },
396        ViewportDelta: Vector {
397            try_get: |e: &Rc<dyn IRoutedEventArgs>| scroll_changed_event_args(e, |e| e.viewport_delta())
398        },
399    ],
400});
401
402/// The types declared in this file.
403pub(super) const TYPES: &[&MarkupType] = &[
404    <RoutedEventOf<ScrollChangedEventArgs> as MarkupTyped>::MARKUP,
405    <ScrollChangedEventArgs as MarkupTyped>::MARKUP,
406    <dyn crate::ICommandBarElement as MarkupTyped>::MARKUP,
407    <FerroListOf<Rc<dyn crate::ICommandBarElement>> as MarkupTyped>::MARKUP,
408    <Controls as MarkupTyped>::MARKUP,
409    <RowDefinitions as MarkupTyped>::MARKUP,
410    <ColumnDefinitions as MarkupTyped>::MARKUP,
411    <ItemCollection as MarkupTyped>::MARKUP,
412    <TrayIcons as MarkupTyped>::MARKUP,
413    <FerroListOf<Ref<TrayIcon>> as MarkupTyped>::MARKUP,
414    <WindowIcon as MarkupTyped>::MARKUP,
415    <InlineCollection as MarkupTyped>::MARKUP,
416    <DataTemplates as MarkupTyped>::MARKUP,
417    <CustomPopupPlacement as MarkupTyped>::MARKUP,
418    <CustomPopupPlacementCallbackValue as MarkupTyped>::MARKUP,
419    <FerroListOf<Ref<Control>> as MarkupTyped>::MARKUP,
420    <FerroListOf<Ref<Inline>> as MarkupTyped>::MARKUP,
421    <FerroListOf<Rc<dyn IDataTemplate>> as MarkupTyped>::MARKUP,
422    <FerroListOf<Ref<RowDefinition>> as MarkupTyped>::MARKUP,
423    <FerroListOf<Ref<ColumnDefinition>> as MarkupTyped>::MARKUP,
424    <FerroListOf<Ref<NativeMenuItemBase>> as MarkupTyped>::MARKUP,
425    <FerroListOf<Ref<Page>> as MarkupTyped>::MARKUP,
426    <FerroListOf<Ref<TableViewColumn>> as MarkupTyped>::MARKUP,
427];
428
429/// Registers the nullable forms of the types that can be held in untyped
430/// values with the untyped value conversions of the current thread.
431pub(super) fn register_value_types() {
432    ValueTypes::register_cast::<RoutedEvent<ScrollChangedEventArgs>, RoutedEvent>(|event| event.as_routed_event());
433    ValueTypes::register_nullable::<Rc<dyn crate::ICommandBarElement>>();
434    ValueTypes::register_nullable::<FerroList<Rc<dyn crate::ICommandBarElement>>>();
435    ValueTypes::register_nullable::<Controls>();
436    ValueTypes::register_nullable::<RowDefinitions>();
437    ValueTypes::register_nullable::<ColumnDefinitions>();
438    ValueTypes::register_nullable::<ItemCollection>();
439    ValueTypes::register_nullable::<InlineCollection>();
440    ValueTypes::register_nullable::<DataTemplates>();
441    ValueTypes::register_nullable::<FerroList<Ref<Control>>>();
442    ValueTypes::register_nullable::<FerroList<Ref<Inline>>>();
443    ValueTypes::register_nullable::<FerroList<Rc<dyn IDataTemplate>>>();
444    ValueTypes::register_nullable::<FerroList<Ref<RowDefinition>>>();
445    ValueTypes::register_nullable::<FerroList<Ref<ColumnDefinition>>>();
446    ValueTypes::register_nullable::<FerroList<Ref<NativeMenuItemBase>>>();
447    ValueTypes::register_nullable::<FerroList<Ref<Page>>>();
448    ValueTypes::register_nullable::<FerroList<Ref<TableViewColumn>>>();
449    ValueTypes::register_nullable::<Rc<WindowIcon>>();
450    ValueTypes::register_nullable::<Rc<RefCell<CustomPopupPlacement>>>();
451    ValueTypes::register_nullable::<CustomPopupPlacementCallbackValue>();
452    // The delegate of a method named in markup is a callback: the value of a
453    // `CustomPopupPlacementCallback` property.
454    ValueTypes::register_cast::<MarkupDelegate, CustomPopupPlacementCallbackValue>(custom_popup_placement_callback);
455    // A named collection is the list it derives from: the same list, so that the members
456    // of the list (`Capacity`) are reached through the collection.
457    // The collection handles of items controls: a property that holds one takes the handle
458    // (and null) from an untyped value, and a binding delivers a handle to it.
459    ValueTypes::register_nullable::<crate::ItemsSource>();
460    ValueTypes::register_nullable::<crate::primitives::SelectedItemsList>();
461    crate::ItemsSource::register_binding_conversion::<crate::ItemsSource>();
462    // A font collection is a read-only list of font families (`IReadOnlyList<FontFamily>` in
463    // the managed original), which a binding delivers to an items source
464    // (`{Binding SystemFonts, Source={x:Static FontManager.Current}}`): the items are the
465    // font families of the collection.
466    crate::ItemsSource::register_binding_conversion_with::<Rc<dyn ferroui_base::media::fonts::IFontCollection>>(|fonts| {
467        crate::ItemsSource::from_values(fonts.font_families())
468    });
469    // A list of untyped items is an enumerable (a list of the runtime library the run-time
470    // loader creates for markup, `List<T>` or `ArrayList`): the handle shares the list.
471    ValueTypes::register_cast::<Rc<FerroList<Option<BoxedValue>>>, crate::ItemsSource>(|list| {
472        crate::ItemsSource::from(list.clone())
473    });
474    // A vector of untyped values is an enumerable too (the errors of a control, an
475    // `IEnumerable<object>` in the managed original, which the template of the errors binds
476    // to the items of an items control): the handle holds the items of the vector. The
477    // conversions are what a binding delivers the vector with, to the handle and to its
478    // nullable form.
479    ValueTypes::register_cast::<Vec<BoxedValue>, crate::ItemsSource>(|items| crate::ItemsSource::from(items.clone()));
480    ValueTypes::register_conversion::<Vec<BoxedValue>, Option<crate::ItemsSource>>(|items| {
481        Some(Some(crate::ItemsSource::from(items.clone())))
482    });
483    ValueTypes::register_cast::<Vec<Option<BoxedValue>>, crate::ItemsSource>(|items| {
484        crate::ItemsSource::from(items.clone())
485    });
486    ValueTypes::register_conversion::<Vec<Option<BoxedValue>>, Option<crate::ItemsSource>>(|items| {
487        Some(Some(crate::ItemsSource::from(items.clone())))
488    });
489    ValueTypes::register_nullable::<Rc<TrayIcons>>();
490    ValueTypes::register_nullable::<FerroList<Ref<TrayIcon>>>();
491    ValueTypes::register_cast::<Rc<TrayIcons>, FerroList<Ref<TrayIcon>>>(|c| (***c).clone());
492    ValueTypes::register_cast::<Controls, FerroList<Ref<Control>>>(|c| (**c).clone());
493    ValueTypes::register_cast::<InlineCollection, FerroList<Ref<Inline>>>(|c| (**c).clone());
494    ValueTypes::register_cast::<DataTemplates, FerroList<Rc<dyn IDataTemplate>>>(|c| (**c).clone());
495    ValueTypes::register_cast::<RowDefinitions, FerroList<Ref<RowDefinition>>>(|c| (***c).clone());
496    ValueTypes::register_cast::<ColumnDefinitions, FerroList<Ref<ColumnDefinition>>>(|c| (***c).clone());
497    // The named collections whose Rust type dereferences to the list: generated code
498    // passes a reference to such a collection where a member of the list takes the list.
499    ValueTypes::register_deref::<Controls, FerroList<Ref<Control>>>(|c| c);
500    ValueTypes::register_deref::<InlineCollection, FerroList<Ref<Inline>>>(|c| c);
501    ValueTypes::register_deref::<DataTemplates, FerroList<Rc<dyn IDataTemplate>>>(|c| c);
502    ValueTypes::register_deref::<RowDefinitions, FerroList<Ref<RowDefinition>>>(|c| c);
503    ValueTypes::register_deref::<ColumnDefinitions, FerroList<Ref<ColumnDefinition>>>(|c| c);
504}