Add printer abstraction on ncurses::WINDOW

Also rename Size -> Vec2
This commit is contained in:
Alexandre Bury 2015-05-15 11:58:47 -07:00
parent 4ebb422611
commit e5c623bb07
7 changed files with 136 additions and 66 deletions

View File

@ -1,11 +1,11 @@
use ncurses;
use event::EventResult; use event::EventResult;
use super::{Size,ToSize}; use vec2::{Vec2,ToVec2};
use view::{View,SizeRequest}; use view::{View,SizeRequest};
use printer::Printer;
/// BoxView is a wrapper around an other view, with a given minimum size. /// BoxView is a wrapper around an other view, with a given minimum size.
pub struct BoxView { pub struct BoxView {
size: Size, size: Vec2,
content: Box<View>, content: Box<View>,
} }
@ -19,9 +19,9 @@ impl BoxView {
/// // Creates a 20x4 BoxView with a TextView content. /// // Creates a 20x4 BoxView with a TextView content.
/// let box = BoxView::new((20,4), TextView::new("Hello!")) /// let box = BoxView::new((20,4), TextView::new("Hello!"))
/// ``` /// ```
pub fn new<S: ToSize, V: View + 'static>(size: S, view: V) -> Self { pub fn new<S: ToVec2, V: View + 'static>(size: S, view: V) -> Self {
BoxView { BoxView {
size: size.to_size(), size: size.to_vec2(),
content: Box::new(view), content: Box::new(view),
} }
} }
@ -32,15 +32,15 @@ impl View for BoxView {
self.content.on_key_event(ch) self.content.on_key_event(ch)
} }
fn draw(&self, win: ncurses::WINDOW, size: Size) { fn draw(&self, printer: &Printer) {
self.content.draw(win, size) self.content.draw(printer)
} }
fn get_min_size(&self, _: SizeRequest) -> Size { fn get_min_size(&self, _: SizeRequest) -> Vec2 {
self.size self.size
} }
fn layout(&mut self, size: Size) { fn layout(&mut self, size: Vec2) {
self.content.layout(size); self.content.layout(size);
} }
} }

View File

@ -1,9 +1,13 @@
extern crate ncurses; extern crate ncurses;
/// Module for user-input events and their effects. /// User-input events and their effects.
pub mod event; pub mod event;
/// Define various views to use when creating the layout. /// Defines various views to use when creating the layout.
pub mod view; pub mod view;
/// Makes drawing on ncurses windows easier.
pub mod printer;
/// 2D points.
pub mod vec2;
mod box_view; mod box_view;
mod stack_view; mod stack_view;
mod text_view; mod text_view;
@ -18,6 +22,7 @@ use stack_view::StackView;
use event::{EventResult,Callback}; use event::{EventResult,Callback};
/// Identifies a screen in the cursive ROOT.
pub type ScreenId = usize; pub type ScreenId = usize;
/// Central part of the cursive library. /// Central part of the cursive library.
@ -134,35 +139,3 @@ impl Drop for Cursive {
} }
} }
/// Simple 2D size, in characters.
#[derive(Clone,Copy)]
pub struct Size {
pub w: u32,
pub h: u32,
}
impl Size {
pub fn new(w: u32, h: u32) -> Self {
Size {
w: w,
h: h,
}
}
}
/// A generic trait for converting a value into a 2D size
pub trait ToSize {
fn to_size(self) -> Size;
}
impl ToSize for Size {
fn to_size(self) -> Size {
self
}
}
impl ToSize for (u32,u32) {
fn to_size(self) -> Size {
Size::new(self.0, self.1)
}
}

31
src/printer.rs Normal file
View File

@ -0,0 +1,31 @@
use ncurses;
use vec2::{Vec2,ToVec2};
/// Wrapper around a subset of a ncurses window.
pub struct Printer {
/// ncurses window this printer will use. You can use it directly if you want.
pub win: ncurses::WINDOW,
/// Offset into the window this printer should start drawing at.
pub offset: Vec2,
/// Size of the area we are allowed to draw on.
pub size: Vec2,
}
impl Printer {
/// Prints some text at the given position relative to the window.
pub fn print<S: ToVec2>(&self, pos: S, text: &str) {
let p = pos.to_vec2();
ncurses::mvwprintw(self.win, (p.y + self.offset.y) as i32, (p.x + self.offset.x) as i32, text);
}
/// Returns a printer on a subset of this one's area.
pub fn sub_printer<S: ToVec2>(&self, offset: S, size: S) -> Printer {
let offset_v = offset.to_vec2();
Printer {
win: self.win,
offset: self.offset + offset_v,
// We can't be larger than what remains
size: Vec2::min(self.size - offset_v, size.to_vec2()),
}
}
}

View File

@ -1,10 +1,9 @@
use std::cmp::max; use std::cmp::max;
use ncurses; use vec2::Vec2;
use super::Size;
use view::{View,SizeRequest}; use view::{View,SizeRequest};
use event::EventResult; use event::EventResult;
use printer::Printer;
/// Simple stack of views. /// Simple stack of views.
/// Only the top-most view is active and can receive input. /// Only the top-most view is active and can receive input.
@ -33,10 +32,10 @@ impl StackView {
impl View for StackView { impl View for StackView {
fn draw(&self, win: ncurses::WINDOW, size: Size) { fn draw(&self, printer: &Printer) {
match self.layers.last() { match self.layers.last() {
None => (), None => (),
Some(v) => v.draw(win, size), Some(v) => v.draw(printer),
} }
} }
@ -47,14 +46,14 @@ impl View for StackView {
} }
} }
fn get_min_size(&self, size: SizeRequest) -> Size { fn get_min_size(&self, size: SizeRequest) -> Vec2 {
// The min size is the max of all children's // The min size is the max of all children's
let mut s = Size::new(1,1); let mut s = Vec2::new(1,1);
for view in self.layers.iter() { for view in self.layers.iter() {
let vs = view.get_min_size(size); let vs = view.get_min_size(size);
s.w = max(s.w, vs.w); s.x = max(s.x, vs.x);
s.h = max(s.h, vs.h); s.y = max(s.y, vs.y);
} }
s s

View File

@ -1,8 +1,7 @@
use ncurses; use vec2::Vec2;
use super::Size;
use view::{View,DimensionRequest,SizeRequest}; use view::{View,DimensionRequest,SizeRequest};
use div::*; use div::*;
use printer::Printer;
/// A simple view showing a fixed text /// A simple view showing a fixed text
pub struct TextView { pub struct TextView {
@ -48,19 +47,20 @@ impl TextView {
} }
impl View for TextView { impl View for TextView {
fn draw(&self, win: ncurses::WINDOW, size: Size) { fn draw(&self, printer: &Printer) {
printer.print((0,0), &self.content);
} }
fn get_min_size(&self, size: SizeRequest) -> Size { fn get_min_size(&self, size: SizeRequest) -> Vec2 {
match (size.w,size.h) { match (size.w,size.h) {
(DimensionRequest::Unknown, DimensionRequest::Unknown) => Size::new(self.content.len() as u32, 1), (DimensionRequest::Unknown, DimensionRequest::Unknown) => Vec2::new(self.content.len() as u32, 1),
(DimensionRequest::Fixed(w),_) => { (DimensionRequest::Fixed(w),_) => {
let h = self.get_num_lines(w as usize) as u32; let h = self.get_num_lines(w as usize) as u32;
Size::new(w, h) Vec2::new(w, h)
}, },
(_,DimensionRequest::Fixed(h)) => { (_,DimensionRequest::Fixed(h)) => {
let w = self.get_num_cols(h as usize) as u32; let w = self.get_num_cols(h as usize) as u32;
Size::new(w, h) Vec2::new(w, h)
}, },
(DimensionRequest::AtMost(_),DimensionRequest::AtMost(_)) => unreachable!(), (DimensionRequest::AtMost(_),DimensionRequest::AtMost(_)) => unreachable!(),
_ => unreachable!(), _ => unreachable!(),

68
src/vec2.rs Normal file
View File

@ -0,0 +1,68 @@
use std::ops::{Add, Sub};
use std::cmp::min;
/// Simple 2D size, in characters.
#[derive(Clone,Copy)]
pub struct Vec2 {
/// X coordinate (column), from left to right.
pub x: u32,
/// Y coordinate (row), from top to bottom.
pub y: u32,
}
impl Vec2 {
/// Creates a new Vec2 from coordinates.
pub fn new(x: u32, y: u32) -> Self {
Vec2 {
x: x,
y: y,
}
}
/// Returns a new Vec2 that is no larger than any input in both dimensions.
pub fn min(a: Vec2, b: Vec2) -> Vec2 {
Vec2 {
x: min(a.x, b.x),
y: min(a.y, b.y),
}
}
}
/// A generic trait for converting a value into a 2D vector.
pub trait ToVec2 {
fn to_vec2(self) -> Vec2;
}
impl ToVec2 for Vec2 {
fn to_vec2(self) -> Vec2 {
self
}
}
impl ToVec2 for (u32,u32) {
fn to_vec2(self) -> Vec2 {
Vec2::new(self.0, self.1)
}
}
impl Add for Vec2 {
type Output = Vec2;
fn add(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl Sub for Vec2 {
type Output = Vec2;
fn sub(self, other: Vec2) -> Vec2 {
Vec2 {
x: self.x - other.x,
y: self.y - other.y,
}
}
}

View File

@ -1,12 +1,11 @@
use ncurses;
use event::EventResult; use event::EventResult;
pub use box_view::BoxView; pub use box_view::BoxView;
pub use stack_view::StackView; pub use stack_view::StackView;
pub use text_view::TextView; pub use text_view::TextView;
use super::Size; use vec2::Vec2;
use printer::Printer;
/// Describe constraints on a view layout in one dimension. /// Describe constraints on a view layout in one dimension.
#[derive(PartialEq,Clone,Copy)] #[derive(PartialEq,Clone,Copy)]
@ -34,12 +33,12 @@ pub trait View {
fn on_key_event(&mut self, i32) -> EventResult { EventResult::Ignored } fn on_key_event(&mut self, i32) -> EventResult { EventResult::Ignored }
/// Returns the minimum size the view requires under the given restrictions. /// Returns the minimum size the view requires under the given restrictions.
fn get_min_size(&self, SizeRequest) -> Size { Size::new(1,1) } fn get_min_size(&self, SizeRequest) -> Vec2 { Vec2::new(1,1) }
/// Called once the size for this view has been decided, so it can /// Called once the size for this view has been decided, so it can
/// propagate the information to its children. /// propagate the information to its children.
fn layout(&mut self, Size) { } fn layout(&mut self, Vec2) { }
/// Draws the view within the given bounds. /// Draws the view within the given bounds.
fn draw(&self, ncurses::WINDOW, Size); fn draw(&self, &Printer);
} }