Skip to main content

ferroui_diagnostics/diagnostics/controls/
top_level_group.rs

1//! Port of `Diagnostics/Controls/TopLevelGroup.cs`.
2
3use crate::diagnostics::IDevToolsTopLevelGroup;
4use ferroui_base::collections::NotifyCollectionChangedEventArgs;
5use ferroui_base::reactive::{Disposable, IDisposable};
6use ferroui_base::utilities::HandlerList;
7use ferroui_base::{ferro_class, ferro_class_info, instantiate, FerroObject, FerroObjectImpl, FerroObjectImplExt, Ref};
8use ferroui_controls::TopLevel;
9use std::rc::Rc;
10
11/// The object DevTools shows at the root of its trees for a group of top levels: the top levels
12/// of the group, and the notifications of the top levels that join and leave it.
13#[repr(C)]
14pub struct TopLevelGroup {
15    base: FerroObject,
16    group: Rc<dyn IDevToolsTopLevelGroup>,
17    added: HandlerList<dyn Fn(&Ref<TopLevel>)>,
18    removed: HandlerList<dyn Fn(&Ref<TopLevel>)>,
19}
20
21ferro_class!(TopLevelGroup: FerroObject);
22ferro_class_info!(TopLevelGroup {});
23
24impl FerroObjectImpl for TopLevelGroup {
25    fn constructed(this: &Self) {
26        Self::parent_constructed(this);
27
28        if let Some(incc) = this.group.observable_items() {
29            let weak = this.to_ref().downgrade();
30            incc.add_collection_changed(Rc::new(move |args: &NotifyCollectionChangedEventArgs<'_, Ref<TopLevel>>| {
31                let Some(this) = weak.upgrade() else {
32                    return;
33                };
34
35                for old_item in args.old_items {
36                    for (_, handler) in this.removed.snapshot().iter() {
37                        handler(old_item);
38                    }
39                }
40
41                for new_item in args.new_items {
42                    for (_, handler) in this.added.snapshot().iter() {
43                        handler(new_item);
44                    }
45                }
46            }));
47        }
48    }
49}
50
51impl TopLevelGroup {
52    pub fn construct(group: Rc<dyn IDevToolsTopLevelGroup>) -> Self {
53        Self { base: FerroObject::construct(), group, added: HandlerList::new(), removed: HandlerList::new() }
54    }
55
56    /// C# `new TopLevelGroup(group)`.
57    pub fn new(group: Rc<dyn IDevToolsTopLevelGroup>) -> Ref<Self> {
58        instantiate(Self::construct(group))
59    }
60
61    pub fn group(&self) -> Rc<dyn IDevToolsTopLevelGroup> {
62        self.group.clone()
63    }
64
65    pub fn items(&self) -> Vec<Ref<TopLevel>> {
66        self.group.items()
67    }
68
69    /// Raised when a top level joins the group. Disposing the returned handle unsubscribes.
70    pub fn added(&self, handler: impl Fn(&Ref<TopLevel>) + 'static) -> Rc<dyn IDisposable> {
71        let token = self.added.add(Rc::new(handler));
72        let weak = self.to_ref().downgrade();
73        Disposable::create(move || {
74            if let Some(this) = weak.upgrade() {
75                this.added.remove(token);
76            }
77        })
78    }
79
80    /// Raised when a top level leaves the group. Disposing the returned handle unsubscribes.
81    pub fn removed(&self, handler: impl Fn(&Ref<TopLevel>) + 'static) -> Rc<dyn IDisposable> {
82        let token = self.removed.add(Rc::new(handler));
83        let weak = self.to_ref().downgrade();
84        Disposable::create(move || {
85            if let Some(this) = weak.upgrade() {
86                this.removed.remove(token);
87            }
88        })
89    }
90}