From 7c8660a6944727a457e029fd76c5ee8a9754079a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCller?= Date: Wed, 8 May 2024 16:33:04 +0200 Subject: [PATCH] Extend placement_stragegy options placement_strategy previously only accepted 'center' and 'top-left', but others are potentially useful too. I personally like 'bottom-left'. The new set of accepted values mirrors the window_logo_position option. --- kitty/layout/base.py | 31 ++++++++++++++++++++----------- kitty/layout/grid.py | 8 +++++--- kitty/options/definition.py | 5 ++++- kitty/options/parse.py | 2 +- kitty/options/types.py | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/kitty/layout/base.py b/kitty/layout/base.py index 649c2d568..9f9174ce0 100644 --- a/kitty/layout/base.py +++ b/kitty/layout/base.py @@ -50,7 +50,8 @@ class NeighborsMap(TypedDict): class LayoutGlobalData: draw_minimal_borders: bool = True draw_active_borders: bool = True - align_top_left: bool = False + alignment_x: int = 0 + alignment_y: int = 0 central: Region = Region((0, 0, 199, 199, 200, 200)) cell_width: int = 20 @@ -70,7 +71,8 @@ def idx_for_id(win_id: int, windows: Iterable[WindowType]) -> Optional[int]: def set_layout_options(opts: Options) -> None: lgd.draw_minimal_borders = opts.draw_minimal_borders and sum(opts.window_margin_width) == 0 lgd.draw_active_borders = opts.active_border_color is not None - lgd.align_top_left = opts.placement_strategy == 'top-left' + lgd.alignment_x = -1 if opts.placement_strategy.endswith('left') else 1 if opts.placement_strategy.endswith('right') else 0 + lgd.alignment_y = -1 if opts.placement_strategy.startswith('top') else 1 if opts.placement_strategy.startswith('bottom') else 0 def convert_bias_map(bias: Dict[int, float], number_of_windows: int, number_of_cells: int) -> Sequence[float]: @@ -107,7 +109,7 @@ def calculate_cells_map( def layout_dimension( start_at: int, length: int, cell_length: int, decoration_pairs: DecorationPairs, - left_align: bool = False, + alignment: int = 0, bias: Union[None, Sequence[float], Dict[int, float]] = None ) -> LayoutDimension: number_of_windows = len(decoration_pairs) @@ -122,8 +124,10 @@ def layout_dimension( assert sum(cells_map) == number_of_cells extra = length - number_of_cells * cell_length - space_needed_for_decorations - pos = start_at - if not left_align: + pos = start_at # start + if alignment > 0: # end + pos += extra + elif alignment == 0: # center pos += extra // 2 last_i = len(cells_map) - 1 @@ -175,9 +179,14 @@ def window_geometry_from_layouts(x: LayoutData, y: LayoutData) -> WindowGeometry return window_geometry(x.content_pos, x.cells_per_window, y.content_pos, y.cells_per_window, x.space_before, y.space_before, x.space_after, y.space_after) -def layout_single_window(xdecoration_pairs: DecorationPairs, ydecoration_pairs: DecorationPairs, left_align: bool = False) -> WindowGeometry: - x = next(layout_dimension(lgd.central.left, lgd.central.width, lgd.cell_width, xdecoration_pairs, left_align=lgd.align_top_left)) - y = next(layout_dimension(lgd.central.top, lgd.central.height, lgd.cell_height, ydecoration_pairs, left_align=lgd.align_top_left)) +def layout_single_window( + xdecoration_pairs: DecorationPairs, + ydecoration_pairs: DecorationPairs, + xalignment: int = 0, + yalignment: int = 0, +) -> WindowGeometry: + x = next(layout_dimension(lgd.central.left, lgd.central.width, lgd.cell_width, xdecoration_pairs, alignment=xalignment)) + y = next(layout_dimension(lgd.central.top, lgd.central.height, lgd.cell_height, ydecoration_pairs, alignment=yalignment)) return window_geometry_from_layouts(x, y) @@ -333,7 +342,7 @@ def layout_single_window_group(self, wg: WindowGroup, add_blank_rects: bool = Tr wg.decoration('top', border_mult=bw, is_single_window=True), wg.decoration('bottom', border_mult=bw, is_single_window=True), ),) - geom = layout_single_window(xdecoration_pairs, ydecoration_pairs, left_align=lgd.align_top_left) + geom = layout_single_window(xdecoration_pairs, ydecoration_pairs, xalignment=lgd.alignment_x, yalignment=lgd.alignment_y) wg.set_geometry(geom) if add_blank_rects and wg: self.blank_rects.extend(blank_rects_for_window(geom)) @@ -355,7 +364,7 @@ def xlayout( start = lgd.central.left if size is None: size = lgd.central.width - return layout_dimension(start, size, lgd.cell_width, decoration_pairs, bias=bias, left_align=lgd.align_top_left) + return layout_dimension(start, size, lgd.cell_width, decoration_pairs, bias=bias, alignment=lgd.alignment_x) def ylayout( self, @@ -374,7 +383,7 @@ def ylayout( start = lgd.central.top if size is None: size = lgd.central.height - return layout_dimension(start, size, lgd.cell_height, decoration_pairs, bias=bias, left_align=lgd.align_top_left) + return layout_dimension(start, size, lgd.cell_height, decoration_pairs, bias=bias, alignment=lgd.alignment_y) def set_window_group_geometry(self, wg: WindowGroup, xl: LayoutData, yl: LayoutData) -> WindowGeometry: geom = window_geometry_from_layouts(xl, yl) diff --git a/kitty/layout/grid.py b/kitty/layout/grid.py index ebc0a8194..5d4aa8dbd 100644 --- a/kitty/layout/grid.py +++ b/kitty/layout/grid.py @@ -45,7 +45,7 @@ def column_layout( bias: Optional[Sequence[float]] = None, ) -> LayoutDimension: decoration_pairs = tuple(repeat((0, 0), num)) - return layout_dimension(lgd.central.left, lgd.central.width, lgd.cell_width, decoration_pairs, bias=bias, left_align=lgd.align_top_left) + return layout_dimension(lgd.central.left, lgd.central.width, lgd.cell_width, decoration_pairs, bias=bias, alignment=lgd.alignment_x) def row_layout( self, @@ -53,7 +53,7 @@ def row_layout( bias: Optional[Sequence[float]] = None, ) -> LayoutDimension: decoration_pairs = tuple(repeat((0, 0), num)) - return layout_dimension(lgd.central.top, lgd.central.height, lgd.cell_height, decoration_pairs, bias=bias, left_align=lgd.align_top_left) + return layout_dimension(lgd.central.top, lgd.central.height, lgd.cell_height, decoration_pairs, bias=bias, alignment=lgd.alignment_y) def variable_layout(self, layout_func: Callable[..., LayoutDimension], num_windows: int, biased_map: Dict[int, float]) -> LayoutDimension: return layout_func(num_windows, bias=biased_map if num_windows > 1 else None) @@ -157,8 +157,10 @@ def layout(ld: LayoutData, cell_length: int, before_dec: int, after_dec: int) -> number_of_cells = content_size // cell_length cell_area = number_of_cells * cell_length extra = content_size - cell_area - if extra > 0 and not lgd.align_top_left: + if lgd.alignment_x == 0: # center before_dec += extra // 2 + elif lgd.alignment_x > 0: # end + before_dec += extra return LayoutData(start + before_dec, number_of_cells, before_dec, size - cell_area - before_dec, cell_area) def position_window_in_grid_cell(window_idx: int, xl: LayoutData, yl: LayoutData) -> None: diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 8428f07cd..e84c2a002 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -1079,13 +1079,16 @@ ) opt('placement_strategy', 'center', - choices=('center', 'top-left'), + choices=('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'), long_text=''' When the window size is not an exact multiple of the cell size, the cell area of the terminal window will have some extra padding on the sides. You can control how that padding is distributed with this option. Using a value of :code:`center` means the cell area will be placed centrally. A value of :code:`top-left` means the padding will be only at the bottom and right edges. +The value can be one of: :code:`top-left`, :code:`top`, :code:`top-right`, +:code:`left`, :code:`center`, :code:`right`, :code:`bottom-left`, +:code:`bottom`, :code:`bottom-right`. ''' ) diff --git a/kitty/options/parse.py b/kitty/options/parse.py index b08b460fc..cfeb2e3b3 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -1135,7 +1135,7 @@ def placement_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> Non raise ValueError(f"The value {val} is not a valid choice for placement_strategy") ans["placement_strategy"] = val - choices_for_placement_strategy = frozenset(('center', 'top-left')) + choices_for_placement_strategy = frozenset(('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right')) def pointer_shape_when_dragging(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: val = val.lower() diff --git a/kitty/options/types.py b/kitty/options/types.py index dac33a8d6..8ee04f12b 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -23,7 +23,7 @@ choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11'] choices_for_macos_colorspace = typing.Literal['srgb', 'default', 'displayp3'] choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window'] -choices_for_placement_strategy = typing.Literal['center', 'top-left'] +choices_for_placement_strategy = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'] choices_for_pointer_shape_when_dragging = choices_for_default_pointer_shape choices_for_pointer_shape_when_grabbed = choices_for_default_pointer_shape choices_for_strip_trailing_spaces = typing.Literal['always', 'never', 'smart']