ferroui_base/data/model/
i_notify_collection_changed.rs1use super::Event;
2use crate::collections::{FerroList, NotifyCollectionChangedEventArgs};
3pub use ferroui_system::collections::specialized::{CollectionChange, INotifyCollectionChanged};
4use crate::data::core::ValueType;
5use crate::{BoxedValue, PropertyValue};
6use std::cell::OnceCell;
7use std::rc::Rc;
8
9pub trait IBindableList {
12 fn count(&self) -> usize;
14
15 fn item_type(&self) -> ValueType {
17 ValueType::object()
18 }
19
20 fn get_item(&self, index: usize) -> Option<BoxedValue>;
22
23 fn set_item(&self, index: usize, value: &BoxedValue) -> bool;
26
27 fn as_notify_collection_changed(&self) -> Option<&dyn INotifyCollectionChanged>;
29}
30
31pub struct BindableList<T: PropertyValue> {
36 items: FerroList<T>,
37 changed: Event<CollectionChange>,
38 forwarder: OnceCell<u64>,
39}
40
41impl<T: PropertyValue> BindableList<T> {
42 pub fn new(items: impl IntoIterator<Item = T>) -> Rc<Self> {
44 let this = Rc::new(Self { items: FerroList::from_items(items), changed: Event::new(), forwarder: OnceCell::new() });
45 let weak = Rc::downgrade(&this);
46 let token = this.items.add_collection_changed(Rc::new(move |e: &NotifyCollectionChangedEventArgs<'_, T>| {
47 if let Some(this) = weak.upgrade() {
48 this.changed.raise(&CollectionChange {
49 action: e.action,
50 new_starting_index: e.new_starting_index,
51 new_count: e.new_items.len(),
52 old_starting_index: e.old_starting_index,
53 old_count: e.old_items.len(),
54 });
55 }
56 }));
57 let _ = this.forwarder.set(token);
58 super::ModelTypes::register_list::<Self>();
59 this
60 }
61
62 pub fn items(&self) -> &FerroList<T> {
64 &self.items
65 }
66}
67
68impl<T: PropertyValue> PartialEq for BindableList<T> {
69 fn eq(&self, other: &Self) -> bool {
70 std::ptr::eq(self, other)
71 }
72}
73
74impl<T: PropertyValue> INotifyCollectionChanged for BindableList<T> {
75 fn collection_changed(&self) -> &Event<CollectionChange> {
76 &self.changed
77 }
78}
79
80impl<T: PropertyValue> IBindableList for BindableList<T> {
81 fn count(&self) -> usize {
82 self.items.count()
83 }
84
85 fn item_type(&self) -> ValueType {
86 ValueType::of::<T>()
87 }
88
89 fn get_item(&self, index: usize) -> Option<BoxedValue> {
90 self.items.try_get(index).map(|v| Rc::new(v) as BoxedValue)
91 }
92
93 fn set_item(&self, index: usize, value: &BoxedValue) -> bool {
94 match value.downcast_ref::<T>() {
95 Some(v) if index < self.items.count() => {
96 self.items.set(index, v.clone());
97 true
98 }
99 _ => false,
100 }
101 }
102
103 fn as_notify_collection_changed(&self) -> Option<&dyn INotifyCollectionChanged> {
104 Some(self)
105 }
106}