4db7165797
- Restructured project into /app, /server, /client with run.py entry point - WSServer (QWebSocketServer) with log_signal, start/stop, client tracking - HTTP server serves /client on port 8080 - Vanilla JS client: faders, toggles, transport, drag-to-arrange, lock/save layout - Start Tablet button + floating Tablet log window in app UI - Preset broadcast on load/switch, DAW state relay, hardware sync via widget_update - Widget colors synced from app palette, toggle state fixed (sends 0/127 correctly) - Layout saved per preset UUID back to presets.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
113 lines
4.0 KiB
Python
113 lines
4.0 KiB
Python
import json
|
|
import os
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QApplication, QMainWindow, QWidget, QVBoxLayout,
|
|
QHBoxLayout, QSlider, QComboBox, QLabel, QPushButton,
|
|
QSizePolicy, QSpinBox, QLineEdit, QInputDialog, QFrame,
|
|
QCheckBox, QMessageBox
|
|
)
|
|
|
|
|
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
PRESETS_DIR = os.path.join(BASE_DIR, "presets")
|
|
PRESETS_FILE = os.path.join(PRESETS_DIR, "presets.json")
|
|
os.makedirs(PRESETS_DIR, exist_ok=True)
|
|
|
|
|
|
|
|
def load_presets_file():
|
|
if os.path.exists(PRESETS_FILE):
|
|
with open(PRESETS_FILE, "r") as f:
|
|
return json.load(f)
|
|
return {"__last_used__": None, "presets": {}}
|
|
|
|
def save_presets_file(data):
|
|
with open(PRESETS_FILE, "w") as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
def ensure_preset_structure(presets):
|
|
if "presets" not in presets:
|
|
return {"__last_used__": None, "presets": presets, "transport_preset": [], "transport_show_hide": False, "io_config": {}}
|
|
if "transport_preset" not in presets:
|
|
presets["transport_preset"] = []
|
|
if "transport_show_hide" not in presets:
|
|
presets["transport_show_hide"] = False
|
|
if "io_config" not in presets:
|
|
presets["io_config"] = {}
|
|
return presets
|
|
|
|
def on_preset_selected(menu_presets: QComboBox, app_window: QMainWindow, ready: bool, loaded_presets: dict, on_load=None):
|
|
|
|
selectedOption = menu_presets.currentText()
|
|
|
|
if ready and selectedOption and selectedOption in loaded_presets["presets"]:
|
|
loaded_presets["__last_used__"] = selectedOption
|
|
save_presets_file(loaded_presets)
|
|
if on_load:
|
|
on_load(loaded_presets["presets"][selectedOption])
|
|
|
|
|
|
def save_preset(app_window: QMainWindow, menu_presets: QComboBox, loaded_presets: dict, on_save=None, on_build=None, on_save_as=None):
|
|
|
|
selectedOption = menu_presets.currentText()
|
|
|
|
if not selectedOption or selectedOption not in loaded_presets["presets"]:
|
|
if on_save_as:
|
|
on_save_as()
|
|
return
|
|
loaded_presets["presets"][selectedOption] = on_build(selectedOption) if on_build else {}
|
|
loaded_presets["__last_used__"] = selectedOption
|
|
save_presets_file(loaded_presets)
|
|
if on_save:
|
|
on_save()
|
|
print(f"Saved preset: {selectedOption}")
|
|
|
|
def save_preset_as(app_window: QMainWindow, menu_presets: QComboBox, loaded_presets: dict, on_save=None, on_refresh=None, on_build=None):
|
|
|
|
print(f"save as button tapped")
|
|
|
|
selectedOption = menu_presets.currentText()
|
|
|
|
selectedOption, ok = QInputDialog.getText(app_window, "Save As", "Preset name:")
|
|
if not ok or not selectedOption.strip():
|
|
return
|
|
selectedOption = selectedOption.strip()
|
|
loaded_presets["presets"][selectedOption] = on_build(selectedOption) if on_build else {}
|
|
loaded_presets["__last_used__"] = selectedOption
|
|
save_presets_file(loaded_presets)
|
|
if on_refresh:
|
|
on_refresh()
|
|
menu_presets.setCurrentText(selectedOption)
|
|
if on_save:
|
|
on_save()
|
|
print(f"Saved preset as: {selectedOption}")
|
|
|
|
|
|
|
|
def delete_preset(app_window: QMainWindow, menu_presets: QComboBox, loaded_presets: dict, on_refresh=None):
|
|
|
|
selectedOption = menu_presets.currentText()
|
|
|
|
if not selectedOption or selectedOption not in loaded_presets["presets"]:
|
|
return
|
|
|
|
msg = QMessageBox(app_window)
|
|
msg.setWindowTitle("Remove Preset")
|
|
msg.setText(f'Are you sure you want to remove "{selectedOption}"?')
|
|
msg.setIcon(QMessageBox.Icon.NoIcon)
|
|
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
|
reply = msg.exec()
|
|
|
|
if reply != QMessageBox.StandardButton.Yes:
|
|
return
|
|
|
|
del loaded_presets["presets"][selectedOption]
|
|
|
|
if loaded_presets["__last_used__"] == selectedOption:
|
|
loaded_presets["__last_used__"] = None
|
|
|
|
save_presets_file(loaded_presets)
|
|
if on_refresh:
|
|
on_refresh()
|
|
print(f"Deleted preset: {selectedOption}") |