Dotfiles/desktopenvs/hyprdrive/supersonic-booster/ui/tabs.py

49 lines
1.8 KiB
Python

"""TabSwitcher — a row of mutually-exclusive toggle buttons driving a
Gtk.Stack, styled as a segmented control (see .sb-tabbar/.sb-tab in
style/style.css). Plain manual mutual exclusion rather than Gtk.CheckButton
grouping, since that's simplest for a small fixed set of tabs."""
from __future__ import annotations
from typing import Callable
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk # noqa: E402
class TabSwitcher(Gtk.Box):
def __init__(self, tabs: list[tuple[str, str, Gtk.Widget]], stack: Gtk.Stack,
on_changed: Callable[[str], None]) -> None:
super().__init__(orientation=Gtk.Orientation.HORIZONTAL, spacing=4)
self.add_css_class("sb-tabbar")
self._stack = stack
self._on_changed = on_changed
self._buttons: dict[str, Gtk.ToggleButton] = {}
first = None
for name, label, _widget in tabs:
btn = Gtk.ToggleButton(label=label)
btn.add_css_class("sb-tab")
btn.connect("toggled", self._make_handler(name))
self.append(btn)
self._buttons[name] = btn
if first is None:
first = name
if first is not None:
self._buttons[first].set_active(True)
def _make_handler(self, name: str):
def handler(btn: Gtk.ToggleButton) -> None:
if not btn.get_active():
if not any(b.get_active() for b in self._buttons.values()):
btn.set_active(True) # one tab must always stay selected
return
for other_name, other_btn in self._buttons.items():
if other_name != name and other_btn.get_active():
other_btn.set_active(False)
self._stack.set_visible_child_name(name)
self._on_changed(name)
return handler