feat(wm): add opt to keep focused column centered on scrolling layout

This commit adds a new option under layout_options.scrolling -
"center_focused_column", which defaults to false. When

set to true, and when the number of scrolling columns is an odd number
>=3, komorebi will, if there are enough windows being managed on the
workspace, and if the focused window is not too close to either the
beginning or the end of the workspace ring, keep the focused window in a
centered position in the layout
This commit is contained in:
LGUG2Z
2025-10-10 17:33:51 -07:00
parent e33a5f28f0
commit 2ac1929117
4 changed files with 41 additions and 16 deletions

View File

@@ -78,6 +78,13 @@ impl Arrangement for DefaultLayout {
// treat >= column_count as scrolling
len => {
let visible_columns = area.right / column_width;
let keep_centered = layout_options
.and_then(|o| {
o.scrolling
.map(|s| s.center_focused_column.unwrap_or_default())
})
.unwrap_or(false);
let first_visible: isize = if focused_idx == 0 {
// if focused idx is 0, we are at the beginning of the scrolling strip
0
@@ -95,24 +102,35 @@ impl Arrangement for DefaultLayout {
let focused_idx = focused_idx as isize;
if focused_idx < previous_first_visible {
// focused window is off the left edge, we need to scroll left
focused_idx
} else if focused_idx
>= previous_first_visible + visible_columns as isize
{
// focused window is off the right edge, we need to scroll right
// and make sure it's the last visible window
(focused_idx + 1 - visible_columns as isize).max(0)
// if center_focused_column is enabled, and we have an odd number of visible columns,
// center the focused window column
if keep_centered && visible_columns % 2 == 1 {
let center_offset = visible_columns as isize / 2;
(focused_idx - center_offset).max(0).min(
(len as isize)
.saturating_sub(visible_columns as isize)
.max(0),
)
} else {
// focused window is already visible, we don't need to scroll
previous_first_visible
if focused_idx < previous_first_visible {
// focused window is off the left edge, we need to scroll left
focused_idx
} else if focused_idx
>= previous_first_visible + visible_columns as isize
{
// focused window is off the right edge, we need to scroll right
// and make sure it's the last visible window
(focused_idx + 1 - visible_columns as isize).max(0)
} else {
// focused window is already visible, we don't need to scroll
previous_first_visible
}
.min(
(len as isize)
.saturating_sub(visible_columns as isize)
.max(0),
)
}
.min(
(len as isize)
.saturating_sub(visible_columns as isize)
.max(0),
)
};
for i in 0..len {

View File

@@ -37,6 +37,8 @@ pub struct LayoutOptions {
pub struct ScrollingLayoutOptions {
/// Desired number of visible columns (default: 3)
pub columns: usize,
/// With an odd number of visible columns, keep the focused window column centered
pub center_focused_column: Option<bool>,
}
impl DefaultLayout {

View File

@@ -921,6 +921,7 @@ impl WindowManager {
None => LayoutOptions {
scrolling: Some(ScrollingLayoutOptions {
columns: count.into(),
center_focused_column: Default::default(),
}),
},
};

View File

@@ -1814,6 +1814,10 @@
"columns"
],
"properties": {
"center_focused_column": {
"description": "With an odd number of visible columns, keep the focused window column centered",
"type": "boolean"
},
"columns": {
"description": "Desired number of visible columns (default: 3)",
"type": "integer",