rumatui_tui/widgets/
block.rs1use crate::buffer::Buffer;
2use crate::layout::Rect;
3use crate::style::Style;
4use crate::symbols::line;
5use crate::widgets::{Borders, Widget};
6
7#[derive(Debug, Copy, Clone)]
8pub enum BorderType {
9 Plain,
10 Rounded,
11 Double,
12 Thick,
13}
14
15impl BorderType {
16 pub fn line_symbols(border_type: BorderType) -> line::Set {
17 match border_type {
18 BorderType::Plain => line::NORMAL,
19 BorderType::Rounded => line::ROUNDED,
20 BorderType::Double => line::DOUBLE,
21 BorderType::Thick => line::THICK,
22 }
23 }
24}
25
26#[derive(Clone, Copy)]
43pub struct Block<'a> {
44 title: Option<&'a str>,
46 title_style: Style,
48 borders: Borders,
50 border_style: Style,
52 border_type: BorderType,
55 style: Style,
57}
58
59impl<'a> Default for Block<'a> {
60 fn default() -> Block<'a> {
61 Block {
62 title: None,
63 title_style: Default::default(),
64 borders: Borders::NONE,
65 border_style: Default::default(),
66 border_type: BorderType::Plain,
67 style: Default::default(),
68 }
69 }
70}
71
72impl<'a> Block<'a> {
73 pub fn title(mut self, title: &'a str) -> Block<'a> {
74 self.title = Some(title);
75 self
76 }
77
78 pub fn title_style(mut self, style: Style) -> Block<'a> {
79 self.title_style = style;
80 self
81 }
82
83 pub fn border_style(mut self, style: Style) -> Block<'a> {
84 self.border_style = style;
85 self
86 }
87
88 pub fn style(mut self, style: Style) -> Block<'a> {
89 self.style = style;
90 self
91 }
92
93 pub fn borders(mut self, flag: Borders) -> Block<'a> {
94 self.borders = flag;
95 self
96 }
97
98 pub fn border_type(mut self, border_type: BorderType) -> Block<'a> {
99 self.border_type = border_type;
100 self
101 }
102
103 pub fn inner(&self, area: Rect) -> Rect {
105 if area.width < 2 || area.height < 2 {
106 return Rect::default();
107 }
108 let mut inner = area;
109 if self.borders.intersects(Borders::LEFT) {
110 inner.x += 1;
111 inner.width -= 1;
112 }
113 if self.borders.intersects(Borders::TOP) || self.title.is_some() {
114 inner.y += 1;
115 inner.height -= 1;
116 }
117 if self.borders.intersects(Borders::RIGHT) {
118 inner.width -= 1;
119 }
120 if self.borders.intersects(Borders::BOTTOM) {
121 inner.height -= 1;
122 }
123 inner
124 }
125}
126
127impl<'a> Widget for Block<'a> {
128 fn render(self, area: Rect, buf: &mut Buffer) {
129 if area.width < 2 || area.height < 2 {
130 return;
131 }
132
133 buf.set_background(area, self.style.bg);
134
135 let symbols = BorderType::line_symbols(self.border_type);
136 if self.borders.intersects(Borders::LEFT) {
138 for y in area.top()..area.bottom() {
139 buf.get_mut(area.left(), y)
140 .set_symbol(symbols.vertical)
141 .set_style(self.border_style);
142 }
143 }
144 if self.borders.intersects(Borders::TOP) {
145 for x in area.left()..area.right() {
146 buf.get_mut(x, area.top())
147 .set_symbol(symbols.horizontal)
148 .set_style(self.border_style);
149 }
150 }
151 if self.borders.intersects(Borders::RIGHT) {
152 let x = area.right() - 1;
153 for y in area.top()..area.bottom() {
154 buf.get_mut(x, y)
155 .set_symbol(symbols.vertical)
156 .set_style(self.border_style);
157 }
158 }
159 if self.borders.intersects(Borders::BOTTOM) {
160 let y = area.bottom() - 1;
161 for x in area.left()..area.right() {
162 buf.get_mut(x, y)
163 .set_symbol(symbols.horizontal)
164 .set_style(self.border_style);
165 }
166 }
167
168 if self.borders.contains(Borders::LEFT | Borders::TOP) {
170 buf.get_mut(area.left(), area.top())
171 .set_symbol(symbols.top_left)
172 .set_style(self.border_style);
173 }
174 if self.borders.contains(Borders::RIGHT | Borders::TOP) {
175 buf.get_mut(area.right() - 1, area.top())
176 .set_symbol(symbols.top_right)
177 .set_style(self.border_style);
178 }
179 if self.borders.contains(Borders::LEFT | Borders::BOTTOM) {
180 buf.get_mut(area.left(), area.bottom() - 1)
181 .set_symbol(symbols.bottom_left)
182 .set_style(self.border_style);
183 }
184 if self.borders.contains(Borders::RIGHT | Borders::BOTTOM) {
185 buf.get_mut(area.right() - 1, area.bottom() - 1)
186 .set_symbol(symbols.bottom_right)
187 .set_style(self.border_style);
188 }
189
190 if let Some(title) = self.title {
191 let lx = if self.borders.intersects(Borders::LEFT) {
192 1
193 } else {
194 0
195 };
196 let rx = if self.borders.intersects(Borders::RIGHT) {
197 1
198 } else {
199 0
200 };
201 let width = area.width - lx - rx;
202 buf.set_stringn(
203 area.left() + lx,
204 area.top(),
205 title,
206 width as usize,
207 self.title_style,
208 );
209 }
210 }
211}