mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-04 20:21:35 +02:00
feat(wm): add grid layout
Based on the Grid layout on LeftWM Co-authored-by: LGUG2Z <LGUG2Z@fastmail.com>
This commit is contained in:
@@ -131,6 +131,42 @@ impl Arrangement for DefaultLayout {
|
|||||||
layouts
|
layouts
|
||||||
}
|
}
|
||||||
Self::UltrawideVerticalStack => ultrawide(area, len, layout_flip, resize_dimensions),
|
Self::UltrawideVerticalStack => ultrawide(area, len, layout_flip, resize_dimensions),
|
||||||
|
Self::Grid => {
|
||||||
|
// Shamelessly lifted from LeftWM
|
||||||
|
// https://github.com/leftwm/leftwm/blob/18675067b8450e520ef75db2ebbb0d973aa1199e/leftwm-core/src/layouts/grid_horizontal.rs
|
||||||
|
let mut layouts: Vec<Rect> = vec![];
|
||||||
|
layouts.resize(len, Rect::default());
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let len = len as i32;
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let num_cols = (len as f32).sqrt().ceil() as i32;
|
||||||
|
let mut iter = layouts.iter_mut().enumerate().peekable();
|
||||||
|
|
||||||
|
for col in 0..num_cols {
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let iter_peek = iter.peek().map(|x| x.0).unwrap_or_default() as i32;
|
||||||
|
let remaining_windows = len - iter_peek;
|
||||||
|
let remaining_columns = num_cols - col;
|
||||||
|
let num_rows_in_this_col = remaining_windows / remaining_columns;
|
||||||
|
|
||||||
|
let win_height = area.bottom / num_rows_in_this_col;
|
||||||
|
let win_width = area.right / num_cols;
|
||||||
|
|
||||||
|
for row in 0..num_rows_in_this_col {
|
||||||
|
if let Some((_idx, win)) = iter.next() {
|
||||||
|
win.bottom = win_height;
|
||||||
|
win.right = win_width;
|
||||||
|
|
||||||
|
win.left = area.left + win_width * col;
|
||||||
|
win.top = area.top + win_height * row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layouts
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
dimensions
|
dimensions
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub enum DefaultLayout {
|
|||||||
VerticalStack,
|
VerticalStack,
|
||||||
HorizontalStack,
|
HorizontalStack,
|
||||||
UltrawideVerticalStack,
|
UltrawideVerticalStack,
|
||||||
|
Grid,
|
||||||
// NOTE: If any new layout is added, please make sure to register the same in `DefaultLayout::cycle`
|
// NOTE: If any new layout is added, please make sure to register the same in `DefaultLayout::cycle`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +136,8 @@ impl DefaultLayout {
|
|||||||
Self::Rows => Self::VerticalStack,
|
Self::Rows => Self::VerticalStack,
|
||||||
Self::VerticalStack => Self::HorizontalStack,
|
Self::VerticalStack => Self::HorizontalStack,
|
||||||
Self::HorizontalStack => Self::UltrawideVerticalStack,
|
Self::HorizontalStack => Self::UltrawideVerticalStack,
|
||||||
Self::UltrawideVerticalStack => Self::BSP,
|
Self::UltrawideVerticalStack => Self::Grid,
|
||||||
|
Self::Grid => Self::BSP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +149,8 @@ impl DefaultLayout {
|
|||||||
Self::HorizontalStack => Self::VerticalStack,
|
Self::HorizontalStack => Self::VerticalStack,
|
||||||
Self::VerticalStack => Self::Rows,
|
Self::VerticalStack => Self::Rows,
|
||||||
Self::Rows => Self::Columns,
|
Self::Rows => Self::Columns,
|
||||||
Self::Columns => Self::BSP,
|
Self::Columns => Self::Grid,
|
||||||
|
Self::Grid => Self::BSP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+126
-20
@@ -19,10 +19,10 @@ pub trait Direction {
|
|||||||
idx: usize,
|
idx: usize,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
fn up_index(&self, idx: usize) -> usize;
|
fn up_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize;
|
||||||
fn down_index(&self, idx: usize) -> usize;
|
fn down_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize;
|
||||||
fn left_index(&self, idx: usize) -> usize;
|
fn left_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize;
|
||||||
fn right_index(&self, idx: usize) -> usize;
|
fn right_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Direction for DefaultLayout {
|
impl Direction for DefaultLayout {
|
||||||
@@ -35,28 +35,28 @@ impl Direction for DefaultLayout {
|
|||||||
match op_direction {
|
match op_direction {
|
||||||
OperationDirection::Left => {
|
OperationDirection::Left => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.left_index(idx))
|
Option::from(self.left_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperationDirection::Right => {
|
OperationDirection::Right => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.right_index(idx))
|
Option::from(self.right_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperationDirection::Up => {
|
OperationDirection::Up => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.up_index(idx))
|
Option::from(self.up_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperationDirection::Down => {
|
OperationDirection::Down => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.down_index(idx))
|
Option::from(self.down_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -77,6 +77,7 @@ impl Direction for DefaultLayout {
|
|||||||
Self::Rows | Self::HorizontalStack => idx != 0,
|
Self::Rows | Self::HorizontalStack => idx != 0,
|
||||||
Self::VerticalStack => idx != 0 && idx != 1,
|
Self::VerticalStack => idx != 0 && idx != 1,
|
||||||
Self::UltrawideVerticalStack => idx > 2,
|
Self::UltrawideVerticalStack => idx > 2,
|
||||||
|
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||||
},
|
},
|
||||||
OperationDirection::Down => match self {
|
OperationDirection::Down => match self {
|
||||||
Self::BSP => count > 2 && idx != count - 1 && idx % 2 != 0,
|
Self::BSP => count > 2 && idx != count - 1 && idx % 2 != 0,
|
||||||
@@ -85,6 +86,7 @@ impl Direction for DefaultLayout {
|
|||||||
Self::VerticalStack => idx != 0 && idx != count - 1,
|
Self::VerticalStack => idx != 0 && idx != count - 1,
|
||||||
Self::HorizontalStack => idx == 0,
|
Self::HorizontalStack => idx == 0,
|
||||||
Self::UltrawideVerticalStack => idx > 1 && idx != count - 1,
|
Self::UltrawideVerticalStack => idx > 1 && idx != count - 1,
|
||||||
|
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||||
},
|
},
|
||||||
OperationDirection::Left => match self {
|
OperationDirection::Left => match self {
|
||||||
Self::BSP => count > 1 && idx != 0,
|
Self::BSP => count > 1 && idx != 0,
|
||||||
@@ -92,6 +94,7 @@ impl Direction for DefaultLayout {
|
|||||||
Self::Rows => false,
|
Self::Rows => false,
|
||||||
Self::HorizontalStack => idx != 0 && idx != 1,
|
Self::HorizontalStack => idx != 0 && idx != 1,
|
||||||
Self::UltrawideVerticalStack => count > 1 && idx != 1,
|
Self::UltrawideVerticalStack => count > 1 && idx != 1,
|
||||||
|
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||||
},
|
},
|
||||||
OperationDirection::Right => match self {
|
OperationDirection::Right => match self {
|
||||||
Self::BSP => count > 1 && idx % 2 == 0 && idx != count - 1,
|
Self::BSP => count > 1 && idx % 2 == 0 && idx != count - 1,
|
||||||
@@ -104,11 +107,12 @@ impl Direction for DefaultLayout {
|
|||||||
2 => idx != 0,
|
2 => idx != 0,
|
||||||
_ => idx < 2,
|
_ => idx < 2,
|
||||||
},
|
},
|
||||||
|
Self::Grid => !is_grid_edge(op_direction, idx, count),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up_index(&self, idx: usize) -> usize {
|
fn up_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::BSP => {
|
Self::BSP => {
|
||||||
if idx % 2 == 0 {
|
if idx % 2 == 0 {
|
||||||
@@ -120,18 +124,20 @@ impl Direction for DefaultLayout {
|
|||||||
Self::Columns => unreachable!(),
|
Self::Columns => unreachable!(),
|
||||||
Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx - 1,
|
Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx - 1,
|
||||||
Self::HorizontalStack => 0,
|
Self::HorizontalStack => 0,
|
||||||
|
Self::Grid => grid_neighbor(op_direction, idx, count),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn down_index(&self, idx: usize) -> usize {
|
fn down_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::BSP | Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx + 1,
|
Self::BSP | Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx + 1,
|
||||||
Self::Columns => unreachable!(),
|
Self::Columns => unreachable!(),
|
||||||
Self::HorizontalStack => 1,
|
Self::HorizontalStack => 1,
|
||||||
|
Self::Grid => grid_neighbor(op_direction, idx, count),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn left_index(&self, idx: usize) -> usize {
|
fn left_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::BSP => {
|
Self::BSP => {
|
||||||
if idx % 2 == 0 {
|
if idx % 2 == 0 {
|
||||||
@@ -148,10 +154,11 @@ impl Direction for DefaultLayout {
|
|||||||
1 => unreachable!(),
|
1 => unreachable!(),
|
||||||
_ => 0,
|
_ => 0,
|
||||||
},
|
},
|
||||||
|
Self::Grid => grid_neighbor(op_direction, idx, count),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn right_index(&self, idx: usize) -> usize {
|
fn right_index(&self, op_direction: OperationDirection, idx: usize, count: usize) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::BSP | Self::Columns | Self::HorizontalStack => idx + 1,
|
Self::BSP | Self::Columns | Self::HorizontalStack => idx + 1,
|
||||||
Self::Rows => unreachable!(),
|
Self::Rows => unreachable!(),
|
||||||
@@ -161,10 +168,109 @@ impl Direction for DefaultLayout {
|
|||||||
0 => 2,
|
0 => 2,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
|
Self::Grid => grid_neighbor(op_direction, idx, count),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GridItem {
|
||||||
|
state: GridItemState,
|
||||||
|
row: usize,
|
||||||
|
num_rows: usize,
|
||||||
|
touching_edges: GridTouchingEdges,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GridItemState {
|
||||||
|
Valid,
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GridTouchingEdges {
|
||||||
|
left: bool,
|
||||||
|
right: bool,
|
||||||
|
up: bool,
|
||||||
|
down: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_grid_item(idx: usize, count: usize) -> GridItem {
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
let num_cols = (count as f32).sqrt().ceil() as usize;
|
||||||
|
let mut iter = 0;
|
||||||
|
|
||||||
|
for col in 0..num_cols {
|
||||||
|
let remaining_windows = count - iter;
|
||||||
|
let remaining_columns = num_cols - col;
|
||||||
|
let num_rows_in_this_col = remaining_windows / remaining_columns;
|
||||||
|
|
||||||
|
for row in 0..num_rows_in_this_col {
|
||||||
|
if iter == idx {
|
||||||
|
return GridItem {
|
||||||
|
state: GridItemState::Valid,
|
||||||
|
row: row + 1,
|
||||||
|
num_rows: num_rows_in_this_col,
|
||||||
|
touching_edges: GridTouchingEdges {
|
||||||
|
left: col == 0,
|
||||||
|
right: col == num_cols - 1,
|
||||||
|
up: row == 0,
|
||||||
|
down: row == num_rows_in_this_col - 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
iter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GridItem {
|
||||||
|
state: GridItemState::Invalid,
|
||||||
|
row: 0,
|
||||||
|
num_rows: 0,
|
||||||
|
touching_edges: GridTouchingEdges {
|
||||||
|
left: true,
|
||||||
|
right: true,
|
||||||
|
up: true,
|
||||||
|
down: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_grid_edge(op_direction: OperationDirection, idx: usize, count: usize) -> bool {
|
||||||
|
let item = get_grid_item(idx, count);
|
||||||
|
|
||||||
|
match item.state {
|
||||||
|
GridItemState::Invalid => false,
|
||||||
|
GridItemState::Valid => match op_direction {
|
||||||
|
OperationDirection::Left => item.touching_edges.left,
|
||||||
|
OperationDirection::Right => item.touching_edges.right,
|
||||||
|
OperationDirection::Up => item.touching_edges.up,
|
||||||
|
OperationDirection::Down => item.touching_edges.down,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grid_neighbor(op_direction: OperationDirection, idx: usize, count: usize) -> usize {
|
||||||
|
let item = get_grid_item(idx, count);
|
||||||
|
|
||||||
|
match op_direction {
|
||||||
|
OperationDirection::Left => {
|
||||||
|
let item_from_prev_col = get_grid_item(idx - item.row, count);
|
||||||
|
|
||||||
|
if item.touching_edges.up && item.num_rows != item_from_prev_col.num_rows {
|
||||||
|
return idx - (item.num_rows - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.num_rows != item_from_prev_col.num_rows && !item.touching_edges.down {
|
||||||
|
return idx - (item.num_rows - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
idx - item.num_rows
|
||||||
|
}
|
||||||
|
OperationDirection::Right => idx + item.num_rows,
|
||||||
|
OperationDirection::Up => idx - 1,
|
||||||
|
OperationDirection::Down => idx + 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Direction for CustomLayout {
|
impl Direction for CustomLayout {
|
||||||
fn index_in_direction(
|
fn index_in_direction(
|
||||||
&self,
|
&self,
|
||||||
@@ -179,28 +285,28 @@ impl Direction for CustomLayout {
|
|||||||
match op_direction {
|
match op_direction {
|
||||||
OperationDirection::Left => {
|
OperationDirection::Left => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.left_index(idx))
|
Option::from(self.left_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperationDirection::Right => {
|
OperationDirection::Right => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.right_index(idx))
|
Option::from(self.right_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperationDirection::Up => {
|
OperationDirection::Up => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.up_index(idx))
|
Option::from(self.up_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperationDirection::Down => {
|
OperationDirection::Down => {
|
||||||
if self.is_valid_direction(op_direction, idx, count) {
|
if self.is_valid_direction(op_direction, idx, count) {
|
||||||
Option::from(self.down_index(idx))
|
Option::from(self.down_index(op_direction, idx, count))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -254,15 +360,15 @@ impl Direction for CustomLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn up_index(&self, idx: usize) -> usize {
|
fn up_index(&self, _op_direction: OperationDirection, idx: usize, _count: usize) -> usize {
|
||||||
idx - 1
|
idx - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn down_index(&self, idx: usize) -> usize {
|
fn down_index(&self, _op_direction: OperationDirection, idx: usize, _count: usize) -> usize {
|
||||||
idx + 1
|
idx + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn left_index(&self, idx: usize) -> usize {
|
fn left_index(&self, _op_direction: OperationDirection, idx: usize, _count: usize) -> usize {
|
||||||
let column_idx = self.column_for_container_idx(idx);
|
let column_idx = self.column_for_container_idx(idx);
|
||||||
if column_idx - 1 == 0 {
|
if column_idx - 1 == 0 {
|
||||||
0
|
0
|
||||||
@@ -271,7 +377,7 @@ impl Direction for CustomLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn right_index(&self, idx: usize) -> usize {
|
fn right_index(&self, _op_direction: OperationDirection, idx: usize, _count: usize) -> usize {
|
||||||
let column_idx = self.column_for_container_idx(idx);
|
let column_idx = self.column_for_container_idx(idx);
|
||||||
self.first_container_idx(column_idx + 1)
|
self.first_container_idx(column_idx + 1)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user