200 lines
8.4 KiB
Python
200 lines
8.4 KiB
Python
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton,
|
|
QLineEdit, QLabel, QScrollArea, QWidget, QCheckBox, QFrame)
|
|
from PyQt6.QtCore import Qt, pyqtSignal
|
|
from .negative_prompt_categories import NEGATIVE_PROMPT_CATEGORIES, NEGATIVE_PROMPT_TRANSLATIONS
|
|
|
|
class NegativePromptWindow(QDialog):
|
|
prompt_selected = pyqtSignal(str)
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Негативные промпты")
|
|
self.setModal(False)
|
|
self.selected_prompts = set()
|
|
self.setup_ui()
|
|
self.load_categories()
|
|
|
|
def setup_ui(self):
|
|
self.setStyleSheet("""
|
|
QDialog {
|
|
background-color: #2b2b2b;
|
|
min-width: 1700px;
|
|
min-height: 800px;
|
|
}
|
|
QScrollArea {
|
|
background-color: #1e1e1e;
|
|
border: 1px solid #3b3b3b;
|
|
border-radius: 4px;
|
|
padding: 8px;
|
|
}
|
|
QScrollArea > QWidget > QWidget {
|
|
background-color: #1e1e1e;
|
|
}
|
|
QLabel {
|
|
color: #ffffff;
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
padding: 8px;
|
|
background-color: #3b3b3b;
|
|
border-radius: 4px;
|
|
}
|
|
QCheckBox {
|
|
color: #ffffff;
|
|
font-size: 14px;
|
|
padding: 4px;
|
|
spacing: 8px;
|
|
}
|
|
QCheckBox::indicator {
|
|
width: 18px;
|
|
height: 18px;
|
|
}
|
|
QCheckBox::indicator:unchecked {
|
|
border: 2px solid #555555;
|
|
background-color: #3b3b3b;
|
|
border-radius: 3px;
|
|
}
|
|
QCheckBox::indicator:checked {
|
|
border: 2px solid #dc3545;
|
|
background-color: #dc3545;
|
|
border-radius: 3px;
|
|
}
|
|
QCheckBox::indicator:hover {
|
|
border-color: #bb2d3b;
|
|
}
|
|
QPushButton {
|
|
background-color: #dc3545;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
padding: 8px 16px;
|
|
font-weight: bold;
|
|
min-width: 120px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #bb2d3b;
|
|
}
|
|
QPushButton:pressed {
|
|
background-color: #a52834;
|
|
}
|
|
QLineEdit {
|
|
background-color: #3b3b3b;
|
|
color: white;
|
|
border: 1px solid #555555;
|
|
border-radius: 4px;
|
|
padding: 8px;
|
|
font-size: 14px;
|
|
min-height: 24px;
|
|
}
|
|
QFrame {
|
|
background-color: #1e1e1e;
|
|
border: 1px solid #3b3b3b;
|
|
border-radius: 4px;
|
|
}
|
|
""")
|
|
|
|
layout = QVBoxLayout(self)
|
|
|
|
# Поиск
|
|
search_layout = QHBoxLayout()
|
|
search_label = QLabel("Поиск:")
|
|
self.search_input = QLineEdit()
|
|
self.search_input.textChanged.connect(self.filter_prompts)
|
|
search_layout.addWidget(search_label)
|
|
search_layout.addWidget(self.search_input)
|
|
layout.addLayout(search_layout)
|
|
|
|
# Горизонтальная прокрутка для категорий
|
|
categories_scroll = QScrollArea()
|
|
categories_scroll.setWidgetResizable(True)
|
|
categories_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
|
|
categories_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
|
|
|
categories_widget = QWidget()
|
|
self.categories_layout = QHBoxLayout(categories_widget)
|
|
self.categories_layout.setSpacing(10)
|
|
categories_scroll.setWidget(categories_widget)
|
|
|
|
layout.addWidget(categories_scroll)
|
|
|
|
# Кнопки
|
|
buttons_layout = QHBoxLayout()
|
|
add_button = QPushButton("Добавить выбранные")
|
|
add_button.clicked.connect(self.add_selected)
|
|
close_button = QPushButton("Закрыть")
|
|
close_button.clicked.connect(self.close)
|
|
buttons_layout.addWidget(add_button)
|
|
buttons_layout.addWidget(close_button)
|
|
layout.addLayout(buttons_layout)
|
|
|
|
def load_categories(self):
|
|
"""Загрузка категорий и промптов"""
|
|
for category, subcategories in NEGATIVE_PROMPT_CATEGORIES.items():
|
|
# Создаем фрейм для категории
|
|
category_frame = QFrame()
|
|
category_layout = QVBoxLayout(category_frame)
|
|
category_layout.setSpacing(5)
|
|
|
|
# Добавляем заголовок категории
|
|
category_label = QLabel(category)
|
|
category_layout.addWidget(category_label)
|
|
|
|
# Создаем скролл для подкатегорий
|
|
subcategories_scroll = QScrollArea()
|
|
subcategories_scroll.setWidgetResizable(True)
|
|
subcategories_widget = QWidget()
|
|
subcategories_layout = QVBoxLayout(subcategories_widget)
|
|
|
|
for subcategory, prompts in subcategories.items():
|
|
# Добавляем заголовок подкатегории
|
|
subcategory_label = QLabel(subcategory)
|
|
subcategories_layout.addWidget(subcategory_label)
|
|
|
|
# Добавляем чекбоксы для промптов
|
|
for prompt in prompts:
|
|
checkbox = QCheckBox(prompt)
|
|
checkbox.stateChanged.connect(lambda state, p=prompt: self.on_checkbox_changed(state, p))
|
|
subcategories_layout.addWidget(checkbox)
|
|
|
|
subcategories_scroll.setWidget(subcategories_widget)
|
|
category_layout.addWidget(subcategories_scroll)
|
|
|
|
# Добавляем категорию в горизонтальный layout
|
|
self.categories_layout.addWidget(category_frame)
|
|
|
|
def on_checkbox_changed(self, state, prompt):
|
|
"""Обработка изменения состояния чекбокса"""
|
|
if state == Qt.CheckState.Checked.value:
|
|
self.selected_prompts.add(prompt)
|
|
else:
|
|
self.selected_prompts.discard(prompt)
|
|
|
|
def filter_prompts(self, text):
|
|
"""Фильтрация промптов по поисковому запросу"""
|
|
text = text.lower()
|
|
for i in range(self.categories_layout.count()):
|
|
category_frame = self.categories_layout.itemAt(i).widget()
|
|
for j in range(category_frame.layout().count()):
|
|
widget = category_frame.layout().itemAt(j).widget()
|
|
if isinstance(widget, QScrollArea):
|
|
scroll_widget = widget.widget()
|
|
for k in range(scroll_widget.layout().count()):
|
|
sub_widget = scroll_widget.layout().itemAt(k).widget()
|
|
if isinstance(sub_widget, QCheckBox):
|
|
sub_widget.setVisible(text in sub_widget.text().lower())
|
|
elif isinstance(sub_widget, QLabel):
|
|
# Показываем/скрываем заголовок подкатегории в зависимости от видимости его промптов
|
|
has_visible_prompts = False
|
|
for l in range(k + 1, scroll_widget.layout().count()):
|
|
next_widget = scroll_widget.layout().itemAt(l).widget()
|
|
if isinstance(next_widget, QCheckBox) and next_widget.isVisible():
|
|
has_visible_prompts = True
|
|
break
|
|
sub_widget.setVisible(has_visible_prompts)
|
|
|
|
def add_selected(self):
|
|
"""Добавление выбранных промптов"""
|
|
if self.selected_prompts:
|
|
# Преобразуем русские названия в английские
|
|
translated_prompts = [NEGATIVE_PROMPT_TRANSLATIONS.get(prompt, prompt) for prompt in self.selected_prompts]
|
|
prompts_text = ", ".join(sorted(translated_prompts))
|
|
self.prompt_selected.emit(prompts_text) |