aboutsummaryrefslogtreecommitdiffstats
path: root/src/ratatui/widgets/mod.rs
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@elliehuxtable.com>2023-03-31 22:57:37 +0100
committerGitHub <noreply@github.com>2023-03-31 22:57:37 +0100
commita515b06bcb556c1be2d0fc3095cd778d413fe40d (patch)
tree4b544de9aa53d6976177c08b91aa3943ef4d9e92 /src/ratatui/widgets/mod.rs
parentfeat: add github action to test the nix builds (#833) (diff)
downloadatuin-a515b06bcb556c1be2d0fc3095cd778d413fe40d.zip
Vendor ratatui temporarily (#835)
* Vendor ratatui temporarily Once https://github.com/tui-rs-revival/ratatui/pull/114 has been merged, we can undo this! But otherwise we can't publish to crates.io with a git dependency. * make tests pass * Shush. * these literally just fail in nix, nowhere else idk how to work with nix properly, and they're also not our tests
Diffstat (limited to 'src/ratatui/widgets/mod.rs')
-rw-r--r--src/ratatui/widgets/mod.rs184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/ratatui/widgets/mod.rs b/src/ratatui/widgets/mod.rs
new file mode 100644
index 00000000..5a6167b8
--- /dev/null
+++ b/src/ratatui/widgets/mod.rs
@@ -0,0 +1,184 @@
+//! `widgets` is a collection of types that implement [`Widget`] or [`StatefulWidget`] or both.
+//!
+//! All widgets are implemented using the builder pattern and are consumable objects. They are not
+//! meant to be stored but used as *commands* to draw common figures in the UI.
+//!
+//! The available widgets are:
+//! - [`Block`]
+//! - [`Tabs`]
+//! - [`List`]
+//! - [`Table`]
+//! - [`Paragraph`]
+//! - [`Chart`]
+//! - [`BarChart`]
+//! - [`Gauge`]
+//! - [`Sparkline`]
+//! - [`Clear`]
+
+mod barchart;
+mod block;
+pub mod canvas;
+mod chart;
+mod clear;
+mod gauge;
+mod list;
+mod paragraph;
+mod reflow;
+mod sparkline;
+mod table;
+mod tabs;
+
+pub use self::barchart::BarChart;
+pub use self::block::{Block, BorderType};
+pub use self::chart::{Axis, Chart, Dataset, GraphType};
+pub use self::clear::Clear;
+pub use self::gauge::{Gauge, LineGauge};
+pub use self::list::{List, ListItem, ListState};
+pub use self::paragraph::{Paragraph, Wrap};
+pub use self::sparkline::Sparkline;
+pub use self::table::{Cell, Row, Table, TableState};
+pub use self::tabs::Tabs;
+
+use crate::ratatui::{buffer::Buffer, layout::Rect};
+use bitflags::bitflags;
+
+bitflags! {
+ /// Bitflags that can be composed to set the visible borders essentially on the block widget.
+ pub struct Borders: u8 {
+ /// Show no border (default)
+ const NONE = 0b0000;
+ /// Show the top border
+ const TOP = 0b0001;
+ /// Show the right border
+ const RIGHT = 0b0010;
+ /// Show the bottom border
+ const BOTTOM = 0b0100;
+ /// Show the left border
+ const LEFT = 0b1000;
+ /// Show all borders
+ const ALL = Self::TOP.bits | Self::RIGHT.bits | Self::BOTTOM.bits | Self::LEFT.bits;
+ }
+}
+
+/// Base requirements for a Widget
+pub trait Widget {
+ /// Draws the current state of the widget in the given buffer. That is the only method required
+ /// to implement a custom widget.
+ fn render(self, area: Rect, buf: &mut Buffer);
+}
+
+/// A `StatefulWidget` is a widget that can take advantage of some local state to remember things
+/// between two draw calls.
+///
+/// Most widgets can be drawn directly based on the input parameters. However, some features may
+/// require some kind of associated state to be implemented.
+///
+/// For example, the [`List`] widget can highlight the item currently selected. This can be
+/// translated in an offset, which is the number of elements to skip in order to have the selected
+/// item within the viewport currently allocated to this widget. The widget can therefore only
+/// provide the following behavior: whenever the selected item is out of the viewport scroll to a
+/// predefined position (making the selected item the last viewable item or the one in the middle
+/// for example). Nonetheless, if the widget has access to the last computed offset then it can
+/// implement a natural scrolling experience where the last offset is reused until the selected
+/// item is out of the viewport.
+///
+/// ## Examples
+///
+/// ```rust,no_run
+/// # use std::io;
+/// # use ratatui::Terminal;
+/// # use ratatui::backend::{Backend, TestBackend};
+/// # use ratatui::widgets::{Widget, List, ListItem, ListState};
+///
+/// // Let's say we have some events to display.
+/// struct Events {
+/// // `items` is the state managed by your application.
+/// items: Vec<String>,
+/// // `state` is the state that can be modified by the UI. It stores the index of the selected
+/// // item as well as the offset computed during the previous draw call (used to implement
+/// // natural scrolling).
+/// state: ListState
+/// }
+///
+/// impl Events {
+/// fn new(items: Vec<String>) -> Events {
+/// Events {
+/// items,
+/// state: ListState::default(),
+/// }
+/// }
+///
+/// pub fn set_items(&mut self, items: Vec<String>) {
+/// self.items = items;
+/// // We reset the state as the associated items have changed. This effectively reset
+/// // the selection as well as the stored offset.
+/// self.state = ListState::default();
+/// }
+///
+/// // Select the next item. This will not be reflected until the widget is drawn in the
+/// // `Terminal::draw` callback using `Frame::render_stateful_widget`.
+/// pub fn next(&mut self) {
+/// let i = match self.state.selected() {
+/// Some(i) => {
+/// if i >= self.items.len() - 1 {
+/// 0
+/// } else {
+/// i + 1
+/// }
+/// }
+/// None => 0,
+/// };
+/// self.state.select(Some(i));
+/// }
+///
+/// // Select the previous item. This will not be reflected until the widget is drawn in the
+/// // `Terminal::draw` callback using `Frame::render_stateful_widget`.
+/// pub fn previous(&mut self) {
+/// let i = match self.state.selected() {
+/// Some(i) => {
+/// if i == 0 {
+/// self.items.len() - 1
+/// } else {
+/// i - 1
+/// }
+/// }
+/// None => 0,
+/// };
+/// self.state.select(Some(i));
+/// }
+///
+/// // Unselect the currently selected item if any. The implementation of `ListState` makes
+/// // sure that the stored offset is also reset.
+/// pub fn unselect(&mut self) {
+/// self.state.select(None);
+/// }
+/// }
+///
+/// # let backend = TestBackend::new(5, 5);
+/// # let mut terminal = Terminal::new(backend).unwrap();
+///
+/// let mut events = Events::new(vec![
+/// String::from("Item 1"),
+/// String::from("Item 2")
+/// ]);
+///
+/// loop {
+/// terminal.draw(|f| {
+/// // The items managed by the application are transformed to something
+/// // that is understood by ratatui.
+/// let items: Vec<ListItem>= events.items.iter().map(|i| ListItem::new(i.as_ref())).collect();
+/// // The `List` widget is then built with those items.
+/// let list = List::new(items);
+/// // Finally the widget is rendered using the associated state. `events.state` is
+/// // effectively the only thing that we will "remember" from this draw call.
+/// f.render_stateful_widget(list, f.size(), &mut events.state);
+/// });
+///
+/// // In response to some input events or an external http request or whatever:
+/// events.next();
+/// }
+/// ```
+pub trait StatefulWidget {
+ type State;
+ fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State);
+}