//! `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, /// // `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) -> Events { /// Events { /// items, /// state: ListState::default(), /// } /// } /// /// pub fn set_items(&mut self, items: Vec) { /// 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= 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); }