mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Don't crash on insufficient space
This commit is contained in:
parent
ab3a55abaf
commit
8750185f8c
@ -67,6 +67,9 @@ impl HAlign {
|
|||||||
/// `container`, printing at the resulting offset will align the view as
|
/// `container`, printing at the resulting offset will align the view as
|
||||||
/// desired.
|
/// desired.
|
||||||
pub fn get_offset(&self, content: usize, container: usize) -> usize {
|
pub fn get_offset(&self, content: usize, container: usize) -> usize {
|
||||||
|
if container < content {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
match *self {
|
match *self {
|
||||||
HAlign::Left => 0,
|
HAlign::Left => 0,
|
||||||
HAlign::Center => (container - content) / 2,
|
HAlign::Center => (container - content) / 2,
|
||||||
@ -74,6 +77,7 @@ impl HAlign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl VAlign {
|
impl VAlign {
|
||||||
/// Returns the offset required to position a view.
|
/// Returns the offset required to position a view.
|
||||||
@ -82,6 +86,9 @@ impl VAlign {
|
|||||||
/// `container`, printing at the resulting offset will align the view as
|
/// `container`, printing at the resulting offset will align the view as
|
||||||
/// desired.
|
/// desired.
|
||||||
pub fn get_offset(&self, content: usize, container: usize) -> usize {
|
pub fn get_offset(&self, content: usize, container: usize) -> usize {
|
||||||
|
if container < content {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
match *self {
|
match *self {
|
||||||
VAlign::Top => 0,
|
VAlign::Top => 0,
|
||||||
VAlign::Center => (container - content) / 2,
|
VAlign::Center => (container - content) / 2,
|
||||||
@ -89,3 +96,4 @@ impl VAlign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -127,11 +127,19 @@ impl View for Dialog {
|
|||||||
.fold(0, |a, b| a + b) + self.buttons.len() - 1
|
.fold(0, |a, b| a + b) + self.buttons.len() - 1
|
||||||
};
|
};
|
||||||
let overhead = self.padding + self.borders;
|
let overhead = self.padding + self.borders;
|
||||||
|
if printer.size.x < overhead.horizontal() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let mut offset = overhead.left +
|
let mut offset = overhead.left +
|
||||||
self.align
|
self.align
|
||||||
.h
|
.h
|
||||||
.get_offset(width, printer.size.x - overhead.horizontal());
|
.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() {
|
for (i, button) in self.buttons.iter().enumerate() {
|
||||||
let size = button.size;
|
let size = button.size;
|
||||||
@ -146,9 +154,13 @@ impl View for Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// What do we have left?
|
// What do we have left?
|
||||||
let inner_size = printer.size - Vec2::new(0, buttons_height) -
|
let taken = Vec2::new(0, buttons_height) +
|
||||||
self.borders.combined() -
|
self.borders.combined() +
|
||||||
self.padding.combined();
|
self.padding.combined();
|
||||||
|
if !taken.fits_in(printer.size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let inner_size = printer.size - taken;
|
||||||
|
|
||||||
self.content
|
self.content
|
||||||
.draw(&printer.sub_printer(self.borders.top_left() +
|
.draw(&printer.sub_printer(self.borders.top_left() +
|
||||||
@ -186,7 +198,13 @@ impl View for Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We also remove one row for the buttons.
|
// 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);
|
let content_size = self.content.get_min_size(content_req);
|
||||||
|
|
||||||
// On the Y axis, we add buttons and content.
|
// On the Y axis, we add buttons and content.
|
||||||
@ -207,7 +225,12 @@ impl View for Dialog {
|
|||||||
fn layout(&mut self, mut size: Vec2) {
|
fn layout(&mut self, mut size: Vec2) {
|
||||||
// Padding and borders are taken, sorry.
|
// Padding and borders are taken, sorry.
|
||||||
// TODO: handle border-less themes?
|
// 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.
|
// Buttons are kings, we give them everything they want.
|
||||||
let mut buttons_height = 0;
|
let mut buttons_height = 0;
|
||||||
@ -218,6 +241,9 @@ impl View for Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Poor content will have to make do with what's left.
|
// 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));
|
self.content.layout(size - Vec2::new(0, buttons_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,11 +239,13 @@ impl View for LinearLayout {
|
|||||||
// Just give up...
|
// Just give up...
|
||||||
// TODO: print some error message or something
|
// TODO: print some error message or something
|
||||||
// println_stderr!("Seriously? {:?} > {:?}???", desperate, req);
|
// println_stderr!("Seriously? {:?} > {:?}???", desperate, req);
|
||||||
self.cache = Some(SizeCache::build(desperate, req));
|
// self.cache = Some(SizeCache::build(desperate, req));
|
||||||
|
self.cache = None;
|
||||||
return desperate;
|
return desperate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 substraction is safe
|
||||||
let mut available = self.orientation.get(&(req - desperate));
|
let mut available = self.orientation.get(&(req - desperate));
|
||||||
// println_stderr!("Available: {:?}", available);
|
// println_stderr!("Available: {:?}", available);
|
||||||
|
|
||||||
@ -252,7 +254,11 @@ impl View for LinearLayout {
|
|||||||
let mut overweight: Vec<(usize, usize)> = sizes.iter()
|
let mut overweight: Vec<(usize, usize)> = sizes.iter()
|
||||||
.map(|v| self.orientation.get(v))
|
.map(|v| self.orientation.get(v))
|
||||||
.zip(min_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()
|
.enumerate()
|
||||||
.collect();
|
.collect();
|
||||||
// println_stderr!("Overweight: {:?}", overweight);
|
// println_stderr!("Overweight: {:?}", overweight);
|
||||||
|
@ -54,10 +54,16 @@ impl Offset {
|
|||||||
/// Computes a single-dimension offset requred to draw a view.
|
/// Computes a single-dimension offset requred to draw a view.
|
||||||
pub fn compute_offset(&self, size: usize, available: usize, parent: usize)
|
pub fn compute_offset(&self, size: usize, available: usize, parent: usize)
|
||||||
-> usize {
|
-> usize {
|
||||||
|
if size > available {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
match *self {
|
match *self {
|
||||||
Offset::Center => (available - size) / 2,
|
Offset::Center => (available - size) / 2,
|
||||||
Offset::Absolute(offset) => min(offset, available - size),
|
Offset::Absolute(offset) => min(offset, available - size),
|
||||||
Offset::Parent(offset) => min(parent + 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)
|
pub fn draw<F>(&self, printer: &Printer, line_drawer: F)
|
||||||
where F: Fn(&Printer, usize)
|
where F: Fn(&Printer, usize)
|
||||||
{
|
{
|
||||||
|
if self.view_height == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Print the content in a sub_printer
|
// Print the content in a sub_printer
|
||||||
let max_y = min(self.view_height,
|
let max_y = min(self.view_height,
|
||||||
self.content_height - self.start_line);
|
self.content_height - self.start_line);
|
||||||
let w = if self.scrollable() {
|
let w = if self.scrollable() {
|
||||||
|
if printer.size.x < 2 { return; }
|
||||||
printer.size.x - 2 + self.scrollbar_padding // TODO: 2
|
printer.size.x - 2 + self.scrollbar_padding // TODO: 2
|
||||||
} else {
|
} else {
|
||||||
printer.size.x
|
printer.size.x
|
||||||
|
@ -22,8 +22,9 @@ impl<T: View> ShadowView<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn padding(&self) -> (usize, usize) {
|
fn padding(&self) -> Vec2 {
|
||||||
(1 + self.left_padding as usize, 1 + self.top_padding as usize)
|
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.
|
/// 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);
|
wrap_impl!(&self.view);
|
||||||
|
|
||||||
fn wrap_get_min_size(&mut self, req: Vec2) -> Vec2 {
|
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
|
self.view.get_min_size(req - offset) + offset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_layout(&mut self, size: Vec2) {
|
fn wrap_layout(&mut self, size: Vec2) {
|
||||||
let offset = self.padding();
|
let offset = self.padding().or_min(size);
|
||||||
self.view.layout(size - offset);
|
self.view.layout(size - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_draw(&self, printer: &Printer) {
|
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
|
// Skip the first row/column
|
||||||
let printer =
|
let printer =
|
||||||
&printer.sub_printer(Vec2::new(self.left_padding as usize,
|
&printer.sub_printer(Vec2::new(self.left_padding as usize,
|
||||||
|
@ -120,15 +120,30 @@ impl TextView {
|
|||||||
|
|
||||||
fn compute_rows(&mut self, size: Vec2) {
|
fn compute_rows(&mut self, size: Vec2) {
|
||||||
if !self.is_cache_valid(size) {
|
if !self.is_cache_valid(size) {
|
||||||
|
self.last_size = None;
|
||||||
// Recompute
|
// Recompute
|
||||||
|
|
||||||
|
if size.x == 0 {
|
||||||
|
// Nothing we can do at this poing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.rows = LinesIterator::new(&self.content, size.x).collect();
|
self.rows = LinesIterator::new(&self.content, size.x).collect();
|
||||||
let mut scrollbar = 0;
|
let mut scrollbar = 0;
|
||||||
if self.scrollable && self.rows.len() > size.y {
|
if self.scrollable && self.rows.len() > size.y {
|
||||||
scrollbar = 2;
|
scrollbar = 2;
|
||||||
|
if size.x < scrollbar {
|
||||||
|
// Again, this is a lost cause.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If we're too high, include a scrollbar
|
// If we're too high, include a scrollbar
|
||||||
self.rows = LinesIterator::new(&self.content,
|
self.rows = LinesIterator::new(&self.content,
|
||||||
size.x - scrollbar)
|
size.x - scrollbar)
|
||||||
.collect();
|
.collect();
|
||||||
|
if self.rows.is_empty() && !self.content.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desired width, including the scrollbar.
|
// Desired width, including the scrollbar.
|
||||||
@ -148,6 +163,8 @@ impl TextView {
|
|||||||
my_size.y = size.y;
|
my_size.y = size.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// println_stderr!("my: {:?} | si: {:?}", my_size, size);
|
||||||
self.last_size = Some(SizeCache::build(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;
|
self.start += head_bytes;
|
||||||
|
|
||||||
Some(Row {
|
Some(Row {
|
||||||
|
Loading…
Reference in New Issue
Block a user