rat_widget/clipper/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//!
//! An alternative view widget.
//!
//! > The extra requirement for this one is that you can create
//! > a Layout that defines the bounds of all widgets that can
//! > be rendered.
//!
//! It works in 4 phases:
//!
//! ```rust no_run
//!     # use rat_widget::clipper::{Clipper, AreaHandle, ClipperLayout, ClipperState};
//!     # use rat_widget::checkbox::{Checkbox, CheckboxState};
//!     # use ratatui::prelude::*;
//!     #
//!     # let l2 = [Rect::ZERO, Rect::ZERO];
//!     # struct State {
//!     #      layout: ClipperLayout,
//!     #      handles: Vec<AreaHandle>,
//!     #      check_states: Vec<CheckboxState>,
//!     #      clipper: ClipperState
//!     #  }
//!     # let mut state = State {
//!     #      layout: ClipperLayout::new(1),
//!     #      handles: Vec::default(),
//!     #      clipper: Default::default(),
//!     #      check_states: Vec::default()
//!     #  };
//!     # let mut buf = Buffer::default();
//!     ///
//!     /// Create the layout. The layout can be stored long-term
//!     /// and needs to be rebuilt only if your widget layout changes.
//!     ///
//!     ///> __Note__: add() returns a handle for the area. Can be used later
//!     ///> to refer to the stored area.
//!
//!     if state.layout.is_empty() {
//!         let mut cl = ClipperLayout::new(1);
//!         for i in 0..100 {
//!             let handle = cl.add(&[Rect::new(10, i*11, 15, 10)]);
//!             state.handles[i as usize] = handle;
//!         }
//!     }
//!
//!     /// The given area plus the current scroll offset define the
//!     /// view area. With the view area a temporary buffer is created
//!     /// that is big enough to fit all widgets that are at least
//!     /// partially visible.
//!
//!     let clipper = Clipper::new();
//!
//!     let mut clip_buf = clipper
//!         .layout(state.layout.clone())
//!         .into_buffer(l2[1], &mut state.clipper);
//!
//!     ///
//!     /// The widgets are rendered to that buffer.
//!     ///
//!     for i in 0..100 {
//!         // create a new area
//!         let v_area = clip_buf.layout().layout_handle(state.handles[i])[0];
//!         let w_area = Rect::new(5, v_area.y, 5, 1);
//!         clip_buf.render_widget(Span::from(format!("{:?}:", i)), w_area);
//!
//!         // refer by handle
//!         clip_buf.render_stateful_handle(
//!             Checkbox::new()
//!                 .text(format!("{:?}", state.handles[i])),
//!             state.handles[i],
//!             0,
//!             &mut state.check_states[i],
//!         );
//!     }
//!
//!     ///
//!     /// The last step clips and copies the buffer to the frame buffer.
//!     ///
//!
//!     clip_buf
//!         .into_widget()
//!         .render(l2[1], &mut buf, &mut state.clipper);
//!
//! ```
//!
//! __StatefulWidget__
//!
//! For this to work with StatefulWidgets they must cooperate
//! by implementing the [RelocatableState](crate::relocate::RelocatableState)
//! trait. With this trait the widget can clip/hide all areas that
//! it stores in its state.
//!
//! __See__
//!
//! [example](https://github.com/thscharler/rat-widget/blob/master/examples/clipper1.rs)
//!

#[allow(clippy::module_inception)]
mod clipper;
mod clipper_layout;
mod clipper_style;

pub use crate::commons::AreaHandle;
pub use clipper::*;
pub use clipper_layout::*;
pub use clipper_style::*;