1use 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
12pub 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
27pub 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
41pub 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
50pub 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
61pub 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
88pub 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
100pub 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
112pub 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}