from textual import on
from textual.app import App
-from textual.containers import HorizontalGroup, ScrollableContainer
+from textual.containers import HorizontalGroup, VerticalGroup
from textual.widgets import Footer, Header
# need to import log to initalize logging
class OBSCtlApp(App):
+ DEFAULT_CSS = """
+ """
CSS_PATH = importlib.resources.files(data).joinpath("layout.tcss")
def compose(self):
yield Footer()
yield obs.API(1, id="api")
logger.debug("Composing OBSCtlApp")
- with HorizontalGroup(id="top_block", classes="block"):
- yield RecordControls(id="record_controls", classes="section")
- yield SettingsBlock(id="settings_container", classes="section")
- yield StatsDisplay(id="stats_display", classes="section")
+ with VerticalGroup(classes="content"):
+ with HorizontalGroup(id="top_block", classes="block"):
+ yield RecordControls(id="record_controls", classes="section")
+ yield SettingsBlock(id="settings_container", classes="section")
+ yield StatsDisplay(id="stats_display", classes="section")
@on(obs.API.Report, "#api")
# ------
# Layout
# ------
-#top_block {
- height:3fr;
- min-height:10;
- max-height:30;
- RecordControls { /** ScrollContainer */
- .record_controls--content {
- height:10;
- min-width:30;
- grid-size:2;
+Screen {
+ overflow-x:auto;
+ .content { /** VerticalGroup */
+ /** Gets this small before being scrollable */
+ min-width:74;
+ min-height:20;
+ /** --------------------------------------- */
+ #top_block { /** HorizontalGroup */
+ min-height:10;
+ max-height:14;
+ RecordControls { /** RecordControls (ScrollableContainer) DEFAULT_CSS */
+ align:center middle;
+ min-width:24;
+ max-width:48;
+ .record_controls--content { /** Grid */
+ height:10;
+ min-width:36;
+ grid-size:2;
+ .bool_control--light{ /** RadioButton */
+ width:16;
+ text-align:center;
+ }
+ }
+ }
+ SettingsBlock { /** Container */
+ min-width:50;
+ .obs_settings_pane--content {
+ grid-size:2 1;
+ grid-columns:16 1fr;
+ min-width:36;
+ }
+ }
}
- }
- SettingsBlock { /** Container */
- .obs_settings_pane--content {
- grid-size:2 1;
- grid-columns:16 1fr;
- min-width:36;
+
+ StatsDisplay { /** StatsDisplay (ScrollableContainer) DEFAULT_CSS */
+ align:left middle;
+ min-height:9;
+ max-height:18;
+ min-width:33;
+ .stats_display--content { /** Grid */
+ grid-size:12;
+ min-height:8;
+ max-height:12;
+ min-width:75;
+ max-width:100;
+ .stats_display--top { /** TextReadout */
+ column-span:3;
+ }
+ .stats_display--bottom { /** TextReadout */
+ column-span:4;
+ }
+ TextReadout { /** Container */
+ .text_readout--readout { /** Label (both) */
+ align-horizontal:center;
+ }
+ .text_readout--label { /** Label (top) */
+ align-vertical:bottom;
+ }
+ }
+
+ }
}
}
}
-StatsDisplay {
- height:5fr;
- min-height:10;
- max-height:30;
-
- .stats_display--content {
- grid-size:12;
- min-height:8;
- max-height:12;
- min-width:77;
- }
-
- .stats_display--top {
- column-span:3;
- }
-
- .stats_display--bottom {
- column-span:4;
- }
-}
# ----------
# Aesthetics
# ----------
RecordControls {
- align:center middle;
border:solid $secondary;
padding:0 1;
.bool_control--light {
background:$panel;
- align:center bottom;
}
.record_controls--output_control {
}
StatsDisplay {
- align:center middle;
border:solid $secondary;
padding:1 2;
-}
-
-TextReadout {
- background:$surface;
- border:solid $primary;
-
- .text_readout--readout {
- align-horizontal:center;
- background:$panel;
- }
-
- .text_readout--label {
- align-vertical:bottom;
+ TextReadout {
+ background:$surface;
+ border:solid $primary;
+ .text_readout--readout {
+ background:$panel;
+ }
}
-}
\ No newline at end of file
+}
from textual import on
from textual.app import ComposeResult
-from textual.containers import Container
+from textual import containers
from textual.message import Message
from textual.reactive import reactive
from textual.widgets import Button, RadioButton
logger = getLogger(__name__)
-class BoolControl(Container):
+class BoolControl(containers.Container):
"""BoolControl manages a boolean that belongs to something else.
In other words, it can display true or false and this can be set
|SetTrue|The SetTrue button was clicked |||
|SetFalse|The SetFalse button was clicked |||
# Component Classes
- bool_control--light
- bool_control--true_button
- bool_control--false_button
- """
-
- DEFAULT_CSS = """
- BoolControl {
- Button {
- width:1fr;
- }
- }
+ bool_control--light (RadioButton)
+ bool_control--true_button (Button)
+ bool_control--false_button (Button)
+ bool_control--buttons (Button)
+ bool_control--lightbox (Center)
+ bool_control--buttonbox (Center)
"""
COMPONENT_CLASSES = {
"bool_control--light",
"bool_control--true_button",
"bool_control--false_button",
+ "bool_control--buttons",
+ "bool_control--light_box",
+ "bool_control--buttons_box",
}
value: reactive[bool] = reactive(False)
"""Updates the control's value; turns on or off the light."""
self.set_reactive(BoolControl.control_layout, layout)
def compose(self) -> ComposeResult:
- with Container(classes="bool_control--light"):
+ with containers.Center(classes="bool_control--light_box"):
yield RadioButton(
label="",
value=False,
disabled=True,
classes="bool_control--light",
)
- yield Button(
- label="Start",
- id="true",
- variant="success",
- compact=True,
- classes="bool_control--true_button"
- )
- yield Button(
- label="Stop",
- id="false",
- variant="error",
- compact=True,
- classes = "bool_control--false_button"
- )
+ with containers.Center(classes="bool_control--buttons_box bool_control--box"):
+ yield Button(
+ label="Start",
+ id="true",
+ variant="success",
+ compact=True,
+ classes="bool_control--buttons bool_control--true_button"
+ )
+ yield Button(
+ label="Stop",
+ id="false",
+ variant="error",
+ compact=True,
+ classes = "bool_control--buttons bool_control--false_button"
+ )
def _on_mount(self, event):
|StreamStopped|Posted when streaming is set False.|||
|OBSWSConnected|Posted when obsws_connected is set True.|||
|OBSWSDisconnected|Posted when obsws_disconnected is set False.|||
+ # Component Classes
+ record_controls--content (Grid)
+ record_controls--control (BoolControl)
+ record_controls--obsws_control (BoolControl)
+ record_controls--output_control (BoolControl)
+ record_controls--record_control (BoolControl)
+ record_controls--stream_control (BoolControl)
+ record_controls--pause_control (BoolControl)
"""
- DEFAULT_CSS = """
- .record_controls--content {
- height:auto;
- }
- """
+
COMPONENT_CLASSES = {
"record_controls--control",
"record_controls--output_control",
"record_controls--obsws_control",
- "record_controls--content"
+ "record_controls--content",
+ "record_controls--record_control",
+ "record_controls--stream_control",
+ "record_controls--pause_control",
}
recording: reactive[bool] = reactive(False)
paused: reactive[bool] = reactive(False)
id="obsws_control",
classes = "record_controls--control record_controls--obsws_control"
)
- yield BoolControl(False, label="Record", id="record_control", classes="record_controls--control record_controls--output_control")
- yield BoolControl(False, label="Stream", id="stream_control", classes="record_controls--control record_controls--output_control")
+ yield BoolControl(False, label="Record", id="record_control", classes="record_controls--control record_controls--output_control record_controls--record_control")
+ yield BoolControl(False, label="Stream", id="stream_control", classes="record_controls--control record_controls--output_control record_controls--stream_control")
yield BoolControl(
False,
label="Pause",
false_label="Unpause",
swap_red=True,
id="pause_control",
- classes="record_controls--control record_controls--output_control"
+ classes="record_controls--control record_controls--output_control record_controls--pause_control"
)