Give each tab its own full timeline and transport (PlayerPanel refactor)
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).
This commit is contained in:
@@ -50,7 +50,7 @@ def main():
|
||||
Qt.MouseButton.LeftButton, Qt.KeyboardModifier.NoModifier,
|
||||
QDropEvent.Type.Drop,
|
||||
)
|
||||
win.player.dropEvent(drop_event)
|
||||
win.source_panel.player.dropEvent(drop_event)
|
||||
qapp.processEvents()
|
||||
time.sleep(0.3)
|
||||
qapp.processEvents()
|
||||
@@ -58,42 +58,43 @@ def main():
|
||||
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.seek_slider.maximum()
|
||||
duration_ms = win.source_panel.seek_slider.maximum()
|
||||
assert duration_ms > 0
|
||||
target_x = win.seek_slider.width() * 0.5
|
||||
click_pos = QPointF(target_x, win.seek_slider.height() / 2)
|
||||
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.player.get_position()
|
||||
win.seek_slider.mousePressEvent(press_event)
|
||||
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.player.get_position()
|
||||
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.seek_slider.sliderPressed.emit()
|
||||
win.source_panel.seek_slider.sliderPressed.emit()
|
||||
qapp.processEvents()
|
||||
drag_value = int(0.2 * duration_ms)
|
||||
win.seek_slider.setValue(drag_value)
|
||||
win.seek_slider.sliderMoved.emit(drag_value)
|
||||
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.player.get_position()
|
||||
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.seek_slider.sliderReleased.emit()
|
||||
win.source_panel.seek_slider.sliderReleased.emit()
|
||||
print("PASS: live-seek during drag works")
|
||||
|
||||
win.player.shutdown()
|
||||
win.source_panel.shutdown()
|
||||
win.preview_panel.shutdown()
|
||||
print("\nALL INTERACTION SMOKE TESTS PASSED")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user