From c9a4ac584f56cc1c69b2c643523f3bc4f7e96657 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Thu, 2 Jul 2026 14:28:51 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Audio=20tab=20QToolBox=20=E2=80=94=20Ex?= =?UTF-8?q?tract=20&=20Edit=20+=20Scan/Classify=20panes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 49 ++++++++++++++++++++++++++++++-------- tests/test_ui_structure.py | 15 +++++++++++- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/main.py b/main.py index 91aed85..7729839 100755 --- a/main.py +++ b/main.py @@ -4777,19 +4777,48 @@ class MainWindow(QMainWindow): g.setRowStretch(4, 1); g.setColumnStretch(2, 1) def _build_audio_tab(self) -> None: - g = QGridLayout(self._tab_audio) + outer = QVBoxLayout(self._tab_audio) + outer.setContentsMargins(0, 0, 0, 0) + tb = QToolBox() + + # ── Page 1: Extract & Edit ─────────────────────────────── + extract_page = QWidget() + g = QGridLayout(extract_page) g.setContentsMargins(8, 6, 8, 6); g.setHorizontalSpacing(8); g.setVerticalSpacing(6) + g.addWidget(QLabel("Length:"), 0, 0) + g.addWidget(self._spn_audio_len, 0, 1) + g.addWidget(QLabel("Format:"), 0, 2) + g.addWidget(self._cmb_audio_fmt, 0, 3) + g.addWidget(self._group_sep(), 1, 0, 1, 4) + g.addWidget(QLabel("Fade in:"), 2, 0) + g.addWidget(self._spn_fade_in, 2, 1) + g.addWidget(QLabel("Fade out:"), 2, 2) + g.addWidget(self._spn_fade_out, 2, 3) + g.addWidget(self._chk_normalize, 3, 0, 1, 2) + g.addWidget(QLabel("Gain:"), 3, 2) + g.addWidget(self._spn_gain, 3, 3) + # Row 4 reserved for the waveform strip (added in a later task). + g.addWidget(self._btn_extract_audio, 5, 0, 1, 4) + g.setColumnStretch(4, 1) # spare gutter column clusters label/field pairs to the left + g.setRowStretch(6, 1) # anchor content to the top (row 4 stays reserved for the waveform) + tb.addItem(extract_page, "Extract & Edit") + + # ── Page 2: Scan / Classify (moved verbatim) ───────────── + scan_page = QWidget() + sg = QGridLayout(scan_page) + sg.setContentsMargins(8, 6, 8, 6); sg.setHorizontalSpacing(8); sg.setVerticalSpacing(6) model_row = QHBoxLayout() model_row.addWidget(self._cmb_scan_model, 1); model_row.addWidget(self._btn_model_history) - g.addWidget(QLabel("Model:"), 0, 0); g.addLayout(model_row, 0, 1, 1, 3) - # Row 1: separator — model │ actions - g.addWidget(self._group_sep(), 1, 0, 1, 4) - g.addWidget(self._btn_scan, 2, 0); g.addWidget(self._btn_auto_export, 2, 1) - g.addWidget(self._btn_speech, 2, 2); g.addWidget(self._btn_scan_mode, 2, 3) - # Row 3: separator — actions │ fuse/threshold - g.addWidget(self._group_sep(), 3, 0, 1, 4) - g.addWidget(self._spn_auto_fuse, 4, 0); g.addWidget(self._sld_threshold, 4, 1) - g.setColumnStretch(3, 1) + sg.addWidget(QLabel("Model:"), 0, 0); sg.addLayout(model_row, 0, 1, 1, 3) + sg.addWidget(self._group_sep(), 1, 0, 1, 4) + sg.addWidget(self._btn_scan, 2, 0); sg.addWidget(self._btn_auto_export, 2, 1) + sg.addWidget(self._btn_speech, 2, 2); sg.addWidget(self._btn_scan_mode, 2, 3) + sg.addWidget(self._group_sep(), 3, 0, 1, 4) + sg.addWidget(self._spn_auto_fuse, 4, 0); sg.addWidget(self._sld_threshold, 4, 1) + sg.setColumnStretch(3, 1) + tb.addItem(scan_page, "Scan / Classify") + + outer.addWidget(tb) # ── Menu bar ───────────────────────────────────────────── diff --git a/tests/test_ui_structure.py b/tests/test_ui_structure.py index 08689bf..c7fd66d 100644 --- a/tests/test_ui_structure.py +++ b/tests/test_ui_structure.py @@ -53,7 +53,7 @@ def test_workers_spinbox_in_export_tab(win): assert win._spn_workers in win._tab_export.findChildren(QSpinBox) -def test_scan_button_in_scan_tab(win): +def test_scan_button_in_audio_tab(win): from PyQt6.QtWidgets import QPushButton assert win._btn_scan in win._tab_audio.findChildren(QPushButton) @@ -295,3 +295,16 @@ def test_audio_edit_widgets_exist(win): assert win._cmb_audio_fmt.findData(".wav") >= 0 assert win._cmb_audio_fmt.findData(".mp3") >= 0 assert win._cmb_audio_fmt.findData(".flac") >= 0 + + +def test_audio_toolbox_has_two_panes(win): + from PyQt6.QtWidgets import QToolBox, QPushButton + tb = win._tab_audio.findChild(QToolBox) + assert tb is not None + titles = [tb.itemText(i) for i in range(tb.count())] + assert titles[0].startswith("Extract") + assert any("Scan" in t or "Classify" in t for t in titles) + # Extract controls now live under the Audio tab. + assert win._btn_extract_audio in tb.findChildren(QPushButton) + # Scan controls remain reachable. + assert win._btn_scan in tb.findChildren(QPushButton)