From 303258a6bb1bac5972b1fa2266090cf9ad979134 Mon Sep 17 00:00:00 2001 From: Andrii Prokhorov Date: Fri, 21 Nov 2025 18:03:45 +0200 Subject: [PATCH] chore: improve dashboard layout --- src/reactor_sim/dashboard.py | 76 ++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/src/reactor_sim/dashboard.py b/src/reactor_sim/dashboard.py index a98ed1c..a29b35b 100644 --- a/src/reactor_sim/dashboard.py +++ b/src/reactor_sim/dashboard.py @@ -155,8 +155,11 @@ class ReactorDashboard: return data_height = height - 6 - left_width = min(max(width - 32, 60), width - 20) - right_width = width - left_width + right_width = max(32, width // 3) + left_width = width - right_width + if left_width < 60: + left_width = min(60, width - 20) + right_width = width - left_width data_win = stdscr.derwin(data_height, left_width, 0, 0) help_win = stdscr.derwin(data_height, right_width, 0, left_width) @@ -177,9 +180,12 @@ class ReactorDashboard: y, "Core", [ - f"Tfuel {state.core.fuel_temperature:8.1f} K Power {state.core.power_output_mw:8.1f} MW", - f"Neutron Flux {state.core.neutron_flux:10.2e} Rods {self.reactor.control.rod_fraction:.3f}", - f"Setpoint {self.reactor.control.setpoint_mw:7.0f} MW Reactivity {state.core.reactivity_margin:+.4f}", + ("Fuel Temp", f"{state.core.fuel_temperature:8.1f} K"), + ("Core Power", f"{state.core.power_output_mw:8.1f} MW"), + ("Neutron Flux", f"{state.core.neutron_flux:10.2e}"), + ("Rods", f"{self.reactor.control.rod_fraction:.3f}"), + ("Setpoint", f"{self.reactor.control.setpoint_mw:7.0f} MW"), + ("Reactivity", f"{state.core.reactivity_margin:+.4f}"), ], ) y = self._draw_section( @@ -187,11 +193,11 @@ class ReactorDashboard: y, "Primary Loop", [ - f"Pump {'ON ' if self.reactor.primary_pump_active else 'OFF'} " - f"Flow {state.primary_loop.mass_flow_rate:7.0f} kg/s", - f"T_in {state.primary_loop.temperature_in:7.1f} K " - f"T_out {state.primary_loop.temperature_out:7.1f} K", - f"Pressure {state.primary_loop.pressure:5.2f} MPa", + ("Pump", "ON" if self.reactor.primary_pump_active else "OFF"), + ("Flow", f"{state.primary_loop.mass_flow_rate:7.0f} kg/s"), + ("Inlet Temp", f"{state.primary_loop.temperature_in:7.1f} K"), + ("Outlet Temp", f"{state.primary_loop.temperature_out:7.1f} K"), + ("Pressure", f"{state.primary_loop.pressure:5.2f} MPa"), ], ) y = self._draw_section( @@ -199,11 +205,11 @@ class ReactorDashboard: y, "Secondary Loop", [ - f"Pump {'ON ' if self.reactor.secondary_pump_active else 'OFF'} " - f"Flow {state.secondary_loop.mass_flow_rate:7.0f} kg/s", - f"T_in {state.secondary_loop.temperature_in:7.1f} K " - f"Pressure {state.secondary_loop.pressure:5.2f} MPa", - f"Steam quality {state.secondary_loop.steam_quality:5.2f}", + ("Pump", "ON" if self.reactor.secondary_pump_active else "OFF"), + ("Flow", f"{state.secondary_loop.mass_flow_rate:7.0f} kg/s"), + ("Inlet Temp", f"{state.secondary_loop.temperature_in:7.1f} K"), + ("Pressure", f"{state.secondary_loop.pressure:5.2f} MPa"), + ("Steam Quality", f"{state.secondary_loop.steam_quality:5.2f}"), ], ) consumer_status = "n/a" @@ -216,10 +222,11 @@ class ReactorDashboard: y, "Turbine / Grid", [ - f"Turbine {'ON ' if self.reactor.turbine_active else 'OFF'} " - f"Electrical {state.turbine.electrical_output_mw:7.1f} MW", - f"Load {state.turbine.load_supplied_mw:7.1f}/{state.turbine.load_demand_mw:7.1f} MW", - f"Consumer {consumer_status} demand {consumer_demand:7.1f} MW", + ("Turbine", "ON" if self.reactor.turbine_active else "OFF"), + ("Electrical", f"{state.turbine.electrical_output_mw:7.1f} MW"), + ("Load", f"{state.turbine.load_supplied_mw:7.1f}/{state.turbine.load_demand_mw:7.1f} MW"), + ("Consumer", f"{consumer_status}"), + ("Demand", f"{consumer_demand:7.1f} MW"), ], ) self._draw_health_bar(win, y + 1) @@ -265,23 +272,30 @@ class ReactorDashboard: win: "curses._CursesWindow", start_y: int, title: str, - lines: list[str], + lines: list[tuple[str, str] | str], ) -> int: height, width = win.getmaxyx() - width -= 4 + inner_width = width - 4 if start_y >= height - 2: return height - 2 - win.addstr(start_y, 2, title[:width], curses.A_BOLD | curses.color_pair(1)) - for idx, line in enumerate(lines, start=start_y + 1): - if idx >= height - 1: + win.addstr(start_y, 2, title[:inner_width], curses.A_BOLD | curses.color_pair(1)) + row = start_y + 1 + for line in lines: + if row >= height - 1: break - win.addstr(idx, 4, line[:width]) - return start_y + len(lines) + 2 + if isinstance(line, tuple): + label, value = line + text = f"{label:<18}: {value}" + else: + text = line + win.addstr(row, 4, text[:inner_width]) + row += 1 + return row + 1 def _draw_health_bar(self, win: "curses._CursesWindow", start_y: int) -> None: win.addstr(start_y, 2, "Component Health", curses.A_BOLD | curses.color_pair(1)) height, width = win.getmaxyx() - bar_width = max(10, min(width - 24, 40)) + bar_width = max(10, min(width - 28, 40)) for idx, (name, comp) in enumerate(self.reactor.health_monitor.components.items(), start=1): filled = int(bar_width * comp.integrity) bar = "█" * filled + "-" * (bar_width - filled) @@ -289,9 +303,11 @@ class ReactorDashboard: row = start_y + idx if row >= height - 1: break - win.addstr(row, 4, f"{name:<12}"[:12], curses.A_BOLD) - win.addstr(row, 16, bar[:bar_width], curses.color_pair(color)) - percent_col = min(width - 8, 18 + bar_width) + label = f"{name:<12}:" + win.addstr(row, 4, label[:14], curses.A_BOLD) + bar_start = 4 + max(len(label), 14) + 1 + win.addstr(row, bar_start, bar[:bar_width], curses.color_pair(color)) + percent_col = min(width - 8, bar_start + bar_width + 2) win.addstr(row, percent_col, f"{comp.integrity*100:5.1f}%", curses.color_pair(color)) def _current_demand(self) -> float: