hefesto_widgets/popups/themed_confirmation_popup/
mod.rs1use ratatui::{
2 buffer::Buffer,
3 layout::Rect,
4 text::Line,
5 style::{Color, Style},
6 widgets::Widget,
7};
8
9use crate::{BadgeStack, BorderType, ConfirmationPopup, DotGridConfig, DotPattern, PopupSize};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ConfirmationVariant {
13 Success,
14 Warning,
15 Danger,
16 None,
17}
18
19#[derive(Clone)]
20pub struct ThemedConfirmationPopup<'a> {
21 title: &'a str,
22 body: Vec<Line<'a>>,
23 variant: ConfirmationVariant,
24 confirm_label: &'a str,
25 cancel_label: &'a str,
26 border_type: BorderType,
27 position: Option<(u16, u16)>,
28 origin: Option<(u16, u16)>,
29 width: Option<PopupSize>,
30 height: Option<PopupSize>,
31 header: bool,
32 padding: u16,
33 bg_color: Option<Color>,
34 no_dot_grid: bool,
35 dot_grid: Option<DotGridConfig>,
36 badges: Option<BadgeStack<'a>>,
37}
38
39impl<'a> ThemedConfirmationPopup<'a> {
40 fn border_color(variant: ConfirmationVariant) -> Color {
41 match variant {
42 ConfirmationVariant::Success => Color::Green,
43 ConfirmationVariant::Warning => Color::Yellow,
44 ConfirmationVariant::Danger => Color::Red,
45 ConfirmationVariant::None => Color::Gray,
46 }
47 }
48
49 fn confirm_color(variant: ConfirmationVariant) -> Color {
50 match variant {
51 ConfirmationVariant::Success => Color::Green,
52 ConfirmationVariant::Warning => Color::Yellow,
53 ConfirmationVariant::Danger => Color::Red,
54 ConfirmationVariant::None => Color::Blue,
55 }
56 }
57
58 fn build_inner(&self) -> ConfirmationPopup<'a> {
59 let mut popup = ConfirmationPopup::new()
60 .title(self.title)
61 .body(self.body.clone())
62 .border_color(Self::border_color(self.variant))
63 .confirm_style(Style::new().bg(Self::confirm_color(self.variant)).fg(Color::Black))
64 .cancel_style(Style::new().bg(Color::Gray).fg(Color::Black))
65 .border_type(self.border_type)
66 .options(self.confirm_label, self.cancel_label)
67 .padding(self.padding);
68
69 if let Some((x, y)) = self.position {
70 popup = popup.position(x, y);
71 }
72 if let Some((x, y)) = self.origin {
73 popup = popup.origin(x, y);
74 }
75 if let Some(w) = self.width {
76 popup = popup.width(w);
77 }
78 if let Some(h) = self.height {
79 popup = popup.height(h);
80 }
81 if self.header {
82 popup = popup.header();
83 }
84 if let Some(bg) = self.bg_color {
85 popup = popup.bg_color(bg);
86 }
87 if self.no_dot_grid {
88 popup = popup.no_background();
89 }
90 if let Some(ref dg) = self.dot_grid {
91 popup = popup
92 .background_dots(dg.color, &dg.symbol, dg.density_x)
93 .background_spacing(dg.density_x, dg.density_y);
94 }
95 if let Some(ref badges) = self.badges {
96 popup = popup.badges(badges.clone());
97 }
98
99 popup
100 }
101
102 pub fn new(title: &'a str, body: Vec<Line<'a>>, variant: ConfirmationVariant) -> Self {
103 Self {
104 title,
105 body,
106 variant,
107 confirm_label: "Confirmar",
108 cancel_label: "Cancelar",
109 border_type: BorderType::Rounded,
110 position: None,
111 origin: None,
112 width: None,
113 height: None,
114 header: false,
115 padding: 0,
116 bg_color: None,
117 no_dot_grid: false,
118 dot_grid: None,
119 badges: None,
120 }
121 }
122
123 pub fn options(mut self, confirm_label: &'a str, cancel_label: &'a str) -> Self {
124 self.confirm_label = confirm_label;
125 self.cancel_label = cancel_label;
126 self
127 }
128
129 pub fn border_type(mut self, border_type: BorderType) -> Self {
130 self.border_type = border_type;
131 self
132 }
133
134 pub fn position(mut self, x: u16, y: u16) -> Self {
135 self.position = Some((x, y));
136 self
137 }
138
139 pub fn origin(mut self, x: u16, y: u16) -> Self {
140 self.origin = Some((x, y));
141 self
142 }
143
144 pub fn width(mut self, width: PopupSize) -> Self {
145 self.width = Some(width);
146 self
147 }
148
149 pub fn height(mut self, height: PopupSize) -> Self {
150 self.height = Some(height);
151 self
152 }
153
154 pub fn header(mut self) -> Self {
155 self.header = true;
156 self
157 }
158
159 pub fn padding(mut self, padding: u16) -> Self {
160 self.padding = padding;
161 self
162 }
163
164 pub fn resolve_rect(&self, area: Rect) -> Rect {
165 self.build_inner().resolve_rect(area)
166 }
167
168 pub fn bg_color(mut self, color: Color) -> Self {
171 self.bg_color = Some(color);
172 self
173 }
174
175 pub fn no_background(mut self) -> Self {
176 self.no_dot_grid = true;
177 self
178 }
179
180 pub fn background_dots(mut self, color: Color, symbol: &str, density: u16) -> Self {
181 self.dot_grid = Some(DotGridConfig { color, symbol: symbol.to_string(), density_x: density, density_y: density, pattern: DotPattern::default() });
182 self
183 }
184
185 pub fn background_pattern(mut self, pattern: DotPattern) -> Self {
186 if let Some(ref mut dg) = self.dot_grid {
187 dg.pattern = pattern;
188 } else {
189 self.no_dot_grid = false;
190 self.dot_grid = Some(DotGridConfig { pattern, ..DotGridConfig::default() });
191 }
192 self
193 }
194
195 pub fn background_spacing(mut self, density_x: u16, density_y: u16) -> Self {
196 if let Some(ref mut dg) = self.dot_grid {
197 dg.density_x = density_x;
198 dg.density_y = density_y;
199 } else {
200 self.no_dot_grid = false;
201 self.dot_grid = Some(DotGridConfig {
202 density_x,
203 density_y,
204 ..DotGridConfig::default()
205 });
206 }
207 self
208 }
209
210 pub fn badges(mut self, badges: BadgeStack<'a>) -> Self {
211 self.badges = Some(badges);
212 self
213 }
214}
215
216impl Widget for ThemedConfirmationPopup<'_> {
217 fn render(self, area: Rect, buf: &mut Buffer) {
218 self.build_inner().render(area, buf);
219 }
220}
221
222#[cfg(test)]
223mod tests;