Cleanup handling of drag_overlay_mode
This commit is contained in:
parent
ae3818bf7e
commit
3d369f8632
7 changed files with 50 additions and 44 deletions
|
|
@ -2,9 +2,10 @@
|
|||
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from collections.abc import Generator, Iterable, Iterator, Sequence
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
from itertools import repeat
|
||||
from typing import Any, Callable, ClassVar, Literal, NamedTuple
|
||||
from typing import Any, Callable, ClassVar, NamedTuple
|
||||
|
||||
from kitty.borders import BorderColor
|
||||
from kitty.fast_data_types import BOTTOM_EDGE, RIGHT_EDGE, Region, get_options, set_active_window, viewport_for_window
|
||||
|
|
@ -225,6 +226,14 @@ def create_window_id_map_for_unserialize(all_windows: WindowList) -> dict[int, i
|
|||
return window_id_map
|
||||
|
||||
|
||||
class DragOverlayMode(Enum):
|
||||
' Controls drag-and-drop overlay display and valid direction axis for body drops '
|
||||
full = 'full' # full-window overlay, positional swap (Stack and any unrecognised layout)
|
||||
axis_x = 'axis_x' # top/bottom halves only (Vertical, Tall, Grid)
|
||||
axis_y = 'axis_y' # left/right halves only (Horizontal, Fat)
|
||||
free = 'free' # 4-way free direction (Splits; handled by its own insert_window_next_to override)
|
||||
|
||||
|
||||
class Layout:
|
||||
|
||||
name: str = ''
|
||||
|
|
@ -232,12 +241,7 @@ class Layout:
|
|||
must_draw_borders = False # can be overridden to customize behavior from kittens
|
||||
layout_opts = LayoutOpts({})
|
||||
only_active_window_visible = False
|
||||
# Controls drag-and-drop overlay display and valid direction axis for body drops.
|
||||
# 'full' – full-window overlay, positional swap (Stack and any unrecognised layout)
|
||||
# 'axis_y' – top/bottom halves only (Vertical, Tall, Grid)
|
||||
# 'axis_x' – left/right halves only (Horizontal, Fat)
|
||||
# 'free' – 4-way free direction (Splits; handled by its own insert_window_next_to override)
|
||||
drag_overlay_mode: ClassVar[Literal['full', 'axis_y', 'axis_x', 'free']] = 'full'
|
||||
drag_overlay_mode: ClassVar[DragOverlayMode] = DragOverlayMode.full
|
||||
|
||||
def __init__(self, os_window_id: int, tab_id: int, layout_opts: str = '') -> None:
|
||||
self.set_owner(os_window_id, tab_id)
|
||||
|
|
@ -317,18 +321,19 @@ def insert_window_next_to(
|
|||
horizontal: bool,
|
||||
after: bool,
|
||||
) -> None:
|
||||
"""Reposition window as a linear neighbour of next_to.
|
||||
'''
|
||||
Reposition window as a linear neighbour of next_to.
|
||||
|
||||
For axis_x/axis_y layouts this performs a positional insert that preserves
|
||||
the order of all other groups. For 'full' layouts it falls back to a swap.
|
||||
The Splits layout overrides this with tree-based logic.
|
||||
"""
|
||||
'''
|
||||
src_wg = all_windows.group_for_window(window)
|
||||
dest_wg = all_windows.group_for_window(next_to)
|
||||
if src_wg is None or dest_wg is None or src_wg.id == dest_wg.id:
|
||||
return
|
||||
all_windows.set_active_window_group_for(window)
|
||||
if self.drag_overlay_mode in ('axis_x', 'axis_y'):
|
||||
if self.drag_overlay_mode in (DragOverlayMode.axis_x, DragOverlayMode.axis_y):
|
||||
all_windows.insert_window_group_next_to(dest_wg.id, after)
|
||||
else:
|
||||
# 'full' fallback: swap (preserves existing behaviour for Stack etc.)
|
||||
|
|
@ -402,7 +407,7 @@ def __call__(self, all_windows: WindowList) -> None:
|
|||
# Set show_title_bar flag on each visible window before layout
|
||||
min_windows = get_options().window_title_bar_min_windows
|
||||
visible_groups = tuple(all_windows.iter_all_layoutable_groups(only_visible=True))
|
||||
force_show = getattr(all_windows, '_force_show_title_bars', False)
|
||||
force_show = all_windows.force_show_title_bars
|
||||
show_title_bar = force_show or (min_windows > 0 and len(visible_groups) >= min_windows)
|
||||
for wg in visible_groups:
|
||||
for w in wg.windows:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
from kitty.typing_compat import WindowType
|
||||
from kitty.window_list import WindowGroup, WindowList
|
||||
|
||||
from .base import BorderLine, Layout, LayoutData, LayoutDimension, ListOfWindows, layout_dimension, lgd
|
||||
from .base import BorderLine, DragOverlayMode, Layout, LayoutData, LayoutDimension, ListOfWindows, layout_dimension, lgd
|
||||
from .tall import neighbors_for_tall_window
|
||||
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ class Grid(Layout):
|
|||
|
||||
name: str = 'grid'
|
||||
no_minimal_window_borders = True
|
||||
drag_overlay_mode = 'axis_y'
|
||||
drag_overlay_mode = DragOverlayMode.axis_y
|
||||
|
||||
def remove_all_biases(self) -> bool:
|
||||
self.biased_rows: dict[int, float] = {}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
from kitty.typing_compat import EdgeLiteral, WindowType
|
||||
from kitty.window_list import WindowGroup, WindowList
|
||||
|
||||
from .base import BorderLine, Layout, LayoutOpts, blank_rects_for_window, lgd, window_geometry_from_layouts
|
||||
from .base import BorderLine, DragOverlayMode, Layout, LayoutOpts, blank_rects_for_window, lgd, window_geometry_from_layouts
|
||||
|
||||
|
||||
class SerializedPair(TypedDict, total=False):
|
||||
|
|
@ -561,7 +561,7 @@ class Splits(Layout):
|
|||
needs_all_windows = True
|
||||
layout_opts = SplitsLayoutOpts({})
|
||||
no_minimal_window_borders = True
|
||||
drag_overlay_mode = 'free'
|
||||
drag_overlay_mode = DragOverlayMode.free
|
||||
|
||||
@property
|
||||
def default_axis_is_horizontal(self) -> bool | None:
|
||||
|
|
@ -731,7 +731,7 @@ def insert_window_next_to(
|
|||
horizontal: bool,
|
||||
after: bool
|
||||
) -> None:
|
||||
"""Reposition an existing window as a split adjacent to next_to."""
|
||||
''' Reposition an existing window as a split adjacent to next_to '''
|
||||
src_wg = all_windows.group_for_window(window)
|
||||
dest_wg = all_windows.group_for_window(next_to)
|
||||
if src_wg is None or dest_wg is None or src_wg.id == dest_wg.id:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import sys
|
||||
from collections.abc import Generator, Iterator, Sequence
|
||||
from itertools import islice, repeat
|
||||
from typing import Any, ClassVar, Literal
|
||||
from typing import Any
|
||||
|
||||
from kitty.borders import BorderColor
|
||||
from kitty.conf.utils import to_bool
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
from .base import (
|
||||
BorderLine,
|
||||
DragOverlayMode,
|
||||
Layout,
|
||||
LayoutData,
|
||||
LayoutDimension,
|
||||
|
|
@ -136,7 +137,7 @@ class Tall(Layout):
|
|||
name = 'tall'
|
||||
main_is_horizontal = True
|
||||
no_minimal_window_borders = True
|
||||
drag_overlay_mode: ClassVar[Literal['full', 'axis_y', 'axis_x', 'free']] = 'axis_y'
|
||||
drag_overlay_mode = DragOverlayMode.axis_y
|
||||
layout_opts = TallLayoutOpts({})
|
||||
main_axis_layout = Layout.xlayout
|
||||
perp_axis_layout = Layout.ylayout
|
||||
|
|
@ -382,6 +383,6 @@ class Fat(Tall):
|
|||
|
||||
name = 'fat'
|
||||
main_is_horizontal = False
|
||||
drag_overlay_mode = 'axis_x'
|
||||
drag_overlay_mode = DragOverlayMode.axis_x
|
||||
main_axis_layout = Layout.ylayout
|
||||
perp_axis_layout = Layout.xlayout
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from collections.abc import Generator, Iterable
|
||||
from typing import Any, ClassVar, Literal
|
||||
from typing import Any
|
||||
|
||||
from kitty.borders import BorderColor
|
||||
from kitty.types import Edges, NeighborsMap, WindowMapper
|
||||
from kitty.typing_compat import EdgeLiteral, WindowType
|
||||
from kitty.window_list import WindowGroup, WindowList
|
||||
|
||||
from .base import BorderLine, Layout, LayoutData, LayoutDimension, lgd
|
||||
from .base import BorderLine, DragOverlayMode, Layout, LayoutData, LayoutDimension, lgd
|
||||
|
||||
|
||||
def borders(
|
||||
|
|
@ -64,7 +64,7 @@ class Vertical(Layout):
|
|||
name = 'vertical'
|
||||
main_is_horizontal = False
|
||||
no_minimal_window_borders = True
|
||||
drag_overlay_mode: ClassVar[Literal['full', 'axis_y', 'axis_x', 'free']] = 'axis_y'
|
||||
drag_overlay_mode = DragOverlayMode.axis_y
|
||||
main_axis_layout = Layout.ylayout
|
||||
perp_axis_layout = Layout.xlayout
|
||||
|
||||
|
|
@ -156,6 +156,6 @@ class Horizontal(Vertical):
|
|||
|
||||
name = 'horizontal'
|
||||
main_is_horizontal = True
|
||||
drag_overlay_mode = 'axis_x'
|
||||
drag_overlay_mode = DragOverlayMode.axis_x
|
||||
main_axis_layout = Layout.xlayout
|
||||
perp_axis_layout = Layout.ylayout
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
swap_tabs,
|
||||
sync_os_window_title,
|
||||
)
|
||||
from .layout.base import Layout
|
||||
from .layout.base import DragOverlayMode, Layout
|
||||
from .layout.interface import create_layout_object_for, evict_cached_layouts
|
||||
from .progress import ProgressState
|
||||
from .tab_bar import TabBar, TabBarData, apply_title_template
|
||||
|
|
@ -466,9 +466,9 @@ def on_bell(self, window: Window) -> None:
|
|||
def relayout(self) -> None:
|
||||
if self.allow_relayouts:
|
||||
if self.windows:
|
||||
self.windows._force_show_title_bars = self.force_show_title_bars
|
||||
self.windows.force_show_title_bars = self.force_show_title_bars
|
||||
self.current_layout(self.windows)
|
||||
self.windows._force_show_title_bars = False
|
||||
self.windows.force_show_title_bars = False
|
||||
self.relayout_borders()
|
||||
|
||||
def relayout_borders(self) -> None:
|
||||
|
|
@ -1959,21 +1959,21 @@ def on_window_drop_move(self, window_id: int = 0, is_dest: bool = False, x: int
|
|||
return
|
||||
active_tab = self.active_tab
|
||||
if active_tab is not None:
|
||||
mode = active_tab.current_layout.drag_overlay_mode
|
||||
rel_x = x - central.left
|
||||
g = dest_window.geometry
|
||||
dx = rel_x - (g.left + g.right) / 2
|
||||
dy = rel_y - (g.top + g.bottom) / 2
|
||||
quad_map = {'left': 1, 'right': 2, 'top': 3, 'bottom': 4}
|
||||
if mode == 'axis_y':
|
||||
direction = 'bottom' if dy > 0 else 'top'
|
||||
elif mode == 'axis_x':
|
||||
direction = 'right' if dx > 0 else 'left'
|
||||
elif mode == 'free':
|
||||
direction = ('right' if dx > 0 else 'left') if abs(dx) >= abs(dy) else ('bottom' if dy > 0 else 'top')
|
||||
else: # 'full' (Stack, etc.): full-window overlay, no directional highlight
|
||||
self._set_drag_target_window(dest_window.id, 6)
|
||||
return
|
||||
match active_tab.current_layout.drag_overlay_mode:
|
||||
case DragOverlayMode.axis_y:
|
||||
direction = 'bottom' if dy > 0 else 'top'
|
||||
case DragOverlayMode.axis_x:
|
||||
direction = 'right' if dx > 0 else 'left'
|
||||
case DragOverlayMode.free:
|
||||
direction = ('right' if dx > 0 else 'left') if abs(dx) >= abs(dy) else ('bottom' if dy > 0 else 'top')
|
||||
case DragOverlayMode.full:
|
||||
self._set_drag_target_window(dest_window.id, 6)
|
||||
return
|
||||
self._set_drag_target_window(dest_window.id, quad_map[direction])
|
||||
else:
|
||||
self._set_drag_target_window(0)
|
||||
|
|
@ -2042,13 +2042,13 @@ def on_window_drop(self, x: int, y: int, window_id: int) -> None:
|
|||
g = dest_window.geometry
|
||||
dx = rel_x - (g.left + g.right) / 2
|
||||
dy = rel_y - (g.top + g.bottom) / 2
|
||||
mode = active_tab.current_layout.drag_overlay_mode
|
||||
if mode == 'axis_y':
|
||||
direction: Literal['left', 'right', 'top', 'bottom'] = 'bottom' if dy > 0 else 'top'
|
||||
elif mode == 'axis_x':
|
||||
direction = 'right' if dx > 0 else 'left'
|
||||
else: # 'free' (Splits) or 'full' (swap fallback)
|
||||
direction = ('right' if dx > 0 else 'left') if abs(dx) >= abs(dy) else ('bottom' if dy > 0 else 'top')
|
||||
match active_tab.current_layout.drag_overlay_mode:
|
||||
case DragOverlayMode.axis_y:
|
||||
direction: Literal['left', 'right', 'top', 'bottom'] = 'bottom' if dy > 0 else 'top'
|
||||
case DragOverlayMode.axis_x:
|
||||
direction = 'right' if dx > 0 else 'left'
|
||||
case DragOverlayMode.free | DragOverlayMode.full:
|
||||
direction = ('right' if dx > 0 else 'left') if abs(dx) >= abs(dy) else ('bottom' if dy > 0 else 'top')
|
||||
boss._insert_window_in_direction(w, dest_window, direction)
|
||||
|
||||
def update_progress(self) -> None:
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ def is_visible_in_layout(self) -> bool:
|
|||
|
||||
class WindowList:
|
||||
|
||||
_force_show_title_bars: bool = False
|
||||
force_show_title_bars: bool = False
|
||||
|
||||
def __init__(self, tab: TabType) -> None:
|
||||
self.all_windows: list[WindowType] = []
|
||||
|
|
|
|||
Loading…
Reference in a new issue