diff --git a/config.json b/config.json index e1fcd3b..bdd5a8e 100644 --- a/config.json +++ b/config.json @@ -2,6 +2,7 @@ "companion": { "host": "127.0.0.1", "port": 8000 }, "page": 19, "page_name": "19\\nStatus", + "nav_keys": ["pagenum"], "variables": { "state": "sp_state", "heartbeat": "sp_hb", "command": "sp_cmd" }, "service_windows": [ diff --git a/make_page.py b/make_page.py index 27c9155..b458607 100644 --- a/make_page.py +++ b/make_page.py @@ -162,8 +162,9 @@ def nav_key(kind, names): def build(cfg): controls = {} + coloured = cfg.get("nav_keys", list(NAV_LOCATIONS)) # which nav keys follow the ALL button for kind, (r, c) in NAV_LOCATIONS.items(): - controls.setdefault(r, {})[c] = nav_key(kind, cfg["variables"]) + controls.setdefault(r, {})[c] = nav_key(kind, cfg["variables"]) if kind in coloured else {"type": kind} for tile in cfg["tiles"]: if "pos" not in tile: continue diff --git a/nav_keys.py b/nav_keys.py index cc5289b..a885f72 100644 --- a/nav_keys.py +++ b/nav_keys.py @@ -1,10 +1,12 @@ #!/usr/bin/env python3 -"""Make the UP / page number / DOWN keys on every page follow the status page's ALL button. +"""Make the page nav keys on every page follow the status page's ALL button. +Which keys follow it is "nav_keys" in config.json (now just the page number). The status page (page 19) carries coloured copies of Companion's own nav keys -(see make_page.py and nav_templates.json). This copies them over the built-in -nav keys on every other page, wherever those sit, using the same "copy button" -call as the Companion UI. Each key keeps its normal press action. +(see make_page.py and nav_templates.json). This copies those over the built-in +keys on every other page, using the same "copy button" call as the Companion UI, +and puts back the built-in key for any kind no longer listed. Each key keeps +its normal press action. python3 nav_keys.py --dry-run list what would change python3 nav_keys.py apply (also refreshes keys already converted) @@ -52,8 +54,12 @@ def nav_kind(control): return None +def is_ours(control): + return (control.get("options", {}).get("notes", "") or "").startswith(NAV_MARKER) + + def find_nav_keys(host, port, status_page): - """[(page, row, column, kind)] for every nav key outside the status page.""" + """[(page, row, column, kind, ours)] for every nav key outside the status page.""" found, page = [], 1 while True: export = page_export(host, port, page) @@ -64,7 +70,7 @@ def find_nav_keys(host, port, status_page): for c, control in cols.items(): kind = nav_kind(control or {}) if kind: - found.append((page, int(r), int(c), kind)) + found.append((page, int(r), int(c), kind, is_ours(control))) page += 1 return found @@ -79,24 +85,28 @@ def main(): args = ap.parse_args() status_page = cfg["page"] + coloured = cfg.get("nav_keys", list(NAV_LOCATIONS)) record = json.load(open(RECORD)) if os.path.exists(RECORD) else {} + found = find_nav_keys(args.host, args.port, status_page) if args.revert: - targets = [(int(k.split("/")[0]), int(k.split("/")[1]), int(k.split("/")[2]), v) for k, v in record.items()] + work = [(p, r, c, k, "restore") for p, r, c, k, ours in found if ours] else: - targets = find_nav_keys(args.host, args.port, status_page) - print("%d nav keys on %d pages" % (len(targets), len({t[0] for t in targets}))) + work = [(p, r, c, k, "colour") for p, r, c, k, ours in found if k in coloured] + work += [(p, r, c, k, "restore") for p, r, c, k, ours in found if ours and k not in coloured] + print("%d nav keys to colour, %d to restore, on %d pages" % ( + sum(1 for w in work if w[4] == "colour"), sum(1 for w in work if w[4] == "restore"), len({w[0] for w in work}))) if args.dry_run: - for t in targets: - print(" page %d row %d col %d: %s" % t) + for w in work: + print(" page %d row %d col %d: %s -> %s" % w) return ws = WebSocket(args.host, args.port, "/trpc") done = 0 try: api = Trpc(ws) - for page, row, col, kind in targets: + for page, row, col, kind, what in work: location = {"pageNumber": page, "row": row, "column": col} - if args.revert: + if what == "restore": api.mutation("controls.resetControl", {"location": location, "newType": kind}) record.pop("%d/%d/%d" % (page, row, col), None) else: @@ -109,7 +119,7 @@ def main(): finally: ws.close() json.dump(record, open(RECORD, "w"), indent=1, sort_keys=True) - print("%s %d nav keys" % ("restored" if args.revert else "coloured", done)) + print("done: %d nav keys changed" % done) if __name__ == "__main__": diff --git a/nav_locations.json b/nav_locations.json index 6aed03b..4bcc570 100644 --- a/nav_locations.json +++ b/nav_locations.json @@ -1,290 +1,98 @@ { - "1/0/0": "pageup", "1/1/0": "pagenum", - "1/2/0": "pagedown", - "10/0/0": "pageup", "10/1/0": "pagenum", - "10/2/0": "pagedown", - "11/0/0": "pageup", "11/1/0": "pagenum", - "11/2/0": "pagedown", - "12/0/0": "pageup", "12/1/0": "pagenum", - "12/2/0": "pagedown", - "13/0/0": "pageup", "13/1/0": "pagenum", - "13/2/0": "pagedown", - "14/0/0": "pageup", "14/1/0": "pagenum", - "14/2/0": "pagedown", - "15/0/0": "pageup", "15/0/1": "pagenum", "15/1/0": "pagenum", - "15/2/0": "pagedown", - "16/0/0": "pageup", "16/1/0": "pagenum", - "16/2/0": "pagedown", - "17/0/0": "pageup", "17/1/0": "pagenum", - "17/2/0": "pagedown", - "18/0/0": "pageup", "18/1/0": "pagenum", - "18/2/0": "pagedown", - "2/0/0": "pageup", "2/1/0": "pagenum", - "2/2/0": "pagedown", - "20/0/0": "pageup", "20/1/0": "pagenum", - "20/2/0": "pagedown", - "21/0/0": "pageup", "21/1/0": "pagenum", - "21/2/0": "pagedown", - "22/0/0": "pageup", "22/1/0": "pagenum", - "22/2/0": "pagedown", - "23/0/0": "pageup", "23/1/0": "pagenum", - "23/2/0": "pagedown", - "24/0/0": "pageup", "24/1/0": "pagenum", - "24/2/0": "pagedown", - "25/0/0": "pageup", "25/1/0": "pagenum", - "25/2/0": "pagedown", - "26/0/0": "pageup", "26/1/0": "pagenum", - "26/2/0": "pagedown", - "27/0/0": "pageup", "27/1/0": "pagenum", - "27/2/0": "pagedown", - "28/0/0": "pageup", "28/1/0": "pagenum", - "28/2/0": "pagedown", - "29/0/0": "pageup", "29/1/0": "pagenum", - "29/2/0": "pagedown", - "3/0/0": "pageup", "3/1/0": "pagenum", - "3/2/0": "pagedown", - "30/0/0": "pageup", "30/1/0": "pagenum", - "30/2/0": "pagedown", - "31/0/0": "pageup", "31/1/0": "pagenum", - "31/2/0": "pagedown", - "32/0/0": "pageup", "32/1/0": "pagenum", - "32/2/0": "pagedown", - "33/0/0": "pageup", "33/1/0": "pagenum", - "33/2/0": "pagedown", - "34/0/0": "pageup", "34/1/0": "pagenum", - "34/2/0": "pagedown", - "35/0/0": "pageup", "35/1/0": "pagenum", - "35/2/0": "pagedown", - "36/0/0": "pageup", "36/1/0": "pagenum", - "36/2/0": "pagedown", - "37/0/0": "pageup", "37/1/0": "pagenum", - "37/2/0": "pagedown", - "38/0/0": "pageup", "38/1/0": "pagenum", - "38/2/0": "pagedown", - "39/0/0": "pageup", "39/1/0": "pagenum", - "39/2/0": "pagedown", - "4/0/0": "pageup", "4/1/0": "pagenum", - "4/2/0": "pagedown", - "40/0/0": "pageup", "40/1/0": "pagenum", - "40/2/0": "pagedown", - "41/0/0": "pageup", "41/1/0": "pagenum", - "41/2/0": "pagedown", - "42/0/0": "pageup", "42/1/0": "pagenum", - "42/2/0": "pagedown", - "43/0/0": "pageup", "43/1/0": "pagenum", - "43/2/0": "pagedown", - "44/0/0": "pageup", "44/1/0": "pagenum", - "44/2/0": "pagedown", - "45/0/0": "pageup", "45/1/0": "pagenum", - "45/2/0": "pagedown", - "46/0/0": "pageup", "46/1/0": "pagenum", - "46/2/0": "pagedown", - "47/0/0": "pageup", "47/1/0": "pagenum", - "47/2/0": "pagedown", - "48/0/0": "pageup", "48/1/0": "pagenum", - "48/2/0": "pagedown", - "49/0/0": "pageup", "49/1/0": "pagenum", - "49/2/0": "pagedown", - "5/0/0": "pageup", "5/1/0": "pagenum", - "5/2/0": "pagedown", - "50/0/0": "pageup", "50/1/0": "pagenum", - "50/2/0": "pagedown", - "51/0/0": "pageup", "51/1/0": "pagenum", - "51/2/0": "pagedown", - "52/0/0": "pageup", "52/1/0": "pagenum", - "52/2/0": "pagedown", - "53/0/0": "pageup", "53/1/0": "pagenum", - "53/2/0": "pagedown", - "54/0/0": "pageup", "54/1/0": "pagenum", - "54/2/0": "pagedown", - "55/0/0": "pageup", "55/1/0": "pagenum", - "55/2/0": "pagedown", - "56/0/0": "pageup", "56/1/0": "pagenum", - "56/2/0": "pagedown", - "57/0/0": "pageup", "57/1/0": "pagenum", - "57/2/0": "pagedown", - "58/0/0": "pageup", "58/1/0": "pagenum", - "58/2/0": "pagedown", - "59/0/0": "pageup", "59/1/0": "pagenum", - "59/2/0": "pagedown", - "6/0/0": "pageup", "6/1/0": "pagenum", - "6/2/0": "pagedown", - "60/0/0": "pageup", "60/1/0": "pagenum", - "60/2/0": "pagedown", - "61/0/0": "pageup", "61/1/0": "pagenum", - "61/2/0": "pagedown", - "62/0/0": "pageup", "62/1/0": "pagenum", - "62/2/0": "pagedown", - "63/0/0": "pageup", "63/1/0": "pagenum", - "63/2/0": "pagedown", - "64/0/0": "pageup", "64/1/0": "pagenum", - "64/2/0": "pagedown", - "65/0/0": "pageup", "65/1/0": "pagenum", - "65/2/0": "pagedown", - "66/0/0": "pageup", "66/1/0": "pagenum", - "66/2/0": "pagedown", - "67/0/0": "pageup", "67/1/0": "pagenum", - "67/2/0": "pagedown", - "68/0/0": "pageup", "68/1/0": "pagenum", - "68/2/0": "pagedown", - "69/0/0": "pageup", "69/1/0": "pagenum", - "69/2/0": "pagedown", - "7/0/0": "pageup", "7/1/0": "pagenum", - "7/2/0": "pagedown", - "70/0/0": "pageup", "70/1/0": "pagenum", - "70/2/0": "pagedown", - "71/0/0": "pageup", "71/1/0": "pagenum", - "71/2/0": "pagedown", - "72/0/0": "pageup", "72/1/0": "pagenum", - "72/2/0": "pagedown", - "73/0/0": "pageup", "73/1/0": "pagenum", - "73/2/0": "pagedown", - "74/0/0": "pageup", "74/1/0": "pagenum", - "74/2/0": "pagedown", - "75/0/0": "pageup", "75/1/0": "pagenum", - "75/2/0": "pagedown", - "76/0/0": "pageup", "76/1/0": "pagenum", - "76/2/0": "pagedown", - "77/0/0": "pageup", "77/1/0": "pagenum", - "77/2/0": "pagedown", - "78/0/0": "pageup", "78/1/0": "pagenum", - "78/2/0": "pagedown", - "79/0/0": "pageup", "79/1/0": "pagenum", - "79/2/0": "pagedown", - "8/0/0": "pageup", "8/1/0": "pagenum", - "8/2/0": "pagedown", - "80/0/0": "pageup", "80/1/0": "pagenum", - "80/2/0": "pagedown", - "81/0/0": "pageup", "81/1/0": "pagenum", - "81/2/0": "pagedown", - "82/0/0": "pageup", "82/1/0": "pagenum", - "82/2/0": "pagedown", - "83/0/0": "pageup", "83/1/0": "pagenum", - "83/2/0": "pagedown", - "84/0/0": "pageup", "84/1/0": "pagenum", - "84/2/0": "pagedown", - "85/0/0": "pageup", "85/1/0": "pagenum", - "85/2/0": "pagedown", - "86/0/0": "pageup", "86/1/0": "pagenum", - "86/2/0": "pagedown", - "87/0/0": "pageup", "87/1/0": "pagenum", - "87/2/0": "pagedown", - "88/0/0": "pageup", "88/1/0": "pagenum", - "88/2/0": "pagedown", - "89/0/0": "pageup", "89/1/0": "pagenum", - "89/2/0": "pagedown", - "9/0/0": "pageup", "9/1/0": "pagenum", - "9/2/0": "pagedown", - "90/0/0": "pageup", "90/1/0": "pagenum", - "90/2/0": "pagedown", - "91/0/0": "pageup", "91/1/0": "pagenum", - "91/2/0": "pagedown", - "92/0/0": "pageup", "92/1/0": "pagenum", - "92/2/0": "pagedown", - "93/0/0": "pageup", "93/1/0": "pagenum", - "93/2/0": "pagedown", - "94/0/0": "pageup", "94/1/0": "pagenum", - "94/2/0": "pagedown", - "95/0/0": "pageup", "95/1/0": "pagenum", - "95/2/0": "pagedown", - "96/0/0": "pageup", - "96/2/0": "pagedown", - "97/0/0": "pageup", - "97/1/0": "pagenum", - "97/2/0": "pagedown" + "97/1/0": "pagenum" } \ No newline at end of file diff --git a/status-page.companionconfig b/status-page.companionconfig index a395e4c..09bc048 100644 Binary files a/status-page.companionconfig and b/status-page.companionconfig differ diff --git a/tests/test_status_panel.py b/tests/test_status_panel.py index c7fcd27..62c7952 100644 --- a/tests/test_status_panel.py +++ b/tests/test_status_panel.py @@ -555,7 +555,9 @@ class TestPage(unittest.TestCase): def test_layout(self): self.assertEqual(self.export["type"], "page") self.assertEqual(self.export["oldPageNumber"], 19) - for (r, kind, action) in (("0", "pageup", "inc_page"), ("1", "pagenum", "set_page"), ("2", "pagedown", "dec_page")): + self.assertEqual(self.controls["0"]["0"], {"type": "pageup"}) # only the page number follows ALL + self.assertEqual(self.controls["2"]["0"], {"type": "pagedown"}) + for (r, kind, action) in (("1", "pagenum", "set_page"),): key = self.controls[r]["0"] self.assertEqual(key["type"], "button-layered") self.assertTrue(key["options"]["notes"].startswith("STATUS nav key (%s)" % kind)) @@ -565,7 +567,7 @@ class TestPage(unittest.TestCase): self.assertIn("'$.all.b'", box["color"]["value"]) # follows the ALL button positioned = [t for t in CONFIG["tiles"] if "pos" in t] n = sum(1 for r in self.controls.values() for c in r.values() if c["type"] == "button-layered") - self.assertEqual(n, len(positioned) + 3) # + the three nav keys + self.assertEqual(n, len(positioned) + 1) # + the page number key # The master is where the smallest Stream Deck can see it. self.assertEqual(CONFIG["tiles"][0]["pos"], [0, 1])