From e9663483211b64b0e389440b102b6b944ebc24a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?joseLu=C3=ADs?= Date: Sat, 26 Dec 2020 06:16:54 +0100 Subject: [PATCH] rust: add NcMenu methods & fix error_ptr macro --- rust/src/macros.rs | 4 +- rust/src/widgets/menu/methods.rs | 193 ++++++++++++++++++++++++++++--- rust/src/widgets/menu/mod.rs | 37 +++--- 3 files changed, 204 insertions(+), 30 deletions(-) diff --git a/rust/src/macros.rs b/rust/src/macros.rs index de04f1082..acf78bcec 100644 --- a/rust/src/macros.rs +++ b/rust/src/macros.rs @@ -138,13 +138,14 @@ macro_rules! error { macro_rules! error_ptr { ($ptr:expr, $msg:expr) => { if $ptr != core::ptr::null_mut() { + #[allow(unused_unsafe)] return Ok(unsafe { &mut *$ptr }); } else { return Err(crate::NcError::with_msg(crate::NCRESULT_ERR, $msg)); } }; ($ptr:expr) => { - error![$ptr, (), ""]; + error_ptr![$ptr, ""]; }; } @@ -160,6 +161,7 @@ macro_rules! error_ptr { macro_rules! error_str { ($str:expr, $msg:expr) => { if $str != core::ptr::null_mut() { + #[allow(unused_unsafe)] return Ok(unsafe { (&*$str).to_string() }); } else { return Err(crate::NcError::with_msg(crate::NCRESULT_ERR, $msg)); diff --git a/rust/src/widgets/menu/methods.rs b/rust/src/widgets/menu/methods.rs index 70981acfa..0da78feff 100644 --- a/rust/src/widgets/menu/methods.rs +++ b/rust/src/widgets/menu/methods.rs @@ -1,31 +1,198 @@ //! `NcMenu*` methods and associated functions. +use core::ptr::null_mut; + use crate::{ - cstring, ncmenu_create, NcChannelPair, NcInput, NcMenu, NcMenuItem, NcMenuOptions, - NcMenuSection, NcPlane, + cstring, error, error_ptr, error_str, ncmenu_create, NcChannelPair, NcInput, NcMenu, + NcMenuItem, NcMenuOptions, NcMenuSection, NcPlane, NcResult, }; -/// # `NcMenu` Constructors +/// # `NcMenu` constructors & destructors impl NcMenu { - /// `NcMenu` simple constructor - pub fn new<'a>(plane: &mut NcPlane) -> &'a mut Self { - Self::with_options(plane, &NcMenuOptions::new()) + /// New NcMenu. + /// + /// *C style function: [ncmenu_create()][crate::ncmenu_create].* + pub fn new<'a>(plane: &mut NcPlane) -> NcResult<&'a mut Self> { + Self::with_options(plane, NcMenuOptions::new()) + } + + /// Creates an [NcMenu] with the specified options. + /// + /// Menus are currently bound to an overall [Notcurses][crate::Notcurses] + /// object (as opposed to a particular plane), and are implemented as + /// [NcPlane]s kept atop other NcPlanes. + /// + /// *C style function: [ncmenu_create()][crate::ncmenu_create].* + pub fn with_options<'a>(plane: &mut NcPlane, options: NcMenuOptions) -> NcResult<&'a mut Self> { + error_ptr![ + unsafe { ncmenu_create(plane, &options) }, + "Creating NcMenu" + ] + } + + /// Destroys an NcMenu created with [create()][NcMenu#method.create]. + /// + /// *C style function: [ncmenu_destroy()][crate::ncmenu_destroy].* + pub fn ncmenu_destroy(&mut self) -> NcResult<()> { + error![unsafe { crate::ncmenu_destroy(self) }] + } +} + +/// # `NcMenu` methods +impl NcMenu { + /// Disables or enables an [NcMenuItem]. + /// + /// *C style function: [ncmenu_item_set_status()][crate::ncmenu_item_set_status].* + pub fn ncmenu_item_set_status( + &mut self, + section: &str, + item: &str, + enabled: bool, + ) -> NcResult<()> { + error![unsafe { + crate::ncmenu_item_set_status(self, cstring![section], cstring![item], enabled) + }] + } + + /// Returns the [NcMenuItem] description corresponding to the mouse click `click`. + /// + /// The [NcMenuItem] must be on an actively unrolled section, and the click + /// must be in the area of a valid item. + /// + /// If `ninput` is provided, and the selected item has a shortcut, + /// it will be filled in with that shortcut. + /// + /// *C style function: [ncmenu_mouse_selected()][crate::ncmenu_mouse_selected].* + pub fn ncmenu_mouse_selected( + &self, + click: &NcInput, + shortcut: Option<&mut NcInput>, + ) -> NcResult { + let ninput; + if let Some(i) = shortcut { + ninput = i as *mut _; + } else { + ninput = null_mut(); + } + error_str![ + unsafe { crate::ncmenu_mouse_selected(self, click, ninput) }, + "Getting NcMenuItem description" + ] + } + + /// Moves to the next item within the currently unrolled section. + /// + /// If no section is unrolled, the first section will be unrolled. + /// + /// *C style function: [ncmenu_nextitem()][crate::ncmenu_nextitem].* + pub fn ncmenu_nextitem(&mut self) -> NcResult<()> { + error![unsafe { crate::ncmenu_nextitem(self) }] + } + + /// Unrolls the next section (relative to current unrolled). + /// + /// If no section is unrolled, the first section will be unrolled. + /// + /// *C style function: [ncmenu_nextsection()][crate::ncmenu_nextsection].* + pub fn ncmenu_nextsection(&mut self) -> NcResult<()> { + error![unsafe { crate::ncmenu_nextsection(self) }] + } + + /// Offers the `input` to this NcMenu. + /// + /// If it's relevant, this function returns true, + /// and the input ought not be processed further. + /// If it's irrelevant to the menu, false is returned. + /// + /// Relevant inputs include: + /// - mouse movement over a hidden menu + /// - a mouse click on a menu section (the section is unrolled) + /// - a mouse click outside of an unrolled menu (the menu is rolled up) + /// - left or right on an unrolled menu (navigates among sections) + /// - up or down on an unrolled menu (navigates among items) + /// - escape on an unrolled menu (the menu is rolled up) + /// + /// *C style function: [ncmenu_offer_input()][crate::ncmenu_offer_input].* + pub fn ncmenu_offer_input(&mut self, input: NcInput) -> bool { + unsafe { crate::ncmenu_offer_input(self, &input) } + } + + /// Returns the [NcPlane] backing this NcMenu. + /// + /// *C style function: [ncmenu_plane()][crate::ncmenu_plane].* + pub fn ncmenu_plane(&mut self) -> NcResult<&NcPlane> { + error_ptr![ + unsafe { crate::ncmenu_plane(self) }, + "Getting the backing NcPlane" + ] + } + + /// Moves to the previous item within the currently unrolled section. + /// + /// If no section is unrolled, the first section will be unrolled. + /// + /// *C style function: [ncmenu_previtem()][crate::ncmenu_previtem].* + pub fn ncmenu_previtem(&mut self) -> NcResult<()> { + error![unsafe{ crate::ncmenu_previtem(self) }] + } + + /// Unrolls the previous section (relative to current unrolled). + /// + /// If no section is unrolled, the first section will be unrolled. + /// + /// *C style function: [ncmenu_prevsection()][crate::ncmenu_prevsection].* + pub fn ncmenu_prevsection(&mut self) -> NcResult<()> { + error![unsafe{ crate::ncmenu_prevsection(self) }] + } + + /// Rolls up any unrolled [NcMenuSection], + /// and hides this NcMenu if using hiding. + /// + /// *C style function: [ncmenu_rollup()][crate::ncmenu_rollup].* + pub fn ncmenu_rollup(&mut self) -> NcResult<()> { + error![unsafe{ crate::ncmenu_rollup(self) }] + } + + /// Returns the selected item description, + /// or an error if no section is unrolled. + /// + /// If `shortcut` is provided, and the selected item has a shortcut, + /// it will be filled in with that shortcut--this can allow faster matching. + /// + /// *C style function: [ncmenu_selected()][crate::ncmenu_selected].* + pub fn ncmenu_selected( + &mut self, + shortcut: Option<&mut NcInput>, + ) -> NcResult { + let ninput; + if let Some(i) = shortcut { + ninput = i as *mut _; + } else { + ninput = null_mut(); + } + error_str![ + unsafe { crate::ncmenu_selected(self, ninput) }, + "Getting the selected NcMenuItem description" + ] } - /// `NcMenu` constructor with options - pub fn with_options<'a>(plane: &mut NcPlane, options: &NcMenuOptions) -> &'a mut Self { - unsafe { &mut *ncmenu_create(plane, options) } + /// Unrolls the specified [NcMenuSection], making the menu visible if it was + /// invisible, and rolling up any NcMenuSection that is already unrolled. + /// + /// *C style function: [ncmenu_unroll()][crate::ncmenu_unroll].* + pub fn ncmenu_unroll(&mut self, sectionindex: u32) -> NcResult<()> { + error![unsafe{ crate::ncmenu_unroll(self, sectionindex as i32) }] } } /// # `NcMenuOptions` Constructors impl NcMenuOptions { - /// `NcMenuOptions` simple constructor + /// New NcMenuOptions. pub fn new() -> Self { Self::with_options(&mut [], 0, 0, 0, 0) } - /// `NcMenuOptions` width options + /// New NcMenuOptions with width options. pub fn with_options( sections: &mut [NcMenuSection], count: u32, @@ -54,7 +221,7 @@ impl NcMenuOptions { /// # `NcMenuItem` Constructors impl NcMenuItem { - /// `NcMenuItem` simple constructor + /// New NcMenuItem. pub fn new(mut desc: i8, shortcut: NcInput) -> Self { Self { // utf-8 menu item, NULL for horizontal separator @@ -68,7 +235,7 @@ impl NcMenuItem { /// # `NcMenuSection` Constructors impl NcMenuSection { - /// `NcMenuSection` simple constructor + /// New NcMenuSection. pub fn new(name: &str, itemcount: i32, items: &mut [NcMenuItem], shortcut: NcInput) -> Self { Self { // utf-8 name string diff --git a/rust/src/widgets/menu/mod.rs b/rust/src/widgets/menu/mod.rs index dcf9dbf16..53a6418e2 100644 --- a/rust/src/widgets/menu/mod.rs +++ b/rust/src/widgets/menu/mod.rs @@ -2,28 +2,33 @@ // functions already exported by bindgen : 13 // ------------------------------------------ -// ncmenu_create -// ncmenu_destroy -// ncmenu_item_set_status -// ncmenu_mouse_selected -// ncmenu_nextitem -// ncmenu_nextsection -// ncmenu_offer_input -// ncmenu_plane -// ncmenu_previtem -// ncmenu_prevsection -// ncmenu_rollup -// ncmenu_selected -// ncmenu_unroll +// (#) test: 0 +// (W) wrap: 13 +// ------------------------------------------ +//W ncmenu_create +//W ncmenu_destroy +//W ncmenu_item_set_status +//W ncmenu_mouse_selected +//W ncmenu_nextitem +//W ncmenu_nextsection +//W ncmenu_offer_input +//W ncmenu_plane +//W ncmenu_previtem +//W ncmenu_prevsection +//W ncmenu_rollup +//W ncmenu_selected +//W ncmenu_unroll mod methods; /// menus on the top or bottom rows /// -/// A notcurses instance supports menu bars on the top or bottom row of the true -/// screen. +/// A [Notcurses][crate::Notcurses] instance supports menu bars +/// on the top or bottom row of the true screen. +/// +/// An NcMenu is composed of [NcMenuSection]s, which are in turn composed of +/// [NcMenuItem]s. /// -/// A menu is composed of sections, which are in turn composed of items. /// Either no sections are visible, and the menu is rolled up, or exactly one /// section is unrolled. ///