1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4use super::{RepaintBufferType, SoftwareRenderer};
5use crate::api::Window;
6use crate::platform::Renderer;
7use crate::window::WindowAdapter;
8use alloc::rc::{Rc, Weak};
9use core::cell::Cell;
10
11/// This is a minimal adapter for a Window that doesn't have any other feature than rendering
12/// using the software renderer.
13pub struct MinimalSoftwareWindow {
14 window: Window,
15 renderer: SoftwareRenderer,
16 needs_redraw: Cell<bool>,
17 size: Cell<crate::api::PhysicalSize>,
18}
19
20impl MinimalSoftwareWindow {
21 /// Instantiate a new MinimalWindowAdaptor
22 ///
23 /// The `repaint_buffer_type` parameter specify what kind of buffer are passed to the [`SoftwareRenderer`]
24 pub fn new(repaint_buffer_type: RepaintBufferType) -> Rc<Self> {
25 Rc::new_cyclic(|w: &Weak<Self>| Self {
26 window: Window::new(w.clone()),
27 renderer: SoftwareRenderer::new_with_repaint_buffer_type(repaint_buffer_type),
28 needs_redraw: Default::default(),
29 size: Default::default(),
30 })
31 }
32 /// If the window needs to be redrawn, the callback will be called with the
33 /// [renderer](SoftwareRenderer) that should be used to do the drawing.
34 ///
35 /// [`SoftwareRenderer::render()`] or [`SoftwareRenderer::render_by_line()`] should be called
36 /// in that callback.
37 ///
38 /// Return true if something was redrawn.
39 pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool {
40 if self.needs_redraw.replace(false) || self.renderer.rendering_metrics_collector.is_some() {
41 render_callback(&self.renderer);
42 true
43 } else {
44 false
45 }
46 }
47
48 #[cfg(feature = "experimental")]
49 #[rustversion::since(1.85)]
50 /// If the window needs to be redrawn, the callback will be called with the
51 /// [renderer](SoftwareRenderer) that should be used to do the drawing.
52 ///
53 /// [`SoftwareRenderer::render()`] or [`SoftwareRenderer::render_by_line()`] should be called
54 /// in that callback.
55 ///
56 /// Return true if something was redrawn.
57 pub async fn draw_async_if_needed(
58 &self,
59 render_callback: impl AsyncFnOnce(&SoftwareRenderer),
60 ) -> bool {
61 if self.needs_redraw.replace(false) || self.renderer.rendering_metrics_collector.is_some() {
62 render_callback(&self.renderer).await;
63 true
64 } else {
65 false
66 }
67 }
68
69 #[doc(hidden)]
70 /// Forward to the window through Deref
71 /// (Before 1.1, WindowAdapter didn't have set_size, so the one from Deref was used.
72 /// But in Slint 1.1, if one had imported the WindowAdapter trait, the other one would be found)
73 pub fn set_size(&self, size: impl Into<crate::api::WindowSize>) {
74 self.window.set_size(size);
75 }
76}
77
78impl WindowAdapter for MinimalSoftwareWindow {
79 fn window(&self) -> &Window {
80 &self.window
81 }
82
83 fn renderer(&self) -> &dyn Renderer {
84 &self.renderer
85 }
86
87 fn size(&self) -> crate::api::PhysicalSize {
88 self.size.get()
89 }
90 fn set_size(&self, size: crate::api::WindowSize) {
91 let sf: f32 = self.window.scale_factor();
92 self.size.set(val:size.to_physical(scale_factor:sf));
93 self.window
94 .dispatch_event(crate::platform::WindowEvent::Resized { size: size.to_logical(scale_factor:sf) })
95 }
96
97 fn request_redraw(&self) {
98 self.needs_redraw.set(val:true);
99 }
100}
101
102impl core::ops::Deref for MinimalSoftwareWindow {
103 type Target = Window;
104 fn deref(&self) -> &Self::Target {
105 &self.window
106 }
107}
108