mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Implement move-column/window-to-monitor actions for the screenshot UI
This commit is contained in:
+104
-20
@@ -1535,7 +1535,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveWindowToMonitorLeft => {
|
||||
if let Some(output) = self.niri.output_left() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_left_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_left() {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
@@ -1546,7 +1551,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveWindowToMonitorRight => {
|
||||
if let Some(output) = self.niri.output_right() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_right_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_right() {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
@@ -1557,7 +1567,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveWindowToMonitorDown => {
|
||||
if let Some(output) = self.niri.output_down() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_down_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_down() {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
@@ -1568,7 +1583,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveWindowToMonitorUp => {
|
||||
if let Some(output) = self.niri.output_up() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_up_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_up() {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
@@ -1579,7 +1599,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveWindowToMonitorPrevious => {
|
||||
if let Some(output) = self.niri.output_previous() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_previous_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_previous() {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
@@ -1590,7 +1615,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveWindowToMonitorNext => {
|
||||
if let Some(output) = self.niri.output_next() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_next_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_next() {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
@@ -1602,12 +1632,17 @@ impl State {
|
||||
}
|
||||
Action::MoveWindowToMonitor(output) => {
|
||||
if let Some(output) = self.niri.output_by_name_match(&output).cloned() {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
if self.niri.screenshot_ui.is_open() {
|
||||
self.move_cursor_to_output(&output);
|
||||
self.niri.screenshot_ui.move_to_output(output);
|
||||
} else {
|
||||
self.niri
|
||||
.layout
|
||||
.move_to_output(None, &output, None, ActivateWindow::Smart);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
self.move_cursor_to_output(&output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1641,7 +1676,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveColumnToMonitorLeft => {
|
||||
if let Some(output) = self.niri.output_left() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_left_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_left() {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
@@ -1650,7 +1690,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveColumnToMonitorRight => {
|
||||
if let Some(output) = self.niri.output_right() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_right_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_right() {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
@@ -1659,7 +1704,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveColumnToMonitorDown => {
|
||||
if let Some(output) = self.niri.output_down() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_down_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_down() {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
@@ -1668,7 +1718,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveColumnToMonitorUp => {
|
||||
if let Some(output) = self.niri.output_up() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_up_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_up() {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
@@ -1677,7 +1732,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveColumnToMonitorPrevious => {
|
||||
if let Some(output) = self.niri.output_previous() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_previous_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_previous() {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
@@ -1686,7 +1746,12 @@ impl State {
|
||||
}
|
||||
}
|
||||
Action::MoveColumnToMonitorNext => {
|
||||
if let Some(output) = self.niri.output_next() {
|
||||
if let Some(current_output) = self.niri.screenshot_ui.selection_output() {
|
||||
if let Some(target_output) = self.niri.output_next_of(current_output) {
|
||||
self.move_cursor_to_output(&target_output);
|
||||
self.niri.screenshot_ui.move_to_output(target_output);
|
||||
}
|
||||
} else if let Some(output) = self.niri.output_next() {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
@@ -1696,10 +1761,15 @@ impl State {
|
||||
}
|
||||
Action::MoveColumnToMonitor(output) => {
|
||||
if let Some(output) = self.niri.output_by_name_match(&output).cloned() {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
if self.niri.screenshot_ui.is_open() {
|
||||
self.move_cursor_to_output(&output);
|
||||
self.niri.screenshot_ui.move_to_output(output);
|
||||
} else {
|
||||
self.niri.layout.move_column_to_output(&output, None, true);
|
||||
self.niri.layout.focus_output(&output);
|
||||
if !self.maybe_warp_cursor_to_focus_centered() {
|
||||
self.move_cursor_to_output(&output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4120,6 +4190,20 @@ fn allowed_during_screenshot(action: &Action) -> bool {
|
||||
| Action::MoveWindowUpOrToWorkspaceUp
|
||||
| Action::MoveWindowDown
|
||||
| Action::MoveWindowDownOrToWorkspaceDown
|
||||
| Action::MoveColumnToMonitorLeft
|
||||
| Action::MoveColumnToMonitorRight
|
||||
| Action::MoveColumnToMonitorUp
|
||||
| Action::MoveColumnToMonitorDown
|
||||
| Action::MoveColumnToMonitorPrevious
|
||||
| Action::MoveColumnToMonitorNext
|
||||
| Action::MoveColumnToMonitor(_)
|
||||
| Action::MoveWindowToMonitorLeft
|
||||
| Action::MoveWindowToMonitorRight
|
||||
| Action::MoveWindowToMonitorUp
|
||||
| Action::MoveWindowToMonitorDown
|
||||
| Action::MoveWindowToMonitorPrevious
|
||||
| Action::MoveWindowToMonitorNext
|
||||
| Action::MoveWindowToMonitor(_)
|
||||
| Action::SetWindowWidth(_)
|
||||
| Action::SetWindowHeight(_)
|
||||
| Action::SetColumnWidth(_)
|
||||
|
||||
@@ -347,6 +347,75 @@ impl ScreenshotUi {
|
||||
self.update_buffers();
|
||||
}
|
||||
|
||||
/// Moves the screenshot selection to a different output.
|
||||
///
|
||||
/// This preserves the relative position while keeping logical size. It is (intentionally) very
|
||||
/// similar to how floating windows move across monitors, but with one difference: floating
|
||||
/// windows can go partially outside the view, while the screenshot selection cannot. So, we
|
||||
/// clamp it to new output bounds, trying to preserve the size if possible.
|
||||
pub fn move_to_output(&mut self, new_output: Output) {
|
||||
let Self::Open {
|
||||
selection,
|
||||
output_data,
|
||||
..
|
||||
} = self
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let (current_output, current_a, current_b) = selection;
|
||||
|
||||
if current_output == &new_output {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(target_data) = output_data.get(&new_output) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let current_data = &output_data[current_output];
|
||||
|
||||
let current_rect: Rectangle<_, Physical> = Rectangle::new(
|
||||
Point::from((current_a.x.min(current_b.x), current_a.y.min(current_b.y))),
|
||||
Size::from((
|
||||
(current_a.x.max(current_b.x) - current_a.x.min(current_b.x) + 1),
|
||||
(current_a.y.max(current_b.y) - current_a.y.min(current_b.y) + 1),
|
||||
)),
|
||||
);
|
||||
let current_rect = current_rect.to_f64();
|
||||
|
||||
let rel_x = current_rect.loc.x / current_data.size.w as f64;
|
||||
let rel_y = current_rect.loc.y / current_data.size.h as f64;
|
||||
|
||||
let factor = target_data.scale / current_data.scale;
|
||||
let mut new_width = (current_rect.size.w * factor).round() as i32;
|
||||
let mut new_height = (current_rect.size.h * factor).round() as i32;
|
||||
|
||||
new_width = new_width.clamp(1, target_data.size.w);
|
||||
new_height = new_height.clamp(1, target_data.size.h);
|
||||
|
||||
let new_x = (rel_x * target_data.size.w as f64).round() as i32;
|
||||
let new_y = (rel_y * target_data.size.h as f64).round() as i32;
|
||||
|
||||
let max_x = target_data.size.w - new_width;
|
||||
let max_y = target_data.size.h - new_height;
|
||||
let new_x = new_x.clamp(0, max_x);
|
||||
let new_y = new_y.clamp(0, max_y);
|
||||
|
||||
let new_rect = Rectangle::new(
|
||||
Point::from((new_x, new_y)),
|
||||
Size::from((new_width, new_height)),
|
||||
);
|
||||
|
||||
*selection = (
|
||||
new_output,
|
||||
new_rect.loc,
|
||||
new_rect.loc + new_rect.size - Size::from((1, 1)),
|
||||
);
|
||||
|
||||
self.update_buffers();
|
||||
}
|
||||
|
||||
pub fn set_width(&mut self, change: SizeChange) {
|
||||
let Self::Open {
|
||||
selection: (output, a, b),
|
||||
|
||||
Reference in New Issue
Block a user