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