"""Verifies the four interaction changes requested after the first review: - clap detection moved to a Tools menu (no more buttons in the layout) - clicking anywhere on the slider track jumps straight there - dragging the slider seeks live (via sliderMoved), not just on release - dropping a file onto the player widget loads it Drives real Qt events (QMouseEvent, QDropEvent) against the actual MainWindow/PlayerWidget classes rather than calling internal methods directly, so this proves the actual event wiring, not just the logic behind it. """ import sys import time from pathlib import Path from PyQt6.QtCore import Qt, QPointF, QUrl, QMimeData from PyQt6.QtGui import QMouseEvent, QDropEvent from PyQt6.QtWidgets import QApplication sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) import main as app_main ROOT = Path(__file__).resolve().parent.parent CLIP = str(ROOT / "test_media" / "sync_test_INSYNC.mp4") def main(): qapp = QApplication(sys.argv) win = app_main.MainWindow() win.show() qapp.processEvents() # -- Tools menu has the clap detection actions, AND both Detect All Claps # and Detect Next Clap are also buttons in the Sync markers panel (each # kept in sync with its menu action's enabled state, since they're two # separate widgets). menu_titles = [a.text() for a in win.menuBar().actions()] assert "&Tools" in menu_titles, f"expected a Tools menu, got {menu_titles}" assert win.detect_all_action.text() == "Detect All Claps" assert win.detect_next_action.text() == "Detect Next Clap" assert win.detect_all_button.text() == "Detect All Claps" assert win.detect_next_button.text() == "Detect Next Clap" assert win.detect_all_action.isEnabled() == win.detect_all_button.isEnabled() assert win.detect_next_action.isEnabled() == win.detect_next_button.isEnabled() print("PASS: Tools menu has plain-labeled clap detection actions, both buttons back in sync markers panel") # -- Load via drag-and-drop simulation on the player widget mime = QMimeData() mime.setUrls([QUrl.fromLocalFile(CLIP)]) drop_event = QDropEvent( QPointF(10, 10), Qt.DropAction.CopyAction, mime, Qt.MouseButton.LeftButton, Qt.KeyboardModifier.NoModifier, QDropEvent.Type.Drop, ) win.source_panel.player.dropEvent(drop_event) qapp.processEvents() time.sleep(0.3) qapp.processEvents() assert win.input_path == CLIP, f"drag-and-drop should have loaded the file, got {win.input_path}" print(f"PASS: drag-and-drop loaded {Path(win.input_path).name}") # -- Clicking directly on the slider track (not the handle) jumps there duration_ms = win.source_panel.seek_slider.maximum() assert duration_ms > 0 target_x = win.source_panel.seek_slider.width() * 0.5 click_pos = QPointF(target_x, win.source_panel.seek_slider.height() / 2) press_event = QMouseEvent( QMouseEvent.Type.MouseButtonPress, click_pos, click_pos, Qt.MouseButton.LeftButton, Qt.MouseButton.LeftButton, Qt.KeyboardModifier.NoModifier, ) before = win.source_panel.player.get_position() win.source_panel.seek_slider.mousePressEvent(press_event) qapp.processEvents() time.sleep(0.2) qapp.processEvents() after = win.source_panel.player.get_position() expected = 0.5 * (duration_ms / 1000.0) print(f"clicked slider track at 50%: before={before:.3f}s after={after:.3f}s expected~{expected:.3f}s") assert abs(after - expected) < 0.5, "clicking the track should jump the player near that position" print("PASS: click-anywhere-on-track seeking works") # -- Dragging (sliderMoved) seeks live, without waiting for release win.source_panel.seek_slider.sliderPressed.emit() qapp.processEvents() drag_value = int(0.2 * duration_ms) win.source_panel.seek_slider.setValue(drag_value) win.source_panel.seek_slider.sliderMoved.emit(drag_value) qapp.processEvents() time.sleep(0.2) qapp.processEvents() live_pos = win.source_panel.player.get_position() expected_drag = drag_value / 1000.0 print(f"dragged to 20% (still 'pressed', not released): live player position={live_pos:.3f}s expected~{expected_drag:.3f}s") assert abs(live_pos - expected_drag) < 0.5, "dragging should seek immediately, before release" win.source_panel.seek_slider.sliderReleased.emit() print("PASS: live-seek during drag works") win.source_panel.shutdown() win.preview_panel.shutdown() print("\nALL INTERACTION SMOKE TESTS PASSED") if __name__ == "__main__": main()