Add focus system

May need to add a direction to take_focus
This commit is contained in:
Alexandre Bury 2015-05-19 15:54:11 -07:00
parent 7cb0a7b6d4
commit c8136c67e0
9 changed files with 76 additions and 65 deletions

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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<Callback>,
}
impl Button {
/// Creates a new button with the given content and callback.
pub fn new<F>(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
}
}

View File

@ -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()
}
}
}

View File

@ -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);
}
}

View File

@ -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 }
}

View File

@ -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()
}
}
}

View File

@ -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() {

View File

@ -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 <T: ViewWrapper> 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 <T: ViewWrapper> 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
}
};
}