rat_widget/pager/
mod.rs

1//!
2//! Alternative to scrolling by page-breaking a layout.
3//!
4//! If you have a lot of widgets to display, splitting
5//! them into pages is an alternative to scrolling.
6//!
7//! ```rust no_run
8//!     # use std::rc::Rc;
9//!     # use rat_widget::pager::{SinglePager, SinglePagerState};
10//!     # use rat_widget::checkbox::{Checkbox, CheckboxState};
11//!     # use ratatui::prelude::*;
12//!     # use rat_focus::FocusFlag;
13//!     # use rat_widget::layout::{GenericLayout, LayoutForm};
14//!     #
15//!     # let l2 = [Rect::ZERO, Rect::ZERO];
16//!     # struct State {
17//!     #      check_states: Vec<CheckboxState>,
18//!     #      pager: SinglePagerState<FocusFlag>
19//!     #  }
20//!     # let mut state = State {
21//!     #      check_states: Vec::default(),
22//!     #      pager: Default::default(),
23//!     #  };
24//!     # let mut buf = Buffer::default();
25//!
26//!     /// Single pager shows the widgets in one column, and
27//!     /// can page through the list.
28//!     let pager = SinglePager::new();
29//!     let size = pager.layout_size(l2[1]);
30//!
31//!     if !state.pager.valid_layout(size) {
32//!           // GenericLayout is very basic.
33//!           // Try LayoutForm or layout_edit() instead.
34//!           let mut pl = GenericLayout::new();
35//!           for i in 0..100 {
36//!               pl.add(
37//!                     state.check_states[i].focus.clone(), // widget-key
38//!                     Rect::new(10, 10+i as u16, 15, 10), // widget area
39//!                     None, // label text
40//!                     Rect::default() // label area
41//!               );
42//!           }
43//!           state.pager.set_layout(pl);
44//!       }
45//!
46//!       ///
47//!       /// Use [SinglePager] or [DualPager] to calculate the page breaks.
48//!       ///
49//!       let mut pg_buf = pager
50//!             .into_buffer(l2[1], &mut buf, &mut state.pager);
51//!
52//!       ///
53//!       /// Render your widgets with the help of [SinglePagerBuffer]/[DualPagerBuffer]
54//!       ///
55//!       for i in 0..100 {
56//!           pg_buf.render(
57//!               state.check_states[i].focus.clone(),
58//!               || {
59//!                 Checkbox::new().text(format!("{:?}", i).to_string())
60//!               },
61//!               &mut state.check_states[i],
62//!           );
63//!       }
64//!
65//! ```
66
67mod dual_pager;
68mod form;
69#[allow(clippy::module_inception)]
70mod pager;
71mod pager_nav;
72mod pager_style;
73mod single_pager;
74
75pub use dual_pager::*;
76pub use form::*;
77pub use pager::{Pager, PagerBuffer};
78pub use pager_nav::{PageNavigation, PageNavigationState};
79pub use pager_style::*;
80pub use single_pager::*;
81
82pub(crate) mod event {
83    use rat_event::{ConsumedEvent, Outcome};
84
85    /// Result of event handling.
86    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
87    pub enum PagerOutcome {
88        /// The given event has not been used at all.
89        Continue,
90        /// The event has been recognized, but the result was nil.
91        /// Further processing for this event may stop.
92        Unchanged,
93        /// The event has been recognized and there is some change
94        /// due to it.
95        /// Further processing for this event may stop.
96        /// Rendering the ui is advised.
97        Changed,
98        /// Displayed page changed.
99        Page(usize),
100    }
101
102    impl ConsumedEvent for PagerOutcome {
103        fn is_consumed(&self) -> bool {
104            *self != PagerOutcome::Continue
105        }
106    }
107
108    // Useful for converting most navigation/edit results.
109    impl From<bool> for PagerOutcome {
110        fn from(value: bool) -> Self {
111            if value {
112                PagerOutcome::Changed
113            } else {
114                PagerOutcome::Unchanged
115            }
116        }
117    }
118
119    impl From<Outcome> for PagerOutcome {
120        fn from(value: Outcome) -> Self {
121            match value {
122                Outcome::Continue => PagerOutcome::Continue,
123                Outcome::Unchanged => PagerOutcome::Unchanged,
124                Outcome::Changed => PagerOutcome::Changed,
125            }
126        }
127    }
128
129    impl From<PagerOutcome> for Outcome {
130        fn from(value: PagerOutcome) -> Self {
131            match value {
132                PagerOutcome::Continue => Outcome::Continue,
133                PagerOutcome::Unchanged => Outcome::Unchanged,
134                PagerOutcome::Changed => Outcome::Changed,
135                PagerOutcome::Page(_) => Outcome::Changed,
136            }
137        }
138    }
139}