Skip to main content

oino_ui/widgets/
scrollbar.rs

1//! ratatui `Scrollbar` (§4.5.1).
2
3use serde::{Deserialize, Serialize};
4
5use crate::node::{Common, IntoNode, Node};
6use crate::style::Style;
7
8/// Scrollbar orientation and edge.
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum ScrollbarOrientation {
11    /// Vertical, right edge (ratatui default).
12    #[default]
13    VerticalRight,
14    /// Vertical, left edge.
15    VerticalLeft,
16    /// Horizontal, bottom edge.
17    HorizontalBottom,
18    /// Horizontal, top edge.
19    HorizontalTop,
20}
21
22/// ratatui `ScrollbarState`.
23#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct ScrollbarState {
26    /// Total content length.
27    pub content_length: u32,
28    /// Current position.
29    pub position: u32,
30    /// Viewport length (derived from the area when absent).
31    #[serde(default, skip_serializing_if = "Option::is_none")]
32    pub viewport_content_length: Option<u32>,
33}
34
35impl ScrollbarState {
36    /// State over the given content length.
37    #[must_use]
38    pub fn new(content_length: u32) -> Self {
39        Self {
40            content_length,
41            position: 0,
42            viewport_content_length: None,
43        }
44    }
45
46    /// Sets the position.
47    #[must_use]
48    pub fn position(mut self, position: u32) -> Self {
49        self.position = position;
50        self
51    }
52
53    /// Sets the viewport length.
54    #[must_use]
55    pub fn viewport_content_length(mut self, length: u32) -> Self {
56        self.viewport_content_length = Some(length);
57        self
58    }
59}
60
61/// ratatui `Scrollbar` (§4.5.1): a read-only position indicator; scrollable
62/// widgets use their own native `scrollbar` flag instead.
63#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct Scrollbar {
66    /// Common node props (`key`, `style`, `block`, `fallback`).
67    #[serde(flatten)]
68    pub common: Common,
69    /// Orientation (default `VerticalRight`).
70    #[serde(default, skip_serializing_if = "Option::is_none")]
71    pub orientation: Option<ScrollbarOrientation>,
72    /// Content / position state.
73    pub state: ScrollbarState,
74    /// Thumb style.
75    #[serde(default, skip_serializing_if = "Option::is_none")]
76    pub thumb_style: Option<Style>,
77    /// Track style.
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub track_style: Option<Style>,
80    /// Begin symbol (`null` = none).
81    #[serde(default, skip_serializing_if = "Option::is_none")]
82    pub begin_symbol: Option<String>,
83    /// End symbol (`null` = none).
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub end_symbol: Option<String>,
86}
87
88impl Scrollbar {
89    /// A scrollbar over the given state.
90    #[must_use]
91    pub fn new(state: ScrollbarState) -> Self {
92        Self {
93            common: Common::new(),
94            orientation: None,
95            state,
96            thumb_style: None,
97            track_style: None,
98            begin_symbol: None,
99            end_symbol: None,
100        }
101    }
102
103    /// Sets the orientation.
104    #[must_use]
105    pub fn orientation(mut self, orientation: ScrollbarOrientation) -> Self {
106        self.orientation = Some(orientation);
107        self
108    }
109
110    /// Sets the thumb style.
111    #[must_use]
112    pub fn thumb_style(mut self, style: Style) -> Self {
113        self.thumb_style = Some(style);
114        self
115    }
116
117    /// Sets the track style.
118    #[must_use]
119    pub fn track_style(mut self, style: Style) -> Self {
120        self.track_style = Some(style);
121        self
122    }
123
124    /// Sets the begin symbol.
125    #[must_use]
126    pub fn begin_symbol(mut self, symbol: impl Into<String>) -> Self {
127        self.begin_symbol = Some(symbol.into());
128        self
129    }
130
131    /// Sets the end symbol.
132    #[must_use]
133    pub fn end_symbol(mut self, symbol: impl Into<String>) -> Self {
134        self.end_symbol = Some(symbol.into());
135        self
136    }
137}
138
139impl IntoNode for Scrollbar {}
140impl From<Scrollbar> for Node {
141    fn from(s: Scrollbar) -> Self {
142        Node::Scrollbar(s)
143    }
144}