Skip to main content

classicube_sys/screen/
mod.rs

1mod priority;
2
3use core::mem;
4
5pub use self::priority::Priority;
6use crate::{
7    PadAxisUpdate,
8    bindings::{Gui_Add, Gui_Remove, InputDevice, Screen, ScreenVTABLE, cc_string},
9    std_types::{Box, c_char, c_int, c_void},
10};
11
12pub struct OwnedScreen {
13    pub screen: Box<Screen>,
14    vtable: Box<ScreenVTABLE>,
15    added: bool,
16}
17
18impl OwnedScreen {
19    pub fn new() -> Self {
20        let mut vtable = Box::new(ScreenVTABLE {
21            Init: Some(Init),
22            Update: Some(Update),
23            Free: Some(Free),
24            Render: Some(Render),
25            BuildMesh: Some(BuildMesh),
26            HandlesInputDown: Some(HandlesInputDown),
27            OnInputUp: Some(OnInputUp),
28            HandlesKeyPress: Some(HandlesKeyPress),
29            HandlesTextChanged: Some(HandlesTextChanged),
30            HandlesPointerDown: Some(HandlesPointerDown),
31            OnPointerUp: Some(OnPointerUp),
32            HandlesPointerMove: Some(HandlesPointerMove),
33            HandlesMouseScroll: Some(HandlesMouseScroll),
34            Layout: Some(Layout),
35            ContextLost: Some(ContextLost),
36            ContextRecreated: Some(ContextRecreated),
37            HandlesPadAxis: Some(HandlesPadAxis),
38        });
39
40        let screen = Box::new(unsafe {
41            let mut screen: Screen = mem::zeroed();
42            screen.VTABLE = vtable.as_mut();
43            screen
44        });
45
46        Self {
47            screen,
48            vtable,
49            added: false,
50        }
51    }
52
53    pub fn add<T: Into<Priority>>(&mut self, priority: T) {
54        if self.added {
55            return;
56        }
57        unsafe {
58            // priority is stored as a u8 even though api is c_int
59            Gui_Add(self.screen.as_mut(), priority.into().to_u8() as _);
60        }
61        self.added = true;
62    }
63
64    pub fn remove(&mut self) {
65        if self.added {
66            unsafe {
67                Gui_Remove(self.screen.as_mut());
68            }
69            self.added = false;
70        }
71    }
72
73    /// Initialises persistent state.
74    pub fn on_init(&mut self, f: unsafe extern "C" fn(elem: *mut c_void)) -> &mut Self {
75        self.vtable.as_mut().Init = Some(f);
76        self
77    }
78
79    /// Updates this screen, called every frame just before Render().
80    pub fn on_update(
81        &mut self,
82        f: unsafe extern "C" fn(elem: *mut c_void, delta: f32),
83    ) -> &mut Self {
84        self.vtable.as_mut().Update = Some(f);
85        self
86    }
87
88    /// Frees/releases persistent state.
89    pub fn on_free(&mut self, f: unsafe extern "C" fn(elem: *mut c_void)) -> &mut Self {
90        self.vtable.as_mut().Free = Some(f);
91        self
92    }
93
94    /// Draws this screen and its widgets on screen.
95    pub fn on_render(
96        &mut self,
97        f: unsafe extern "C" fn(elem: *mut c_void, delta: f32),
98    ) -> &mut Self {
99        self.vtable.as_mut().Render = Some(f);
100        self
101    }
102
103    /// Builds the vertex mesh for all the widgets in the screen.
104    pub fn on_build_mesh(&mut self, f: unsafe extern "C" fn(elem: *mut c_void)) -> &mut Self {
105        self.vtable.as_mut().BuildMesh = Some(f);
106        self
107    }
108
109    /// Returns non-zero if an input press is handled.
110    pub fn on_handles_input_down(
111        &mut self,
112        f: unsafe extern "C" fn(elem: *mut c_void, key: c_int, device: *mut InputDevice) -> c_int,
113    ) -> &mut Self {
114        self.vtable.as_mut().HandlesInputDown = Some(f);
115        self
116    }
117
118    /// Returns non-zero if an input release is handled.
119    pub fn on_on_input_up(
120        &mut self,
121        f: unsafe extern "C" fn(elem: *mut c_void, key: c_int, device: *mut InputDevice),
122    ) -> &mut Self {
123        self.vtable.as_mut().OnInputUp = Some(f);
124        self
125    }
126
127    /// Returns non-zero if a key character press is handled.
128    pub fn on_handles_key_press(
129        &mut self,
130        f: unsafe extern "C" fn(elem: *mut c_void, keyChar: c_char) -> c_int,
131    ) -> &mut Self {
132        self.vtable.as_mut().HandlesKeyPress = Some(f);
133        self
134    }
135
136    /// Returns non-zero if a key character press is handled.
137    /// Currently only raised by on-screen keyboard in web client.
138    pub fn on_handles_text_changed(
139        &mut self,
140        f: unsafe extern "C" fn(elem: *mut c_void, str: *const cc_string) -> c_int,
141    ) -> &mut Self {
142        self.vtable.as_mut().HandlesTextChanged = Some(f);
143        self
144    }
145
146    /// Returns non-zero if a pointer press is handled.
147    pub fn on_handles_pointer_down(
148        &mut self,
149        f: unsafe extern "C" fn(elem: *mut c_void, id: c_int, x: c_int, y: c_int) -> c_int,
150    ) -> &mut Self {
151        self.vtable.as_mut().HandlesPointerDown = Some(f);
152        self
153    }
154
155    /// Returns non-zero if a pointer release is handled.
156    pub fn on_on_pointer_up(
157        &mut self,
158        f: unsafe extern "C" fn(elem: *mut c_void, id: c_int, x: c_int, y: c_int),
159    ) -> &mut Self {
160        self.vtable.as_mut().OnPointerUp = Some(f);
161        self
162    }
163
164    /// Returns non-zero if a pointer movement is handled.
165    pub fn on_handles_pointer_move(
166        &mut self,
167        f: unsafe extern "C" fn(elem: *mut c_void, id: c_int, x: c_int, y: c_int) -> c_int,
168    ) -> &mut Self {
169        self.vtable.as_mut().HandlesPointerMove = Some(f);
170        self
171    }
172
173    /// Returns non-zero if a mouse wheel scroll is handled.
174    pub fn on_handles_mouse_scroll(
175        &mut self,
176        f: unsafe extern "C" fn(elem: *mut c_void, delta: f32) -> c_int,
177    ) -> &mut Self {
178        self.vtable.as_mut().HandlesMouseScroll = Some(f);
179        self
180    }
181
182    /// Positions widgets on screen. Typically called on window resize.
183    pub fn on_layout(&mut self, f: unsafe extern "C" fn(elem: *mut c_void)) -> &mut Self {
184        self.vtable.as_mut().Layout = Some(f);
185        self
186    }
187
188    /// Destroys graphics resources. (textures, vertex buffers, etc)
189    pub fn on_context_lost(&mut self, f: unsafe extern "C" fn(elem: *mut c_void)) -> &mut Self {
190        self.vtable.as_mut().ContextLost = Some(f);
191        self
192    }
193
194    /// Allocates graphics resources. (textures, vertex buffers, etc)
195    pub fn on_context_recreated(
196        &mut self,
197        f: unsafe extern "C" fn(elem: *mut c_void),
198    ) -> &mut Self {
199        self.vtable.as_mut().ContextRecreated = Some(f);
200        self
201    }
202
203    /// Returns non-zero if a pad axis update is handled.
204    pub fn on_handles_pad_axis(
205        &mut self,
206        f: unsafe extern "C" fn(elem: *mut c_void, upd: *mut PadAxisUpdate) -> c_int,
207    ) -> &mut Self {
208        self.vtable.as_mut().HandlesPadAxis = Some(f);
209        self
210    }
211}
212
213impl Default for OwnedScreen {
214    fn default() -> Self {
215        Self::new()
216    }
217}
218
219impl Drop for OwnedScreen {
220    fn drop(&mut self) {
221        #[cfg(not(test))]
222        self.remove();
223    }
224}
225
226// default noop functions
227unsafe extern "C" fn Init(_elem: *mut c_void) {}
228unsafe extern "C" fn Update(_elem: *mut c_void, _delta: f32) {}
229unsafe extern "C" fn Free(_elem: *mut c_void) {}
230unsafe extern "C" fn Render(_elem: *mut c_void, _delta: f32) {}
231unsafe extern "C" fn BuildMesh(_elem: *mut c_void) {}
232unsafe extern "C" fn HandlesInputDown(
233    _elem: *mut c_void,
234    _key: c_int,
235    _device: *mut InputDevice,
236) -> c_int {
237    0
238}
239unsafe extern "C" fn OnInputUp(_elem: *mut c_void, _key: c_int, _device: *mut InputDevice) {}
240unsafe extern "C" fn HandlesKeyPress(_elem: *mut c_void, _keyChar: c_char) -> c_int {
241    0
242}
243unsafe extern "C" fn HandlesTextChanged(_elem: *mut c_void, _str: *const cc_string) -> c_int {
244    0
245}
246unsafe extern "C" fn HandlesPointerDown(
247    _elem: *mut c_void,
248    _id: c_int,
249    _x: c_int,
250    _y: c_int,
251) -> c_int {
252    0
253}
254unsafe extern "C" fn OnPointerUp(_elem: *mut c_void, _id: c_int, _x: c_int, _y: c_int) {}
255unsafe extern "C" fn HandlesPointerMove(
256    _elem: *mut c_void,
257    _id: c_int,
258    _x: c_int,
259    _y: c_int,
260) -> c_int {
261    0
262}
263unsafe extern "C" fn HandlesMouseScroll(_elem: *mut c_void, _delta: f32) -> c_int {
264    0
265}
266unsafe extern "C" fn Layout(_elem: *mut c_void) {}
267unsafe extern "C" fn ContextLost(_elem: *mut c_void) {}
268unsafe extern "C" fn ContextRecreated(_elem: *mut c_void) {}
269unsafe extern "C" fn HandlesPadAxis(_elem: *mut c_void, _upd: *mut PadAxisUpdate) -> c_int {
270    0
271}
272
273#[test]
274fn test_screen() {
275    extern "C" fn init(_elem: *mut c_void) {
276        //
277    }
278
279    let _screen = OwnedScreen::new().on_init(init);
280    let mut screen = OwnedScreen::new();
281    screen.on_init(init);
282}