wxrust_base/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::marker::PhantomData;
4use std::mem;
5use std::os::raw::{c_char, c_int, c_void};
6use std::ptr;
7use std::slice;
8use std::str;
9
10mod macros;
11
12mod constants;
13#[doc(hidden)]
14pub use constants::*;
15mod manual;
16#[doc(hidden)]
17pub use manual::*;
18
19mod generated;
20pub use generated::class::*;
21
22use methods::*;
23
24mod ffi {
25    use std::os::raw::{c_char, c_int, c_uchar, c_void};
26
27    #[repr(C)]
28    pub struct UTF8Data {
29        pub data: *mut c_uchar,
30        pub length: usize,
31    }
32    extern "C" {
33        pub fn wxObject_delete(self_: *mut c_void);
34
35        pub fn AppSetOnInit(aFn: *mut c_void, aParam: *mut c_void);
36        pub fn wxEvtHandler_Bind(
37            self_: *mut c_void,
38            eventType: c_int,
39            aFn: *mut c_void,
40            aParam: *mut c_void,
41        );
42
43        // String
44        pub fn wxString_new(psz: *const c_uchar, nLength: usize) -> *mut c_void;
45        pub fn wxString_delete(self_: *mut c_void);
46        pub fn wxString_UTF8Data(self_: *mut c_void) -> UTF8Data;
47
48        // (wx)String::const_iterator
49        pub fn wxStringConstIterator_new() -> *mut c_void;
50        pub fn wxStringConstIterator_delete(self_: *mut c_void);
51        pub fn wxStringConstIterator_IndexIn(self_: *mut c_void, s: *const c_void) -> usize;
52
53        // ArrayInt
54        pub fn wxArrayInt_new() -> *mut c_void;
55        pub fn wxArrayInt_delete(self_: *mut c_void);
56        pub fn wxArrayInt_Add(self_: *mut c_void, i: c_int);
57        pub fn wxArrayInt_Item(self_: *mut c_void, index: usize) -> c_int;
58
59        // ArrayString
60        pub fn wxArrayString_new() -> *mut c_void;
61        pub fn wxArrayString_delete(self_: *mut c_void);
62        pub fn wxArrayString_Add(self_: *mut c_void, s: *const c_void);
63
64        pub fn wxRustEntry(argc: *mut c_int, argv: *mut *mut c_char) -> c_int;
65
66        // WeakRef
67        pub fn OpaqueWeakRef_new(obj: *mut c_void) -> *mut c_void;
68        pub fn OpaqueWeakRef_copy(obj: *mut c_void) -> *mut c_void;
69        pub fn OpaqueWeakRef_delete(self_: *mut c_void);
70        pub fn OpaqueWeakRef_Get(self_: *mut c_void) -> *mut c_void;
71
72        // DateTime
73        pub fn wxDateTime_ParseDate(
74            self_: *mut c_void,
75            date: *const c_void,
76            end: *mut c_void,
77        ) -> bool;
78    }
79}
80
81pub mod methods {
82    pub use super::generated::methods::*;
83    use super::*;
84
85    pub trait Bindable {
86        fn bind<E: EventMethods, F: Fn(&E) + 'static>(&self, event_type: RustEvent, closure: F);
87    }
88
89    pub trait ArrayIntMethods: WxRustMethods {
90        fn add(&self, i: c_int) {
91            unsafe { ffi::wxArrayInt_Add(self.as_ptr(), i) }
92        }
93        fn item(&self, index: usize) -> c_int {
94            unsafe { ffi::wxArrayInt_Item(self.as_ptr(), index) }
95        }
96    }
97
98    pub trait ArrayStringMethods: WxRustMethods {
99        fn add(&self, s: &str) {
100            unsafe {
101                let s = WxString::from(s);
102                ffi::wxArrayString_Add(self.as_ptr(), s.as_ptr())
103            }
104        }
105    }
106
107    pub trait StringConstIteratorMethods: WxRustMethods {
108        fn index_in(&self, s: *const c_void) -> usize {
109            unsafe { ffi::wxStringConstIterator_IndexIn(self.as_ptr(), s) }
110        }
111    }
112
113    // TODO: Support manual(semi-auto) binding in codegen
114    //
115    // This trait should be `DateTimeMethods` and, the base trait
116    // should be `DateTimeMethodsAuto` for API consistencey.
117    pub trait DateTimeMethodsManual: DateTimeMethods {
118        fn parse_date(&self, date: &str) -> Option<usize> {
119            unsafe {
120                let end = StringConstIterator::new();
121                let date = WxString::from(date);
122                let date = date.as_ptr();
123                if ffi::wxDateTime_ParseDate(self.as_ptr(), date, end.as_ptr()) {
124                    Some(end.index_in(date))
125                } else {
126                    None
127                }
128            }
129        }
130    }
131
132    pub trait DynamicCast: ObjectMethods {
133        fn class_info() -> ClassInfoIsOwned<false>;
134        fn as_unowned<T: DynamicCast>(&self) -> Option<T::Unowned> {
135            if self.is_kind_of(Some(&T::class_info())) {
136                unsafe { Some(T::from_unowned_ptr(self.as_ptr())) }
137            } else {
138                None
139            }
140        }
141    }
142
143    pub trait Trackable<T>: EvtHandlerMethods {
144        fn to_weak_ref(&self) -> WeakRef<T>;
145    }
146}
147
148// wxString
149pub struct WxString(*mut c_void);
150impl WxString {
151    pub unsafe fn from_ptr(ptr: *mut c_void) -> Self {
152        WxString(ptr)
153    }
154    pub unsafe fn as_ptr(&self) -> *mut c_void {
155        return self.0;
156    }
157    pub fn to_str<'a>(&'a self) -> &'a str {
158        unsafe {
159            let utf8 = ffi::wxString_UTF8Data(self.as_ptr());
160            let len = utf8.length;
161            let slice = slice::from_raw_parts(utf8.data, len);
162            str::from_utf8_unchecked(slice)
163        }
164    }
165}
166impl From<WxString> for String {
167    fn from(s: WxString) -> Self {
168        s.to_str().to_owned()
169    }
170}
171impl From<&str> for WxString {
172    fn from(s: &str) -> Self {
173        unsafe { WxString(ffi::wxString_new(s.as_ptr(), s.len())) }
174    }
175}
176impl Drop for WxString {
177    fn drop(&mut self) {
178        unsafe { ffi::wxString_delete(self.0) }
179    }
180}
181
182// Rust closure to wx calablle function+param pair.
183unsafe fn to_wx_callable<F: Fn(*mut c_void) + 'static>(closure: F) -> (*mut c_void, *mut c_void) {
184    unsafe fn trampoline<F: Fn(*mut c_void) + 'static>(closure: *mut c_void, arg: *mut c_void) {
185        let closure = &*(closure as *const F);
186        closure(arg);
187    }
188    // pass the pointer in the heap to avoid move.
189    let closure = Box::new(closure);
190    (trampoline::<F> as _, Box::into_raw(closure) as _)
191}
192
193// TODO auto generate
194pub enum RustEvent {
195    BookctrlPageChanged,
196    Button,
197    CheckBox,
198    Menu,
199    RadioBox,
200    Timer,
201}
202impl<T: EvtHandlerMethods> Bindable for T {
203    fn bind<E: EventMethods, F: Fn(&E) + 'static>(&self, event_type: RustEvent, closure: F) {
204        unsafe {
205            let (f, param) = to_wx_callable(move |arg: *mut c_void| {
206                E::with_ptr(arg, |event| {
207                    closure(event);
208                });
209            });
210            ffi::wxEvtHandler_Bind(self.as_ptr(), event_type as c_int, f, param);
211        }
212    }
213}
214
215// Effectively all wxEvtHandlers are wxTrackable.
216impl<T: EvtHandlerMethods> Trackable<T> for T {
217    fn to_weak_ref(&self) -> WeakRef<T> {
218        unsafe { WeakRef::from(self.as_ptr()) }
219    }
220}
221
222// wxApp
223pub enum App {}
224impl App {
225    pub fn on_init<F: Fn(*mut c_void) + 'static>(closure: F) {
226        unsafe {
227            let (f, param) = to_wx_callable(closure);
228            ffi::AppSetOnInit(f, param);
229        }
230    }
231    pub fn run<F: Fn(*mut c_void) + 'static>(closure: F) {
232        Self::on_init(closure);
233        entry();
234    }
235}
236
237wxwidgets! {
238    class ArrayInt
239        = ArrayIntIsOwned<true>(wxArrayInt) impl
240        ArrayIntMethods
241}
242impl<const OWNED: bool> ArrayIntIsOwned<OWNED> {
243    pub fn new() -> Self {
244        unsafe { ArrayIntIsOwned(ffi::wxArrayInt_new()) }
245    }
246}
247impl<const OWNED: bool> Drop for ArrayIntIsOwned<OWNED> {
248    fn drop(&mut self) {
249        if OWNED {
250            unsafe { ffi::wxArrayInt_delete(self.0) }
251        }
252    }
253}
254
255wxwidgets! {
256    class ArrayString
257        = ArrayStringIsOwned<true>(wxArrayString) impl
258        ArrayStringMethods
259}
260impl<const OWNED: bool> ArrayStringIsOwned<OWNED> {
261    pub fn new() -> Self {
262        unsafe { ArrayStringIsOwned(ffi::wxArrayString_new()) }
263    }
264}
265impl<const OWNED: bool> Drop for ArrayStringIsOwned<OWNED> {
266    fn drop(&mut self) {
267        if OWNED {
268            unsafe { ffi::wxArrayString_delete(self.0) }
269        }
270    }
271}
272
273// (wx)String::const_iterator
274wxwidgets! {
275    class StringConstIterator
276        = StringConstIteratorIsOwned<true>(wxStringConstIterator) impl
277        StringConstIteratorMethods
278}
279impl<const OWNED: bool> StringConstIteratorIsOwned<OWNED> {
280    pub fn new() -> Self {
281        unsafe { StringConstIteratorIsOwned(ffi::wxStringConstIterator_new()) }
282    }
283}
284impl<const OWNED: bool> Drop for StringConstIteratorIsOwned<OWNED> {
285    fn drop(&mut self) {
286        if OWNED {
287            unsafe { ffi::wxStringConstIterator_delete(self.0) }
288        }
289    }
290}
291
292// wxEntry
293pub fn entry() {
294    let args: Vec<String> = std::env::args().collect();
295    let mut argv: Vec<*mut c_char> = Vec::with_capacity(args.len() + 1);
296    for arg in &args {
297        argv.push(arg.as_ptr() as *mut c_char);
298    }
299    argv.push(ptr::null_mut()); // Nul terminator.
300    let mut argc: c_int = args.len().try_into().unwrap();
301    unsafe {
302        ffi::wxRustEntry(&mut argc, argv.as_mut_ptr());
303    }
304}
305
306// wxWeakRef
307pub struct WeakRef<T>(*mut c_void, PhantomData<T>);
308impl<T: WxRustMethods> WeakRef<T> {
309    pub unsafe fn from(ptr: *mut c_void) -> Self {
310        let ptr = if ptr.is_null() {
311            ptr
312        } else {
313            ffi::OpaqueWeakRef_new(ptr)
314        };
315        WeakRef(ptr, PhantomData)
316    }
317    pub fn get(&self) -> Option<T::Unowned> {
318        unsafe {
319            let ptr = self.0;
320            let ptr = if ptr.is_null() {
321                ptr
322            } else {
323                ffi::OpaqueWeakRef_Get(ptr)
324            };
325            if ptr.is_null() {
326                None
327            } else {
328                Some(T::from_unowned_ptr(ptr))
329            }
330        }
331    }
332}
333impl<T: WxRustMethods> Clone for WeakRef<T> {
334    fn clone(&self) -> Self {
335        unsafe {
336            let ptr = ffi::OpaqueWeakRef_copy(self.0);
337            WeakRef(ptr, PhantomData)
338        }
339    }
340}
341impl<T> Drop for WeakRef<T> {
342    fn drop(&mut self) {
343        unsafe { ffi::OpaqueWeakRef_delete(self.0) }
344    }
345}
346
347impl<const OWNED: bool> DateTimeMethodsManual for DateTimeIsOwned<OWNED> {}