175 lines
5 KiB
Python
175 lines
5 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import tkinter as tk
|
|
from tkinter import ttk, messagebox, simpledialog
|
|
from typing import final
|
|
from netbrite import (
|
|
NetBrite,
|
|
NetbriteConnectionException,
|
|
NetbriteTransferException,
|
|
Zone,
|
|
Message,
|
|
)
|
|
|
|
WIDTH = 300
|
|
DEFAULT_ZONE = Zone(0, 0, 150, 7)
|
|
DEFAULT_ZONE_NAME = "default"
|
|
|
|
|
|
@final
|
|
class SignControlGUI(tk.Tk):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.title("SignControl")
|
|
self.geometry(f"{WIDTH}x350")
|
|
self.resizable(False, True)
|
|
|
|
self.devices: list[NetBrite] = []
|
|
|
|
self._build_ui()
|
|
|
|
def _build_ui(self):
|
|
frm_devices = ttk.LabelFrame(self, text="Devices")
|
|
frm_devices.pack(fill="both", expand=True, padx=5, pady=5)
|
|
|
|
self.radios_frame = ttk.Frame(frm_devices)
|
|
self.radios_frame.pack(fill="both", expand=True, padx=5, pady=5)
|
|
|
|
self.selected_index = tk.IntVar(value=-1)
|
|
|
|
btn_frm = ttk.Frame(frm_devices)
|
|
btn_frm.pack(fill="both", padx=5, pady=5)
|
|
ttk.Button(btn_frm, text="Add", command=self._add_device).pack(side="left")
|
|
ttk.Button(btn_frm, text="Remove", command=self._remove_device).pack(
|
|
side="left"
|
|
)
|
|
|
|
frm_msg = ttk.LabelFrame(self, text="Message")
|
|
frm_msg.pack(fill="both", expand=False, padx=5, pady=5)
|
|
self.txt = tk.Text(frm_msg, height=1, wrap="word")
|
|
self.txt.pack(fill="both", expand=False, padx=5, pady=5)
|
|
|
|
hint = (
|
|
"Templates: {scrollon} {scrolloff} {blinkon} {blinkoff} "
|
|
"{left} {center} {right} {erase} {serialnum} {bell} "
|
|
"{red} {green} {yellow}"
|
|
)
|
|
ttk.Label(
|
|
self,
|
|
text=hint,
|
|
font=("Segoe UI", 8),
|
|
foreground="gray",
|
|
wraplength=WIDTH - 20,
|
|
justify="center",
|
|
).pack(
|
|
padx=5,
|
|
pady=(0, 5),
|
|
)
|
|
|
|
btm_btn_frm = ttk.Frame(self)
|
|
btm_btn_frm.pack(fill="y", padx=5, pady=5)
|
|
ttk.Button(btm_btn_frm, text="Send", command=self._send_message).pack(
|
|
side="left"
|
|
)
|
|
ttk.Button(btm_btn_frm, text="Reset", command=self._reset_selected_zone).pack(
|
|
side="left"
|
|
)
|
|
ttk.Button(btm_btn_frm, text="Quit", command=self.quit).pack(side="right")
|
|
|
|
_ = self.bind("<Return>", lambda e: self._send_message())
|
|
|
|
def _get_selection(self) -> tuple[int, NetBrite] | None:
|
|
idx = self.selected_index.get()
|
|
if idx == -1:
|
|
_ = messagebox.showwarning("No device", "Please select a device first.")
|
|
return None
|
|
return idx, self.devices[idx]
|
|
|
|
def _add_device(self):
|
|
ip = simpledialog.askstring("Add device", "IP address:")
|
|
if not ip:
|
|
return
|
|
self._add_device_ip(ip.strip())
|
|
|
|
def _add_device_ip(self, ip: str):
|
|
try:
|
|
device = NetBrite(ip)
|
|
length = len(self.devices)
|
|
|
|
self._reset_zone(device)
|
|
self.devices.append(device)
|
|
|
|
radio = ttk.Radiobutton(
|
|
self.radios_frame,
|
|
text=ip,
|
|
value=length,
|
|
variable=self.selected_index,
|
|
)
|
|
radio.pack(anchor="w")
|
|
|
|
self.selected_index.set(length)
|
|
|
|
except NetbriteConnectionException as exc:
|
|
_ = messagebox.showerror("Connection error", str(exc))
|
|
|
|
def _remove_device(self):
|
|
sel = self._get_selection()
|
|
if sel is None:
|
|
return
|
|
idx, _ = sel
|
|
|
|
_ = self.devices.pop(idx)
|
|
|
|
radio = self.radios_frame.winfo_children()[idx]
|
|
radio.destroy()
|
|
|
|
for new_idx, widget in enumerate(self.radios_frame.winfo_children()):
|
|
if isinstance(widget, ttk.Radiobutton):
|
|
_ = widget.configure(value=new_idx)
|
|
|
|
self.selected_index.set(
|
|
-1 if not self.devices else min(idx, len(self.devices) - 1)
|
|
)
|
|
|
|
def _send_message(self):
|
|
sel = self._get_selection()
|
|
if sel is None:
|
|
return
|
|
|
|
_, dev = sel
|
|
raw_text = self.txt.get("1.0", "end-1c").strip()
|
|
if not raw_text:
|
|
return
|
|
|
|
msg = Message("{erase}" + raw_text)
|
|
try:
|
|
dev.message(msg, DEFAULT_ZONE_NAME)
|
|
self.txt.delete("1.0", "end")
|
|
except NetbriteTransferException as exc:
|
|
_ = messagebox.showerror(
|
|
"Send failed, try removing and adding the device.", str(exc)
|
|
)
|
|
|
|
def _reset_selected_zone(self):
|
|
sel = self._get_selection()
|
|
if sel is None:
|
|
return
|
|
|
|
_, dev = sel
|
|
self._reset_zone(dev)
|
|
|
|
def _reset_zone(self, device: NetBrite):
|
|
zone = DEFAULT_ZONE
|
|
message = Message("hello")
|
|
|
|
try:
|
|
device.zones({DEFAULT_ZONE_NAME: zone})
|
|
device.message(message, DEFAULT_ZONE_NAME)
|
|
except NetbriteTransferException as exc:
|
|
_ = messagebox.showerror(
|
|
"Send failed, try removing and adding the device.", str(exc)
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
SignControlGUI().mainloop()
|