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::{Box, ToString};
10use crate::{UiCap, UiCapImage, UiCapInput, UiCapWindow, UiService, is};
11#[cfg(doc)]
12use ::miniquad::FilterMode;
13use ::miniquad::{EventHandler, conf::Conf};
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.
48#[derive(Debug)]
49pub struct MiniquadService<T: MiniquadEventHandlerExt + 'static> {
50    handler: Option<T>,
51    conf: Conf,
52
53    /* pixel buffer settings */
54    width: u32,
55    height: u32,
56}
57
58impl<T: MiniquadEventHandlerExt + 'static> Default for MiniquadService<T> {
59    /// Returns a default `MiniquadService` without a handler.
60    fn default() -> Self {
61        Self {
62            handler: None,
63            conf: Conf::default(),
64            //
65            width: 0,
66            height: 0,
67        }
68    }
69}
70
71/// # builder methods
72impl<T: MiniquadEventHandlerExt + 'static> MiniquadService<T> {
73    /// Returns a default `MiniquadService` with the given `handler`,
74    pub fn with(handler: T) -> Self {
75        Self { handler: Some(handler), ..Default::default() }
76    }
77
78    /// Initialize the miniquad rendering context, opening the window.
79    ///
80    /// This must be the last method to call.
81    ///
82    /// # Panics
83    /// Panics if the handler is not set (e.g. by constructing with `default()`)
84    pub fn init(self) {
85        let handler = self.handler.expect("Event handler is required");
86        ::miniquad::start(self.conf, move || Box::new(handler.init()));
87    }
88
89    /* builder methods */
90
91    /// Sets the given handler.
92    pub fn handler(mut self, handler: T) -> Self {
93        self.handler = Some(handler);
94        self
95    }
96
97    /// Sets the given miniquad configuration.
98    pub fn conf(mut self, conf: Conf) -> Self {
99        self.conf = conf;
100        self
101    }
102
103    /// Whether the event loop should block until [`schedule_update`] is called.
104    ///
105    /// [`schedule_update`]: crate::MiniquadWindow::schedule_update
106    pub fn blocking_event_loop(mut self, blocking: bool) -> Self {
107        self.conf.platform.blocking_event_loop = blocking;
108        self
109    }
110
111    /* window */
112
113    /// Sets the window title.
114    pub fn title(mut self, title: impl ToString) -> Self {
115        self.conf.window_title = title.to_string();
116        self
117    }
118
119    /// Sets the window size.
120    ///
121    /// NOTE: in X11 it needs to have `window_resizable` set to `true` for it to have any effect.
122    pub fn window_size(mut self, width: u32, height: u32) -> Self {
123        assert![width <= i32::MAX as u32];
124        assert![height <= i32::MAX as u32];
125        self.conf.window_width = width as i32;
126        self.conf.window_height = height as i32;
127        self
128    }
129
130    /// Whether the window should be `resizable` by the user.
131    pub fn window_resizable(mut self, resizable: bool) -> Self {
132        self.conf.window_resizable = resizable;
133        self
134    }
135
136    /// Whether the window should be `fullscreen`.
137    pub fn fullscreen(mut self, fullscreen: bool) -> Self {
138        self.conf.fullscreen = fullscreen;
139        self
140    }
141
142    /* buffer */
143
144    /// Sets the size of the pixel buffer.
145    pub fn buffer_size(mut self, width: u32, height: u32) -> Self {
146        assert![width <= i32::MAX as u32];
147        assert![height <= i32::MAX as u32];
148        self.width = width;
149        self.height = height;
150        self
151    }
152    /// If `linear == true` uses [`FilterMode::Linear`], otherwise [`FilterMode::Nearest`].
153    ///
154    /// If the `handler` has not been set, this does nothing.
155    pub fn interpolation(mut self, linear: bool) -> Self {
156        is![let Some(h) = self.handler.as_mut(); h.set_interpolation(linear)];
157        self
158    }
159
160    /// Set whether to `maintain` the aspect ratio on window resize.
161    ///
162    /// If the `handler` has not been set, this does nothing.
163    pub fn maintain_aspect_ratio(mut self, maintain: bool) -> Self {
164        is![let Some(h) = self.handler.as_mut(); h.set_maintain_aspect_ratio(maintain)];
165        self
166    }
167}
168
169/// # getters and setters
170impl<T: MiniquadEventHandlerExt + 'static> MiniquadService<T> {
171    /// Whether the aspect ratio is maintained on window resize.
172    pub fn get_interpolation(self) -> bool {
173        self.handler.as_ref().map(|h| h.interpolation()).unwrap_or_default()
174    }
175    /// Set whether to `maintain` the aspect ratio on window resize.
176    pub fn set_interpolation(&mut self, interpolate: bool) {
177        is![let Some(h) = self.handler.as_mut(); h.set_interpolation(interpolate)];
178    }
179
180    /// Whether the aspect ratio is maintained on window resize.
181    pub fn get_maintain_aspect_ratio(self) -> bool {
182        self.handler.as_ref().map(|h| h.maintain_aspect_ratio()).unwrap_or_default()
183    }
184    /// Set whether to `maintain` the aspect ratio on window resize.
185    pub fn set_maintain_aspect_ratio(&mut self, maintain: bool) {
186        is![let Some(h) = self.handler.as_mut(); h.set_maintain_aspect_ratio(maintain)];
187    }
188}