tui_piechart/border_style.rs
1//! Border styles for pie chart block wrappers.
2//!
3//! This module provides predefined border styles that can be used to customize
4//! the appearance of the block that wraps a pie chart.
5//!
6//! # Examples
7//!
8//! ```
9//! use tui_piechart::{PieChart, PieSlice, border_style::BorderStyle};
10//! use ratatui::style::Color;
11//!
12//! let slices = vec![PieSlice::new("Rust", 45.0, Color::Red)];
13//! let piechart = PieChart::new(slices)
14//! .block(BorderStyle::Rounded.block().title("My Chart"));
15//! ```
16
17use ratatui::symbols::border;
18use ratatui::widgets::Block;
19
20// Re-export title positioning types for backward compatibility
21// The actual implementations are in the `title` module
22pub use crate::title::{BlockExt, TitleAlignment, TitlePosition};
23
24// ============================================================================
25// BORDER STYLE ENUM
26// ============================================================================
27
28/// Predefined border styles for the pie chart block wrapper.
29///
30/// These styles provide convenient ways to customize the appearance of the
31/// block that wraps the pie chart.
32///
33/// # Unicode Limitations
34///
35/// Note that `DoubleLineRounded` and `ThickRounded` use mixed styles because
36/// Unicode doesn't have true rounded double-line or thick-line box-drawing
37/// characters. These styles use single-line rounded corners with double/thick
38/// edges for a softer appearance.
39///
40/// # Examples
41///
42/// ```
43/// use tui_piechart::{PieChart, PieSlice, border_style::BorderStyle};
44/// use ratatui::style::Color;
45///
46/// let slices = vec![PieSlice::new("Rust", 45.0, Color::Red)];
47///
48/// // Dashed borders for a subtle look
49/// let chart = PieChart::new(slices.clone())
50/// .block(BorderStyle::Dashed.block().title("Dashed"));
51///
52/// // Thick rounded for bold emphasis
53/// let chart = PieChart::new(slices)
54/// .block(BorderStyle::ThickRounded.block().title("Bold"));
55/// ```
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
57pub enum BorderStyle {
58 /// Standard single-line borders (default)
59 #[default]
60 Standard,
61 /// Rounded corners with single-line borders
62 Rounded,
63 /// Dashed lines throughout (┄┄┄)
64 Dashed,
65 /// Rounded corners with dashed borders
66 RoundedDashed,
67 /// Standard borders with gaps only at corners
68 CornerGapped,
69 /// Rounded borders with gaps only at corners
70 RoundedCornerGapped,
71 /// Double-line borders for standard style
72 DoubleLineStandard,
73 /// Double-line borders with rounded corners (mixed: rounded corners + double edges)
74 DoubleLineRounded,
75 /// Thick borders (uses heavy line drawing characters)
76 Thick,
77 /// Thick borders with rounded corners (mixed: rounded corners + thick edges)
78 ThickRounded,
79 /// Thick borders with dashed lines
80 ThickDashed,
81 /// Thick borders with gaps only at corners
82 ThickCornerGapped,
83}
84
85impl BorderStyle {
86 /// Like [`block`](Self::block) with border colors from a shared theme.
87 #[cfg(feature = "theme")]
88 #[must_use]
89 pub fn themed_block(self, theme: &tui_nuances::Theme, focused: bool) -> Block<'static> {
90 self.block().border_style(theme.border_style(focused))
91 }
92
93 /// Creates a new `Block` with the specified border style.
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// use tui_piechart::border_style::BorderStyle;
99 ///
100 /// let block = BorderStyle::Rounded.block().title("My Chart");
101 /// ```
102 #[must_use]
103 pub fn block(self) -> Block<'static> {
104 match self {
105 Self::Standard => Block::bordered(),
106 Self::Rounded => Block::bordered().border_set(border::ROUNDED),
107 Self::Dashed => Block::bordered().border_set(BORDER_DASHED),
108 Self::RoundedDashed => Block::bordered().border_set(BORDER_ROUNDED_DASHED),
109 Self::CornerGapped => Block::bordered().border_set(BORDER_CORNER_GAPPED),
110 Self::RoundedCornerGapped => Block::bordered().border_set(BORDER_ROUNDED_CORNER_GAPPED),
111 Self::DoubleLineStandard => Block::bordered().border_set(border::DOUBLE),
112 Self::DoubleLineRounded => Block::bordered().border_set(BORDER_DOUBLE_ROUNDED),
113 Self::Thick => Block::bordered().border_set(border::THICK),
114 Self::ThickRounded => Block::bordered().border_set(BORDER_THICK_ROUNDED),
115 Self::ThickDashed => Block::bordered().border_set(BORDER_THICK_DASHED),
116 Self::ThickCornerGapped => Block::bordered().border_set(BORDER_THICK_CORNER_GAPPED),
117 }
118 }
119}
120
121// ============================================================================
122// CUSTOM BORDER SETS
123// ============================================================================
124
125/// Border set with dashed lines throughout
126///
127/// Uses Unicode dashed line characters (┄ and ┊) for a subtle, non-intrusive
128/// border appearance.
129pub const BORDER_DASHED: border::Set = border::Set {
130 top_left: "┌",
131 top_right: "┐",
132 bottom_left: "└",
133 bottom_right: "┘",
134 vertical_left: "┊",
135 vertical_right: "┊",
136 horizontal_top: "┄",
137 horizontal_bottom: "┄",
138};
139
140/// Border set with rounded corners and dashed lines
141///
142/// Combines rounded corners with dashed lines for a modern, subtle look.
143pub const BORDER_ROUNDED_DASHED: border::Set = border::Set {
144 top_left: "╭",
145 top_right: "╮",
146 bottom_left: "╰",
147 bottom_right: "╯",
148 vertical_left: "┊",
149 vertical_right: "┊",
150 horizontal_top: "┄",
151 horizontal_bottom: "┄",
152};
153
154/// Border set with gaps only at corners (standard lines)
155///
156/// Provides a minimalist look with continuous lines and gaps only at corners.
157pub const BORDER_CORNER_GAPPED: border::Set = border::Set {
158 top_left: " ",
159 top_right: " ",
160 bottom_left: " ",
161 bottom_right: " ",
162 vertical_left: "│",
163 vertical_right: "│",
164 horizontal_top: "─",
165 horizontal_bottom: "─",
166};
167
168/// Border set with rounded corners and gaps only at corners
169///
170/// Provides a minimalist look with continuous lines, rounded appearance, and
171/// gaps only at corners.
172pub const BORDER_ROUNDED_CORNER_GAPPED: border::Set = border::Set {
173 top_left: " ",
174 top_right: " ",
175 bottom_left: " ",
176 bottom_right: " ",
177 vertical_left: "│",
178 vertical_right: "│",
179 horizontal_top: "─",
180 horizontal_bottom: "─",
181};
182
183/// Border set with double lines and rounded corners (mixed style)
184///
185/// # Unicode Limitation
186///
187/// Unicode doesn't have true rounded double-line corners, so this uses
188/// rounded single-line corners with double-line edges for a softer appearance.
189///
190/// Visual: `╭═══╮` instead of the non-existent `╔═══╗` with rounded corners.
191pub const BORDER_DOUBLE_ROUNDED: border::Set = border::Set {
192 top_left: "╭",
193 top_right: "╮",
194 bottom_left: "╰",
195 bottom_right: "╯",
196 vertical_left: "║",
197 vertical_right: "║",
198 horizontal_top: "═",
199 horizontal_bottom: "═",
200};
201
202/// Border set with thick lines and rounded corners (mixed style)
203///
204/// # Unicode Limitation
205///
206/// Unicode doesn't have true rounded thick-line corners, so this uses
207/// rounded single-line corners with thick-line edges for a softer appearance.
208///
209/// Visual: `╭━━━╮` instead of the non-existent `┏━━━┓` with rounded corners.
210pub const BORDER_THICK_ROUNDED: border::Set = border::Set {
211 top_left: "╭",
212 top_right: "╮",
213 bottom_left: "╰",
214 bottom_right: "╯",
215 vertical_left: "┃",
216 vertical_right: "┃",
217 horizontal_top: "━",
218 horizontal_bottom: "━",
219};
220
221/// Border set with thick dashed lines
222///
223/// Uses Unicode heavy dashed line characters (┅ and ┇) for bold, non-intrusive
224/// emphasis.
225pub const BORDER_THICK_DASHED: border::Set = border::Set {
226 top_left: "┏",
227 top_right: "┓",
228 bottom_left: "┗",
229 bottom_right: "┛",
230 vertical_left: "┇",
231 vertical_right: "┇",
232 horizontal_top: "┅",
233 horizontal_bottom: "┅",
234};
235
236/// Border set with thick lines and gaps only at corners
237///
238/// Provides a bold minimalist look with thick continuous lines and gaps only
239/// at corners.
240pub const BORDER_THICK_CORNER_GAPPED: border::Set = border::Set {
241 top_left: " ",
242 top_right: " ",
243 bottom_left: " ",
244 bottom_right: " ",
245 vertical_left: "┃",
246 vertical_right: "┃",
247 horizontal_top: "━",
248 horizontal_bottom: "━",
249};
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254
255 #[test]
256 fn border_style_default() {
257 assert_eq!(BorderStyle::default(), BorderStyle::Standard);
258 }
259
260 #[test]
261 fn border_style_block_creation() {
262 // Test that all variants can create blocks without panicking
263 let styles = [
264 BorderStyle::Standard,
265 BorderStyle::Rounded,
266 BorderStyle::Dashed,
267 BorderStyle::RoundedDashed,
268 BorderStyle::CornerGapped,
269 BorderStyle::RoundedCornerGapped,
270 BorderStyle::DoubleLineStandard,
271 BorderStyle::DoubleLineRounded,
272 BorderStyle::Thick,
273 BorderStyle::ThickRounded,
274 BorderStyle::ThickDashed,
275 BorderStyle::ThickCornerGapped,
276 ];
277
278 for style in &styles {
279 let _block = style.block();
280 }
281 }
282
283 #[test]
284 fn border_style_equality() {
285 assert_eq!(BorderStyle::Standard, BorderStyle::Standard);
286 assert_ne!(BorderStyle::Standard, BorderStyle::Rounded);
287 }
288
289 #[test]
290 fn border_sets_have_valid_characters() {
291 // Ensure all border sets have non-empty strings
292 let sets = [
293 BORDER_DASHED,
294 BORDER_ROUNDED_DASHED,
295 BORDER_CORNER_GAPPED,
296 BORDER_ROUNDED_CORNER_GAPPED,
297 BORDER_DOUBLE_ROUNDED,
298 BORDER_THICK_ROUNDED,
299 BORDER_THICK_DASHED,
300 BORDER_THICK_CORNER_GAPPED,
301 ];
302
303 for set in &sets {
304 assert_ne!(set.top_left, "");
305 assert_ne!(set.top_right, "");
306 assert_ne!(set.bottom_left, "");
307 assert_ne!(set.bottom_right, "");
308 assert_ne!(set.vertical_left, "");
309 assert_ne!(set.vertical_right, "");
310 assert_ne!(set.horizontal_top, "");
311 assert_ne!(set.horizontal_bottom, "");
312 }
313 }
314
315 // Note: Title alignment and position tests are in the `title` module
316}