mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-13 12:23:38 +01:00
feat(scrolling): add commands and config for the scrolling layout
Focus, move, resize, retile and closing a window now go through the strip of columns in the Scrolling layout. New commands: consume, expel, toggle-column-stack, scrolling-layout-full-width and center-focus. A top level scrolling section configures centering, centring a lone column, and the minimum height of a window in a column of several.
This commit is contained in:
1 parent
8c7327fd31
commit
598390d9cb
5 files changed
+102
-46
No files matched your search
@@ -41,6 +41,7 @@ pub use komorebi_layouts::OperationDirection;
|
||||
pub use komorebi_layouts::Rect;
|
||||
pub use komorebi_layouts::ScrollingLayoutOptions;
|
||||
pub use komorebi_layouts::Sizing;
|
||||
pub use komorebi_layouts::scrolling::ScrollingCentering;
|
||||
pub use komorebi_layouts::validate_ratios;
|
||||
|
||||
// Local modules and exports
|
||||
@@ -125,6 +126,12 @@ pub enum SocketMessage {
|
||||
CycleLayout(CycleDirection),
|
||||
LayoutRatios(Option<Vec<f32>>, Option<Vec<f32>>),
|
||||
ScrollingLayoutColumns(NonZeroUsize),
|
||||
ScrollingLayoutFullWidth,
|
||||
CenterFocus,
|
||||
Expand,
|
||||
Consume(OperationDirection),
|
||||
Expel,
|
||||
ToggleColumnStack,
|
||||
ChangeLayoutCustom(#[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||
FlipLayout(Axis),
|
||||
ToggleWorkspaceWindowContainerBehaviour,
|
||||
|
||||
@@ -64,7 +64,6 @@ use crate::core::MonocleFocusBehaviour;
|
||||
use crate::core::MoveBehaviour;
|
||||
use crate::core::OperationDirection;
|
||||
use crate::core::Rect;
|
||||
use crate::core::ScrollingLayoutOptions;
|
||||
use crate::core::Sizing;
|
||||
use crate::core::SocketMessage;
|
||||
use crate::core::StateQuery;
|
||||
@@ -900,28 +899,33 @@ impl WindowManager {
|
||||
}
|
||||
SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?,
|
||||
SocketMessage::ScrollingLayoutColumns(count) => {
|
||||
let focused_workspace = self.focused_workspace_mut()?;
|
||||
|
||||
let options = match focused_workspace.layout_options {
|
||||
Some(mut opts) => {
|
||||
if let Some(scrolling) = &mut opts.scrolling {
|
||||
scrolling.columns = count.into();
|
||||
self.focused_workspace_mut()?
|
||||
.set_scrolling_columns(count.into());
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
|
||||
opts
|
||||
SocketMessage::ScrollingLayoutFullWidth => {
|
||||
self.focused_workspace_mut()?.toggle_scrolling_full_width();
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
None => LayoutOptions {
|
||||
scrolling: Some(ScrollingLayoutOptions {
|
||||
columns: count.into(),
|
||||
center_focused_column: Default::default(),
|
||||
}),
|
||||
grid: None,
|
||||
column_ratios: None,
|
||||
row_ratios: None,
|
||||
},
|
||||
};
|
||||
|
||||
focused_workspace.layout_options = Some(options);
|
||||
SocketMessage::CenterFocus => {
|
||||
self.focused_workspace_mut()?.center_scrolling_column();
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::Expand => {
|
||||
self.focused_workspace_mut()?.expand_scrolling_column();
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::Consume(direction) => {
|
||||
self.focused_workspace_mut()?.consume_scrolling(direction);
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::ToggleColumnStack => {
|
||||
self.focused_workspace_mut()?
|
||||
.toggle_scrolling_column_stack()?;
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::Expel => {
|
||||
self.focused_workspace_mut()?.expel_scrolling();
|
||||
self.update_focused_workspace(false, false)?;
|
||||
}
|
||||
SocketMessage::ChangeLayout(layout) => self.change_workspace_layout_default(layout)?,
|
||||
|
||||
@@ -771,6 +771,10 @@ impl WindowManager {
|
||||
// Reset any resize adjustments if we want to force a retile
|
||||
if !preserve_resize_dimensions {
|
||||
workspace.resize_dimensions.fill(None);
|
||||
|
||||
// and the widths and heights of the Scrolling layout, which are resize
|
||||
// adjustments too
|
||||
workspace.reset_scrolling_sizes();
|
||||
}
|
||||
|
||||
if (workspace.wallpaper.is_some() || monitor_wp.is_some())
|
||||
@@ -1271,6 +1275,16 @@ impl WindowManager {
|
||||
}
|
||||
WorkspaceLayer::Tiling => {
|
||||
match workspace.layout {
|
||||
Layout::Default(DefaultLayout::Scrolling) => {
|
||||
tracing::info!("resizing column");
|
||||
workspace.resize_scrolling_column(direction, sizing, delta);
|
||||
|
||||
return if update {
|
||||
self.update_focused_workspace(false, false)
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
Layout::Default(layout) => {
|
||||
tracing::info!("resizing window");
|
||||
let len = NonZeroUsize::new(workspace.containers().len())
|
||||
@@ -2608,10 +2622,15 @@ impl WindowManager {
|
||||
}
|
||||
Some(new_idx) => {
|
||||
let workspace = self.focused_workspace_mut()?;
|
||||
|
||||
// a column of the Scrolling layout moves whole, and its tiles move within it,
|
||||
// which is not a swap of two containers
|
||||
if !(workspace.is_scrolling() && workspace.move_scrolling(direction)) {
|
||||
workspace.swap_containers(origin_container_idx, new_idx);
|
||||
workspace.focus_container(new_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.update_focused_workspace(self.mouse_follows_focus, true)?;
|
||||
|
||||
|
||||
+15
-25
@@ -1064,6 +1064,9 @@ impl Workspace {
|
||||
// this fn respects locked container indexes - we should use it for pretty much everything
|
||||
// except monocle and maximize toggles
|
||||
pub fn remove_container_by_idx(&mut self, idx: usize) -> Option<Container> {
|
||||
// wherever it goes next, it goes as wide as it was
|
||||
self.note_scrolling_departure(idx);
|
||||
|
||||
let container = self.containers_mut().remove_respecting_locks(idx);
|
||||
|
||||
if idx < self.resize_dimensions.len() {
|
||||
@@ -1143,8 +1146,12 @@ impl Workspace {
|
||||
.ok_or_eyre("there is no window")?;
|
||||
|
||||
if container.windows().is_empty() {
|
||||
let container_id = container.id.clone();
|
||||
self.remove_container_by_idx(container_idx);
|
||||
|
||||
if !self.focus_after_scrolling_removal(&container_id) {
|
||||
self.focus_previous_container();
|
||||
}
|
||||
} else {
|
||||
container.load_focused_window();
|
||||
if let Some(window) = container.focused_window() {
|
||||
@@ -1183,6 +1190,12 @@ impl Workspace {
|
||||
}
|
||||
|
||||
pub fn new_idx_for_direction(&self, direction: OperationDirection) -> Option<usize> {
|
||||
// in a strip, left and right are the neighbouring columns and up and down are the tiles of
|
||||
// the column, which the strip is the one to say
|
||||
if self.is_scrolling() && self.scrolling.is_some() {
|
||||
return self.scrolling_idx_for_direction(direction);
|
||||
}
|
||||
|
||||
let len = NonZeroUsize::new(self.containers().len())?;
|
||||
|
||||
direction.destination(
|
||||
@@ -1288,6 +1301,8 @@ impl Workspace {
|
||||
next
|
||||
} else if self.containers().is_empty() {
|
||||
0
|
||||
} else if let Some(idx) = self.scrolling_insertion_idx() {
|
||||
idx
|
||||
} else {
|
||||
self.resolve_placement_index(&window)
|
||||
};
|
||||
@@ -1475,9 +1490,6 @@ impl Workspace {
|
||||
Layout::Default(DefaultLayout::UltrawideVerticalStack) => {
|
||||
self.enforce_resize_for_ultrawide();
|
||||
}
|
||||
Layout::Default(DefaultLayout::Scrolling) => {
|
||||
self.enforce_resize_for_scrolling();
|
||||
}
|
||||
_ => self.enforce_no_resize(),
|
||||
}
|
||||
}
|
||||
@@ -1705,28 +1717,6 @@ impl Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_resize_for_scrolling(&mut self) {
|
||||
let resize_dimensions = &mut self.resize_dimensions;
|
||||
match resize_dimensions.len() {
|
||||
0 | 1 => self.enforce_no_resize(),
|
||||
_ => {
|
||||
let len = resize_dimensions.len();
|
||||
|
||||
for (i, rect) in resize_dimensions.iter_mut().enumerate() {
|
||||
if let Some(rect) = rect {
|
||||
rect.top = 0;
|
||||
rect.bottom = 0;
|
||||
|
||||
if i == 0 {
|
||||
rect.left = 0;
|
||||
} else if i == len - 1 {
|
||||
rect.right = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn enforce_no_resize(&mut self) {
|
||||
for rect in self.resize_dimensions.iter_mut().flatten() {
|
||||
rect.left = 0;
|
||||
|
||||
@@ -151,6 +151,7 @@ macro_rules! gen_enum_subcommand_args {
|
||||
gen_enum_subcommand_args! {
|
||||
Focus: OperationDirection,
|
||||
Move: OperationDirection,
|
||||
Consume: OperationDirection,
|
||||
PreselectDirection: OperationDirection,
|
||||
CycleFocus: CycleDirection,
|
||||
CycleMove: CycleDirection,
|
||||
@@ -1284,6 +1285,23 @@ enum SubCommand {
|
||||
/// Set the number of visible columns for the Scrolling layout on the focused workspace
|
||||
#[clap(arg_required_else_help = true)]
|
||||
ScrollingLayoutColumns(ScrollingLayoutColumns),
|
||||
/// Make the focused column of the Scrolling layout as wide as the screen, or put it back to
|
||||
/// the width that it had
|
||||
ScrollingLayoutFullWidth,
|
||||
/// Scroll the Scrolling layout so that the focused column is in the middle of the screen, once
|
||||
CenterFocus,
|
||||
/// Make the focused column of the Scrolling layout fill the room that the columns in view leave
|
||||
/// on the screen, which does nothing in any other layout
|
||||
Expand,
|
||||
/// Take the neighbouring window on one side into the focused column of the Scrolling layout
|
||||
#[clap(arg_required_else_help = true)]
|
||||
Consume(Consume),
|
||||
/// Take the focused window out of its column in the Scrolling layout and put it in a column
|
||||
/// of its own on the right
|
||||
Expel,
|
||||
/// Stack the windows of the focused column of the Scrolling layout, or spread the focused
|
||||
/// stack out into a column with a window in each slot
|
||||
ToggleColumnStack,
|
||||
/// Set the layout column and row ratios for the focused workspace
|
||||
LayoutRatios(LayoutRatios),
|
||||
/// Load a custom layout from file for the focused workspace
|
||||
@@ -2956,6 +2974,24 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
||||
SubCommand::ScrollingLayoutColumns(args) => {
|
||||
send_message(&SocketMessage::ScrollingLayoutColumns(args.count))?;
|
||||
}
|
||||
SubCommand::ScrollingLayoutFullWidth => {
|
||||
send_message(&SocketMessage::ScrollingLayoutFullWidth)?;
|
||||
}
|
||||
SubCommand::CenterFocus => {
|
||||
send_message(&SocketMessage::CenterFocus)?;
|
||||
}
|
||||
SubCommand::Expand => {
|
||||
send_message(&SocketMessage::Expand)?;
|
||||
}
|
||||
SubCommand::Consume(args) => {
|
||||
send_message(&SocketMessage::Consume(args.operation_direction))?;
|
||||
}
|
||||
SubCommand::Expel => {
|
||||
send_message(&SocketMessage::Expel)?;
|
||||
}
|
||||
SubCommand::ToggleColumnStack => {
|
||||
send_message(&SocketMessage::ToggleColumnStack)?;
|
||||
}
|
||||
SubCommand::LayoutRatios(args) => {
|
||||
if args.columns.is_none() && args.rows.is_none() {
|
||||
println!(
|
||||
|
||||
Reference in new issue
Block a user