fix: consider scrollable in TextArea required size

This commit is contained in:
Alexandre Bury 2017-07-17 09:55:48 -07:00
parent 94c67b2257
commit 20e6938bbb
2 changed files with 46 additions and 33 deletions

View File

@ -156,9 +156,12 @@ impl<T: View> ViewWrapper for BoxView<T> {
let req = self.size.zip_map(req, SizeConstraint::available); let req = self.size.zip_map(req, SizeConstraint::available);
let child_size = self.view.required_size(req); let child_size = self.view.required_size(req);
let result = self.size let result = self.size
.zip_map(child_size.zip(req), SizeConstraint::result); .zip_map(child_size.zip(req), SizeConstraint::result);
// println_stderr!("{:?}", result);
if self.squishable { if self.squishable {
// We respect the request if we're less or equal. // We respect the request if we're less or equal.
let respect_req = result.zip_map(req, |res, req| res <= req); let respect_req = result.zip_map(req, |res, req| res <= req);

View File

@ -36,9 +36,7 @@ pub struct TextArea {
} }
fn make_rows(text: &str, width: usize) -> Vec<Row> { fn make_rows(text: &str, width: usize) -> Vec<Row> {
LinesIterator::new(text, width) LinesIterator::new(text, width).show_spaces().collect()
.show_spaces()
.collect()
} }
new_default!(TextArea); new_default!(TextArea);
@ -157,10 +155,7 @@ impl TextArea {
} }
let text = &self.content[self.rows[row].start..self.cursor]; let text = &self.content[self.rows[row].start..self.cursor];
text.graphemes(true) text.graphemes(true).last().unwrap().len()
.last()
.unwrap()
.len()
}; };
self.cursor -= len; self.cursor -= len;
} }
@ -186,7 +181,8 @@ impl TextArea {
fn fix_ghost_row(&mut self) { fn fix_ghost_row(&mut self) {
if self.rows.is_empty() || if self.rows.is_empty() ||
self.rows.last().unwrap().end != self.content.len() { self.rows.last().unwrap().end != self.content.len()
{
// Add a fake, empty row at the end. // Add a fake, empty row at the end.
self.rows.push(Row { self.rows.push(Row {
start: self.content.len(), start: self.content.len(),
@ -312,10 +308,12 @@ impl TextArea {
// We don't need to go beyond a newline. // We don't need to go beyond a newline.
// If we don't find one, end of the text it is. // If we don't find one, end of the text it is.
// println_stderr!("Cursor: {}", self.cursor); // println_stderr!("Cursor: {}", self.cursor);
let last_byte = self.content[self.cursor..] let last_byte = self.content[self.cursor..].find('\n').map(|i| {
.find('\n') 1 + i + self.cursor
.map(|i| 1 + i + self.cursor); });
let last_row = last_byte.map_or(self.rows.len(), |last_byte| self.row_at(last_byte)); let last_row = last_byte.map_or(self.rows.len(), |last_byte| {
self.row_at(last_byte)
});
let last_byte = last_byte.unwrap_or_else(|| self.content.len()); let last_byte = last_byte.unwrap_or_else(|| self.content.len());
// println_stderr!("Content: `{}` (len={})", // println_stderr!("Content: `{}` (len={})",
@ -335,13 +333,13 @@ impl TextArea {
// First attempt, if scrollbase status didn't change. // First attempt, if scrollbase status didn't change.
// println_stderr!("Rows: {:?}", self.rows); // println_stderr!("Rows: {:?}", self.rows);
let new_rows = make_rows(&self.content[first_byte..last_byte], let new_rows =
available); make_rows(&self.content[first_byte..last_byte], available);
// How much did this add? // How much did this add?
// println_stderr!("New rows: {:?}", new_rows); // println_stderr!("New rows: {:?}", new_rows);
// println_stderr!("{}-{}", first_row, last_row); // println_stderr!("{}-{}", first_row, last_row);
let new_row_count = self.rows.len() + new_rows.len() + first_row - let new_row_count = self.rows.len() + new_rows.len() + first_row -
last_row; last_row;
if !scrollable && new_row_count > size.y { if !scrollable && new_row_count > size.y {
// We just changed scrollable status. // We just changed scrollable status.
// This changes everything. // This changes everything.
@ -354,8 +352,8 @@ impl TextArea {
// Otherwise, replace stuff. // Otherwise, replace stuff.
let affected_rows = first_row..last_row; let affected_rows = first_row..last_row;
let replacement_rows = new_rows.into_iter() let replacement_rows =
.map(|row| row.shifted(first_byte)); new_rows.into_iter().map(|row| row.shifted(first_byte));
VecExt::splice(&mut self.rows, affected_rows, replacement_rows); VecExt::splice(&mut self.rows, affected_rows, replacement_rows);
self.fix_ghost_row(); self.fix_ghost_row();
self.scrollbase.set_heights(size.y, self.rows.len()); self.scrollbase.set_heights(size.y, self.rows.len());
@ -364,10 +362,17 @@ impl TextArea {
impl View for TextArea { impl View for TextArea {
fn required_size(&mut self, constraint: Vec2) -> Vec2 { fn required_size(&mut self, constraint: Vec2) -> Vec2 {
// Make sure our structure is up to date
self.compute_rows(constraint); self.compute_rows(constraint);
// Ideally, we'd want x = the longest row + 1
// (we always keep a space at the end)
// And y = number of rows
// println_stderr!("{:?}", self.rows);
let scroll_width = if self.rows.len() > constraint.y { 1 } else { 0 };
Vec2::new( Vec2::new(
1 + self.rows.iter().map(|r| r.width).max().unwrap_or(1), scroll_width + 1 + self.rows.iter().map(|r| r.width).max().unwrap_or(1),
self.rows.len() self.rows.len(),
) )
} }
@ -384,10 +389,12 @@ impl View for TextArea {
} else { } else {
printer.size.x printer.size.x
}; };
printer.with_effect(effect, printer.with_effect(
|printer| for y in 0..printer.size.y { effect,
printer.print_hline((0, y), w, " "); |printer| for y in 0..printer.size.y {
}); printer.print_hline((0, y), w, " ");
},
);
// println_stderr!("Content: `{}`", &self.content); // println_stderr!("Content: `{}`", &self.content);
self.scrollbase.draw(printer, |printer, i| { self.scrollbase.draw(printer, |printer, i| {
@ -396,19 +403,19 @@ impl View for TextArea {
// println_stderr!("row: {:?}", row); // println_stderr!("row: {:?}", row);
let text = &self.content[row.start..row.end]; let text = &self.content[row.start..row.end];
// println_stderr!("row text: `{}`", text); // println_stderr!("row text: `{}`", text);
printer.with_effect(effect, |printer| { printer.with_effect(
printer.print((0, 0), text); effect,
}); |printer| { printer.print((0, 0), text); },
);
if printer.focused && i == self.selected_row() { if printer.focused && i == self.selected_row() {
let cursor_offset = self.cursor - row.start; let cursor_offset = self.cursor - row.start;
let c = if cursor_offset == text.len() { let c = if cursor_offset == text.len() {
"_" "_"
} else { } else {
text[cursor_offset..] text[cursor_offset..].graphemes(true).next().expect(
.graphemes(true) "Found no char!",
.next() )
.expect("Found no char!")
}; };
let offset = text[..cursor_offset].width(); let offset = text[..cursor_offset].width();
printer.print((offset, 0), c); printer.print((offset, 0), c);
@ -431,7 +438,8 @@ impl View for TextArea {
let row = self.selected_row(); let row = self.selected_row();
self.cursor = self.rows[row].end; self.cursor = self.rows[row].end;
if row + 1 < self.rows.len() && if row + 1 < self.rows.len() &&
self.cursor == self.rows[row + 1].start { self.cursor == self.rows[row + 1].start
{
self.move_left(); self.move_left();
} }
} }
@ -441,8 +449,10 @@ impl View for TextArea {
self.cursor = self.rows[self.selected_row()].start self.cursor = self.rows[self.selected_row()].start
} }
Event::Key(Key::Up) if self.selected_row() > 0 => self.move_up(), Event::Key(Key::Up) if self.selected_row() > 0 => self.move_up(),
Event::Key(Key::Down) if self.selected_row() + 1 < Event::Key(Key::Down)
self.rows.len() => self.move_down(), if self.selected_row() + 1 < self.rows.len() => {
self.move_down()
}
Event::Key(Key::PageUp) => self.page_up(), Event::Key(Key::PageUp) => self.page_up(),
Event::Key(Key::PageDown) => self.page_down(), Event::Key(Key::PageDown) => self.page_down(),
Event::Key(Key::Left) if self.cursor > 0 => self.move_left(), Event::Key(Key::Left) if self.cursor > 0 => self.move_left(),