Add base for menubar

Cursive now has a global menubar, with a `select_menubar()` method.
This commit is contained in:
Alexandre Bury 2016-06-27 21:59:42 -07:00
parent 43230534ff
commit 042e631d9f
2 changed files with 108 additions and 16 deletions

View File

@ -31,6 +31,10 @@ pub mod vec;
pub mod theme; pub mod theme;
pub mod align; pub mod align;
pub mod orientation; pub mod orientation;
pub mod menu;
// This probably doesn't need to be public?
mod menubar;
mod div; mod div;
mod utf8; mod utf8;
@ -43,9 +47,9 @@ use std::path::Path;
use vec::Vec2; use vec::Vec2;
use printer::Printer; use printer::Printer;
use view::View; use view::View;
use view::{StackView, Selector}; use view::{Selector, StackView};
use event::{Event, ToEvent, Key, EventResult, Callback}; use event::{Callback, Event, EventResult, Key, ToEvent};
/// Identifies a screen in the cursive ROOT. /// Identifies a screen in the cursive ROOT.
pub type ScreenId = usize; pub type ScreenId = usize;
@ -58,15 +62,14 @@ pub type ScreenId = usize;
/// ///
/// It uses a list of screen, with one screen active at a time. /// It uses a list of screen, with one screen active at a time.
pub struct Cursive { pub struct Cursive {
theme: theme::Theme,
screens: Vec<StackView>, screens: Vec<StackView>,
global_callbacks: HashMap<Event, Rc<Callback>>,
menu: menubar::Menubar,
active_screen: ScreenId, active_screen: ScreenId,
running: bool, running: bool,
global_callbacks: HashMap<Event, Rc<Callback>>,
theme: theme::Theme,
} }
impl Cursive { impl Cursive {
@ -88,11 +91,12 @@ impl Cursive {
ncurses::COLOR_PAIR(theme::ColorPair::Background.ncurses_id())); ncurses::COLOR_PAIR(theme::ColorPair::Background.ncurses_id()));
let mut res = Cursive { let mut res = Cursive {
theme: theme,
screens: Vec::new(), screens: Vec::new(),
global_callbacks: HashMap::new(),
menu: menubar::Menubar::new(),
active_screen: 0, active_screen: 0,
running: true, running: true,
global_callbacks: HashMap::new(),
theme: theme,
}; };
res.screens.push(StackView::new()); res.screens.push(StackView::new());
@ -100,6 +104,24 @@ impl Cursive {
res res
} }
/// Selects the menubar
pub fn select_menu(&mut self) {
self.menu.selected = true;
}
/// Sets the menubar autohide_menubar feature.
///
/// * When enabled, the menu is only visible when selected.
/// * When disabled, the menu is always visible and reserves the top row.
pub fn set_autohide_menu(&mut self, autohide: bool) {
self.menu.autohide = autohide;
}
/// Retrieve the menu tree used by the menubar.
pub fn menu(&mut self) -> &mut menu::MenuTree {
&mut self.menu.menu
}
/// Returns the currently used theme /// Returns the currently used theme
pub fn current_theme(&self) -> &theme::Theme { pub fn current_theme(&self) -> &theme::Theme {
&self.theme &self.theme
@ -150,7 +172,8 @@ impl Cursive {
/// Sets the active screen. Panics if no such screen exist. /// Sets the active screen. Panics if no such screen exist.
pub fn set_screen(&mut self, screen_id: ScreenId) { pub fn set_screen(&mut self, screen_id: ScreenId) {
if screen_id >= self.screens.len() { if screen_id >= self.screens.len() {
panic!("Tried to set an invalid screen ID: {}, but only {} screens present.", panic!("Tried to set an invalid screen ID: {}, but only {} \
screens present.",
screen_id, screen_id,
self.screens.len()); self.screens.len());
} }
@ -222,8 +245,28 @@ impl Cursive {
} }
fn draw(&mut self) { fn draw(&mut self) {
// TODO: don't clone the theme
// Reference it or something
let printer = Printer::new(self.screen_size(), self.theme.clone()); let printer = Printer::new(self.screen_size(), self.theme.clone());
self.screen_mut().draw(&printer);
// Draw the currently active screen
// If the menubar is active, nothing else can be.
let offset = if self.menu.autohide {
1
} else {
0
};
let selected = self.menu.selected;
self.screen_mut()
.draw(&printer.sub_printer(Vec2::new(0, offset),
printer.size,
!selected));
// Draw the menubar?
if self.menu.selected || !self.menu.autohide {
self.menu.draw(&printer);
}
ncurses::refresh(); ncurses::refresh();
} }
@ -232,13 +275,16 @@ impl Cursive {
// Is it a UTF-8 starting point? // Is it a UTF-8 starting point?
if 32 <= ch && ch < 0x100 && ch != 127 { if 32 <= ch && ch < 0x100 && ch != 127 {
Event::CharEvent(utf8::read_char(ch as u8, || ncurses::getch() as u8).unwrap()) Event::CharEvent(utf8::read_char(ch as u8,
|| ncurses::getch() as u8)
.unwrap())
} else { } else {
Event::KeyEvent(Key::from_ncurses(ch)) Event::KeyEvent(Key::from_ncurses(ch))
} }
} }
/// Runs the event loop. /// Runs the event loop.
///
/// It will wait for user input (key presses) and trigger callbacks accordingly. /// It will wait for user input (key presses) and trigger callbacks accordingly.
/// Blocks until quit() is called. /// Blocks until quit() is called.
pub fn run(&mut self) { pub fn run(&mut self) {
@ -259,11 +305,22 @@ impl Cursive {
// (If set_fps was called, this returns -1 now and then) // (If set_fps was called, this returns -1 now and then)
let event = Cursive::poll_event(); let event = Cursive::poll_event();
match self.screen_mut().on_event(event) { // Event dispatch order:
// If the event was ignored, it is our turn to play with it. // * Focused element:
EventResult::Ignored => self.on_event(event), // * Menubar (if active)
EventResult::Consumed(None) => (), // * Current screen (top layer)
EventResult::Consumed(Some(cb)) => cb(self), // * Global callbacks
if self.menu.selected {
if let Some(cb) = self.menu.on_event(event) {
cb(self);
}
} else {
match self.screen_mut().on_event(event) {
// If the event was ignored, it is our turn to play with it.
EventResult::Ignored => self.on_event(event),
EventResult::Consumed(None) => (),
EventResult::Consumed(Some(cb)) => cb(self),
}
} }
} }
} }

35
src/menubar.rs Normal file
View File

@ -0,0 +1,35 @@
use menu::*;
use theme::ColorPair;
use printer::Printer;
use event::*;
use std::rc::Rc;
pub struct Menubar {
pub menu: MenuTree,
pub autohide: bool,
pub selected: bool,
}
impl Menubar {
pub fn new() -> Self {
Menubar {
menu: MenuTree::new(),
autohide: true,
selected: false,
}
}
pub fn draw(&mut self, printer: &Printer) {
// Draw the bar at the top
printer.with_color(ColorPair::Primary, |printer| {
printer.print_hline((0, 0), printer.size.x, " ");
});
// TODO: draw the rest
}
pub fn on_event(&mut self, event: Event) -> Option<Rc<Callback>> {
None
}
}