diff --git a/Cargo.toml b/Cargo.toml index 77da48c..d8072e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ repository = "https://github.com/gyscos/cursive" version = "0.12.1-alpha.0" edition = "2018" +[package.metadata.docs.rs] +features = ["unstable_scroll"] + [badges.travis-ci] repository = "gyscos/cursive" diff --git a/src/view/scroll/core.rs b/src/view/scroll/core.rs index f7c7e14..d80b820 100644 --- a/src/view/scroll/core.rs +++ b/src/view/scroll/core.rs @@ -26,7 +26,11 @@ pub trait Scroller { /// Core system for scrolling views. /// -/// See also [`ScrollView`](crate::views::ScrollView). +/// This is the lowest-level element handling scroll logic. +/// +/// Higher-level abstractions are probably what you're after. +/// +/// In particular, see also [`ScrollView`](crate::views::ScrollView). #[derive(Debug)] pub struct Core { /// This is the size the child thinks we're giving him. @@ -93,7 +97,8 @@ impl Core { /// Returns a sub-printer ready to draw the content. pub fn sub_printer<'a, 'b>( - &self, printer: &Printer<'a, 'b>, + &self, + printer: &Printer<'a, 'b>, ) -> Printer<'a, 'b> { // Draw scrollbar? let scrolling = self.is_scrolling(); @@ -180,7 +185,9 @@ impl Core { /// Handle an event after processing by the content. pub fn on_inner_event( - &mut self, event: Event, inner_result: EventResult, + &mut self, + event: Event, + inner_result: EventResult, important_area: Rect, ) -> EventResult { match inner_result { @@ -358,7 +365,9 @@ impl Core { /// Performs `View::call_on_any()` pub fn call_on_any<'a, F>( - &mut self, selector: &Selector<'_>, cb: AnyCb<'a>, + &mut self, + selector: &Selector<'_>, + cb: AnyCb<'a>, inner_call_on_any: F, ) where F: FnOnce(&Selector, AnyCb), @@ -368,7 +377,9 @@ impl Core { /// Performs `View::focus_view()` pub fn focus_view( - &mut self, selector: &Selector<'_>, inner_focus_view: F, + &mut self, + selector: &Selector<'_>, + inner_focus_view: F, ) -> Result<(), ()> where F: FnOnce(&Selector) -> Result<(), ()>, @@ -402,7 +413,8 @@ impl Core { /// Sets the padding between content and scrollbar. pub fn set_scrollbar_padding>( - &mut self, scrollbar_padding: V, + &mut self, + scrollbar_padding: V, ) { self.scrollbar_padding = scrollbar_padding.into(); } @@ -411,7 +423,8 @@ impl Core { /// /// Chainable variant. pub fn scrollbar_padding>( - self, scrollbar_padding: V, + self, + scrollbar_padding: V, ) -> Self { self.with(|s| s.set_scrollbar_padding(scrollbar_padding)) } diff --git a/src/view/scroll/mod.rs b/src/view/scroll/mod.rs index d0e2170..2f569bc 100644 --- a/src/view/scroll/mod.rs +++ b/src/view/scroll/mod.rs @@ -1,8 +1,21 @@ //! Core mechanisms to implement scrolling. //! //! *This module is still unstable and may go through breaking changes.* +//! In addition, it is private unless you enable the `unstable_scroll` feature. //! -//! This module defines [`Core`](crate::view::scroll::Core) and related traits. +//! This modules defines: +//! +//! * [`scroll::Core`](crate::view::scroll::Core): stores the state variables +//! required to handle scrolling. Any view that needs to implement scrolling +//! should embed a `scroll::Core`. +//! * [`scroll::Scroller`](crate::view::scroll::Scroller): a trait for +//! something that embeds a such a `scroll::Core`. +//! * Some free functions to help implement the usual `View` trait for a type +//! implementing `scroll::Scroller`. +//! Some methods, like `View::call_on_any`, are not affected by scrolling +//! and are not covered here. +//! * The functions defined here will usually take a reference to the +//! `Scroller` object, as well as closures to implement the "inner view". //! //! [`ScrollView`](crate::views::ScrollView) may be an easier way to add scrolling to an existing view. @@ -41,7 +54,9 @@ impl Default for ScrollStrategy { /// } /// ``` pub fn on_event( - scroller: &mut T, event: Event, on_event: OnEvent, + scroller: &mut T, + event: Event, + on_event: OnEvent, important_area: ImportantArea, ) -> EventResult where @@ -60,7 +75,9 @@ where /// Performs `View::important_area` on a `scroll::Scroller`. pub fn important_area( - scroller: &T, size: Vec2, mut important_area: ImportantArea, + scroller: &T, + size: Vec2, + mut important_area: ImportantArea, ) -> Rect where T: Scroller, @@ -79,7 +96,10 @@ where /// Performs `View::layout` on a `scroll::Scroller`. pub fn layout( - scroller: &mut T, size: Vec2, needs_relayout: bool, layout: Layout, + scroller: &mut T, + size: Vec2, + needs_relayout: bool, + layout: Layout, required_size: RequiredSize, ) where T: Scroller, @@ -98,7 +118,9 @@ pub fn layout( /// Performs `View::required_size` on a `scroll::Scroller`. pub fn required_size( - scroller: &mut T, size: Vec2, needs_relayout: bool, + scroller: &mut T, + size: Vec2, + needs_relayout: bool, required_size: RequiredSize, ) -> Vec2 where @@ -127,7 +149,9 @@ where /// /// This is an alternative to `scroll::draw()` when you just need to print individual lines. pub fn draw_lines( - scroller: &T, printer: &Printer, mut line_drawer: LineDrawer, + scroller: &T, + printer: &Printer, + mut line_drawer: LineDrawer, ) where T: Scroller, LineDrawer: FnMut(&T, &Printer, usize), @@ -146,8 +170,11 @@ pub fn draw_lines( /// /// `left_border` will be called for each row to draw the left border for the given line number. pub fn draw_frame( - scroller: &T, printer: &Printer, mut left_border: LeftBorder, - mut top_border: TopBorder, mut right_border: RightBorder, + scroller: &T, + printer: &Printer, + mut left_border: LeftBorder, + mut top_border: TopBorder, + mut right_border: RightBorder, mut bottom_border: BottomBorder, ) where T: Scroller, @@ -197,7 +224,9 @@ pub fn draw_frame( /// /// It will print a box with the appropriate `├`, `┤` and so on. pub fn draw_box_frame( - scroller: &T, printer: &Printer, is_h_delim: IsHDelim, + scroller: &T, + printer: &Printer, + is_h_delim: IsHDelim, is_v_delim: IsVDelim, ) where T: Scroller, diff --git a/src/view/scroll/raw.rs b/src/view/scroll/raw.rs index f1696e6..1ed0aba 100644 --- a/src/view/scroll/raw.rs +++ b/src/view/scroll/raw.rs @@ -1,3 +1,7 @@ +//! Low-level implementation of the `View` trait using a `scroll::Core`. +//! +//! Most functions take a generic `Model` class, and various closures to get +//! the required things from this model. use crate::event::{Event, EventResult}; use crate::rect::Rect; use crate::view::scroll; @@ -5,8 +9,11 @@ use crate::xy::XY; use crate::Printer; use crate::Vec2; +/// Implements `View::draw` over the `model`. pub fn draw( - printer: &Printer, model: &Model, mut get_scroller: GetScroller, + printer: &Printer, + model: &Model, + mut get_scroller: GetScroller, inner_draw: Draw, ) where Model: ?Sized, @@ -17,9 +24,20 @@ pub fn draw( inner_draw(model, &printer); } +/// Intermediate method to get the size requirements of a view. +/// +/// Assumes we are already scrolling on the axis designated by `scrolling`. +/// +/// `strict` means the result will never be bigger than the constraint. +/// +/// Returns (Inner size, Outer size, New scrolling) fn sizes_when_scrolling( - constraint: Vec2, scrollable: XY, strict: bool, model: &mut Model, - get_scroller: &mut GetScroller, required_size: &mut RequiredSize, + constraint: Vec2, + scrolling: XY, + strict: bool, + model: &mut Model, + get_scroller: &mut GetScroller, + required_size: &mut RequiredSize, ) -> (Vec2, Vec2, XY) where Model: ?Sized, @@ -27,7 +45,7 @@ where RequiredSize: FnMut(&mut Model, Vec2) -> Vec2, { // This is the size taken by the scrollbars. - let scrollbar_size = scrollable.swap().select_or( + let scrollbar_size = scrolling.swap().select_or( get_scroller(model).get_scrollbar_padding() + (1, 1), Vec2::zero(), ); @@ -56,14 +74,21 @@ where .is_enabled() .select_or(inner_size, size.saturating_sub(scrollbar_size)); - let new_scrollable = inner_size.zip_map(size, |i, s| i > s); + let new_scrolling = inner_size.zip_map(size, |i, s| i > s); - (inner_size, size, new_scrollable) + (inner_size, size, new_scrolling) } +/// Returns the size requirement of the view. +/// +/// Returns (Inner size, Outer size) fn sizes( - constraint: Vec2, strict: bool, needs_relayout: bool, model: &mut Model, - get_scroller: &mut GetScroller, required_size: &mut RequiredSize, + constraint: Vec2, + strict: bool, + needs_relayout: bool, + model: &mut Model, + get_scroller: &mut GetScroller, + required_size: &mut RequiredSize, ) -> (Vec2, Vec2) where Model: ?Sized, @@ -77,7 +102,7 @@ where } // Attempt 1: try without scrollbars - let (inner_size, size, scrollable) = sizes_when_scrolling( + let (inner_size, size, scrolling) = sizes_when_scrolling( constraint, XY::new(false, false), strict, @@ -87,18 +112,18 @@ where ); // If we need to add scrollbars, the available size will change. - if scrollable.any() && get_scroller(model).get_show_scrollbars() { + if scrolling.any() && get_scroller(model).get_show_scrollbars() { // Attempt 2: he wants to scroll? Sure! // Try again with some space for the scrollbar. - let (inner_size, size, new_scrollable) = sizes_when_scrolling( + let (inner_size, size, new_scrolling) = sizes_when_scrolling( constraint, - scrollable, + scrolling, strict, model, get_scroller, required_size, ); - if scrollable == new_scrollable { + if scrolling == new_scrolling { // Yup, scrolling did it. We're good to go now. (inner_size, size) } else { @@ -106,7 +131,7 @@ where // There is no end to this! let (inner_size, size, _) = sizes_when_scrolling( constraint, - new_scrollable, + new_scrolling, strict, model, get_scroller, @@ -124,9 +149,13 @@ where } } +/// Implements `View::layout` on the given model. pub fn layout( - size: Vec2, needs_relayout: bool, model: &mut Model, - mut get_scroller: GetScroller, mut required_size: RequiredSize, + size: Vec2, + needs_relayout: bool, + model: &mut Model, + mut get_scroller: GetScroller, + mut required_size: RequiredSize, mut layout: Layout, ) where Model: ?Sized, @@ -154,9 +183,13 @@ pub fn layout( get_scroller(model).update_offset(); } +/// Implements `View::required_size` on the given model. pub fn required_size( - constraint: Vec2, needs_relayout: bool, model: &mut Model, - mut get_scroller: GetScroller, mut required_size: RequiredSize, + constraint: Vec2, + needs_relayout: bool, + model: &mut Model, + mut get_scroller: GetScroller, + mut required_size: RequiredSize, ) -> Vec2 where Model: ?Sized, @@ -175,9 +208,13 @@ where size } +/// Implements `View::on_event` on the given model. pub fn on_event( - event: Event, model: &mut Model, mut get_scroller: GetScroller, - mut on_event: OnEvent, mut important_area: ImportantArea, + event: Event, + model: &mut Model, + mut get_scroller: GetScroller, + mut on_event: OnEvent, + mut important_area: ImportantArea, ) -> EventResult where Model: ?Sized,