ferroui_controls/embedding/offscreen/
offscreen_top_level_impl.rs1use crate::platform::{IPlatformHandle, IPopupImpl, ITopLevelImpl, PlatformThemeVariant};
2use crate::{AcrylicPlatformCompensationLevels, WindowResizeReason, WindowTransparencyLevel};
3use ferroui_base::input::raw::IRawInputEventArgs;
4use ferroui_base::input::{IInputRoot, IMouseDevice};
5use ferroui_base::platform::surfaces::IPlatformRenderSurface;
6use ferroui_base::platform::{ICursorImpl, IOptionalFeatureProvider};
7use ferroui_base::reactive::IDisposable;
8use ferroui_base::rendering::composition::Compositor;
9use ferroui_base::{PixelPoint, Point, Rect, Size};
10use std::any::{Any, TypeId};
11use std::cell::{Cell, RefCell};
12use std::rc::Rc;
13
14pub trait OffscreenTopLevelImplOverrides {
20 fn surfaces(&self) -> Vec<std::sync::Arc<dyn IPlatformRenderSurface>>;
22
23 fn mouse_device(&self) -> Rc<dyn IMouseDevice>;
25
26 fn dispose(&self, base: &OffscreenTopLevelImplBase) {
29 base.base_dispose();
30 }
31
32 fn desktop_scaling(&self, base: &OffscreenTopLevelImplBase) -> f64 {
35 base.render_scaling()
36 }
37
38 fn point_to_client(&self, point: PixelPoint) -> Point {
40 point.to_point(1.0)
41 }
42
43 fn point_to_screen(&self, point: Point) -> PixelPoint {
45 PixelPoint::from_point(point, 1.0)
46 }
47
48 fn set_cursor(&self, _cursor: Option<Rc<dyn ICursorImpl>>) {}
50
51 fn try_get_feature(&self, _feature_type: TypeId) -> Option<Rc<dyn Any>> {
53 None
54 }
55}
56
57pub struct OffscreenTopLevelImplBase {
63 overrides: Rc<dyn OffscreenTopLevelImplOverrides>,
64 scaling: Cell<f64>,
65 client_size: Cell<Size>,
66 input_root: RefCell<Option<Rc<dyn IInputRoot>>>,
67 is_disposed: Cell<bool>,
68 compositor: Rc<Compositor>,
69 input: RefCell<Option<Rc<dyn Fn(Rc<dyn IRawInputEventArgs>)>>>,
70 paint: RefCell<Option<Rc<dyn Fn(Rect)>>>,
71 resized: RefCell<Option<Rc<dyn Fn(Size, WindowResizeReason)>>>,
72 scaling_changed: RefCell<Option<Rc<dyn Fn(f64)>>>,
73 transparency_level_changed: RefCell<Option<Rc<dyn Fn(WindowTransparencyLevel)>>>,
74 closed: RefCell<Option<Rc<dyn Fn()>>>,
75 lost_focus: RefCell<Option<Rc<dyn Fn()>>>,
76}
77
78impl OffscreenTopLevelImplBase {
79 pub fn new(overrides: Rc<dyn OffscreenTopLevelImplOverrides>) -> Rc<Self> {
82 Rc::new(Self {
83 overrides,
84 scaling: Cell::new(1.0),
85 client_size: Cell::new(Size::default()),
86 input_root: RefCell::new(None),
87 is_disposed: Cell::new(false),
88 compositor: Compositor::new(None, false),
89 input: RefCell::new(None),
90 paint: RefCell::new(None),
91 resized: RefCell::new(None),
92 scaling_changed: RefCell::new(None),
93 transparency_level_changed: RefCell::new(None),
94 closed: RefCell::new(None),
95 lost_focus: RefCell::new(None),
96 })
97 }
98
99 pub fn overrides(&self) -> &Rc<dyn OffscreenTopLevelImplOverrides> {
101 &self.overrides
102 }
103
104 pub fn input_root(&self) -> Option<Rc<dyn IInputRoot>> {
106 self.input_root.borrow().clone()
107 }
108
109 pub fn is_disposed(&self) -> bool {
111 self.is_disposed.get()
112 }
113
114 pub fn base_dispose(&self) {
116 self.is_disposed.set(true);
117 }
118
119 pub fn compositor(&self) -> &Rc<Compositor> {
121 &self.compositor
122 }
123
124 pub fn client_size(&self) -> Size {
126 self.client_size.get()
127 }
128
129 pub fn frame_size(&self) -> Option<Size> {
131 None
132 }
133
134 pub fn set_client_size(&self, value: Size) {
136 self.client_size.set(value);
137 let resized = self.resized.borrow().clone();
138 if let Some(resized) = resized {
139 resized(value, WindowResizeReason::Unspecified);
140 }
141 }
142
143 pub fn render_scaling(&self) -> f64 {
145 self.scaling.get()
146 }
147
148 pub fn set_render_scaling(&self, value: f64) {
150 self.scaling.set(value);
151 let scaling_changed = self.scaling_changed.borrow().clone();
152 if let Some(scaling_changed) = scaling_changed {
153 scaling_changed(value);
154 }
155 }
156
157 pub fn mouse_device(&self) -> Rc<dyn IMouseDevice> {
159 self.overrides.mouse_device()
160 }
161}
162
163impl IDisposable for OffscreenTopLevelImplBase {
164 fn dispose(&self) {
165 self.overrides.dispose(self);
166 }
167}
168
169impl IOptionalFeatureProvider for OffscreenTopLevelImplBase {
170 fn try_get_feature(&self, feature_type: TypeId) -> Option<Rc<dyn Any>> {
171 self.overrides.try_get_feature(feature_type)
172 }
173}
174
175impl ITopLevelImpl for OffscreenTopLevelImplBase {
176 fn desktop_scaling(&self) -> f64 {
177 self.overrides.desktop_scaling(self)
178 }
179
180 fn handle(&self) -> Option<Rc<dyn IPlatformHandle>> {
181 None
182 }
183
184 fn client_size(&self) -> Size {
185 self.client_size.get()
186 }
187
188 fn render_scaling(&self) -> f64 {
189 self.scaling.get()
190 }
191
192 fn surfaces(&self) -> Vec<std::sync::Arc<dyn IPlatformRenderSurface>> {
193 self.overrides.surfaces()
194 }
195
196 fn compositor(&self) -> Option<Rc<Compositor>> {
197 Some(self.compositor.clone())
198 }
199
200 fn input(&self) -> Option<Rc<dyn Fn(Rc<dyn IRawInputEventArgs>)>> {
201 self.input.borrow().clone()
202 }
203
204 fn set_input(&self, value: Option<Rc<dyn Fn(Rc<dyn IRawInputEventArgs>)>>) {
205 *self.input.borrow_mut() = value;
206 }
207
208 fn paint(&self) -> Option<Rc<dyn Fn(Rect)>> {
209 self.paint.borrow().clone()
210 }
211
212 fn set_paint(&self, value: Option<Rc<dyn Fn(Rect)>>) {
213 *self.paint.borrow_mut() = value;
214 }
215
216 fn resized(&self) -> Option<Rc<dyn Fn(Size, WindowResizeReason)>> {
217 self.resized.borrow().clone()
218 }
219
220 fn set_resized(&self, value: Option<Rc<dyn Fn(Size, WindowResizeReason)>>) {
221 *self.resized.borrow_mut() = value;
222 }
223
224 fn scaling_changed(&self) -> Option<Rc<dyn Fn(f64)>> {
225 self.scaling_changed.borrow().clone()
226 }
227
228 fn set_scaling_changed(&self, value: Option<Rc<dyn Fn(f64)>>) {
229 *self.scaling_changed.borrow_mut() = value;
230 }
231
232 fn transparency_level_changed(&self) -> Option<Rc<dyn Fn(WindowTransparencyLevel)>> {
233 self.transparency_level_changed.borrow().clone()
234 }
235
236 fn set_transparency_level_changed(&self, value: Option<Rc<dyn Fn(WindowTransparencyLevel)>>) {
237 *self.transparency_level_changed.borrow_mut() = value;
238 }
239
240 fn set_input_root(&self, input_root: Rc<dyn IInputRoot>) {
241 *self.input_root.borrow_mut() = Some(input_root);
242 }
243
244 fn point_to_client(&self, point: PixelPoint) -> Point {
245 self.overrides.point_to_client(point)
246 }
247
248 fn point_to_screen(&self, point: Point) -> PixelPoint {
249 self.overrides.point_to_screen(point)
250 }
251
252 fn set_cursor(&self, cursor: Option<Rc<dyn ICursorImpl>>) {
253 self.overrides.set_cursor(cursor)
254 }
255
256 fn closed(&self) -> Option<Rc<dyn Fn()>> {
257 self.closed.borrow().clone()
258 }
259
260 fn set_closed(&self, value: Option<Rc<dyn Fn()>>) {
261 *self.closed.borrow_mut() = value;
262 }
263
264 fn lost_focus(&self) -> Option<Rc<dyn Fn()>> {
265 self.lost_focus.borrow().clone()
266 }
267
268 fn set_lost_focus(&self, value: Option<Rc<dyn Fn()>>) {
269 *self.lost_focus.borrow_mut() = value;
270 }
271
272 fn create_popup(&self) -> Option<Rc<dyn IPopupImpl>> {
273 None
274 }
275
276 fn set_transparency_level_hint(&self, _transparency_levels: &[WindowTransparencyLevel]) {}
277
278 fn transparency_level(&self) -> WindowTransparencyLevel {
279 WindowTransparencyLevel::none()
280 }
281
282 fn acrylic_compensation_levels(&self) -> AcrylicPlatformCompensationLevels {
283 AcrylicPlatformCompensationLevels::new(1.0, 1.0, 1.0)
284 }
285
286 fn set_frame_theme_variant(&self, _theme_variant: Option<PlatformThemeVariant>) {}
287
288 fn as_any(&self) -> &dyn Any {
289 self
290 }
291}