mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Allow negative relative offset in Position
Was causing crashes when popup-SelectViews were larger than their parent. Made some methods on Vec2 more generic to XY<T: ...>
This commit is contained in:
parent
ddff15b6cf
commit
14f971e2bc
@ -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"
|
||||
|
@ -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<T: Clone>(&self, v: &XY<T>) -> 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<T>) -> &'b mut T {
|
||||
match *self {
|
||||
Orientation::Horizontal => &mut v.x,
|
||||
Orientation::Vertical => &mut v.y,
|
||||
|
@ -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;
|
||||
|
107
src/vec.rs
107
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<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
impl XY<usize> {
|
||||
impl<T: Ord> XY<T> {
|
||||
/// Returns `true` if `self` could fit inside `other`.
|
||||
///
|
||||
/// Shortcut for `self.x <= other.x && self.y <= other.y`.
|
||||
pub fn fits_in<O: Into<Self>>(&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<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
|
||||
pub fn max<A: Into<XY<T>>, B: Into<XY<T>>>(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<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
|
||||
pub fn min<A: Into<XY<T>>, B: Into<XY<T>>>(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<T: Into<Vec2>>(self, other: T) -> Self {
|
||||
Vec2::min(self, other)
|
||||
pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
|
||||
Self::min(self, other)
|
||||
}
|
||||
|
||||
/// Returns the maximum of `self` and `other`.
|
||||
pub fn or_max<T: Into<Vec2>>(self, other: T) -> Self {
|
||||
Vec2::max(self, other)
|
||||
pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
|
||||
Self::max(self, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord + Add<Output = T> + Clone> XY<T> {
|
||||
/// 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<T: Zero + Clone> XY<T> {
|
||||
/// 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<T: Into<Vec2>>(&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 <T: Into<XY<usize>>> From<T> for XY<isize> {
|
||||
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<usize> {
|
||||
}
|
||||
|
||||
|
||||
impl<T: Into<Vec2>> Add<T> for XY<usize> {
|
||||
type Output = Vec2;
|
||||
impl<T: Add<Output=T>, O: Into<XY<T>>> Add<O> for XY<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, other: T) -> Vec2 {
|
||||
fn add(self, other: O) -> Self {
|
||||
self.zip_map(other.into(), Add::add)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<Vec2>> Sub<T> for XY<usize> {
|
||||
type Output = Vec2;
|
||||
impl<T: Sub<Output=T>, O: Into<XY<T>>> Sub<O> for XY<T> {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, other: T) -> Vec2 {
|
||||
fn sub(self, other: O) -> Self {
|
||||
self.zip_map(other.into(), Sub::sub)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for XY<usize> {
|
||||
type Output = Vec2;
|
||||
impl <T: Clone + Div<Output=T>> Div<T> for XY<T> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl Position {
|
||||
}
|
||||
|
||||
/// Returns a position relative to the parent on both axis.
|
||||
pub fn parent<T: Into<Vec2>>(offset: T) -> Self {
|
||||
pub fn parent<T: Into<XY<isize>>>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<T: 'static> View for SelectView<T> {
|
||||
// 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<T: 'static> View for SelectView<T> {
|
||||
// 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::<isize>::from(offset) - current_offset;
|
||||
// And finally, put the view in view!
|
||||
s.screen_mut()
|
||||
.add_layer_at(Position::parent(offset),
|
||||
|
21
src/xy.rs
21
src/xy.rs
@ -56,6 +56,27 @@ impl<T> XY<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Clone> XY<T> {
|
||||
/// 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<T> XY<Option<T>> {
|
||||
/// Returns a new `XY` by calling `unwrap_or` on each axis.
|
||||
pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
|
||||
|
Loading…
Reference in New Issue
Block a user