#!/usr/bin/env python3 """Generate shows/simple.qxw — per-mover position + shared and individual RGBW.""" from __future__ import annotations from pathlib import Path ROOT = Path(__file__).resolve().parents[1] OUT = ROOT / "shows" / "simple.qxw" # Fixture IDs match shows/xchc.qxw CANS = list(range(8)) # BCC145 #1–#8 M1, M2 = 8, 9 MOVERS = [M1, M2] # Can 8ch: Dim=0, R=2, G=3, B=4, W=5 # Mover 43ch: Center Bright=8; RGBW heads 1–7 MOVER_R = [10, 14, 18, 22, 26, 30, 34] MOVER_G = [11, 15, 19, 23, 27, 31, 35] MOVER_B = [12, 16, 20, 24, 28, 32, 36] MOVER_W = [13, 17, 21, 25, 29, 33, 37] COLORS = [ ("R", 2, MOVER_R, "4294901760", "Red"), ("G", 3, MOVER_G, "4278255360", "Green"), ("B", 4, MOVER_B, "4278190335", "Blue"), ("W", 5, MOVER_W, "4294967295", "None"), ] def appearance( fg: str = "Default", bg: str = "Default", frame: str = "Sunken", ) -> str: return f""" {frame} {fg} {bg} None Default """ def slider( wid: int, caption: str, x: int, y: int, w: int, h: int, channels: list[tuple[int, int]], *, value: int = 0, fg: str = "Default", cng: str = "None", ) -> str: ch_xml = "\n".join( f' {ch}' for fid, ch in channels ) return f""" {appearance(fg=fg)} Level {ch_xml} 4294967295 """ def xypad(wid: int, caption: str, fid: int, x: int, y: int, w: int, h: int) -> str: return f""" {appearance()} """ def label_frame(caption: str, x: int, y: int, w: int, h: int) -> str: return f""" Sunken Default Default None Default True True True False False False """ def fixture_xml() -> str: parts = [] for i in range(8): parts.append( f""" beamZ BCC145 8 Channel {i} BCC145 #{i + 1} 0
{87 + i * 8}
8
""" ) for i, addr in enumerate((0, 44)): parts.append( f""" Small Eye 7 Mover 43 Channel {8 + i} Small Eye 7 #{i + 1} 0
{addr}
43
""" ) return "\n".join(parts) def main() -> None: pad_w, pad_h = 240, 240 sl_w, sl_h = 44, 240 ind_w, ind_h = 36, 160 gap = 8 widgets: list[str] = [] wid = 0 max_x = 0 max_y = 0 def place_slider(caption, x, y, w, h, channels, value=0, fg="Default", cng="None"): nonlocal wid, max_x, max_y widgets.append( slider(wid, caption, x, y, w, h, channels, value=value, fg=fg, cng=cng) ) wid += 1 max_x = max(max_x, x + w) max_y = max(max_y, y + h) y0 = 28 x = 10 widgets.append(xypad(wid, "M1 Position", M1, x, y0, pad_w, pad_h)) wid += 1 x += pad_w + gap widgets.append(xypad(wid, "M2 Position", M2, x, y0, pad_w, pad_h)) wid += 1 x += pad_w + gap + 12 max_x = max(max_x, x) max_y = max(max_y, y0 + pad_h) place_slider("C Dim", x, y0, sl_w, sl_h, [(f, 0) for f in CANS], 255, "4294967295") x += sl_w + 2 for name, can_ch, _mover_chs, fg, cng in COLORS: place_slider( f"C {name}", x, y0, sl_w, sl_h, [(f, can_ch) for f in CANS], fg=fg, cng=cng, ) x += sl_w + 2 x += 14 place_slider("M Dim", x, y0, sl_w, sl_h, [(f, 8) for f in MOVERS], 255, "4294967295") x += sl_w + 2 for name, _can_ch, mover_chs, fg, cng in COLORS: place_slider( f"M {name}", x, y0, sl_w, sl_h, [(f, c) for f in MOVERS for c in mover_chs], fg=fg, cng=cng, ) x += sl_w + 2 y1 = y0 + pad_h + 36 x = 10 widgets.append(label_frame("Cans individual RGBW", x, y1 - 28, 200, 24)) for i, fid in enumerate(CANS): col_x = x + i * (4 * (ind_w + 2) + 10) for j, (name, can_ch, _m, fg, cng) in enumerate(COLORS): place_slider( f"{i + 1}{name}", col_x + j * (ind_w + 2), y1, ind_w, ind_h, [(fid, can_ch)], fg=fg, cng=cng, ) mx = x + 8 * (4 * (ind_w + 2) + 10) + 16 widgets.append(label_frame("Movers individual RGBW", mx, y1 - 28, 220, 24)) for mi, (fid, label) in enumerate(((M1, "M1"), (M2, "M2"))): col_x = mx + mi * (4 * (ind_w + 2) + 14) for j, (name, _can_ch, mover_chs, fg, cng) in enumerate(COLORS): place_slider( f"{label}{name}", col_x + j * (ind_w + 2), y1, ind_w, ind_h, [(fid, c) for c in mover_chs], fg=fg, cng=cng, ) total_w = max_x + 16 total_h = max_y + 16 qxw = f""" Q Light Controller Plus 4.12.7 Jimmy {fixture_xml()} BCC145 U 0 0 0 0 0 0 0 0 Small Eye Movers 0 0 None Default Default None Default {"\n".join(widgets)} """ OUT.parent.mkdir(parents=True, exist_ok=True) OUT.write_text(qxw) print(f"Wrote {OUT} ({total_w}x{total_h}, {wid} widgets)") if __name__ == "__main__": main()