Skip to content

Commit 72bd0c9

Browse files
committed
Add vertical tab bars on the left and right
Teach tab_bar_edge about left and right sidebars and route tab layout, hit-testing, and drag/drop through the vertical axis when needed.
1 parent 88a4d90 commit 72bd0c9

11 files changed

Lines changed: 338 additions & 68 deletions

File tree

kitty/boss.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1989,7 +1989,7 @@ def on_drop(self, os_window_id: int, drop: dict[str, bytes] | int, from_self: bo
19891989
window.on_drop(drop)
19901990
break
19911991
elif tab_bar.left <= x < tab_bar.right and tab_bar.top <= y < tab_bar.bottom:
1992-
if (tab_id := tm.tab_bar.tab_id_at(x)) and (tab := self.tab_for_id(tab_id)) and (w := tab.active_window):
1992+
if (tab_id := tm.tab_bar.tab_id_at(x, y)) and (tab := self.tab_for_id(tab_id)) and (w := tab.active_window):
19931993
w.on_drop(drop)
19941994

19951995
def on_drag_source_finished(

kitty/mouse.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,8 @@ mouse_region(bool detect_borders, bool detect_title_bar) {
988988
const bool in_central = mouse_in_region(&central);
989989
if (!in_central) {
990990
if (
991+
(tab_bar.left < central.left && w->mouse_x < central.left) ||
992+
(tab_bar.right > central.right && w->mouse_x >= central.right) ||
991993
(tab_bar.top < central.top && w->mouse_y < central.top) ||
992994
(tab_bar.bottom > central.bottom && w->mouse_y >= central.bottom)
993995
) ans.in_tab_bar = true;

kitty/options/definition.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,18 +1615,22 @@
16151615

16161616
opt('tab_bar_edge', 'bottom',
16171617
option_type='tab_bar_edge', ctype='int',
1618-
long_text='The edge to show the tab bar on, :code:`top` or :code:`bottom`.'
1618+
long_text='The edge to show the tab bar on, :code:`top`, :code:`bottom`, :code:`left` or :code:`right`.'
16191619
)
16201620

16211621
opt('tab_bar_margin_width', '0.0',
16221622
option_type='positive_float',
1623-
long_text='The margin to the left and right of the tab bar (in pts).'
1623+
long_text='''
1624+
The margin perpendicular to the tab bar edge (in pts). For tab bars on the
1625+
top or bottom this is the margin to the left and right. For tab bars on the
1626+
left or right this is the margin above and below.
1627+
'''
16241628
)
16251629

16261630
opt('tab_bar_margin_height', '0.0 0.0',
16271631
option_type='tab_bar_margin_height', ctype='!tab_bar_margin_height',
16281632
long_text='''
1629-
The margin above and below the tab bar (in pts). The first number is the margin
1633+
The margin along the tab bar edge (in pts). The first number is the margin
16301634
between the edge of the OS Window and the tab bar. The second number is the
16311635
margin between the tab bar and the contents of the current tab.
16321636
'''
@@ -1677,7 +1681,8 @@
16771681
opt('tab_bar_align', 'left',
16781682
choices=('left', 'center', 'right'),
16791683
long_text='''
1680-
The horizontal alignment of the tab bar, can be one of: :code:`left`,
1684+
The horizontal alignment of the tab bar. For vertical tab bars this controls the
1685+
alignment of each tab title within the sidebar. Can be one of: :code:`left`,
16811686
:code:`center`, :code:`right`.
16821687
'''
16831688
)
@@ -1745,10 +1750,12 @@
17451750
)
17461751

17471752
opt('tab_title_max_length', '0',
1748-
option_type='positive_int',
1753+
option_type='positive_int', ctype='int',
17491754
long_text='''
17501755
The maximum number of cells that can be used to render the text in a tab.
1751-
A value of zero means that no limit is applied.
1756+
A value of zero means that no limit is applied. For vertical tab bars, kitty
1757+
uses a default sidebar width sized for about twenty title cells when this is
1758+
left unset.
17521759
'''
17531760
)
17541761

kitty/options/to-c-generated.h

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

kitty/options/utils.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,12 @@ def tab_separator(x: str) -> str:
751751

752752

753753
def tab_bar_edge(x: str) -> int:
754-
return {'top': defines.TOP_EDGE, 'bottom': defines.BOTTOM_EDGE}.get(x.lower(), defines.BOTTOM_EDGE)
754+
return {
755+
'left': defines.LEFT_EDGE,
756+
'top': defines.TOP_EDGE,
757+
'right': defines.RIGHT_EDGE,
758+
'bottom': defines.BOTTOM_EDGE,
759+
}.get(x.lower(), defines.BOTTOM_EDGE)
755760

756761

757762
def tab_font_style(x: str) -> tuple[bool, bool]:

kitty/state.c

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -640,29 +640,76 @@ pyset_borders_rects(PyObject *self UNUSED, PyObject *args) {
640640
}
641641

642642

643+
static unsigned
644+
vertical_tab_bar_cols(const OSWindow *os_window, long margin_outer, long margin_inner) {
645+
unsigned cell_width = MAX(1u, os_window->fonts_data->fcm.cell_width);
646+
long available_width = (long)os_window->viewport_width - margin_outer - margin_inner;
647+
if (available_width <= 0) return 0;
648+
unsigned available_cols = MAX(1u, (unsigned)available_width / cell_width);
649+
unsigned title_cols = OPT(tab_title_max_length) > 0 ? (unsigned)OPT(tab_title_max_length) : 20u;
650+
unsigned desired_cols = title_cols + 8u;
651+
unsigned soft_max = available_cols / 3u;
652+
if (soft_max < 6u) soft_max = available_cols;
653+
return MAX(1u, MIN(available_cols, MIN(desired_cols, MAX(1u, soft_max))));
654+
}
655+
643656
void
644657
os_window_regions(const OSWindow *os_window, Region *central, Region *tab_bar) {
645658
if (!OPT(tab_bar_hidden) && os_window->num_tabs && !os_window->has_too_few_tabs) {
646659
long margin_outer = pt_to_px_for_os_window(OPT(tab_bar_margin_height.outer), os_window);
647660
long margin_inner = pt_to_px_for_os_window(OPT(tab_bar_margin_height.inner), os_window);
648661
central->left = 0; central->right = os_window->viewport_width;
649-
unsigned tab_bar_height = os_window->fonts_data->fcm.cell_height + margin_inner + margin_outer;
662+
central->top = 0; central->bottom = os_window->viewport_height;
650663
switch(OPT(tab_bar_edge)) {
651-
case TOP_EDGE:
664+
case TOP_EDGE: {
665+
unsigned tab_bar_height = os_window->fonts_data->fcm.cell_height + margin_inner + margin_outer;
652666
central->top = tab_bar_height;
653667
central->bottom = os_window->viewport_height;
654668
central->top = MIN(central->top, central->bottom);
655669
tab_bar->top = margin_outer;
670+
tab_bar->left = central->left; tab_bar->right = central->right;
671+
tab_bar->bottom = tab_bar->top + os_window->fonts_data->fcm.cell_height;
672+
break;
673+
}
674+
case LEFT_EDGE: {
675+
unsigned left_cols = vertical_tab_bar_cols(os_window, margin_outer, margin_inner);
676+
if (!left_cols) {
677+
zero_at_ptr(tab_bar);
678+
return;
679+
}
680+
unsigned left_width = left_cols * os_window->fonts_data->fcm.cell_width;
681+
central->left = MIN((long)(left_width + margin_inner + margin_outer), (long)central->right);
682+
tab_bar->left = margin_outer;
683+
tab_bar->right = tab_bar->left + left_width;
684+
tab_bar->top = central->top;
685+
tab_bar->bottom = central->bottom;
656686
break;
657-
default:
687+
}
688+
case RIGHT_EDGE: {
689+
unsigned right_cols = vertical_tab_bar_cols(os_window, margin_outer, margin_inner);
690+
if (!right_cols) {
691+
zero_at_ptr(tab_bar);
692+
return;
693+
}
694+
unsigned right_width = right_cols * os_window->fonts_data->fcm.cell_width;
695+
central->right = MAX(0, (long)os_window->viewport_width - (long)(right_width + margin_inner + margin_outer));
696+
tab_bar->left = central->right + margin_inner;
697+
tab_bar->right = tab_bar->left + right_width;
698+
tab_bar->top = central->top;
699+
tab_bar->bottom = central->bottom;
700+
break;
701+
}
702+
default: {
703+
unsigned tab_bar_height = os_window->fonts_data->fcm.cell_height + margin_inner + margin_outer;
658704
central->top = 0;
659705
long bottom = os_window->viewport_height - tab_bar_height;
660706
central->bottom = MAX(0, bottom);
661707
tab_bar->top = central->bottom + margin_inner;
708+
tab_bar->left = central->left; tab_bar->right = central->right;
709+
tab_bar->bottom = tab_bar->top + os_window->fonts_data->fcm.cell_height;
662710
break;
711+
}
663712
}
664-
tab_bar->left = central->left; tab_bar->right = central->right;
665-
tab_bar->bottom = tab_bar->top + os_window->fonts_data->fcm.cell_height;
666713
} else {
667714
zero_at_ptr(tab_bar);
668715
central->left = 0; central->top = 0; central->right = os_window->viewport_width;

kitty/state.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ typedef struct Options {
103103
bool dynamic_background_opacity;
104104
float inactive_text_alpha;
105105
Edge tab_bar_edge;
106+
int tab_title_max_length;
106107
DisableLigature disable_ligatures;
107108
bool force_ltr;
108109
bool resize_in_steps;

0 commit comments

Comments
 (0)