Skip to main content

ferroui_xaml_interactivity/collections/
action_collection.rs

1//! Port of `Collections/ActionCollection.cs`.
2
3use crate::IAction;
4use ferroui_base::collections::{FerroList, NotifyCollectionChangedAction, NotifyCollectionChangedEventArgs, WeakFerroList};
5use ferroui_base::utilities::WeakEventSender;
6use ferroui_base::{FerroObject, Ref};
7use std::ops::Deref;
8use std::rc::Rc;
9
10/// Represents a collection of [`IAction`]s.
11///
12/// The collection is a notifying list of objects (`FerroList<FerroObject>`); every item must be
13/// an action. It is a reference object: clones refer to the same collection and compare by
14/// identity.
15#[derive(Clone, PartialEq)]
16pub struct ActionCollection(FerroList<Ref<FerroObject>>);
17
18impl ActionCollection {
19    /// Initializes a new instance of the [`ActionCollection`] class.
20    pub fn new() -> Self {
21        let list: FerroList<Ref<FerroObject>> = FerroList::new();
22        let weak = list.downgrade_sender();
23        list.add_collection_changed(Rc::new(move |e: &NotifyCollectionChangedEventArgs<'_, Ref<FerroObject>>| {
24            Self::action_collection_collection_changed(&weak, e);
25        }));
26        Self(list)
27    }
28
29    /// The list of the collection.
30    pub fn list(&self) -> &FerroList<Ref<FerroObject>> {
31        &self.0
32    }
33
34    fn action_collection_collection_changed(
35        this: &WeakFerroList<Ref<FerroObject>>,
36        event_args: &NotifyCollectionChangedEventArgs<'_, Ref<FerroObject>>,
37    ) {
38        match event_args.action {
39            NotifyCollectionChangedAction::Reset => {
40                if let Some(this) = <FerroList<Ref<FerroObject>> as WeakEventSender>::upgrade_sender(this) {
41                    for item in this.snapshot().iter() {
42                        Self::verify_type(Some(item));
43                    }
44                }
45            }
46            NotifyCollectionChangedAction::Add | NotifyCollectionChangedAction::Replace => {
47                let changed_item = event_args.new_items.first();
48                Self::verify_type(changed_item);
49            }
50            _ => {}
51        }
52    }
53
54    fn verify_type(item: Option<&Ref<FerroObject>>) {
55        let Some(item) = item else {
56            return;
57        };
58
59        if <dyn IAction>::of(item).is_none() {
60            panic!("Only IAction types are supported in an ActionCollection.");
61        }
62    }
63}
64
65impl Default for ActionCollection {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71impl Deref for ActionCollection {
72    type Target = FerroList<Ref<FerroObject>>;
73
74    fn deref(&self) -> &FerroList<Ref<FerroObject>> {
75        &self.0
76    }
77}
78
79impl std::fmt::Debug for ActionCollection {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        write!(f, "ActionCollection({})", self.0.count())
82    }
83}