1use crate::_private::NonExhaustive;
38use crate::splitter::split_impl::{get_fill_char, get_join_0, get_join_1, get_mark_0, get_mark_1};
39use crate::splitter::split_layout::layout_split;
40use crate::util::{fill_buf_area, revert_style};
41use rat_event::util::MouseFlagsN;
42use rat_event::{HandleEvent, MouseOnly, Outcome, Regular, ct_event, event_flow};
43use rat_focus::{FocusBuilder, FocusFlag, HasFocus, Navigation};
44use rat_reloc::{RelocatableState, relocate_area, relocate_areas, relocate_positions};
45use ratatui::buffer::Buffer;
46use ratatui::layout::{Constraint, Direction, Position, Rect};
47use ratatui::style::Style;
48use ratatui::widgets::{Block, BorderType, StatefulWidget, Widget};
49use std::cmp::{max, min};
50use std::rc::Rc;
51use unicode_segmentation::UnicodeSegmentation;
52
53mod split_impl;
54mod split_layout;
55
56#[derive(Debug, Default, Clone)]
57pub struct Split<'a> {
79 direction: Direction,
81 constraints: Vec<Constraint>,
84 resize: SplitResize,
86
87 split_type: SplitType,
89 join_0: Option<BorderType>,
91 join_1: Option<BorderType>,
93 mark_offset: u16,
95 mark_0_char: Option<&'a str>,
97 mark_1_char: Option<&'a str>,
99
100 style: Style,
102 block: Option<Block<'a>>,
103 arrow_style: Option<Style>,
104 drag_style: Option<Style>,
105}
106
107#[derive(Debug, Clone)]
109pub struct LayoutWidget<'a> {
110 split: Rc<Split<'a>>,
111}
112
113#[derive(Debug, Clone)]
115pub struct SplitWidget<'a> {
116 split: Rc<Split<'a>>,
117}
118
119#[derive(Debug, Clone)]
123pub struct SplitStyle {
124 pub style: Style,
126 pub block: Option<Block<'static>>,
128 pub border_style: Option<Style>,
129 pub title_style: Option<Style>,
130 pub arrow_style: Option<Style>,
132 pub drag_style: Option<Style>,
134
135 pub horizontal_mark: Option<&'static str>,
138 pub vertical_mark: Option<&'static str>,
141
142 pub non_exhaustive: NonExhaustive,
143}
144
145#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
147pub enum SplitType {
148 #[default]
151 FullEmpty,
152 FullPlain,
155 FullDouble,
158 FullThick,
161 FullQuadrantInside,
165 FullQuadrantOutside,
169 Scroll,
180 Widget,
187}
188
189#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
191pub enum SplitResize {
192 Neighbours,
195 #[default]
199 Full,
200}
201
202const SPLIT_WIDTH: u16 = 1;
203
204#[derive(Debug)]
206pub struct SplitState {
207 pub area: Rect,
210 pub inner: Rect,
213 pub widget_areas: Vec<Rect>,
217 pub splitline_areas: Vec<Rect>,
221 pub splitline_mark_position: Vec<Position>,
224 pub mark_offset: u16,
227
228 pub direction: Direction,
231 pub split_type: SplitType,
233 pub resize: SplitResize,
235
236 area_length: Vec<u16>,
241 hidden_length: Vec<u16>,
243
244 pub focus: FocusFlag,
247 pub focus_marker: Option<usize>,
251
252 pub mouse: MouseFlagsN,
255
256 relocate_split: bool,
259
260 pub non_exhaustive: NonExhaustive,
261}
262
263impl SplitType {
264 pub fn is_full(&self) -> bool {
265 use SplitType::*;
266 match self {
267 FullEmpty => true,
268 FullPlain => true,
269 FullDouble => true,
270 FullThick => true,
271 FullQuadrantInside => true,
272 FullQuadrantOutside => true,
273 Scroll => false,
274 Widget => false,
275 }
276 }
277}
278
279impl Default for SplitStyle {
280 fn default() -> Self {
281 Self {
282 style: Default::default(),
283 block: Default::default(),
284 border_style: Default::default(),
285 title_style: Default::default(),
286 arrow_style: Default::default(),
287 drag_style: Default::default(),
288 horizontal_mark: Default::default(),
289 vertical_mark: Default::default(),
290 non_exhaustive: NonExhaustive,
291 }
292 }
293}
294
295impl<'a> Split<'a> {
296 pub fn new() -> Self {
301 Self {
302 direction: Direction::Horizontal,
303 ..Default::default()
304 }
305 }
306
307 pub fn horizontal() -> Self {
309 Self {
310 direction: Direction::Horizontal,
311 ..Default::default()
312 }
313 }
314
315 pub fn vertical() -> Self {
317 Self {
318 direction: Direction::Horizontal,
319 ..Default::default()
320 }
321 }
322
323 pub fn constraints(mut self, constraints: impl IntoIterator<Item = Constraint>) -> Self {
329 self.constraints = constraints.into_iter().collect();
330 self
331 }
332
333 pub fn direction(mut self, direction: Direction) -> Self {
337 self.direction = direction;
338 self
339 }
340
341 pub fn split_type(mut self, split_type: SplitType) -> Self {
343 self.split_type = split_type;
344 self
345 }
346
347 pub fn resize(mut self, resize: SplitResize) -> Self {
349 self.resize = resize;
350 self
351 }
352
353 pub fn join(mut self, border: BorderType) -> Self {
357 self.join_0 = Some(border);
358 self.join_1 = Some(border);
359 self
360 }
361
362 pub fn join_0(mut self, border: BorderType) -> Self {
366 self.join_0 = Some(border);
367 self
368 }
369
370 pub fn join_1(mut self, border: BorderType) -> Self {
374 self.join_1 = Some(border);
375 self
376 }
377
378 pub fn block(mut self, block: Block<'a>) -> Self {
380 self.block = Some(block);
381 self
382 }
383
384 pub fn styles(mut self, styles: SplitStyle) -> Self {
386 self.style = styles.style;
387 if styles.block.is_some() {
388 self.block = styles.block;
389 }
390 if let Some(border_style) = styles.border_style {
391 self.block = self.block.map(|v| v.border_style(border_style));
392 }
393 if let Some(title_style) = styles.title_style {
394 self.block = self.block.map(|v| v.title_style(title_style));
395 }
396 self.block = self.block.map(|v| v.style(self.style));
397
398 if styles.drag_style.is_some() {
399 self.drag_style = styles.drag_style;
400 }
401 if styles.arrow_style.is_some() {
402 self.arrow_style = styles.arrow_style;
403 }
404 match self.direction {
405 Direction::Horizontal => {
406 if let Some(mark) = styles.horizontal_mark {
407 let mut g = mark.graphemes(true);
408 if let Some(g0) = g.next() {
409 self.mark_0_char = Some(g0);
410 }
411 if let Some(g1) = g.next() {
412 self.mark_1_char = Some(g1);
413 }
414 }
415 }
416 Direction::Vertical => {
417 if let Some(mark) = styles.vertical_mark {
418 let mut g = mark.graphemes(true);
419 if let Some(g0) = g.next() {
420 self.mark_0_char = Some(g0);
421 }
422 if let Some(g1) = g.next() {
423 self.mark_1_char = Some(g1);
424 }
425 }
426 }
427 }
428 self
429 }
430
431 pub fn style(mut self, style: Style) -> Self {
433 self.style = style;
434 self.block = self.block.map(|v| v.style(style));
435 self
436 }
437
438 pub fn arrow_style(mut self, style: Style) -> Self {
440 self.arrow_style = Some(style);
441 self
442 }
443
444 pub fn drag_style(mut self, style: Style) -> Self {
446 self.drag_style = Some(style);
447 self
448 }
449
450 pub fn mark_offset(mut self, offset: u16) -> Self {
452 self.mark_offset = offset;
453 self
454 }
455
456 pub fn mark_0(mut self, mark: &'a str) -> Self {
458 self.mark_0_char = Some(mark);
459 self
460 }
461
462 pub fn mark_1(mut self, mark: &'a str) -> Self {
464 self.mark_1_char = Some(mark);
465 self
466 }
467
468 #[deprecated(since = "2.4.0", note = "use into_widgets() instead")]
476 pub fn into_widget(self, area: Rect, state: &mut SplitState) -> SplitWidget<'a> {
477 layout_split(&self, area, state);
478 SplitWidget {
479 split: Rc::new(self),
480 }
481 }
482
483 #[deprecated(since = "2.4.0", note = "use into_widgets() instead")]
492 pub fn into_widget_layout(
493 self,
494 area: Rect,
495 state: &mut SplitState,
496 ) -> (SplitWidget<'a>, Vec<Rect>) {
497 layout_split(&self, area, state);
498 (
499 SplitWidget {
500 split: Rc::new(self),
501 },
502 state.widget_areas.clone(),
503 )
504 }
505
506 pub fn into_widgets(self) -> (LayoutWidget<'a>, SplitWidget<'a>) {
518 let split = Rc::new(self);
519 (
520 LayoutWidget {
521 split: split.clone(), },
523 SplitWidget {
524 split, },
526 )
527 }
528}
529
530impl<'a> StatefulWidget for &Split<'a> {
531 type State = SplitState;
532
533 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
534 layout_split(self, area, state);
535 render_split(self, buf, state);
536 state.relocate_split = false;
537 }
538}
539
540impl<'a> StatefulWidget for Split<'a> {
541 type State = SplitState;
542
543 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
544 layout_split(&self, area, state);
545 render_split(&self, buf, state);
546 state.relocate_split = false;
547 }
548}
549
550impl<'a> StatefulWidget for &LayoutWidget<'a> {
551 type State = SplitState;
552
553 fn render(self, area: Rect, _buf: &mut Buffer, state: &mut Self::State) {
554 layout_split(&self.split, area, state);
556 }
557}
558
559impl<'a> StatefulWidget for LayoutWidget<'a> {
560 type State = SplitState;
561
562 fn render(self, area: Rect, _buf: &mut Buffer, state: &mut Self::State) {
563 layout_split(&self.split, area, state);
565 }
566}
567
568impl<'a> StatefulWidget for &SplitWidget<'a> {
569 type State = SplitState;
570
571 fn render(self, _area: Rect, buf: &mut Buffer, state: &mut Self::State) {
572 render_split(&self.split, buf, state);
573 }
574}
575
576impl StatefulWidget for SplitWidget<'_> {
577 type State = SplitState;
578
579 fn render(self, _area: Rect, buf: &mut Buffer, state: &mut Self::State) {
580 render_split(&self.split, buf, state);
581 }
582}
583
584fn render_split(split: &Split<'_>, buf: &mut Buffer, state: &mut SplitState) {
585 let area = state.area;
586 if state.is_focused() {
587 if state.focus_marker.is_none() {
588 state.focus_marker = Some(0);
589 }
590 } else {
591 state.focus_marker = None;
592 }
593
594 split.block.render(area, buf);
595
596 for (n, split_area) in state.splitline_areas.iter().enumerate() {
597 if split.direction == Direction::Horizontal {
599 if split_area.width == 0 {
600 continue;
601 }
602 } else {
603 if split_area.height == 0 {
604 continue;
605 }
606 }
607
608 let (style, arrow_style) = if Some(n) == state.mouse.drag.get()
609 || Some(n) == state.focus_marker
610 || Some(n) == state.mouse.hover.get()
611 {
612 if let Some(drag) = split.drag_style {
613 (drag, drag)
614 } else {
615 (revert_style(split.style), revert_style(split.style))
616 }
617 } else {
618 if let Some(arrow) = split.arrow_style {
619 (split.style, arrow)
620 } else {
621 (split.style, split.style)
622 }
623 };
624
625 if let Some(fill) = get_fill_char(split) {
626 fill_buf_area(buf, *split_area, fill, style);
627 }
628
629 let mark = state.splitline_mark_position[n];
630 if split.direction == Direction::Horizontal {
631 if buf.area.contains((mark.x, mark.y).into()) {
632 if let Some(cell) = buf.cell_mut((mark.x, mark.y)) {
633 cell.set_style(arrow_style);
634 cell.set_symbol(get_mark_0(split));
635 }
636 }
637 if buf.area.contains((mark.x, mark.y + 1).into()) {
638 if let Some(cell) = buf.cell_mut((mark.x, mark.y + 1)) {
639 cell.set_style(arrow_style);
640 cell.set_symbol(get_mark_1(split));
641 }
642 }
643 } else {
644 if let Some(cell) = buf.cell_mut((mark.x, mark.y)) {
645 cell.set_style(arrow_style);
646 cell.set_symbol(get_mark_0(split));
647 }
648 if let Some(cell) = buf.cell_mut((mark.x + 1, mark.y)) {
649 cell.set_style(arrow_style);
650 cell.set_symbol(get_mark_1(split));
651 }
652 }
653
654 if let Some((pos_0, c_0)) = get_join_0(split, *split_area, state) {
655 if let Some(cell) = buf.cell_mut((pos_0.x, pos_0.y)) {
656 cell.set_symbol(c_0);
657 }
658 }
659 if let Some((pos_1, c_1)) = get_join_1(split, *split_area, state) {
660 if let Some(cell) = buf.cell_mut((pos_1.x, pos_1.y)) {
661 cell.set_symbol(c_1);
662 }
663 }
664 }
665}
666
667impl Default for SplitState {
668 fn default() -> Self {
669 Self {
670 area: Default::default(),
671 inner: Default::default(),
672 widget_areas: Default::default(),
673 splitline_areas: Default::default(),
674 splitline_mark_position: Default::default(),
675 mark_offset: Default::default(),
676 direction: Default::default(),
677 split_type: Default::default(),
678 resize: Default::default(),
679 area_length: Default::default(),
680 hidden_length: Default::default(),
681 focus: Default::default(),
682 focus_marker: Default::default(),
683 mouse: Default::default(),
684 relocate_split: Default::default(),
685 non_exhaustive: NonExhaustive,
686 }
687 }
688}
689
690impl Clone for SplitState {
691 fn clone(&self) -> Self {
692 Self {
693 area: self.area,
694 inner: self.inner,
695 widget_areas: self.widget_areas.clone(),
696 splitline_areas: self.splitline_areas.clone(),
697 splitline_mark_position: self.splitline_mark_position.clone(),
698 mark_offset: self.mark_offset,
699 direction: self.direction,
700 split_type: self.split_type,
701 resize: self.resize,
702 area_length: self.area_length.clone(),
703 hidden_length: self.hidden_length.clone(),
704 focus: self.focus.new_instance(),
705 focus_marker: self.focus_marker,
706 mouse: Default::default(),
707 relocate_split: self.relocate_split,
708 non_exhaustive: NonExhaustive,
709 }
710 }
711}
712
713impl HasFocus for SplitState {
714 fn build(&self, builder: &mut FocusBuilder) {
715 builder.leaf_widget(self);
716 }
717
718 fn focus(&self) -> FocusFlag {
719 self.focus.clone()
720 }
721
722 fn area(&self) -> Rect {
723 Rect::default()
725 }
726
727 fn navigable(&self) -> Navigation {
728 Navigation::Leave
729 }
730}
731
732impl RelocatableState for SplitState {
733 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
734 if !self.relocate_split {
736 self.area = relocate_area(self.area, shift, clip);
737 self.inner = relocate_area(self.inner, shift, clip);
738 relocate_areas(self.widget_areas.as_mut_slice(), shift, clip);
739 relocate_areas(self.splitline_areas.as_mut_slice(), shift, clip);
740 relocate_positions(self.splitline_mark_position.as_mut_slice(), shift, clip);
741 }
742 }
743
744 fn relocate_popup(&mut self, shift: (i16, i16), clip: Rect) {
745 if self.relocate_split {
746 self.relocate_split = false;
747 self.area = relocate_area(self.area, shift, clip);
748 self.inner = relocate_area(self.inner, shift, clip);
749 relocate_areas(self.widget_areas.as_mut_slice(), shift, clip);
750 relocate_areas(self.splitline_areas.as_mut_slice(), shift, clip);
751 relocate_positions(self.splitline_mark_position.as_mut_slice(), shift, clip);
752 }
753 }
754}
755
756#[allow(clippy::len_without_is_empty)]
757impl SplitState {
758 pub fn new() -> Self {
760 Self::default()
761 }
762
763 pub fn named(name: &str) -> Self {
765 let mut z = Self::default();
766 z.focus = z.focus.with_name(name);
767 z
768 }
769
770 pub fn set_screen_split_pos(&mut self, n: usize, pos: (u16, u16)) -> bool {
777 if self.is_hidden(n) {
778 return false;
779 }
780 if self.direction == Direction::Horizontal {
781 let pos = if pos.0 < self.inner.left() {
782 0
783 } else if pos.0 < self.inner.right() {
784 pos.0 - self.inner.x
785 } else {
786 self.inner.width
787 };
788
789 let split_pos = self.split_pos(n);
790 self.set_split_pos(n, pos);
791
792 split_pos != self.split_pos(n)
793 } else {
794 let pos = if pos.1 < self.inner.top() {
795 0
796 } else if pos.1 < self.inner.bottom() {
797 pos.1 - self.inner.y
798 } else {
799 self.inner.height
800 };
801
802 let split_pos = self.split_pos(n);
803 self.set_split_pos(n, pos);
804
805 split_pos != self.split_pos(n)
806 }
807 }
808
809 pub fn move_split_left(&mut self, n: usize, delta: u16) -> bool {
813 let split_pos = self.split_pos(n);
814 self.set_split_pos(n, split_pos - delta);
815
816 split_pos != self.split_pos(n)
817 }
818
819 pub fn move_split_right(&mut self, n: usize, delta: u16) -> bool {
822 let split_pos = self.split_pos(n);
823 self.set_split_pos(n, split_pos + delta);
824
825 split_pos != self.split_pos(n)
826 }
827
828 pub fn move_split_up(&mut self, n: usize, delta: u16) -> bool {
831 self.move_split_left(n, delta)
832 }
833
834 pub fn move_split_down(&mut self, n: usize, delta: u16) -> bool {
837 self.move_split_right(n, delta)
838 }
839
840 pub fn select_next_split(&mut self) -> bool {
842 if self.is_focused() {
843 let n = self.focus_marker.unwrap_or_default();
844 if n + 1 >= self.area_length.len().saturating_sub(1) {
845 self.focus_marker = Some(0);
846 } else {
847 self.focus_marker = Some(n + 1);
848 }
849 true
850 } else {
851 false
852 }
853 }
854
855 pub fn select_prev_split(&mut self) -> bool {
857 if self.is_focused() {
858 let n = self.focus_marker.unwrap_or_default();
859 if n == 0 {
860 self.focus_marker =
861 Some(self.area_length.len().saturating_sub(1).saturating_sub(1));
862 } else {
863 self.focus_marker = Some(n - 1);
864 }
865 true
866 } else {
867 false
868 }
869 }
870
871 pub fn len(&self) -> usize {
873 self.area_length.len()
874 }
875
876 pub fn area_lengths(&self) -> &[u16] {
878 &self.area_length
879 }
880
881 pub fn set_area_lengths(&mut self, lengths: Vec<u16>) {
894 self.area_length = lengths;
895 while self.hidden_length.len() < self.area_length.len() {
896 self.hidden_length.push(0);
897 }
898 while self.hidden_length.len() > self.area_length.len() {
899 self.hidden_length.pop();
900 }
901 }
902
903 pub fn hidden_lengths(&self) -> &[u16] {
905 &self.hidden_length
906 }
907
908 pub fn set_hidden_lengths(&mut self, hidden: Vec<u16>) {
913 for i in 0..self.hidden_length.len() {
914 if let Some(v) = hidden.get(i) {
915 self.hidden_length[i] = *v;
916 } else {
917 self.hidden_length[i] = 0;
918 }
919 }
920 }
921
922 pub fn area_len(&self, n: usize) -> u16 {
932 if n >= self.area_length.len() {
933 return 0;
934 }
935 self.area_length[n]
936 }
937
938 pub fn total_area_len(&self) -> u16 {
940 self.area_length.iter().sum()
941 }
942
943 pub fn set_area_len(&mut self, n: usize, len: u16) {
976 if n >= self.area_length.len() {
977 return;
978 }
979 self.area_length[n] = len;
980 self.hidden_length[n] = 0;
981 }
982
983 pub fn split_pos(&self, n: usize) -> u16 {
995 if n + 1 >= self.area_length.len() {
996 return self.area_length.iter().sum();
997 }
998 self.area_length[..n + 1].iter().sum()
999 }
1000
1001 pub fn set_split_pos(&mut self, n: usize, pos: u16) {
1017 if n + 1 >= self.area_length.len() {
1018 return;
1019 }
1020
1021 match self.resize {
1022 SplitResize::Neighbours => {
1023 self.set_split_pos_neighbour(n, pos);
1024 }
1025 SplitResize::Full => {
1026 self.set_split_pos_full(n, pos);
1027 }
1028 }
1029 }
1030
1031 fn set_split_pos_neighbour(&mut self, n: usize, pos: u16) {
1034 assert!(n + 1 < self.area_length.len());
1035
1036 let mut pos_vec = Vec::new();
1038 let mut pp = 0;
1039 for len in &self.area_length {
1040 pp += *len;
1041 pos_vec.push(pp);
1042 }
1043 let pos_count = pos_vec.len();
1045
1046 let (min_pos, max_pos) = if n == 0 {
1047 if n + 2 >= pos_count {
1048 (SPLIT_WIDTH, pos_vec[n + 1])
1049 } else {
1050 (SPLIT_WIDTH, pos_vec[n + 1] - SPLIT_WIDTH)
1051 }
1052 } else if n + 2 < pos_count {
1053 (pos_vec[n - 1] + 1, pos_vec[n + 1] - SPLIT_WIDTH)
1054 } else {
1055 (pos_vec[n - 1] + 1, pos_vec[n + 1])
1056 };
1057
1058 pos_vec[n] = min(max(min_pos, pos), max_pos);
1059
1060 for i in 0..pos_vec.len() {
1062 if i > 0 {
1063 self.area_length[i] = pos_vec[i] - pos_vec[i - 1];
1064 } else {
1065 self.area_length[i] = pos_vec[i];
1066 }
1067 }
1068 }
1069
1070 #[allow(clippy::needless_range_loop)]
1073 #[allow(clippy::comparison_chain)]
1074 fn set_split_pos_full(&mut self, n: usize, pos: u16) {
1075 assert!(n + 1 < self.area_length.len());
1076
1077 let total_len = self.total_area_len();
1078
1079 let mut pos_vec = Vec::new();
1081 let mut pp = 0;
1082 for len in &self.area_length {
1083 pp += *len;
1084 pos_vec.push(pp);
1085 }
1086 pos_vec.pop();
1088 let pos_count = pos_vec.len();
1089
1090 let mut min_pos = SPLIT_WIDTH;
1091 for i in 0..pos_vec.len() {
1092 if i < n {
1093 if self.area_length[i] == 0 {
1094 pos_vec[i] = min_pos;
1095 } else if self.hidden_length[i] != 0 {
1096 pos_vec[i] = min_pos;
1097 min_pos += SPLIT_WIDTH;
1098 } else {
1099 if pos_vec[i] >= pos {
1100 let rest_area_count = n - (i + 1);
1102 let rest_area_width = rest_area_count as u16 * SPLIT_WIDTH;
1103 pos_vec[i] = max(
1105 min_pos,
1106 pos.saturating_sub(SPLIT_WIDTH)
1107 .saturating_sub(rest_area_width),
1108 );
1109 min_pos += SPLIT_WIDTH;
1110 } else {
1111 }
1113 }
1114 } else if i == n {
1115 let rest_area_count = pos_count - (i + 1);
1117 let rest_area_width = rest_area_count as u16 * SPLIT_WIDTH;
1118 let rest_len = total_len - (min_pos + 1);
1119 let rest_len = rest_len - rest_area_width;
1121 let rest_len = rest_len + SPLIT_WIDTH;
1123
1124 let max_pos = min_pos + rest_len;
1125
1126 pos_vec[i] = min(max(min_pos, pos), max_pos);
1127
1128 min_pos = pos_vec[i] + SPLIT_WIDTH;
1129 } else {
1130 if self.area_length[i] == 0 {
1131 pos_vec[i] = min_pos;
1132 } else if self.hidden_length[i] != 0 {
1133 pos_vec[i] = min_pos;
1134 min_pos += SPLIT_WIDTH;
1135 } else {
1136 if pos_vec[i] <= pos {
1137 pos_vec[i] = min_pos;
1138 min_pos += SPLIT_WIDTH;
1139 } else {
1140 }
1142 }
1143 }
1144 }
1145
1146 for i in 0..pos_vec.len() {
1148 if i > 0 {
1149 self.area_length[i] = pos_vec[i] - pos_vec[i - 1];
1150 } else {
1151 self.area_length[i] = pos_vec[i];
1152 }
1153 }
1154 self.area_length[pos_count] = total_len - pos_vec[pos_count - 1];
1155 }
1156
1157 pub fn is_hidden(&self, n: usize) -> bool {
1159 self.hidden_length[n] > 0
1160 }
1161
1162 pub fn hide_split(&mut self, n: usize) -> bool {
1166 if self.hidden_length[n] == 0 {
1167 let mut hide = if n + 1 == self.area_length.len() {
1168 self.area_length[n]
1169 } else {
1170 self.area_length[n].saturating_sub(SPLIT_WIDTH)
1171 };
1172 for idx in n + 1..self.area_length.len() {
1173 if self.hidden_length[idx] == 0 {
1174 self.area_length[idx] += hide;
1175 hide = 0;
1176 break;
1177 }
1178 }
1179 if hide > 0 {
1180 for idx in (0..n).rev() {
1181 if self.hidden_length[idx] == 0 {
1182 self.area_length[idx] += hide;
1183 hide = 0;
1184 break;
1185 }
1186 }
1187 }
1188
1189 if hide > 0 {
1190 self.hidden_length[n] = 0;
1192 false
1193 } else {
1194 if n + 1 == self.area_length.len() {
1195 self.hidden_length[n] = self.area_length[n];
1196 self.area_length[n] = 0;
1197 } else {
1198 self.hidden_length[n] = self.area_length[n].saturating_sub(SPLIT_WIDTH);
1199 self.area_length[n] = 1;
1200 };
1201 true
1202 }
1203 } else {
1204 false
1205 }
1206 }
1207
1208 pub fn show_split(&mut self, n: usize) -> bool {
1212 let mut show = self.hidden_length[n];
1213 if show > 0 {
1214 for idx in n + 1..self.area_length.len() {
1215 if self.hidden_length[idx] == 0 {
1216 if self.area_length[idx] > show + SPLIT_WIDTH {
1218 self.area_length[idx] -= show;
1219 show = 0;
1220 } else if self.area_length[idx] > SPLIT_WIDTH {
1221 show -= self.area_length[idx] - SPLIT_WIDTH;
1222 self.area_length[idx] = SPLIT_WIDTH;
1223 }
1224 if show == 0 {
1225 break;
1226 }
1227 }
1228 }
1229 if show > 0 {
1230 for idx in (0..n).rev() {
1231 if self.hidden_length[idx] == 0 {
1232 if self.area_length[idx] > show + SPLIT_WIDTH {
1233 self.area_length[idx] -= show;
1234 show = 0;
1235 } else if self.area_length[idx] > SPLIT_WIDTH {
1236 show -= self.area_length[idx] - SPLIT_WIDTH;
1237 self.area_length[idx] = SPLIT_WIDTH;
1238 }
1239 if show == 0 {
1240 break;
1241 }
1242 }
1243 }
1244 }
1245
1246 self.area_length[n] += self.hidden_length[n] - show;
1247 self.hidden_length[n] = 0;
1248 true
1249 } else {
1250 false
1251 }
1252 }
1253}
1254
1255impl HandleEvent<crossterm::event::Event, Regular, Outcome> for SplitState {
1256 fn handle(&mut self, event: &crossterm::event::Event, _qualifier: Regular) -> Outcome {
1257 event_flow!(
1258 return if self.is_focused() {
1259 if let Some(n) = self.focus_marker {
1260 match event {
1261 ct_event!(keycode press Left) => self.select_prev_split().into(),
1262 ct_event!(keycode press Right) => self.select_next_split().into(),
1263 ct_event!(keycode press Up) => self.select_prev_split().into(),
1264 ct_event!(keycode press Down) => self.select_next_split().into(),
1265
1266 ct_event!(keycode press CONTROL-Left) => self.move_split_left(n, 1).into(),
1267 ct_event!(keycode press CONTROL-Right) => {
1268 self.move_split_right(n, 1).into()
1269 }
1270 ct_event!(keycode press CONTROL-Up) => self.move_split_up(n, 1).into(),
1271 ct_event!(keycode press CONTROL-Down) => self.move_split_down(n, 1).into(),
1272 _ => Outcome::Continue,
1273 }
1274 } else {
1275 Outcome::Continue
1276 }
1277 } else {
1278 Outcome::Continue
1279 }
1280 );
1281
1282 self.handle(event, MouseOnly)
1283 }
1284}
1285
1286impl HandleEvent<crossterm::event::Event, MouseOnly, Outcome> for SplitState {
1287 fn handle(&mut self, event: &crossterm::event::Event, _qualifier: MouseOnly) -> Outcome {
1288 match event {
1289 ct_event!(mouse any for m) if self.mouse.hover(&self.splitline_areas, m) => {
1290 Outcome::Changed
1291 }
1292 ct_event!(mouse any for m) => {
1293 let was_drag = self.mouse.drag.get();
1294 if self.mouse.drag(&self.splitline_areas, m) {
1295 if let Some(n) = self.mouse.drag.get() {
1296 self.set_screen_split_pos(n, self.mouse.pos_of(m)).into()
1297 } else {
1298 Outcome::Continue
1299 }
1300 } else {
1301 if was_drag.is_some() {
1303 Outcome::Changed
1304 } else {
1305 Outcome::Continue
1306 }
1307 }
1308 }
1309 _ => Outcome::Continue,
1310 }
1311 }
1312}
1313
1314pub fn handle_events(
1318 state: &mut SplitState,
1319 focus: bool,
1320 event: &crossterm::event::Event,
1321) -> Outcome {
1322 state.focus.set(focus);
1323 HandleEvent::handle(state, event, Regular)
1324}
1325
1326pub fn handle_mouse_events(state: &mut SplitState, event: &crossterm::event::Event) -> Outcome {
1328 HandleEvent::handle(state, event, MouseOnly)
1329}