mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-10 03:10:41 +00:00
Don't crash on insufficient space
This commit is contained in:
parent
ab3a55abaf
commit
8750185f8c
24
src/align.rs
24
src/align.rs
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user