Coverage for src/secchi/ui/widgets/panel.py: 82%

33 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-04 22:15 +0000

1"""Reusable titled-box-with-caption panel — the mock's recurring container look.""" 

2 

3from __future__ import annotations 

4 

5import logging 

6 

7from textual.app import ComposeResult 

8from textual.containers import Vertical 

9from textual.widget import Widget 

10from textual.widgets import Static 

11 

12logger = logging.getLogger(__name__) 

13 

14 

15class Panel(Vertical): 

16 """A bordered box with an embedded title and an optional dim caption footer. 

17 

18 Children passed positionally are mounted into the body. Subclasses that need 

19 to build content lazily can override `compose_body()` instead. 

20 """ 

21 

22 def __init__( 

23 self, 

24 title: str, 

25 *children: Widget, 

26 caption: str = "", 

27 id: str | None = None, 

28 classes: str | None = None, 

29 ) -> None: 

30 super().__init__(id=id, classes=classes) 

31 self._title = title 

32 self._body_children = list(children) 

33 self._caption = caption 

34 self.add_class("panel") 

35 

36 def on_mount(self) -> None: 

37 self.border_title = self._title 

38 

39 def compose(self) -> ComposeResult: 

40 body_children = self.compose_body() 

41 yield PanelBody(*body_children) 

42 if self._caption: 

43 yield Static(self._caption, classes="panel-caption") 

44 

45 def compose_body(self) -> list[Widget]: 

46 """Override to build body widgets lazily; default returns ctor children.""" 

47 return self._body_children 

48 

49 def set_caption(self, caption: str) -> None: 

50 self._caption = caption 

51 try: 

52 self.query_one(".panel-caption", Static).update(caption) 

53 except Exception: 

54 # Captions may be updated before the lazily-built body is mounted. 

55 logger.debug("Unable to update panel caption", exc_info=True) 

56 

57 

58class PanelBody(Vertical): 

59 """The flexible-height body region of a Panel (above the caption).""" 

60 

61 def __init__(self, *children: Widget) -> None: 

62 super().__init__(*children) 

63 self.add_class("panel-body")