Fix mode panels: Screen → Container with on_show/on_hide lifecycle

Textual's ContentSwitcher expects regular Widget/Container children,
not Screen subclasses. Screen's on_mount fires for all children at
once regardless of visibility, so demo workers for all 5 modes
started simultaneously and competed for the bridge.

Container children get proper on_show/on_hide from ContentSwitcher's
visibility toggling — only the active panel's worker runs.
This commit is contained in:
Ryan Malloy 2026-02-13 04:42:59 -07:00
parent 64c33985a3
commit 8da486719a
5 changed files with 23 additions and 28 deletions

View file

@ -5,8 +5,7 @@ waterfall beneath it. Uses threaded workers for the blocking USB sweep.
"""
from textual.app import ComposeResult
from textual.containers import Horizontal, Vertical
from textual.screen import Screen
from textual.containers import Container, Horizontal, Vertical
from textual.widgets import Label, Input, Button, Static, ProgressBar, Checkbox
from textual import work
from textual.worker import Worker
@ -15,7 +14,7 @@ from skywalker_tui.widgets.spectrum_plot import SpectrumPlot
from skywalker_tui.widgets.waterfall import WaterfallDisplay
class SpectrumScreen(Screen):
class SpectrumScreen(Container):
"""Spectrum analyzer with bar chart and optional waterfall."""
DEFAULT_CSS = """
@ -94,11 +93,11 @@ class SpectrumScreen(Screen):
yield Button("Sweep", id="spec-sweep-btn", variant="success")
yield Button("Stop", id="spec-stop-btn", variant="error")
def on_mount(self) -> None:
if self._bridge.is_demo:
def on_show(self) -> None:
if self._bridge.is_demo and not self._sweeping:
self._start_sweep()
def on_unmount(self) -> None:
def on_hide(self) -> None:
self._stop_sweep()
def on_button_pressed(self, event: Button.Pressed) -> None: