mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-26 18:22:09 +02:00
Implement resizing semantics based on layout
Still need to do splits layout but all others should be OK
This commit is contained in:
@@ -2427,13 +2427,17 @@ class Boss:
|
|||||||
self, edges: int, x: float, y: float, window_id: int, cell_width: int, cell_height: int,
|
self, edges: int, x: float, y: float, window_id: int, cell_width: int, cell_height: int,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
if (w := self.window_id_map.get(window_id)) and (tab := w.tabref()):
|
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))
|
horizontal_allowed = bool(edges & (LEFT_EDGE | RIGHT_EDGE))
|
||||||
vertical_allowed = bool(edges & (TOP_EDGE | BOTTOM_EDGE))
|
vertical_allowed = bool(edges & (TOP_EDGE | BOTTOM_EDGE))
|
||||||
self.drag_resize_of_window = WindowResizeDrag(
|
self.drag_resize_of_window = WindowResizeDrag(
|
||||||
is_active=True, horizontal_target_window_id=horizontal.id if horizontal_allowed else 0,
|
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,
|
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 True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -2441,18 +2445,20 @@ class Boss:
|
|||||||
if not (r := self.drag_resize_of_window):
|
if not (r := self.drag_resize_of_window):
|
||||||
return
|
return
|
||||||
if h := self.window_id_map.get(r.horizontal_target_window_id):
|
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
|
dx = step_x - r.last_step_x
|
||||||
if dx != 0:
|
if dx != 0:
|
||||||
self.resize_layout_window(h, float(dx), True, False)
|
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)
|
self.drag_resize_of_window = r._replace(last_step_x=step_x)
|
||||||
|
|
||||||
if v := self.window_id_map.get(r.vertical_target_window_id):
|
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
|
dy = step_y - r.last_step_y
|
||||||
if dy != 0:
|
if dy != 0:
|
||||||
self.resize_layout_window(v, float(dy), False, False)
|
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)
|
self.drag_resize_of_window = r._replace(last_step_y=step_y)
|
||||||
|
|
||||||
def drag_resize_end(self) -> None:
|
def drag_resize_end(self) -> None:
|
||||||
self.drag_resize_of_window = WindowResizeDrag()
|
self.drag_resize_of_window = WindowResizeDrag()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from itertools import repeat
|
|||||||
from typing import Any, Callable, NamedTuple
|
from typing import Any, Callable, NamedTuple
|
||||||
|
|
||||||
from kitty.borders import BorderColor
|
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.options.types import Options
|
||||||
from kitty.types import Edges, NeighborsMap, WindowGeometry, WindowMapper
|
from kitty.types import Edges, NeighborsMap, WindowGeometry, WindowMapper
|
||||||
from kitty.typing_compat import WindowType
|
from kitty.typing_compat import WindowType
|
||||||
@@ -453,31 +453,9 @@ class Layout:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def drag_resize_target_windows(
|
def drag_resize_target_windows(
|
||||||
self, click_window: WindowType, x: float, y: float, all_windows: WindowList
|
self, click_window: WindowType, x: float, y: float, edges: int, all_windows: WindowList,
|
||||||
) -> tuple[WindowType, WindowType]:
|
) -> tuple[WindowType, bool, WindowType, bool]:
|
||||||
g = click_window.geometry
|
return click_window, bool(edges & RIGHT_EDGE), click_window, bool(edges & BOTTOM_EDGE)
|
||||||
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
|
|
||||||
|
|
||||||
def serialize(self, all_windows: WindowList) -> dict[str, Any]:
|
def serialize(self, all_windows: WindowList) -> dict[str, Any]:
|
||||||
ans = self.layout_state()
|
ans = self.layout_state()
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import sys
|
||||||
from collections.abc import Generator, Sequence
|
from collections.abc import Generator, Sequence
|
||||||
from itertools import islice, repeat
|
from itertools import islice, repeat
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from kitty.borders import BorderColor
|
from kitty.borders import BorderColor
|
||||||
from kitty.conf.utils import to_bool
|
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.types import Edges, NeighborsMap, WindowMapper
|
||||||
from kitty.typing_compat import EdgeLiteral, WindowType
|
from kitty.typing_compat import EdgeLiteral, WindowType
|
||||||
from kitty.window_list import WindowGroup, WindowList
|
from kitty.window_list import WindowGroup, WindowList
|
||||||
@@ -24,6 +26,36 @@ from .base import (
|
|||||||
from .vertical import borders
|
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(
|
def neighbors_for_tall_window(
|
||||||
num_full_size_windows: int,
|
num_full_size_windows: int,
|
||||||
window: WindowType,
|
window: WindowType,
|
||||||
@@ -357,6 +389,11 @@ class Tall(Layout):
|
|||||||
self.layout_opts = TallLayoutOpts(layout_state['opts'])
|
self.layout_opts = TallLayoutOpts(layout_state['opts'])
|
||||||
return True
|
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):
|
class Fat(Tall):
|
||||||
|
|
||||||
|
|||||||
@@ -253,6 +253,8 @@ class WindowResizeDrag(NamedTuple):
|
|||||||
initial_y: float = 0
|
initial_y: float = 0
|
||||||
last_step_x: float = 0
|
last_step_x: float = 0
|
||||||
last_step_y: float = 0
|
last_step_y: float = 0
|
||||||
|
height_increases_downwards: bool = True
|
||||||
|
width_increases_rightwards: bool = True
|
||||||
|
|
||||||
def __bool__(self) -> bool:
|
def __bool__(self) -> bool:
|
||||||
return self.is_active
|
return self.is_active
|
||||||
|
|||||||
Reference in New Issue
Block a user