devela/ui/back/miniquad/
service.rs

1// devela::ui::back::miniquad::service
2//
3//! Defines [`MiniquadEventHandlerExt`] and [`MiniquadService`].
4//
5// TOC
6// - MiniquadEventHandlerExt
7// - MiniquadService
8
9use crate::{iif, UiCap, UiCapImage, UiCapInput, UiCapWindow, UiService};
10use crate::{Box, ToString};
11#[cfg(doc)]
12use ::miniquad::FilterMode;
13use ::miniquad::{conf::Conf, EventHandler};
14
15/// An extension trait for miniquad's `MiniquadEventHandler`.
16///
17/// It allows lazy initialization and other methods.
18//
19// https://docs.rs/miniquad/latest/miniquad/trait.EventHandler.html
20pub trait MiniquadEventHandlerExt: EventHandler {
21    /// Returns the event handler initialized.
22    fn init(self) -> Self;
23
24    /// Whether it interpolates the scaled pixels.
25    fn interpolation(&self) -> bool;
26    /// Set whether to `interpolate` the scaled pixels.
27    fn set_interpolation(&mut self, interpolate: bool);
28
29    /// Whether the aspect ratio is maintained on window resize.
30    fn maintain_aspect_ratio(&self) -> bool;
31    /// Set whether to `maintain` the aspect ratio on window resize.
32    fn set_maintain_aspect_ratio(&mut self, maintain: bool);
33}
34
35impl<T: MiniquadEventHandlerExt + 'static> UiService for MiniquadService<T> {
36    fn capabilities(&self) -> UiCap {
37        let image = Some(UiCapImage { rgb: true, ..Default::default() });
38        let input = Some(UiCapInput { keyboard: true, mouse: true, ..Default::default() });
39        let window = Some(UiCapWindow { multi: false });
40        UiCap { image, input, window, ..Default::default() }
41    }
42    fn version(&self) -> (u32, u32, u32) {
43        (0, 4, 7)
44    }
45}
46
47/// `miniquad`'s UI Service.
48pub struct MiniquadService<T: MiniquadEventHandlerExt + 'static> {
49    handler: Option<T>,
50    conf: Conf,
51
52    /* pixel buffer settings */
53    width: u32,
54    height: u32,
55}
56
57impl<T: MiniquadEventHandlerExt + 'static> Default for MiniquadService<T> {
58    /// Returns a default `MiniquadService` without a handler.
59    fn default() -> Self {
60        Self {
61            handler: None,
62            conf: Conf::default(),
63            //
64            width: 0,
65            height: 0,
66        }
67    }
68}
69
70/// # builder methods
71impl<T: MiniquadEventHandlerExt + 'static> MiniquadService<T> {
72    /// Returns a default `MiniquadService` with the given `handler`,
73    pub fn with(handler: T) -> Self {
74        Self { handler: Some(handler), ..Default::default() }
75    }
76
77    /// Initialize the miniquad rendering context, opening the window.
78    ///
79    /// This must be the last method to call.
80    ///
81    /// # Panics
82    /// Panics if the handler is not set (e.g. by constructing with `default()`)
83    pub fn init(self) {
84        let handler = self.handler.expect("Event handler is required");
85        ::miniquad::start(self.conf, move || Box::new(handler.init()));
86    }
87
88    /* builder methods */
89
90    /// Sets the given handler.
91    pub fn handler(mut self, handler: T) -> Self {
92        self.handler = Some(handler);
93        self
94    }
95
96    /// Sets the given miniquad configuration.
97    pub fn conf(mut self, conf: Conf) -> Self {
98        self.conf = conf;
99        self
100    }
101
102    /// Whether the event loop should block until [`schedule_update`] is called.
103    ///
104    /// [`schedule_update`]: crate::MiniquadWindow::schedule_update
105    pub fn blocking_event_loop(mut self, blocking: bool) -> Self {
106        self.conf.platform.blocking_event_loop = blocking;
107        self
108    }
109
110    /* window */
111
112    /// Sets the window title.
113    pub fn title(mut self, title: impl ToString) -> Self {
114        self.conf.window_title = title.to_string();
115        self
116    }
117
118    /// Sets the window size.
119    ///
120    /// NOTE: in X11 it needs to have `window_resizable` set to `true` for it to have any effect.
121    pub fn window_size(mut self, width: u32, height: u32) -> Self {
122        assert![width <= i32::MAX as u32];
123        assert![height <= i32::MAX as u32];
124        self.conf.window_width = width as i32;
125        self.conf.window_height = height as i32;
126        self
127    }
128
129    /// Whether the window should be `resizable` by the user.
130    pub fn window_resizable(mut self, resizable: bool) -> Self {
131        self.conf.window_resizable = resizable;
132        self
133    }
134
135    /// Whether the window should be `fullscreen`.
136    pub fn fullscreen(mut self, fullscreen: bool) -> Self {
137        self.conf.fullscreen = fullscreen;
138        self
139    }
140
141    /* buffer */
142
143    /// Sets the size of the pixel buffer.
144    pub fn buffer_size(mut self, width: u32, height: u32) -> Self {
145        assert![width <= i32::MAX as u32];
146        assert![height <= i32::MAX as u32];
147        self.width = width;
148        self.height = height;
149        self
150    }
151    /// If `linear == true` uses [`FilterMode:Linear`], otherwise [`FilterMode::Nearest`].
152    ///
153    /// If the `handler` has not been set, this does nothing.
154    pub fn interpolation(mut self, linear: bool) -> Self {
155        iif![let Some(h) = self.handler.as_mut(); h.set_interpolation(linear)];
156        self
157    }
158
159    /// Set whether to `maintain` the aspect ratio on window resize.
160    ///
161    /// If the `handler` has not been set, this does nothing.
162    pub fn maintain_aspect_ratio(mut self, maintain: bool) -> Self {
163        iif![let Some(h) = self.handler.as_mut(); h.set_maintain_aspect_ratio(maintain)];
164        self
165    }
166}
167
168/// # getters and setters
169impl<T: MiniquadEventHandlerExt + 'static> MiniquadService<T> {
170    /// Whether the aspect ratio is maintained on window resize.
171    pub fn get_interpolation(self) -> bool {
172        self.handler.as_ref().map(|h| h.interpolation()).unwrap_or_default()
173    }
174    /// Set whether to `maintain` the aspect ratio on window resize.
175    pub fn set_interpolation(&mut self, interpolate: bool) {
176        iif![let Some(h) = self.handler.as_mut(); h.set_interpolation(interpolate)];
177    }
178
179    /// Whether the aspect ratio is maintained on window resize.
180    pub fn get_maintain_aspect_ratio(self) -> bool {
181        self.handler.as_ref().map(|h| h.maintain_aspect_ratio()).unwrap_or_default()
182    }
183    /// Set whether to `maintain` the aspect ratio on window resize.
184    pub fn set_maintain_aspect_ratio(&mut self, maintain: bool) {
185        iif![let Some(h) = self.handler.as_mut(); h.set_maintain_aspect_ratio(maintain)];
186    }
187}