From 1b1d7166a1d1abda9b8d538e81e04cac2e59c3f1 Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Sat, 2 Jul 2016 00:47:38 -0700 Subject: [PATCH] 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. --- src/div.rs | 3 +++ src/orientation.rs | 2 +- src/theme.rs | 1 - src/view/box_view.rs | 12 ++++++--- src/view/button.rs | 4 +-- src/view/dialog.rs | 13 ++++------ src/view/edit_view.rs | 4 +-- src/view/full_view.rs | 17 +++---------- src/view/linear_layout.rs | 16 ++++++------ src/view/mod.rs | 4 +-- src/view/select_view.rs | 15 +++++------- src/view/shadow_view.rs | 6 ++--- src/view/stack_view.rs | 21 ++++++---------- src/view/text_view.rs | 51 ++++++++++----------------------------- src/view/view_wrapper.rs | 6 ++--- 15 files changed, 65 insertions(+), 110 deletions(-) diff --git a/src/div.rs b/src/div.rs index c6a3a4b..4704b75 100644 --- a/src/div.rs +++ b/src/div.rs @@ -1,3 +1,5 @@ + +/* /// Integer division that rounds up. pub fn div_up_usize(p: usize, q: usize) -> 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 } } +*/ diff --git a/src/orientation.rs b/src/orientation.rs index e37fe5a..5b9176d 100644 --- a/src/orientation.rs +++ b/src/orientation.rs @@ -2,7 +2,7 @@ use vec::Vec2; /// Describes a vertical or horizontal orientation for a view. -#[derive(Clone,Copy,PartialEq)] +#[derive(Clone,Copy,Debug,PartialEq)] pub enum Orientation { /// Horizontal orientation Horizontal, diff --git a/src/theme.rs b/src/theme.rs index b98a948..bf9f338 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -295,7 +295,6 @@ impl Color { } else if value.len() == 3 { // RGB values between 0 and 5 maybe? 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) { Some(Color::RgbLowRes(rgb[0] as u8, rgb[1] as u8, rgb[2] as u8)) } else { diff --git a/src/view/box_view.rs b/src/view/box_view.rs index 2bb2ad3..ef821a3 100644 --- a/src/view/box_view.rs +++ b/src/view/box_view.rs @@ -1,5 +1,7 @@ +use std::cmp; + 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. pub struct BoxView { @@ -28,16 +30,18 @@ impl BoxView { impl ViewWrapper for BoxView { 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 { - req.w = DimensionRequest::AtMost(self.size.x); + req.x = cmp::min(self.size.x, req.x); } 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); + // Did he think he got to decide? + // Of course we have the last word here. if self.size.x > 0 { size.x = self.size.x; } diff --git a/src/view/button.rs b/src/view/button.rs index e041d81..07b93b4 100644 --- a/src/view/button.rs +++ b/src/view/button.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use theme::ColorStyle; use Cursive; use vec::Vec2; -use view::{SizeRequest, View}; +use view::{View}; use event::*; 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. Vec2::new(2 + self.label.chars().count(), 1) } diff --git a/src/view/dialog.rs b/src/view/dialog.rs index d41dae4..a732352 100644 --- a/src/view/dialog.rs +++ b/src/view/dialog.rs @@ -5,7 +5,7 @@ use Cursive; use align::*; use event::*; use theme::ColorStyle; -use view::{DimensionRequest, Selector, SizeRequest, TextView, View}; +use view::{Selector, TextView, View}; use view::{Button, SizedView}; use vec::{ToVec4, Vec2, Vec4}; 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. - 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 mut buttons_size = Vec2::new(0, 0); @@ -189,16 +189,13 @@ 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 req = SizeRequest { - w: DimensionRequest::AtMost(size.x), - h: DimensionRequest::AtMost(size.y), - }; // Buttons are kings, we give them everything they want. let mut buttons_height = 0; 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); button.layout(size); } diff --git a/src/view/edit_view.rs b/src/view/edit_view.rs index 7544ac0..0578495 100644 --- a/src/view/edit_view.rs +++ b/src/view/edit_view.rs @@ -4,7 +4,7 @@ use std::cmp::min; use theme::{ColorStyle, Effect}; use vec::Vec2; -use view::{IdView, SizeRequest, View}; +use view::{IdView, View}; use event::*; use printer::Printer; @@ -123,7 +123,7 @@ impl View for EditView { 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) } diff --git a/src/view/full_view.rs b/src/view/full_view.rs index 50662e0..f90d12a 100644 --- a/src/view/full_view.rs +++ b/src/view/full_view.rs @@ -1,4 +1,4 @@ -use view::{DimensionRequest, SizeRequest, View, ViewWrapper}; +use view::{View, ViewWrapper}; use vec::Vec2; /// Simple wrapper view that asks for all the space it can get. @@ -16,18 +16,7 @@ impl FullView { impl ViewWrapper for FullView { wrap_impl!(&self.view); - fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 { - let w = match req.w { - 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) + fn wrap_get_min_size(&self, req: Vec2) -> Vec2 { + req } } diff --git a/src/view/linear_layout.rs b/src/view/linear_layout.rs index b8fce25..55d1251 100644 --- a/src/view/linear_layout.rs +++ b/src/view/linear_layout.rs @@ -1,4 +1,4 @@ -use view::{DimensionRequest, SizeRequest, View}; +use view::View; use vec::Vec2; use printer::Printer; use orientation::Orientation; @@ -115,6 +115,8 @@ impl View for LinearLayout { for (i, child) in self.children.iter_mut().enumerate() { 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 .get(&child.size); } @@ -122,18 +124,16 @@ impl View for LinearLayout { fn layout(&mut self, size: Vec2) { // Compute the very minimal required size - let req = SizeRequest { - w: DimensionRequest::AtMost(size.x), - h: DimensionRequest::AtMost(size.y), - }; + // Look how mean we are: we offer the whole size to every child. + // As if they could get it all. let min_sizes: Vec = self.children .iter() - .map(|child| child.view.get_min_size(req)) + .map(|child| Vec2::min(size, child.view.get_min_size(size))) .collect(); let min_size = self.orientation.stack(min_sizes.iter()); // 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)) { // Error! Not enough space! Emergency procedures! 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. let sizes: Vec = self.children .iter() diff --git a/src/view/mod.rs b/src/view/mod.rs index 09f7692..abb5a0c 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -5,7 +5,6 @@ mod view_wrapper; // Essentials components mod position; -mod request; mod view_path; // Helper bases @@ -36,7 +35,6 @@ use printer::Printer; pub use self::position::{Position, Offset}; -pub use self::request::{DimensionRequest, SizeRequest}; pub use self::scroll::ScrollBase; pub use self::id_view::IdView; @@ -65,7 +63,7 @@ pub trait View { } /// 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) } diff --git a/src/view/select_view.rs b/src/view/select_view.rs index 72b2ffd..1eec1b8 100644 --- a/src/view/select_view.rs +++ b/src/view/select_view.rs @@ -4,7 +4,7 @@ use std::rc::Rc; use theme::ColorStyle; use Cursive; use align::*; -use view::{DimensionRequest, IdView, SizeRequest, View}; +use view::{IdView, View}; use event::{Event, EventResult, Key}; use vec::Vec2; use printer::Printer; @@ -150,7 +150,10 @@ impl View for SelectView { }); } - 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 .iter() .map(|item| item.label.len()) @@ -158,13 +161,7 @@ impl View for SelectView { .unwrap_or(1); let h = self.items.len(); - let scrolling = if let DimensionRequest::Fixed(r_h) = req.h { - r_h < h - } else if let DimensionRequest::AtMost(r_h) = req.h { - r_h < h - } else { - false - }; + let scrolling = req.y < h; // Add 2 spaces for the scrollbar if we need let w = if scrolling { diff --git a/src/view/shadow_view.rs b/src/view/shadow_view.rs index d41ad09..e068a54 100644 --- a/src/view/shadow_view.rs +++ b/src/view/shadow_view.rs @@ -1,4 +1,4 @@ -use view::{SizeRequest, View, ViewWrapper}; +use view::{View, ViewWrapper}; use printer::Printer; use vec::Vec2; use theme::ColorStyle; @@ -20,8 +20,8 @@ impl ShadowView { impl ViewWrapper for ShadowView { wrap_impl!(&self.view); - fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 { - self.view.get_min_size(req.reduced((2, 2))) + (2, 2) + fn wrap_get_min_size(&self, req: Vec2) -> Vec2 { + self.view.get_min_size(req - (2, 2)) + (2, 2) } fn wrap_layout(&mut self, size: Vec2) { diff --git a/src/view/stack_view.rs b/src/view/stack_view.rs index e5418af..54c34b0 100644 --- a/src/view/stack_view.rs +++ b/src/view/stack_view.rs @@ -1,7 +1,7 @@ use std::any::Any; use vec::Vec2; -use view::{DimensionRequest, Selector, ShadowView, SizeRequest, View, Position}; +use view::{Selector, ShadowView, View, Position}; use event::{Event, EventResult}; use printer::Printer; use theme::ColorStyle; @@ -78,14 +78,10 @@ impl View for StackView { fn layout(&mut self, size: Vec2) { // The call has been made, we can't ask for more space anymore. // 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 { // 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); // 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 - let mut s = Vec2::new(1, 1); - for layer in &self.layers { - let vs = layer.view.get_min_size(size); - s = Vec2::max(s, vs); - } - - s + self.layers + .iter() + .map(|layer| layer.view.get_min_size(size)) + .fold(Vec2::new(1, 1), Vec2::max) } fn take_focus(&mut self) -> bool { diff --git a/src/view/text_view.rs b/src/view/text_view.rs index ce10190..7ce2611 100644 --- a/src/view/text_view.rs +++ b/src/view/text_view.rs @@ -1,8 +1,7 @@ use std::cmp::max; use vec::Vec2; -use view::{DimensionRequest, SizeRequest, View}; -use div::*; +use view::View; use printer::Printer; use align::*; use event::*; @@ -105,15 +104,6 @@ impl TextView { .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? fn get_ideal_size(&self) -> Vec2 { let mut max_width = 0; @@ -244,34 +234,19 @@ impl View for TextView { EventResult::Consumed(None) } - fn get_min_size(&self, size: SizeRequest) -> Vec2 { - match (size.w, size.h) { - // If we have no directive, ask for a single big line. - // 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. - let ideal = self.get_ideal_size(); + fn get_min_size(&self, size: Vec2) -> Vec2 { + // If we have no directive, ask for a single big line. + // TODO: what if the text has newlines?? + // Don't _force_ the max width, but take it if we have to. + let ideal = self.get_ideal_size(); - if w >= ideal.x { - // This is the cheap path - ideal - } else { - // This is the expensive one :( - let h = self.get_num_lines(w); - Vec2::new(w, h) - } - } - _ => unreachable!(), + if size.x >= ideal.x { + ideal + } else { + // Ok, se we have less width than we'd like. + // Take everything we can, and plan our height accordingly. + let h = self.get_num_lines(size.x); + Vec2::new(size.x, h) } } diff --git a/src/view/view_wrapper.rs b/src/view/view_wrapper.rs index 242af9d..84b98f8 100644 --- a/src/view/view_wrapper.rs +++ b/src/view/view_wrapper.rs @@ -1,7 +1,7 @@ use std::any::Any; use vec::Vec2; -use view::{Selector, SizeRequest, View}; +use view::{Selector, View}; use printer::Printer; use event::{Event, EventResult}; @@ -21,7 +21,7 @@ pub trait ViewWrapper { } /// 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) } @@ -50,7 +50,7 @@ impl View for T { 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) }