mathy/collatz_ui/dashboard.py

94 lines
2.7 KiB
Python

from __future__ import annotations
import curses
from pathlib import Path
from .colors import UIColors
from .views import HeaderView, GraphView, NumberView, LogView
class CollatzDashboard:
"""Coordinates curses windows and renders the visualization."""
def __init__(self, stdscr: "curses._CursesWindow", log_dir: Path) -> None:
self.stdscr = stdscr
self.log_dir = log_dir
try:
curses.curs_set(0)
except curses.error:
pass
self.stdscr.nodelay(True)
self.stdscr.timeout(100)
UIColors.setup()
self.num_scroll = 0
self.log_scroll = 0
self._last_step = 0
self._build_views()
def _build_views(self) -> None:
lines = curses.LINES
cols = curses.COLS
header_h = 6
graph_h = 1
available = max(2, lines - header_h - graph_h - 2)
num_h = max(1, (available * 3) // 4)
log_h = max(1, available - num_h)
self.header = HeaderView(header_h, cols, 0, 0)
self.graph = GraphView(graph_h, cols, header_h + 1, 0)
self.number = NumberView(num_h, cols, header_h + graph_h + 1, 0)
self.log = LogView(log_h, cols, header_h + graph_h + num_h + 2, 0, self.log_dir)
def render(
self,
step: int,
elapsed: float,
avg_step: float,
digits: str,
delta_sign: int,
current_calc: float,
last_calc: float,
computing: bool,
) -> None:
self.header.render(
step,
elapsed,
avg_step,
len(digits),
current_calc,
last_calc,
computing,
)
if step > self._last_step:
self.graph.add_delta(delta_sign)
self._last_step = step
else:
self.graph.redraw()
self.num_scroll = self.number.render(digits, self.num_scroll)
self.log_scroll = self.log.render(self.log_scroll)
curses.doupdate()
def handle_input(self, ch: int) -> None:
if ch == curses.KEY_UP:
self.num_scroll = max(0, self.num_scroll - 1)
elif ch == curses.KEY_DOWN:
self.num_scroll += 1
elif ch == curses.KEY_PPAGE:
self.log_scroll = max(0, self.log_scroll - 3)
elif ch == curses.KEY_NPAGE:
self.log_scroll += 3
def show_message(self, message: str, color_pair: int) -> None:
self.stdscr.nodelay(False)
self.stdscr.erase()
try:
self.stdscr.addstr(0, 0, message, UIColors.style(color_pair, bold=True))
except curses.error:
self.stdscr.addstr(0, 0, message)
self.stdscr.refresh()
self.stdscr.getch()
self.stdscr.nodelay(True)
self.stdscr.timeout(10)