From 500456e2e588c68c50cb10dd52afab19f065637c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?joseLu=C3=ADs?= Date: Fri, 1 Jan 2021 14:17:01 +0100 Subject: [PATCH] rust: continue working on the poc-menu example. - change return type of NcMenu.selected to Option. - change type to &str in ncplane_set_base. - bonus: update some comments. --- rust/examples/poc-menu.rs | 79 +++++++++++++++++---------- rust/src/notcurses/methods.rs | 16 +++--- rust/src/notcurses/reimplemented.rs | 3 +- rust/src/plane/methods.rs | 36 ++++++++---- rust/src/widgets/menu/methods/menu.rs | 14 ++--- 5 files changed, 90 insertions(+), 58 deletions(-) diff --git a/rust/examples/poc-menu.rs b/rust/examples/poc-menu.rs index 63236c9ee..464e78995 100644 --- a/rust/examples/poc-menu.rs +++ b/rust/examples/poc-menu.rs @@ -24,7 +24,8 @@ fn main() -> NcResult<()> { NcMenuSection::new("Schwarzgerät", &mut demo_items, NcInput::with_alt('ä')), NcMenuSection::new("File", &mut file_items, NcInput::with_alt('f')), NcMenuSection::new_separator(), - NcMenuSection::new("Help", &mut help_items, NcInput::with_alt('h')), + // DEBUG: remove alt modifier for now. + NcMenuSection::new("Help", &mut help_items, NcInput::new('h')), ]; let mut mopts = NcMenuOptions::new(&mut sections); @@ -33,33 +34,39 @@ fn main() -> NcResult<()> { mopts.section_channels_mut().set_fg_rgb(0xb0d700); mopts.section_channels_mut().set_bg_rgb(0x002000); - let plane = nc.stdplane()?; - let (dim_y, _dim_x) = plane.dim_yx(); - let menu_top = NcMenu::new(plane, mopts)?; + let stdplane = nc.stdplane()?; + let (dim_y, _dim_x) = stdplane.dim_yx(); + + let menu_top = NcMenu::new(stdplane, mopts)?; menu_top.item_set_status("Schwarzgerät", "Disabled", false)?; menu_top.item_set_status("Schwarzgerät", "Restart", false)?; let mut channels: NcChannelPair = 0; channels.set_fg_rgb(0x88aa00); channels.set_bg_rgb(0x000088); - plane.set_base('x', 0, channels)?; + stdplane.set_base("x", 0, channels)?; nc.render()?; - plane.set_fg_rgb(0x00dddd); - plane.putstr_aligned( + stdplane.set_fg_rgb(0x00dddd); + stdplane.putstr_aligned( dim_y - 1, NCALIGN_RIGHT, " -=+ menu poc. press q to exit +=-", )?; + run_menu(nc, menu_top)?; - plane.erase(); + stdplane.erase(); // is this needed? + + // BUG FIXME: this doesn't show over the menu (at row 0) + stdplane.putstr_aligned(0, NCALIGN_RIGHT, " -=+ menu poc. press q to exit +=-")?; + stdplane.putstr_aligned(1, NCALIGN_CENTER, " -=+ menu poc. press q to exit +=-")?; + stdplane.putstr_aligned(2, NCALIGN_LEFT, " -=+ menu poc. press q to exit +=-")?; mopts.flags |= NCMENU_OPTION_BOTTOM; - let menu_bottom = NcMenu::new(plane, mopts)?; - // FIXME: - plane.putstr_aligned(1, NCALIGN_RIGHT, " -=+ menu poc. press q to exit +=-")?; + let menu_bottom = NcMenu::new(stdplane, mopts)?; + run_menu(nc, menu_bottom)?; nc.stop()?; @@ -71,46 +78,58 @@ fn run_menu(nc: &mut Notcurses, menu: &mut NcMenu) -> NcResult<()> { let planeopts = NcPlaneOptions::new_aligned(10, NCALIGN_CENTER, 3, 40); let stdplane = nc.stdplane()?; let selplane = NcPlane::with_options_bound(stdplane, planeopts)?; - selplane.set_fg_rgb(0); selplane.set_bg_rgb(0xdddddd); let mut channels = 0; channels.set_fg_rgb(0x000088); channels.set_bg_rgb(0x88aa00); - selplane.set_base(' ', 0, channels)?; + selplane.set_base(" ", 0, channels)?; let mut ni = NcInput::new_empty(); let mut keypress: char; + nc.render()?; - // FIXME: screen updates one keypress later. loop { + stdplane.erase(); + selplane.erase(); + keypress = nc.getc_blocking(Some(&mut ni))?; + // DEBUG + stdplane.putstr_yx(2, 0, &format!["{:?}", ni])?; + nc.render()?; + + // BUG FIXME: always returns false: if !menu.offer_input(ni) { - if keypress == 'q' { - menu.destroy()?; - selplane.destroy()?; - return Ok(()); - } else if keypress == NCKEY_ENTER { - // selected a menu item - // BUG FIXME: - let sel = menu.selected(Some(&mut ni))?; - if sel == "Quit" { + match keypress { + 'q' => { menu.destroy()?; selplane.destroy()?; return Ok(()); + }, + NCKEY_ENTER => { + if let Some(selection) = menu.selected(Some(&mut ni)) { + match selection.as_ref() { + "Quit" => { + menu.destroy()?; + selplane.destroy()?; + return Ok(()); + } + _ => () + } + } } + _ => () } } let mut selni = NcInput::new_empty(); - // if let Some(selitem) = menu.selected(Some(&mut selni)) { - // selplane.putstr_aligned(1, NCALIGN_CENTER, &selitem)?; - // } else { - // // DEBUG - // selplane.putstr_aligned(1, NCALIGN_CENTER, "nothing opened")?; - // } - + if let Some(selitem) = menu.selected(Some(&mut selni)) { + selplane.putstr_aligned(1, NCALIGN_CENTER, &selitem)?; + } else { + // DEBUG + selplane.putstr_aligned(1, NCALIGN_CENTER, "nothing opened")?; + } nc.render()?; } } diff --git a/rust/src/notcurses/methods.rs b/rust/src/notcurses/methods.rs index 8587fd43e..c589cae3c 100644 --- a/rust/src/notcurses/methods.rs +++ b/rust/src/notcurses/methods.rs @@ -85,38 +85,40 @@ impl NotcursesOptions { /// # `Notcurses` Constructors impl Notcurses { - /// Returns a Notcurses context (without banners). + /// New Notcurses (without banners). pub fn new<'a>() -> NcResult<&'a mut Notcurses> { Self::with_flags(NCOPTION_SUPPRESS_BANNERS) } - /// Returns a Notcurses context, with banners. The default in the C library. + /// New Notcurses, with banners. + /// + /// This is the default in the C library. pub fn with_banners<'a>() -> NcResult<&'a mut Notcurses> { Self::with_flags(0) } - /// Returns a Notcurses context, without an alternate screen (nor banners). + /// New Notcurses, without an alternate screen (nor banners). pub fn without_altscreen<'a>() -> NcResult<&'a mut Notcurses> { Self::with_flags(NCOPTION_NO_ALTERNATE_SCREEN) } - /// Returns a Notcurses context, without an alternate screen, with banners. + /// New Notcurses, without an alternate screen, with banners. pub fn without_altscreen_nor_banners<'a>() -> NcResult<&'a mut Notcurses> { Self::with_flags(NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_SUPPRESS_BANNERS) } - /// Returns a Notcurses context, expects [NotcursesOptions]. + /// New Notcurses, expects `NCOPTION_*` flags. pub fn with_flags<'a>(flags: u64) -> NcResult<&'a mut Notcurses> { Self::with_options(NotcursesOptions::with_flags(flags)) } - /// Returns a Notcurses context, expects [NotcursesOptions]. + /// New Notcurses, expects [NotcursesOptions]. pub fn with_options<'a>(options: NotcursesOptions) -> NcResult<&'a mut Notcurses> { let res = unsafe { notcurses_init(&options, null_mut()) }; error_ref_mut![res, "Notcurses.with_options()"] } - /// Returns a Notcurses context. Expects [NcLogLevel] and flags. + /// New Notcurses, expects [NcLogLevel] and flags. pub fn with_debug<'a>(loglevel: NcLogLevel, flags: u64) -> NcResult<&'a mut Notcurses> { Self::with_options(NotcursesOptions::with_all_options( loglevel, 0, 0, 0, 0, flags, diff --git a/rust/src/notcurses/reimplemented.rs b/rust/src/notcurses/reimplemented.rs index f73fa9b1b..ef0776302 100644 --- a/rust/src/notcurses/reimplemented.rs +++ b/rust/src/notcurses/reimplemented.rs @@ -36,7 +36,7 @@ pub fn notcurses_align(availcols: NcDimension, align: NcAlign, cols: NcDimension /// /// *Method: Notcurses.[getc_nblock()][Notcurses#method.getc_nblock].* // -// `input` may be NULL if the caller is uninterested in event details. +// TODO: use from_u32 & return Option. #[inline] pub fn notcurses_getc_nblock(nc: &mut Notcurses, input: &mut NcInput) -> char { unsafe { @@ -46,7 +46,6 @@ pub fn notcurses_getc_nblock(nc: &mut Notcurses, input: &mut NcInput) -> char { tv_sec: 0, tv_nsec: 0, }; - // https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.html core::char::from_u32_unchecked(crate::notcurses_getc(nc, &ts, &mut sigmask, input)) } } diff --git a/rust/src/plane/methods.rs b/rust/src/plane/methods.rs index ea1848e67..c109e44a0 100644 --- a/rust/src/plane/methods.rs +++ b/rust/src/plane/methods.rs @@ -4,9 +4,9 @@ use core::ptr::{null, null_mut}; use crate::{ cstring, error, error_ref, error_ref_mut, rstring, NcAlign, NcAlphaBits, NcBoxMask, NcCell, - NcChannel, NcChannelPair, NcColor, NcDimension, NcEgc, NcFadeCb, NcOffset, NcPaletteIndex, - NcPlane, NcPlaneOptions, NcResizeCb, NcResult, NcRgb, NcStyleMask, NcTime, Notcurses, - NCRESULT_ERR, + NcChannel, NcChannelPair, NcColor, NcDimension, NcEgc, NcError, NcFadeCb, NcOffset, + NcPaletteIndex, NcPlane, NcPlaneOptions, NcResizeCb, NcResult, NcRgb, NcStyleMask, NcTime, + Notcurses, NCRESULT_ERR, }; /// # NcPlaneOptions Constructors @@ -491,7 +491,7 @@ impl NcPlane { ) -> NcResult { let egc = unsafe { crate::ncplane_at_cursor(self, stylemask, channels) }; if egc.is_null() { - return Err(crate::NcError::new(NCRESULT_ERR)); + return Err(NcError::new(NCRESULT_ERR)); } let egc = core::char::from_u32(unsafe { *egc } as u32).expect("wrong char"); Ok(egc) @@ -524,7 +524,7 @@ impl NcPlane { ) -> NcResult { let egc = unsafe { crate::ncplane_at_yx(self, y as i32, x as i32, stylemask, channels) }; if egc.is_null() { - return Err(crate::NcError::new(NCRESULT_ERR)); + return Err(NcError::new(NCRESULT_ERR)); } let egc = core::char::from_u32(unsafe { *egc } as u32).expect("wrong char"); Ok(egc) @@ -556,7 +556,7 @@ impl NcPlane { error![unsafe { crate::ncplane_base(self, cell) }] } - /// Sets this NcPlane's base NcCell from its components. + /// Sets this NcPlane's base [NcCell] from its components. /// /// This function must be called with an empty `egc`. /// `egc` must be a single extended grapheme cluster. @@ -567,18 +567,28 @@ impl NcPlane { /// Erasing the NcPlane does not reset the base cell. /// /// *C style function: [ncplane_set_base()][crate::ncplane_set_base].* + // call stack: + // - ncplane_set_base calls cell_prime: + // return cell_prime(ncp, &ncp->basecell, egc, stylemask, channels); + // - cell_prime calls notcurses.c/cell_load: + // return cell_load(n, c, gcluster); + // - cell-load calls internal.h/pool load: + // return pool_load(&n->pool, c, gcluster); pub fn set_base( &mut self, - egc: NcEgc, + egc: &str, stylemask: NcStyleMask, channels: NcChannelPair, - ) -> NcResult<()> { + ) -> NcResult { + let res = + unsafe { crate::ncplane_set_base(self, cstring![egc], stylemask as u32, channels) }; error![ - unsafe { crate::ncplane_set_base(self, &(egc as i8), stylemask as u32, channels) }, + res, &format!( "NcPlane.set_base({:?}, {:0x}, {:0x})", - egc as i32, stylemask, channels - ) + egc, stylemask, channels + ), + res as u32 ] } @@ -642,7 +652,9 @@ impl NcPlane { /// /// *C style function: [ncplane_erase()][crate::ncplane_erase].* pub fn erase(&mut self) { - unsafe { crate::ncplane_erase(self) } + unsafe { + crate::ncplane_erase(self); + } } /// Replaces the NcCell at the specified coordinates with the provided NcCell, diff --git a/rust/src/widgets/menu/methods/menu.rs b/rust/src/widgets/menu/methods/menu.rs index ff872dd9e..ec34ad93a 100644 --- a/rust/src/widgets/menu/methods/menu.rs +++ b/rust/src/widgets/menu/methods/menu.rs @@ -143,24 +143,24 @@ impl NcMenu { error![unsafe { crate::ncmenu_rollup(self) }] } - /// Returns the selected item description, - /// or an error if no section is unrolled. + /// Returns the selected item description, if there's an unrolled section. /// /// 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 selected(&mut self, shortcut: Option<&mut NcInput>) -> NcResult { + pub fn selected(&mut self, shortcut: Option<&mut NcInput>) -> Option { 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" - ] + let res = unsafe { crate::ncmenu_selected(self, ninput) }; + if res != null_mut() { + return Some(unsafe { (&*res).to_string() }); + } + None } /// Unrolls the specified [NcMenuSection][crate::NcMenuSection],