Files
ComfyGallery/ui/widgets/right_panel.py
T

186 lines
7.5 KiB
Python
Raw Normal View History

2026-05-31 18:43:18 +08:00
# ui/widgets/right_panel.py
import json
from typing import Optional # <-- Добавлен пропущенный импорт
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QTabWidget,
QTextEdit, QLineEdit, QPushButton, QFormLayout, QComboBox, QMessageBox, QApplication
)
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt, pyqtSignal
class RightPanel(QWidget):
save_clicked = pyqtSignal(int, dict)
send_to_comfy_clicked = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.current_file_id = None
self.current_filepath = None
self.current_raw_prompt = None
self.init_ui()
def init_ui(self):
layout = QVBoxLayout(self)
layout.setContentsMargins(5, 5, 5, 5)
self.preview_label = QLabel("Нет выделенного изображения")
self.preview_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.preview_label.setMinimumHeight(250)
self.preview_label.setStyleSheet(
"QLabel { background-color: #0f0f0f; border: 1px solid #2d2d2d; border-radius: 4px; }"
)
layout.addWidget(self.preview_label)
self.tabs = QTabWidget()
self.gen_tab = QWidget()
gen_layout = QVBoxLayout(self.gen_tab)
gen_layout.setContentsMargins(5, 5, 5, 5)
form_layout = QFormLayout()
self.model_input = QLineEdit()
self.model_input.setReadOnly(True)
form_layout.addRow("Модель:", self.model_input)
self.sampler_input = QLineEdit()
self.sampler_input.setReadOnly(True)
form_layout.addRow("Сэмплер:", self.sampler_input)
params_row = QHBoxLayout()
self.seed_input = QLineEdit()
self.seed_input.setReadOnly(True)
self.steps_input = QLineEdit()
self.steps_input.setReadOnly(True)
self.cfg_input = QLineEdit()
self.cfg_input.setReadOnly(True)
params_row.addWidget(QLabel("Seed:"))
params_row.addWidget(self.seed_input)
params_row.addWidget(QLabel("Steps:"))
params_row.addWidget(self.steps_input)
params_row.addWidget(QLabel("CFG:"))
params_row.addWidget(self.cfg_input)
form_layout.addRow(params_row)
self.rating_combo = QComboBox()
self.rating_combo.addItems(["Без рейтинга", "", "★★", "★★★", "★★★★", "★★★★★"])
form_layout.addRow("Рейтинг:", self.rating_combo)
gen_layout.addLayout(form_layout)
gen_layout.addWidget(QLabel("Позитивный промт:"))
self.positive_text = QTextEdit()
gen_layout.addWidget(self.positive_text)
gen_layout.addWidget(QLabel("Негативный промт:"))
self.negative_text = QTextEdit()
gen_layout.addWidget(self.negative_text)
self.save_btn = QPushButton("Сохранить изменения")
self.save_btn.clicked.connect(self._on_save_clicked)
gen_layout.addWidget(self.save_btn)
self.workflow_tab = QWidget()
wf_layout = QVBoxLayout(self.workflow_tab)
wf_layout.setContentsMargins(5, 5, 5, 5)
self.workflow_text = QTextEdit()
self.workflow_text.setReadOnly(True)
wf_layout.addWidget(self.workflow_text)
self.tabs.addTab(self.gen_tab, "Generation")
self.tabs.addTab(self.workflow_tab, "Workflow")
layout.addWidget(self.tabs)
export_layout = QHBoxLayout()
self.copy_pos_btn = QPushButton("Коп. Pos")
self.copy_pos_btn.clicked.connect(self._copy_positive)
self.copy_neg_btn = QPushButton("Коп. Neg")
self.copy_neg_btn.clicked.connect(self._copy_negative)
self.copy_wf_btn = QPushButton("Коп. Work")
self.copy_wf_btn.clicked.connect(self._copy_workflow)
export_layout.addWidget(self.copy_pos_btn)
export_layout.addWidget(self.copy_neg_btn)
export_layout.addWidget(self.copy_wf_btn)
layout.addLayout(export_layout)
self.send_btn = QPushButton("Отправить в ComfyUI")
self.send_btn.clicked.connect(self._on_send_clicked)
layout.addWidget(self.send_btn)
def display_metadata(self, file_details: Optional[dict]):
if not file_details:
self.clear_fields()
return
self.current_file_id = file_details["id"]
self.current_filepath = file_details["filepath"]
self.current_raw_prompt = file_details.get("prompt_json")
pixmap = QPixmap(self.current_filepath)
if not pixmap.isNull():
scaled = pixmap.scaled(
self.preview_label.width(), self.preview_label.height(),
Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation
)
self.preview_label.setPixmap(scaled)
else:
self.preview_label.setText("Ошибка рендеринга превью")
self.model_input.setText(file_details.get("model_name") or "Не указано")
self.sampler_input.setText(file_details.get("sampler") or "Не указано")
self.seed_input.setText(str(file_details.get("seed") or ""))
self.steps_input.setText(str(file_details.get("steps") or ""))
self.cfg_input.setText(str(file_details.get("cfg") or ""))
rating = file_details.get("rating", 0)
self.rating_combo.setCurrentIndex(rating if 0 <= rating <= 5 else 0)
self.positive_text.setPlainText(file_details.get("positive_prompt") or "")
self.negative_text.setPlainText(file_details.get("negative_prompt") or "")
wf_raw = file_details.get("workflow_json")
if wf_raw:
try:
self.workflow_text.setPlainText(json.dumps(json.loads(wf_raw), indent=2, ensure_ascii=False))
except Exception:
self.workflow_text.setPlainText(wf_raw)
else:
self.workflow_text.setPlainText("Workflow не найден")
def clear_fields(self):
self.current_file_id = None
self.current_filepath = None
self.current_raw_prompt = None
self.preview_label.setText("Нет выделенного изображения")
self.preview_label.setPixmap(QPixmap())
self.model_input.clear()
self.sampler_input.clear()
self.seed_input.clear()
self.steps_input.clear()
self.cfg_input.clear()
self.rating_combo.setCurrentIndex(0)
self.positive_text.clear()
self.negative_text.clear()
self.workflow_text.clear()
def _on_save_clicked(self):
if self.current_file_id is None: return
payload = {
"positive_prompt": self.positive_text.toPlainText(),
"negative_prompt": self.negative_text.toPlainText(),
"rating": self.rating_combo.currentIndex()
}
self.save_clicked.emit(self.current_file_id, payload)
def _on_send_clicked(self):
if not self.current_raw_prompt:
QMessageBox.warning(self, "Ошибка", "У изображения отсутствует prompt-граф.")
return
self.send_to_comfy_clicked.emit(self.current_raw_prompt)
def _copy_positive(self):
QApplication.clipboard().setText(self.positive_text.toPlainText())
def _copy_negative(self):
QApplication.clipboard().setText(self.negative_text.toPlainText())
def _copy_workflow(self):
QApplication.clipboard().setText(self.workflow_text.toPlainText())