Tab bar: Improve empty space management when some tabs have short titles, allocate the saved space to the active tab
Fixes #5548
This commit is contained in:
parent
a116e3cadd
commit
647b18d345
@ -44,6 +44,8 @@ Detailed list of changes
|
|||||||
|
|
||||||
- X11: Fix a regression in the previous release that caused pasting from GTK based applications to have extra newlines (:iss:`5528`)
|
- X11: Fix a regression in the previous release that caused pasting from GTK based applications to have extra newlines (:iss:`5528`)
|
||||||
|
|
||||||
|
- Tab bar: Improve empty space management when some tabs have short titles, allocate the saved space to the active tab (:iss:`5548`)
|
||||||
|
|
||||||
|
|
||||||
0.26.3 [2022-09-22]
|
0.26.3 [2022-09-22]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import os
|
|||||||
from functools import lru_cache, partial, wraps
|
from functools import lru_cache, partial, wraps
|
||||||
from string import Formatter as StringFormatter
|
from string import Formatter as StringFormatter
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, List, NamedTuple, Optional, Sequence, Tuple, Union
|
Any, Callable, Dict, List, NamedTuple, Optional, Sequence, Tuple, Union,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .borders import Border, BorderColor
|
from .borders import Border, BorderColor
|
||||||
@ -13,7 +13,7 @@ from .config import build_ansi_color_table
|
|||||||
from .constants import config_dir
|
from .constants import config_dir
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
DECAWM, Color, Region, Screen, cell_size_for_window, get_boss, get_options,
|
DECAWM, Color, Region, Screen, cell_size_for_window, get_boss, get_options,
|
||||||
pt_to_px, set_tab_bar_render_data, viewport_for_window
|
pt_to_px, set_tab_bar_render_data, viewport_for_window,
|
||||||
)
|
)
|
||||||
from .rgb import alpha_blend, color_as_sgr, color_from_int, to_color
|
from .rgb import alpha_blend, color_as_sgr, color_from_int, to_color
|
||||||
from .types import WindowGeometry, run_once
|
from .types import WindowGeometry, run_once
|
||||||
@ -151,6 +151,7 @@ class SupSub:
|
|||||||
class ExtraData:
|
class ExtraData:
|
||||||
prev_tab: Optional[TabBarData] = None
|
prev_tab: Optional[TabBarData] = None
|
||||||
next_tab: Optional[TabBarData] = None
|
next_tab: Optional[TabBarData] = None
|
||||||
|
for_layout: bool = False
|
||||||
|
|
||||||
|
|
||||||
def draw_attributed_string(title: str, screen: Screen) -> None:
|
def draw_attributed_string(title: str, screen: Screen) -> None:
|
||||||
@ -435,6 +436,7 @@ class TabBar:
|
|||||||
self.num_tabs = 1
|
self.num_tabs = 1
|
||||||
self.data_buffer_size = 0
|
self.data_buffer_size = 0
|
||||||
self.blank_rects: Tuple[Border, ...] = ()
|
self.blank_rects: Tuple[Border, ...] = ()
|
||||||
|
self.cell_ranges: List[Tuple[int, int]] = []
|
||||||
self.laid_out_once = False
|
self.laid_out_once = False
|
||||||
self.apply_options()
|
self.apply_options()
|
||||||
|
|
||||||
@ -571,31 +573,66 @@ class TabBar:
|
|||||||
if not self.laid_out_once:
|
if not self.laid_out_once:
|
||||||
return
|
return
|
||||||
s = self.screen
|
s = self.screen
|
||||||
s.cursor.x = 0
|
|
||||||
s.erase_in_line(2, False)
|
|
||||||
max_title_length = max(1, (self.screen.columns // max(1, len(data))) - 1)
|
|
||||||
cr = []
|
|
||||||
last_tab = data[-1] if data else None
|
last_tab = data[-1] if data else None
|
||||||
ed = ExtraData()
|
ed = ExtraData()
|
||||||
|
|
||||||
for i, t in enumerate(data):
|
def draw_tab(i: int, tab: TabBarData, cell_ranges: List[Tuple[int, int]], max_tab_length: int, check_overflow: bool = True) -> None:
|
||||||
ed.prev_tab = data[i - 1] if i > 0 else None
|
ed.prev_tab = data[i - 1] if i > 0 else None
|
||||||
ed.next_tab = data[i + 1] if i + 1 < len(data) else None
|
ed.next_tab = data[i + 1] if i + 1 < len(data) else None
|
||||||
s.cursor.bg = as_rgb(self.draw_data.tab_bg(t))
|
s.cursor.bg = as_rgb(self.draw_data.tab_bg(t))
|
||||||
s.cursor.fg = as_rgb(self.draw_data.tab_fg(t))
|
s.cursor.fg = as_rgb(self.draw_data.tab_fg(t))
|
||||||
s.cursor.bold, s.cursor.italic = self.active_font_style if t.is_active else self.inactive_font_style
|
s.cursor.bold, s.cursor.italic = self.active_font_style if t.is_active else self.inactive_font_style
|
||||||
before = s.cursor.x
|
before = s.cursor.x
|
||||||
end = self.draw_func(self.draw_data, s, t, before, max_title_length, i + 1, t is last_tab, ed)
|
end = self.draw_func(self.draw_data, s, t, before, max_tab_length, i + 1, t is last_tab, ed)
|
||||||
s.cursor.bg = s.cursor.fg = 0
|
s.cursor.bg = s.cursor.fg = 0
|
||||||
cr.append((before, end))
|
cell_ranges.append((before, end))
|
||||||
if s.cursor.x > s.columns - max_title_length and t is not last_tab:
|
if check_overflow and s.cursor.x > s.columns - max_tab_length and t is not last_tab:
|
||||||
s.cursor.x = s.columns - 2
|
s.cursor.x = s.columns - 2
|
||||||
s.cursor.bg = as_rgb(color_as_int(self.draw_data.default_bg))
|
s.cursor.bg = as_rgb(color_as_int(self.draw_data.default_bg))
|
||||||
s.cursor.fg = as_rgb(0xff0000)
|
s.cursor.fg = as_rgb(0xff0000)
|
||||||
s.draw(' …')
|
s.draw(' …')
|
||||||
|
raise StopIteration()
|
||||||
|
|
||||||
|
unconstrained_tab_length = max(1, s.columns - 2)
|
||||||
|
ideal_tab_lengths = [i for i in range(len(data))]
|
||||||
|
default_max_tab_length = max(1, (s.columns // max(1, len(data))) - 1)
|
||||||
|
max_tab_lengths = [default_max_tab_length for _ in range(len(data))]
|
||||||
|
active_idx = 0
|
||||||
|
extra = 0
|
||||||
|
ed.for_layout = True
|
||||||
|
for i, t in enumerate(data):
|
||||||
|
s.cursor.x = 0
|
||||||
|
draw_tab(i, t, [], unconstrained_tab_length, check_overflow=False)
|
||||||
|
ideal_tab_lengths[i] = tl = max(1, s.cursor.x)
|
||||||
|
if t.is_active:
|
||||||
|
active_idx = i
|
||||||
|
if tl < default_max_tab_length:
|
||||||
|
max_tab_lengths[i] = tl
|
||||||
|
extra += default_max_tab_length - tl
|
||||||
|
if extra > 0:
|
||||||
|
if ideal_tab_lengths[active_idx] > max_tab_lengths[active_idx]:
|
||||||
|
d = min(extra, ideal_tab_lengths[active_idx] - max_tab_lengths[active_idx])
|
||||||
|
max_tab_lengths[active_idx] += d
|
||||||
|
extra -= d
|
||||||
|
if extra > 0:
|
||||||
|
over_achievers = tuple(i for i in range(len(data)) if ideal_tab_lengths[i] > max_tab_lengths[i])
|
||||||
|
if over_achievers:
|
||||||
|
amt_per_over_achiever = extra // len(over_achievers)
|
||||||
|
if amt_per_over_achiever > 0:
|
||||||
|
for i in over_achievers:
|
||||||
|
max_tab_lengths[i] += amt_per_over_achiever
|
||||||
|
|
||||||
|
s.cursor.x = 0
|
||||||
|
s.erase_in_line(2, False)
|
||||||
|
cr: List[Tuple[int, int]] = []
|
||||||
|
ed.for_layout = False
|
||||||
|
for i, t in enumerate(data):
|
||||||
|
try:
|
||||||
|
draw_tab(i, t, cr, max_tab_lengths[i])
|
||||||
|
except StopIteration:
|
||||||
break
|
break
|
||||||
s.erase_in_line(0, False) # Ensure no long titles bleed after the last tab
|
|
||||||
self.cell_ranges = cr
|
self.cell_ranges = cr
|
||||||
|
s.erase_in_line(0, False) # Ensure no long titles bleed after the last tab
|
||||||
self.align()
|
self.align()
|
||||||
|
|
||||||
def align_with_factor(self, factor: int = 1) -> None:
|
def align_with_factor(self, factor: int = 1) -> None:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user