Replace SizeRequest with simple Vec2

We may go back to an enum though, to handle text views in LinearLayouts.
But the previous Fixed/AtMost/Unknown distinction was useless.
This commit is contained in:
Alexandre Bury 2016-07-02 00:47:38 -07:00
parent c958093b74
commit 1b1d7166a1
15 changed files with 65 additions and 110 deletions

View File

@ -1,3 +1,5 @@
/*
/// Integer division that rounds up. /// Integer division that rounds up.
pub fn div_up_usize(p: usize, q: usize) -> usize { pub fn div_up_usize(p: usize, q: usize) -> usize {
div_up(p as u32, q as u32) as usize div_up(p as u32, q as u32) as usize
@ -11,3 +13,4 @@ pub fn div_up(p: u32, q: u32) -> u32 {
1 + p / q 1 + p / q
} }
} }
*/

View File

@ -2,7 +2,7 @@
use vec::Vec2; use vec::Vec2;
/// Describes a vertical or horizontal orientation for a view. /// Describes a vertical or horizontal orientation for a view.
#[derive(Clone,Copy,PartialEq)] #[derive(Clone,Copy,Debug,PartialEq)]
pub enum Orientation { pub enum Orientation {
/// Horizontal orientation /// Horizontal orientation
Horizontal, Horizontal,

View File

@ -295,7 +295,6 @@ impl Color {
} else if value.len() == 3 { } else if value.len() == 3 {
// RGB values between 0 and 5 maybe? // RGB values between 0 and 5 maybe?
let rgb: Vec<_> = value.chars().map(|c| c as i16 - '0' as i16).collect(); let rgb: Vec<_> = value.chars().map(|c| c as i16 - '0' as i16).collect();
println!("{:?}", rgb);
if rgb.iter().all(|&i| i >= 0 && i < 6) { if rgb.iter().all(|&i| i >= 0 && i < 6) {
Some(Color::RgbLowRes(rgb[0] as u8, rgb[1] as u8, rgb[2] as u8)) Some(Color::RgbLowRes(rgb[0] as u8, rgb[1] as u8, rgb[2] as u8))
} else { } else {

View File

@ -1,5 +1,7 @@
use std::cmp;
use vec::{ToVec2, Vec2}; use vec::{ToVec2, Vec2};
use super::{DimensionRequest, SizeRequest, View, ViewWrapper}; use super::{View, ViewWrapper};
/// `BoxView` is a wrapper around an other view, with a given minimum size. /// `BoxView` is a wrapper around an other view, with a given minimum size.
pub struct BoxView<T: View> { pub struct BoxView<T: View> {
@ -28,16 +30,18 @@ impl<T: View> BoxView<T> {
impl<T: View> ViewWrapper for BoxView<T> { impl<T: View> ViewWrapper for BoxView<T> {
wrap_impl!(&self.view); wrap_impl!(&self.view);
fn wrap_get_min_size(&self, mut req: SizeRequest) -> Vec2 { fn wrap_get_min_size(&self, mut req: Vec2) -> Vec2 {
if self.size.x > 0 { if self.size.x > 0 {
req.w = DimensionRequest::AtMost(self.size.x); req.x = cmp::min(self.size.x, req.x);
} }
if self.size.y > 0 { if self.size.y > 0 {
req.h = DimensionRequest::AtMost(self.size.y); req.y = cmp::min(self.size.y, req.y);
} }
let mut size = self.view.get_min_size(req); let mut size = self.view.get_min_size(req);
// Did he think he got to decide?
// Of course we have the last word here.
if self.size.x > 0 { if self.size.x > 0 {
size.x = self.size.x; size.x = self.size.x;
} }

View File

@ -3,7 +3,7 @@ use std::rc::Rc;
use theme::ColorStyle; use theme::ColorStyle;
use Cursive; use Cursive;
use vec::Vec2; use vec::Vec2;
use view::{SizeRequest, View}; use view::{View};
use event::*; use event::*;
use printer::Printer; use printer::Printer;
@ -42,7 +42,7 @@ impl View for Button {
}); });
} }
fn get_min_size(&self, _: SizeRequest) -> Vec2 { fn get_min_size(&self, _: Vec2) -> Vec2 {
// Meh. Fixed size we are. // Meh. Fixed size we are.
Vec2::new(2 + self.label.chars().count(), 1) Vec2::new(2 + self.label.chars().count(), 1)
} }

View File

@ -5,7 +5,7 @@ use Cursive;
use align::*; use align::*;
use event::*; use event::*;
use theme::ColorStyle; use theme::ColorStyle;
use view::{DimensionRequest, Selector, SizeRequest, TextView, View}; use view::{Selector, TextView, View};
use view::{Button, SizedView}; use view::{Button, SizedView};
use vec::{ToVec4, Vec2, Vec4}; use vec::{ToVec4, Vec2, Vec4};
use printer::Printer; use printer::Printer;
@ -157,9 +157,9 @@ impl View for Dialog {
} }
fn get_min_size(&self, req: SizeRequest) -> Vec2 { fn get_min_size(&self, req: Vec2) -> Vec2 {
// Padding and borders are not available for kids. // Padding and borders are not available for kids.
let content_req = req.reduced(self.padding.combined() + self.borders.combined()); let content_req = req - (self.padding.combined() + self.borders.combined());
let content_size = self.content.get_min_size(content_req); let content_size = self.content.get_min_size(content_req);
let mut buttons_size = Vec2::new(0, 0); let mut buttons_size = Vec2::new(0, 0);
@ -189,16 +189,13 @@ 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?
size = size - (self.borders.combined() + self.padding.combined()); size = size - (self.borders.combined() + self.padding.combined());
let req = SizeRequest {
w: DimensionRequest::AtMost(size.x),
h: DimensionRequest::AtMost(size.y),
};
// 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;
for button in self.buttons.iter_mut().rev() { for button in self.buttons.iter_mut().rev() {
let size = button.get_min_size(req); let size = button.get_min_size(size);
buttons_height = max(buttons_height, size.y + 1); buttons_height = max(buttons_height, size.y + 1);
button.layout(size); button.layout(size);
} }

View File

@ -4,7 +4,7 @@ use std::cmp::min;
use theme::{ColorStyle, Effect}; use theme::{ColorStyle, Effect};
use vec::Vec2; use vec::Vec2;
use view::{IdView, SizeRequest, View}; use view::{IdView, View};
use event::*; use event::*;
use printer::Printer; use printer::Printer;
@ -123,7 +123,7 @@ impl View for EditView {
self.last_length = size.x; self.last_length = size.x;
} }
fn get_min_size(&self, _: SizeRequest) -> Vec2 { fn get_min_size(&self, _: Vec2) -> Vec2 {
Vec2::new(self.min_length, 1) Vec2::new(self.min_length, 1)
} }

View File

@ -1,4 +1,4 @@
use view::{DimensionRequest, SizeRequest, View, ViewWrapper}; use view::{View, ViewWrapper};
use vec::Vec2; use vec::Vec2;
/// Simple wrapper view that asks for all the space it can get. /// Simple wrapper view that asks for all the space it can get.
@ -16,18 +16,7 @@ impl<T: View> FullView<T> {
impl<T: View> ViewWrapper for FullView<T> { impl<T: View> ViewWrapper for FullView<T> {
wrap_impl!(&self.view); wrap_impl!(&self.view);
fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 { fn wrap_get_min_size(&self, req: Vec2) -> Vec2 {
let w = match req.w { req
DimensionRequest::Fixed(w) |
DimensionRequest::AtMost(w) => w,
DimensionRequest::Unknown => self.view.get_min_size(req).x,
};
let h = match req.h {
DimensionRequest::Fixed(h) |
DimensionRequest::AtMost(h) => h,
DimensionRequest::Unknown => self.view.get_min_size(req).y,
};
Vec2::new(w, h)
} }
} }

View File

@ -1,4 +1,4 @@
use view::{DimensionRequest, SizeRequest, View}; use view::View;
use vec::Vec2; use vec::Vec2;
use printer::Printer; use printer::Printer;
use orientation::Orientation; use orientation::Orientation;
@ -115,6 +115,8 @@ impl View for LinearLayout {
for (i, child) in self.children.iter_mut().enumerate() { for (i, child) in self.children.iter_mut().enumerate() {
child.view.draw(&printer.sub_printer(offset, child.size, i == self.focus)); child.view.draw(&printer.sub_printer(offset, child.size, i == self.focus));
// On the axis given by the orientation,
// add the child size to the offset.
*self.orientation.get_ref(&mut offset) += self.orientation *self.orientation.get_ref(&mut offset) += self.orientation
.get(&child.size); .get(&child.size);
} }
@ -122,18 +124,16 @@ impl View for LinearLayout {
fn layout(&mut self, size: Vec2) { fn layout(&mut self, size: Vec2) {
// Compute the very minimal required size // Compute the very minimal required size
let req = SizeRequest { // Look how mean we are: we offer the whole size to every child.
w: DimensionRequest::AtMost(size.x), // As if they could get it all.
h: DimensionRequest::AtMost(size.y),
};
let min_sizes: Vec<Vec2> = self.children let min_sizes: Vec<Vec2> = self.children
.iter() .iter()
.map(|child| child.view.get_min_size(req)) .map(|child| Vec2::min(size, child.view.get_min_size(size)))
.collect(); .collect();
let min_size = self.orientation.stack(min_sizes.iter()); let min_size = self.orientation.stack(min_sizes.iter());
// Emulate 'non-strict inequality' on integers // Emulate 'non-strict inequality' on integers
// (default comparison on Vec2 is strict) // (default comparison on Vec2 is strict, and (0,1).cmp((1,1)) is undefined)
if !(min_size < size + (1, 1)) { if !(min_size < size + (1, 1)) {
// Error! Not enough space! Emergency procedures! // Error! Not enough space! Emergency procedures!
return; return;
@ -160,7 +160,7 @@ impl View for LinearLayout {
} }
} }
fn get_min_size(&self, req: SizeRequest) -> Vec2 { fn get_min_size(&self, req: Vec2) -> Vec2 {
// First, make a naive scenario: everything will work fine. // First, make a naive scenario: everything will work fine.
let sizes: Vec<Vec2> = self.children let sizes: Vec<Vec2> = self.children
.iter() .iter()

View File

@ -5,7 +5,6 @@ mod view_wrapper;
// Essentials components // Essentials components
mod position; mod position;
mod request;
mod view_path; mod view_path;
// Helper bases // Helper bases
@ -36,7 +35,6 @@ use printer::Printer;
pub use self::position::{Position, Offset}; pub use self::position::{Position, Offset};
pub use self::request::{DimensionRequest, SizeRequest};
pub use self::scroll::ScrollBase; pub use self::scroll::ScrollBase;
pub use self::id_view::IdView; pub use self::id_view::IdView;
@ -65,7 +63,7 @@ pub trait View {
} }
/// Returns the minimum size the view requires under the given restrictions. /// Returns the minimum size the view requires under the given restrictions.
fn get_min_size(&self, SizeRequest) -> Vec2 { fn get_min_size(&self, Vec2) -> Vec2 {
Vec2::new(1, 1) Vec2::new(1, 1)
} }

View File

@ -4,7 +4,7 @@ use std::rc::Rc;
use theme::ColorStyle; use theme::ColorStyle;
use Cursive; use Cursive;
use align::*; use align::*;
use view::{DimensionRequest, IdView, SizeRequest, View}; use view::{IdView, View};
use event::{Event, EventResult, Key}; use event::{Event, EventResult, Key};
use vec::Vec2; use vec::Vec2;
use printer::Printer; use printer::Printer;
@ -150,7 +150,10 @@ impl<T: 'static> View for SelectView<T> {
}); });
} }
fn get_min_size(&self, req: SizeRequest) -> Vec2 { fn get_min_size(&self, req: Vec2) -> Vec2 {
// Items here are not compressible.
// So no matter what the horizontal requirements are,
// we'll still return our longest item.
let w = self.items let w = self.items
.iter() .iter()
.map(|item| item.label.len()) .map(|item| item.label.len())
@ -158,13 +161,7 @@ impl<T: 'static> View for SelectView<T> {
.unwrap_or(1); .unwrap_or(1);
let h = self.items.len(); let h = self.items.len();
let scrolling = if let DimensionRequest::Fixed(r_h) = req.h { let scrolling = req.y < h;
r_h < h
} else if let DimensionRequest::AtMost(r_h) = req.h {
r_h < h
} else {
false
};
// Add 2 spaces for the scrollbar if we need // Add 2 spaces for the scrollbar if we need
let w = if scrolling { let w = if scrolling {

View File

@ -1,4 +1,4 @@
use view::{SizeRequest, View, ViewWrapper}; use view::{View, ViewWrapper};
use printer::Printer; use printer::Printer;
use vec::Vec2; use vec::Vec2;
use theme::ColorStyle; use theme::ColorStyle;
@ -20,8 +20,8 @@ impl<T: View> ShadowView<T> {
impl<T: View> ViewWrapper for ShadowView<T> { impl<T: View> ViewWrapper for ShadowView<T> {
wrap_impl!(&self.view); wrap_impl!(&self.view);
fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 { fn wrap_get_min_size(&self, req: Vec2) -> Vec2 {
self.view.get_min_size(req.reduced((2, 2))) + (2, 2) self.view.get_min_size(req - (2, 2)) + (2, 2)
} }
fn wrap_layout(&mut self, size: Vec2) { fn wrap_layout(&mut self, size: Vec2) {

View File

@ -1,7 +1,7 @@
use std::any::Any; use std::any::Any;
use vec::Vec2; use vec::Vec2;
use view::{DimensionRequest, Selector, ShadowView, SizeRequest, View, Position}; use view::{Selector, ShadowView, View, Position};
use event::{Event, EventResult}; use event::{Event, EventResult};
use printer::Printer; use printer::Printer;
use theme::ColorStyle; use theme::ColorStyle;
@ -78,14 +78,10 @@ impl View for StackView {
fn layout(&mut self, size: Vec2) { fn layout(&mut self, size: Vec2) {
// The call has been made, we can't ask for more space anymore. // The call has been made, we can't ask for more space anymore.
// Let's make do with what we have. // Let's make do with what we have.
let req = SizeRequest {
w: DimensionRequest::AtMost(size.x),
h: DimensionRequest::AtMost(size.y),
};
for layer in &mut self.layers { for layer in &mut self.layers {
// Give each guy what he asks for, within the budget constraints. // Give each guy what he asks for, within the budget constraints.
layer.size = Vec2::min(size, layer.view.get_min_size(req)); layer.size = Vec2::min(size, layer.view.get_min_size(size));
layer.view.layout(layer.size); layer.view.layout(layer.size);
// We do it here instead of when adding a new layer because...? // We do it here instead of when adding a new layer because...?
@ -97,16 +93,13 @@ impl View for StackView {
} }
} }
fn get_min_size(&self, size: SizeRequest) -> Vec2 { fn get_min_size(&self, size: Vec2) -> Vec2 {
// The min size is the max of all children's // The min size is the max of all children's
let mut s = Vec2::new(1, 1);
for layer in &self.layers { self.layers
let vs = layer.view.get_min_size(size); .iter()
s = Vec2::max(s, vs); .map(|layer| layer.view.get_min_size(size))
} .fold(Vec2::new(1, 1), Vec2::max)
s
} }
fn take_focus(&mut self) -> bool { fn take_focus(&mut self) -> bool {

View File

@ -1,8 +1,7 @@
use std::cmp::max; use std::cmp::max;
use vec::Vec2; use vec::Vec2;
use view::{DimensionRequest, SizeRequest, View}; use view::View;
use div::*;
use printer::Printer; use printer::Printer;
use align::*; use align::*;
use event::*; use event::*;
@ -105,15 +104,6 @@ impl TextView {
.fold(0, |sum, x| sum + x) .fold(0, |sum, x| sum + x)
} }
// Given the specified height,
// how many columns do we need to properly display?
fn get_num_cols(&self, max_height: usize) -> usize {
let len = self.content.chars().count();
(div_up_usize(len, max_height)..len)
.find(|w| self.get_num_lines(*w) <= max_height)
.unwrap()
}
// In the absence of any constraint, what size would we like? // In the absence of any constraint, what size would we like?
fn get_ideal_size(&self) -> Vec2 { fn get_ideal_size(&self) -> Vec2 {
let mut max_width = 0; let mut max_width = 0;
@ -244,34 +234,19 @@ impl View for TextView {
EventResult::Consumed(None) EventResult::Consumed(None)
} }
fn get_min_size(&self, size: SizeRequest) -> Vec2 { fn get_min_size(&self, size: Vec2) -> Vec2 {
match (size.w, size.h) {
// If we have no directive, ask for a single big line. // If we have no directive, ask for a single big line.
// TODO: what if the text has newlines?? // TODO: what if the text has newlines??
(DimensionRequest::Unknown, DimensionRequest::Unknown) => self.get_ideal_size(),
(DimensionRequest::Fixed(w), _) => {
// In a BoxView or something.
let h = self.get_num_lines(w);
Vec2::new(w, h)
}
(_, DimensionRequest::Fixed(h)) => {
let w = self.get_num_cols(h);
Vec2::new(w, h)
}
(DimensionRequest::AtMost(w), _) => {
// Don't _force_ the max width, but take it if we have to. // Don't _force_ the max width, but take it if we have to.
let ideal = self.get_ideal_size(); let ideal = self.get_ideal_size();
if w >= ideal.x { if size.x >= ideal.x {
// This is the cheap path
ideal ideal
} else { } else {
// This is the expensive one :( // Ok, se we have less width than we'd like.
let h = self.get_num_lines(w); // Take everything we can, and plan our height accordingly.
Vec2::new(w, h) let h = self.get_num_lines(size.x);
} Vec2::new(size.x, h)
}
_ => unreachable!(),
} }
} }

View File

@ -1,7 +1,7 @@
use std::any::Any; use std::any::Any;
use vec::Vec2; use vec::Vec2;
use view::{Selector, SizeRequest, View}; use view::{Selector, View};
use printer::Printer; use printer::Printer;
use event::{Event, EventResult}; use event::{Event, EventResult};
@ -21,7 +21,7 @@ pub trait ViewWrapper {
} }
/// Wraps the get_min_size method. /// Wraps the get_min_size method.
fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 { fn wrap_get_min_size(&self, req: Vec2) -> Vec2 {
self.get_view().get_min_size(req) self.get_view().get_min_size(req)
} }
@ -50,7 +50,7 @@ impl<T: ViewWrapper> View for T {
self.wrap_draw(printer); self.wrap_draw(printer);
} }
fn get_min_size(&self, req: SizeRequest) -> Vec2 { fn get_min_size(&self, req: Vec2) -> Vec2 {
self.wrap_get_min_size(req) self.wrap_get_min_size(req)
} }