137 lines
5.3 KiB
Python
137 lines
5.3 KiB
Python
"""Modal popup invoked when a device sends a Request BLE Variable(s) op.
|
|
|
|
The dialog lists the variable names the device asked for, pre-fills with the
|
|
current device-profile values (if any), and returns the user's edits via the
|
|
on_submit callback. Clicking Cancel returns None — the BLE client falls back
|
|
to the existing values in that case.
|
|
"""
|
|
|
|
import tkinter as tk
|
|
from tkinter import messagebox
|
|
|
|
|
|
class RequestVariableDialog(tk.Toplevel):
|
|
_BG = "#2D2D3D"
|
|
_ROW_BG = "#252535"
|
|
_ENTRY_BG = "#1E1E2E"
|
|
_FG = "#FFFFFF"
|
|
_DIM_FG = "#AAAAAA"
|
|
_BTN_BG = "#3D3D5C"
|
|
_SAVE_BG = "#0077CC"
|
|
|
|
def __init__(self, parent, mac: str, names: list, current: dict,
|
|
on_submit, play_sound: bool = True):
|
|
super().__init__(parent)
|
|
self.title(f"Variable Request — {mac}")
|
|
self.geometry("520x420")
|
|
self.minsize(380, 240)
|
|
self.configure(bg=self._BG)
|
|
self.transient(parent)
|
|
self.grab_set()
|
|
|
|
self._on_submit = on_submit
|
|
self._mac = mac
|
|
self._names = list(names)
|
|
self._current = dict(current or {})
|
|
self._rows = []
|
|
|
|
try:
|
|
import ctypes
|
|
self.update_idletasks()
|
|
hwnd = ctypes.windll.user32.GetParent(self.winfo_id())
|
|
ctypes.windll.dwmapi.DwmSetWindowAttribute(
|
|
hwnd, 20, ctypes.byref(ctypes.c_int(1)), ctypes.sizeof(ctypes.c_int))
|
|
except Exception:
|
|
pass
|
|
|
|
self._build_ui()
|
|
# Intentionally NOT binding <Return> globally on the Toplevel: a stray
|
|
# Enter keystroke pending in the OS keyboard queue when this dialog
|
|
# focus_force()s itself in would auto-submit before the user types,
|
|
# send empty values back to the device, and "end the routine."
|
|
# Submission goes through the Send to Device button only.
|
|
self.protocol("WM_DELETE_WINDOW", self._cancel)
|
|
|
|
if play_sound:
|
|
try:
|
|
import winsound
|
|
winsound.MessageBeep(winsound.MB_ICONEXCLAMATION)
|
|
except Exception:
|
|
pass
|
|
|
|
self.lift()
|
|
self.focus_force()
|
|
|
|
def _build_ui(self):
|
|
hdr = tk.Frame(self, bg=self._BG)
|
|
hdr.pack(fill="x", padx=14, pady=(12, 4))
|
|
tk.Label(hdr, text="Variable Request", bg=self._BG, fg="#0AACFF",
|
|
font=("Segoe UI", 11, "bold")).pack(side="left")
|
|
tk.Label(hdr, text=f"Device {self._mac}", bg=self._BG, fg=self._DIM_FG,
|
|
font=("Segoe UI", 8)).pack(side="left", padx=(10, 0))
|
|
|
|
tk.Label(self, bg=self._BG, fg=self._DIM_FG, font=("Segoe UI", 8),
|
|
text="Fill in values below; the device will receive them and "
|
|
"the device profile will be updated.").pack(
|
|
anchor="w", padx=14)
|
|
|
|
outer = tk.Frame(self, bg=self._BG)
|
|
outer.pack(fill="both", expand=True, padx=14, pady=8)
|
|
|
|
canvas = tk.Canvas(outer, bg=self._BG, highlightthickness=0)
|
|
scrollbar = tk.Scrollbar(outer, orient="vertical", command=canvas.yview)
|
|
canvas.configure(yscrollcommand=scrollbar.set)
|
|
scrollbar.pack(side="right", fill="y")
|
|
canvas.pack(side="left", fill="both", expand=True)
|
|
|
|
rows_frame = tk.Frame(canvas, bg=self._BG)
|
|
rows_window = canvas.create_window((0, 0), window=rows_frame, anchor="nw")
|
|
rows_frame.bind("<Configure>",
|
|
lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
|
|
canvas.bind("<Configure>",
|
|
lambda e: canvas.itemconfig(rows_window, width=e.width))
|
|
|
|
first_entry = None
|
|
for name in self._names:
|
|
row = tk.Frame(rows_frame, bg=self._ROW_BG, pady=3)
|
|
row.pack(fill="x", pady=2)
|
|
tk.Label(row, text=name, bg=self._ROW_BG, fg=self._FG,
|
|
font=("Segoe UI", 9, "bold"), width=18, anchor="w").pack(
|
|
side="left", padx=(8, 4))
|
|
var = tk.StringVar(value=str(self._current.get(name, "")))
|
|
entry = tk.Entry(row, textvariable=var, bg=self._ENTRY_BG,
|
|
fg=self._FG, insertbackground=self._FG,
|
|
font=("Segoe UI", 9), relief="flat")
|
|
entry.pack(side="left", fill="x", expand=True, padx=(0, 8), ipady=3)
|
|
self._rows.append((name, var))
|
|
if first_entry is None:
|
|
first_entry = entry
|
|
|
|
if first_entry is not None:
|
|
first_entry.focus_set()
|
|
|
|
btns = tk.Frame(self, bg=self._BG)
|
|
btns.pack(fill="x", padx=14, pady=(4, 12))
|
|
tk.Button(btns, text="Cancel", bg=self._BTN_BG, fg=self._FG,
|
|
relief="flat", padx=12, font=("Segoe UI", 9),
|
|
command=self._cancel).pack(side="right", padx=(6, 0))
|
|
tk.Button(btns, text="Send to Device", bg=self._SAVE_BG, fg=self._FG,
|
|
relief="flat", padx=14, font=("Segoe UI", 9, "bold"),
|
|
command=self._submit).pack(side="right")
|
|
|
|
def _submit(self):
|
|
result = {name: var.get() for name, var in self._rows}
|
|
try:
|
|
self._on_submit(result)
|
|
except Exception as e:
|
|
messagebox.showerror("Variable Request", str(e), parent=self)
|
|
return
|
|
self.destroy()
|
|
|
|
def _cancel(self):
|
|
try:
|
|
self._on_submit(None)
|
|
except Exception:
|
|
pass
|
|
self.destroy()
|