Fix size confusion in LinearLayout::Child

This commit is contained in:
Alexandre Bury 2020-06-08 19:57:55 -07:00
parent 5b3f4e95a4
commit a68e237c81
4 changed files with 47 additions and 29 deletions

View File

@ -31,6 +31,5 @@ install:
build: false build: false
# Equivalent to Travis' `script` phase # Equivalent to Travis' `script` phase
# TODO modify this phase as you see fit
test_script: test_script:
- cd cursive && cargo test --verbose --all --no-default-features --features markdown,crossterm-backend - cd cursive && cargo test --verbose --no-default-features --features markdown,crossterm-backend

View File

@ -447,6 +447,11 @@ impl MouseEvent {
/// Returns `true` if `self` is an event that can grab focus. /// Returns `true` if `self` is an event that can grab focus.
/// ///
/// This includes `Press`, `WheelUp` and `WheelDown`. /// This includes `Press`, `WheelUp` and `WheelDown`.
///
/// It does _not_ include `Release` or `Hold`.
///
/// It means you should be able to grab a scroll bar, and move the mouse
/// away from the view, without actually changing the focus.
pub fn grabs_focus(self) -> bool { pub fn grabs_focus(self) -> bool {
match self { match self {
MouseEvent::Press(_) MouseEvent::Press(_)

View File

@ -33,17 +33,26 @@ pub struct LinearLayout {
struct Child { struct Child {
view: Box<dyn View>, view: Box<dyn View>,
// The last result from the child's required_size // The last result from the child's required_size
// Doesn't have to be what the child actually gets. // Doesn't have to be what the child actually gets.
size: Vec2, required_size: Vec2,
last_size: Vec2,
weight: usize, weight: usize,
} }
impl Child { impl Child {
// Compute and caches the required size. // Compute and caches the required size.
fn required_size(&mut self, req: Vec2) -> Vec2 { fn required_size(&mut self, req: Vec2) -> Vec2 {
self.size = self.view.required_size(req); self.required_size = self.view.required_size(req);
self.size self.required_size
}
fn layout(&mut self, size: Vec2) {
self.last_size = size;
self.view.layout(size);
} }
fn as_view(&self) -> &dyn View { fn as_view(&self) -> &dyn View {
@ -95,8 +104,10 @@ impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator
// debug!("Available: {}", self.available); // debug!("Available: {}", self.available);
let length = let length = min(
min(self.available, *child.size.get(self.orientation)); self.available,
*child.required_size.get(self.orientation),
);
// Allocated width // Allocated width
self.available = self.available.saturating_sub(length); self.available = self.available.saturating_sub(length);
@ -163,7 +174,8 @@ impl LinearLayout {
pub fn add_child<V: IntoBoxedView + 'static>(&mut self, view: V) { pub fn add_child<V: IntoBoxedView + 'static>(&mut self, view: V) {
self.children.push(Child { self.children.push(Child {
view: view.as_boxed_view(), view: view.as_boxed_view(),
size: Vec2::zero(), required_size: Vec2::zero(),
last_size: Vec2::zero(),
weight: 0, weight: 0,
}); });
self.invalidate(); self.invalidate();
@ -183,7 +195,8 @@ impl LinearLayout {
i, i,
Child { Child {
view: view.as_boxed_view(), view: view.as_boxed_view(),
size: Vec2::zero(), required_size: Vec2::zero(),
last_size: Vec2::zero(),
weight: 0, weight: 0,
}, },
); );
@ -384,7 +397,7 @@ impl LinearLayout {
{ {
// Get the child size: // Get the child size:
// this will give us the allowed window for a click. // this will give us the allowed window for a click.
let child_size = item.child.size.get(self.orientation); let child_size = item.child.last_size.get(self.orientation);
if item.offset + child_size > position { if item.offset + child_size > position {
if item.child.view.take_focus(direction::Direction::none()) if item.child.view.take_focus(direction::Direction::none())
@ -421,11 +434,11 @@ impl View for LinearLayout {
.enumerate() .enumerate()
{ {
// debug!("Printer size: {:?}", printer.size); // debug!("Printer size: {:?}", printer.size);
// debug!("Child size: {:?}", item.child.size); // debug!("Child size: {:?}", item.child.required_size);
// debug!("Offset: {:?}", item.offset); // debug!("Offset: {:?}", item.offset);
let printer = &printer let printer = &printer
.offset(self.orientation.make_vec(item.offset, 0)) .offset(self.orientation.make_vec(item.offset, 0))
.cropped(item.child.size) .cropped(item.child.last_size)
.focused(i == self.focus); .focused(i == self.focus);
item.child.view.draw(printer); item.child.view.draw(printer);
} }
@ -440,9 +453,8 @@ impl View for LinearLayout {
} }
fn layout(&mut self, size: Vec2) { fn layout(&mut self, size: Vec2) {
// If we can get away without breaking a sweat, you can bet we will.
// debug!("Laying out with {:?}", size);
if self.get_cache(size).is_none() { if self.get_cache(size).is_none() {
// Build the cache if needed.
self.required_size(size); self.required_size(size);
} }
@ -453,9 +465,9 @@ impl View for LinearLayout {
ChildIterator::new(self.children.iter_mut(), o, *size.get(o)) ChildIterator::new(self.children.iter_mut(), o, *size.get(o))
{ {
// Every item has the same size orthogonal to the layout // Every item has the same size orthogonal to the layout
item.child.size.set_axis_from(o.swap(), &size); let size = size.with_axis(o, item.length);
item.child.view.layout(size.with_axis(o, item.length)); item.child.layout(size);
} }
} }
@ -509,7 +521,7 @@ impl View for LinearLayout {
cap( cap(
self.children self.children
.iter_mut() .iter_mut()
.map(|c| c.size.get_mut(orientation)), .map(|c| c.required_size.get_mut(orientation)),
*req.get(self.orientation), *req.get(self.orientation),
); );
@ -595,21 +607,21 @@ impl View for LinearLayout {
// In what order will we iterate on the children? // In what order will we iterate on the children?
let rel = source.relative(self.orientation); let rel = source.relative(self.orientation);
// We activate from_focus only if coming from the "sides". // We activate from_focus only if coming from the "sides".
let i = if let Some(i) = self let mut get_next_focus = || {
.iter_mut(rel.is_none(), rel.unwrap_or(direction::Relative::Front)) self.iter_mut(
rel.is_none(),
rel.unwrap_or(direction::Relative::Front),
)
.filter_map(|p| try_focus(p, source)) .filter_map(|p| try_focus(p, source))
.next() .next()
{
// ... we can't update `self.focus` here,
// because rustc thinks we still borrow `self`.
// :(
i
} else {
return false;
}; };
if let Some(i) = get_next_focus() {
self.focus = i; self.focus = i;
true true
} else {
false
}
} }
fn on_event(&mut self, event: Event) -> EventResult { fn on_event(&mut self, event: Event) -> EventResult {
@ -714,7 +726,7 @@ impl View for LinearLayout {
let offset = self.orientation.make_vec(item.offset, 0); let offset = self.orientation.make_vec(item.offset, 0);
// And ask the child its own area. // And ask the child its own area.
let rect = item.child.view.important_area(item.child.size); let rect = item.child.view.important_area(item.child.last_size);
// Add `offset` to the rect. // Add `offset` to the rect.
rect + offset rect + offset

View File

@ -186,6 +186,8 @@ pub struct TextView {
rows: Vec<Row>, rows: Vec<Row>,
align: Align, align: Align,
// TODO: remove now that we have styled text?
effect: Effect, effect: Effect,
// True if we can wrap long lines. // True if we can wrap long lines.