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.7 KiB
Python
100 lines
3.7 KiB
Python
"""
|
|
Левая панель: поиск, выбор корневой папки, дерево подпапок,
|
|
фильтр избранного и фильтр по тегу.
|
|
"""
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QLabel, QLineEdit, QTreeView, QComboBox, QCheckBox
|
|
)
|
|
from PyQt6.QtGui import QFileSystemModel
|
|
from PyQt6.QtCore import QDir, pyqtSignal
|
|
|
|
from comfy_studio.core.i18n import tr
|
|
from comfy_studio.ui.widgets.translatable_text_edit import TranslatableLineEdit
|
|
|
|
|
|
class LeftPanel(QWidget):
|
|
search_changed = pyqtSignal(str)
|
|
root_folder_changed = pyqtSignal(str)
|
|
filters_changed = pyqtSignal() # избранное / тег
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(5, 5, 5, 5)
|
|
|
|
self.search_input = TranslatableLineEdit()
|
|
self.search_input.setPlaceholderText(tr("search_placeholder"))
|
|
self.search_input.textChanged.connect(self.search_changed.emit)
|
|
layout.addWidget(self.search_input)
|
|
|
|
# Фильтр избранного
|
|
self.favorites_check = QCheckBox(tr("filter_favorites"))
|
|
self.favorites_check.stateChanged.connect(lambda _: self.filters_changed.emit())
|
|
layout.addWidget(self.favorites_check)
|
|
|
|
# Фильтр по тегу
|
|
layout.addWidget(QLabel(tr("filter_tag")))
|
|
self.tag_combo = QComboBox()
|
|
self.tag_combo.addItem(tr("all_tags"), None)
|
|
self.tag_combo.currentIndexChanged.connect(lambda _: self.filters_changed.emit())
|
|
layout.addWidget(self.tag_combo)
|
|
|
|
# Выбор активной корневой директории
|
|
layout.addWidget(QLabel(tr("active_folder")))
|
|
self.folder_selector = QComboBox()
|
|
self.folder_selector.currentTextChanged.connect(self._on_folder_changed)
|
|
layout.addWidget(self.folder_selector)
|
|
|
|
layout.addWidget(QLabel(tr("subfolder_tree")))
|
|
|
|
self.folder_model = QFileSystemModel()
|
|
self.folder_model.setFilter(QDir.Filter.Dirs | QDir.Filter.NoDotAndDotDot)
|
|
|
|
self.tree_view = QTreeView()
|
|
self.tree_view.setModel(self.folder_model)
|
|
self.tree_view.setHeaderHidden(True)
|
|
|
|
for i in range(1, self.folder_model.columnCount()):
|
|
self.tree_view.setColumnHidden(i, True)
|
|
|
|
layout.addWidget(self.tree_view)
|
|
|
|
# ── Публичные методы ──
|
|
|
|
def set_tracked_folders(self, folders: list):
|
|
self.folder_selector.blockSignals(True)
|
|
self.folder_selector.clear()
|
|
self.folder_selector.addItems(folders)
|
|
self.folder_selector.blockSignals(False)
|
|
|
|
def set_root_path(self, path: str):
|
|
self.folder_model.setRootPath(path)
|
|
self.tree_view.setRootIndex(self.folder_model.index(path))
|
|
|
|
def update_tags(self, tags: list):
|
|
"""Обновляет список тегов, сохраняя текущий выбор если возможно."""
|
|
current = self.tag_combo.currentData()
|
|
self.tag_combo.blockSignals(True)
|
|
self.tag_combo.clear()
|
|
self.tag_combo.addItem(tr("all_tags"), None)
|
|
for t in tags:
|
|
self.tag_combo.addItem(t, t)
|
|
if current in tags:
|
|
self.tag_combo.setCurrentIndex(tags.index(current) + 1)
|
|
self.tag_combo.blockSignals(False)
|
|
|
|
def get_filters(self) -> dict:
|
|
return {
|
|
"favorites_only": self.favorites_check.isChecked(),
|
|
"tag": self.tag_combo.currentData(),
|
|
}
|
|
|
|
def _on_folder_changed(self, path: str):
|
|
if path:
|
|
self.set_root_path(path)
|
|
self.root_folder_changed.emit(path)
|