Fixes for ScrollView

This commit is contained in:
Alexandre Bury 2018-06-17 18:17:16 -07:00
parent 804e41ec43
commit f3d822c00c
2 changed files with 53 additions and 4 deletions

View File

@ -1,8 +1,11 @@
//! Points on the 2D character grid. //! Points on the 2D character grid.
use num::traits::Zero;
use std::cmp::{max, min, Ordering}; use std::cmp::{max, min, Ordering};
use std::ops::{Add, Div, Mul, Sub}; use std::ops::{Add, Div, Mul, Sub};
use num::traits::Zero;
use div;
use XY; use XY;
/// Simple 2D size, in cells. /// Simple 2D size, in cells.
@ -30,6 +33,11 @@ impl<T: PartialOrd> PartialOrd for XY<T> {
} }
impl XY<usize> { impl XY<usize> {
/// Returns a `Vec2` with `usize::max_value()` in each axis.
pub fn max_value() -> Self {
Self::new(usize::max_value(), usize::max_value())
}
/// Saturating subtraction. Computes `self - other`, saturating at 0. /// Saturating subtraction. Computes `self - other`, saturating at 0.
/// ///
/// Never panics. /// Never panics.
@ -53,6 +61,14 @@ impl XY<usize> {
}) })
} }
/// Term-by-term integer division that rounds up.
pub fn div_up<O>(&self, other: O) -> Self
where
O: Into<Self>,
{
self.zip_map(other.into(), div::div_up)
}
/// Checked subtraction. Computes `self - other` if possible. /// Checked subtraction. Computes `self - other` if possible.
/// ///
/// Returns `None` if `self.x < other.x || self.y < other.y`. /// Returns `None` if `self.x < other.x || self.y < other.y`.

View File

@ -149,6 +149,7 @@ impl<V> ScrollView<V> {
/// Will be zero in axis where we're not scrolling. /// Will be zero in axis where we're not scrolling.
fn scrollbar_size(&self) -> Vec2 { fn scrollbar_size(&self) -> Vec2 {
self.is_scrolling() self.is_scrolling()
.swap()
.select_or(self.scrollbar_padding + (1, 1), Vec2::zero()) .select_or(self.scrollbar_padding + (1, 1), Vec2::zero())
} }
@ -172,6 +173,7 @@ where
) -> (Vec2, Vec2, XY<bool>) { ) -> (Vec2, Vec2, XY<bool>) {
// This is the size taken by the scrollbars. // This is the size taken by the scrollbars.
let scrollbar_size = scrollable let scrollbar_size = scrollable
.swap()
.select_or(self.scrollbar_padding + (1, 1), Vec2::zero()); .select_or(self.scrollbar_padding + (1, 1), Vec2::zero());
let available = constraint.saturating_sub(scrollbar_size); let available = constraint.saturating_sub(scrollbar_size);
@ -244,11 +246,15 @@ where
let lengths = self.scrollbar_thumb_lengths(); let lengths = self.scrollbar_thumb_lengths();
let available = self.available_size(); let available = self.available_size();
// We want self.scrollbar_thumb_offsets() to be thumb_pos
// steps * self.o / (self.inner + 1 - available) = thumb_pos
// self.o = thumb_pos * (self.inner + 1 - available) / (available + 1 - lengths)
// The new offset is: // The new offset is:
// thumb_pos * (content + 1 - available) / (available + 1 - thumb size) // thumb_pos * (content + 1 - available) / (available + 1 - thumb size)
let new_offset = (self.inner_size + (1, 1)).saturating_sub(available) let new_offset = ((self.inner_size + (1, 1)).saturating_sub(available)
* thumb_pos * thumb_pos)
/ (available + (1, 1)).saturating_sub(lengths); .div_up((available + (1, 1)).saturating_sub(lengths));
let max_offset = self.inner_size.saturating_sub(self.available_size()); let max_offset = self.inner_size.saturating_sub(self.available_size());
self.offset self.offset
.set_axis_from(orientation, &new_offset.or_min(max_offset)); .set_axis_from(orientation, &new_offset.or_min(max_offset));
@ -433,12 +439,39 @@ where
self.release_grab(); self.release_grab();
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(Key::Home) if self.enabled.any() => {
self.offset =
self.enabled.select_or(Vec2::zero(), self.offset);
EventResult::Consumed(None)
}
Event::Key(Key::End) if self.enabled.any() => {
let max_offset = self
.inner_size
.saturating_sub(self.available_size());
self.offset =
self.enabled.select_or(max_offset, self.offset);
EventResult::Consumed(None)
}
Event::Ctrl(Key::Up) | Event::Key(Key::Up) Event::Ctrl(Key::Up) | Event::Key(Key::Up)
if self.enabled.y && self.offset.y > 0 => if self.enabled.y && self.offset.y > 0 =>
{ {
self.offset.y -= 1; self.offset.y -= 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Key(Key::PageUp)
if self.enabled.y && self.offset.y > 0 =>
{
self.offset.y = self.offset.y.saturating_sub(5);
EventResult::Consumed(None)
}
Event::Key(Key::PageDown)
if self.enabled.y
&& (self.offset.y + self.available_size().y
< self.inner_size.y) =>
{
self.offset.y += 5;
EventResult::Consumed(None)
}
Event::Ctrl(Key::Down) | Event::Key(Key::Down) Event::Ctrl(Key::Down) | Event::Key(Key::Down)
if self.enabled.y if self.enabled.y
&& (self.offset.y + self.available_size().y && (self.offset.y + self.available_size().y