mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-09 06:25:23 +02: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:
@@ -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 {
|
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>) {
|
pub fn hide(&self, omit: Option<isize>) {
|
||||||
for window in self.windows().iter().rev() {
|
for window in self.windows().iter().rev() {
|
||||||
let mut should_hide = omit.is_none();
|
let mut should_hide = omit.is_none();
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ pub enum SocketMessage {
|
|||||||
FocusWindow(OperationDirection),
|
FocusWindow(OperationDirection),
|
||||||
MoveWindow(OperationDirection),
|
MoveWindow(OperationDirection),
|
||||||
PreselectDirection(OperationDirection),
|
PreselectDirection(OperationDirection),
|
||||||
|
CancelPreselect,
|
||||||
CycleFocusWindow(CycleDirection),
|
CycleFocusWindow(CycleDirection),
|
||||||
CycleMoveWindow(CycleDirection),
|
CycleMoveWindow(CycleDirection),
|
||||||
StackWindow(OperationDirection),
|
StackWindow(OperationDirection),
|
||||||
|
|||||||
@@ -305,9 +305,25 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
SocketMessage::PreselectDirection(direction) => {
|
SocketMessage::PreselectDirection(direction) => {
|
||||||
let focused_workspace = self.focused_workspace()?;
|
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)?;
|
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) => {
|
SocketMessage::MoveWindow(direction) => {
|
||||||
let focused_workspace = self.focused_workspace()?;
|
let focused_workspace = self.focused_workspace()?;
|
||||||
|
|||||||
@@ -2077,7 +2077,7 @@ impl WindowManager {
|
|||||||
_ => new_idx,
|
_ => new_idx,
|
||||||
};
|
};
|
||||||
|
|
||||||
workspace.preselect_container_index(adjusted_idx);
|
workspace.preselect_container_idx(adjusted_idx);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
|
|||||||
@@ -449,7 +449,8 @@ impl Workspace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure we are never holding on to empty containers
|
// 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
|
let container_padding = self
|
||||||
.container_padding
|
.container_padding
|
||||||
@@ -979,8 +980,16 @@ impl Workspace {
|
|||||||
container
|
container
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preselect_container_index(&mut self, insertion_index: usize) {
|
pub fn preselect_container_idx(&mut self, insertion_idx: usize) {
|
||||||
self.preselected_container_idx = Some(insertion_index);
|
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> {
|
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) {
|
pub fn new_container_for_window(&mut self, window: Window) {
|
||||||
let next_idx = if let Some(idx) = self.preselected_container_idx {
|
let next_idx = if let Some(idx) = self.preselected_container_idx {
|
||||||
let next = idx;
|
let next = idx;
|
||||||
|
|
||||||
self.preselected_container_idx = None;
|
self.preselected_container_idx = None;
|
||||||
|
self.remove_container_by_idx(next);
|
||||||
next
|
next
|
||||||
} else if self.containers().is_empty() {
|
} else if self.containers().is_empty() {
|
||||||
0
|
0
|
||||||
|
|||||||
@@ -1099,6 +1099,8 @@ enum SubCommand {
|
|||||||
/// Preselect the specified direction for the next window to be spawned on supported layouts
|
/// Preselect the specified direction for the next window to be spawned on supported layouts
|
||||||
#[clap(arg_required_else_help = true)]
|
#[clap(arg_required_else_help = true)]
|
||||||
PreselectDirection(PreselectDirection),
|
PreselectDirection(PreselectDirection),
|
||||||
|
/// Cancel a workspace preselect set by the preselect-direction command, if one exists
|
||||||
|
CancelPreselect,
|
||||||
/// Minimize the focused window
|
/// Minimize the focused window
|
||||||
Minimize,
|
Minimize,
|
||||||
/// Close the focused window
|
/// Close the focused window
|
||||||
@@ -2045,6 +2047,9 @@ fn main() -> eyre::Result<()> {
|
|||||||
SubCommand::PreselectDirection(arg) => {
|
SubCommand::PreselectDirection(arg) => {
|
||||||
send_message(&SocketMessage::PreselectDirection(arg.operation_direction))?;
|
send_message(&SocketMessage::PreselectDirection(arg.operation_direction))?;
|
||||||
}
|
}
|
||||||
|
SubCommand::CancelPreselect => {
|
||||||
|
send_message(&SocketMessage::CancelPreselect)?;
|
||||||
|
}
|
||||||
SubCommand::CycleFocus(arg) => {
|
SubCommand::CycleFocus(arg) => {
|
||||||
send_message(&SocketMessage::CycleFocusWindow(arg.cycle_direction))?;
|
send_message(&SocketMessage::CycleFocusWindow(arg.cycle_direction))?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ nav:
|
|||||||
- cli/focus.md
|
- cli/focus.md
|
||||||
- cli/move.md
|
- cli/move.md
|
||||||
- cli/preselect-direction.md
|
- cli/preselect-direction.md
|
||||||
|
- cli/cancel-preselect.md
|
||||||
- cli/minimize.md
|
- cli/minimize.md
|
||||||
- cli/close.md
|
- cli/close.md
|
||||||
- cli/force-focus.md
|
- cli/force-focus.md
|
||||||
|
|||||||
Reference in New Issue
Block a user