diff --git a/main.py b/main.py index c44a35e..770fe38 100644 --- a/main.py +++ b/main.py @@ -166,6 +166,14 @@ buttonImport = QPushButton("Import") buttonImport.setFixedWidth(55) buttonImport.clicked.connect(lambda: import_preset()) +buttonDuplicate = QPushButton("Duplicate") +buttonDuplicate.setFixedWidth(75) +buttonDuplicate.clicked.connect(lambda: duplicate_preset()) + +buttonRename = QPushButton("Rename") +buttonRename.setFixedWidth(65) +buttonRename.clicked.connect(lambda: rename_preset()) + checkbox_lock_preset = QCheckBox("Lock Preset") checkbox_lock_preset.setStyleSheet("color: #aaa; font-size: 11px;") checkbox_lock_preset.setChecked(True) @@ -578,32 +586,29 @@ _section_sep.setFrameShape(QFrame.Shape.HLine) _section_sep.setStyleSheet("color: #3a3a3a;") vstack_layout_panel.addWidget(_section_sep) -# Section rows (layout only — not wired yet) -_section_rows = [ - ("Preset Browser", "chk_section_preset_browser"), - ("Big Title", "chk_section_big_title"), - ("Fader Row", "chk_section_fader_row"), - ("Toggle Row", "chk_section_toggle_row"), - ("Transport Row", "chk_section_transport_row"), -] -from PyQt6.QtWidgets import QCheckBox -for _lbl, _attr in _section_rows: - _row = QWidget() - _row.setStyleSheet("background: transparent;") - _hbox = QHBoxLayout(_row) - _hbox.setContentsMargins(4, 2, 4, 2) - _hbox.setSpacing(8) - _chk = QCheckBox() - _chk.setChecked(True) - _chk.setFixedSize(16, 16) - _name_lbl = QLabel(_lbl) - _name_lbl.setStyleSheet("color: #d4d4d4; font-size: 12px; background: transparent;") - _hbox.addWidget(_chk) - _hbox.addWidget(_name_lbl) - _hbox.addStretch() - globals()[_attr] = _chk - vstack_layout_panel.addWidget(_row) -del _lbl, _attr, _row, _hbox, _chk, _name_lbl, _section_rows +_section_btn_style = ( + "QPushButton { background: transparent; border: none; color: #ffffff;" + " font-size: 12px; font-weight: bold; text-align: left; padding: 4px 6px; }" + "QPushButton:!checked { color: #444444; font-weight: normal; }" +) + +def _make_section_row(label_text): + btn = QPushButton(label_text) + btn.setCheckable(True) + btn.setChecked(True) + btn.setFlat(True) + btn.setStyleSheet(_section_btn_style) + return btn + +chk_section_preset_browser = _make_section_row("Preset Browser") +chk_section_big_title = _make_section_row("Big Title") +chk_section_fader_row = _make_section_row("Fader Row") +chk_section_toggle_row = _make_section_row("Toggle Row") +chk_section_transport_row = _make_section_row("Transport Row") + +for _btn in (chk_section_preset_browser, chk_section_big_title, chk_section_fader_row, chk_section_toggle_row, chk_section_transport_row): + vstack_layout_panel.addWidget(_btn) +del _btn vstack_layout_panel.addStretch() @@ -855,6 +860,8 @@ class MainWindow(QMainWindow): hstack_preset_row.addWidget(buttonSave) #save button hstack_preset_row.addWidget(buttonSaveAs) #save as button hstack_preset_row.addWidget(buttonRemove) #remove button + hstack_preset_row.addWidget(buttonDuplicate) + hstack_preset_row.addWidget(buttonRename) hstack_preset_row.addWidget(buttonExport) hstack_preset_row.addWidget(buttonImport) hstack_preset_row.addWidget(checkbox_lock_preset) @@ -1118,9 +1125,15 @@ class MainWindow(QMainWindow): container_midi_out_log.setVisible(False) #MARK: LAYOUT PANEL - container_layout_panel.setVisible(False) + container_layout_panel.setVisible(True) + button_layout_panel.setChecked(True) - main_layout.addWidget(make_separator()) + container_transport_row = QWidget() + _vbox_transport_row = QVBoxLayout(container_transport_row) + _vbox_transport_row.setContentsMargins(0, 0, 0, 0) + _vbox_transport_row.setSpacing(0) + _vbox_transport_row.addWidget(make_separator()) + _vbox_transport_row.addSpacing(4) # MARK: TRANSPORT ROW CONTROLS global hstack_row_transport_control_buttons @@ -1129,7 +1142,7 @@ class MainWindow(QMainWindow): hstack_row_transport_control_buttons.addWidget(button_transport_show_hide_config) hstack_row_transport_control_buttons.addStretch() button_transport_show_hide_config.clicked.connect(transport_show_hide_config_toggle) - main_layout.addLayout(hstack_row_transport_control_buttons) + _vbox_transport_row.addLayout(hstack_row_transport_control_buttons) #MARK: TRANSPORT ROW @@ -1150,7 +1163,9 @@ class MainWindow(QMainWindow): hstack_full_transport.addWidget(vsep_transport_right) hstack_full_transport.addLayout(hstack_transport_zone_right) - main_layout.addLayout(hstack_full_transport) + _vbox_transport_row.addLayout(hstack_full_transport) + main_layout.addWidget(container_transport_row) + chk_section_transport_row.toggled.connect(container_transport_row.setVisible) #MARK: PRESET BROWSER CONTAINER global container_preset_browser @@ -1171,10 +1186,13 @@ class MainWindow(QMainWindow): button_preset_browser_show_hide_config.clicked.connect(preset_browser_show_hide_config_toggle) vstack_preset_browser_container.addWidget(make_separator()) - vstack_preset_browser_container.addWidget(label_preset_browser_title) vstack_preset_browser_container.addLayout(hstack_preset_browser_controls) + vstack_preset_browser_container.addWidget(label_preset_browser_title) vstack_preset_browser_container.addLayout(hstack_preset_browser) main_layout.addWidget(container_preset_browser) + main_layout.addWidget(make_separator()) + + chk_section_preset_browser.toggled.connect(container_preset_browser.setVisible) # MARK: CONTAINER ROWS AND WIDGETS (fader + toggle only) @@ -1187,16 +1205,10 @@ class MainWindow(QMainWindow): controls_layout.setContentsMargins(0, 0, 0, 0) main_layout.addWidget(container_rows_and_widgets) - # MARK: BIG TITLE - big_title_edit = QLineEdit("") - big_title_edit.setPlaceholderText("Title") - big_title_edit.setAlignment(Qt.AlignmentFlag.AlignCenter) - big_title_edit.setStyleSheet( - "QLineEdit { background: transparent; border: none; border-bottom: 1px solid #3a3a3a;" - " color: #ffffff; font-size: 28px; font-weight: bold; padding: 4px 0; }" - "QLineEdit:focus { border-bottom: 1px solid #00e676; }" - ) - controls_layout.addWidget(big_title_edit) + container_fader_row = QWidget() + _vbox_fader_row = QVBoxLayout(container_fader_row) + _vbox_fader_row.setContentsMargins(0, 0, 0, 0) + _vbox_fader_row.setSpacing(0) # MARK: FADER ROW CONTROLS global hstack_row_fader_control_buttons @@ -1207,7 +1219,19 @@ class MainWindow(QMainWindow): hstack_row_fader_control_buttons.addStretch() button_fader_show_hide_config.clicked.connect(fader_show_hide_config_toggle) button_fader_clear_all.clicked.connect(clear_all_faders) - controls_layout.addLayout(hstack_row_fader_control_buttons) + _vbox_fader_row.addLayout(hstack_row_fader_control_buttons) + + # MARK: BIG TITLE + big_title_edit = QLineEdit("") + big_title_edit.setPlaceholderText("Title") + big_title_edit.setAlignment(Qt.AlignmentFlag.AlignCenter) + big_title_edit.setStyleSheet( + "QLineEdit { background: transparent; border: none;" + " color: #ffffff; font-size: 28px; font-weight: bold; padding: 4px 0; }" + "QLineEdit:focus { border-bottom: 1px solid #00e676; }" + ) + _vbox_fader_row.addWidget(big_title_edit) + chk_section_big_title.toggled.connect(big_title_edit.setVisible) #MARK: FADERS ROW global hstack_full_fader @@ -1224,7 +1248,7 @@ class MainWindow(QMainWindow): hstack_full_fader.addWidget(separator_vertical_fader_zone_right) hstack_full_fader.addLayout(hstack_fader_zone_right) - controls_layout.addLayout(hstack_full_fader) + _vbox_fader_row.addLayout(hstack_full_fader) global placeholder_fader_empty placeholder_fader_empty = QWidget() @@ -1240,7 +1264,10 @@ class MainWindow(QMainWindow): _pf_btn.clicked.connect(fader_add) _pf_layout.addWidget(_pf_btn, alignment=Qt.AlignmentFlag.AlignCenter) _pf_layout.addWidget(_pf_lbl) - controls_layout.addWidget(placeholder_fader_empty) + _vbox_fader_row.addWidget(placeholder_fader_empty) + + controls_layout.addWidget(container_fader_row) + chk_section_fader_row.toggled.connect(container_fader_row.setVisible) controls_layout.addWidget(make_separator()) @@ -1252,6 +1279,11 @@ class MainWindow(QMainWindow): global separator_vertical_toggle_zone_right global hstack_toggle_zone_right + container_toggle_row = QWidget() + _vbox_toggle_row = QVBoxLayout(container_toggle_row) + _vbox_toggle_row.setContentsMargins(0, 0, 0, 0) + _vbox_toggle_row.setSpacing(0) + # MARK: TOGGLE ROW CONTROLS global hstack_row_toggle_control_buttons global button_toggle_show_hide_config @@ -1261,7 +1293,7 @@ class MainWindow(QMainWindow): hstack_row_toggle_control_buttons.addStretch() button_toggle_show_hide_config.clicked.connect(toggle_show_hide_config_toggle) button_toggle_clear_all.clicked.connect(clear_all_toggles) - controls_layout.addLayout(hstack_row_toggle_control_buttons) + _vbox_toggle_row.addLayout(hstack_row_toggle_control_buttons) #MARK: TOGGLES ROW # assemble full toggle row @@ -1271,7 +1303,7 @@ class MainWindow(QMainWindow): hstack_full_toggle.addWidget(separator_vertical_toggle_zone_right) hstack_full_toggle.addLayout(hstack_toggle_zone_right) - controls_layout.addLayout(hstack_full_toggle) + _vbox_toggle_row.addLayout(hstack_full_toggle) global placeholder_toggle_empty placeholder_toggle_empty = QWidget() @@ -1287,7 +1319,10 @@ class MainWindow(QMainWindow): _pt_btn.clicked.connect(toggle_add) _pt_layout.addWidget(_pt_btn, alignment=Qt.AlignmentFlag.AlignCenter) _pt_layout.addWidget(_pt_lbl) - controls_layout.addWidget(placeholder_toggle_empty) + _vbox_toggle_row.addWidget(placeholder_toggle_empty) + + controls_layout.addWidget(container_toggle_row) + chk_section_toggle_row.toggled.connect(container_toggle_row.setVisible) controls_layout.addStretch() @@ -1427,6 +1462,47 @@ def new_blank_preset(): menuPresets.setCurrentText(name) clear_all_strips() big_title_edit.setText("") + chk_section_preset_browser.setChecked(True) + chk_section_big_title.setChecked(True) + chk_section_fader_row.setChecked(True) + chk_section_toggle_row.setChecked(True) + chk_section_transport_row.setChecked(True) + show_save_status() + +def rename_preset(): + from PyQt6.QtWidgets import QInputDialog + current_name = menuPresets.currentText() + if not current_name: + return + new_name, ok = QInputDialog.getText(app_window, "Rename Preset", "New name:", text=current_name) + if not ok or not new_name.strip() or new_name.strip() == current_name: + return + new_name = new_name.strip() + loaded_presets["presets"][new_name] = loaded_presets["presets"].pop(current_name) + if loaded_presets.get("__last_used__") == current_name: + loaded_presets["__last_used__"] = new_name + save_presets_file(loaded_presets) + populate_preset_dropdown_menu() + menuPresets.setCurrentText(new_name) + show_save_status() + +def duplicate_preset(): + from PyQt6.QtWidgets import QInputDialog + current_name = menuPresets.currentText() + if not current_name: + return + new_name, ok = QInputDialog.getText(app_window, "Duplicate Preset", "Name for duplicate:", text=f"{current_name} Copy") + if not ok or not new_name.strip(): + return + new_name = new_name.strip() + snapshot = preset_build_snapshot(current_name) + snapshot["preset_uuid"] = str(uuid.uuid4()) + loaded_presets["presets"][new_name] = snapshot + loaded_presets["__last_used__"] = new_name + save_presets_file(loaded_presets) + populate_preset_dropdown_menu() + menuPresets.setCurrentText(new_name) + label_preset_uuid.setText(snapshot["preset_uuid"]) show_save_status() def show_save_status(): @@ -1985,6 +2061,13 @@ def preset_build_snapshot(name): "toggle": toggle_show_hide_config, "transport": transport_show_hide_config, "browser": preset_browser_show_hide_config, + }, + "sections": { + "preset_browser": chk_section_preset_browser.isChecked(), + "big_title": chk_section_big_title.isChecked(), + "fader_row": chk_section_fader_row.isChecked(), + "toggle_row": chk_section_toggle_row.isChecked(), + "transport_row": chk_section_transport_row.isChecked(), } } @@ -2101,6 +2184,14 @@ def preset_load(preset): big_title_edit.setText(preset.get("big_title", "")) label_preset_uuid.setText(preset.get("preset_uuid", "")) + + sections = preset.get("sections", {}) + chk_section_preset_browser.setChecked(sections.get("preset_browser", True)) + chk_section_big_title.setChecked(sections.get("big_title", True)) + chk_section_fader_row.setChecked(sections.get("fader_row", True)) + chk_section_toggle_row.setChecked(sections.get("toggle_row", True)) + chk_section_transport_row.setChecked(sections.get("transport_row", True)) + check_and_index_strip_labels() def export_preset(): @@ -2602,4 +2693,5 @@ app.setPalette(dark_palette) window = MainWindow() set_window(window) window.show() +layout_panel_window_calc() sys.exit(app.exec()) \ No newline at end of file