34a40ae759
Десктопная галерея и менеджер изображений ComfyUI (PyQt6 + SQLite): - мультипапочный мониторинг (watchdog), грид миниатюр, drag-and-drop - теги, избранное, рейтинг, поиск по промтам - парсер метаданных ComfyUI (PNG/WebP/JPEG), редактор workflow/prompt JSON - перевод выделенного текста через контекстное меню (настраиваемые языки) - отправка промта в очередь ComfyUI с внедрением правок и нового seed - полноэкранный просмотр, локализация ru/en, тёмная тема Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
100 lines
3.1 KiB
Python
100 lines
3.1 KiB
Python
"""
|
|
Полноэкранный просмотрщик изображений.
|
|
Стрелки ←/→ — листание, Esc / двойной клик — выход, колесо мыши — листание.
|
|
"""
|
|
|
|
import logging
|
|
from typing import List
|
|
|
|
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel
|
|
from PyQt6.QtGui import QPixmap, QKeyEvent
|
|
from PyQt6.QtCore import Qt
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class FullscreenViewer(QWidget):
|
|
def __init__(self, filepaths: List[str], start_index: int = 0, parent=None):
|
|
super().__init__(parent)
|
|
self.filepaths = filepaths
|
|
self.index = max(0, min(start_index, len(filepaths) - 1))
|
|
|
|
self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.FramelessWindowHint)
|
|
self.setStyleSheet("background-color: #000000;")
|
|
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
self.image_label = QLabel()
|
|
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
self.image_label.setStyleSheet("background-color: #000000;")
|
|
layout.addWidget(self.image_label, 1)
|
|
|
|
self.info_label = QLabel()
|
|
self.info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
self.info_label.setStyleSheet(
|
|
"color: #9e9e9e; background-color: #000000; padding: 6px; font-size: 12px;")
|
|
layout.addWidget(self.info_label)
|
|
|
|
self._current_pixmap = None
|
|
|
|
def open_fullscreen(self):
|
|
self.showFullScreen()
|
|
self._load_current()
|
|
|
|
def _load_current(self):
|
|
if not self.filepaths:
|
|
return
|
|
path = self.filepaths[self.index]
|
|
pixmap = QPixmap(path)
|
|
if pixmap.isNull():
|
|
self.image_label.setText("⚠")
|
|
self._current_pixmap = None
|
|
else:
|
|
self._current_pixmap = pixmap
|
|
self._rescale()
|
|
self.info_label.setText(f"{self.index + 1} / {len(self.filepaths)} — {path}")
|
|
|
|
def _rescale(self):
|
|
if self._current_pixmap:
|
|
scaled = self._current_pixmap.scaled(
|
|
self.image_label.size(),
|
|
Qt.AspectRatioMode.KeepAspectRatio,
|
|
Qt.TransformationMode.SmoothTransformation
|
|
)
|
|
self.image_label.setPixmap(scaled)
|
|
|
|
def resizeEvent(self, event):
|
|
self._rescale()
|
|
super().resizeEvent(event)
|
|
|
|
def keyPressEvent(self, event: QKeyEvent):
|
|
key = event.key()
|
|
if key == Qt.Key.Key_Escape:
|
|
self.close()
|
|
elif key in (Qt.Key.Key_Right, Qt.Key.Key_Down, Qt.Key.Key_Space):
|
|
self._next()
|
|
elif key in (Qt.Key.Key_Left, Qt.Key.Key_Up):
|
|
self._prev()
|
|
else:
|
|
super().keyPressEvent(event)
|
|
|
|
def wheelEvent(self, event):
|
|
if event.angleDelta().y() < 0:
|
|
self._next()
|
|
else:
|
|
self._prev()
|
|
|
|
def mouseDoubleClickEvent(self, event):
|
|
self.close()
|
|
|
|
def _next(self):
|
|
if self.index < len(self.filepaths) - 1:
|
|
self.index += 1
|
|
self._load_current()
|
|
|
|
def _prev(self):
|
|
if self.index > 0:
|
|
self.index -= 1
|
|
self._load_current()
|