Add video scrubbing and click to seek/change volume on sliders
This commit is contained in:
@@ -2,7 +2,7 @@ import os
|
||||
import datetime
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||
QPushButton, QFrame, QSlider, QTextEdit, QApplication
|
||||
QPushButton, QFrame, QSlider, QTextEdit, QApplication, QToolTip
|
||||
)
|
||||
from PyQt6.QtCore import Qt, pyqtSignal, QTimer
|
||||
from PyQt6.QtGui import QIcon
|
||||
@@ -10,6 +10,49 @@ import uuid
|
||||
|
||||
from vlc_player import VLCSyncPlayer
|
||||
|
||||
class ClickableSlider(QSlider):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._get_tooltip_text = None
|
||||
|
||||
def set_tooltip_provider(self, provider_func):
|
||||
self._get_tooltip_text = provider_func
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
super().mousePressEvent(event)
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
val = 0
|
||||
if self.orientation() == Qt.Orientation.Horizontal:
|
||||
if self.width() > 0:
|
||||
val = self.minimum() + ((self.maximum() - self.minimum()) * event.pos().x()) / self.width()
|
||||
else:
|
||||
if self.height() > 0:
|
||||
val = self.minimum() + ((self.maximum() - self.minimum()) * (self.height() - event.pos().y())) / self.height()
|
||||
|
||||
val = max(self.minimum(), min(self.maximum(), int(val)))
|
||||
self.setValue(val)
|
||||
self.sliderMoved.emit(val)
|
||||
|
||||
if self._get_tooltip_text:
|
||||
text = self._get_tooltip_text(val)
|
||||
if text:
|
||||
QToolTip.showText(event.globalPosition().toPoint(), text, self)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
super().mouseMoveEvent(event)
|
||||
if event.buttons() & Qt.MouseButton.LeftButton:
|
||||
if self._get_tooltip_text:
|
||||
text = self._get_tooltip_text(self.value())
|
||||
if text:
|
||||
QToolTip.showText(event.globalPosition().toPoint(), text, self)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
super().mouseReleaseEvent(event)
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
# Explicitly emit sliderReleased on mouse release
|
||||
# to ensure single clicks on the track also trigger the release logic
|
||||
self.sliderReleased.emit()
|
||||
|
||||
class ExpectedVlcEvent:
|
||||
def __init__(self, action: str, req_id: str, target_val=None):
|
||||
self.action = action
|
||||
@@ -90,23 +133,25 @@ class RoomWidget(QWidget):
|
||||
self.play_btn.setObjectName("playBtn")
|
||||
|
||||
# Time and SeekBar
|
||||
self.seekbar = QSlider(Qt.Orientation.Horizontal)
|
||||
self.seekbar = ClickableSlider(Qt.Orientation.Horizontal)
|
||||
self.seekbar.setRange(0, 1000)
|
||||
self.seekbar.setObjectName("seekBar")
|
||||
self.seekbar.sliderMoved.connect(self.on_seekbar_dragged)
|
||||
self.seekbar.sliderReleased.connect(self.on_seekbar_released)
|
||||
self.seekbar.set_tooltip_provider(self.get_seekbar_tooltip)
|
||||
|
||||
self.time_lbl = QLabel("00:00:00 / 00:00:00")
|
||||
|
||||
# Volume
|
||||
self.vol_icon = QLabel("🔊")
|
||||
self.vol_icon.setObjectName("volIcon")
|
||||
self.volume_slider = QSlider(Qt.Orientation.Horizontal)
|
||||
self.volume_slider = ClickableSlider(Qt.Orientation.Horizontal)
|
||||
self.volume_slider.setRange(0, 100)
|
||||
self.volume_slider.setValue(100)
|
||||
self.volume_slider.setFixedWidth(100)
|
||||
self.volume_slider.setObjectName("volumeSlider")
|
||||
self.volume_slider.valueChanged.connect(self.on_volume_changed)
|
||||
self.volume_slider.set_tooltip_provider(lambda v: f"{v}%")
|
||||
|
||||
# Fullscreen
|
||||
self.fullscreen_btn = QPushButton("⛶")
|
||||
@@ -172,6 +217,14 @@ class RoomWidget(QWidget):
|
||||
|
||||
self.play_btn.clicked.connect(self.toggle_playback)
|
||||
|
||||
def get_seekbar_tooltip(self, value):
|
||||
length_ms = self.vlc_player.get_length()
|
||||
if length_ms > 0:
|
||||
target_ms = int((value / 1000.0) * length_ms)
|
||||
s = max(0, target_ms) // 1000
|
||||
return f"{s//3600:02d}:{(s%3600)//60:02d}:{s%60:02d}"
|
||||
return ""
|
||||
|
||||
def setup_room(self, room_code: str, username: str, file_name: str, file_path: str, start_time_s: float = 0.0):
|
||||
self.room_code = room_code
|
||||
self.username = username
|
||||
@@ -313,6 +366,8 @@ class RoomWidget(QWidget):
|
||||
s = max(0, ms) // 1000
|
||||
return f"{s//3600:02d}:{(s%3600)//60:02d}:{s%60:02d}"
|
||||
self.time_lbl.setText(f"{fmt(target_ms)} / {fmt(length_ms)}")
|
||||
# Scrub the video locally in real-time
|
||||
self._tell_vlc_and_expect("seek", target_ms / 1000.0)
|
||||
|
||||
def on_seekbar_released(self):
|
||||
length_ms = self.vlc_player.get_length()
|
||||
|
||||
Reference in New Issue
Block a user