classicube_sys\screen/
mod.rs

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