Scrollview: move offset to keep important area in view

This commit is contained in:
Alexandre Bury 2018-05-21 17:25:32 -07:00
parent 2088d5de2a
commit 94504ae91b
3 changed files with 35 additions and 5 deletions

View File

@ -96,11 +96,12 @@ impl<'a> Printer<'a> {
// We don't want people to start calling prints in parallel? // We don't want people to start calling prints in parallel?
/// Prints some text at the given position relative to the window. /// Prints some text at the given position relative to the window.
pub fn print<S: Into<Vec2>>(&self, start: S, text: &str) { pub fn print<S: Into<Vec2>>(&self, start: S, text: &str) {
// Where we are asked to start printing. Oh boy.
let start = start.into(); let start = start.into();
// We accept requests between `content_offset` and // We accept requests between `content_offset` and
// `content_offset + size` // `content_offset + output_size`.
if start >= self.output_size + self.content_offset { if !(start < (self.output_size + self.content_offset)) {
return; return;
} }

View File

@ -4,6 +4,7 @@ use event::*;
use theme::ColorStyle; use theme::ColorStyle;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use vec::Vec2; use vec::Vec2;
use rect::Rect;
use view::View; use view::View;
use {Cursive, Printer, With}; use {Cursive, Printer, With};
@ -139,8 +140,7 @@ impl View for Button {
ColorStyle::highlight() ColorStyle::highlight()
}; };
let offset = let offset = HAlign::Center.get_offset(self.label.width(), printer.size.x);
HAlign::Center.get_offset(self.label.len(), printer.size.x);
printer.with_color(style, |printer| { printer.with_color(style, |printer| {
printer.print((offset, 0), &self.label); printer.print((offset, 0), &self.label);
@ -175,4 +175,11 @@ impl View for Button {
fn take_focus(&mut self, _: Direction) -> bool { fn take_focus(&mut self, _: Direction) -> bool {
self.enabled self.enabled
} }
fn important_area(&self, view_size: Vec2) -> Rect {
let width = self.label.width();
let offset = HAlign::Center.get_offset(width, view_size.x);
Rect::from_size((offset, 0), (width, 1))
}
} }

View File

@ -182,13 +182,16 @@ where
EventResult::Ignored => { EventResult::Ignored => {
// If it's an arrow, try to scroll in the given direction. // If it's an arrow, try to scroll in the given direction.
// If it's a mouse scroll, try to scroll as well. // If it's a mouse scroll, try to scroll as well.
// Also allow Ctrl+arrow to move the view without moving selection.
match event { match event {
Event::Ctrl(Key::Up) |
Event::Key(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::Ctrl(Key::Down) |
Event::Key(Key::Down) Event::Key(Key::Down)
if self.enabled.y if self.enabled.y
&& (self.offset.y + self.last_size.y && (self.offset.y + self.last_size.y
@ -197,12 +200,14 @@ where
self.offset.y += 1; self.offset.y += 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Ctrl(Key::Left) |
Event::Key(Key::Left) Event::Key(Key::Left)
if self.enabled.x && self.offset.x > 0 => if self.enabled.x && self.offset.x > 0 =>
{ {
self.offset.x -= 1; self.offset.x -= 1;
EventResult::Consumed(None) EventResult::Consumed(None)
} }
Event::Ctrl(Key::Right) |
Event::Key(Key::Right) Event::Key(Key::Right)
if self.enabled.x if self.enabled.x
&& (self.offset.x + self.last_size.x && (self.offset.x + self.last_size.x
@ -214,7 +219,24 @@ where
_ => EventResult::Ignored, _ => EventResult::Ignored,
} }
} }
other => other, other => {
// Fix offset?
let important = self.inner.important_area(self.inner_size);
// The furthest top-left we can go
let top_left = (important.bottom_right() + (1,1)).saturating_sub(self.last_size);
// The furthest bottom-right we can go
let bottom_right = important.top_left();
// "top_left < bottom_right" is NOT guaranteed
// if the child is larger than the view.
let offset_min = Vec2::min(top_left, bottom_right);
let offset_max = Vec2::max(top_left, bottom_right);
self.offset = self.offset.or_max(offset_min).or_min(offset_max);
other
},
} }
} }