diff --git a/README.md b/README.md
index 19ec3e4..fd2d07f 100644
--- a/README.md
+++ b/README.md
@@ -237,9 +237,9 @@ Click on the image to open a full-size web view.
|`tab_bar.border_size` | 0 | Size of the border around tab bars |
|`tab_bar.border_color` | Gruvbox.dark_yellow | Color of border around tab bars |
|`tab_bar.bg_color` | Gruvbox.bg0 | Background color of tab bars, beind their tabs |
-|`tab_bar.tab.min_width` | 50 | Minimum width of a tab on a tab bar |
-|`tab_bar.tab.margin` | 0 | Size of the margin space around individual tabs |
-|`tab_bar.tab.padding` | 20 | Size of the padding space inside individual tabs |
+|`tab_bar.tab.width` | 50 | Width of a tab on a tab bar.
Can be an int or `auto`. If `auto`, the tabs take up as much of the available
screen space as possible.
Note that this width follows the 'margin box'/'principal box' model, so it
includes any configured margin amount. |
+|`tab_bar.tab.margin` | 0 | Size of the space on either outer side of individual tabs. |
+|`tab_bar.tab.padding` | 0 | Size of the space on either inner side of individual tabs. |
|`tab_bar.tab.bg_color` | Gruvbox.bg1 | Background color of individual tabs |
|`tab_bar.tab.fg_color` | Gruvbox.fg1 | Foreground text color of individual tabs |
|`tab_bar.tab.font_family` | Mono | Font family to use for tab titles |
diff --git a/src/qtile_bonsai/layout.py b/src/qtile_bonsai/layout.py
index 72a2144..2182d44 100644
--- a/src/qtile_bonsai/layout.py
+++ b/src/qtile_bonsai/layout.py
@@ -176,15 +176,27 @@ class AddClientMode(enum.Enum):
default_value_label="Gruvbox.bg0",
),
LayoutOption(
- "tab_bar.tab.min_width", 50, "Minimum width of a tab on a tab bar"
+ "tab_bar.tab.width",
+ 50,
+ """
+ Width of a tab on a tab bar.
+
+ Can be an int or `auto`. If `auto`, the tabs take up as much of the
+ available screen space as possible.
+
+ Note that this width follows the 'margin box'/'principal box' model, so it
+ includes any configured margin amount.
+ """,
),
LayoutOption(
- "tab_bar.tab.margin", 0, "Size of the margin space around individual tabs"
+ "tab_bar.tab.margin",
+ 0,
+ "Size of the space on either outer side of individual tabs.",
),
LayoutOption(
"tab_bar.tab.padding",
- 20,
- "Size of the padding space inside individual tabs",
+ 0,
+ "Size of the space on either inner side of individual tabs.",
),
LayoutOption(
"tab_bar.tab.bg_color",
diff --git a/src/qtile_bonsai/tree.py b/src/qtile_bonsai/tree.py
index c44b9dc..f589bc6 100644
--- a/src/qtile_bonsai/tree.py
+++ b/src/qtile_bonsai/tree.py
@@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2023-present Aravinda Rao
# SPDX-License-Identifier: MIT
-
from libqtile.backend.base.drawer import Drawer, TextLayout
from libqtile.backend.base.window import Internal, Window
from libqtile.config import ScreenRect
@@ -58,21 +57,21 @@ def render(self, screen_rect: ScreenRect, tree: "BonsaiTree"):
level = self.tab_level
- tab_bar_border_color = tree.get_config("tab_bar.border_color", level=level)
- tab_bar_bg_color = tree.get_config("tab_bar.bg_color", level=level)
+ tab_bar_border_color: str = tree.get_config("tab_bar.border_color", level=level)
+ tab_bar_bg_color: str = tree.get_config("tab_bar.bg_color", level=level)
- tab_min_width = tree.get_config("tab_bar.tab.min_width", level=level)
- tab_margin = tree.get_config("tab_bar.tab.margin", level=level)
- tab_padding = tree.get_config("tab_bar.tab.padding", level=level)
- tab_font_family = tree.get_config("tab_bar.tab.font_family", level=level)
- tab_font_size = tree.get_config("tab_bar.tab.font_size", level=level)
- tab_bg_color = tree.get_config("tab_bar.tab.bg_color", level=level)
- tab_fg_color = tree.get_config("tab_bar.tab.fg_color", level=level)
+ tab_width: int | str = tree.get_config("tab_bar.tab.width", level=level)
+ tab_margin: int = tree.get_config("tab_bar.tab.margin", level=level)
+ tab_padding: int = tree.get_config("tab_bar.tab.padding", level=level)
+ tab_font_family: str = tree.get_config("tab_bar.tab.font_family", level=level)
+ tab_font_size: float = tree.get_config("tab_bar.tab.font_size", level=level)
+ tab_bg_color: str = tree.get_config("tab_bar.tab.bg_color", level=level)
+ tab_fg_color: str = tree.get_config("tab_bar.tab.fg_color", level=level)
- tab_active_bg_color = tree.get_config(
+ tab_active_bg_color: str = tree.get_config(
"tab_bar.tab.active.bg_color", level=level
)
- tab_active_fg_color = tree.get_config(
+ tab_active_fg_color: str = tree.get_config(
"tab_bar.tab.active.fg_color", level=level
)
@@ -97,9 +96,21 @@ def render(self, screen_rect: ScreenRect, tree: "BonsaiTree"):
self.bar_drawer.clear(tab_bar_bg_color)
- offset = 0
+ if tab_width == "auto":
+ per_tab_w: int = bar_rect.w // len(self.children)
+ else:
+ per_tab_w = tab_width
+
+ # NOTE: This is accurate for monospaced fonts, but is still a safe enough
+ # approximation for non-monospaced fonts as we may only over-estimate.
+ one_char_w, _ = self.bar_drawer.max_layout_size(
+ ["x"], tab_font_family, tab_font_size
+ )
+ per_tab_max_chars = int(
+ (per_tab_w - tab_margin * 2 - tab_padding * 2) / one_char_w
+ )
+
for i, tab in enumerate(self.children):
- # Prime drawers with colors
if tab is self.active_child:
self.bar_drawer.set_source_rgb(tab_active_bg_color)
self.bar_text_layout.colour = tab_active_fg_color
@@ -109,29 +120,29 @@ def render(self, screen_rect: ScreenRect, tree: "BonsaiTree"):
self.bar_text_layout.font_family = tab_font_family
self.bar_text_layout.font_size = tab_font_size
- # Compute space for the tab rect
- tab_title = f"{i + 1}: {tab.title}" if tab.title else f"{i + 1}"
- content_w, _ = self.bar_drawer.max_layout_size(
- [tab_title], tab_font_family, tab_font_size
- )
- principal_w = max(
- tab_min_width, content_w + (2 * tab_margin) + (2 * tab_padding)
- )
tab_box = Box(
- principal_rect=Rect(offset, 0, principal_w, bar_rect.h),
+ principal_rect=Rect(i * per_tab_w, 0, per_tab_w, bar_rect.h),
margin=tab_margin,
border=0, # Individual tabs don't have borders
padding=tab_padding,
)
+ tab_title = f"{i + 1}: {tab.title}" if tab.title else f"{i + 1}"
+ if len(tab_title) > per_tab_max_chars:
+ tab_title = f"{tab_title[:per_tab_max_chars - 1]}…"
+
# Draw the tab
self.bar_drawer.fillrect(
tab_box.border_rect.x, 0, tab_box.border_rect.w, bar_rect.h
)
- self.bar_text_layout.text = tab_title
- self.bar_text_layout.draw(tab_box.content_rect.x, 0)
- offset += principal_w
+ # Draw the tab's title text
+ text_w, _ = self.bar_drawer.max_layout_size(
+ [tab_title], tab_font_family, tab_font_size
+ )
+ self.bar_text_layout.text = tab_title
+ text_offset = (tab_box.content_rect.w - text_w) / 2
+ self.bar_text_layout.draw(tab_box.content_rect.x + text_offset, 0)
self.bar_drawer.draw(0, 0, bar_rect.w, bar_rect.h)