From 46fa55ec2ad3506d9a4845b5156f7d8247603db0 Mon Sep 17 00:00:00 2001 From: sbkelley Date: Sun, 30 Nov 2025 00:07:51 -0500 Subject: [PATCH] Move SingleStatusControl to its own file --- src/obs_ctl/__init__.py | 4 +- src/obs_ctl/widget/__init__.py | 149 ----------------- .../widget/element/single_status_control.py | 158 ++++++++++++++++++ 3 files changed, 161 insertions(+), 150 deletions(-) create mode 100644 src/obs_ctl/widget/element/single_status_control.py diff --git a/src/obs_ctl/__init__.py b/src/obs_ctl/__init__.py index 10643af..0350709 100644 --- a/src/obs_ctl/__init__.py +++ b/src/obs_ctl/__init__.py @@ -11,7 +11,9 @@ from textual.widgets import Footer, Header, Label, Placeholder, TabbedContent, T from textual.css.query import NoMatches from . import log, data -from .widget import SingleStatusControl, LabeledLabel, OBSSettingsPane +from .widget import LabeledLabel, OBSSettingsPane + +from .widget.element.single_status_control import SingleStatusControl logger = log.getLogger(__name__) obs_req_client = obs.ReqClient() diff --git a/src/obs_ctl/widget/__init__.py b/src/obs_ctl/widget/__init__.py index 3d57701..cf90886 100644 --- a/src/obs_ctl/widget/__init__.py +++ b/src/obs_ctl/widget/__init__.py @@ -53,155 +53,6 @@ class OBSSettingsPane(VerticalScroll): input.value = value -class SingleStatusControl(Container): - DEFAULT_CSS = """ - .singlestatuscontrol--light { - background:$panel; - text-align:center; - align:center bottom; - width:1fr; - height:1fr; - } - .singlestatuscontrol--on_button { - width:1fr; - height:1fr; - } - .singlestatuscontrol--off_button { - width:1fr; - height:1fr; - } - """ - COMPONENT_CLASSES = { - "singlestatuscontrol--light", - "singlesttauscontrol--on_button", - "singlestatuscontrol--off_button", - } - status = reactive(False) - label = reactive("Status") - on_label = reactive("Start") - off_label = reactive("Stop") - swap_red = reactive(False) - - class MsgBase(Message): - control: "SingleStatusControl" = None - def __init__(self, control): - super().__init__() - self.control = control - class TurnedOn(MsgBase): ... - class TurnedOff(MsgBase): ... - - - def __init__( - self, - *children, - label: str = "Status", - on_label = "Start", - off_label = "Stop", - swap_red = False, - layout = "vertical", - name = None, - id = None, - classes = None, - disabled = False, - markup = True): - super().__init__(*children, name=name, id=id, classes=classes, disabled=disabled, markup=markup) - self.status = False - self.label = label - self.on_label = on_label - self.off_label = off_label - self.swap_red = swap_red - self.set_styles(layout=layout) - - def compose(self) -> ComposeResult: - logger.debug("Composing SingleStatusControl") - with Container(classes="singlestatuscontrol--light"): - yield RadioButton( - label="", - value=False, - button_first=False, - id="light", - compact=True, - disabled=True, - ) - yield Button( - label="Start", - id="on", - variant="success", - compact=True, - classes="singlestatuscontrol--on_button" - ) - yield Button( - label="Stop", - id="off", - variant="error", - compact=True, - classes = "singlestatuscontrol--off_button" - ) - - - def _on_mount(self, event): - # super()._on_mount(event) - self.watch_status(self.status) - self.watch_label(self.label) - self.watch_on_label(self.on_label) - self.watch_off_label(self.off_label) - self.watch_swap_red(self.swap_red) - self.refresh() - - - def on_button_pressed(self, event: Button.Pressed): - if event.button.id == "on": - logger.debug(f"'On' pressed on {event.control}") - self.post_message(self.TurnedOn(self)) - elif event.button.id == "off": - logger.debug(f"'Off' pressed on {event.control}") - self.post_message(self.TurnedOff(self)) - - - def watch_status(self, value: bool) -> None: - try: - light: RadioButton = self.query_exactly_one("#light") - light.value = value - except query.NoMatches: - if self.is_mounted: - raise - - - def watch_label(self, value): - try: - light: RadioButton = self.query_exactly_one("#light") - light.label = value - except query.NoMatches: - if self.is_mounted: - raise - - def watch_on_label(self, value): - try: - on: Button = self.query_exactly_one("#on") - on.label = value - except query.NoMatches: - if self.is_mounted: - raise - - def watch_off_label(self, value): - try: - off: Button = self.query_exactly_one("#off") - off.label = value - except query.NoMatches: - if self.is_mounted: - raise - - def watch_swap_red(self, value): - try: - on: Button = self.query_exactly_one("#on") - off: Button = self.query_exactly_one("#off") - off.variant = "success" if value else "error" - on.variant = "error" if value else "success" - except query.NoMatches: - if self.is_mounted: - raise - - class LabeledLabel(Container): COMPONENT_CLASSES = { "labeledlabel--constant", diff --git a/src/obs_ctl/widget/element/single_status_control.py b/src/obs_ctl/widget/element/single_status_control.py new file mode 100644 index 0000000..bb3f4e1 --- /dev/null +++ b/src/obs_ctl/widget/element/single_status_control.py @@ -0,0 +1,158 @@ +from textual.containers import Container +from textual.message import Message +from textual.reactive import reactive +from textual.css import query +from textual.widget import ComposeResult +from textual.widgets import Button, RadioButton + +from ...log import getLogger + +logger = getLogger() + +class SingleStatusControl(Container): + DEFAULT_CSS = """ + .singlestatuscontrol--light { + background:$panel; + text-align:center; + align:center bottom; + width:1fr; + height:1fr; + } + .singlestatuscontrol--on_button { + width:1fr; + height:1fr; + } + .singlestatuscontrol--off_button { + width:1fr; + height:1fr; + } + """ + COMPONENT_CLASSES = { + "singlestatuscontrol--light", + "singlesttauscontrol--on_button", + "singlestatuscontrol--off_button", + } + status = reactive(False) + label = reactive("Status") + on_label = reactive("Start") + off_label = reactive("Stop") + swap_red = reactive(False) + + class MsgBase(Message): + control: "SingleStatusControl" = None + def __init__(self, control): + super().__init__() + self.control = control + class TurnedOn(MsgBase): ... + class TurnedOff(MsgBase): ... + + + def __init__( + self, + *children, + label: str = "Status", + on_label = "Start", + off_label = "Stop", + swap_red = False, + layout = "vertical", + name = None, + id = None, + classes = None, + disabled = False, + markup = True): + super().__init__(*children, name=name, id=id, classes=classes, disabled=disabled, markup=markup) + self.status = False + self.label = label + self.on_label = on_label + self.off_label = off_label + self.swap_red = swap_red + self.set_styles(layout=layout) + + def compose(self) -> ComposeResult: + logger.debug("Composing SingleStatusControl") + with Container(classes="singlestatuscontrol--light"): + yield RadioButton( + label="", + value=False, + button_first=False, + id="light", + compact=True, + disabled=True, + ) + yield Button( + label="Start", + id="on", + variant="success", + compact=True, + classes="singlestatuscontrol--on_button" + ) + yield Button( + label="Stop", + id="off", + variant="error", + compact=True, + classes = "singlestatuscontrol--off_button" + ) + + + def _on_mount(self, event): + # super()._on_mount(event) + self.watch_status(self.status) + self.watch_label(self.label) + self.watch_on_label(self.on_label) + self.watch_off_label(self.off_label) + self.watch_swap_red(self.swap_red) + self.refresh() + + + def on_button_pressed(self, event: Button.Pressed): + if event.button.id == "on": + logger.debug(f"'On' pressed on {event.control}") + self.post_message(self.TurnedOn(self)) + elif event.button.id == "off": + logger.debug(f"'Off' pressed on {event.control}") + self.post_message(self.TurnedOff(self)) + + + def watch_status(self, value: bool) -> None: + try: + light: RadioButton = self.query_exactly_one("#light") + light.value = value + except query.NoMatches: + if self.is_mounted: + raise + + + def watch_label(self, value): + try: + light: RadioButton = self.query_exactly_one("#light") + light.label = value + except query.NoMatches: + if self.is_mounted: + raise + + def watch_on_label(self, value): + try: + on: Button = self.query_exactly_one("#on") + on.label = value + except query.NoMatches: + if self.is_mounted: + raise + + def watch_off_label(self, value): + try: + off: Button = self.query_exactly_one("#off") + off.label = value + except query.NoMatches: + if self.is_mounted: + raise + + def watch_swap_red(self, value): + try: + on: Button = self.query_exactly_one("#on") + off: Button = self.query_exactly_one("#off") + off.variant = "success" if value else "error" + on.variant = "error" if value else "success" + except query.NoMatches: + if self.is_mounted: + raise \ No newline at end of file -- 2.47.3