Fix desperate LinearLayout

This commit is contained in:
Alexandre Bury 2018-09-12 16:13:41 -07:00
parent be977c705f
commit 810dc6a591
4 changed files with 24 additions and 11 deletions

View File

@ -63,7 +63,6 @@ impl<'a> Iterator for LinesIterator<'a> {
fn next(&mut self) -> Option<Row> { fn next(&mut self) -> Option<Row> {
let row = self.iter.next()?; let row = self.iter.next()?;
// println!("Got a row: {:?}", row);
let start = row.segments.first()?.start; let start = row.segments.first()?.start;
let end = row.segments.last()?.end; let end = row.segments.last()?.end;

View File

@ -78,7 +78,7 @@ impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator
// Save the current offset. // Save the current offset.
let offset = self.offset; let offset = self.offset;
// eprintln!("Available: {}", self.available); // debug!("Available: {}", self.available);
let length = let length =
min(self.available, *child.size.get(self.orientation)); min(self.available, *child.size.get(self.orientation));
@ -336,16 +336,16 @@ fn try_focus(
impl View for LinearLayout { impl View for LinearLayout {
fn draw(&self, printer: &Printer) { fn draw(&self, printer: &Printer) {
// Use pre-computed sizes // Use pre-computed sizes
// eprintln!("Pre loop!"); // debug!("Pre loop!");
for (i, item) in ChildIterator::new( for (i, item) in ChildIterator::new(
self.children.iter(), self.children.iter(),
self.orientation, self.orientation,
*printer.size.get(self.orientation), *printer.size.get(self.orientation),
).enumerate() ).enumerate()
{ {
// eprintln!("Printer size: {:?}", printer.size); // debug!("Printer size: {:?}", printer.size);
// eprintln!("Child size: {:?}", item.child.size); // debug!("Child size: {:?}", item.child.size);
// eprintln!("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.size)
@ -364,7 +364,7 @@ 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. // If we can get away without breaking a sweat, you can bet we will.
// eprintln!("Laying out with {:?}", size); // debug!("Laying out with {:?}", size);
if self.get_cache(size).is_none() { if self.get_cache(size).is_none() {
self.required_size(size); self.required_size(size);
} }
@ -387,6 +387,7 @@ impl View for LinearLayout {
if let Some(size) = self.get_cache(req) { if let Some(size) = self.get_cache(req) {
return size; return size;
} }
debug!("Req: {:?}", req);
// First, make a naive scenario: everything will work fine. // First, make a naive scenario: everything will work fine.
let ideal_sizes: Vec<Vec2> = self let ideal_sizes: Vec<Vec2> = self
@ -425,7 +426,7 @@ impl View for LinearLayout {
// This is the lowest we'll ever go. It better fit at least. // This is the lowest we'll ever go. It better fit at least.
let orientation = self.orientation; let orientation = self.orientation;
if !desperate.fits_in(req) { if desperate.get(orientation) > req.get(orientation) {
// Just give up... // Just give up...
// TODO: hard-cut // TODO: hard-cut
cap( cap(
@ -447,7 +448,8 @@ impl View for LinearLayout {
// This here is how much we're generously offered // This here is how much we're generously offered
// (We just checked that req >= desperate, so the subtraction is safe // (We just checked that req >= desperate, so the subtraction is safe
let mut available = self.orientation.get(&(req - desperate)); let mut available =
self.orientation.get(&(req.saturating_sub(desperate)));
debug!("Available: {:?}", available); debug!("Available: {:?}", available);
// Here, we have to make a compromise between the ideal // Here, we have to make a compromise between the ideal

View File

@ -56,9 +56,11 @@ impl Placement {
enum ChildWrapper<T: View> { enum ChildWrapper<T: View> {
// Some views include a shadow around. // Some views include a shadow around.
Shadow(ShadowView<Layer<T>>), Shadow(ShadowView<Layer<T>>),
// Some include a background.
// Some include only include a background.
Backfilled(Layer<T>), Backfilled(Layer<T>),
// Some views don't (fullscreen views mostly)
// Some views don't even have a background (they'll be transparent).
Plain(T), Plain(T),
} }

View File

@ -18,7 +18,10 @@ use {Printer, With, XY};
pub struct TextArea { pub struct TextArea {
// TODO: use a smarter data structure (rope?) // TODO: use a smarter data structure (rope?)
content: String, content: String,
/// Byte offsets within `content` representing text rows /// Byte offsets within `content` representing text rows
///
/// Invariant: never empty.
rows: Vec<Row>, rows: Vec<Row>,
/// When `false`, we don't take any input. /// When `false`, we don't take any input.
@ -36,6 +39,8 @@ pub struct TextArea {
} }
fn make_rows(text: &str, width: usize) -> Vec<Row> { fn make_rows(text: &str, width: usize) -> Vec<Row> {
// We can't make rows with width=0, so force at least width=1.
let width = usize::max(width, 1);
LinesIterator::new(text, width).show_spaces().collect() LinesIterator::new(text, width).show_spaces().collect()
} }
@ -142,6 +147,10 @@ impl TextArea {
/// Finds the row containing the grapheme at the given offset /// Finds the row containing the grapheme at the given offset
fn row_at(&self, offset: usize) -> usize { fn row_at(&self, offset: usize) -> usize {
debug!("Offset: {}", offset); debug!("Offset: {}", offset);
assert!(!self.rows.is_empty());
assert!(offset >= self.rows[0].start);
self.rows self.rows
.iter() .iter()
.enumerate() .enumerate()
@ -160,6 +169,7 @@ impl TextArea {
/// Finds the row containing the cursor /// Finds the row containing the cursor
fn selected_row(&self) -> usize { fn selected_row(&self) -> usize {
assert!(!self.rows.is_empty(), "Rows should never be empty.");
self.row_at(self.cursor) self.row_at(self.cursor)
} }