playdate_menu/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3#[macro_use]
4extern crate sys;
5extern crate alloc;
6
7pub mod error;
8
9
10use alloc::borrow::Cow;
11use alloc::boxed::Box;
12use alloc::ffi::NulError;
13use core::ffi::c_int;
14use core::ffi::c_char;
15use core::ffi::c_void;
16use core::marker::PhantomData;
17use sys::ffi::PDMenuItemCallbackFunction;
18use sys::ffi::PDMenuItem;
19use sys::ffi::CStr;
20use sys::ffi::CString;
21
22use error::{Error, ApiError};
23
24
25pub type SimpleMenuItem<UserData = (), Api = api::Default, const REMOVE_ON_DROP: bool = true> =
26	MenuItem<kind::Simple, UserData, Api, REMOVE_ON_DROP>;
27
28pub type CheckMenuItem<UserData = (), Api = api::Default, const REMOVE_ON_DROP: bool = true> =
29	MenuItem<kind::Check, UserData, Api, REMOVE_ON_DROP>;
30
31pub type OptionsMenuItem<UserData = (), Api = api::Default, const REMOVE_ON_DROP: bool = true> =
32	MenuItem<kind::Options, UserData, Api, REMOVE_ON_DROP>;
33
34
35#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
36pub struct MenuItem<Kind, UserData = (), Api= api::Default, const REMOVE_ON_DROP: bool = true>(*mut PDMenuItem, Api, PhantomData<Kind>, PhantomData<UserData>) where Kind: kind::Kind, UserData: Into<Box<UserData>>, Api: api::Api;
37
38
39impl<UD, K: kind::Kind, Api: api::Api, const REM: bool> MenuItem<K, UD, Api, REM> {
40	/// Gets the display title of the menu item.
41	///
42	/// Returns [`sys::ffi::playdate_sys::getMenuItemTitle`]
43	#[doc(alias = "sys::ffi::playdate_sys::getMenuItemTitle")]
44	pub fn title(&self) -> Cow<'_, str> {
45		let f = self.1.get_menu_item_title();
46		unsafe { CStr::from_ptr(f(self.0) as _) }.to_string_lossy()
47	}
48
49	/// Sets the display title of the menu item.
50	///
51	/// Returns [`sys::ffi::playdate_sys::setMenuItemTitle`]
52	#[doc(alias = "sys::ffi::playdate_sys::setMenuItemTitle")]
53	pub fn set_title<S: AsRef<str>>(&self, title: S) -> Result<(), NulError> {
54		let f = self.1.set_menu_item_title();
55		let s = CString::new(title.as_ref())?;
56		unsafe { f(self.0, s.as_ptr() as *mut c_char) };
57		core::mem::drop(s);
58		Ok(())
59	}
60
61	pub fn get_userdata(&self) -> Option<&mut UD> { self.get_userdata_full().map(|(_, ud)| ud) }
62
63	fn get_userdata_full(&self) -> Option<&mut CallbackUserData<UD>> {
64		let f = self.1.get_menu_item_userdata();
65		let ptr = unsafe { f(self.0) };
66		if ptr.is_null()
67		/* TODO: check ptr is miss-aligned */
68		{
69			return None;
70		}
71
72		unsafe { (ptr as *mut CallbackUserData<UD>).as_mut() }
73	}
74
75	/// Set `userdata`, replace and return old userdata.
76	pub fn set_userdata(&self, userdata: UD) -> Option<UD> {
77		if let Some(existing) = self.get_userdata() {
78			core::mem::replace(existing, userdata).into()
79		} else {
80			todo!()
81		}
82	}
83
84	/// Gets the integer value of the menu item.
85	///
86	/// See also [`MenuItem::set_value`].
87	///
88	/// Equivalent to [`sys::ffi::playdate_sys::getMenuItemValue`]
89	#[doc(alias = "sys::ffi::playdate_sys::getMenuItemValue")]
90	pub fn value(&self) -> c_int {
91		let f = self.1.get_menu_item_value();
92		unsafe { f(self.0) }
93	}
94
95	/// Sets the integer value of the menu item.
96	///
97	/// For checkmark menu items ([`CheckMenuItem`]), `1` means checked, `0` unchecked.
98	///
99	/// For option menu items ([`OptionsMenuItem`]), the value indicates the array index of the currently selected option.
100	///
101	/// See also [`CheckMenuItem::is_checked`], [`OptionsMenuItem::selected_option`].
102	///
103	/// Equivalent to [`sys::ffi::playdate_sys::setMenuItemValue`]
104	#[doc(alias = "sys::ffi::playdate_sys::setMenuItemValue")]
105	pub fn set_value(&self, value: c_int) {
106		let f = self.1.set_menu_item_value();
107		unsafe { f(self.0, value) }
108	}
109
110
111	fn take_userdata(&mut self) -> Option<UD> {
112		if self.0.is_null() {
113			return None;
114		}
115
116		let f = self.1.get_menu_item_userdata();
117		let ptr = unsafe { f(self.0) };
118		if ptr.is_null() {
119			return None;
120		} else if core::mem::size_of::<UD>() == 0
121		// || ptr.addr() & (core::mem::align_of::<CallbackUserData<UD>>() - 1) != 0
122		{
123			// invalid pointer, mostly means that the userdata was not set/initialized
124			return None;
125		}
126
127		let ud: CallbackUserData<UD> = *unsafe { Box::from_raw(ptr as *mut CallbackUserData<UD>) };
128		let (_, userdata) = ud;
129		Some(userdata)
130	}
131}
132
133
134impl<UD: Sized, Api: api::Api, const REM: bool> MenuItem<kind::Check, UD, Api, REM> {
135	#[inline(always)]
136	pub fn new<S: AsRef<str>>(title: S,
137	                          checked: bool,
138	                          callback: Option<MenuItemCallback<UD>>,
139	                          userdata: UD)
140	                          -> Result<Self, ApiError>
141		where Api: Default
142	{
143		Self::new_with(Api::default(), title, checked, callback, userdata)
144	}
145
146	pub fn new_with<S: AsRef<str>>(api: Api,
147	                               title: S,
148	                               checked: bool,
149	                               callback: Option<MenuItemCallback<UD>>,
150	                               userdata: UD)
151	                               -> Result<Self, ApiError> {
152		let (callback, userdata) = proxy_menu_parts::<_, _>(callback, userdata);
153		let title = CString::new(title.as_ref())?;
154
155		let ctor = api.add_checkmark_menu_item();
156		let ptr = unsafe { ctor(title.as_ptr() as *mut c_char, checked as _, callback, userdata) };
157
158		if ptr.is_null() {
159			Err(Error::Alloc.into())
160		} else {
161			Ok(MenuItem(ptr, api, PhantomData, PhantomData))
162		}
163	}
164}
165
166
167impl<UD: Sized, Api: api::Api, const REM: bool> MenuItem<kind::Simple, UD, Api, REM> {
168	#[inline(always)]
169	pub fn new<S: AsRef<str>>(title: S,
170	                          callback: Option<MenuItemCallback<UD>>,
171	                          userdata: UD)
172	                          -> Result<Self, ApiError>
173		where Api: Default
174	{
175		Self::new_with(Api::default(), title, callback, userdata)
176	}
177
178	pub fn new_with<S: AsRef<str>>(api: Api,
179	                               title: S,
180	                               callback: Option<MenuItemCallback<UD>>,
181	                               userdata: UD)
182	                               -> Result<Self, ApiError> {
183		let (callback, userdata) = proxy_menu_parts::<_, _>(callback, userdata);
184		let title = CString::new(title.as_ref())?;
185
186		let ctor = api.add_menu_item();
187		let ptr = unsafe { ctor(title.as_ptr() as *mut c_char, callback, userdata) };
188
189		if ptr.is_null() {
190			Err(Error::Alloc.into())
191		} else {
192			Ok(MenuItem(ptr, api, PhantomData, PhantomData::<UD>))
193		}
194	}
195}
196
197impl<UD: Sized, Api: api::Api, const REM: bool> MenuItem<kind::Options, UD, Api, REM> {
198	#[inline(always)]
199	pub fn new<S: AsRef<str>, O: AsRef<[S]>>(title: S,
200	                                         options: O,
201	                                         callback: Option<MenuItemCallback<UD>>,
202	                                         userdata: UD)
203	                                         -> Result<Self, ApiError>
204		where Api: Default
205	{
206		Self::new_with(Api::default(), title, options, callback, userdata)
207	}
208
209	pub fn new_with<S: AsRef<str>, O: AsRef<[S]>>(api: Api,
210	                                              title: S,
211	                                              options: O,
212	                                              callback: Option<MenuItemCallback<UD>>,
213	                                              userdata: UD)
214	                                              -> Result<Self, ApiError> {
215		#[allow(unused_imports)]
216		use alloc::vec::Vec;
217
218
219		let (callback, userdata) = proxy_menu_parts::<_, _>(callback, userdata);
220		let title = CString::new(title.as_ref())?;
221
222		let options = options.as_ref();
223		let mut opts = Vec::with_capacity(options.len());
224		for opt in options {
225			let opt = CString::new(opt.as_ref())?;
226			opts.push(opt)
227		}
228		let mut ptrs = Vec::with_capacity(options.len());
229		ptrs.extend(opts.iter().map(|s| s.as_ptr()));
230
231		let ctor = api.add_options_menu_item();
232		let ptr = unsafe {
233			ctor(
234			     title.as_ptr() as *mut c_char,
235			     ptrs.as_mut_ptr() as _,
236			     ptrs.len() as _,
237			     callback,
238			     userdata,
239			)
240		};
241
242		core::mem::drop(ptrs);
243		core::mem::drop(opts);
244
245		if ptr.is_null() {
246			Err(Error::Alloc.into())
247		} else {
248			Ok(MenuItem(ptr, api, PhantomData, PhantomData::<UD>))
249		}
250	}
251}
252
253
254#[inline(always)]
255fn proxy_menu_parts<UD: Sized, F: FnMut(&mut UD)>(cb: Option<F>,
256                                                  ud: UD)
257                                                  -> (PDMenuItemCallbackFunction, *mut c_void) {
258	unsafe extern "C" fn proxy<UserData: Sized>(userdata: *mut c_void) {
259		if let Some((callback, userdata)) = (userdata as *mut CallbackUserData<UserData>).as_mut() {
260			callback(userdata)
261		} else {
262			panic!("user callback missed");
263		}
264	}
265
266	if let Some(callback) = cb {
267		// convert (callback, userdata) -> pointer:
268		let ptr = Box::into_raw(Box::from((callback, ud)));
269		(Some(proxy::<UD> as _), ptr as *mut _)
270	} else {
271		// we can get user data smaller:
272		// convert userdata -> pointer:
273		// let ptr = Box::into_raw(Box::from(userdata));
274		// Ok((None, ptr as _))
275
276		// but better to have same for consistency,
277		// required for get/set userdata:
278		fn noop<UserData: Sized>(_: &mut UserData) {}
279		let ptr = Box::into_raw(Box::from((noop::<UD>, ud)));
280		(None, ptr as *mut _)
281	}
282}
283
284
285impl<UD, Api: api::Api, const REM: bool> MenuItem<kind::Check, UD, Api, REM> {
286	/// Equivalent to [`sys::ffi::playdate_sys::getMenuItemValue`]
287	#[doc(alias = "sys::ffi::playdate_sys::getMenuItemValue")]
288	#[inline(always)]
289	pub fn is_checked(&self) -> bool { self.value() == 1 }
290}
291
292
293impl<UD, Api: api::Api, const REM: bool> MenuItem<kind::Options, UD, Api, REM> {
294	/// The array index of the currently selected option.
295	///
296	/// Equivalent to [`sys::ffi::playdate_sys::getMenuItemValue`]
297	#[doc(alias = "sys::ffi::playdate_sys::getMenuItemValue")]
298	#[inline(always)]
299	pub fn selected_option(&self) -> i32 { self.value() }
300}
301
302
303impl<UD, K: kind::Kind, Api: api::Api, const REM: bool> Drop for MenuItem<K, UD, Api, REM> {
304	fn drop(&mut self) {
305		if REM && !self.0.is_null() {
306			// we have to drop userdata:
307			self.take_userdata();
308			let f = self.1.remove_menu_item();
309			unsafe { f(self.0) };
310		}
311	}
312}
313
314impl<UD, K: kind::Kind, Api: api::Api, const REM: bool> MenuItem<K, UD, Api, REM> {
315	#[inline(always)]
316	pub fn remove(mut self) -> Option<UD> {
317		let ud = self.take_userdata();
318
319		let f = self.1.remove_menu_item();
320		unsafe { f(self.0) };
321		self.0 = core::ptr::null_mut() as _;
322
323		ud
324	}
325}
326
327
328/// Removes all custom menu items from the system menu.
329///
330/// Equivalent to [`sys::ffi::playdate_sys::removeAllMenuItems`]
331#[doc(alias = "sys::ffi::playdate_sys::removeAllMenuItems")]
332#[inline(always)]
333pub fn remove_all_menu_items() { remove_all_menu_items_with(api::Default::default()) }
334
335/// Removes all custom menu items from the system menu.
336///
337/// Uses given `api`.
338///
339/// Equivalent to [`sys::ffi::playdate_sys::removeAllMenuItems`]
340#[doc(alias = "sys::ffi::playdate_sys::removeAllMenuItems")]
341pub fn remove_all_menu_items_with<Api: api::Api>(api: Api) {
342	let f = api.remove_all_menu_items();
343	unsafe { f() };
344}
345
346
347pub trait SystemMenu<Api: api::Api + Copy> {
348	/// Removes all custom menu items from the system menu.
349	///
350	/// Equivalent to [`sys::ffi::playdate_sys::removeAllMenuItems`]
351	#[doc(alias = "sys::ffi::playdate_sys::removeAllMenuItems")]
352	fn remove_all_menu_items(&self);
353}
354
355impl<Api: system::api::Api + api::Api + Copy> SystemMenu<Api> for system::System<Api> {
356	#[inline(always)]
357	fn remove_all_menu_items(&self) { remove_all_menu_items_with(self.inner()) }
358}
359
360
361type CallbackUserData<UserData> = (MenuItemCallback<UserData>, UserData);
362type MenuItemCallback<T> = fn(userdata: &mut T);
363
364
365pub mod kind {
366	pub trait Kind {}
367
368
369	#[derive(Debug)]
370	pub struct Simple;
371
372	#[derive(Debug)]
373	pub struct Check;
374
375	#[derive(Debug)]
376	pub struct Options;
377
378	impl Kind for Simple {}
379	impl Kind for Check {}
380	impl Kind for Options {}
381}
382
383
384pub mod api {
385	use core::ffi::c_char;
386	use core::ffi::c_int;
387	use core::ffi::c_void;
388	use core::ptr::NonNull;
389	use sys::ffi::PDMenuItem;
390	use sys::ffi::PDMenuItemCallbackFunction;
391	use sys::ffi::playdate_sys;
392
393
394	/// Default system menu api end-point, ZST.
395	///
396	/// All calls approximately costs ~3 derefs.
397	#[derive(Debug, Clone, Copy, core::default::Default)]
398	pub struct Default;
399	impl Api for Default {}
400
401
402	/// Cached system menu api end-point.
403	///
404	/// Stores one reference, so size on stack is eq `usize`.
405	///
406	/// All calls approximately costs ~1 deref.
407	#[derive(Clone, Copy)]
408	#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
409	pub struct Cache(&'static playdate_sys);
410
411	impl core::default::Default for Cache {
412		fn default() -> Self { Self(api!(system)) }
413	}
414
415	impl From<*const playdate_sys> for Cache {
416		#[inline(always)]
417		fn from(ptr: *const playdate_sys) -> Self { Self(unsafe { ptr.as_ref() }.expect("system")) }
418	}
419
420	impl From<&'static playdate_sys> for Cache {
421		#[inline(always)]
422		fn from(r: &'static playdate_sys) -> Self { Self(r) }
423	}
424
425	impl From<NonNull<playdate_sys>> for Cache {
426		#[inline(always)]
427		fn from(ptr: NonNull<playdate_sys>) -> Self { Self(unsafe { ptr.as_ref() }) }
428	}
429
430	impl From<&'_ NonNull<playdate_sys>> for Cache {
431		#[inline(always)]
432		fn from(ptr: &NonNull<playdate_sys>) -> Self { Self(unsafe { ptr.as_ref() }) }
433	}
434
435	impl From<system::api::Cache> for Cache {
436		#[inline(always)]
437		fn from(api: system::api::Cache) -> Self { Self(api.as_inner()) }
438	}
439
440	impl Api for system::api::Default {}
441
442	impl Api for system::api::Cache {
443		#[inline(always)]
444		fn add_menu_item(
445			&self)
446			-> unsafe extern "C" fn(title: *const c_char,
447			                        callback: PDMenuItemCallbackFunction,
448			                        userdata: *mut c_void) -> *mut PDMenuItem {
449			self.as_inner().addMenuItem.expect("addMenuItem")
450		}
451
452		#[inline(always)]
453		fn add_checkmark_menu_item(
454			&self)
455			-> unsafe extern "C" fn(title: *const c_char,
456			                        value: c_int,
457			                        callback: PDMenuItemCallbackFunction,
458			                        userdata: *mut c_void) -> *mut PDMenuItem {
459			self.as_inner()
460			    .addCheckmarkMenuItem
461			    .expect("addCheckmarkMenuItem")
462		}
463
464		#[inline(always)]
465		fn add_options_menu_item(
466			&self)
467			-> unsafe extern "C" fn(title: *const c_char,
468			                        optionTitles: *mut *const c_char,
469			                        optionsCount: c_int,
470			                        f: PDMenuItemCallbackFunction,
471			                        userdata: *mut c_void) -> *mut PDMenuItem {
472			self.as_inner().addOptionsMenuItem.expect("addOptionsMenuItem")
473		}
474
475		#[inline(always)]
476		fn remove_menu_item(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) {
477			self.as_inner().removeMenuItem.expect("removeMenuItem")
478		}
479
480		#[inline(always)]
481		fn get_menu_item_value(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> c_int {
482			self.as_inner().getMenuItemValue.expect("getMenuItemValue")
483		}
484
485		#[inline(always)]
486		fn set_menu_item_value(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem, value: c_int) {
487			self.as_inner().setMenuItemValue.expect("setMenuItemValue")
488		}
489
490		#[inline(always)]
491		fn get_menu_item_title(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> *const c_char {
492			self.as_inner().getMenuItemTitle.expect("getMenuItemTitle")
493		}
494
495		#[inline(always)]
496		fn set_menu_item_title(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem, title: *const c_char) {
497			self.as_inner().setMenuItemTitle.expect("setMenuItemTitle")
498		}
499
500		#[inline(always)]
501		fn get_menu_item_userdata(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> *mut c_void {
502			self.as_inner().getMenuItemUserdata.expect("getMenuItemUserdata")
503		}
504
505		#[inline(always)]
506		fn remove_all_menu_items(&self) -> unsafe extern "C" fn() {
507			self.as_inner().removeAllMenuItems.expect("removeAllMenuItems")
508		}
509	}
510
511
512	impl Api for Cache {
513		#[inline(always)]
514		fn add_menu_item(
515			&self)
516			-> unsafe extern "C" fn(title: *const c_char,
517			                        callback: PDMenuItemCallbackFunction,
518			                        userdata: *mut c_void) -> *mut PDMenuItem {
519			self.0.addMenuItem.expect("addMenuItem")
520		}
521
522		#[inline(always)]
523		fn add_checkmark_menu_item(
524			&self)
525			-> unsafe extern "C" fn(title: *const c_char,
526			                        value: c_int,
527			                        callback: PDMenuItemCallbackFunction,
528			                        userdata: *mut c_void) -> *mut PDMenuItem {
529			self.0.addCheckmarkMenuItem.expect("addCheckmarkMenuItem")
530		}
531
532		#[inline(always)]
533		fn add_options_menu_item(
534			&self)
535			-> unsafe extern "C" fn(title: *const c_char,
536			                        optionTitles: *mut *const c_char,
537			                        optionsCount: c_int,
538			                        f: PDMenuItemCallbackFunction,
539			                        userdata: *mut c_void) -> *mut PDMenuItem {
540			self.0.addOptionsMenuItem.expect("addOptionsMenuItem")
541		}
542
543		#[inline(always)]
544		fn remove_menu_item(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) {
545			self.0.removeMenuItem.expect("removeMenuItem")
546		}
547
548		#[inline(always)]
549		fn get_menu_item_value(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> c_int {
550			self.0.getMenuItemValue.expect("getMenuItemValue")
551		}
552
553		#[inline(always)]
554		fn set_menu_item_value(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem, value: c_int) {
555			self.0.setMenuItemValue.expect("setMenuItemValue")
556		}
557
558		#[inline(always)]
559		fn get_menu_item_title(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> *const c_char {
560			self.0.getMenuItemTitle.expect("getMenuItemTitle")
561		}
562
563		#[inline(always)]
564		fn set_menu_item_title(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem, title: *const c_char) {
565			self.0.setMenuItemTitle.expect("setMenuItemTitle")
566		}
567
568		#[inline(always)]
569		fn get_menu_item_userdata(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> *mut c_void {
570			self.0.getMenuItemUserdata.expect("getMenuItemUserdata")
571		}
572
573		#[inline(always)]
574		fn remove_all_menu_items(&self) -> unsafe extern "C" fn() {
575			self.0.removeAllMenuItems.expect("removeAllMenuItems")
576		}
577	}
578
579
580	pub trait Api {
581		/// Returns [`sys::ffi::playdate_sys::addMenuItem`]
582		#[doc(alias = "sys::ffi::playdate_sys::addMenuItem")]
583		fn add_menu_item(
584			&self)
585			-> unsafe extern "C" fn(title: *const c_char,
586			                        callback: PDMenuItemCallbackFunction,
587			                        userdata: *mut c_void) -> *mut PDMenuItem {
588			*sys::api!(system.addMenuItem)
589		}
590
591		/// Returns [`sys::ffi::playdate_sys::addCheckmarkMenuItem`]
592		#[doc(alias = "sys::ffi::playdate_sys::addCheckmarkMenuItem")]
593		fn add_checkmark_menu_item(
594			&self)
595			-> unsafe extern "C" fn(title: *const c_char,
596			                        value: c_int,
597			                        callback: PDMenuItemCallbackFunction,
598			                        userdata: *mut c_void) -> *mut PDMenuItem {
599			*sys::api!(system.addCheckmarkMenuItem)
600		}
601
602		/// Returns [`sys::ffi::playdate_sys::addOptionsMenuItem`]
603		#[doc(alias = "sys::ffi::playdate_sys::addOptionsMenuItem")]
604		fn add_options_menu_item(
605			&self)
606			-> unsafe extern "C" fn(title: *const c_char,
607			                        optionTitles: *mut *const c_char,
608			                        optionsCount: c_int,
609			                        f: PDMenuItemCallbackFunction,
610			                        userdata: *mut c_void) -> *mut PDMenuItem {
611			*sys::api!(system.addOptionsMenuItem)
612		}
613
614		/// Returns [`sys::ffi::playdate_sys::removeMenuItem`]
615		#[doc(alias = "sys::ffi::playdate_sys::removeMenuItem")]
616		fn remove_menu_item(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) {
617			*sys::api!(system.removeMenuItem)
618		}
619
620		/// Returns [`sys::ffi::playdate_sys::getMenuItemValue`]
621		#[doc(alias = "sys::ffi::playdate_sys::getMenuItemValue")]
622		fn get_menu_item_value(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> c_int {
623			*sys::api!(system.getMenuItemValue)
624		}
625
626		/// Returns [`sys::ffi::playdate_sys::setMenuItemValue`]
627		#[doc(alias = "sys::ffi::playdate_sys::setMenuItemValue")]
628		fn set_menu_item_value(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem, value: c_int) {
629			*sys::api!(system.setMenuItemValue)
630		}
631
632		/// Returns [`sys::ffi::playdate_sys::getMenuItemTitle`]
633		#[doc(alias = "sys::ffi::playdate_sys::getMenuItemTitle")]
634		fn get_menu_item_title(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> *const c_char {
635			*sys::api!(system.getMenuItemTitle)
636		}
637
638		/// Returns [`sys::ffi::playdate_sys::setMenuItemTitle`]
639		#[doc(alias = "sys::ffi::playdate_sys::setMenuItemTitle")]
640		fn set_menu_item_title(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem, title: *const c_char) {
641			*sys::api!(system.setMenuItemTitle)
642		}
643
644		/// Returns [`sys::ffi::playdate_sys::getMenuItemUserdata`]
645		#[doc(alias = "sys::ffi::playdate_sys::getMenuItemUserdata")]
646		fn get_menu_item_userdata(&self) -> unsafe extern "C" fn(menuItem: *mut PDMenuItem) -> *mut c_void {
647			*sys::api!(system.getMenuItemUserdata)
648		}
649
650		/// Returns [`sys::ffi::playdate_sys::removeAllMenuItems`]
651		#[doc(alias = "sys::ffi::playdate_sys::removeAllMenuItems")]
652		fn remove_all_menu_items(&self) -> unsafe extern "C" fn() { *sys::api!(system.removeAllMenuItems) }
653	}
654}