ferroui_controls/
items_source_view.rs1use crate::items_source::{unbox_item, ItemsChangedEventArgs, ItemsChangedHandler, ItemsSource};
5use crate::utils::{CollectionChangedEventManager, ICollectionChangedListener};
6use ferroui_base::utilities::HandlerList;
7use ferroui_base::{BoxedValue, PropertyValue};
8use std::cell::{Cell, RefCell};
9use std::marker::PhantomData;
10use std::ops::Deref;
11use std::rc::{Rc, Weak};
12
13ferroui_base::ferro_thread_local! {
14 static EMPTY: Rc<ItemsSourceView> = ItemsSourceView::new(ItemsSource::from_items([]));
15 static UNINITIALIZED_SOURCE: ItemsSource = ItemsSource::from_items([]);
17}
18
19pub struct ItemsSourceView {
22 this: Weak<ItemsSourceView>,
23 source: RefCell<ItemsSource>,
24 collection_changed: HandlerList<ItemsChangedHandler>,
25 pre_collection_changed: HandlerList<ItemsChangedHandler>,
26 post_collection_changed: HandlerList<ItemsChangedHandler>,
27 listening: Cell<bool>,
28}
29
30impl ItemsSourceView {
31 pub fn empty() -> Rc<ItemsSourceView> {
33 EMPTY.with(Rc::clone)
34 }
35
36 pub(crate) fn uninitialized_source() -> ItemsSource {
38 UNINITIALIZED_SOURCE.with(Clone::clone)
39 }
40
41 pub(crate) fn new(source: ItemsSource) -> Rc<Self> {
43 Rc::new_cyclic(|this| Self {
44 this: this.clone(),
45 source: RefCell::new(source),
46 collection_changed: HandlerList::new(),
47 pre_collection_changed: HandlerList::new(),
48 post_collection_changed: HandlerList::new(),
49 listening: Cell::new(false),
50 })
51 }
52
53 #[inline]
55 pub fn count(&self) -> usize {
56 self.source.borrow().count()
57 }
58
59 #[inline]
61 pub fn source(&self) -> ItemsSource {
62 self.source.borrow().clone()
63 }
64
65 pub(crate) fn try_get_initialized_source(&self) -> Option<ItemsSource> {
66 let source = self.source();
67 if source.ptr_eq(&Self::uninitialized_source()) {
68 None
69 } else {
70 Some(source)
71 }
72 }
73
74 pub fn add_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> u64 {
78 self.add_listener_if_necessary();
79 self.collection_changed.add(handler)
80 }
81
82 pub fn remove_collection_changed(&self, token: u64) {
83 self.collection_changed.remove(token);
84 self.remove_listener_if_necessary();
85 }
86
87 pub(crate) fn add_pre_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> u64 {
90 self.add_listener_if_necessary();
91 self.pre_collection_changed.add(handler)
92 }
93
94 pub(crate) fn remove_pre_collection_changed(&self, token: u64) {
95 self.pre_collection_changed.remove(token);
96 self.remove_listener_if_necessary();
97 }
98
99 pub(crate) fn add_post_collection_changed(&self, handler: Rc<ItemsChangedHandler>) -> u64 {
103 self.add_listener_if_necessary();
104 self.post_collection_changed.add(handler)
105 }
106
107 pub(crate) fn remove_post_collection_changed(&self, token: u64) {
108 self.post_collection_changed.remove(token);
109 self.remove_listener_if_necessary();
110 }
111
112 #[inline]
114 pub fn get_at(&self, index: usize) -> Option<BoxedValue> {
115 let source = self.source.borrow().clone();
116 source.get_at(index)
117 }
118
119 pub fn contains(&self, item: &Option<BoxedValue>) -> bool {
121 self.index_of(item) >= 0
122 }
123
124 pub fn index_of(&self, item: &Option<BoxedValue>) -> i32 {
126 let source = self.source.borrow().clone();
127 source.index_of(item)
128 }
129
130 pub fn get_or_create(items: Option<&ItemsSource>) -> Rc<ItemsSourceView> {
135 match items {
136 None => Self::empty(),
137 Some(items) => Self::new(items.clone()),
138 }
139 }
140
141 pub fn get_or_create_of<T: PropertyValue>(items: Option<&ItemsSource>) -> ItemsSourceViewOf<T> {
143 match items {
144 None => ItemsSourceViewOf::empty(),
145 Some(items) => ItemsSourceViewOf::new(items.clone()),
146 }
147 }
148
149 pub fn iter(&self) -> impl Iterator<Item = Option<BoxedValue>> {
151 let source = self.source();
152 let mut index = 0;
153 std::iter::from_fn(move || {
154 if index < source.count() {
155 index += 1;
156 Some(source.get_at(index - 1))
157 } else {
158 None
159 }
160 })
161 }
162
163 pub fn to_vec(&self) -> Vec<Option<BoxedValue>> {
165 self.source().to_vec()
166 }
167
168 pub(crate) fn raise_collection_changed(&self, e: &ItemsChangedEventArgs<'_>) {
169 Self::invoke(&self.pre_collection_changed, e);
170 Self::invoke(&self.collection_changed, e);
171 Self::invoke(&self.post_collection_changed, e);
172 }
173
174 pub(crate) fn set_source(&self, source: ItemsSource) {
175 let listener: Weak<dyn ICollectionChangedListener> = self.this.clone();
176
177 if self.listening.get() {
178 let old = self.source();
179 if old.is_notifying() {
180 CollectionChangedEventManager::remove_listener(&old, &listener);
181 }
182 }
183
184 *self.source.borrow_mut() = source.clone();
185
186 if self.listening.get() && source.is_notifying() {
187 CollectionChangedEventManager::add_listener(&source, listener);
188 }
189 }
190
191 fn add_listener_if_necessary(&self) {
192 if !self.listening.get() {
193 let source = self.source();
194 if source.is_notifying() {
195 CollectionChangedEventManager::add_listener(&source, self.this.clone());
196 }
197 self.listening.set(true);
198 }
199 }
200
201 fn remove_listener_if_necessary(&self) {
202 if self.listening.get() && self.collection_changed.is_empty() && self.post_collection_changed.is_empty() {
203 let source = self.source();
204 if source.is_notifying() {
205 let listener: Weak<dyn ICollectionChangedListener> = self.this.clone();
206 CollectionChangedEventManager::remove_listener(&source, &listener);
207 }
208 self.listening.set(false);
209 }
210 }
211
212 #[inline]
213 fn invoke(handlers: &HandlerList<ItemsChangedHandler>, e: &ItemsChangedEventArgs<'_>) {
214 if !handlers.is_empty() {
215 for (_, handler) in handlers.snapshot().iter() {
216 handler(e);
217 }
218 }
219 }
220}
221
222impl ICollectionChangedListener for ItemsSourceView {
223 fn pre_changed(&self, e: &ItemsChangedEventArgs<'_>) {
224 Self::invoke(&self.pre_collection_changed, e);
225 }
226
227 fn changed(&self, e: &ItemsChangedEventArgs<'_>) {
228 Self::invoke(&self.collection_changed, e);
229 }
230
231 fn post_changed(&self, e: &ItemsChangedEventArgs<'_>) {
232 Self::invoke(&self.post_collection_changed, e);
233 }
234}
235
236pub struct ItemsSourceViewOf<T: PropertyValue> {
240 view: Rc<ItemsSourceView>,
241 marker: PhantomData<fn() -> T>,
242}
243
244impl<T: PropertyValue> Clone for ItemsSourceViewOf<T> {
245 fn clone(&self) -> Self {
246 Self { view: self.view.clone(), marker: PhantomData }
247 }
248}
249
250impl<T: PropertyValue> Deref for ItemsSourceViewOf<T> {
251 type Target = ItemsSourceView;
252
253 fn deref(&self) -> &ItemsSourceView {
254 &self.view
255 }
256}
257
258impl<T: PropertyValue> ItemsSourceViewOf<T> {
259 pub fn empty() -> Self {
261 Self { view: ItemsSourceView::empty(), marker: PhantomData }
262 }
263
264 pub(crate) fn new(source: ItemsSource) -> Self {
266 Self { view: ItemsSourceView::new(source), marker: PhantomData }
267 }
268
269 pub fn from_view(view: &ItemsSourceView) -> Self {
271 Self::new(view.source())
272 }
273
274 pub fn view(&self) -> &Rc<ItemsSourceView> {
276 &self.view
277 }
278
279 pub fn get_at(&self, index: usize) -> Option<T> {
282 let item = self.view.get_at(index);
283 if item.is_none() {
284 return None;
285 }
286 match unbox_item::<T>(&item) {
287 Some(value) => Some(value),
288 None => panic!("Unable to cast the item to type '{}'.", std::any::type_name::<T>()),
289 }
290 }
291
292 pub fn iter(&self) -> impl Iterator<Item = Option<T>> + '_ {
294 let mut index = 0;
295 std::iter::from_fn(move || {
296 if index < self.view.count() {
297 index += 1;
298 Some(self.get_at(index - 1))
299 } else {
300 None
301 }
302 })
303 }
304}