ferroui_controls/platform/
i_screen_impl.rs1use super::{IPlatformHandle, ITopLevelImpl, IWindowBaseImpl, Screen, ScreenHelper};
2use ferroui_base::threading::{Dispatcher, DispatcherOperation, DispatcherPriority};
3use ferroui_base::{PixelPoint, PixelRect};
4use std::cell::{Cell, RefCell};
5use std::collections::{HashMap, HashSet};
6use std::future::Future;
7use std::hash::Hash;
8use std::ops::Deref;
9use std::pin::Pin;
10use std::rc::Rc;
11
12pub trait IScreenImpl {
14 fn screen_count(&self) -> i32;
16
17 fn all_screens(&self) -> Vec<Rc<Screen>>;
19
20 fn changed(&self) -> Option<Rc<dyn Fn()>>;
22
23 fn set_changed(&self, value: Option<Rc<dyn Fn()>>);
25
26 fn screen_from_window(&self, window: &dyn IWindowBaseImpl) -> Option<Rc<Screen>>;
28
29 fn screen_from_top_level(&self, top_level: &dyn ITopLevelImpl) -> Option<Rc<Screen>>;
31
32 fn screen_from_point(&self, point: PixelPoint) -> Option<Rc<Screen>>;
34
35 fn screen_from_rect(&self, rect: PixelRect) -> Option<Rc<Screen>>;
37
38 fn request_screen_details(&self) -> Pin<Box<dyn Future<Output = bool>>>;
44}
45
46pub struct PlatformScreen {
52 screen: Rc<Screen>,
53}
54
55impl PlatformScreen {
56 pub fn new(platform_handle: Rc<dyn IPlatformHandle>) -> Self {
58 Self { screen: Rc::new(Screen::new(Some(platform_handle))) }
59 }
60
61 pub fn screen(&self) -> &Rc<Screen> {
63 &self.screen
64 }
65}
66
67impl Deref for PlatformScreen {
68 type Target = Screen;
69
70 fn deref(&self) -> &Screen {
71 &self.screen
72 }
73}
74
75impl AsRef<PlatformScreen> for PlatformScreen {
76 fn as_ref(&self) -> &PlatformScreen {
77 self
78 }
79}
80
81pub struct ScreensBase<TKey, TScreen> {
84 all_screens_by_key: RefCell<HashMap<TKey, Rc<TScreen>>>,
85 all_screens: RefCell<Option<Vec<Rc<TScreen>>>>,
86 screen_count: Cell<Option<i32>>,
87 screen_details_request_granted: Rc<Cell<Option<bool>>>,
88 on_change_operation: RefCell<Option<DispatcherOperation>>,
89 changed: RefCell<Option<Rc<dyn Fn()>>>,
90}
91
92impl<TKey, TScreen> ScreensBase<TKey, TScreen> {
93 pub fn new() -> Self {
95 Self {
96 all_screens_by_key: RefCell::new(HashMap::new()),
97 all_screens: RefCell::new(None),
98 screen_count: Cell::new(None),
99 screen_details_request_granted: Rc::new(Cell::new(None)),
100 on_change_operation: RefCell::new(None),
101 changed: RefCell::new(None),
102 }
103 }
104}
105
106impl<TKey, TScreen> Default for ScreensBase<TKey, TScreen> {
107 fn default() -> Self {
108 Self::new()
109 }
110}
111
112pub trait ScreensBaseImpl: 'static {
122 type Key: Eq + Hash + Clone + 'static;
124
125 type Screen: AsRef<PlatformScreen> + 'static;
127
128 fn screens_base(&self) -> &ScreensBase<Self::Key, Self::Screen>;
130
131 fn get_all_screen_keys(&self) -> Vec<Self::Key>;
133
134 fn create_screen_from_key(&self, key: &Self::Key) -> Rc<Self::Screen>;
136
137 fn screen_added(&self, screen: &Rc<Self::Screen>) {
139 self.screen_changed(screen);
140 }
141
142 fn screen_changed(&self, _screen: &Rc<Self::Screen>) {}
144
145 fn screen_removed(&self, screen: &Rc<Self::Screen>) {
147 (**screen).as_ref().on_removed();
148 }
149
150 fn get_screen_count(&self) -> i32 {
152 self.all_platform_screens().len() as i32
153 }
154
155 fn request_screen_details_core(&self) -> Pin<Box<dyn Future<Output = bool>>> {
157 Box::pin(std::future::ready(true))
158 }
159
160 fn screen_from_top_level_core(&self, top_level: &dyn ITopLevelImpl) -> Option<Rc<Screen>> {
162 match top_level.as_window_impl() {
163 Some(window) => ScreenHelper::screen_from_window(window, &IScreenImpl::all_screens(self)),
164 None => None,
165 }
166 }
167
168 fn screen_from_point_core(&self, point: PixelPoint) -> Option<Rc<Screen>> {
170 ScreenHelper::screen_from_point(point, &IScreenImpl::all_screens(self))
171 }
172
173 fn screen_from_rect_core(&self, rect: PixelRect) -> Option<Rc<Screen>> {
175 ScreenHelper::screen_from_rect(rect, &IScreenImpl::all_screens(self))
176 }
177}
178
179pub trait ScreensBaseImplExt: ScreensBaseImpl {
181 fn on_changed(self: &Rc<Self>);
187
188 fn try_get_screen(&self, key: &Self::Key) -> Option<Rc<Self::Screen>>;
190
191 fn all_platform_screens(&self) -> Vec<Rc<Self::Screen>>;
193}
194
195fn ensure_screens<T: ScreensBaseImpl + ?Sized>(this: &T) {
196 let base = this.screens_base();
197 if base.all_screens.borrow().is_some() {
198 return;
199 }
200
201 Dispatcher::ui_thread().verify_access();
204
205 let screens = this.get_all_screen_keys();
206
207 let removed_keys: Vec<T::Key> = {
208 let screens_set: HashSet<&T::Key> = screens.iter().collect();
209 let all_screens_by_key = base.all_screens_by_key.borrow();
210 all_screens_by_key.keys().filter(|key| !screens_set.contains(key)).cloned().collect()
211 };
212 for old_screen_key in removed_keys {
213 let removed = base.all_screens_by_key.borrow_mut().remove(&old_screen_key);
214 if let Some(screen) = removed {
215 this.screen_removed(&screen);
216 }
217 }
218
219 let mut temp_screens = Vec::with_capacity(screens.len());
220 for new_screen_key in &screens {
221 let old_screen = base.all_screens_by_key.borrow().get(new_screen_key).cloned();
222 match old_screen {
223 Some(old_screen) => {
224 this.screen_changed(&old_screen);
225 temp_screens.push(old_screen);
226 }
227 None => {
228 let new_screen = this.create_screen_from_key(new_screen_key);
229 this.screen_added(&new_screen);
230 base.all_screens_by_key.borrow_mut().insert(new_screen_key.clone(), new_screen.clone());
231 temp_screens.push(new_screen);
232 }
233 }
234 }
235
236 *base.all_screens.borrow_mut() = Some(temp_screens);
237}
238
239impl<T: ScreensBaseImpl + ?Sized> ScreensBaseImplExt for T {
240 fn on_changed(self: &Rc<Self>) {
241 let base = self.screens_base();
242
243 base.screen_count.set(None);
245 *base.all_screens.borrow_mut() = None;
246
247 let previous = base.on_change_operation.take();
250 if let Some(previous) = previous {
251 previous.abort();
252 }
253
254 let this = Rc::downgrade(self);
255 let operation = Dispatcher::ui_thread().invoke_async_local_with_priority(
256 move || {
257 let Some(this) = this.upgrade() else {
258 return;
259 };
260 let base = this.screens_base();
261
262 let has_subscriber = base.changed.borrow().is_some();
266 if has_subscriber || !base.all_screens_by_key.borrow().is_empty() {
267 ensure_screens(&*this);
268 let changed = base.changed.borrow().clone();
269 if let Some(changed) = changed {
270 changed();
271 }
272 }
273 },
274 DispatcherPriority::INPUT,
275 );
276 *base.on_change_operation.borrow_mut() = Some(operation);
277 }
278
279 fn try_get_screen(&self, key: &Self::Key) -> Option<Rc<Self::Screen>> {
280 ensure_screens(self);
281 self.screens_base().all_screens_by_key.borrow().get(key).cloned()
282 }
283
284 fn all_platform_screens(&self) -> Vec<Rc<Self::Screen>> {
285 ensure_screens(self);
286 self.screens_base().all_screens.borrow().clone().unwrap_or_default()
287 }
288}
289
290impl<T: ScreensBaseImpl + ?Sized> IScreenImpl for T {
291 fn screen_count(&self) -> i32 {
292 let base = self.screens_base();
293 match base.screen_count.get() {
294 Some(screen_count) => screen_count,
295 None => {
296 let screen_count = self.get_screen_count();
297 base.screen_count.set(Some(screen_count));
298 screen_count
299 }
300 }
301 }
302
303 fn all_screens(&self) -> Vec<Rc<Screen>> {
304 ensure_screens(self);
305 match self.screens_base().all_screens.borrow().as_ref() {
306 Some(all_screens) => {
307 all_screens.iter().map(|screen| (**screen).as_ref().screen().clone()).collect()
308 }
309 None => Vec::new(),
310 }
311 }
312
313 fn changed(&self) -> Option<Rc<dyn Fn()>> {
314 self.screens_base().changed.borrow().clone()
315 }
316
317 fn set_changed(&self, value: Option<Rc<dyn Fn()>>) {
318 let previous = self.screens_base().changed.replace(value);
319 drop(previous);
320 }
321
322 fn screen_from_window(&self, window: &dyn IWindowBaseImpl) -> Option<Rc<Screen>> {
323 IScreenImpl::screen_from_top_level(self, window)
324 }
325
326 fn screen_from_top_level(&self, top_level: &dyn ITopLevelImpl) -> Option<Rc<Screen>> {
327 self.screen_from_top_level_core(top_level)
328 }
329
330 fn screen_from_point(&self, point: PixelPoint) -> Option<Rc<Screen>> {
331 self.screen_from_point_core(point)
332 }
333
334 fn screen_from_rect(&self, rect: PixelRect) -> Option<Rc<Screen>> {
335 self.screen_from_rect_core(rect)
336 }
337
338 fn request_screen_details(&self) -> Pin<Box<dyn Future<Output = bool>>> {
339 let granted = self.screens_base().screen_details_request_granted.clone();
340 if let Some(granted) = granted.get() {
341 return Box::pin(std::future::ready(granted));
342 }
343
344 let request = self.request_screen_details_core();
345 Box::pin(async move {
346 let result = request.await;
347 granted.set(Some(result));
348 result
349 })
350 }
351}