from prompt_toolkit.formatted_text import HTML, merge_formatted_text
from typing import Callable, Literal, Optional
from rich.console import Console
class BottomBar:
def __init__(self, columns: int = 3):
self.columns = columns
self.console = Console()
self._items: list[Callable[[], HTML]] = []
self._named_items: dict[str, Callable[[], HTML]] = {}
self._states: dict[str, any] = {}
def get_space(self) -> str:
return self.console.width // self.columns
def add_static(self, name: str, text: str) -> None:
def render():
return HTML(f"")
self._add_named(name, render)
def add_counter(self, name: str, label: str, current: int, total: int) -> None:
self._states[name] = (label, current, total)
def render():
l, c, t = self._states[name]
text = f"{l}: {c}/{t}"
return HTML(f"")
self._add_named(name, render)
def add_toggle(self, name: str, label: str, state: bool) -> None:
self._states[name] = (label, state)
def render():
l, s = self._states[name]
color = '#A3BE8C' if s else '#BF616A'
status = "ON" if s else "OFF"
text = f"{l}: {status}"
return HTML(f"")
self._add_named(name, render)
def update_toggle(self, name: str, state: bool) -> None:
if name in self._states:
label, _ = self._states[name]
self._states[name] = (label, state)
def update_counter(self, name: str, current: Optional[int] = None, total: Optional[int] = None) -> None:
if name in self._states:
label, c, t = self._states[name]
self._states[name] = (label, current if current is not None else c, total if total is not None else t)
def _add_named(self, name: str, render_fn: Callable[[], HTML]) -> None:
self._named_items[name] = render_fn
self._items = list(self._named_items.values())
def render(self):
return merge_formatted_text([fn() for fn in self._items])