diff --git a/src/lib.rs b/src/lib.rs index 700ab1e..d408052 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,6 +87,7 @@ pub mod logger; pub mod menu; pub mod theme; pub mod vec; +#[macro_use] pub mod views; // This probably doesn't need to be public? diff --git a/src/view/mod.rs b/src/view/mod.rs index 79570fd..3ce7bf7 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -51,13 +51,9 @@ mod view_trait; // Helper bases mod boxable; mod identifiable; -#[cfg(feature = "unstable_scroll")] +#[macro_use] pub mod scroll; -#[cfg(not(feature = "unstable_scroll"))] -#[allow(dead_code)] -pub(crate) mod scroll; - mod scroll_base; mod scrollable; diff --git a/src/view/scroll/core.rs b/src/view/scroll/core.rs index 54a0906..947f557 100644 --- a/src/view/scroll/core.rs +++ b/src/view/scroll/core.rs @@ -24,6 +24,36 @@ pub trait Scroller { fn get_scroller(&self) -> &Core; } +/// Implements the `Scroller` trait for any type. +#[macro_export] +macro_rules! impl_scroller { + ($class:ident :: $core:ident) => { + impl $crate::view::scroll::Scroller for $class { + fn get_scroller_mut( + &mut self, + ) -> &mut $crate::view::scroll::Core { + &mut self.$core + } + fn get_scroller(&self) -> &$crate::view::scroll::Core { + &self.$core + } + } + }; + ($class:ident < $($args:tt),* > :: $core:ident) => { + impl <$( $args ),* > $crate::view::scroll::Scroller for $class<$($args),*> { + + fn get_scroller_mut( + &mut self, + ) -> &mut $crate::view::scroll::Core { + &mut self.$core + } + fn get_scroller(&self) -> &$crate::view::scroll::Core { + &self.$core + } + } + }; +} + /// Core system for scrolling views. /// /// This is the lowest-level element handling scroll logic. diff --git a/src/view/scroll/mod.rs b/src/view/scroll/mod.rs index 8d4300e..175c53b 100644 --- a/src/view/scroll/mod.rs +++ b/src/view/scroll/mod.rs @@ -19,6 +19,7 @@ //! //! [`ScrollView`](crate::views::ScrollView) may be an easier way to add scrolling to an existing view. +#[macro_use] mod core; mod raw; @@ -48,9 +49,32 @@ impl Default for ScrollStrategy { /// /// Example: /// -/// ```rust,ignore -/// fn on_event(&mut self, event: Event) -> EventResult { -/// scroll::on_event(self, event, Self::inner_on_event, Self::inner_important_area) +/// ``` +/// use cursive::{Printer, Vec2, Rect}; +/// use cursive::event::{Event, EventResult}; +/// use cursive::view::{View, scroll}; +/// +/// struct MyView { +/// core: scroll::Core, +/// } +/// +/// cursive::impl_scroller!(MyView::core); +/// +/// impl MyView { +/// fn inner_on_event(&mut self, event: Event) -> EventResult { +/// EventResult::Ignored +/// } +/// +/// fn inner_important_area(&self, size: Vec2) -> Rect { +/// Rect::from_size((0,0), size) +/// } +/// } +/// +/// impl View for MyView { +/// # fn draw(&self, printer: &Printer) {} +/// fn on_event(&mut self, event: Event) -> EventResult { +/// scroll::on_event(self, event, Self::inner_on_event, Self::inner_important_area) +/// } /// } /// ``` pub fn on_event( diff --git a/src/view/size_cache.rs b/src/view/size_cache.rs index d209b2e..1b7dc56 100644 --- a/src/view/size_cache.rs +++ b/src/view/size_cache.rs @@ -23,12 +23,13 @@ impl SizeCache { /// Returns `true` if `self` is still valid for the given `request`. pub fn accept(self, request: usize) -> bool { - if request < self.value { - false - } else if request == self.value { - true - } else { - !self.constrained + match (request, self.value) { + // Request a smaller size than last time? Hell no! + (r, v) if r < v => false, + // Request exactly what we had last time? Sure! + (r, v) if r == v => true, + // Request more than we had last time? Maybe? + _ => !self.constrained, } } diff --git a/src/views/enableable_view.rs b/src/views/enableable_view.rs index 17254d1..e3edb8e 100644 --- a/src/views/enableable_view.rs +++ b/src/views/enableable_view.rs @@ -1,6 +1,6 @@ use crate::event::{Event, EventResult}; use crate::view::{View, ViewWrapper}; -use crate::{Printer, With}; +use crate::Printer; /// Wrapper around another view that can be enabled/disabled at will. /// diff --git a/src/views/menu_popup.rs b/src/views/menu_popup.rs index 672547c..baada2d 100644 --- a/src/views/menu_popup.rs +++ b/src/views/menu_popup.rs @@ -34,15 +34,7 @@ pub struct MenuPopup { // The `scroll::Scroller` trait is used to weave the borrow phases. // // TODO: use some macro to auto-generate this. -impl scroll::Scroller for MenuPopup { - fn get_scroller(&self) -> &scroll::Core { - &self.scroll_core - } - - fn get_scroller_mut(&mut self) -> &mut scroll::Core { - &mut self.scroll_core - } -} +impl_scroller!(MenuPopup::scroll_core); impl MenuPopup { /// Creates a new `MenuPopup` using the given menu tree. diff --git a/src/views/mod.rs b/src/views/mod.rs index 1d29fdf..6341438 100644 --- a/src/views/mod.rs +++ b/src/views/mod.rs @@ -1,6 +1,22 @@ //! Various views to use when creating the layout. /// A macro to help with creating toggleable views. +/// +/// # Examples +/// +/// ``` +/// struct MyView { +/// enabled: bool, +/// } +/// +/// impl MyView { +/// cursive::impl_enabled!(self.enabled); +/// } +/// +/// let view = MyView { enabled: true }; +/// assert!(view.is_enabled()); +/// ``` +#[macro_export] macro_rules! impl_enabled { (self.$x:ident) => { @@ -15,6 +31,7 @@ macro_rules! impl_enabled { /// /// Chainable variant. pub fn disabled(self) -> Self { + use $crate::traits::With as _; self.with(Self::disable) } diff --git a/src/views/scroll_view.rs b/src/views/scroll_view.rs index 4cdd08b..119ea69 100644 --- a/src/views/scroll_view.rs +++ b/src/views/scroll_view.rs @@ -11,17 +11,7 @@ pub struct ScrollView { core: scroll::Core, } -impl scroll::Scroller for ScrollView -where - V: View, -{ - fn get_scroller(&self) -> &scroll::Core { - &self.core - } - fn get_scroller_mut(&mut self) -> &mut scroll::Core { - &mut self.core - } -} +impl_scroller!(ScrollView::core); impl ScrollView where diff --git a/src/views/slider_view.rs b/src/views/slider_view.rs index 3beabf2..6441cc3 100644 --- a/src/views/slider_view.rs +++ b/src/views/slider_view.rs @@ -10,6 +10,21 @@ use crate::{Cursive, Printer}; use std::rc::Rc; /// A horizontal or vertical slider. +/// +/// # Examples +/// +/// ``` +/// use cursive::views::{Dialog, SliderView}; +/// +/// let slider_view = SliderView::horizontal(10) +/// .on_change(|s, n| if n == 5 { +/// s.add_layer(Dialog::info("5! Pick 5!")); +/// }) +/// .on_enter(|s, n| match n { +/// 5 => s.add_layer(Dialog::info("You did it!")), +/// n => s.add_layer(Dialog::info(format!("Why {}? Why not 5?", n))), +/// }); +/// ``` pub struct SliderView { orientation: Orientation, on_change: Option>, @@ -24,6 +39,8 @@ impl SliderView { /// /// The view will have a fixed length of `max_value`, /// with one tick per block. + /// + /// The actual range of values for this slider is `[0, max_value - 1]`. pub fn new(orientation: Orientation, max_value: usize) -> Self { SliderView { orientation, diff --git a/src/views/text_area.rs b/src/views/text_area.rs index 83ab61f..1a12c28 100644 --- a/src/views/text_area.rs +++ b/src/views/text_area.rs @@ -16,6 +16,19 @@ use unicode_width::UnicodeWidthStr; /// A `TextArea` will attempt to grow vertically and horizontally /// dependent on the content. Wrap it in a `BoxView` to /// constrain its size. +/// +/// # Examples +/// +/// ``` +/// use cursive::traits::{Boxable, Identifiable}; +/// use cursive::views::TextArea; +/// +/// let text_area = TextArea::new() +/// .content("Write description here...") +/// .with_id("text_area") +/// .fixed_width(30) +/// .min_height(5); +/// ``` pub struct TextArea { // TODO: use a smarter data structure (rope?) content: String,