mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Fix focus in LinearLayout
Focus now at least works. #42 is still open though.
This commit is contained in:
parent
9390504290
commit
5059e21cb1
27
src/vec.rs
27
src/vec.rs
@ -9,6 +9,7 @@ use std::cmp::{Ordering, max, min};
|
|||||||
pub type Vec2 = XY<usize>;
|
pub type Vec2 = XY<usize>;
|
||||||
|
|
||||||
impl PartialOrd for Vec2 {
|
impl PartialOrd for Vec2 {
|
||||||
|
/// `a < b` <=> `a.x < b.x && a.y < b.y`
|
||||||
fn partial_cmp(&self, other: &Vec2) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Vec2) -> Option<Ordering> {
|
||||||
if self == other {
|
if self == other {
|
||||||
Some(Ordering::Equal)
|
Some(Ordering::Equal)
|
||||||
@ -27,14 +28,14 @@ impl Vec2 {
|
|||||||
pub fn max<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
|
pub fn max<A: Into<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
|
||||||
let a = a.into();
|
let a = a.into();
|
||||||
let b = b.into();
|
let b = b.into();
|
||||||
Vec2::new(max(a.x, b.x), max(a.y, b.y))
|
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<Vec2>, B: Into<Vec2>>(a: A, b: B) -> Self {
|
||||||
let a = a.into();
|
let a = a.into();
|
||||||
let b = b.into();
|
let b = b.into();
|
||||||
Vec2::new(min(a.x, b.x), min(a.y, b.y))
|
a.zip_map(b, min)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the minimum of `self` and `other`.
|
/// Returns the minimum of `self` and `other`.
|
||||||
@ -105,11 +106,7 @@ 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.into();
|
self.zip_map(other.into(), Add::add)
|
||||||
Vec2 {
|
|
||||||
x: self.x + ov.x,
|
|
||||||
y: self.y + ov.y,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,11 +114,7 @@ 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.into();
|
self.zip_map(other.into(), Sub::sub)
|
||||||
Vec2 {
|
|
||||||
x: self.x - ov.x,
|
|
||||||
y: self.y - ov.y,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,10 +122,7 @@ impl Div<usize> for Vec2 {
|
|||||||
type Output = Vec2;
|
type Output = Vec2;
|
||||||
|
|
||||||
fn div(self, other: usize) -> Vec2 {
|
fn div(self, other: usize) -> Vec2 {
|
||||||
Vec2 {
|
self.map(|s| s / other)
|
||||||
x: self.x / other,
|
|
||||||
y: self.y / other,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,10 +130,7 @@ impl Mul<usize> for Vec2 {
|
|||||||
type Output = Vec2;
|
type Output = Vec2;
|
||||||
|
|
||||||
fn mul(self, other: usize) -> Vec2 {
|
fn mul(self, other: usize) -> Vec2 {
|
||||||
Vec2 {
|
self.map(|s| s * other)
|
||||||
x: self.x * other,
|
|
||||||
y: self.y * other,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,14 @@ impl Child {
|
|||||||
self.size = self.view.get_min_size(req);
|
self.size = self.view.get_min_size(req);
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_ref(&self) -> &View {
|
||||||
|
&*self.view
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_mut(&mut self) -> &mut View {
|
||||||
|
&mut *self.view
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LinearLayout {
|
impl LinearLayout {
|
||||||
@ -85,7 +93,7 @@ impl LinearLayout {
|
|||||||
Some(ref cache) => {
|
Some(ref cache) => {
|
||||||
// Is our cache even valid?
|
// Is our cache even valid?
|
||||||
// Also, is any child invalidating the layout?
|
// Also, is any child invalidating the layout?
|
||||||
if cache.x.accept(req.x) && cache.y.accept(req.y) &&
|
if cache.zip_map(req, SizeCache::accept).both() &&
|
||||||
self.children_are_sleeping() {
|
self.children_are_sleeping() {
|
||||||
Some(cache.map(|s| s.value))
|
Some(cache.map(|s| s.value))
|
||||||
} else {
|
} else {
|
||||||
@ -98,9 +106,36 @@ impl LinearLayout {
|
|||||||
fn children_are_sleeping(&self) -> bool {
|
fn children_are_sleeping(&self) -> bool {
|
||||||
!self.children
|
!self.children
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| &*c.view)
|
.map(Child::as_ref)
|
||||||
.any(View::needs_relayout)
|
.any(View::needs_relayout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn focus_prev(&mut self) -> EventResult {
|
||||||
|
if let Some(i) = self.children[..self.focus]
|
||||||
|
.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.map(Child::as_mut)
|
||||||
|
.position(View::take_focus) {
|
||||||
|
|
||||||
|
self.focus = i;
|
||||||
|
EventResult::Consumed(None)
|
||||||
|
} else {
|
||||||
|
EventResult::Ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus_next(&mut self) -> EventResult {
|
||||||
|
if let Some(i) = self.children[(self.focus + 1)..]
|
||||||
|
.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.map(Child::as_mut)
|
||||||
|
.position(View::take_focus) {
|
||||||
|
self.focus = i;
|
||||||
|
EventResult::Consumed(None)
|
||||||
|
} else {
|
||||||
|
EventResult::Ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for LinearLayout {
|
impl View for LinearLayout {
|
||||||
@ -166,6 +201,7 @@ impl View for LinearLayout {
|
|||||||
let budget_req = req.with(self.orientation, 1);
|
let budget_req = req.with(self.orientation, 1);
|
||||||
// println_stderr!("Budget req: {:?}", budget_req);
|
// println_stderr!("Budget req: {:?}", budget_req);
|
||||||
|
|
||||||
|
// See how they like it that way
|
||||||
let min_sizes: Vec<Vec2> = self.children
|
let min_sizes: Vec<Vec2> = self.children
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|c| c.get_min_size(budget_req))
|
.map(|c| c.get_min_size(budget_req))
|
||||||
@ -174,9 +210,10 @@ impl View for LinearLayout {
|
|||||||
// println_stderr!("Min sizes: {:?}", min_sizes);
|
// println_stderr!("Min sizes: {:?}", min_sizes);
|
||||||
// println_stderr!("Desperate: {:?}", desperate);
|
// println_stderr!("Desperate: {:?}", desperate);
|
||||||
|
|
||||||
// I really hope it fits this time...
|
// This is the lowest we'll ever go. It better fit at least.
|
||||||
if !desperate.fits_in(req) {
|
if !desperate.fits_in(req) {
|
||||||
// Just give up...
|
// Just give up...
|
||||||
|
// TODO: print some error message or something
|
||||||
// println_stderr!("Seriously? {:?} > {:?}???", desperate, req);
|
// println_stderr!("Seriously? {:?} > {:?}???", desperate, req);
|
||||||
self.cache = Some(SizeCache::build(desperate, req));
|
self.cache = Some(SizeCache::build(desperate, req));
|
||||||
return desperate;
|
return desperate;
|
||||||
@ -198,19 +235,25 @@ impl View for LinearLayout {
|
|||||||
|
|
||||||
// So... distribute `available` to reduce the overweight...
|
// So... distribute `available` to reduce the overweight...
|
||||||
// TODO: use child weight in the distribution...
|
// TODO: use child weight in the distribution...
|
||||||
|
|
||||||
|
// We'll give everyone his share of what we have left,
|
||||||
|
// starting with those who ask the least.
|
||||||
overweight.sort_by_key(|&(_, weight)| weight);
|
overweight.sort_by_key(|&(_, weight)| weight);
|
||||||
let mut allocations = vec![0; overweight.len()];
|
let mut allocations = vec![0; overweight.len()];
|
||||||
|
|
||||||
for (i, &(j, weight)) in overweight.iter().enumerate() {
|
for (i, &(j, weight)) in overweight.iter().enumerate() {
|
||||||
|
// This is the number of people we still have to feed.
|
||||||
let remaining = overweight.len() - i;
|
let remaining = overweight.len() - i;
|
||||||
|
// How much we can spare on each one
|
||||||
let budget = available / remaining;
|
let budget = available / remaining;
|
||||||
|
// Maybe he doesn't even need that much?
|
||||||
let spent = min(budget, weight);
|
let spent = min(budget, weight);
|
||||||
allocations[j] = spent;
|
allocations[j] = spent;
|
||||||
available -= spent;
|
available -= spent;
|
||||||
}
|
}
|
||||||
// println_stderr!("Allocations: {:?}", allocations);
|
// println_stderr!("Allocations: {:?}", allocations);
|
||||||
|
|
||||||
// Final lengths are the minimum ones + allocations
|
// Final lengths are the minimum ones + generous allocations
|
||||||
let final_lengths: Vec<Vec2> = min_sizes.iter()
|
let final_lengths: Vec<Vec2> = min_sizes.iter()
|
||||||
.map(|v| self.orientation.get(v))
|
.map(|v| self.orientation.get(v))
|
||||||
.zip(allocations.iter())
|
.zip(allocations.iter())
|
||||||
@ -219,60 +262,66 @@ impl View for LinearLayout {
|
|||||||
.collect();
|
.collect();
|
||||||
// println_stderr!("Final sizes: {:?}", final_lengths);
|
// println_stderr!("Final sizes: {:?}", final_lengths);
|
||||||
|
|
||||||
|
// Let's ask everyone one last time. Everyone should be happy.
|
||||||
|
// (But they may ask more on the other axis.)
|
||||||
let final_sizes: Vec<Vec2> = self.children
|
let final_sizes: Vec<Vec2> = self.children
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, c)| {
|
.map(|(i, c)| c.get_min_size(final_lengths[i]))
|
||||||
c.get_min_size(final_lengths[i])
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
// println_stderr!("Final sizes2: {:?}", final_sizes);
|
// println_stderr!("Final sizes2: {:?}", final_sizes);
|
||||||
|
|
||||||
|
// Let's stack everything to see what it looks like.
|
||||||
let compromise = self.orientation.stack(final_sizes.iter());
|
let compromise = self.orientation.stack(final_sizes.iter());
|
||||||
|
|
||||||
|
// Phew, that was a lot of work! I'm not doing it again.
|
||||||
self.cache = Some(SizeCache::build(compromise, req));
|
self.cache = Some(SizeCache::build(compromise, req));
|
||||||
|
|
||||||
compromise
|
compromise
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn take_focus(&mut self) -> bool {
|
||||||
|
if let Some(i) = self.children
|
||||||
|
.iter_mut()
|
||||||
|
.map(Child::as_mut)
|
||||||
|
.position(View::take_focus) {
|
||||||
|
self.focus = i;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_event(&mut self, event: Event) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
match self.children[self.focus].view.on_event(event) {
|
match self.children[self.focus].view.on_event(event) {
|
||||||
EventResult::Ignored => {
|
EventResult::Ignored => {
|
||||||
match event {
|
match event {
|
||||||
Event::Key(Key::Tab) if self.focus > 0 => {
|
Event::Shift(Key::Tab) if self.focus > 0 => {
|
||||||
self.focus -= 1;
|
self.focus_prev()
|
||||||
EventResult::Consumed(None)
|
|
||||||
}
|
}
|
||||||
Event::Shift(Key::Tab) if self.focus + 1 <
|
Event::Key(Key::Tab) if self.focus + 1 <
|
||||||
self.children.len() => {
|
self.children.len() => {
|
||||||
self.focus += 1;
|
self.focus_next()
|
||||||
EventResult::Consumed(None)
|
|
||||||
}
|
}
|
||||||
Event::Key(Key::Left) if self.orientation ==
|
Event::Key(Key::Left) if self.orientation ==
|
||||||
Orientation::Horizontal &&
|
Orientation::Horizontal &&
|
||||||
self.focus > 0 => {
|
self.focus > 0 => {
|
||||||
self.focus -= 1;
|
self.focus_prev()
|
||||||
EventResult::Consumed(None)
|
|
||||||
}
|
}
|
||||||
Event::Key(Key::Up) if self.orientation ==
|
Event::Key(Key::Up) if self.orientation ==
|
||||||
Orientation::Vertical &&
|
Orientation::Vertical &&
|
||||||
self.focus > 0 => {
|
self.focus > 0 => self.focus_prev(),
|
||||||
self.focus -= 1;
|
|
||||||
EventResult::Consumed(None)
|
|
||||||
}
|
|
||||||
Event::Key(Key::Right) if self.orientation ==
|
Event::Key(Key::Right) if self.orientation ==
|
||||||
Orientation::Horizontal &&
|
Orientation::Horizontal &&
|
||||||
self.focus + 1 <
|
self.focus + 1 <
|
||||||
self.children.len() => {
|
self.children.len() => {
|
||||||
self.focus += 1;
|
self.focus_next()
|
||||||
EventResult::Consumed(None)
|
|
||||||
}
|
}
|
||||||
Event::Key(Key::Down) if self.orientation ==
|
Event::Key(Key::Down) if self.orientation ==
|
||||||
Orientation::Vertical &&
|
Orientation::Vertical &&
|
||||||
self.focus + 1 <
|
self.focus + 1 <
|
||||||
self.children.len() => {
|
self.children.len() => {
|
||||||
self.focus += 1;
|
self.focus_next()
|
||||||
EventResult::Consumed(None)
|
|
||||||
}
|
}
|
||||||
_ => EventResult::Ignored,
|
_ => EventResult::Ignored,
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ impl SizeCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if `self` is still valid for the given `request`.
|
/// Returns `true` if `self` is still valid for the given `request`.
|
||||||
pub fn accept(&self, request: usize) -> bool {
|
pub fn accept(self, request: usize) -> bool {
|
||||||
if request < self.value {
|
if request < self.value {
|
||||||
false
|
false
|
||||||
} else if request == self.value {
|
} else if request == self.value {
|
||||||
|
14
src/xy.rs
14
src/xy.rs
@ -60,9 +60,21 @@ impl <T> XY<Option<T>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl XY<bool> {
|
||||||
|
/// Returns `true` if any of `x` or `y` is `true`.
|
||||||
|
pub fn any(&self) -> bool {
|
||||||
|
self.x || self.y
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if both `x` and `y` are `true`.
|
||||||
|
pub fn both(&self) -> bool {
|
||||||
|
self.x && self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Copy> XY<T> {
|
impl<T: Copy> XY<T> {
|
||||||
/// Creates a `XY` with both `x` and `y` set to `value`.
|
/// Creates a `XY` with both `x` and `y` set to `value`.
|
||||||
pub fn both(value: T) -> Self {
|
pub fn both_from(value: T) -> Self {
|
||||||
XY::new(value, value)
|
XY::new(value, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user