94 lines
2.7 KiB
Python
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)
|