diff --git a/src/vec.rs b/src/vec.rs index a40f258..f4a1b83 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -82,7 +82,7 @@ impl Vec2 { /// Returns a new `Vec2` with the axis `o` set to `value`. pub fn with(&self, o: Orientation, value: usize) -> Self { - let mut other = self.clone(); + let mut other = *self; *o.get_ref(&mut other) = value; other } diff --git a/src/view/box_view.rs b/src/view/box_view.rs index 0910832..989dfb7 100644 --- a/src/view/box_view.rs +++ b/src/view/box_view.rs @@ -68,6 +68,6 @@ impl ViewWrapper for BoxView { Vec2::new(self.size.x.unwrap_or(child_size.x), self.size.y.unwrap_or(child_size.y)) - }.or_min(req) + } } } diff --git a/src/view/linear_layout.rs b/src/view/linear_layout.rs index dd1b235..3bdd5e9 100644 --- a/src/view/linear_layout.rs +++ b/src/view/linear_layout.rs @@ -103,56 +103,6 @@ impl LinearLayout { } } -/// Returns the index of the maximum element. -/// WTF isn't it part of standard library?? -fn find_max(list: &[usize]) -> usize { - let mut max_value = 0; - let mut max = 0; - for (i, &x) in list.iter().enumerate() { - if x > max_value { - max_value = x; - max = i; - } - } - max -} - -/// Given a total number of points and a list of weights, -/// try to share the points according to the weight, -/// rounding properly and conserving the sum of points. -fn share(total: usize, weights: Vec) -> Vec { - // It first give a base value to everyone, which is their truncated share. - // Then, it gives the rest to the most deserving. - if weights.is_empty() { - return Vec::new(); - } - - let sum_weight = weights.iter().fold(0, |a, b| a + b); - if sum_weight == 0 { - return (0..weights.len()).map(|_| 0).collect(); - } - - let mut base = Vec::with_capacity(weights.len()); - let mut rest = Vec::with_capacity(weights.len()); - let mut extra = total; - - for weight in &weights { - let b = total * weight / sum_weight; - extra -= b; - base.push(b); - rest.push(total * weight - b * sum_weight); - } - - // TODO: better to sort (base,rest) as one array and pick the extra first. - for _ in 0..extra { - let i = find_max(&rest); - rest[i] = 0; - base[i] += 1; - } - - base -} - impl View for LinearLayout { fn draw(&mut self, printer: &Printer) { // Use pre-computed sizes @@ -184,50 +134,8 @@ impl View for LinearLayout { } for child in &mut self.children { - // println_stderr!("Child size: {:?}", child.size); child.view.layout(child.size); } - - /* - - // Need to compute things again... - self.get_min_size(size); - - let min_sizes: Vec = self.children - .iter_mut() - .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, - // and (0,1).cmp((1,1)) is undefined) - if !(min_size < size + (1, 1)) { - // Error! Not enough space! Emergency procedures! - return; - } - - // Now share this extra space among everyone - - let extras = { - let extra = size - min_size; - let space = self.orientation.get(&extra); - share(space, - self.children.iter().map(|child| child.weight).collect()) - }; - - - for (child, (child_size, extra)) in self.children - .iter_mut() - .zip(min_sizes.iter().zip(extras.iter())) { - let mut child_size = *child_size; - *self.orientation.get_ref(&mut child_size) += *extra; - *self.orientation.swap().get_ref(&mut child_size) = - self.orientation.swap().get(&size); - child.size = child_size; - child.view.layout(child_size); - } - */ } fn get_min_size(&mut self, req: Vec2) -> Vec2 { diff --git a/src/view/mod.rs b/src/view/mod.rs index c92bb42..b5c1549 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -1,4 +1,38 @@ //! Defines various views to use when creating the layout. +//! +//! Views are the main building blocks of your UI. +//! +//! A view can delegate part or all of its responsabilities to child views, +//! forming a view tree. The root of this tree is a `StackView` handled +//! directly by the `Cursive` element. +//! +//! # Layout +//! +//! The layout phase is when the size and location of each view is computed. +//! +//! Each view is given an area of the screen by the `View::layout()` method. +//! With this, the view is free to plan its content, including calling +//! `View::layout()` on its own children. +//! +//! In order to determine how much space should be given each child, parents +//! can use `View::get_min_size()` on them. +//! +//! +//! ### Contracts +//! +//! When building new Views, you should respect these contracts: +//! +//! * By default, `View::layout()` should be called before any call to +//! `View::draw()` with the same available size. The only exceptions is +//! when both following conditions are met: +//! * The available size has not changed since the last call to `View::layout()` +//! * `View::needs_relayout()` returns `false` +//! +//! In this case, it is safe to omit the call to `View::layout()`. +//! +//! * The value returned by `get_min_size` should be an actually viable size, +//! no matter what the request is. This means calling `View::layout()` with +//! a size returned by `get_min_size` is **never** an error. #[macro_use] mod view_wrapper;