1use crate::layout::GenericLayout;
7use ratatui::layout::{Flex, Rect, Size};
8use std::borrow::Cow;
9use std::cmp::{max, min};
10
11#[allow(variant_size_differences)]
13#[derive(Debug)]
14pub enum EditConstraint {
15 Label(Cow<'static, str>),
17 LabelWidth(u16),
20 LabelRows(u16, u16),
23 TitleLabel(Cow<'static, str>),
26 TitleLabelWidth(u16),
30 TitleLabelRows(u16),
34 Widget(u16),
37 WidgetRows(u16, u16),
40 Empty,
43 EmptyRows(u16),
47 LineWidget(u16),
50 LineWidgetRows(u16, u16),
53}
54
55#[allow(clippy::comparison_chain)]
68pub fn layout_edit(
69 area: Size,
70 constraints: &[EditConstraint],
71 mut spacing: u16,
72 flex: Flex,
73) -> GenericLayout<usize> {
74 let mut max_label = 0;
75 let mut max_widget = 0;
76
77 for l in constraints.iter() {
79 match l {
80 EditConstraint::Label(s) => max_label = max(max_label, s.len() as u16),
81 EditConstraint::LabelWidth(w) => max_label = max(max_label, *w),
82 EditConstraint::LabelRows(w, _) => max_label = max(max_label, *w),
83 EditConstraint::TitleLabel(_) => {}
84 EditConstraint::TitleLabelWidth(_) => {}
85 EditConstraint::TitleLabelRows(_) => {}
86 EditConstraint::Widget(w) => max_widget = max(max_widget, *w),
87 EditConstraint::WidgetRows(w, _) => max_widget = max(max_widget, *w),
88 EditConstraint::LineWidget(_) => {}
89 EditConstraint::LineWidgetRows(_, _) => {}
90 EditConstraint::Empty => {}
91 EditConstraint::EmptyRows(_) => {}
92 }
93 }
94
95 let mut gen_layout = GenericLayout::new();
96
97 if max_label + spacing + max_widget > area.width {
99 let mut reduce = max_label + spacing + max_widget - area.width;
100
101 if spacing > reduce {
102 spacing -= reduce;
103 reduce = 0;
104 } else {
105 reduce -= spacing;
106 spacing = 0;
107 }
108 if max_label > 5 {
109 if max_label - 5 > reduce {
110 max_label -= reduce;
111 reduce = 0;
112 } else {
113 reduce -= max_label - 5;
114 max_label = 5;
115 }
116 }
117 if max_widget > 5 {
118 if max_widget - 5 > reduce {
119 max_widget -= reduce;
120 reduce = 0;
121 } else {
122 reduce -= max_widget - 5;
123 max_widget = 5;
124 }
125 }
126 if max_label > reduce {
127 max_label -= reduce;
128 reduce = 0;
129 } else {
130 reduce -= max_label;
131 max_label = 0;
132 }
133 if max_widget > reduce {
134 max_widget -= reduce;
135 } else {
137 max_widget = 0;
139 }
140 }
141
142 let label_x;
143 let widget_x;
144
145 match flex {
146 Flex::Legacy => {
147 label_x = 0;
148 widget_x = label_x + spacing + max_label;
149 }
150 Flex::Start => {
151 label_x = 0;
152 widget_x = label_x + spacing + max_label;
153 }
154 Flex::End => {
155 widget_x = area.width - max_widget;
156 label_x = widget_x - spacing - max_label;
157 }
158 Flex::Center => {
159 let rest = area.width - max_label - max_widget - spacing;
160 label_x = rest / 2;
161 widget_x = label_x + spacing + max_label;
162 }
163 Flex::SpaceAround => {
164 let rest = area.width - max_label - max_widget - spacing;
165 label_x = rest / 2;
166 widget_x = label_x + spacing + max_label;
167 }
168 Flex::SpaceBetween => {
169 let rest = area.width - max_label - max_widget;
170 label_x = rest / 3;
171 widget_x = label_x + rest / 3 + max_label;
172 }
173 }
174 let total = max_label + spacing + max_widget;
175
176 let mut n = 0;
177 let mut y = 0;
178
179 let mut label_area = Rect::default();
180 let mut label_text = None;
181
182 let mut rest_height = if area.height > 0 { area.height - 1 } else { 0 };
183
184 for l in constraints.iter() {
185 let height;
186
187 match l {
189 EditConstraint::Label(s) => {
190 height = 0;
191 label_area = Rect::new(label_x, y, max_label, min(1, rest_height));
192 label_text = Some(s.clone());
193 }
194 EditConstraint::LabelWidth(_) => {
195 height = 0;
196 label_area = Rect::new(label_x, y, max_label, min(1, rest_height));
197 label_text = None;
198 }
199 EditConstraint::LabelRows(_, h) => {
200 height = 0;
201 label_area = Rect::new(label_x, y, max_label, min(1, min(*h, rest_height)));
202 label_text = None;
203 }
204 EditConstraint::TitleLabel(s) => {
205 height = min(1, rest_height);
206
207 label_area = Rect::new(label_x, y, total, height);
208 gen_layout.add(n, Rect::default(), Some(s.clone()), label_area);
209
210 n += 1;
211 label_area = Rect::default();
212 label_text = None;
213 }
214 EditConstraint::TitleLabelWidth(w) => {
215 height = min(1, rest_height);
216
217 label_area = Rect::new(label_x, y, min(*w, max_label), height);
218 gen_layout.add(n, Rect::default(), None, label_area);
219
220 n += 1;
221 label_area = Rect::default();
222 label_text = None;
223 }
224 EditConstraint::TitleLabelRows(h) => {
225 height = min(*h, rest_height);
226
227 label_area = Rect::new(label_x, y, total, height);
228 gen_layout.add(n, Rect::default(), None, label_area);
229
230 n += 1;
231 label_area = Rect::default();
232 label_text = None;
233 }
234 EditConstraint::Widget(w) => {
235 let w_height = min(1, rest_height);
236 height = max(label_area.height, w_height);
237
238 let area = Rect::new(widget_x, y, min(*w, max_widget), w_height);
239 gen_layout.add(n, area, label_text.take(), label_area);
240
241 n += 1;
242 label_area = Rect::default();
243 }
244 EditConstraint::WidgetRows(w, h) => {
245 let w_height = min(*h, rest_height);
246 height = max(label_area.height, w_height);
247
248 let area = Rect::new(widget_x, y, min(*w, max_widget), w_height);
249 gen_layout.add(n, area, label_text.take(), label_area);
250
251 n += 1;
252 label_area = Rect::default();
253 }
254 EditConstraint::LineWidget(w) => {
255 height = min(1, rest_height);
256
257 let area = Rect::new(label_x, y, min(*w, total), height);
258 gen_layout.add(n, area, label_text.take(), label_area);
259
260 n += 1;
261 label_area = Rect::default();
262 }
263 EditConstraint::LineWidgetRows(w, h) => {
264 height = min(*h, rest_height);
265
266 let area = Rect::new(label_x, y, min(*w, total), height);
267 gen_layout.add(n, area, label_text.take(), label_area);
268
269 n += 1;
270 label_area = Rect::default();
271 }
272 EditConstraint::Empty => {
273 height = min(1, rest_height);
274
275 label_text = None;
276 label_area = Rect::default();
277 }
278 EditConstraint::EmptyRows(h) => {
279 height = min(*h, rest_height);
280
281 label_text = None;
282 label_area = Rect::default();
283 }
284 }
285
286 y += height;
287 rest_height -= height;
288 }
289
290 gen_layout
291}