mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Initial scrollview implementation
This commit is contained in:
parent
56ce95f9b6
commit
1f6de5a591
@ -1,17 +1,58 @@
|
|||||||
use view::View;
|
|
||||||
use Printer;
|
use Printer;
|
||||||
|
use direction::Direction;
|
||||||
|
use event::{AnyCb, Event, EventResult, Key};
|
||||||
|
use rect::Rect;
|
||||||
|
use std::cmp::min;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
use view::{Selector, View};
|
||||||
|
use xy::XY;
|
||||||
|
|
||||||
/// Wraps a view in a scrollable area.
|
/// Wraps a view in a scrollable area.
|
||||||
pub struct ScrollView<V> {
|
pub struct ScrollView<V> {
|
||||||
|
inner_size: Vec2,
|
||||||
inner: V,
|
inner: V,
|
||||||
|
// Offset into the inner view.
|
||||||
|
//
|
||||||
|
// Our `(0,0)` will be inner's `offset`
|
||||||
offset: Vec2,
|
offset: Vec2,
|
||||||
|
|
||||||
// Togglable horizontal/vertical scrolling?
|
last_size: Vec2,
|
||||||
|
|
||||||
|
// Can we scroll horizontally?
|
||||||
|
enabled: XY<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <V> View for ScrollView<V> where V: View {
|
impl<V> ScrollView<V> {
|
||||||
|
/// Creates a new ScrollView around `view`.
|
||||||
|
pub fn new(view: V) -> Self {
|
||||||
|
ScrollView {
|
||||||
|
inner: view,
|
||||||
|
inner_size: Vec2::zero(),
|
||||||
|
offset: Vec2::zero(),
|
||||||
|
last_size: Vec2::zero(),
|
||||||
|
enabled: XY::new(false, true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the viewport in the inner content.
|
||||||
|
pub fn content_viewport(&self) -> Rect {
|
||||||
|
Rect::from_size(self.offset, self.last_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the scroll offset to the given value
|
||||||
|
pub fn set_offset<S>(&mut self, offset: S)
|
||||||
|
where
|
||||||
|
S: Into<Vec2>,
|
||||||
|
{
|
||||||
|
let max_offset = self.inner_size.saturating_sub(self.last_size);
|
||||||
|
self.offset = offset.into().or_min(max_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V> View for ScrollView<V>
|
||||||
|
where
|
||||||
|
V: View,
|
||||||
|
{
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer) {
|
||||||
// Draw content
|
// Draw content
|
||||||
let printer = printer.content_offset(self.offset);
|
let printer = printer.content_offset(self.offset);
|
||||||
@ -19,4 +60,67 @@ impl <V> View for ScrollView<V> where V: View {
|
|||||||
|
|
||||||
// Draw scrollbar?
|
// Draw scrollbar?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
|
// Relativize event accorging to the offset
|
||||||
|
let mut relative_event = event.clone();
|
||||||
|
if let Some(pos) = relative_event.mouse_position_mut() {
|
||||||
|
*pos = *pos + self.offset;
|
||||||
|
}
|
||||||
|
match self.inner.on_event(relative_event) {
|
||||||
|
EventResult::Ignored => {
|
||||||
|
// If it's an arrow, try to scroll in the given direction.
|
||||||
|
// If it's a mouse scroll, try to scroll as well.
|
||||||
|
match event {
|
||||||
|
Event::Key(Key::Up) if self.offset.y > 0 => {
|
||||||
|
self.offset.y -= 1;
|
||||||
|
EventResult::Consumed(None)
|
||||||
|
}
|
||||||
|
Event::Key(Key::Left) if self.offset.x > 0 => {
|
||||||
|
self.offset.x -= 1;
|
||||||
|
EventResult::Consumed(None)
|
||||||
|
}
|
||||||
|
_ => EventResult::Ignored,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(&mut self, size: Vec2) {
|
||||||
|
self.last_size = size;
|
||||||
|
|
||||||
|
// Ask one more time
|
||||||
|
self.inner_size = self.inner.required_size(size).or_max(size);
|
||||||
|
self.inner.layout(self.inner_size);
|
||||||
|
|
||||||
|
// TODO: Refresh offset if needed!
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs_relayout(&self) -> bool {
|
||||||
|
self.inner.needs_relayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn required_size(&mut self, constraint: Vec2) -> Vec2 {
|
||||||
|
// TODO: depend on allowed axis
|
||||||
|
let size = self.inner.required_size(constraint);
|
||||||
|
|
||||||
|
// For each enabled direction, return the min of size and constraint.
|
||||||
|
// For the rest, directly return the size.
|
||||||
|
self.enabled.select_or(Vec2::min(size, constraint), size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_on_any<'a>(&mut self, selector: &Selector, cb: AnyCb<'a>) {
|
||||||
|
self.inner.call_on_any(selector, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
|
||||||
|
self.inner.focus_view(selector)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_focus(&mut self, source: Direction) -> bool {
|
||||||
|
let is_scrollable =
|
||||||
|
self.enabled.any() && (self.inner_size != self.last_size);
|
||||||
|
self.inner.take_focus(source) || is_scrollable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user