From 7f414d80b866dc0f4a107256f196fd0af36b175a Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Fri, 3 Jul 2026 02:16:50 +0200 Subject: [PATCH] feat: Audio tab drives timeline audio-mode; drag the band to set the extract region --- main.py | 13 +++++++++++++ tests/test_ui_structure.py | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/main.py b/main.py index 4f28f76..1cc3aaa 100755 --- a/main.py +++ b/main.py @@ -4533,6 +4533,7 @@ class MainWindow(QMainWindow): self._timeline.scan_region_resized.connect(self._on_scan_region_resized) self._timeline.clip_count_delta.connect(self._change_clip_count) self._timeline.autoclip_requested.connect(self._autoclip) + self._timeline.audio_region_changed.connect(self._on_wave_selection_changed) self._lbl_file = QLabel("← Drop files onto the queue") self._lbl_file.setAlignment(Qt.AlignmentFlag.AlignCenter) @@ -5231,6 +5232,9 @@ class MainWindow(QMainWindow): panel._pinned = panel._deck_key in _deck_pinned self._refresh_deck_layout() + # Sync timeline audio-mode to the current deck tab (Export default → off). + self._on_deck_tab_changed(self._control_deck.currentIndex()) + # Defer the changelog modal so the window paints/interacts first. QTimer.singleShot(120, self._show_changelog) @@ -5269,6 +5273,7 @@ class MainWindow(QMainWindow): deck.addTab(self._tab_audio, self._tab_audio._label) self._control_deck = deck deck.tabBar().pin_toggle_requested.connect(self._on_deck_pin_toggle) + deck.currentChanged.connect(self._on_deck_tab_changed) # Side-by-side container (shown when 2+ panels are pinned), wrapped in a # stack so the deck can swap between tabbed and split views. @@ -7363,6 +7368,14 @@ class MainWindow(QMainWindow): self._wave.set_peaks(peaks(samples)) return samples.size > 0 + def _on_deck_tab_changed(self, _idx: int) -> None: + if self._deck_loading: + return + is_audio = self._control_deck.currentWidget() is self._tab_audio + self._timeline.set_audio_mode(is_audio) + if is_audio and self._file_path: + self._update_audio_region() # ensure the band reflects cursor + length + def _on_wave_selection_changed(self, s: float, e: float) -> None: if self._wave_syncing: return diff --git a/tests/test_ui_structure.py b/tests/test_ui_structure.py index 7e98eee..2dc12d0 100644 --- a/tests/test_ui_structure.py +++ b/tests/test_ui_structure.py @@ -284,6 +284,9 @@ def test_timeline_audio_mode_flag(win): def test_timeline_audio_band_drag_move(win): tl = win._timeline + # The band is now wired to the window; fake a loaded file so the window's + # _update_audio_region keeps the region instead of clearing it on release. + win._file_path = "/x/v.mp4" tl._duration = 20.0 tl._view_start = 0.0; tl._view_span = 20.0 # full view tl.resize(400, tl.height() or 80) @@ -304,6 +307,8 @@ def test_timeline_audio_band_drag_move(win): def test_timeline_audio_band_resize_right(win): tl = win._timeline + # Fake a loaded file so the window keeps the region on release (see above). + win._file_path = "/x/v.mp4" tl._duration = 20.0; tl._view_start = 0.0; tl._view_span = 20.0 tl.resize(400, tl.height() or 80) tl.set_audio_mode(True) @@ -316,6 +321,22 @@ def test_timeline_audio_band_resize_right(win): tl.set_audio_mode(False) +def test_timeline_audio_mode_follows_deck(win): + win._control_deck.setCurrentWidget(win._tab_audio) + assert win._timeline._audio_mode is True + win._control_deck.setCurrentWidget(win._tab_export) + assert win._timeline._audio_mode is False + + +def test_timeline_audio_region_edit_syncs_cursor_length(win): + win._file_path = "/x/v.mp4" + win._cursor = 2.0 + win._spn_audio_len.setValue(3.0) + win._timeline.audio_region_changed.emit(5.0, 9.0) # user dragged the band to [5,9] + assert win._cursor == 5.0 + assert abs(win._spn_audio_len.value() - 4.0) < 1e-6 + + def test_audio_deck_tab_exists(win): # The old "Scan" deck tab is now "Audio". assert hasattr(win, "_tab_audio")