from textual import on
from textual.app import App
-from textual.containers import Horizontal, ScrollableContainer
+from textual.containers import HorizontalGroup, ScrollableContainer
from textual.widgets import Footer, Header
# need to import log to initalize logging
yield Footer()
yield obs.API(1, id="api")
logger.debug("Composing OBSCtlApp")
- with Horizontal(id="top_block", classes="block"):
+ 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")
-#top_block {
- RecordControls {
- Grid {
+# ------
+# Layout
+# ------
+#top_block {
+ height:3fr;
+ min-height:10;
+ max-height:30;
+ RecordControls { /** ScrollContainer */
+ .record_controls--content {
+ height:10;
+ min-width:30;
grid-size:2;
- grid-rows:5;
- min-height:10;
}
- .bool_control--light {
- background:$panel;
- text-align:center;
- align:center bottom;
- }
- .bool_control--true_button {
- width:1fr;
- # height:1fr;
- }
- .bool_control--false_button {
- width:1fr;
- # height:1fr;
- }
- .record_controls--output_control {
- background:$surface;
- border:blank;
- }
-
- .record_controls--obsws_control {
- background:$background;
- border:solid $primary;
- }
- }
- SettingsBlock {
- OBSSettings {
- .obssettingspane--input {
- width:1fr;
- }
- Grid {
- grid-size:2 1;
- grid-columns:21 1fr;
- Label {
- width:1fr;
- text-align:right;
- padding-right:1;
- }
- }
+ }
+ SettingsBlock { /** Container */
+ .obs_settings_pane--content {
+ grid-size:2 1;
+ grid-columns:16 1fr;
+ min-width:36;
}
}
}
StatsDisplay {
- Grid {
- grid-size:4;
- grid-rows:4;
+ 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;
}
- TextReadout {
+
+ .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 {
+ background:$surface;
+ border:blank;
+ }
+
+ .record_controls--obsws_control {
+ background:$background;
border:solid $primary;
- width:1fr;
+ }
+}
+
+SettingsBlock {
+ border:solid $secondary;
+ padding:0 1;
+ .obs_settings_pane--scrollbox {
background:$surface;
- .text_readout--label {
- height:1;
- align:center middle;
- }
- .text_readout--text {
- align:center middle;
- }
+ border:solid $primary;
+ padding:0 1;
+ }
+
+ .obs_settings_pane--label {
+ width:1fr;
+ text-align:right;
+ padding-right:1;
+ }
+
+ .obs_settings_pane--input {
+ background:$panel;
}
}
+
+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;
+ }
+}
\ No newline at end of file
"""
DEFAULT_CSS = """
- # .bool_control--light {
- # background:$panel;
- # text-align:center;
- # align:center bottom;
- # width:1fr;
- # height:1;
- # }
- # .bool_control--true_button {
- # width:1fr;
- # height:1fr;
- # }
- # .bool_control--false_button {
- # width:1fr;
- # height:1fr;
- # }
+ BoolControl {
+ Button {
+ width:1fr;
+ }
+ }
"""
COMPONENT_CLASSES = {
"bool_control--light",
# Component Classes
text_readout--label
text_readout--text
- """
- DEFAULT_CSS = """
- # TextReadout {
- # width:1fr;
- # background:$surface;
- # }
+ text_readout--readout
"""
COMPONENT_CLASSES = {
"text_readout--label",
"text_readout--text",
+ "text_readout--readout",
}
text = reactive("Text")
label = reactive("Label")
def compose(self):
- yield Container(Label(self.label, id="label"), classes="text_readout--label")
- yield Container(Label(self.text, id="text"), classes="text_readout--text")
+ yield Container(Label(self.label, id="label"), classes="text_readout--label text_readout--readout")
+ yield Container(Label(self.text, id="text"), classes="text_readout--text text_readout--readout")
def watch_text(self, value: str):
text: Label = self.query_exactly_one("#text")
|OBSWSDisconnected|Posted when obsws_disconnected is set False.|||
"""
DEFAULT_CSS = """
- /*Grid {
- grid-size:2;
- grid-rows:5;
- }*/
+ .record_controls--content {
+ height:auto;
+ }
"""
COMPONENT_CLASSES = {
"record_controls--control",
"record_controls--output_control",
- "record_controls--obsws_control"
+ "record_controls--obsws_control",
+ "record_controls--content"
}
recording: reactive[bool] = reactive(False)
paused: reactive[bool] = reactive(False)
def compose(self):
- with Grid():
+ with Grid(classes="record_controls--content"):
yield BoolControl(
False,
label="OBS WS",
-from textual.containers import VerticalScroll, Grid
+from textual.containers import ScrollableContainer, Grid
from textual.message import Message
from textual.reactive import reactive
from textual.widgets import Label, Input, TabPane
logger = getLogger(__name__)
class OBSSettings(TabPane):
- DEFAULT_CSS = """
- # .obssettingspane--input {
- # width:1fr;
- # }
- # Grid {
- # grid-size:2 1;
- # grid-columns:21 1fr;
- # Label {
- # width:1fr;
- # text-align:right;
- # padding-right:1;
- # }
- # }
- """
COMPONENT_CLASSES = {
- "obssettingspane--input",
+ "obs_settings_pane--input",
+ "obs_settings_pane--output",
+ "obs_settings_pane--content",
+ "obs_settings_pane--scrollbox"
}
record_path: reactive[str] = reactive("")
def compose(self):
- with VerticalScroll():
- with Grid():
- yield Label("Record path:")
- yield Input("path", id="input_record_path", classes="obssettingspane--input", compact=True)
+ with ScrollableContainer(classes="obs_settings_pane--scrollbox"):
+ with Grid(classes="obs_settings_pane--content"):
+ yield Label("Record path:", classes="obs_settings_pane--label")
+ yield Input("path", id="input_record_path", classes="obs_settings_pane--input", compact=True)
def on_input_submitted(self, event:Input.Submitted):
class SettingsBlock(Container):
-
def compose(self):
with TabbedContent(classes="settings_block--tabbed-content"):
yield pane.OBSSettings(id="settings-content", classes="settings_block--obs_settings")
stats_display--dropped_ren
stats_display--dropped_enc
"""
- DEFAULT_CSS = """
- /* StatsDisplay {
- Grid {
- grid-size:4;
- grid-rows:4;
- min-height:8;
- }
- TextReadout {
- border:solid $primary;
- .text_readout--label {
- height:1;
- align:center middle;
- }
- .text_readout--text {
- align:center middle;
- }
- }
- }*/
- """
+
COMPONENT_CLASSES = {
"stats_display--cpu",
"stats_display--ram",
"stats_display--fps",
"stats_display--dropped_net",
"stats_display--droped_ren",
- "stats-display--dropped_enc"
+ "stats_display--dropped_enc",
+ "stats_display--bottom",
+ "stats_display--top",
+ "stats_display--content"
}
def compose(self):
- with Grid():
- yield TextReadout("CPU Usage", "-.-%", id="cpu", classes="stats_display--cpu")
- yield TextReadout("RAM Usage", "-b", id="ram", classes="stats_display--ram")
- yield TextReadout("Time 'til Full", "N/A", id="hdd", classes="stats_display--hdd")
- yield TextReadout("FPS", "--.--", id="fps", classes="stats_display-fps")
- yield TextReadout("Netwrk frames dropped", "-/- (-.-%)", id="dropped_net", classes="stats_display--dropped_net")
- yield TextReadout("Render frames dropped", "-/- (-.-%)", id="dropped_ren", classes="stats_display--dropped_ren")
- yield TextReadout("Encdng frames dropped", "-/- (-.-%)", id="dropped_enc", classes="stats_display--dropped_enc")
+ with Grid(classes="stats_display--content"):
+ yield TextReadout("CPU Usage", "-.-%", id="cpu", classes="stats_display--cpu stats_display--top")
+ yield TextReadout("RAM Usage", "-b", id="ram", classes="stats_display--ram stats_display--top")
+ yield TextReadout("ETA (disk)", "N/A", id="hdd", classes="stats_display--hdd stats_display--top")
+ yield TextReadout("FPS", "--.--", id="fps", classes="stats_display-fps stats_display--top")
+ yield TextReadout("Netwrk frames dropped", "-/- (-.-%)", id="dropped_net", classes="stats_display--dropped_net stats_display--bottom")
+ yield TextReadout("Render frames dropped", "-/- (-.-%)", id="dropped_ren", classes="stats_display--dropped_ren stats_display--bottom")
+ yield TextReadout("Encdng frames dropped", "-/- (-.-%)", id="dropped_enc", classes="stats_display--dropped_enc stats_display--bottom")
def update_text_readouts(self, obs_stats: obs.OBSStats):