mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-25 17:52:02 +02:00
Let the layout control which window borders are drawn
This commit is contained in:
@@ -8,7 +8,6 @@ from .fast_data_types import (
|
|||||||
BORDERS_PROGRAM, add_borders_rect, compile_program, init_borders_program
|
BORDERS_PROGRAM, add_borders_rect, compile_program, init_borders_program
|
||||||
)
|
)
|
||||||
from .utils import load_shaders
|
from .utils import load_shaders
|
||||||
from .window import Widths
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from enum import IntFlag
|
from enum import IntFlag
|
||||||
@@ -29,19 +28,15 @@ def horizontal_edge(os_window_id, tab_id, color, height, left, right, top):
|
|||||||
add_borders_rect(os_window_id, tab_id, left, top, right, top + height, color)
|
add_borders_rect(os_window_id, tab_id, left, top, right, top + height, color)
|
||||||
|
|
||||||
|
|
||||||
def border(os_window_id, tab_id, color, widths, geometry, base_width=0):
|
def draw_edges(os_window_id, tab_id, colors, width, geometry, base_width=0):
|
||||||
left = geometry.left - (widths.left + base_width)
|
left = geometry.left - (width + base_width)
|
||||||
top = geometry.top - (widths.top + base_width)
|
top = geometry.top - (width + base_width)
|
||||||
right = geometry.right + (widths.right + base_width)
|
right = geometry.right + (width + base_width)
|
||||||
bottom = geometry.bottom + (widths.bottom + base_width)
|
bottom = geometry.bottom + (width + base_width)
|
||||||
if widths.top > 0:
|
horizontal_edge(os_window_id, tab_id, colors[1], width, left, right, top)
|
||||||
horizontal_edge(os_window_id, tab_id, color, widths.top, left, right, top)
|
horizontal_edge(os_window_id, tab_id, colors[3], width, left, right, geometry.bottom + base_width)
|
||||||
if widths.bottom > 0:
|
vertical_edge(os_window_id, tab_id, colors[0], width, top, bottom, left)
|
||||||
horizontal_edge(os_window_id, tab_id, color, widths.bottom, left, right, geometry.bottom + base_width)
|
vertical_edge(os_window_id, tab_id, colors[2], width, top, bottom, geometry.right + base_width)
|
||||||
if widths.left > 0:
|
|
||||||
vertical_edge(os_window_id, tab_id, color, widths.left, top, bottom, left)
|
|
||||||
if widths.right > 0:
|
|
||||||
vertical_edge(os_window_id, tab_id, color, widths.right, top, bottom, geometry.right + base_width)
|
|
||||||
|
|
||||||
|
|
||||||
def load_borders_program():
|
def load_borders_program():
|
||||||
@@ -70,18 +65,27 @@ class Borders:
|
|||||||
for br in chain(current_layout.blank_rects, extra_blank_rects):
|
for br in chain(current_layout.blank_rects, extra_blank_rects):
|
||||||
add_borders_rect(self.os_window_id, self.tab_id, *br, BorderColor.default_bg)
|
add_borders_rect(self.os_window_id, self.tab_id, *br, BorderColor.default_bg)
|
||||||
bw, pw = self.border_width, self.padding_width
|
bw, pw = self.border_width, self.padding_width
|
||||||
|
|
||||||
if bw + pw <= 0:
|
if bw + pw <= 0:
|
||||||
return
|
return
|
||||||
for w in windows:
|
draw_borders = bw > 0 and draw_window_borders and len(windows) > 1
|
||||||
|
if draw_borders:
|
||||||
|
border_data = current_layout.resolve_borders(windows, active_window)
|
||||||
|
|
||||||
|
for i, w in enumerate(windows):
|
||||||
g = w.geometry
|
g = w.geometry
|
||||||
if bw > 0 and draw_window_borders:
|
window_bg = w.screen.color_profile.default_bg
|
||||||
|
window_bg = (window_bg << 8) | BorderColor.window_bg
|
||||||
|
if draw_borders:
|
||||||
# Draw the border rectangles
|
# Draw the border rectangles
|
||||||
color = BorderColor.active if w is active_window else (BorderColor.bell if w.needs_attention else BorderColor.inactive)
|
if w is active_window:
|
||||||
border(self.os_window_id, self.tab_id, color, w.border_widths, g, base_width=pw)
|
color = BorderColor.active
|
||||||
|
else:
|
||||||
|
color = BorderColor.bell if w.needs_attention else BorderColor.inactive
|
||||||
|
colors = tuple(color if needed else window_bg for needed in next(border_data))
|
||||||
|
draw_edges(
|
||||||
|
self.os_window_id, self.tab_id, colors, bw, g, base_width=pw)
|
||||||
if pw > 0:
|
if pw > 0:
|
||||||
widths = Widths(pw)
|
|
||||||
# Draw the background rectangles over the padding region
|
# Draw the background rectangles over the padding region
|
||||||
color = w.screen.color_profile.default_bg
|
colors = (window_bg, window_bg, window_bg, window_bg)
|
||||||
border(
|
draw_edges(
|
||||||
self.os_window_id, self.tab_id, (color << 8) | BorderColor.window_bg, widths, g)
|
self.os_window_id, self.tab_id, colors, pw, g)
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ from .fast_data_types import (
|
|||||||
# Utils {{{
|
# Utils {{{
|
||||||
central = Region((0, 0, 199, 199, 200, 200))
|
central = Region((0, 0, 199, 199, 200, 200))
|
||||||
cell_width = cell_height = 20
|
cell_width = cell_height = 20
|
||||||
|
all_borders = True, True, True, True
|
||||||
|
no_borders = False, False, False, False
|
||||||
|
|
||||||
|
|
||||||
def idx_for_id(win_id, windows):
|
def idx_for_id(win_id, windows):
|
||||||
@@ -22,6 +24,10 @@ def idx_for_id(win_id, windows):
|
|||||||
return i
|
return i
|
||||||
|
|
||||||
|
|
||||||
|
def window_needs_borders(window, active_window):
|
||||||
|
return window is active_window or window.needs_attention
|
||||||
|
|
||||||
|
|
||||||
def layout_dimension(start_at, length, cell_length, decoration_pairs, left_align=False, bias=None):
|
def layout_dimension(start_at, length, cell_length, decoration_pairs, left_align=False, bias=None):
|
||||||
number_of_windows = len(decoration_pairs)
|
number_of_windows = len(decoration_pairs)
|
||||||
number_of_cells = length // cell_length
|
number_of_cells = length // cell_length
|
||||||
@@ -325,9 +331,6 @@ class Layout: # {{{
|
|||||||
windows = all_windows
|
windows = all_windows
|
||||||
self.update_visibility(all_windows, active_window, overlaid_windows)
|
self.update_visibility(all_windows, active_window, overlaid_windows)
|
||||||
self.blank_rects = []
|
self.blank_rects = []
|
||||||
for w in all_windows:
|
|
||||||
w.border_widths.reset(self.border_width)
|
|
||||||
w.neighbors.reset()
|
|
||||||
self.do_layout(windows, active_window_idx)
|
self.do_layout(windows, active_window_idx)
|
||||||
return idx_for_id(active_window.id, all_windows)
|
return idx_for_id(active_window.id, all_windows)
|
||||||
|
|
||||||
@@ -362,6 +365,13 @@ class Layout: # {{{
|
|||||||
|
|
||||||
def do_layout(self, windows, active_window_idx):
|
def do_layout(self, windows, active_window_idx):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def resolve_borders(self, windows, active_window):
|
||||||
|
yield from self.do_resolve_borders(windows, active_window)
|
||||||
|
|
||||||
|
def do_resolve_borders(self, windows, active_window):
|
||||||
|
for w in windows:
|
||||||
|
yield all_borders
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
@@ -433,15 +443,6 @@ class Tall(Layout): # {{{
|
|||||||
def do_layout(self, windows, active_window_idx):
|
def do_layout(self, windows, active_window_idx):
|
||||||
if len(windows) == 1:
|
if len(windows) == 1:
|
||||||
return self.layout_single_window(windows[0])
|
return self.layout_single_window(windows[0])
|
||||||
# setup neighbors
|
|
||||||
if len(windows) == 2:
|
|
||||||
windows[0].neighbors.right = windows[1]
|
|
||||||
windows[1].neighbors.left = windows[0]
|
|
||||||
else:
|
|
||||||
num = len(windows)
|
|
||||||
for i in range(1, num - 1):
|
|
||||||
windows[i].neighbors.bottom = windows[i+1]
|
|
||||||
windows[i+1].neighbors.top = windows[i]
|
|
||||||
xlayout = self.xlayout(2, bias=self.main_bias)
|
xlayout = self.xlayout(2, bias=self.main_bias)
|
||||||
xstart, xnum = next(xlayout)
|
xstart, xnum = next(xlayout)
|
||||||
ystart, ynum = next(self.vlayout(1))
|
ystart, ynum = next(self.vlayout(1))
|
||||||
@@ -459,6 +460,7 @@ class Tall(Layout): # {{{
|
|||||||
self.between_blank_rect(windows[0], windows[1])
|
self.between_blank_rect(windows[0], windows[1])
|
||||||
# left bottom blank rect
|
# left bottom blank rect
|
||||||
self.bottom_blank_rect(windows[0])
|
self.bottom_blank_rect(windows[0])
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
@@ -471,15 +473,6 @@ class Fat(Tall): # {{{
|
|||||||
def do_layout(self, windows, active_window_idx):
|
def do_layout(self, windows, active_window_idx):
|
||||||
if len(windows) == 1:
|
if len(windows) == 1:
|
||||||
return self.layout_single_window(windows[0])
|
return self.layout_single_window(windows[0])
|
||||||
# setup neighbors
|
|
||||||
if len(windows) == 2:
|
|
||||||
windows[0].neighbors.bottom = windows[1]
|
|
||||||
windows[1].neighbors.top = windows[0]
|
|
||||||
else:
|
|
||||||
num = len(windows)
|
|
||||||
for i in range(1, num - 1):
|
|
||||||
windows[i].neighbors.right = windows[i+1]
|
|
||||||
windows[i+1].neighbors.left = windows[i]
|
|
||||||
xstart, xnum = next(self.xlayout(1))
|
xstart, xnum = next(self.xlayout(1))
|
||||||
ylayout = self.ylayout(2, bias=self.main_bias)
|
ylayout = self.ylayout(2, bias=self.main_bias)
|
||||||
ystart, ynum = next(ylayout)
|
ystart, ynum = next(ylayout)
|
||||||
@@ -613,29 +606,6 @@ class Grid(Layout): # {{{
|
|||||||
for i in range(ncols - 1):
|
for i in range(ncols - 1):
|
||||||
self.between_blank_rect(win_col_map[i][0], win_col_map[i + 1][0])
|
self.between_blank_rect(win_col_map[i][0], win_col_map[i + 1][0])
|
||||||
|
|
||||||
self.setup_neighbors(special_rows, nrows, win_col_map)
|
|
||||||
|
|
||||||
def setup_neighbors(self, special_rows, nrows, win_col_map):
|
|
||||||
ncols = len(win_col_map)
|
|
||||||
|
|
||||||
def vertical_neighbors(windows):
|
|
||||||
for i in range(0, len(windows) - 1):
|
|
||||||
windows[i].neighbors.bottom = windows[i+1]
|
|
||||||
windows[i+1].neighbors.top = windows[i]
|
|
||||||
|
|
||||||
if ncols <= 1:
|
|
||||||
vertical_neighbors(win_col_map[0])
|
|
||||||
else:
|
|
||||||
if special_rows != nrows:
|
|
||||||
win_col_map = [cm for cm in win_col_map if len(cm) == nrows]
|
|
||||||
ncols = len(win_col_map)
|
|
||||||
for i, col_windows in enumerate(win_col_map):
|
|
||||||
vertical_neighbors(col_windows)
|
|
||||||
if i < ncols - 1:
|
|
||||||
next_col = win_col_map[i + 1]
|
|
||||||
for w, neighbor in zip(col_windows, next_col):
|
|
||||||
w.neighbors.right = neighbor
|
|
||||||
neighbor.neighbors.left = w
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
@@ -670,11 +640,6 @@ class Vertical(Layout): # {{{
|
|||||||
window_count = len(windows)
|
window_count = len(windows)
|
||||||
if window_count == 1:
|
if window_count == 1:
|
||||||
return self.layout_single_window(windows[0])
|
return self.layout_single_window(windows[0])
|
||||||
# setup neighbors
|
|
||||||
num = len(windows)
|
|
||||||
for i in range(num - 1):
|
|
||||||
windows[i].neighbors.bottom = windows[i+1]
|
|
||||||
windows[i + 1].neighbors.top = windows[i]
|
|
||||||
|
|
||||||
xlayout = self.xlayout(1)
|
xlayout = self.xlayout(1)
|
||||||
xstart, xnum = next(xlayout)
|
xstart, xnum = next(xlayout)
|
||||||
@@ -699,11 +664,6 @@ class Horizontal(Vertical): # {{{
|
|||||||
window_count = len(windows)
|
window_count = len(windows)
|
||||||
if window_count == 1:
|
if window_count == 1:
|
||||||
return self.layout_single_window(windows[0])
|
return self.layout_single_window(windows[0])
|
||||||
# setup neighbors
|
|
||||||
num = len(windows)
|
|
||||||
for i in range(num - 1):
|
|
||||||
windows[i].neighbors.right = windows[i+1]
|
|
||||||
windows[i + 1].neighbors.left = windows[i]
|
|
||||||
|
|
||||||
xlayout = self.variable_layout(window_count, self.biased_map)
|
xlayout = self.variable_layout(window_count, self.biased_map)
|
||||||
ylayout = self.ylayout(1)
|
ylayout = self.ylayout(1)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import sys
|
|||||||
import weakref
|
import weakref
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from operator import attrgetter
|
|
||||||
|
|
||||||
from .child import cwd_of_process
|
from .child import cwd_of_process
|
||||||
from .config import build_ansi_color_table
|
from .config import build_ansi_color_table
|
||||||
@@ -38,45 +37,6 @@ class DynamicColor(IntEnum):
|
|||||||
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
|
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
|
||||||
|
|
||||||
|
|
||||||
def _none():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def neighbor_property(which):
|
|
||||||
getter = attrgetter(which)
|
|
||||||
|
|
||||||
def fget(self):
|
|
||||||
return getter(self)()
|
|
||||||
|
|
||||||
def fset(self, window):
|
|
||||||
setattr(self, which, (_none if window is None else weakref.ref(window)))
|
|
||||||
return property(fget=fget, fset=fset)
|
|
||||||
|
|
||||||
|
|
||||||
class Neighbors:
|
|
||||||
|
|
||||||
__slots__ = '_left', '_top', '_right', '_bottom'
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self._left = self._top = self._right = self._bottom = _none
|
|
||||||
|
|
||||||
left, top, right, bottom = map(neighbor_property, __slots__)
|
|
||||||
|
|
||||||
|
|
||||||
class Widths:
|
|
||||||
|
|
||||||
__slots__ = 'left', 'top', 'right', 'bottom'
|
|
||||||
|
|
||||||
def __init__(self, val=0):
|
|
||||||
self.reset(val)
|
|
||||||
|
|
||||||
def reset(self, val=0):
|
|
||||||
self.left = self.top = self.right = self.bottom = val
|
|
||||||
|
|
||||||
|
|
||||||
DYNAMIC_COLOR_CODES = {
|
DYNAMIC_COLOR_CODES = {
|
||||||
10: DynamicColor.default_fg,
|
10: DynamicColor.default_fg,
|
||||||
11: DynamicColor.default_bg,
|
11: DynamicColor.default_bg,
|
||||||
@@ -134,8 +94,6 @@ class Window:
|
|||||||
|
|
||||||
def __init__(self, tab, child, opts, args, override_title=None):
|
def __init__(self, tab, child, opts, args, override_title=None):
|
||||||
self.action_on_close = None
|
self.action_on_close = None
|
||||||
self.border_widths = Widths()
|
|
||||||
self.neighbors = Neighbors()
|
|
||||||
self.needs_attention = False
|
self.needs_attention = False
|
||||||
self.override_title = override_title
|
self.override_title = override_title
|
||||||
self.overlay_window_id = None
|
self.overlay_window_id = None
|
||||||
|
|||||||
Reference in New Issue
Block a user