rat_widget/
util.rs

1//!
2//! Small helpers.
3//!
4use ratatui::buffer::Buffer;
5use ratatui::layout::{Rect, Size};
6use ratatui::prelude::BlockExt;
7use ratatui::style::{Style, Stylize};
8use ratatui::widgets::Widget;
9use ratatui::widgets::{Block, Padding};
10use std::{fmt, mem};
11
12/// Union the areas, but regard only non-empty ones.
13///
14/// This can help if you want to union two non-adjacent areas.
15pub fn union_non_empty(area1: Rect, area2: Rect) -> Rect {
16    if area1.is_empty() && area2.is_empty() {
17        Rect::new(area1.x, area1.y, 0, 0)
18    } else if area1.is_empty() {
19        area2
20    } else if area2.is_empty() {
21        area1
22    } else {
23        area1.union(area2)
24    }
25}
26
27/// Returns a new style with fg and bg swapped.
28///
29/// This is not the same as setting Style::reversed().
30/// The latter sends special controls to the terminal,
31/// the former just swaps.
32pub fn revert_style(mut style: Style) -> Style {
33    if style.fg.is_some() || style.bg.is_some() {
34        mem::swap(&mut style.fg, &mut style.bg);
35        style
36    } else {
37        style.black().on_white()
38    }
39}
40
41/// Fallback for select style.
42pub fn fallback_select_style(style: Style) -> Style {
43    if style.fg.is_some() || style.bg.is_some() {
44        style
45    } else {
46        style.underlined()
47    }
48}
49
50/// Reset an area of the buffer.
51pub fn reset_buf_area(area: Rect, buf: &mut Buffer) {
52    for y in area.top()..area.bottom() {
53        for x in area.left()..area.right() {
54            if let Some(cell) = buf.cell_mut((x, y)) {
55                cell.reset();
56            }
57        }
58    }
59}
60
61/// Fill the given area of the buffer.
62pub fn fill_buf_area(buf: &mut Buffer, area: Rect, symbol: &str, style: impl Into<Style>) {
63    let style = style.into();
64
65    for y in area.top()..area.bottom() {
66        for x in area.left()..area.right() {
67            if let Some(cell) = buf.cell_mut((x, y)) {
68                cell.reset();
69                cell.set_symbol(symbol);
70                cell.set_style(style);
71            }
72        }
73    }
74}
75
76pub fn rect_dbg(area: Rect) -> String {
77    use fmt::Write;
78    let mut buf = String::new();
79    _ = write!(buf, "{}:{}+{}+{}", area.x, area.y, area.width, area.height);
80    buf
81}
82
83pub(crate) const DOUBLE_VERTICAL_SINGLE_LEFT: &str = "\u{2562}";
84pub(crate) const DOUBLE_VERTICAL_SINGLE_RIGHT: &str = "\u{255F}";
85pub(crate) const THICK_VERTICAL_SINGLE_LEFT: &str = "\u{2528}";
86pub(crate) const THICK_VERTICAL_SINGLE_RIGHT: &str = "\u{2520}";
87
88/// Get the padding the block imposes as Padding.
89pub fn block_padding(block: &Option<Block<'_>>) -> Padding {
90    let area = Rect::new(0, 0, 20, 20);
91    let inner = block.inner_if_some(area);
92    Padding {
93        left: inner.left() - area.left(),
94        right: area.right() - inner.right(),
95        top: inner.top() - area.top(),
96        bottom: area.bottom() - inner.bottom(),
97    }
98}
99
100/// Get the padding the block imposes as Padding.
101pub fn block_padding2(block: &Block<'_>) -> Padding {
102    let area = Rect::new(0, 0, 20, 20);
103    let inner = block.inner(area);
104    Padding {
105        left: inner.left() - area.left(),
106        right: area.right() - inner.right(),
107        top: inner.top() - area.top(),
108        bottom: area.bottom() - inner.bottom(),
109    }
110}
111
112/// Get the padding the block imposes as a Size.
113pub fn block_size(block: &Option<Block<'_>>) -> Size {
114    let area = Rect::new(0, 0, 20, 20);
115    let inner = block.inner_if_some(area);
116    Size {
117        width: (inner.left() - area.left()) + (area.right() - inner.right()),
118        height: (inner.top() - area.top()) + (area.bottom() - inner.bottom()),
119    }
120}
121
122pub(crate) fn block_left(block: &Block<'_>) -> String {
123    let area = Rect::new(0, 0, 3, 3);
124    let mut buf = Buffer::empty(area);
125    block.clone().render(area, &mut buf);
126    buf.cell((0, 1)).expect("cell").symbol().into()
127}
128
129pub(crate) fn block_right(block: &Block<'_>) -> String {
130    let area = Rect::new(0, 0, 3, 3);
131    let mut buf = Buffer::empty(area);
132    block.clone().render(area, &mut buf);
133    buf.cell((2, 1)).expect("cell").symbol().into()
134}
135
136#[allow(dead_code)]
137pub(crate) fn block_top(block: &Block<'_>) -> String {
138    let area = Rect::new(0, 0, 3, 3);
139    let mut buf = Buffer::empty(area);
140    block.clone().render(area, &mut buf);
141    buf.cell((1, 0)).expect("cell").symbol().into()
142}
143
144#[allow(dead_code)]
145pub(crate) fn block_bottom(block: &Block<'_>) -> String {
146    let area = Rect::new(0, 0, 3, 3);
147    let mut buf = Buffer::empty(area);
148    block.clone().render(area, &mut buf);
149    buf.cell((1, 2)).expect("cell").symbol().into()
150}