/
Ruden161
/
player
Обзор
Документация
Войти
/
Ruden161
/
player
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/ui/timecode_buttons.py
292 строки
10 KB
Ruden161
Проводник видео, горячие клавиши, YouTube-style панель
01 мар 2026, 19:16
01 мар 2026, 19:16
816ee8b
Код
Авторство
О чём код?
""" Компоненты виджета таймкода """ from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QFrame, QSizePolicy, QMenu, QInputDialog from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtGui import QCursor from src.video.timecodes import TimecodeEntry from src.utils.config import Config class LoopButton(QPushButton): """Кнопка зацикливания с контекстным меню""" loop_toggled = pyqtSignal(bool) def __init__(self): super().__init__("⟲") self.setFixedSize(28, 28) self.setCursor(Qt.CursorShape.PointingHandCursor) self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.customContextMenuRequested.connect(self._show_context_menu) self.loop_duration_index = -1 self.LOOP_DURATIONS = [0.5, 1, 2, 3, 5, 7, 10] self.custom_loop_duration = None self._apply_style() self.clicked.connect(self.toggle_loop) def toggle_loop(self): """Переключить зацикливание""" self.loop_duration_index += 1 if self.loop_duration_index >= len(self.LOOP_DURATIONS): self.loop_duration_index = -1 self.custom_loop_duration = None self._update_text() self.loop_toggled.emit(False) else: self._update_text() self.loop_toggled.emit(True) def _show_context_menu(self, pos): """Показать контекстное меню""" menu = QMenu(self) self._style_menu(menu) disable_action = menu.addAction("Отключить") disable_action.triggered.connect(self._disable_loop) menu.addSeparator() custom_action = menu.addAction("Ввести время...") custom_action.triggered.connect(self._set_custom_duration) menu.exec(QCursor.pos()) def _disable_loop(self): """Отключить зацикливание""" self.loop_duration_index = -1 self.custom_loop_duration = None self._update_text() self.loop_toggled.emit(False) def _set_custom_duration(self): """Установить пользовательскую длительность""" duration, ok = QInputDialog.getDouble( self, "Длительность зацикливания", "Введите длительность (секунды):", value=2.0, min=0.1, max=60.0, decimals=1 ) if ok: self.custom_loop_duration = duration self.loop_duration_index = -2 self._update_text() self.loop_toggled.emit(True) def _update_text(self): """Обновить текст кнопки""" if self.loop_duration_index == -1: self.setText("⟲") self._apply_style() elif self.loop_duration_index == -2: duration_text = f"{self.custom_loop_duration:.1f}s" if self.custom_loop_duration else "?" self.setText(duration_text) self._set_active_style() else: duration = self.LOOP_DURATIONS[self.loop_duration_index] duration_text = f"{duration:.1f}s" if duration < 1 else f"{int(duration)}s" self.setText(duration_text) self._set_active_style() def _apply_style(self): """Применить стиль кнопки""" self.setStyleSheet(f""" QPushButton {{ background-color: transparent; border: none; color: {Config.COLOR_TEXT_DIM}; font-size: 11px; padding: 0px; border-radius: 4px; font-weight: bold; }} QPushButton:hover {{ background-color: {Config.COLOR_BUTTON_HOVER}; color: {Config.COLOR_ACCENT}; }} QPushButton:pressed {{ background-color: {Config.COLOR_ACCENT}; color: white; }} """) def _set_active_style(self): """Установить стиль активной кнопки""" self.setStyleSheet(f""" QPushButton {{ background-color: {Config.COLOR_ACCENT}; border: none; color: white; font-size: 9px; padding: 0px; border-radius: 4px; font-weight: bold; }} QPushButton:hover {{ background-color: {Config.COLOR_ACCENT_HOVER}; }} QPushButton:pressed {{ background-color: {Config.COLOR_BUTTON_HOVER}; }} """) def get_duration(self) -> float: """Получить длительность зацикливания""" if self.loop_duration_index == -1: return 0 elif self.loop_duration_index == -2: return self.custom_loop_duration or 0 else: return self.LOOP_DURATIONS[self.loop_duration_index] @staticmethod def _style_menu(menu: QMenu): """Стилизировать меню""" menu.setStyleSheet(f""" QMenu {{ background-color: {Config.COLOR_PANEL}; border: 1px solid {Config.COLOR_BORDER}; border-radius: 4px; padding: 4px; }} QMenu::item {{ color: {Config.COLOR_TEXT}; padding: 6px 20px; border-radius: 3px; }} QMenu::item:selected {{ background-color: {Config.COLOR_ACCENT}; color: white; }} """) class SlowMoButton(QPushButton): """Кнопка slow-motion с контекстным меню""" slowmo_toggled = pyqtSignal(bool) def __init__(self): super().__init__("◐") self.setFixedSize(28, 28) self.setCursor(Qt.CursorShape.PointingHandCursor) self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.customContextMenuRequested.connect(self._show_context_menu) self.slowmo_speed_index = -1 self.SLOWMO_SPEEDS = [0.5, 0.25, 0.125, 0.0625, 0.03125] self.custom_slowmo_speed = None self._apply_style() self.clicked.connect(self.toggle_slowmo) def toggle_slowmo(self): """Переключить slow-motion""" self.slowmo_speed_index += 1 if self.slowmo_speed_index >= len(self.SLOWMO_SPEEDS): self.slowmo_speed_index = -1 self.custom_slowmo_speed = None self._update_text() self.slowmo_toggled.emit(False) else: self._update_text() self.slowmo_toggled.emit(True) def _show_context_menu(self, pos): """Показать контекстное меню""" menu = QMenu(self) LoopButton._style_menu(menu) disable_action = menu.addAction("Отключить") disable_action.triggered.connect(self._disable_slowmo) menu.addSeparator() custom_action = menu.addAction("Ввести скорость...") custom_action.triggered.connect(self._set_custom_speed) menu.exec(QCursor.pos()) def _disable_slowmo(self): """Отключить slow-motion""" self.slowmo_speed_index = -1 self.custom_slowmo_speed = None self._update_text() self.slowmo_toggled.emit(False) def _set_custom_speed(self): """Установить пользовательскую скорость""" speed, ok = QInputDialog.getDouble( self, "Скорость воспроизведения", "Введите скорость (0.01 - 1.0):", value=0.5, min=0.01, max=1.0, decimals=2 ) if ok: self.custom_slowmo_speed = speed self.slowmo_speed_index = -2 self._update_text() self.slowmo_toggled.emit(True) def _update_text(self): """Обновить текст кнопки""" if self.slowmo_speed_index == -1: self.setText("◐") self._apply_style() elif self.slowmo_speed_index == -2: speed_text = f"{self.custom_slowmo_speed:.2f}x" if self.custom_slowmo_speed else "?" self.setText(speed_text) self._set_active_style() else: speed = self.SLOWMO_SPEEDS[self.slowmo_speed_index] self.setText(f"{speed}x") self._set_active_style() def _apply_style(self): """Применить стиль кнопки""" self.setStyleSheet(f""" QPushButton {{ background-color: transparent; border: none; color: {Config.COLOR_TEXT_DIM}; font-size: 11px; padding: 0px; border-radius: 4px; font-weight: bold; }} QPushButton:hover {{ background-color: {Config.COLOR_BUTTON_HOVER}; color: {Config.COLOR_ACCENT}; }} QPushButton:pressed {{ background-color: {Config.COLOR_ACCENT}; color: white; }} """) def _set_active_style(self): """Установить стиль активной кнопки""" self.setStyleSheet(f""" QPushButton {{ background-color: {Config.COLOR_ACCENT}; border: none; color: white; font-size: 9px; padding: 0px; border-radius: 4px; font-weight: bold; }} QPushButton:hover {{ background-color: {Config.COLOR_ACCENT_HOVER}; }} QPushButton:pressed {{ background-color: {Config.COLOR_BUTTON_HOVER}; }} """) def get_speed(self) -> float: """Получить скорость slow-motion""" if self.slowmo_speed_index == -1: return 1.0 elif self.slowmo_speed_index == -2: return self.custom_slowmo_speed or 1.0 else: return self.SLOWMO_SPEEDS[self.slowmo_speed_index]