diff --git a/src/lib.rs b/src/lib.rs index 42e6912..0300410 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,7 +171,7 @@ impl Cursive { offset: Vec2::new(0,0), size: self.screen_size(), }; - self.screen_mut().draw(&printer); + self.screen_mut().draw(&printer, true); ncurses::wrefresh(ncurses::stdscr); } diff --git a/src/view/box_view.rs b/src/view/box_view.rs index d6ba4d4..239e248 100644 --- a/src/view/box_view.rs +++ b/src/view/box_view.rs @@ -1,7 +1,5 @@ -use event::EventResult; use vec::{Vec2,ToVec2}; -use super::{View,SizeRequest}; -use printer::Printer; +use super::{View,ViewWrapper,SizeRequest}; /// BoxView is a wrapper around an other view, with a given minimum size. pub struct BoxView { @@ -27,20 +25,11 @@ impl BoxView { } } -impl View for BoxView { - fn on_key_event(&mut self, ch: i32) -> EventResult { - self.content.on_key_event(ch) - } +impl ViewWrapper for BoxView { - fn draw(&self, printer: &Printer) { - self.content.draw(printer) - } + wrap_impl!(content); - fn get_min_size(&self, _: SizeRequest) -> Vec2 { + fn wrap_get_min_size(&self, _: SizeRequest) -> Vec2 { self.size } - - fn layout(&mut self, size: Vec2) { - self.content.layout(size); - } } diff --git a/src/view/button.rs b/src/view/button.rs index 6070dcf..6f7737d 100644 --- a/src/view/button.rs +++ b/src/view/button.rs @@ -1,7 +1,5 @@ use std::rc::Rc; -use ncurses; - use ::Cursive; use vec::Vec2; use view::{View,ViewPath,SizeRequest}; @@ -9,12 +7,14 @@ use event::{Callback,EventResult}; use printer::Printer; /// Simple text label with a callback when ENTER is pressed. +/// A button shows its content in a single line and has a fixed size. pub struct Button { label: String, callback: Rc, } impl Button { + /// Creates a new button with the given content and callback. pub fn new(label: &str, cb: F) -> Self where F: Fn(&mut Cursive, &ViewPath) + 'static { @@ -27,13 +27,17 @@ impl Button { impl View for Button { - fn draw(&self, printer: &Printer) { + fn draw(&self, printer: &Printer, focused: bool) { printer.print((1u32,0u32), &self.label); - printer.print((0u32,0u32), "<"); - printer.print((printer.size.x-1,0), ">"); + + if focused { + printer.print((0u32,0u32), "<"); + printer.print((printer.size.x-1,0), ">"); + } } - fn get_min_size(&self, req: SizeRequest) -> Vec2 { + fn get_min_size(&self, _: SizeRequest) -> Vec2 { + // Meh. Fixed size we are. Vec2::new(2 + self.label.len() as u32, 1) } @@ -44,4 +48,8 @@ impl View for Button { _ => EventResult::Ignored, } } + + fn take_focus(&mut self) -> bool { + true + } } diff --git a/src/view/dialog.rs b/src/view/dialog.rs index a73a764..c0cb80a 100644 --- a/src/view/dialog.rs +++ b/src/view/dialog.rs @@ -13,7 +13,6 @@ use printer::Printer; enum Focus { Content, Button(usize), - Nothing, } pub struct Dialog { @@ -48,26 +47,16 @@ impl Dialog { } -fn offset_request(request: DimensionRequest, offset: i32) -> DimensionRequest { - match request { - DimensionRequest::Fixed(w) => DimensionRequest::Fixed((w as i32 + offset) as u32), - DimensionRequest::AtMost(w) => DimensionRequest::AtMost((w as i32 + offset) as u32), - DimensionRequest::Unknown => DimensionRequest::Unknown, - } -} - impl View for Dialog { - fn draw(&self, printer: &Printer) { + fn draw(&self, printer: &Printer, focused: bool) { let mut height = 0; let mut x = 0; for (i,button) in self.buttons.iter().enumerate().rev() { let size = button.size; let offset = printer.size - self.borders.bot_right() - self.padding.bot_right() - size - Vec2::new(x, 0); - if self.focus == Focus::Button(i) { - // Add some special effect to the focused button - } - button.draw(&printer.sub_printer(offset, size)); + // Add some special effect to the focused button + button.draw(&printer.sub_printer(offset, size), focused && (self.focus == Focus::Button(i))); x += size.x + 1; height = max(height, size.y+1); } @@ -77,7 +66,7 @@ impl View for Dialog { - self.borders.combined() - self.padding.combined(); - self.content.draw(&printer.sub_printer(self.borders.top_left() + self.padding.top_left(), inner_size)); + self.content.draw(&printer.sub_printer(self.borders.top_left() + self.padding.top_left(), inner_size), focused && self.focus == Focus::Content); printer.print(Vec2::new(0,0), "+"); printer.print(Vec2::new(printer.size.x-1, 0), "+"); @@ -147,7 +136,16 @@ impl View for Dialog { }, res => res, }, - Focus::Nothing => EventResult::Ignored, + } + } + + fn take_focus(&mut self) -> bool { + if !self.buttons.is_empty() { + self.focus = Focus::Button(0); + true + } else { + self.focus = Focus::Content; + self.content.take_focus() } } } diff --git a/src/view/key_event_view.rs b/src/view/key_event_view.rs index 83600eb..87181a6 100644 --- a/src/view/key_event_view.rs +++ b/src/view/key_event_view.rs @@ -3,9 +3,7 @@ use std::rc::Rc; use ::Cursive; use event::{EventResult,Callback}; -use vec::{Vec2}; -use super::{View,SizeRequest,ViewPath}; -use printer::Printer; +use super::{View,ViewPath,ViewWrapper}; /// A simple wrapper view that catches some ignored event from its child. /// @@ -34,26 +32,18 @@ impl KeyEventView { } } -impl View for KeyEventView { - fn on_key_event(&mut self, ch: i32) -> EventResult { +impl ViewWrapper for KeyEventView { + + wrap_impl!(content); + + fn wrap_on_key_event(&mut self, ch: i32) -> EventResult { match self.content.on_key_event(ch) { EventResult::Ignored => match self.callbacks.get(&ch) { None => EventResult::Ignored, Some(cb) => EventResult::Consumed(Some(cb.clone()), ViewPath::new()), }, - EventResult::Consumed(cb, path) => EventResult::Consumed(cb, path), + res => res, } } - fn draw(&self, printer: &Printer) { - self.content.draw(printer) - } - - fn get_min_size(&self, req: SizeRequest) -> Vec2 { - self.content.get_min_size(req) - } - - fn layout(&mut self, size: Vec2) { - self.content.layout(size); - } } diff --git a/src/view/mod.rs b/src/view/mod.rs index e7581af..354f556 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -1,5 +1,6 @@ //! Defines various views to use when creating the layout. +#[macro_use] mod view_wrapper; mod box_view; mod stack_view; mod text_view; @@ -8,7 +9,6 @@ mod view_path; mod dialog; mod button; mod sized_view; -mod view_wrapper; use std::any::Any; @@ -85,11 +85,14 @@ pub trait View { /// propagate the information to its children. fn layout(&mut self, Vec2) { } - /// Draws the view within the given bounds. - fn draw(&self, &Printer); + /// Draws the view with the given printer (includes bounds) and focus. + fn draw(&self, printer: &Printer, focused: bool); /// Finds the view pointed to by the given path. /// Returns None if the path doesn't lead to a view. fn find(&mut self, &ViewPath) -> Option<&mut Any> { None } + + /// This view is offered focus. Will it take it? + fn take_focus(&mut self) -> bool { false } } diff --git a/src/view/stack_view.rs b/src/view/stack_view.rs index ae932d7..31ef892 100644 --- a/src/view/stack_view.rs +++ b/src/view/stack_view.rs @@ -40,14 +40,14 @@ impl StackView { impl View for StackView { - fn draw(&self, printer: &Printer) { + fn draw(&self, printer: &Printer, focused: bool) { match self.layers.last() { None => (), Some(v) => { // Center the view let view_size = Vec2::min(printer.size, v.size); let offset = (printer.size - view_size) / 2; - v.view.draw(&printer.sub_printer(offset, v.size)); + v.view.draw(&printer.sub_printer(offset, v.size), focused); }, } } @@ -82,4 +82,11 @@ impl View for StackView { s } + + fn take_focus(&mut self) -> bool { + match self.layers.last_mut() { + None => false, + Some(mut v) => v.view.take_focus() + } + } } diff --git a/src/view/text_view.rs b/src/view/text_view.rs index ca847c1..d2b719d 100644 --- a/src/view/text_view.rs +++ b/src/view/text_view.rs @@ -112,7 +112,9 @@ impl <'a> Iterator for LinesIterator<'a> { } impl View for TextView { - fn draw(&self, printer: &Printer) { + fn draw(&self, printer: &Printer, _: bool) { + // We don't have a focused view + let lines = self.content.split("\n") .flat_map(|line| LinesIterator::new(line, printer.size.x as usize)); for (i, line) in lines.enumerate() { diff --git a/src/view/view_wrapper.rs b/src/view/view_wrapper.rs index 127c13b..bb1d019 100644 --- a/src/view/view_wrapper.rs +++ b/src/view/view_wrapper.rs @@ -7,8 +7,8 @@ pub trait ViewWrapper { fn get_view(&self) -> &View; fn get_view_mut(&mut self) -> &mut View; - fn wrap_draw(&self, printer: &Printer) { - self.get_view().draw(printer); + fn wrap_draw(&self, printer: &Printer, focused: bool) { + self.get_view().draw(printer, focused); } fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 { @@ -25,8 +25,8 @@ pub trait ViewWrapper { } impl View for T { - fn draw(&self, printer: &Printer) { - self.wrap_draw(printer); + fn draw(&self, printer: &Printer, focused: bool) { + self.wrap_draw(printer, focused); } fn get_min_size(&self, req: SizeRequest) -> Vec2 { @@ -41,3 +41,17 @@ impl View for T { self.wrap_layout(size); } } + +#[macro_export] +macro_rules! wrap_impl { + ($v:ident) => { + + fn get_view(&self) -> &View { + &*self.$v + } + + fn get_view_mut(&mut self) -> &mut View { + &mut *self.$v + } + }; +}