diff --git a/kitty/boss.py b/kitty/boss.py index 924e3919b..1ed9842b5 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -2427,13 +2427,17 @@ class Boss: self, edges: int, x: float, y: float, window_id: int, cell_width: int, cell_height: int, ) -> bool: if (w := self.window_id_map.get(window_id)) and (tab := w.tabref()): - horizontal, vertical = tab.current_layout.drag_resize_target_windows(w, x, y, tab.windows) + horizontal, width_increases_rightwards, vertical, height_increases_downwards = \ + tab.current_layout.drag_resize_target_windows(w, x, y, edges, tab.windows) horizontal_allowed = bool(edges & (LEFT_EDGE | RIGHT_EDGE)) vertical_allowed = bool(edges & (TOP_EDGE | BOTTOM_EDGE)) self.drag_resize_of_window = WindowResizeDrag( is_active=True, horizontal_target_window_id=horizontal.id if horizontal_allowed else 0, vertical_target_window_id=vertical.id if vertical_allowed else 0, - cell_width=cell_width, cell_height=cell_height, initial_x=x, initial_y=y) + cell_width=cell_width, cell_height=cell_height, initial_x=x, initial_y=y, + width_increases_rightwards=width_increases_rightwards, + height_increases_downwards=height_increases_downwards, + ) return True return False @@ -2441,18 +2445,20 @@ class Boss: if not (r := self.drag_resize_of_window): return if h := self.window_id_map.get(r.horizontal_target_window_id): - step_x = floor((x - r.initial_x) / r.cell_width) + mult = 1 if r.width_increases_rightwards else -1 + step_x = floor((x - r.initial_x) / r.cell_width) * mult dx = step_x - r.last_step_x if dx != 0: - self.resize_layout_window(h, float(dx), True, False) - self.drag_resize_of_window = r._replace(last_step_x=step_x) + if self.resize_layout_window(h, float(dx), is_horizontal=True) is None: + self.drag_resize_of_window = r._replace(last_step_x=step_x) if v := self.window_id_map.get(r.vertical_target_window_id): - step_y = floor((y - r.initial_y) / r.cell_height) + mult = 1 if r.height_increases_downwards else -1 + step_y = floor((y - r.initial_y) / r.cell_height) * mult dy = step_y - r.last_step_y if dy != 0: - self.resize_layout_window(v, float(dy), False, False) - self.drag_resize_of_window = r._replace(last_step_y=step_y) + if self.resize_layout_window(v, float(dy), is_horizontal=False) is None: + self.drag_resize_of_window = r._replace(last_step_y=step_y) def drag_resize_end(self) -> None: self.drag_resize_of_window = WindowResizeDrag() diff --git a/kitty/layout/base.py b/kitty/layout/base.py index 3812bc7f6..d8b02b30e 100644 --- a/kitty/layout/base.py +++ b/kitty/layout/base.py @@ -7,7 +7,7 @@ from itertools import repeat from typing import Any, Callable, NamedTuple from kitty.borders import BorderColor -from kitty.fast_data_types import Region, get_options, set_active_window, viewport_for_window +from kitty.fast_data_types import BOTTOM_EDGE, RIGHT_EDGE, Region, get_options, set_active_window, viewport_for_window from kitty.options.types import Options from kitty.types import Edges, NeighborsMap, WindowGeometry, WindowMapper from kitty.typing_compat import WindowType @@ -453,31 +453,9 @@ class Layout: return True def drag_resize_target_windows( - self, click_window: WindowType, x: float, y: float, all_windows: WindowList - ) -> tuple[WindowType, WindowType]: - g = click_window.geometry - left_half_clicked = x <= g.left + (g.right - g.left) / 2 - top_half_clicked = y <= g.top + (g.bottom - g.top) / 2 - neighbors = self.neighbors_for_window(click_window, all_windows) - left = neighbors.get("left", ()) - right = neighbors.get("right", ()) - top = neighbors.get("top", ()) - bottom = neighbors.get("bottom", ()) - horizontal_target = vertical_target = click_window - - # Infer which window should be horizontally resized based on click - # position and layout state - if ((left_half_clicked and len(left) > 0) or - (not left_half_clicked and len(left) > 0 and len(right) == 0)): - horizontal_target = all_windows.id_map[left[0]] - - # Infer which window should be vertically resized based on click - # position and layout state - if ((top_half_clicked and len(top) > 0) or - (not top_half_clicked and len(top) > 0 and len(bottom) == 0)): - vertical_target = all_windows.id_map[top[0]] - - return horizontal_target, vertical_target + self, click_window: WindowType, x: float, y: float, edges: int, all_windows: WindowList, + ) -> tuple[WindowType, bool, WindowType, bool]: + return click_window, bool(edges & RIGHT_EDGE), click_window, bool(edges & BOTTOM_EDGE) def serialize(self, all_windows: WindowList) -> dict[str, Any]: ans = self.layout_state() diff --git a/kitty/layout/tall.py b/kitty/layout/tall.py index 0d2737971..9cd5197e1 100644 --- a/kitty/layout/tall.py +++ b/kitty/layout/tall.py @@ -1,12 +1,14 @@ #!/usr/bin/env python # License: GPLv3 Copyright: 2020, Kovid Goyal +import sys from collections.abc import Generator, Sequence from itertools import islice, repeat from typing import Any from kitty.borders import BorderColor from kitty.conf.utils import to_bool +from kitty.fast_data_types import BOTTOM_EDGE, RIGHT_EDGE from kitty.types import Edges, NeighborsMap, WindowMapper from kitty.typing_compat import EdgeLiteral, WindowType from kitty.window_list import WindowGroup, WindowList @@ -24,6 +26,36 @@ from .base import ( from .vertical import borders +def drag_resize_target_windows( + click_window: WindowType, + edges: int, + x: float, y: float, + num_full_size_windows: int, + all_windows: WindowList, + main_is_horizontal: bool = True +) -> tuple[WindowType, bool, WindowType, bool]: + groups = tuple(all_windows.iter_all_layoutable_groups()) + horizontal = vertical = click_window + min_dist = float(sys.maxsize) + height_increases_downwards = bool(edges * BOTTOM_EDGE) + width_increases_rightwards = bool(edges * RIGHT_EDGE) + for gr in groups[num_full_size_windows:]: + if gr.windows: + w = gr.windows[-1] + g = w.geometry + if main_is_horizontal: + if (dist := min(abs(g.top - y), abs(g.bottom - y))) < min_dist: + min_dist = dist + vertical = w + height_increases_downwards = y > g.top + (g.bottom - g.top) / 2 + else: + if (dist := min(abs(g.left - x), abs(g.right - x))) < min_dist: + min_dist = dist + horizontal = w + width_increases_rightwards = x > g.left + (g.right - g.left) / 2 + return horizontal, width_increases_rightwards, vertical, height_increases_downwards + + def neighbors_for_tall_window( num_full_size_windows: int, window: WindowType, @@ -357,6 +389,11 @@ class Tall(Layout): self.layout_opts = TallLayoutOpts(layout_state['opts']) return True + def drag_resize_target_windows( + self, click_window: WindowType, x: float, y: float, edges: int, all_windows: WindowList, + ) -> tuple[WindowType, bool, WindowType, bool]: + return drag_resize_target_windows(click_window, edges, x, y, self.num_full_size_windows, all_windows, self.main_is_horizontal) + class Fat(Tall): diff --git a/kitty/types.py b/kitty/types.py index f40f99764..5f0bd0721 100644 --- a/kitty/types.py +++ b/kitty/types.py @@ -253,6 +253,8 @@ class WindowResizeDrag(NamedTuple): initial_y: float = 0 last_step_x: float = 0 last_step_y: float = 0 + height_increases_downwards: bool = True + width_increases_rightwards: bool = True def __bool__(self) -> bool: return self.is_active