Extracts a new PlayerPanel widget (video + its own seek slider/marker strip + its own centered frame-step/play/mute transport row) into player_panel.py. Both Source and Preview tabs now use one, so switching tabs switches a complete, independent monitor -- its own scrubber, its own play state, its own frame-stepping -- not just the video frame with a single shared play button underneath. main.py's global keyboard shortcuts (,/./space/left/right) now dispatch to whichever panel is active via a small _active_panel() helper, so they follow the same 'whichever monitor you're looking at' rule as the on-screen controls. MarkerStrip (clap detection) and the Mark Audio/Video/offset/export row stay outside the tabs, at the MainWindow level -- marking and exporting are inherently about the source file, not the preview clip, so only the timeline+transport moved, not the whole marking workflow. Updated every existing smoke test for the new win.source_panel.* / win.preview_panel.* structure (previously flat win.player, win.seek_slider, etc.), and added a new check to smoke_test_preview.py confirming the Preview tab's slider is a genuinely separate, functional widget -- dragging it seeks the preview player without moving the source player, which is the actual thing this change was for. Verified the full suite on the virtual Xvfb display, plus a live click-through (mark both events, build preview, confirm the Preview tab shows its own populated timeline/transport, not the source's).
93 lines
3.3 KiB
Python
93 lines
3.3 KiB
Python
"""Verifies left/right arrow keys skip +/-5s (clamped to file bounds) and
|
|
that loading a file shows a status bar message. Drives the real
|
|
QShortcut-bound keys via QTest.keyClick so it's testing the actual key
|
|
binding, not calling _seek_relative directly.
|
|
|
|
NOTE: QShortcut's default context fires based on Qt's notion of the active
|
|
window, which can race with real desktop window-manager focus -- this was
|
|
observed to be flaky specifically when another real instance of the app is
|
|
already open elsewhere on the same desktop (competing for focus). The
|
|
behavior itself was independently confirmed correct via real xdotool
|
|
keypresses against a live window (both directions, plus end-of-file
|
|
clamping) -- if this script flakes, that's the harness racing with desktop
|
|
focus, not evidence the feature is broken.
|
|
"""
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
from PyQt6.QtWidgets import QApplication
|
|
from PyQt6.QtTest import QTest
|
|
from PyQt6.QtCore import Qt
|
|
|
|
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") # 10s clip
|
|
|
|
|
|
def main():
|
|
qapp = QApplication(sys.argv)
|
|
win = app_main.MainWindow()
|
|
win.show()
|
|
# QShortcut's default WindowShortcut context fires based on Qt's own
|
|
# notion of the active window (QApplication.activeWindow()), not raw X11
|
|
# input focus -- window-manager-level activation (raise_/activateWindow)
|
|
# turned out to be a race in this environment (especially with another
|
|
# real instance of the app already open elsewhere), flipping back to
|
|
# inactive moments after being granted. Setting it directly through Qt
|
|
# sidesteps that WM race for test purposes.
|
|
qapp.setActiveWindow(win)
|
|
qapp.processEvents()
|
|
|
|
win._load(CLIP)
|
|
qapp.processEvents()
|
|
time.sleep(0.2)
|
|
qapp.processEvents()
|
|
|
|
# log hidden by default
|
|
assert not win.log_view.isVisible()
|
|
assert not win.toggle_log_action.isChecked()
|
|
print("PASS: log panel hidden by default")
|
|
|
|
win.source_panel.player.seek(5.0)
|
|
qapp.processEvents()
|
|
QTest.keyClick(win, Qt.Key.Key_Right)
|
|
qapp.processEvents()
|
|
time.sleep(0.2)
|
|
qapp.processEvents()
|
|
pos = win.source_panel.player.get_position()
|
|
print(f"after Right arrow from 5.0s: pos={pos:.3f}s")
|
|
assert abs(pos - 10.0) < 0.5, f"expected ~10.0s, got {pos:.3f}s" # 10s clip, clamps at end
|
|
|
|
win.source_panel.player.seek(5.0)
|
|
qapp.processEvents()
|
|
QTest.keyClick(win, Qt.Key.Key_Left)
|
|
qapp.processEvents()
|
|
time.sleep(0.2)
|
|
qapp.processEvents()
|
|
pos = win.source_panel.player.get_position()
|
|
print(f"after Left arrow from 5.0s: pos={pos:.3f}s")
|
|
assert abs(pos - 0.0) < 0.5, f"expected ~0.0s, got {pos:.3f}s"
|
|
|
|
win.source_panel.player.seek(2.0)
|
|
qapp.processEvents()
|
|
QTest.keyClick(win, Qt.Key.Key_Left)
|
|
qapp.processEvents()
|
|
time.sleep(0.2)
|
|
qapp.processEvents()
|
|
pos = win.source_panel.player.get_position()
|
|
print(f"after Left arrow from 2.0s (should clamp to 0, not go negative): pos={pos:.3f}s")
|
|
assert 0.0 <= pos < 0.5, f"expected clamped to ~0.0s, got {pos:.3f}s"
|
|
|
|
print("PASS: arrow keys skip 5s and clamp to file bounds")
|
|
|
|
win.source_panel.shutdown()
|
|
win.preview_panel.shutdown()
|
|
print("\nARROW SEEK SMOKE TEST PASSED")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|