Split width and height in BoxView

They are now both optional
This commit is contained in:
Alexandre Bury 2016-07-11 19:24:00 -07:00
parent c07e8b6aee
commit b7a270f258
8 changed files with 85 additions and 100 deletions

View File

@ -9,7 +9,7 @@ use cursive::event::{EventResult, Event};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
siv.add_layer(BoxView::new((30, 10), KeyCodeView::new(10))); siv.add_layer(BoxView::fixed_size((30, 10), KeyCodeView::new(10)));
siv.run(); siv.run();
} }

View File

@ -17,7 +17,7 @@ fn main() {
.child(TextView::new("Title").h_align(HAlign::Center)) .child(TextView::new("Title").h_align(HAlign::Center))
// Box the textview, so it doesn't get too wide. // Box the textview, so it doesn't get too wide.
// A 0 height value means it will be unconstrained. // A 0 height value means it will be unconstrained.
.child(BoxView::new((30,0), TextView::new(text)))) .child(BoxView::fixed_width(30, TextView::new(text))))
.button("Quit", |s| s.quit()) .button("Quit", |s| s.quit())
.h_align(HAlign::Center)); .h_align(HAlign::Center));

View File

@ -24,7 +24,7 @@ fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
// Let's add a BoxView to keep the list at a reasonable size - it can scroll anyway. // Let's add a BoxView to keep the list at a reasonable size - it can scroll anyway.
siv.add_layer(Dialog::new(BoxView::new((20, 10), select)) siv.add_layer(Dialog::new(BoxView::fixed_size((20, 10), select))
.title("Where are you from?")); .title("Where are you from?"));
siv.run(); siv.run();

View File

@ -7,7 +7,7 @@ use backend::Backend;
use B; use B;
use theme::{ColorStyle, Effect, Theme}; use theme::{ColorStyle, Effect, Theme};
use vec::{ToVec2, Vec2}; use vec::Vec2;
/// Convenient interface to draw on a subset of the screen. /// Convenient interface to draw on a subset of the screen.
#[derive(Clone)] #[derive(Clone)]
@ -24,10 +24,10 @@ pub struct Printer {
impl Printer { impl Printer {
/// Creates a new printer on the given window. /// Creates a new printer on the given window.
pub fn new<T: ToVec2>(size: T, theme: Theme) -> Self { pub fn new<T: Into<Vec2>>(size: T, theme: Theme) -> Self {
Printer { Printer {
offset: Vec2::zero(), offset: Vec2::zero(),
size: size.to_vec2(), size: size.into(),
focused: true, focused: true,
theme: theme, theme: theme,
} }
@ -36,8 +36,8 @@ impl Printer {
// TODO: use &mut self? We don't *need* it, but it may make sense. // TODO: use &mut self? We don't *need* it, but it may make sense.
// We don't want people to start calling prints in parallel? // We don't want people to start calling prints in parallel?
/// Prints some text at the given position relative to the window. /// Prints some text at the given position relative to the window.
pub fn print<S: ToVec2>(&self, pos: S, text: &str) { pub fn print<S: Into<Vec2>>(&self, pos: S, text: &str) {
let p = pos.to_vec2(); let p = pos.into();
if p.y >= self.size.y || p.x >= self.size.x { if p.y >= self.size.y || p.x >= self.size.x {
return; return;
} }
@ -59,8 +59,8 @@ impl Printer {
} }
/// Prints a vertical line using the given character. /// Prints a vertical line using the given character.
pub fn print_vline<T: ToVec2>(&self, start: T, len: usize, c: &str) { pub fn print_vline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
let p = start.to_vec2(); let p = start.into();
if p.y > self.size.y || p.x > self.size.x { if p.y > self.size.y || p.x > self.size.x {
return; return;
} }
@ -73,8 +73,8 @@ impl Printer {
} }
/// Prints a horizontal line using the given character. /// Prints a horizontal line using the given character.
pub fn print_hline<T: ToVec2>(&self, start: T, len: usize, c: &str) { pub fn print_hline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
let p = start.to_vec2(); let p = start.into();
if p.y > self.size.y || p.x > self.size.x { if p.y > self.size.y || p.x > self.size.x {
return; return;
} }
@ -125,9 +125,9 @@ impl Printer {
/// # let printer = Printer::new((6,4), theme::load_default()); /// # let printer = Printer::new((6,4), theme::load_default());
/// printer.print_box((0,0), (6,4)); /// printer.print_box((0,0), (6,4));
/// ``` /// ```
pub fn print_box<T: ToVec2>(&self, start: T, size: T) { pub fn print_box<T: Into<Vec2>>(&self, start: T, size: T) {
let start_v = start.to_vec2(); let start_v = start.into();
let size_v = size.to_vec2() - (1, 1); let size_v = size.into() - (1, 1);
self.print(start_v, ""); self.print(start_v, "");
self.print(start_v + size_v.keep_x(), ""); self.print(start_v + size_v.keep_x(), "");
@ -157,21 +157,21 @@ impl Printer {
f); f);
} }
pub fn print_hdelim<T: ToVec2>(&self, start: T, len: usize) { pub fn print_hdelim<T: Into<Vec2>>(&self, start: T, len: usize) {
let start = start.to_vec2(); let start = start.into();
self.print(start, ""); self.print(start, "");
self.print_hline(start + (1, 0), len - 2, ""); self.print_hline(start + (1, 0), len - 2, "");
self.print(start + (len - 1, 0), ""); self.print(start + (len - 1, 0), "");
} }
/// Returns a printer on a subset of this one's area. /// Returns a printer on a subset of this one's area.
pub fn sub_printer<S: ToVec2>(&self, offset: S, size: S, focused: bool) pub fn sub_printer<S: Into<Vec2>>(&self, offset: S, size: S, focused: bool)
-> Printer { -> Printer {
let offset_v = offset.to_vec2(); let offset_v = offset.into();
Printer { Printer {
offset: self.offset + offset_v, offset: self.offset + offset_v,
// We can't be larger than what remains // We can't be larger than what remains
size: Vec2::min(self.size - offset_v, size.to_vec2()), size: Vec2::min(self.size - offset_v, size.into()),
focused: self.focused && focused, focused: self.focused && focused,
theme: self.theme.clone(), theme: self.theme.clone(),
} }

View File

@ -68,41 +68,30 @@ impl Vec2 {
} }
} }
/// A generic trait for converting a value into a 2D vector. impl From<(usize, usize)> for Vec2 {
pub trait ToVec2 { fn from((x, y): (usize, usize)) -> Self {
/// Converts self into a Vec2. Vec2::new(x, y)
fn to_vec2(self) -> Vec2;
}
impl ToVec2 for Vec2 {
fn to_vec2(self) -> Vec2 {
self
} }
} }
impl ToVec2 for (i32, i32) { impl From<(i32, i32)> for Vec2 {
fn to_vec2(self) -> Vec2 { fn from((x, y): (i32, i32)) -> Self {
(self.0 as usize, self.1 as usize).to_vec2() (x as usize, y as usize).into()
} }
} }
impl ToVec2 for (usize, usize) { impl From<(u32, u32)> for Vec2 {
fn to_vec2(self) -> Vec2 { fn from((x, y): (u32, u32)) -> Self {
Vec2::new(self.0, self.1) (x as usize, y as usize).into()
} }
} }
impl ToVec2 for (u32, u32) {
fn to_vec2(self) -> Vec2 {
Vec2::new(self.0 as usize, self.1 as usize)
}
}
impl<T: ToVec2> Add<T> for Vec2 { impl<T: Into<Vec2>> Add<T> for Vec2 {
type Output = Vec2; type Output = Vec2;
fn add(self, other: T) -> Vec2 { fn add(self, other: T) -> Vec2 {
let ov = other.to_vec2(); let ov = other.into();
Vec2 { Vec2 {
x: self.x + ov.x, x: self.x + ov.x,
y: self.y + ov.y, y: self.y + ov.y,
@ -110,11 +99,11 @@ impl<T: ToVec2> Add<T> for Vec2 {
} }
} }
impl<T: ToVec2> Sub<T> for Vec2 { impl<T: Into<Vec2>> Sub<T> for Vec2 {
type Output = Vec2; type Output = Vec2;
fn sub(self, other: T) -> Vec2 { fn sub(self, other: T) -> Vec2 {
let ov = other.to_vec2(); let ov = other.into();
Vec2 { Vec2 {
x: self.x - ov.x, x: self.x - ov.x,
y: self.y - ov.y, y: self.y - ov.y,
@ -194,38 +183,23 @@ impl Vec4 {
} }
} }
/// Generic trait for converting a value into a Vec4. impl From<(usize, usize, usize, usize)> for Vec4 {
pub trait ToVec4 { fn from((left, right, top, bottom): (usize, usize, usize, usize)) -> Vec4 {
/// Converts self to a Vec4. Vec4::new(left, right, top, bottom)
fn to_vec4(self) -> Vec4;
}
impl ToVec4 for Vec4 {
fn to_vec4(self) -> Vec4 {
self
} }
} }
impl ToVec4 for (usize, usize, usize, usize) { impl From<(i32, i32, i32, i32)> for Vec4 {
fn to_vec4(self) -> Vec4 { fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Vec4 {
Vec4::new(self.0, self.1, self.2, self.3) (left as usize, right as usize, top as usize, bottom as usize).into()
} }
} }
impl ToVec4 for (i32, i32, i32, i32) { impl<T: Into<Vec4>> Add<T> for Vec4 {
fn to_vec4(self) -> Vec4 {
Vec4::new(self.0 as usize,
self.1 as usize,
self.2 as usize,
self.3 as usize)
}
}
impl<T: ToVec4> Add<T> for Vec4 {
type Output = Vec4; type Output = Vec4;
fn add(self, other: T) -> Vec4 { fn add(self, other: T) -> Vec4 {
let ov = other.to_vec4(); let ov = other.into();
Vec4 { Vec4 {
left: self.left + ov.left, left: self.left + ov.left,
@ -236,11 +210,11 @@ impl<T: ToVec4> Add<T> for Vec4 {
} }
} }
impl<T: ToVec4> Sub<T> for Vec4 { impl<T: Into<Vec4>> Sub<T> for Vec4 {
type Output = Vec4; type Output = Vec4;
fn sub(self, other: T) -> Vec4 { fn sub(self, other: T) -> Vec4 {
let ov = other.to_vec4(); let ov = other.into();
Vec4 { Vec4 {
left: self.left - ov.left, left: self.left - ov.left,

View File

@ -1,11 +1,12 @@
use std::cmp; use std::cmp;
use vec::{ToVec2, Vec2}; use vec::Vec2;
use super::{View, ViewWrapper}; use super::{View, ViewWrapper};
/// `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<T: View> { pub struct BoxView<T: View> {
size: Vec2, width: Option<usize>,
height: Option<usize>,
view: T, view: T,
} }
@ -17,38 +18,48 @@ impl<T: View> BoxView<T> {
/// ``` /// ```
/// # use cursive::view::{BoxView,TextView}; /// # use cursive::view::{BoxView,TextView};
/// // Creates a 20x4 BoxView with a TextView content. /// // Creates a 20x4 BoxView with a TextView content.
/// let view = BoxView::new((20,4), TextView::new("Hello!")); /// let view = BoxView::fixed_size((20,4), TextView::new("Hello!"));
/// ``` /// ```
pub fn new<S: ToVec2>(size: S, view: T) -> Self { pub fn fixed_size<S: Into<Vec2>>(size: S, view: T) -> Self {
let size = size.into();
BoxView::new(Some(size.x), Some(size.y), view)
}
pub fn new(width: Option<usize>, height: Option<usize>, view: T) -> Self {
BoxView { BoxView {
size: size.to_vec2(), width: width,
height: height,
view: view, view: view,
} }
} }
pub fn fixed_width(width: usize, view: T) -> Self {
BoxView::new(Some(width), None, view)
}
}
fn min<T: Ord>(a: T, b: Option<T>) -> T {
match b {
Some(b) => cmp::min(a, b),
None => a,
}
} }
impl<T: View> ViewWrapper for BoxView<T> { impl<T: View> ViewWrapper for BoxView<T> {
wrap_impl!(&self.view); wrap_impl!(&self.view);
fn wrap_get_min_size(&mut self, mut req: Vec2) -> Vec2 { fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 {
if self.size.x > 0 {
req.x = cmp::min(self.size.x, req.x);
}
if self.size.y > 0 {
req.y = cmp::min(self.size.y, req.y);
}
let mut size = self.view.get_min_size(req); if let (Some(w), Some(h)) = (self.width, self.height) {
Vec2::new(w, h)
} else {
let req = Vec2::new(min(req.x, self.width),
min(req.y, self.height));
let child_size = self.view.get_min_size(req);
// Did he think he got to decide? Vec2::new(self.width.unwrap_or(child_size.x),
// Of course we have the last word here. self.height.unwrap_or(child_size.y))
if self.size.x > 0 {
size.x = self.size.x;
} }
if self.size.y > 0 {
size.y = self.size.y;
}
size
} }
} }

View File

@ -7,7 +7,7 @@ use event::*;
use theme::ColorStyle; use theme::ColorStyle;
use view::{Selector, TextView, View}; use view::{Selector, TextView, View};
use view::{Button, SizedView}; use view::{Button, SizedView};
use vec::{ToVec4, Vec2, Vec4}; use vec::{Vec2, Vec4};
use printer::Printer; use printer::Printer;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
@ -99,8 +99,8 @@ impl Dialog {
} }
/// Sets the padding in the dialog (around content and buttons). /// Sets the padding in the dialog (around content and buttons).
pub fn padding<T: ToVec4>(mut self, padding: T) -> Self { pub fn padding<T: Into<Vec4>>(mut self, padding: T) -> Self {
self.padding = padding.to_vec4(); self.padding = padding.into();
self self
} }

View File

@ -1,5 +1,5 @@
use std::cmp::min; use std::cmp::min;
use vec::{ToVec2, Vec2}; use vec::Vec2;
/// Location of the view on screen /// Location of the view on screen
#[derive(PartialEq,Debug,Clone)] #[derive(PartialEq,Debug,Clone)]
@ -17,13 +17,13 @@ impl Position {
Position::new(Offset::Center, Offset::Center) Position::new(Offset::Center, Offset::Center)
} }
pub fn absolute<T: ToVec2>(offset: T) -> Self { pub fn absolute<T: Into<Vec2>>(offset: T) -> Self {
let offset = offset.to_vec2(); let offset = offset.into();
Position::new(Offset::Absolute(offset.x), Offset::Absolute(offset.y)) Position::new(Offset::Absolute(offset.x), Offset::Absolute(offset.y))
} }
pub fn parent<T: ToVec2>(offset: T) -> Self { pub fn parent<T: Into<Vec2>>(offset: T) -> Self {
let offset = offset.to_vec2(); let offset = offset.into();
Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y)) Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y))
} }