Don't crash on insufficient space

This commit is contained in:
Alexandre Bury 2016-07-16 22:05:28 -07:00
parent ab3a55abaf
commit 8750185f8c
7 changed files with 103 additions and 23 deletions

View File

@ -67,10 +67,14 @@ impl HAlign {
/// `container`, printing at the resulting offset will align the view as
/// desired.
pub fn get_offset(&self, content: usize, container: usize) -> usize {
match *self {
HAlign::Left => 0,
HAlign::Center => (container - content) / 2,
HAlign::Right => (container - content),
if container < content {
0
} else {
match *self {
HAlign::Left => 0,
HAlign::Center => (container - content) / 2,
HAlign::Right => (container - content),
}
}
}
}
@ -82,10 +86,14 @@ impl VAlign {
/// `container`, printing at the resulting offset will align the view as
/// desired.
pub fn get_offset(&self, content: usize, container: usize) -> usize {
match *self {
VAlign::Top => 0,
VAlign::Center => (container - content) / 2,
VAlign::Bottom => (container - content),
if container < content {
0
} else {
match *self {
VAlign::Top => 0,
VAlign::Center => (container - content) / 2,
VAlign::Bottom => (container - content),
}
}
}
}

View File

@ -127,11 +127,19 @@ impl View for Dialog {
.fold(0, |a, b| a + b) + self.buttons.len() - 1
};
let overhead = self.padding + self.borders;
if printer.size.x < overhead.horizontal() {
return;
}
let mut offset = overhead.left +
self.align
.h
.get_offset(width, printer.size.x - overhead.horizontal());
let y = printer.size.y - self.padding.bottom - self.borders.bottom - 1;
let overhead_bottom = self.padding.bottom + self.borders.bottom + 1;
if overhead_bottom > printer.size.y {
return;
}
let y = printer.size.y - overhead_bottom;
for (i, button) in self.buttons.iter().enumerate() {
let size = button.size;
@ -146,9 +154,13 @@ impl View for Dialog {
}
// What do we have left?
let inner_size = printer.size - Vec2::new(0, buttons_height) -
self.borders.combined() -
let taken = Vec2::new(0, buttons_height) +
self.borders.combined() +
self.padding.combined();
if !taken.fits_in(printer.size) {
return;
}
let inner_size = printer.size - taken;
self.content
.draw(&printer.sub_printer(self.borders.top_left() +
@ -186,7 +198,13 @@ impl View for Dialog {
}
// We also remove one row for the buttons.
let content_req = req - (nomans_land + Vec2::new(0, buttons_size.y));
let taken = nomans_land + Vec2::new(0, buttons_size.y);
if !taken.fits_in(req) {
// Bad!!
return taken;
}
let content_req = req - taken;
let content_size = self.content.get_min_size(content_req);
// On the Y axis, we add buttons and content.
@ -207,7 +225,12 @@ impl View for Dialog {
fn layout(&mut self, mut size: Vec2) {
// Padding and borders are taken, sorry.
// TODO: handle border-less themes?
size = size - (self.borders.combined() + self.padding.combined());
let taken = self.borders.combined() + self.padding.combined();
size = if taken.fits_in(size) {
size - taken
} else {
Vec2::zero()
};
// Buttons are kings, we give them everything they want.
let mut buttons_height = 0;
@ -218,6 +241,9 @@ impl View for Dialog {
}
// Poor content will have to make do with what's left.
if buttons_height > size.y {
buttons_height = size.y;
}
self.content.layout(size - Vec2::new(0, buttons_height));
}

View File

@ -239,11 +239,13 @@ impl View for LinearLayout {
// Just give up...
// TODO: print some error message or something
// println_stderr!("Seriously? {:?} > {:?}???", desperate, req);
self.cache = Some(SizeCache::build(desperate, req));
// self.cache = Some(SizeCache::build(desperate, req));
self.cache = None;
return desperate;
}
// This here is how much we're generously offered
// (We just checked that req >= desperate, so the substraction is safe
let mut available = self.orientation.get(&(req - desperate));
// println_stderr!("Available: {:?}", available);
@ -252,7 +254,11 @@ impl View for LinearLayout {
let mut overweight: Vec<(usize, usize)> = sizes.iter()
.map(|v| self.orientation.get(v))
.zip(min_sizes.iter().map(|v| self.orientation.get(v)))
.map(|(a, b)| a - b)
.map(|(a, b)| if a > b {
a - b
} else {
0
})
.enumerate()
.collect();
// println_stderr!("Overweight: {:?}", overweight);

View File

@ -54,10 +54,16 @@ impl Offset {
/// Computes a single-dimension offset requred to draw a view.
pub fn compute_offset(&self, size: usize, available: usize, parent: usize)
-> usize {
match *self {
Offset::Center => (available - size) / 2,
Offset::Absolute(offset) => min(offset, available - size),
Offset::Parent(offset) => min(parent + offset, available - size),
if size > available {
0
} else {
match *self {
Offset::Center => (available - size) / 2,
Offset::Absolute(offset) => min(offset, available - size),
Offset::Parent(offset) => {
min(parent + offset, available - size)
}
}
}
}
}

View File

@ -130,10 +130,14 @@ impl ScrollBase {
pub fn draw<F>(&self, printer: &Printer, line_drawer: F)
where F: Fn(&Printer, usize)
{
if self.view_height == 0 {
return;
}
// Print the content in a sub_printer
let max_y = min(self.view_height,
self.content_height - self.start_line);
let w = if self.scrollable() {
if printer.size.x < 2 { return; }
printer.size.x - 2 + self.scrollbar_padding // TODO: 2
} else {
printer.size.x

View File

@ -22,8 +22,9 @@ impl<T: View> ShadowView<T> {
}
}
fn padding(&self) -> (usize, usize) {
(1 + self.left_padding as usize, 1 + self.top_padding as usize)
fn padding(&self) -> Vec2 {
Vec2::new(1 + self.left_padding as usize,
1 + self.top_padding as usize)
}
/// If set, adds an empty column to the left of the view.
@ -47,17 +48,23 @@ impl<T: View> ViewWrapper for ShadowView<T> {
wrap_impl!(&self.view);
fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 {
let offset = self.padding();
// Make sure req >= offset
let offset = self.padding().or_min(req);
self.view.get_min_size(req - offset) + offset
}
fn wrap_layout(&mut self, size: Vec2) {
let offset = self.padding();
let offset = self.padding().or_min(size);
self.view.layout(size - offset);
}
fn wrap_draw(&self, printer: &Printer) {
if printer.size.y == 0 || printer.size.x == 0 {
// Nothing to do if there's no place to draw.
return;
}
// Skip the first row/column
let printer =
&printer.sub_printer(Vec2::new(self.left_padding as usize,

View File

@ -120,15 +120,30 @@ impl TextView {
fn compute_rows(&mut self, size: Vec2) {
if !self.is_cache_valid(size) {
self.last_size = None;
// Recompute
if size.x == 0 {
// Nothing we can do at this poing.
return;
}
self.rows = LinesIterator::new(&self.content, size.x).collect();
let mut scrollbar = 0;
if self.scrollable && self.rows.len() > size.y {
scrollbar = 2;
if size.x < scrollbar {
// Again, this is a lost cause.
return;
}
// If we're too high, include a scrollbar
self.rows = LinesIterator::new(&self.content,
size.x - scrollbar)
.collect();
if self.rows.is_empty() && !self.content.is_empty() {
return;
}
}
// Desired width, including the scrollbar.
@ -148,6 +163,8 @@ impl TextView {
my_size.y = size.y;
}
// println_stderr!("my: {:?} | si: {:?}", my_size, size);
self.last_size = Some(SizeCache::build(my_size, size));
}
}
@ -214,6 +231,12 @@ impl<'a> Iterator for LinesIterator<'a> {
}
};
if head_bytes == 0 {
// This mean we can't even get a single char?
// Sucks. Let's bail.
return None;
}
self.start += head_bytes;
Some(Row {