@@ -12,15 +12,20 @@ use super::custom_layout::ColumnSplitWithCapacity;
1212use super::CustomLayout;
1313use super::DefaultLayout;
1414use super::Rect;
15+use crate::default_layout::LayoutOptions;
15161617pub trait Arrangement {
18+#[allow(clippy::too_many_arguments)]
1719fn calculate(
1820&self,
1921area: &Rect,
2022len: NonZeroUsize,
2123container_padding: Option<i32>,
2224layout_flip: Option<Axis>,
2325resize_dimensions: &[Option<Rect>],
26+focused_idx: usize,
27+layout_options: Option<LayoutOptions>,
28+latest_layout: &[Rect],
2429) -> Vec<Rect>;
2530}
2631@@ -33,9 +38,110 @@ impl Arrangement for DefaultLayout {
3338container_padding: Option<i32>,
3439layout_flip: Option<Axis>,
3540resize_dimensions: &[Option<Rect>],
41+focused_idx: usize,
42+layout_options: Option<LayoutOptions>,
43+latest_layout: &[Rect],
3644) -> Vec<Rect> {
3745let len = usize::from(len);
3846let mut dimensions = match self {
47+Self::Scrolling => {
48+let column_count = layout_options
49+.and_then(|o| o.scrolling.map(|s| s.columns))
50+.unwrap_or(3);
51+52+let column_width = area.right / column_count as i32;
53+let mut layouts = Vec::with_capacity(len);
54+55+match len {
56+// treat < 3 windows the same as the columns layout
57+ len if len < 3 => {
58+ layouts = columns(area, len);
59+60+let adjustment = calculate_columns_adjustment(resize_dimensions);
61+ layouts.iter_mut().zip(adjustment.iter()).for_each(
62+ |(layout, adjustment)| {
63+ layout.top += adjustment.top;
64+ layout.bottom += adjustment.bottom;
65+ layout.left += adjustment.left;
66+ layout.right += adjustment.right;
67+},
68+);
69+70+if matches!(
71+ layout_flip,
72+Some(Axis::Horizontal | Axis::HorizontalAndVertical)
73+) {
74+if let 2.. = len {
75+columns_reverse(&mut layouts);
76+}
77+}
78+}
79+// treat >= column_count as scrolling
80+ len => {
81+let visible_columns = area.right / column_width;
82+let first_visible: isize = if focused_idx == 0 {
83+// if focused idx is 0, we are at the beginning of the scrolling strip
84+0
85+} else {
86+let previous_first_visible = if latest_layout.is_empty() {
87+0
88+} else {
89+// previous first_visible based on the left position of the first visible window
90+let left_edge = area.left;
91+ latest_layout
92+.iter()
93+.position(|rect| rect.left >= left_edge)
94+.unwrap_or(0) as isize
95+};
96+97+let focused_idx = focused_idx as isize;
98+99+if focused_idx < previous_first_visible {
100+// focused window is off the left edge, we need to scroll left
101+ focused_idx
102+} else if focused_idx
103+ >= previous_first_visible + visible_columns as isize
104+{
105+// focused window is off the right edge, we need to scroll right
106+// and make sure it's the last visible window
107+(focused_idx + 1 - visible_columns as isize).max(0)
108+} else {
109+// focused window is already visible, we don't need to scroll
110+ previous_first_visible
111+}
112+.min(
113+(len as isize)
114+.saturating_sub(visible_columns as isize)
115+.max(0),
116+)
117+};
118+119+for i in 0..len {
120+let position = (i as isize) - first_visible;
121+let left = area.left + (position as i32 * column_width);
122+123+ layouts.push(Rect {
124+ left,
125+top: area.top,
126+right: column_width,
127+bottom: area.bottom,
128+});
129+}
130+131+let adjustment = calculate_scrolling_adjustment(resize_dimensions);
132+ layouts.iter_mut().zip(adjustment.iter()).for_each(
133+ |(layout, adjustment)| {
134+ layout.top += adjustment.top;
135+ layout.bottom += adjustment.bottom;
136+ layout.left += adjustment.left;
137+ layout.right += adjustment.right;
138+},
139+);
140+}
141+}
142+143+ layouts
144+}
39145Self::BSP => recursive_fibonacci(
401460,
41147 len,
@@ -487,6 +593,9 @@ impl Arrangement for CustomLayout {
487593container_padding: Option<i32>,
488594_layout_flip: Option<Axis>,
489595_resize_dimensions: &[Option<Rect>],
596+_focused_idx: usize,
597+_layout_options: Option<LayoutOptions>,
598+_latest_layout: &[Rect],
490599) -> Vec<Rect> {
491600let mut dimensions = vec![];
492601let container_count = len.get();
@@ -541,7 +650,7 @@ impl Arrangement for CustomLayout {
541650};
542651543652match column {
544-Column::Primary(Option::Some(_)) => {
653+Column::Primary(Some(_)) => {
545654let main_column_area = if idx == 0 {
546655Self::main_column_area(area, primary_right, None)
547656} else {
@@ -1115,6 +1224,37 @@ fn calculate_ultrawide_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rec
11151224 result
11161225}
111712261227+fn calculate_scrolling_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
1228+let len = resize_dimensions.len();
1229+let mut result = vec![Rect::default(); len];
1230+1231+if len <= 1 {
1232+return result;
1233+}
1234+1235+for (i, rect) in resize_dimensions.iter().enumerate() {
1236+if let Some(rect) = rect {
1237+let is_leftmost = i == 0;
1238+let is_rightmost = i == len - 1;
1239+1240+resize_left(&mut result[i], rect.left);
1241+resize_right(&mut result[i], rect.right);
1242+resize_top(&mut result[i], rect.top);
1243+resize_bottom(&mut result[i], rect.bottom);
1244+1245+if !is_leftmost && rect.left != 0 {
1246+resize_right(&mut result[i - 1], rect.left);
1247+}
1248+1249+if !is_rightmost && rect.right != 0 {
1250+resize_left(&mut result[i + 1], rect.right);
1251+}
1252+}
1253+}
1254+1255+ result
1256+}
1257+11181258fn resize_left(rect: &mut Rect, resize: i32) {
11191259 rect.left += resize / 2;
11201260 rect.right += -resize / 2;