diff --git a/Cargo.toml b/Cargo.toml index 9c37924..81b4967 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ version = "0.6" [dependencies] chan = "0.1.18" +num = "0.1" chan-signal = "0.1" odds = "0.2" toml = "0.2" diff --git a/src/direction.rs b/src/direction.rs index 4b5f5f1..258674a 100644 --- a/src/direction.rs +++ b/src/direction.rs @@ -16,6 +16,7 @@ //! Its actual direction depends on the orientation. use vec::Vec2; +use XY; /// Describes a vertical or horizontal orientation for a view. #[derive(Clone,Copy,Debug,PartialEq)] @@ -31,8 +32,8 @@ impl Orientation { /// /// (`Horizontal` will return the x value, /// and `Vertical` will return the y value.) - pub fn get(&self, v: &Vec2) -> usize { - *v.get(*self) + pub fn get(&self, v: &XY) -> T { + v.get(*self).clone() } /// Returns the other orientation. @@ -45,7 +46,7 @@ impl Orientation { /// Returns a mutable reference to the component of the given vector /// corresponding to this orientation. - pub fn get_ref<'a, 'b>(&'a self, v: &'b mut Vec2) -> &'b mut usize { + pub fn get_ref<'a, 'b, T>(&'a self, v: &'b mut XY) -> &'b mut T { match *self { Orientation::Horizontal => &mut v.x, Orientation::Vertical => &mut v.y, diff --git a/src/lib.rs b/src/lib.rs index f1b2995..cec30e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,7 @@ extern crate toml; extern crate unicode_segmentation; extern crate unicode_width; extern crate odds; +extern crate num; #[macro_use] extern crate chan; diff --git a/src/vec.rs b/src/vec.rs index 31389e6..bd17bb3 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -2,6 +2,7 @@ use XY; use direction::Orientation; +use num::traits::Zero; use std::cmp::{Ordering, max, min}; use std::ops::{Add, Div, Mul, Sub}; @@ -30,81 +31,75 @@ impl PartialOrd for XY { } } -impl XY { +impl XY { + /// Returns `true` if `self` could fit inside `other`. + /// + /// Shortcut for `self.x <= other.x && self.y <= other.y`. + pub fn fits_in>(&self, other: O) -> bool { + let other = other.into(); + self.x <= other.x && self.y <= other.y + } + /// Returns a new Vec2 that is a maximum per coordinate. - pub fn max, B: Into>(a: A, b: B) -> Self { + pub fn max>, B: Into>>(a: A, b: B) -> Self { let a = a.into(); let b = b.into(); a.zip_map(b, max) } /// Returns a new Vec2 that is no larger than any input in both dimensions. - pub fn min, B: Into>(a: A, b: B) -> Self { + pub fn min>, B: Into>>(a: A, b: B) -> Self { let a = a.into(); let b = b.into(); a.zip_map(b, min) } /// Returns the minimum of `self` and `other`. - pub fn or_min>(self, other: T) -> Self { - Vec2::min(self, other) + pub fn or_min>>(self, other: O) -> Self { + Self::min(self, other) } /// Returns the maximum of `self` and `other`. - pub fn or_max>(self, other: T) -> Self { - Vec2::max(self, other) + pub fn or_max>>(self, other: O) -> Self { + Self::max(self, other) + } +} + +impl + Clone> XY { + /// Returns (max(self.x,other.x), self.y+other.y) + pub fn stack_vertical(&self, other: &Self) -> Self { + Self::new(max(self.x.clone(), other.x.clone()), + self.y.clone() + other.y.clone()) } + /// Returns (self.x+other.x, max(self.y,other.y)) + pub fn stack_horizontal(&self, other: &Self) -> Self { + Self::new(self.x.clone() + other.x.clone(), + max(self.y.clone(), other.y.clone())) + } +} + +impl XY { /// Returns a vector with the X component of self, and y=0. pub fn keep_x(&self) -> Self { - Vec2::new(self.x, 0) + Self::new(self.x.clone(), T::zero()) } /// Returns a vector with the Y component of self, and x=0. pub fn keep_y(&self) -> Self { - Vec2::new(0, self.y) + Self::new(T::zero(), self.y.clone()) } - /// Alias for `Vec2::new(0,0)`. + /// Alias for `Self::new(0,0)`. pub fn zero() -> Self { - Vec2::new(0, 0) + Self::new(T::zero(), T::zero()) } +} - /// Returns (max(self.x,other.x), self.y+other.y) - pub fn stack_vertical(&self, other: &Vec2) -> Vec2 { - Vec2::new(max(self.x, other.x), self.y + other.y) - } - - /// Returns (self.x+other.x, max(self.y,other.y)) - pub fn stack_horizontal(&self, other: &Vec2) -> Vec2 { - Vec2::new(self.x + other.x, max(self.y, other.y)) - } - - /// Returns `true` if `self` could fit inside `other`. - /// - /// Shortcut for `self.x <= other.x && self.y <= other.y`. - pub fn fits_in>(&self, other: T) -> bool { - let other = other.into(); - self.x <= other.x && self.y <= other.y - } - - /// Returns a new `Vec2` with the axis `o` set to `value`. - pub fn with_axis(&self, o: Orientation, value: usize) -> Self { - let mut new = *self; - *o.get_ref(&mut new) = value; - new - } - - /// Returns a new `Vec2` with the axis `o` set to the value from `other`. - pub fn with_axis_from(&self, o: Orientation, other: &Vec2) -> Self { - let mut new = *self; - new.set_axis_from(o, other); - new - } - - /// Sets the axis `o` on `self` to the value from `other`. - pub fn set_axis_from(&mut self, o: Orientation, other: &Vec2) { - *o.get_ref(self) = o.get(other); +impl >> From for XY { + fn from(t: T) -> Self { + let other = t.into(); + Self::new(other.x as isize, other.y as isize) } } @@ -121,27 +116,27 @@ impl From<(u32, u32)> for XY { } -impl> Add for XY { - type Output = Vec2; +impl, O: Into>> Add for XY { + type Output = Self; - fn add(self, other: T) -> Vec2 { + fn add(self, other: O) -> Self { self.zip_map(other.into(), Add::add) } } -impl> Sub for XY { - type Output = Vec2; +impl, O: Into>> Sub for XY { + type Output = Self; - fn sub(self, other: T) -> Vec2 { + fn sub(self, other: O) -> Self { self.zip_map(other.into(), Sub::sub) } } -impl Div for XY { - type Output = Vec2; +impl > Div for XY { + type Output = Self; - fn div(self, other: usize) -> Vec2 { - self.map(|s| s / other) + fn div(self, other: T) -> Self { + self.map(|s| s / other.clone()) } } diff --git a/src/view/position.rs b/src/view/position.rs index 524107e..2afca1f 100644 --- a/src/view/position.rs +++ b/src/view/position.rs @@ -18,7 +18,7 @@ impl Position { } /// Returns a position relative to the parent on both axis. - pub fn parent>(offset: T) -> Self { + pub fn parent>>(offset: T) -> Self { let offset = offset.into(); Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y)) } @@ -55,7 +55,7 @@ pub enum Offset { /// Offset from the previous layer's top-left corner. /// /// If this is the first layer, behaves like `Absolute`. - Parent(usize), // TODO: use a signed vec for negative offset? + Parent(isize), } impl Offset { @@ -70,7 +70,7 @@ impl Offset { Offset::Center => (available - size) / 2, Offset::Absolute(offset) => min(offset, available - size), Offset::Parent(offset) => { - min(parent + offset, available - size) + min((parent as isize + offset) as usize, available - size) } } } diff --git a/src/views/select_view.rs b/src/views/select_view.rs index e9ce58e..ef9dc6c 100644 --- a/src/views/select_view.rs +++ b/src/views/select_view.rs @@ -1,6 +1,7 @@ use Cursive; use Printer; use With; +use XY; use align::{Align, HAlign, VAlign}; use direction::Direction; use event::{Callback, Event, EventResult, Key}; @@ -425,8 +426,13 @@ impl View for SelectView { // This is the offset for the label text. // We'll want to show the popup so that the text matches. // It'll be soo cool. - let text_offset = - (self.last_size.x - self.items[focus].label.len()) / 2; + let item_length = self.items[focus].label.len(); + let text_offset = if self.last_size.x >= item_length { + (self.last_size.x - item_length) / 2 + } else { + // We were too small to show the entire item last time. + 0 + }; // The total offset for the window is: // * the last absolute offset at which we drew this view // * shifted to the top of the focus (so the line matches) @@ -444,7 +450,7 @@ impl View for SelectView { // A nice effect is that window resizes will keep both // layers together. let current_offset = s.screen().offset(); - let offset = offset - current_offset; + let offset = XY::::from(offset) - current_offset; // And finally, put the view in view! s.screen_mut() .add_layer_at(Position::parent(offset), diff --git a/src/xy.rs b/src/xy.rs index 31a6031..4f30323 100644 --- a/src/xy.rs +++ b/src/xy.rs @@ -56,6 +56,27 @@ impl XY { } } +impl XY { + /// Returns a new `XY` with the axis `o` set to `value`. + pub fn with_axis(&self, o: Orientation, value: T) -> Self { + let mut new = self.clone(); + *o.get_ref(&mut new) = value; + new + } + + /// Returns a new `XY` with the axis `o` set to the value from `other`. + pub fn with_axis_from(&self, o: Orientation, other: &Self) -> Self { + let mut new = self.clone(); + new.set_axis_from(o, other); + new + } + + /// Sets the axis `o` on `self` to the value from `other`. + pub fn set_axis_from(&mut self, o: Orientation, other: &Self) { + *o.get_ref(self) = o.get(other); + } +} + impl XY> { /// Returns a new `XY` by calling `unwrap_or` on each axis. pub fn unwrap_or(self, other: XY) -> XY {