Source code for runtimepy.net.server.app.env.widgets

"""
Channel-environment tab widget interfaces.
"""

# built-in
from typing import cast

# third-party
from svgen.element import Element
from svgen.element.html import div

# internal
from runtimepy.channel.environment.command.processor import (
    ChannelCommandProcessor,
)
from runtimepy.enum import RuntimeEnum
from runtimepy.net.html.bootstrap import icon_str
from runtimepy.net.html.bootstrap.elements import (
    flex,
    input_box,
    set_tooltip,
    toggle_button,
)


[docs] def plot_checkbox(parent: Element, name: str) -> None: """Add a checkbox for individual channel plot status.""" container = div(tag="td", parent=parent, class_str="text-center p-0 fs-5") title = f"Enable plotting channel '{name}'." set_tooltip( div( tag="input", type="checkbox", value="", id=f"plot-{name}", allow_no_end_tag=True, parent=div(tag="label", parent=container), class_str="form-check-input rounded-0", title=title, ), title, placement="left", )
[docs] def select_element(**kwargs) -> Element: """Create a select element.""" select = div(tag="select", **kwargs) select.add_class( "form-select", "rounded-0", "border-top-0", "border-bottom-0" ) if "title" in kwargs: select["aria-label"] = kwargs["title"] return select
[docs] def enum_dropdown( parent: Element, name: str, enum: RuntimeEnum, current: int | bool ) -> Element: """Implement a drop down for enumeration options.""" select = select_element( parent=parent, title=f"Enumeration selection for '{name}'.", id=name ) for key, val in cast(dict[str, dict[str, int | bool]], enum.asdict())[ "items" ].items(): opt = div(tag="option", value=val, text=key, parent=select) if current == val: opt.booleans.add("selected") return select
TABLE_BUTTON_CLASSES = ("border-top-0", "border-bottom-0")
[docs] def views_dropdown(parent: Element, command: ChannelCommandProcessor) -> None: """Dropdown menu for channel environment views.""" select = select_element( parent=div( tag="th", parent=parent, class_str="p-0 channel-views-min-width" ), id="filter-view", title="Canonical channel filters.", ).add_class("border-end-0", "w-100") div(tag="option", value="", text="-", parent=select) div(tag="option", value="^$", text="hide", parent=select) for text, value in command.env.views.items(): div(tag="option", value=value, text=text, parent=select)
[docs] def channel_table_header( parent: Element, command: ChannelCommandProcessor ) -> None: """Add header row to channel table.""" env = command.env # Add some controls. ctl_row = div( tag="tr", parent=parent, class_str="bg-body-tertiary border-start border-end", ) # Button for clearing plotted channels. toggle_button( div(tag="th", parent=ctl_row, class_str="text-center p-0"), tooltip="Clear plotted channels.", icon="x-lg", placement="left", id="clear-plotted-channels", title="button for clearing plotted channels", ).add_class(*TABLE_BUTTON_CLASSES) _, label, box = input_box( div( tag="th", parent=ctl_row, class_str="p-0 border-end-0 channel-filter-min-width", ), description="Channel name filter.", pattern=".* ! @ $", label="filter", id="channel-filter", icon="funnel", spellcheck="false", ) label.add_class("border-top-0", "border-bottom-0") box.add_class("border-top-0", "border-bottom-0", "border-end-0") views_dropdown(ctl_row, command) cell = flex( parent=div(tag="th", parent=ctl_row, colspan="2", class_str="p-0") ) # Add a selection menu for custom commands. select = select_element( parent=cell, id="custom-commands", title="Custom command selector." ) if command.custom_commands: for key in command.custom_commands: opt = div(tag="option", value=key, text=key, parent=select) if len(select.children) == 1: opt.booleans.add("selected") # Add button to send command. toggle_button( cell, icon="send", id="send-custom-commands", title="send selected command button", tooltip="Send selected command (left dropdown).", ).add_class(*TABLE_BUTTON_CLASSES) else: div(tag="option", parent=select, value="noop", text="-") select.booleans.add("disabled") # Button for 'reset all defaults' if this tab has more than one channel # with a default value. if env.num_defaults > 1: toggle_button( cell, id="set-defaults", icon="arrow-counterclockwise", tooltip="Reset all channels to their default values.", ).add_class(*TABLE_BUTTON_CLASSES) toggle_button( cell, icon="eye-slash", tooltip="Toggle command channels.", id="toggle-command-channels", title="button for toggling command-channel visibility", icon_classes=["text-info-emphasis"], ).add_class(*TABLE_BUTTON_CLASSES) toggle_button( cell, icon="eye-slash-fill", tooltip="Toggle regular channels.", id="toggle-regular-channels", title="button for toggling regular-channel visibility", ).add_class(*TABLE_BUTTON_CLASSES) toggle_button( cell, icon="trash", tooltip="Clear all plot points.", id="clear-plotted-points", title="button for clearing plot point data", ).add_class("me-auto", *TABLE_BUTTON_CLASSES) # Add header. header_row = div( tag="tr", parent=parent, class_str="border-end text-center bg-body-tertiary", ) icon_classes = ["text-primary-emphasis"] for heading, desc in [ ( icon_str("activity", classes=icon_classes) + "?", "Toggle plotting for channels.", ), ( icon_str("pen", classes=icon_classes) + " name", "Channel names.", ), ( icon_str("database", classes=icon_classes) + " value", "Channel values.", ), ( icon_str("controller", classes=icon_classes) + " controls", "Type-specific channel controls.", ), ( icon_str("braces", classes=icon_classes) + " type", "Channel types.", ), ]: set_tooltip( div( tag="th", scope="col", parent=header_row, text=heading, class_str="text-secondary p-1 border-start text-nowrap", ), "(column) " + desc, placement="left", )
[docs] def value_input_box(name: str, parent: Element) -> Element: """Create an input box for channel values.""" input_container = flex(parent=parent) div( tag="input", type="text", parent=input_container, title=f"Set command value for '{name}'.", id=name, ).add_class( "channel-value-input", "rounded-0", "font-monospace", "form-control", "p-0", "ps-2", "border-0", "text-secondary-emphasis", ) toggle_button( input_container, icon="send", id=name, title=f"Send command value for '{name}'.", ).add_class("pt-0", "pb-0", *TABLE_BUTTON_CLASSES) return input_container