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}