Initial release: Comfy-Studio v1.0.0
Десктопная галерея и менеджер изображений 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>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
"""
|
||||
Левая панель: поиск, выбор корневой папки, дерево подпапок,
|
||||
фильтр избранного и фильтр по тегу.
|
||||
"""
|
||||
|
||||
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)
|
||||
Reference in New Issue
Block a user