mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-01-11 22:12:53 +01:00
feat(wm): add visual feedback for preselection
This commit adds visual feedback in the form of a ghost tile for preselections made by the preselect-direction command. A container with the id "PRESELECT" will be added to the workspace, and replaced when the next manage-able window is spawned. A new command, cancel-preselect, has been added to remove both the preselection index and the ghost tile if the user changes their mind.
This commit is contained in:
12
docs/cli/cancel-preselect.md
Normal file
12
docs/cli/cancel-preselect.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# cancel-preselect
|
||||
|
||||
```
|
||||
Cancel a workspace preselect set by the preselect-direction command, if one exists
|
||||
|
||||
Usage: komorebic.exe cancel-preselect
|
||||
|
||||
Options:
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
```
|
||||
@@ -41,6 +41,18 @@ impl Lockable for Container {
|
||||
}
|
||||
|
||||
impl Container {
|
||||
pub fn preselect() -> Self {
|
||||
Self {
|
||||
id: "PRESELECT".to_string(),
|
||||
locked: false,
|
||||
windows: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_preselect(&self) -> bool {
|
||||
self.id == "PRESELECT"
|
||||
}
|
||||
|
||||
pub fn hide(&self, omit: Option<isize>) {
|
||||
for window in self.windows().iter().rev() {
|
||||
let mut should_hide = omit.is_none();
|
||||
|
||||
@@ -56,6 +56,7 @@ pub enum SocketMessage {
|
||||
FocusWindow(OperationDirection),
|
||||
MoveWindow(OperationDirection),
|
||||
PreselectDirection(OperationDirection),
|
||||
CancelPreselect,
|
||||
CycleFocusWindow(CycleDirection),
|
||||
CycleMoveWindow(CycleDirection),
|
||||
StackWindow(OperationDirection),
|
||||
|
||||
@@ -305,9 +305,25 @@ impl WindowManager {
|
||||
}
|
||||
SocketMessage::PreselectDirection(direction) => {
|
||||
let focused_workspace = self.focused_workspace()?;
|
||||
if matches!(focused_workspace.layer, WorkspaceLayer::Tiling) {
|
||||
let mut update = false;
|
||||
|
||||
if focused_workspace.preselected_container_idx.is_some() {
|
||||
tracing::warn!(
|
||||
"ignoring command as this workspace already has a direction preselect set"
|
||||
);
|
||||
} else if matches!(focused_workspace.layer, WorkspaceLayer::Tiling) {
|
||||
self.preselect_container_in_direction(direction)?;
|
||||
update = true;
|
||||
}
|
||||
|
||||
if update {
|
||||
self.focused_workspace_mut()?.update()?;
|
||||
}
|
||||
}
|
||||
SocketMessage::CancelPreselect => {
|
||||
let focused_workspace = self.focused_workspace_mut()?;
|
||||
focused_workspace.cancel_preselect();
|
||||
focused_workspace.update()?;
|
||||
}
|
||||
SocketMessage::MoveWindow(direction) => {
|
||||
let focused_workspace = self.focused_workspace()?;
|
||||
|
||||
@@ -2077,7 +2077,7 @@ impl WindowManager {
|
||||
_ => new_idx,
|
||||
};
|
||||
|
||||
workspace.preselect_container_index(adjusted_idx);
|
||||
workspace.preselect_container_idx(adjusted_idx);
|
||||
}
|
||||
None => {
|
||||
tracing::debug!(
|
||||
|
||||
@@ -449,7 +449,8 @@ impl Workspace {
|
||||
}
|
||||
|
||||
// make sure we are never holding on to empty containers
|
||||
self.containers_mut().retain(|c| !c.windows().is_empty());
|
||||
self.containers_mut()
|
||||
.retain(|c| c.is_preselect() || !c.windows().is_empty());
|
||||
|
||||
let container_padding = self
|
||||
.container_padding
|
||||
@@ -979,8 +980,16 @@ impl Workspace {
|
||||
container
|
||||
}
|
||||
|
||||
pub fn preselect_container_index(&mut self, insertion_index: usize) {
|
||||
self.preselected_container_idx = Some(insertion_index);
|
||||
pub fn preselect_container_idx(&mut self, insertion_idx: usize) {
|
||||
self.preselected_container_idx = Some(insertion_idx);
|
||||
self.insert_container_at_idx(insertion_idx, Container::preselect());
|
||||
}
|
||||
|
||||
pub fn cancel_preselect(&mut self) {
|
||||
if let Some(idx) = self.preselected_container_idx {
|
||||
self.containers_mut().remove_respecting_locks(idx);
|
||||
self.preselected_container_idx = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_idx_for_direction(&self, direction: OperationDirection) -> Option<usize> {
|
||||
@@ -1084,9 +1093,8 @@ impl Workspace {
|
||||
pub fn new_container_for_window(&mut self, window: Window) {
|
||||
let next_idx = if let Some(idx) = self.preselected_container_idx {
|
||||
let next = idx;
|
||||
|
||||
self.preselected_container_idx = None;
|
||||
|
||||
self.remove_container_by_idx(next);
|
||||
next
|
||||
} else if self.containers().is_empty() {
|
||||
0
|
||||
|
||||
@@ -1099,6 +1099,8 @@ enum SubCommand {
|
||||
/// Preselect the specified direction for the next window to be spawned on supported layouts
|
||||
#[clap(arg_required_else_help = true)]
|
||||
PreselectDirection(PreselectDirection),
|
||||
/// Cancel a workspace preselect set by the preselect-direction command, if one exists
|
||||
CancelPreselect,
|
||||
/// Minimize the focused window
|
||||
Minimize,
|
||||
/// Close the focused window
|
||||
@@ -2045,6 +2047,9 @@ fn main() -> eyre::Result<()> {
|
||||
SubCommand::PreselectDirection(arg) => {
|
||||
send_message(&SocketMessage::PreselectDirection(arg.operation_direction))?;
|
||||
}
|
||||
SubCommand::CancelPreselect => {
|
||||
send_message(&SocketMessage::CancelPreselect)?;
|
||||
}
|
||||
SubCommand::CycleFocus(arg) => {
|
||||
send_message(&SocketMessage::CycleFocusWindow(arg.cycle_direction))?;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ nav:
|
||||
- cli/focus.md
|
||||
- cli/move.md
|
||||
- cli/preselect-direction.md
|
||||
- cli/cancel-preselect.md
|
||||
- cli/minimize.md
|
||||
- cli/close.md
|
||||
- cli/force-focus.md
|
||||
|
||||
Reference in New Issue
Block a user