Add some doc to the menu module

This commit is contained in:
Alexandre Bury 2016-07-19 20:28:34 -07:00
parent 7a466e254f
commit 2065be3e88
3 changed files with 48 additions and 3 deletions

View File

@ -94,6 +94,7 @@ mod backend;
pub use xy::XY; pub use xy::XY;
pub use with::With; pub use with::With;
pub use printer::Printer; pub use printer::Printer;
pub use menubar::Menubar;
use backend::{Backend, NcursesBackend}; use backend::{Backend, NcursesBackend};

View File

@ -1,4 +1,16 @@
//! Module to build menus. //! Module to build menus.
//!
//! Menus are a way to arrange many actions in groups of more manageable size.
//!
//! A menu can be seen as a `MenuTree`. It has a list of children:
//!
//! * Leaf nodes are made of a label and a callback
//! * Sub-trees are made of a label, and another `MenuTree`.
//! * Delimiters are just there to separate groups of related children.
//!
//! The [menubar] is the main way to show menus.
//!
//! [menubar]: ../struct.Cursive.html#method.menubar
use With; use With;
use Cursive; use Cursive;

View File

@ -27,16 +27,26 @@ enum State {
Submenu, Submenu,
} }
/// Shows a single-line list of items, with pop-up menus when one is selected.
///
/// The [`Cursive`] root already includes a menubar that you just needs to configure.
///
/// [`Cursive`]: struct.Cursive.html#method.menubar
pub struct Menubar { pub struct Menubar {
/// Menu items in this menubar.
pub menus: Vec<(String, Rc<MenuTree>)>, pub menus: Vec<(String, Rc<MenuTree>)>,
/// TODO: move this out of this view.
pub autohide: bool, pub autohide: bool,
pub focus: usize, focus: usize,
// TODO: make Menubar impl View and take out the State management
state: State, state: State,
} }
new_default!(Menubar); new_default!(Menubar);
impl Menubar { impl Menubar {
/// Creates a new, empty menubar.
pub fn new() -> Self { pub fn new() -> Self {
Menubar { Menubar {
menus: Vec::new(), menus: Vec::new(),
@ -46,28 +56,41 @@ impl Menubar {
} }
} }
/// Hides the menubar.
fn hide(&mut self) { fn hide(&mut self) {
self.state = State::Inactive; self.state = State::Inactive;
::B::clear(); ::B::clear();
} }
/// Takes the focus.
///
/// TODO: impl View
pub fn take_focus(&mut self) { pub fn take_focus(&mut self) {
self.state = State::Selected; self.state = State::Selected;
} }
/// True if we should be receiving events.
pub fn receive_events(&self) -> bool { pub fn receive_events(&self) -> bool {
self.state == State::Selected self.state == State::Selected
} }
/// Returns `true` if we should be drawn.
pub fn visible(&self) -> bool { pub fn visible(&self) -> bool {
!self.autohide || self.state != State::Inactive !self.autohide || self.state != State::Inactive
} }
/// Adds a new item to the menubar.
///
/// The item will use the given title, and on selection, will open a
/// popup-menu with the given menu tree.
pub fn add(&mut self, title: &str, menu: MenuTree) -> &mut Self { pub fn add(&mut self, title: &str, menu: MenuTree) -> &mut Self {
self.menus.push((title.to_string(), Rc::new(menu))); self.menus.push((title.to_string(), Rc::new(menu)));
self self
} }
/// Draws the view.
///
/// TODO: impl View
pub fn draw(&mut self, printer: &Printer) { pub fn draw(&mut self, printer: &Printer) {
// Draw the bar at the top // Draw the bar at the top
printer.with_color(ColorStyle::Primary, |printer| { printer.with_color(ColorStyle::Primary, |printer| {
@ -88,6 +111,9 @@ impl Menubar {
} }
} }
/// Reacts to event.
///
/// TODO: impl View
pub fn on_event(&mut self, event: Event) -> Option<Callback> { pub fn on_event(&mut self, event: Event) -> Option<Callback> {
match event { match event {
Event::Key(Key::Esc) => self.hide(), Event::Key(Key::Esc) => self.hide(),
@ -133,6 +159,12 @@ impl Menubar {
} }
fn show_child(s: &mut Cursive, offset: (usize, usize), menu: Rc<MenuTree>) { fn show_child(s: &mut Cursive, offset: (usize, usize), menu: Rc<MenuTree>) {
// Adds a new layer located near the item title with the menu popup.
// Also adds two key callbacks on this new view, to handle `left` and
// `right` key presses.
// (If the view itself listens for a `left` or `right` press, it will
// consume it before our KeyEventView. This means sub-menus can properly
// be entered.)
s.screen_mut() s.screen_mut()
.add_layer_at(Position::absolute(offset), .add_layer_at(Position::absolute(offset),
KeyEventView::new(MenuPopup::new(menu) KeyEventView::new(MenuPopup::new(menu)
@ -142,8 +174,8 @@ fn show_child(s: &mut Cursive, offset: (usize, usize), menu: Rc<MenuTree>) {
})) }))
.register(Key::Right, |s| { .register(Key::Right, |s| {
s.pop_layer(); s.pop_layer();
// Act as if we sent "Left" then "Enter"
s.select_menubar(); s.select_menubar();
// Act as if we sent "Right" then "Down"
s.menubar().on_event(Event::Key(Key::Right)); s.menubar().on_event(Event::Key(Key::Right));
if let Some(cb) = s.menubar() if let Some(cb) = s.menubar()
.on_event(Event::Key(Key::Down)) { .on_event(Event::Key(Key::Down)) {
@ -152,8 +184,8 @@ fn show_child(s: &mut Cursive, offset: (usize, usize), menu: Rc<MenuTree>) {
}) })
.register(Key::Left, |s| { .register(Key::Left, |s| {
s.pop_layer(); s.pop_layer();
// Act as if we sent "Left" then "Enter"
s.select_menubar(); s.select_menubar();
// Act as if we sent "Left" then "Down"
s.menubar().on_event(Event::Key(Key::Left)); s.menubar().on_event(Event::Key(Key::Left));
if let Some(cb) = s.menubar() if let Some(cb) = s.menubar()
.on_event(Event::Key(Key::Down)) { .on_event(Event::Key(Key::Down)) {