1#[doc(hidden)]
2#[macro_export]
3macro_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 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 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 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 }
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;