fltk/macros/
menu.rs

1#[doc(hidden)]
2#[macro_export]
3/// Implements MenuExt
4macro_rules! impl_menu_ext {
5    ($name: ident, $flname: ident) => {
6        impl IntoIterator for $name {
7            type Item = MenuItem;
8            type IntoIter = std::vec::IntoIter<Self::Item>;
9
10            fn into_iter(self) -> Self::IntoIter {
11                let mut v: Vec<MenuItem> = vec![];
12                for i in 0..self.size() {
13                    v.push(self.at(i).unwrap());
14                }
15                v.into_iter()
16            }
17        }
18
19        paste::paste! {
20            unsafe impl MenuExt for $name {
21                fn add<F: FnMut(&mut Self) + 'static>(
22                    &mut self,
23                    name: &str,
24                    shortcut: $crate::enums::Shortcut,
25                    flag: MenuFlag,
26                    cb: F,
27                ) -> i32 {
28                    let temp = CString::safe_new(name);
29                    unsafe {
30                    unsafe extern "C" fn shim(wid: *mut Fl_Widget, data: *mut std::os::raw::c_void) { unsafe {
31                            let mut wid = $crate::widget::Widget::from_widget_ptr(wid as *mut _);
32                            let a: *mut Box<dyn FnMut(&mut $crate::widget::Widget)> =
33                                data as *mut Box<dyn FnMut(&mut $crate::widget::Widget)>;
34                            let f: &mut dyn FnMut(&mut $crate::widget::Widget) = &mut **a;
35                            let _ =
36                                std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&mut wid)));
37                        }}
38                        let a: *mut Box<dyn FnMut(&mut Self)> = Box::into_raw(Box::new(Box::new(cb)));
39                        let data: *mut std::os::raw::c_void = a as *mut std::os::raw::c_void;
40                        let callback: Fl_Callback = Some(shim);
41                        [<$flname _add>](
42                            self.inner.widget() as _,
43                            temp.as_ptr(),
44                            shortcut.bits() as i32,
45                            callback,
46                            data,
47                            flag.bits(),
48                        )
49                    }
50                }
51
52                fn insert<F: FnMut(&mut Self) + 'static>(
53                    &mut self,
54                    idx: i32,
55                    name: &str,
56                    shortcut: $crate::enums::Shortcut,
57                    flag: MenuFlag,
58                    cb: F,
59                ) -> i32 {
60                    let idx = if idx < self.size() && idx >= 0 {
61                        idx
62                    } else {
63                        if self.size() == 0 {
64                            0
65                        } else {
66                            self.size() - 1
67                        }
68                    };
69                    let temp = CString::safe_new(name);
70                    unsafe {
71                    unsafe extern "C" fn shim(wid: *mut Fl_Widget, data: *mut std::os::raw::c_void) { unsafe {
72                            let mut wid = $crate::widget::Widget::from_widget_ptr(wid as *mut _);
73                            let a: *mut Box<dyn FnMut(&mut $crate::widget::Widget)> =
74                                data as *mut Box<dyn FnMut(&mut $crate::widget::Widget)>;
75                            let f: &mut dyn FnMut(&mut $crate::widget::Widget) = &mut **a;
76                            let _ =
77                                std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&mut wid)));
78                        }}
79                        let a: *mut Box<dyn FnMut(&mut Self)> = Box::into_raw(Box::new(Box::new(cb)));
80                        let data: *mut std::os::raw::c_void = a as *mut std::os::raw::c_void;
81                        let callback: Fl_Callback = Some(shim);
82                        [<$flname _insert>](
83                            self.inner.widget() as _,
84                            idx as i32,
85                            temp.as_ptr(),
86                            shortcut.bits() as i32,
87                            callback,
88                            data,
89                            flag.bits(),
90                        )
91                    }
92                }
93
94                fn add_emit<T: 'static + Clone + Send + Sync>(
95                    &mut self,
96                    label: &str,
97                    shortcut: $crate::enums::Shortcut,
98                    flag: $crate::menu::MenuFlag,
99                    sender: $crate::app::Sender<T>,
100                    msg: T,
101                ) -> i32 {
102                    self.add(label, shortcut, flag, move |_| sender.send(msg.clone()))
103                }
104
105                fn insert_emit<T: 'static + Clone + Send + Sync>(
106                    &mut self,
107                    idx: i32,
108                    label: &str,
109                    shortcut: $crate::enums::Shortcut,
110                    flag: $crate::menu::MenuFlag,
111                    sender: $crate::app::Sender<T>,
112                    msg: T,
113                ) -> i32 {
114                    self.insert(idx, label, shortcut, flag, move |_| {
115                        sender.send(msg.clone())
116                    })
117                }
118
119                fn remove(&mut self, idx: i32) {
120                    assert!(self.size() != 0 && idx >= 0 && idx < self.size());
121                    unsafe { [<$flname _remove>](self.inner.widget() as _, idx as i32) }
122                }
123
124                fn find_item(&self, name: &str) -> Option<MenuItem> {
125                    let name = CString::safe_new(name);
126                    unsafe {
127                        let menu_item = [<$flname _get_item>](self.inner.widget() as _, name.as_ptr());
128                        if menu_item.is_null() {
129                            None
130                        } else {
131                            Some(MenuItem::from_ptr(
132                                menu_item
133                            ))
134                        }
135                    }
136                }
137
138                fn set_item(&mut self, item: &MenuItem) -> bool {
139                    unsafe {
140                        [<$flname _set_item>](self.inner.widget() as _, item.as_ptr()) != 0
141                    }
142                }
143
144                fn find_index(&self, label: &str) -> i32 {
145                    let label = CString::safe_new(label);
146                    unsafe { [<$flname _find_index>](self.inner.widget() as _, label.as_ptr()) as i32 }
147                }
148
149                fn text_font(&self) -> $crate::enums::Font {
150                    unsafe {
151                        std::mem::transmute([<$flname _text_font>](self.inner.widget() as _))
152                    }
153                }
154
155                fn set_text_font(&mut self, c: $crate::enums::Font) {
156                    unsafe {
157                        [<$flname _set_text_font>](self.inner.widget() as _, c.bits() as i32)
158                    }
159                }
160
161                fn text_size(&self) -> i32 {
162                    unsafe {
163                        [<$flname _text_size>](self.inner.widget() as _) as i32
164                    }
165                }
166
167                fn set_text_size(&mut self, c: i32) {
168                    unsafe {
169                        [<$flname _set_text_size>](self.inner.widget() as _, c as i32)
170                    }
171                }
172
173                fn text_color(&self) -> $crate::enums::Color {
174                    unsafe {
175                        std::mem::transmute([<$flname _text_color>](self.inner.widget() as _))
176                    }
177                }
178
179                fn set_text_color(&mut self, c: $crate::enums::Color) {
180                    unsafe {
181                        [<$flname _set_text_color>](self.inner.widget() as _, c.bits() as u32)
182                    }
183                }
184
185                fn add_choice(&mut self, text: &str) -> i32 {
186                    unsafe {
187                        let arg2 = CString::safe_new(text);
188                        [<$flname _add_choice>](
189                            self.inner.widget() as _,
190                            arg2.as_ptr() as *mut std::os::raw::c_char,
191                        )
192                    }
193                }
194
195                fn choice(&self) -> Option<String> {
196                    unsafe {
197                        let choice_ptr = [<$flname _get_choice>](self.inner.widget() as _);
198                        if choice_ptr.is_null() {
199                            None
200                        } else {
201                            Some(
202                                CStr::from_ptr(choice_ptr as *mut std::os::raw::c_char)
203                                    .to_string_lossy()
204                                    .to_string(),
205                            )
206                        }
207                    }
208                }
209
210                fn value(&self) -> i32 {
211                    unsafe {
212                        [<$flname _value>](self.inner.widget() as _)
213                    }
214                }
215
216                fn set_value(&mut self, v: i32) -> bool {
217                    unsafe {
218                        [<$flname _set_value>](self.inner.widget() as _, v) != 0
219                    }
220                }
221
222                fn clear(&mut self) {
223                    unsafe {
224                        if $crate::app::grab().is_none() {
225                            [<$flname _clear>](self.inner.widget() as _);
226                        }
227                    }
228                }
229
230                unsafe fn unsafe_clear(&mut self) { unsafe {
231                    let sz = self.size();
232                    if sz > 0 {
233                        for i in 0..sz {
234                            // Shouldn't fail
235                            let c = self.at(i).unwrap();
236                            let _ = c.user_data();
237                        }
238                    }
239                    [<$flname _clear>](self.inner.widget() as _);
240                }}
241
242                fn clear_submenu(&mut self, idx: i32) -> Result<(), FltkError> {
243                    unsafe {
244                        assert!(self.size() != 0 && idx >= 0 && idx < self.size());
245                        match [<$flname _clear_submenu>](self.inner.widget() as _, idx as i32) {
246                            0 => Ok(()),
247                            _ => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
248                        }
249                    }
250                }
251
252                unsafe fn unsafe_clear_submenu(&mut self, idx: i32) -> Result<(), FltkError> { unsafe {
253                    let x = self.at(idx);
254                    if x.is_none() {
255                        return Err(FltkError::Internal(FltkErrorKind::FailedOperation));
256                    }
257                    // Shouldn't fail
258                    let x = x.unwrap();
259                    if !x.is_submenu() {
260                        return Err(FltkError::Internal(FltkErrorKind::FailedOperation));
261                    }
262                    let mut i = idx;
263                    loop {
264                        // Shouldn't fail
265                        let item = self.at(i).unwrap();
266                        if item.label().is_none() {
267                            break;
268                        }
269                        let _ = item.user_data();
270                        i += 1;
271                    }
272                    match [<$flname _clear_submenu>](self.inner.widget() as _, idx as i32) {
273                        0 => Ok(()),
274                        _ => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
275                    }
276                }}
277
278                fn size(&self) -> i32 {
279                    unsafe { [<$flname _size>](self.inner.widget() as _) as i32 }
280                }
281
282                fn text(&self, idx: i32) -> Option<String> {
283                    assert!(self.size() != 0 && idx >= 0 && idx < self.size());
284                    unsafe {
285                        let text = [<$flname _text>](self.inner.widget() as _, idx as i32);
286                        if text.is_null() {
287                            None
288                        } else {
289                            Some(
290                                CStr::from_ptr(text as *mut std::os::raw::c_char)
291                                    .to_string_lossy()
292                                    .to_string(),
293                            )
294                        }
295                    }
296                }
297
298                fn at(&self, idx: i32) -> Option<$crate::menu::MenuItem> {
299                    assert!(self.size() != 0 && idx >= 0 && idx < self.size());
300                    unsafe {
301                        let ptr =
302                            [<$flname _at>](self.inner.widget() as _, idx as i32) as *mut Fl_Menu_Item;
303                        if ptr.is_null() {
304                            None
305                        } else {
306                            Some(MenuItem::from_ptr(ptr))
307                        }
308                    }
309                }
310
311                fn mode(&self, idx: i32) -> $crate::menu::MenuFlag {
312                    assert!(self.size() != 0 && idx >= 0 && idx < self.size());
313                    unsafe { std::mem::transmute([<$flname _mode>](self.inner.widget() as _, idx as i32)) }
314                }
315
316                fn set_mode(&mut self, idx: i32, flag: $crate::menu::MenuFlag) {
317                    assert!(self.size() != 0 && idx >= 0 && idx < self.size());
318                    unsafe { [<$flname _set_mode>](self.inner.widget() as _, idx as i32, flag.bits()) }
319                }
320
321                fn end(&mut self) {
322                    //
323                }
324
325                fn set_down_frame(&mut self, f: $crate::enums::FrameType) {
326                    unsafe { [<$flname _set_down_box>](self.inner.widget() as _, f.as_i32()) }
327                }
328
329                fn down_frame(&self) -> $crate::enums::FrameType {
330                    unsafe { $crate::enums::FrameType::from_i32([<$flname _down_box>](self.inner.widget() as _)) }
331                }
332
333                fn global(&mut self) {
334                    unsafe { [<$flname _global>](self.inner.widget() as _) }
335                }
336
337                fn menu(&self) -> Option<$crate::menu::MenuItem> {
338                    unsafe {
339                        let ptr = [<$flname _menu>](self.inner.widget() as _);
340                        if ptr.is_null() {
341                            None
342                        } else {
343                            Some(MenuItem::from_ptr(ptr as _))
344                        }
345                    }
346                }
347
348                unsafe fn set_menu(&mut self, item: $crate::menu::MenuItem) { unsafe {
349                    [<$flname _set_menu>](self.inner.widget() as _, item.as_ptr())
350                }}
351
352                fn item_pathname(&self, item: Option<&$crate::menu::MenuItem>) -> Result<String, FltkError> {
353                    let item = if let Some(item) = item {
354                    unsafe { item.as_ptr() }
355                    } else {
356                        std::ptr::null_mut()
357                    };
358                    let mut temp = vec![0u8; 256];
359                    unsafe {
360                        let ret = [<$flname _item_pathname>](self.inner.widget() as _, temp.as_mut_ptr() as _, 256, item);
361                        if ret == 0 {
362                            if let Some(pos) = temp.iter().position(|x| *x == 0) {
363                                temp = temp.split_at(pos).0.to_vec();
364                            }
365                            Ok(String::from_utf8_lossy(&temp).to_string())
366                        } else {
367                            Err(FltkError::Internal(FltkErrorKind::FailedOperation))
368                        }
369                    }
370                }
371
372                fn set_menu_frame(&mut self, f: $crate::enums::FrameType) {
373                    unsafe { [<$flname _set_menu_box>](self.inner.widget() as _, f.as_i32()) }
374                }
375
376                fn menu_frame(&self) -> $crate::enums::FrameType {
377                    unsafe { $crate::enums::FrameType::from_i32([<$flname _menu_box>](self.inner.widget() as _)) }
378                }
379
380                fn mvalue(&self) -> Option<$crate::menu::MenuItem> {
381                    unsafe {
382                        let ptr =
383                            [<$flname _mvalue>](self.inner.widget() as _) as *mut Fl_Menu_Item;
384                        if ptr.is_null() {
385                            None
386                        } else {
387                            Some(MenuItem::from_ptr(ptr))
388                        }
389                    }
390                }
391
392                fn prev_mvalue(&self) -> Option<$crate::menu::MenuItem> {
393                    unsafe {
394                        let ptr =
395                            [<$flname _prev_mvalue>](self.inner.widget() as _) as *mut Fl_Menu_Item;
396                        if ptr.is_null() {
397                            None
398                        } else {
399                            Some(MenuItem::from_ptr(ptr))
400                        }
401                    }
402                }
403            }
404        }
405    };
406}
407
408pub use impl_menu_ext;