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]
|
[dependencies]
|
||||||
chan = "0.1.18"
|
chan = "0.1.18"
|
||||||
|
num = "0.1"
|
||||||
chan-signal = "0.1"
|
chan-signal = "0.1"
|
||||||
odds = "0.2"
|
odds = "0.2"
|
||||||
toml = "0.2"
|
toml = "0.2"
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
//! Its actual direction depends on the orientation.
|
//! Its actual direction depends on the orientation.
|
||||||
|
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
use XY;
|
||||||
|
|
||||||
/// Describes a vertical or horizontal orientation for a view.
|
/// Describes a vertical or horizontal orientation for a view.
|
||||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||||
@ -31,8 +32,8 @@ impl Orientation {
|
|||||||
///
|
///
|
||||||
/// (`Horizontal` will return the x value,
|
/// (`Horizontal` will return the x value,
|
||||||
/// and `Vertical` will return the y value.)
|
/// and `Vertical` will return the y value.)
|
||||||
pub fn get(&self, v: &Vec2) -> usize {
|
pub fn get<T: Clone>(&self, v: &XY<T>) -> T {
|
||||||
*v.get(*self)
|
v.get(*self).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the other orientation.
|
/// Returns the other orientation.
|
||||||
@ -45,7 +46,7 @@ impl Orientation {
|
|||||||
|
|
||||||
/// Returns a mutable reference to the component of the given vector
|
/// Returns a mutable reference to the component of the given vector
|
||||||
/// corresponding to this orientation.
|
/// 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 {
|
match *self {
|
||||||
Orientation::Horizontal => &mut v.x,
|
Orientation::Horizontal => &mut v.x,
|
||||||
Orientation::Vertical => &mut v.y,
|
Orientation::Vertical => &mut v.y,
|
||||||
|
@ -63,6 +63,7 @@ extern crate toml;
|
|||||||
extern crate unicode_segmentation;
|
extern crate unicode_segmentation;
|
||||||
extern crate unicode_width;
|
extern crate unicode_width;
|
||||||
extern crate odds;
|
extern crate odds;
|
||||||
|
extern crate num;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate chan;
|
extern crate chan;
|
||||||
|
107
src/vec.rs
107
src/vec.rs
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use XY;
|
use XY;
|
||||||
use direction::Orientation;
|
use direction::Orientation;
|
||||||
|
use num::traits::Zero;
|
||||||
use std::cmp::{Ordering, max, min};
|
use std::cmp::{Ordering, max, min};
|
||||||
|
|
||||||
use std::ops::{Add, Div, Mul, Sub};
|
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.
|
/// 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 a = a.into();
|
||||||
let b = b.into();
|
let b = b.into();
|
||||||
a.zip_map(b, max)
|
a.zip_map(b, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new Vec2 that is no larger than any input in both dimensions.
|
/// 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 a = a.into();
|
||||||
let b = b.into();
|
let b = b.into();
|
||||||
a.zip_map(b, min)
|
a.zip_map(b, min)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the minimum of `self` and `other`.
|
/// Returns the minimum of `self` and `other`.
|
||||||
pub fn or_min<T: Into<Vec2>>(self, other: T) -> Self {
|
pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
|
||||||
Vec2::min(self, other)
|
Self::min(self, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the maximum of `self` and `other`.
|
/// Returns the maximum of `self` and `other`.
|
||||||
pub fn or_max<T: Into<Vec2>>(self, other: T) -> Self {
|
pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
|
||||||
Vec2::max(self, other)
|
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.
|
/// Returns a vector with the X component of self, and y=0.
|
||||||
pub fn keep_x(&self) -> Self {
|
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.
|
/// Returns a vector with the Y component of self, and x=0.
|
||||||
pub fn keep_y(&self) -> Self {
|
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 {
|
pub fn zero() -> Self {
|
||||||
Vec2::new(0, 0)
|
Self::new(T::zero(), T::zero())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns (max(self.x,other.x), self.y+other.y)
|
impl <T: Into<XY<usize>>> From<T> for XY<isize> {
|
||||||
pub fn stack_vertical(&self, other: &Vec2) -> Vec2 {
|
fn from(t: T) -> Self {
|
||||||
Vec2::new(max(self.x, other.x), self.y + other.y)
|
let other = t.into();
|
||||||
}
|
Self::new(other.x as isize, other.y as isize)
|
||||||
|
|
||||||
/// 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,27 +116,27 @@ impl From<(u32, u32)> for XY<usize> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T: Into<Vec2>> Add<T> for XY<usize> {
|
impl<T: Add<Output=T>, O: Into<XY<T>>> Add<O> for XY<T> {
|
||||||
type Output = Vec2;
|
type Output = Self;
|
||||||
|
|
||||||
fn add(self, other: T) -> Vec2 {
|
fn add(self, other: O) -> Self {
|
||||||
self.zip_map(other.into(), Add::add)
|
self.zip_map(other.into(), Add::add)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<Vec2>> Sub<T> for XY<usize> {
|
impl<T: Sub<Output=T>, O: Into<XY<T>>> Sub<O> for XY<T> {
|
||||||
type Output = Vec2;
|
type Output = Self;
|
||||||
|
|
||||||
fn sub(self, other: T) -> Vec2 {
|
fn sub(self, other: O) -> Self {
|
||||||
self.zip_map(other.into(), Sub::sub)
|
self.zip_map(other.into(), Sub::sub)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Div<usize> for XY<usize> {
|
impl <T: Clone + Div<Output=T>> Div<T> for XY<T> {
|
||||||
type Output = Vec2;
|
type Output = Self;
|
||||||
|
|
||||||
fn div(self, other: usize) -> Vec2 {
|
fn div(self, other: T) -> Self {
|
||||||
self.map(|s| s / other)
|
self.map(|s| s / other.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a position relative to the parent on both axis.
|
/// 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();
|
let offset = offset.into();
|
||||||
Position::new(Offset::Parent(offset.x), Offset::Parent(offset.y))
|
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.
|
/// Offset from the previous layer's top-left corner.
|
||||||
///
|
///
|
||||||
/// If this is the first layer, behaves like `Absolute`.
|
/// If this is the first layer, behaves like `Absolute`.
|
||||||
Parent(usize), // TODO: use a signed vec for negative offset?
|
Parent(isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Offset {
|
impl Offset {
|
||||||
@ -70,7 +70,7 @@ impl Offset {
|
|||||||
Offset::Center => (available - size) / 2,
|
Offset::Center => (available - size) / 2,
|
||||||
Offset::Absolute(offset) => min(offset, available - size),
|
Offset::Absolute(offset) => min(offset, available - size),
|
||||||
Offset::Parent(offset) => {
|
Offset::Parent(offset) => {
|
||||||
min(parent + offset, available - size)
|
min((parent as isize + offset) as usize, available - size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use Cursive;
|
use Cursive;
|
||||||
use Printer;
|
use Printer;
|
||||||
use With;
|
use With;
|
||||||
|
use XY;
|
||||||
use align::{Align, HAlign, VAlign};
|
use align::{Align, HAlign, VAlign};
|
||||||
use direction::Direction;
|
use direction::Direction;
|
||||||
use event::{Callback, Event, EventResult, Key};
|
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.
|
// This is the offset for the label text.
|
||||||
// We'll want to show the popup so that the text matches.
|
// We'll want to show the popup so that the text matches.
|
||||||
// It'll be soo cool.
|
// It'll be soo cool.
|
||||||
let text_offset =
|
let item_length = self.items[focus].label.len();
|
||||||
(self.last_size.x - self.items[focus].label.len()) / 2;
|
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 total offset for the window is:
|
||||||
// * the last absolute offset at which we drew this view
|
// * the last absolute offset at which we drew this view
|
||||||
// * shifted to the top of the focus (so the line matches)
|
// * 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
|
// A nice effect is that window resizes will keep both
|
||||||
// layers together.
|
// layers together.
|
||||||
let current_offset = s.screen().offset();
|
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!
|
// And finally, put the view in view!
|
||||||
s.screen_mut()
|
s.screen_mut()
|
||||||
.add_layer_at(Position::parent(offset),
|
.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>> {
|
impl<T> XY<Option<T>> {
|
||||||
/// Returns a new `XY` by calling `unwrap_or` on each axis.
|
/// Returns a new `XY` by calling `unwrap_or` on each axis.
|
||||||
pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
|
pub fn unwrap_or(self, other: XY<T>) -> XY<T> {
|
||||||
|
Loading…
Reference in New Issue
Block a user