1 //! `widgets` is a collection of types that implement [`Widget`] or [`StatefulWidget`] or both.
2 //!
3 //! All widgets are implemented using the builder pattern and are consumable objects. They are not
4 //! meant to be stored but used as *commands* to draw common figures in the UI.
5 //!
6 //! The available widgets are:
7 //! - [`Block`]
8 //! - [`Tabs`]
9 //! - [`List`]
10 //! - [`Table`]
11 //! - [`Paragraph`]
12 //! - [`Chart`]
13 //! - [`BarChart`]
14 //! - [`Gauge`]
15 //! - [`Sparkline`]
16 //! - [`Clear`]
17 
18 mod barchart;
19 mod block;
20 pub mod canvas;
21 mod chart;
22 mod clear;
23 mod gauge;
24 mod list;
25 mod paragraph;
26 mod reflow;
27 mod sparkline;
28 mod table;
29 mod tabs;
30 
31 pub use self::barchart::BarChart;
32 pub use self::block::{Block, BorderType};
33 pub use self::chart::{Axis, Chart, Dataset, GraphType};
34 pub use self::clear::Clear;
35 pub use self::gauge::{Gauge, LineGauge};
36 pub use self::list::{List, ListItem, ListState};
37 pub use self::paragraph::{Paragraph, Wrap};
38 pub use self::sparkline::Sparkline;
39 pub use self::table::{Cell, Row, Table, TableState};
40 pub use self::tabs::Tabs;
41 
42 use crate::{buffer::Buffer, layout::Rect};
43 use bitflags::bitflags;
44 
45 bitflags! {
46     /// Bitflags that can be composed to set the visible borders essentially on the block widget.
47     pub struct Borders: u32 {
48         /// Show no border (default)
49         const NONE  = 0b0000_0001;
50         /// Show the top border
51         const TOP   = 0b0000_0010;
52         /// Show the right border
53         const RIGHT = 0b0000_0100;
54         /// Show the bottom border
55         const BOTTOM = 0b000_1000;
56         /// Show the left border
57         const LEFT = 0b0001_0000;
58         /// Show all borders
59         const ALL = Self::TOP.bits | Self::RIGHT.bits | Self::BOTTOM.bits | Self::LEFT.bits;
60     }
61 }
62 
63 /// Base requirements for a Widget
64 pub trait Widget {
65     /// Draws the current state of the widget in the given buffer. That the only method required to
66     /// implement a custom widget.
render(self, area: Rect, buf: &mut Buffer)67     fn render(self, area: Rect, buf: &mut Buffer);
68 }
69 
70 /// A `StatefulWidget` is a widget that can take advantage of some local state to remember things
71 /// between two draw calls.
72 ///
73 /// Most widgets can be drawn directly based on the input parameters. However, some features may
74 /// require some kind of associated state to be implemented.
75 ///
76 /// For example, the [`List`] widget can highlight the item currently selected. This can be
77 /// translated in an offset, which is the number of elements to skip in order to have the selected
78 /// item within the viewport currently allocated to this widget. The widget can therefore only
79 /// provide the following behavior: whenever the selected item is out of the viewport scroll to a
80 /// predefined position (making the selected item the last viewable item or the one in the middle
81 /// for example). Nonetheless, if the widget has access to the last computed offset then it can
82 /// implement a natural scrolling experience where the last offset is reused until the selected
83 /// item is out of the viewport.
84 ///
85 /// ## Examples
86 ///
87 /// ```rust,no_run
88 /// # use std::io;
89 /// # use tui::Terminal;
90 /// # use tui::backend::{Backend, TermionBackend};
91 /// # use tui::widgets::{Widget, List, ListItem, ListState};
92 ///
93 /// // Let's say we have some events to display.
94 /// struct Events {
95 ///     // `items` is the state managed by your application.
96 ///     items: Vec<String>,
97 ///     // `state` is the state that can be modified by the UI. It stores the index of the selected
98 ///     // item as well as the offset computed during the previous draw call (used to implement
99 ///     // natural scrolling).
100 ///     state: ListState
101 /// }
102 ///
103 /// impl Events {
104 ///     fn new(items: Vec<String>) -> Events {
105 ///         Events {
106 ///             items,
107 ///             state: ListState::default(),
108 ///         }
109 ///     }
110 ///
111 ///     pub fn set_items(&mut self, items: Vec<String>) {
112 ///         self.items = items;
113 ///         // We reset the state as the associated items have changed. This effectively reset
114 ///         // the selection as well as the stored offset.
115 ///         self.state = ListState::default();
116 ///     }
117 ///
118 ///     // Select the next item. This will not be reflected until the widget is drawn in the
119 ///     // `Terminal::draw` callback using `Frame::render_stateful_widget`.
120 ///     pub fn next(&mut self) {
121 ///         let i = match self.state.selected() {
122 ///             Some(i) => {
123 ///                 if i >= self.items.len() - 1 {
124 ///                     0
125 ///                 } else {
126 ///                     i + 1
127 ///                 }
128 ///             }
129 ///             None => 0,
130 ///         };
131 ///         self.state.select(Some(i));
132 ///     }
133 ///
134 ///     // Select the previous item. This will not be reflected until the widget is drawn in the
135 ///     // `Terminal::draw` callback using `Frame::render_stateful_widget`.
136 ///     pub fn previous(&mut self) {
137 ///         let i = match self.state.selected() {
138 ///             Some(i) => {
139 ///                 if i == 0 {
140 ///                     self.items.len() - 1
141 ///                 } else {
142 ///                     i - 1
143 ///                 }
144 ///             }
145 ///             None => 0,
146 ///         };
147 ///         self.state.select(Some(i));
148 ///     }
149 ///
150 ///     // Unselect the currently selected item if any. The implementation of `ListState` makes
151 ///     // sure that the stored offset is also reset.
152 ///     pub fn unselect(&mut self) {
153 ///         self.state.select(None);
154 ///     }
155 /// }
156 ///
157 /// let stdout = io::stdout();
158 /// let backend = TermionBackend::new(stdout);
159 /// let mut terminal = Terminal::new(backend).unwrap();
160 ///
161 /// let mut events = Events::new(vec![
162 ///     String::from("Item 1"),
163 ///     String::from("Item 2")
164 /// ]);
165 ///
166 /// loop {
167 ///     terminal.draw(|f| {
168 ///         // The items managed by the application are transformed to something
169 ///         // that is understood by tui.
170 ///         let items: Vec<ListItem>= events.items.iter().map(|i| ListItem::new(i.as_ref())).collect();
171 ///         // The `List` widget is then built with those items.
172 ///         let list = List::new(items);
173 ///         // Finally the widget is rendered using the associated state. `events.state` is
174 ///         // effectively the only thing that we will "remember" from this draw call.
175 ///         f.render_stateful_widget(list, f.size(), &mut events.state);
176 ///     });
177 ///
178 ///     // In response to some input events or an external http request or whatever:
179 ///     events.next();
180 /// }
181 /// ```
182 pub trait StatefulWidget {
183     type State;
render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State)184     fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State);
185 }
186