1use super::{actions::*, after::*, split_panel::*, which::*};
2
3use {
4 cursive::{direction::*, event::*, theme::*, view::*, *},
5 std::cmp::*,
6};
7
8const TYPE_NAME: &str = "SplitPanel";
9
10const TOP_LEFT: &str = "┌";
11const BOTTOM_LEFT: &str = "└";
12const TOP_RIGHT: &str = "┐";
13const BOTTOM_RIGHT: &str = "┘";
14const VERTICAL: &str = "│";
15const VERTICAL_THICK: &str = "┃";
16const HORIZONTAL: &str = "─";
17const HORIZONTAL_THICK: &str = "━";
18const TOP_HINGE: &str = "┰";
19const BOTTOM_HINGE: &str = "┸";
20const LEFT_HINGE: &str = "┝";
21const RIGHT_HINGE: &str = "┥";
22
23impl View for SplitPanel {
24 fn type_name(&self) -> &'static str {
25 TYPE_NAME
26 }
27
28 fn focus_view(&mut self, selector: &Selector) -> Result<EventResult, ViewNotFound> {
29 if let Ok(prior) = self.front.view.focus_view(selector) {
30 Ok(self.set_focus(Some(WhichPane::Front)).after(prior))
31 } else if let Ok(prior) = self.back.view.focus_view(selector) {
32 Ok(self.set_focus(Some(WhichPane::Back)).after(prior))
33 } else {
34 Err(ViewNotFound)
35 }
36 }
37
38 fn take_focus(&mut self, source: Direction) -> Result<EventResult, CannotFocus> {
39 match source.relative(self.orientation).unwrap_or(Relative::Front) {
40 Relative::Front => match self.front.view.take_focus(source) {
41 Ok(event_result) => Ok(event_result),
42 Err(_) => self.back.view.take_focus(source),
43 },
44
45 Relative::Back => match self.back.view.take_focus(source) {
46 Ok(event_result) => Ok(event_result),
47 Err(_) => self.front.view.take_focus(source),
48 },
49 }
50 }
51
52 fn needs_relayout(&self) -> bool {
53 self.needs_relayout || self.front.view.needs_relayout() || self.back.view.needs_relayout()
54 }
55
56 fn layout(&mut self, mut size: Vec2) {
57 self.size = Some(size);
58
59 if self.border {
61 size = size.checked_sub((2, 2)).unwrap_or_default();
62 }
63 let extent = *size.get(self.orientation);
64
65 let mut divider = self.layout_divider(extent);
67
68 self.front.start = 0;
70 self.front.extent = divider;
71
72 if self.visible_divider {
73 divider += 1;
74 }
75
76 self.back.start = divider;
78 if self.back.start >= extent {
79 self.back.start = 0;
81 self.back.extent = 0;
82 } else {
83 self.back.extent = extent - self.back.start;
84 }
85
86 self.front.layout(size, self.orientation);
87 self.back.layout(size, self.orientation);
88
89 self.needs_relayout = false;
90 }
91
92 fn required_size(&mut self, mut constraint: Vec2) -> Vec2 {
93 if self.border {
94 constraint = constraint.checked_sub((2, 2)).unwrap_or_default();
95 }
96
97 let front = self.front.required_size(constraint, self.orientation);
98 let back = self.back.required_size(constraint, self.orientation);
99
100 let size = Vec2::from(match self.orientation {
101 Orientation::Horizontal => (front.x + back.x, max(front.y, back.y)),
102 Orientation::Vertical => (max(front.x, back.x), front.y + back.y),
103 });
104
105 match (self.border, self.visible_divider) {
106 (true, true) => {
107 size + match self.orientation {
108 Orientation::Horizontal => (3, 2),
109 Orientation::Vertical => (2, 3),
110 }
111 }
112
113 (true, false) => size + (2, 2),
114
115 (false, true) => {
116 size + match self.orientation {
117 Orientation::Horizontal => (1, 0),
118 Orientation::Vertical => (0, 1),
119 }
120 }
121
122 (false, false) => size,
123 }
124 }
125
126 fn important_area(&self, size: Vec2) -> Rect {
127 match self.focus {
128 Some(WhichPane::Front) => self.front.important_area(size, self.orientation, self.border),
129 Some(WhichPane::Back) => self.back.important_area(size, self.orientation, self.border),
130 None => Rect::from_size((0, 0), size),
131 }
132 }
133
134 fn on_event(&mut self, event: Event) -> EventResult {
135 match if self.movable_divider { self.actions.get(&event) } else { None } {
136 Some(action) => match action {
137 Action::MoveDividerToFront => self.move_divider(-1),
138 Action::MoveDividerToBack => self.move_divider(1),
139
140 Action::ToggleBorder => {
141 self.set_border(!self.border);
142 EventResult::consumed()
143 }
144
145 Action::ToggleVisibleDivider => {
146 self.set_visible_divider(!self.visible_divider);
147 EventResult::consumed()
148 }
149
150 Action::ToggleMovableDivider => {
151 self.set_movable_divider(!self.movable_divider);
152 EventResult::consumed()
153 }
154
155 Action::ToggleOrientation => {
156 self.set_orientation(self.orientation.swap());
157
158 self.remove_action(Action::MoveDividerToFront);
159 self.remove_action(Action::MoveDividerToBack);
160
161 match self.orientation {
162 Orientation::Horizontal => {
163 self.set_action(Action::MoveDividerToFront, Event::Shift(Key::Left));
164 self.set_action(Action::MoveDividerToBack, Event::Shift(Key::Right));
165 }
166 direction::Orientation::Vertical => {
167 self.set_action(Action::MoveDividerToFront, Event::Shift(Key::Up));
168 self.set_action(Action::MoveDividerToBack, Event::Shift(Key::Down));
169 }
170 }
171
172 EventResult::consumed()
173 }
174 },
175
176 None => match event {
177 Event::Mouse { offset, position, event } => {
178 if event.button() == Some(MouseButton::Left) && self.is_on_movable_divider(offset, position) {
179 self.moving_divider = true;
182 EventResult::consumed()
183 } else if self.moving_divider {
184 if matches!(event, MouseEvent::Release(_)) {
185 self.moving_divider = false;
188 } else if let Some(position) = position.checked_sub(offset) {
189 let mut divider = *position.get(self.orientation);
192
193 if self.border {
194 divider = divider.checked_sub(1).unwrap_or_default();
195 }
196
197 self.set_divider(divider);
198 }
199
200 EventResult::consumed()
201 } else if let Some((offset, position)) =
202 self.front.mouse_event(offset, position, self.orientation, self.border, self.size)
203 {
204 let prior = if event.grabs_focus() {
207 self.set_focus(Some(WhichPane::Front))
208 } else {
209 EventResult::Ignored
210 };
211
212 self.front.view.on_event(Event::Mouse { offset, position, event }).after(prior)
213 } else if let Some((offset, position)) =
214 self.back.mouse_event(offset, position, self.orientation, self.border, self.size)
215 {
216 let prior = if event.grabs_focus() {
219 self.set_focus(Some(WhichPane::Back))
220 } else {
221 EventResult::Ignored
222 };
223
224 self.back.view.on_event(Event::Mouse { offset, position, event }).after(prior)
225 } else {
226 EventResult::Ignored
227 }
228 }
229
230 event => match self.focus {
231 Some(WhichPane::Front) => self.front.view.on_event(event),
232 Some(WhichPane::Back) => self.back.view.on_event(event),
233 None => {
234 let prior = self.set_focus(Some(WhichPane::Front));
236 self.front.view.on_event(event).after(prior)
237 }
238 },
239 },
240 }
241 }
242
243 fn call_on_any(&mut self, selector: &Selector, callback: AnyCb) {
244 self.front.view.call_on_any(selector, callback);
245 self.back.view.call_on_any(selector, callback);
246 }
247
248 fn draw(&self, printer: &Printer) {
249 let mut _shrinked = None;
250 let printer = if self.draw_lines(printer) {
251 _shrinked = Some(printer.shrinked_centered((2, 2)));
252 &_shrinked.expect("shrinked")
253 } else {
254 printer
255 };
256
257 self.front.draw(printer, self.orientation, self.is_focused(WhichPane::Front));
258 self.back.draw(printer, self.orientation, self.is_focused(WhichPane::Back));
259 }
260}
261
262impl SplitPanel {
263 fn is_focused(&self, which: WhichPane) -> bool {
265 self.focus.map(|focus| focus == which).unwrap_or_default()
266 }
267
268 fn set_focus(&mut self, focus: Option<WhichPane>) -> EventResult {
270 let old_focus = self.focus;
271 self.focus = focus;
272 if self.focus != old_focus
273 && let Some(old_focus) = old_focus
274 {
275 match old_focus {
276 WhichPane::Front => self.front.view.on_event(Event::FocusLost),
277 WhichPane::Back => self.back.view.on_event(Event::FocusLost),
278 }
279 } else {
280 EventResult::consumed()
281 }
282 }
283
284 fn is_on_movable_divider(&self, offset: Vec2, position: Vec2) -> bool {
286 if self.visible_divider
287 && self.movable_divider
288 && !self.moving_divider
289 && let Some(mut divider) = self.divider
290 && let Some(size) = self.size
291 && let Some(position) = position.checked_sub(offset)
292 {
293 if self.border {
294 divider += 1;
295 let corner = size.checked_sub((1, 1)).unwrap_or_default();
296 match self.orientation {
297 Orientation::Horizontal => position.y > 0 && position.y < corner.y && position.x == divider,
298 Orientation::Vertical => position.x > 0 && position.x < corner.x && position.y == divider,
299 }
300 } else {
301 match self.orientation {
302 Orientation::Horizontal => position.x == divider,
303 Orientation::Vertical => position.y == divider,
304 }
305 }
306 } else {
307 false
308 }
309 }
310
311 fn move_divider(&mut self, delta: isize) -> EventResult {
313 if self.movable_divider {
314 self.set_divider(self.divider.and_then(|divider| divider.checked_add_signed(delta)).unwrap_or_default());
315 EventResult::consumed()
316 } else {
317 EventResult::Ignored
318 }
319 }
320
321 fn layout_divider(&mut self, extent: usize) -> usize {
325 self.divider = Some(match self.divider {
326 Some(divider) => min(divider, extent.checked_sub(1).unwrap_or_default()),
327 None => extent / 2,
328 });
329
330 self.divider.expect("divider")
331 }
332
333 fn draw_lines(&self, printer: &Printer) -> bool {
337 let corner = printer.size.checked_sub((1, 1)).unwrap_or_default();
338
339 if self.border {
340 printer.print((0, 0), TOP_LEFT);
342 printer.print((corner.x, 0), TOP_RIGHT);
343 printer.print((0, corner.y), BOTTOM_LEFT);
344 printer.print(corner, BOTTOM_RIGHT);
345
346 if self.visible_divider
347 && let Some(mut divider) = self.divider
348 {
349 divider = min(divider + 1, corner.get(self.orientation).checked_sub(1).unwrap_or_default());
350
351 let mut _divider_printer = None;
352 let divider_printer = if self.moving_divider {
353 let mut divider_printer = printer.clone();
354 divider_printer.set_effect(Effect::Reverse);
355 _divider_printer = Some(divider_printer);
356 &_divider_printer.expect("divider_printer")
357 } else {
358 printer
359 };
360
361 match self.orientation {
362 Orientation::Horizontal => {
363 printer.print((divider, 0), TOP_HINGE);
365 printer.print((divider, corner.y), BOTTOM_HINGE);
366
367 if let Some(length) = divider.checked_sub(1) {
369 printer.print_hline((1, 0), length, HORIZONTAL);
371 printer.print_hline((1, corner.y), length, HORIZONTAL);
373 }
374
375 if let Some(length) = corner.x.checked_sub(divider + 1) {
377 printer.print_hline((divider + 1, 0), length, HORIZONTAL);
379 printer.print_hline((divider + 1, corner.y), length, HORIZONTAL);
381 }
382
383 if let Some(length) = corner.y.checked_sub(1) {
384 printer.print_vline((0, 1), length, VERTICAL);
386 divider_printer.print_vline((divider, 1), length, VERTICAL_THICK);
388 printer.print_vline((corner.x, 1), length, VERTICAL);
390 }
391 }
392
393 Orientation::Vertical => {
394 printer.print((0, divider), LEFT_HINGE);
396 printer.print((corner.x, divider), RIGHT_HINGE);
397
398 if let Some(length) = divider.checked_sub(1) {
400 printer.print_vline((0, 1), length, VERTICAL);
402 printer.print_vline((corner.x, 1), length, VERTICAL);
404 }
405
406 if let Some(length) = corner.y.checked_sub(divider + 1) {
408 printer.print_vline((0, divider + 1), length, VERTICAL);
410 printer.print_vline((corner.x, divider + 1), length, VERTICAL);
412 }
413
414 if let Some(length) = corner.x.checked_sub(1) {
415 printer.print_hline((1, 0), length, HORIZONTAL);
417 divider_printer.print_hline((1, divider), length, HORIZONTAL_THICK);
419 printer.print_hline((1, corner.y), length, HORIZONTAL);
421 }
422 }
423 }
424 } else {
425 if let Some(length) = corner.y.checked_sub(1) {
426 printer.print_vline((0, 1), length, VERTICAL);
428 printer.print_vline((corner.x, 1), length, VERTICAL);
430 }
431
432 if let Some(length) = corner.x.checked_sub(1) {
433 printer.print_hline((1, 0), length, HORIZONTAL);
435 printer.print_hline((1, corner.y), length, HORIZONTAL);
437 }
438 }
439
440 true
441 } else if self.visible_divider
442 && let Some(divider) = self.divider
443 {
444 match self.orientation {
445 Orientation::Horizontal => printer.print_vline((divider, 0), corner.y, VERTICAL),
446 Orientation::Vertical => printer.print_vline((divider, 0), corner.y, VERTICAL),
447 }
448
449 false
450 } else {
451 false
452 }
453 }
454}