From ec5b85573c6026230b3a7bbcd9d969fa0fe45f51 Mon Sep 17 00:00:00 2001 From: kromskii2 <146603192+kromskii2@users.noreply.github.com> Date: Fri, 14 Mar 2025 19:49:29 +0700 Subject: [PATCH 1/2] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BE=D0=BA=D0=BD=D0=BE=20=D0=BD=D0=B5=D0=B3?= =?UTF-8?q?=D0=B0=D1=82=D0=B8=D0=B2=D0=BD=D1=8B=D1=85=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=BC=D0=BF=D1=82=D0=BE=D0=B2=20=D1=81=20=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=D1=80=D0=B8=D1=8F=D0=BC=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D0=B0=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=B8=D0=BC=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 55 ++++--- modules/negative_prompt_categories.py | 134 +++++++++++++++++ modules/negative_prompt_window.py | 200 ++++++++++++++++++++++++++ 3 files changed, 372 insertions(+), 17 deletions(-) create mode 100644 modules/negative_prompt_categories.py create mode 100644 modules/negative_prompt_window.py diff --git a/main.py b/main.py index c3674d0..9a89921 100644 --- a/main.py +++ b/main.py @@ -17,6 +17,7 @@ from modules.console_window import ConsoleWindow from modules.model_manager import ModelManager from modules.sampler_manager import SamplerManager from modules.prompt_window import PromptWindow +from modules.negative_prompt_window import NegativePromptWindow class GenerationThread(QThread): progress_updated = pyqtSignal(float, str) @@ -64,6 +65,7 @@ class MainWindow(QMainWindow): self.api_url = "http://localhost:7860" # URL по умолчанию self.console_window = None self.prompt_window = None + self.negative_prompt_window = None self.progress_timer = None self.init_ui() @@ -164,29 +166,32 @@ class MainWindow(QMainWindow): settings_layout.addLayout(api_layout) # Промпт - prompt_label = QLabel("Промпт:") - self.prompt_input = QTextEdit() - self.prompt_input.setPlaceholderText("Введите описание изображения...") prompt_layout = QVBoxLayout() prompt_header = QHBoxLayout() - prompt_header.addWidget(prompt_label) - - # Добавляем кнопку промптов рядом с полем промпта + prompt_label = QLabel("Промпт:") + self.prompt_input = QTextEdit() + self.prompt_input.setMinimumHeight(100) + prompt_buttons = QHBoxLayout() self.prompt_button = QPushButton("Готовые промпты") self.prompt_button.clicked.connect(self.toggle_prompt_window) - prompt_header.addWidget(self.prompt_button) - prompt_header.addStretch() - + self.negative_prompt_button = QPushButton("Негативные промпты") + self.negative_prompt_button.clicked.connect(self.toggle_negative_prompt_window) + prompt_buttons.addWidget(self.prompt_button) + prompt_buttons.addWidget(self.negative_prompt_button) + prompt_header.addWidget(prompt_label) + prompt_header.addLayout(prompt_buttons) prompt_layout.addLayout(prompt_header) prompt_layout.addWidget(self.prompt_input) settings_layout.addLayout(prompt_layout) # Негативный промпт - neg_prompt_label = QLabel("Негативный промпт:") - self.neg_prompt_input = QTextEdit() - self.neg_prompt_input.setPlaceholderText("Введите нежелательные элементы...") - settings_layout.addWidget(neg_prompt_label) - settings_layout.addWidget(self.neg_prompt_input) + negative_prompt_layout = QVBoxLayout() + negative_prompt_label = QLabel("Негативный промпт:") + self.negative_prompt_input = QTextEdit() + self.negative_prompt_input.setMinimumHeight(100) + negative_prompt_layout.addWidget(negative_prompt_label) + negative_prompt_layout.addWidget(self.negative_prompt_input) + settings_layout.addLayout(negative_prompt_layout) # Добавляем менеджер моделей self.model_manager = ModelManager(self.api_url) @@ -316,12 +321,28 @@ class MainWindow(QMainWindow): else: self.prompt_window.close() - def add_prompt(self, prompt): + def toggle_negative_prompt_window(self): + """Открыть/закрыть окно с негативными промптами""" + if self.negative_prompt_window is None: + self.negative_prompt_window = NegativePromptWindow(parent=self) + self.negative_prompt_window.prompt_selected.connect(self.add_negative_prompt) + self.negative_prompt_window.show() + else: + self.negative_prompt_window.close() + + def add_prompt(self, text): """Добавить промпт в поле ввода""" current_text = self.prompt_input.toPlainText() if current_text: current_text += ", " - self.prompt_input.setText(current_text + prompt) + self.prompt_input.setText(current_text + text) + + def add_negative_prompt(self, text): + """Добавить негативный промпт в поле ввода""" + current_text = self.negative_prompt_input.toPlainText() + if current_text: + current_text += ", " + self.negative_prompt_input.setText(current_text + text) def start_generation(self): self.generate_button.setEnabled(False) @@ -329,7 +350,7 @@ class MainWindow(QMainWindow): params = { "prompt": self.prompt_input.toPlainText(), - "negative_prompt": self.neg_prompt_input.toPlainText(), + "negative_prompt": self.negative_prompt_input.toPlainText(), "width": self.width_input.value(), "height": self.height_input.value(), "seed": self.seed_input.value(), diff --git a/modules/negative_prompt_categories.py b/modules/negative_prompt_categories.py new file mode 100644 index 0000000..40275e4 --- /dev/null +++ b/modules/negative_prompt_categories.py @@ -0,0 +1,134 @@ +NEGATIVE_PROMPT_CATEGORIES = { + "Общие проблемы": { + "Качество": [ + "Низкое качество", + "Обычное качество", + "Худшее качество", + "Низкое разрешение", + "Размытое", + "Не в фокусе" + ], + "Технические артефакты": [ + "Логотип", + "Текст", + "Подпись", + "Водяной знак", + "Обрезанное", + "Монохромное", + "Оттенки серого" + ], + "Контент": [ + "Нецензурный контент", + "NSFW", + "Удалить взрослых", + "Удалить молодых" + ] + }, + "Анатомия": { + "Общие проблемы": [ + "Неправильная анатомия", + "Плохое тело", + "Длинное тело", + "Длинная шея", + "Неправильные пропорции", + "Деформированный", + "Мутировавший", + "Мутация", + "Уродливый", + "Испорченный" + ], + "Лицо": [ + "Плохо нарисованное лицо", + "Пятна на коже", + "Веснушки", + "Прыщи", + "Косоглазый" + ], + "Конечности": [ + "Отсутствующая конечность", + "Деформированные конечности", + "Плавающие конечности", + "Отсоединенные конечности", + "Дополнительная конечность", + "Дополнительные руки", + "Мутировавшие руки", + "Плохо нарисованные руки", + "Деформированные руки", + "Мутировавшие руки и пальцы", + "Плохие руки", + "Отсутствующие пальцы", + "Сросшиеся пальцы", + "Слишком много пальцев", + "Дополнительные ноги", + "Плохие ноги" + ] + }, + "Дополнительные модели": { + "Негативные модели": [ + "AS-YoungV2-neg", + "BadDream", + "badhandv4", + "BadNegAnatomyV1-neg", + "EasyNegative", + "FastNegativeV2" + ] + } +} + +# Словарь для перевода русских названий в английские +NEGATIVE_PROMPT_TRANSLATIONS = { + "Низкое качество": "low quality", + "Обычное качество": "normal quality", + "Худшее качество": "worstquality", + "Низкое разрешение": "lowres", + "Размытое": "blurry", + "Не в фокусе": "out of focus", + "Логотип": "logo", + "Текст": "text", + "Подпись": "signature", + "Водяной знак": "watermark", + "Обрезанное": "cropped", + "Монохромное": "monochrome", + "Оттенки серого": "grayscale", + "Нецензурный контент": "NSFW content", + "NSFW": "NSFW", + "Удалить взрослых": "(AS-YoungV2-Neg:1.3)", + "Удалить молодых": "(AS-Adult-Neg:1.3)", + "Неправильная анатомия": "bad anatomy", + "Плохое тело": "bad body", + "Длинное тело": "long body", + "Длинная шея": "long neck", + "Неправильные пропорции": "bad proportions", + "Деформированный": "deformed", + "Мутировавший": "mutated", + "Мутация": "mutation", + "Уродливый": "ugly", + "Испорченный": "disfigured", + "Плохо нарисованное лицо": "poorly drawn face", + "Пятна на коже": "skin blemishes", + "Веснушки": "skin spots", + "Прыщи": "acnes", + "Косоглазый": "cross-eyed", + "Отсутствующая конечность": "missing limb", + "Деформированные конечности": "malformed limbs", + "Плавающие конечности": "floating limbs", + "Отсоединенные конечности": "disconnected limbs", + "Дополнительная конечность": "extra limb", + "Дополнительные руки": "extra arms", + "Мутировавшие руки": "mutated hands", + "Плохо нарисованные руки": "poorly drawn hands", + "Деформированные руки": "malformed hands", + "Мутировавшие руки и пальцы": "mutated hands and fingers", + "Плохие руки": "bad hands", + "Отсутствующие пальцы": "missing fingers", + "Сросшиеся пальцы": "fused fingers", + "Слишком много пальцев": "too many fingers", + "Дополнительные ноги": "extra legs", + "Плохие ноги": "bad feet", + "AS-YoungV2-neg": "AS-YoungV2-neg", + "BadDream": "BadDream", + "badhandv4": "badhandv4", + "BadNegAnatomyV1-neg": "BadNegAnatomyV1-neg", + "EasyNegative": "EasyNegative", + "FastNegativeV2": "FastNegativeV2" +} \ No newline at end of file diff --git a/modules/negative_prompt_window.py b/modules/negative_prompt_window.py new file mode 100644 index 0000000..38f8fdc --- /dev/null +++ b/modules/negative_prompt_window.py @@ -0,0 +1,200 @@ +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: 1500px; + min-height: 700px; + } + 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) \ No newline at end of file -- 2.54.0 From 828f3c6c1222e08ca9fc43edf3c1d366afc0d9b9 Mon Sep 17 00:00:00 2001 From: kromskii2 Date: Fri, 14 Mar 2025 20:11:38 +0700 Subject: [PATCH 2/2] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=20=D0=BE=D0=BA=D0=BE=D0=BD:=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=81=D1=82=D0=B8=D0=BB=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80=D1=8B=20=D1=8D=D0=BB=D0=B5?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=82=D0=BE=D0=B2,=20=D1=83=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D1=88=D0=B5=D0=BD=D0=B0=20=D1=87=D0=B8=D1=82=D0=B0=D0=B5?= =?UTF-8?q?=D0=BC=D0=BE=D1=81=D1=82=D1=8C=20=D1=82=D0=B5=D0=BA=D1=81=D1=82?= =?UTF-8?q?=D0=B0,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D0=B8=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BE=D0=BA,=20=D0=BE=D0=BF?= =?UTF-8?q?=D1=82=D0=B8=D0=BC=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BE=D1=82=D1=81=D1=82=D1=83=D0=BF=D1=8B=20?= =?UTF-8?q?=D0=B8=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80=D1=8B=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/console_window.py | 45 ++++++++------- modules/model_manager.py | 59 ++++++++++++++++++++ modules/prompt_window.py | 110 ++++++++++++++++++++++--------------- modules/sampler_manager.py | 43 +++++++++++++++ 4 files changed, 194 insertions(+), 63 deletions(-) diff --git a/modules/console_window.py b/modules/console_window.py index 50dd06a..759c05d 100644 --- a/modules/console_window.py +++ b/modules/console_window.py @@ -17,36 +17,42 @@ class ConsoleWindow(QDialog): def setup_ui(self): self.setStyleSheet(""" QDialog { - background-color: #2b2b2b; - min-width: 600px; - min-height: 400px; + background-color: #1e1e1e; + min-width: 700px; + min-height: 500px; } QTextEdit { - background-color: #1e1e1e; - color: #ffffff; - border: 1px solid #3b3b3b; - border-radius: 4px; - font-family: 'Consolas', 'Courier New', monospace; - font-size: 12px; - padding: 8px; + background-color: #252526; + color: #d4d4d4; + border: none; + border-radius: 8px; + font-family: 'JetBrains Mono', 'Consolas', 'Courier New', monospace; + font-size: 13px; + padding: 12px; + selection-background-color: #264f78; } QPushButton { - background-color: #0d6efd; - color: white; - border: none; - border-radius: 4px; + background-color: #2d2d2d; + color: #d4d4d4; + border: 1px solid #3e3e3e; + border-radius: 6px; padding: 8px 16px; - font-weight: bold; + font-weight: 500; + min-width: 100px; + margin: 4px; } QPushButton:hover { - background-color: #0b5ed7; + background-color: #3e3e3e; + border-color: #565656; } QPushButton:pressed { - background-color: #0a58ca; + background-color: #565656; } """) layout = QVBoxLayout(self) + layout.setContentsMargins(16, 16, 16, 16) + layout.setSpacing(12) # Область для логов self.console_output = QTextEdit() @@ -55,11 +61,12 @@ class ConsoleWindow(QDialog): # Кнопки управления buttons_layout = QHBoxLayout() + buttons_layout.setSpacing(8) - copy_button = QPushButton("Копировать всё") + copy_button = QPushButton("📋 Копировать") copy_button.clicked.connect(self.copy_all) - clear_button = QPushButton("Очистить") + clear_button = QPushButton("🗑️ Очистить") clear_button.clicked.connect(self.clear_console) buttons_layout.addWidget(copy_button) diff --git a/modules/model_manager.py b/modules/model_manager.py index c313c01..a8551e9 100644 --- a/modules/model_manager.py +++ b/modules/model_manager.py @@ -13,8 +13,65 @@ class ModelManager(QWidget): self.load_models() def setup_ui(self): + self.setStyleSheet(""" + QWidget { + background-color: transparent; + } + QLabel { + color: #d4d4d4; + font-size: 13px; + font-weight: 500; + margin-right: 8px; + } + QComboBox { + background-color: #252526; + color: #d4d4d4; + border: 1px solid #3e3e3e; + border-radius: 6px; + padding: 6px 12px; + min-width: 200px; + font-size: 13px; + } + QComboBox:hover { + border-color: #565656; + } + QComboBox:focus { + border-color: #007acc; + } + QComboBox::drop-down { + border: none; + width: 20px; + } + QComboBox::down-arrow { + image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMTFMNCBTTDEyIDUiIHN0cm9rZT0iI2Q0ZDRkNCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+); + } + QComboBox QAbstractItemView { + background-color: #252526; + color: #d4d4d4; + border: 1px solid #3e3e3e; + selection-background-color: #094771; + outline: none; + } + QPushButton { + background-color: #2d2d2d; + color: #d4d4d4; + border: 1px solid #3e3e3e; + border-radius: 6px; + padding: 6px 12px; + font-size: 13px; + } + QPushButton:hover { + background-color: #3e3e3e; + border-color: #565656; + } + QPushButton:pressed { + background-color: #565656; + } + """) + layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(8) # Метка label = QLabel("Модель:") @@ -22,11 +79,13 @@ class ModelManager(QWidget): # Выпадающий список моделей self.model_combo = QComboBox() + self.model_combo.setFixedHeight(32) self.model_combo.currentTextChanged.connect(self.on_model_changed) layout.addWidget(self.model_combo) # Кнопка обновления refresh_button = QPushButton("🔄") + refresh_button.setFixedSize(32, 32) refresh_button.setToolTip("Обновить список моделей") refresh_button.clicked.connect(self.load_models) layout.addWidget(refresh_button) diff --git a/modules/prompt_window.py b/modules/prompt_window.py index 02ac453..c2fb17d 100644 --- a/modules/prompt_window.py +++ b/modules/prompt_window.py @@ -18,87 +18,105 @@ class PromptWindow(QDialog): def setup_ui(self): self.setStyleSheet(""" QDialog { - background-color: #2b2b2b; - min-width: 1500px; - min-height: 700px; + background-color: #1e1e1e; + min-width: 1200px; + min-height: 800px; } QScrollArea { - background-color: #1e1e1e; - border: 1px solid #3b3b3b; - border-radius: 4px; - padding: 8px; + background-color: #252526; + border: none; + border-radius: 8px; } QScrollArea > QWidget > QWidget { - background-color: #1e1e1e; + background-color: #252526; } QLabel { - color: #ffffff; + color: #d4d4d4; font-size: 14px; - font-weight: bold; - padding: 8px; - background-color: #3b3b3b; - border-radius: 4px; + font-weight: 600; + padding: 12px; + background-color: #2d2d2d; + border-radius: 6px; + margin-bottom: 8px; } QCheckBox { - color: #ffffff; - font-size: 14px; - padding: 4px; + color: #d4d4d4; + font-size: 13px; + padding: 6px; spacing: 8px; } + QCheckBox:hover { + background-color: #2d2d2d; + border-radius: 4px; + } QCheckBox::indicator { width: 18px; height: 18px; + border-radius: 4px; } QCheckBox::indicator:unchecked { - border: 2px solid #555555; - background-color: #3b3b3b; - border-radius: 3px; + border: 2px solid #565656; + background-color: #252526; } QCheckBox::indicator:checked { - border: 2px solid #0d6efd; - background-color: #0d6efd; - border-radius: 3px; + border: 2px solid #007acc; + background-color: #007acc; } QCheckBox::indicator:hover { - border-color: #0b5ed7; + border-color: #007acc; } QPushButton { - background-color: #0d6efd; - color: white; - border: none; - border-radius: 4px; + background-color: #2d2d2d; + color: #d4d4d4; + border: 1px solid #3e3e3e; + border-radius: 6px; padding: 8px 16px; - font-weight: bold; + font-weight: 500; min-width: 120px; + font-size: 13px; } QPushButton:hover { - background-color: #0b5ed7; + background-color: #3e3e3e; + border-color: #565656; } QPushButton:pressed { - background-color: #0a58ca; + background-color: #565656; } QLineEdit { - background-color: #3b3b3b; - color: white; - border: 1px solid #555555; - border-radius: 4px; - padding: 8px; - font-size: 14px; - min-height: 24px; + background-color: #252526; + color: #d4d4d4; + border: 1px solid #3e3e3e; + border-radius: 6px; + padding: 8px 12px; + font-size: 13px; + min-height: 32px; + } + QLineEdit:focus { + border-color: #007acc; } QFrame { - background-color: #1e1e1e; - border: 1px solid #3b3b3b; - border-radius: 4px; + background-color: #252526; + border: 1px solid #3e3e3e; + border-radius: 8px; + padding: 12px; + margin: 4px; + } + QFrame:hover { + border-color: #565656; } """) layout = QVBoxLayout(self) + layout.setContentsMargins(16, 16, 16, 16) + layout.setSpacing(12) # Поиск search_layout = QHBoxLayout() - search_label = QLabel("Поиск:") + search_layout.setSpacing(8) + search_label = QLabel("🔍 Поиск:") + search_label.setStyleSheet("background: transparent; padding: 0;") self.search_input = QLineEdit() + self.search_input.setPlaceholderText("Введите текст для поиска...") self.search_input.textChanged.connect(self.filter_prompts) search_layout.addWidget(search_label) search_layout.addWidget(self.search_input) @@ -109,22 +127,26 @@ class PromptWindow(QDialog): categories_scroll.setWidgetResizable(True) categories_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn) categories_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + categories_scroll.setMinimumHeight(600) categories_widget = QWidget() self.categories_layout = QHBoxLayout(categories_widget) - self.categories_layout.setSpacing(10) + self.categories_layout.setSpacing(12) + self.categories_layout.setContentsMargins(12, 12, 12, 12) categories_scroll.setWidget(categories_widget) layout.addWidget(categories_scroll) # Кнопки buttons_layout = QHBoxLayout() - add_button = QPushButton("Добавить выбранные") + buttons_layout.setSpacing(8) + add_button = QPushButton("✨ Добавить выбранные") add_button.clicked.connect(self.add_selected) - close_button = QPushButton("Закрыть") + close_button = QPushButton("❌ Закрыть") close_button.clicked.connect(self.close) buttons_layout.addWidget(add_button) buttons_layout.addWidget(close_button) + buttons_layout.addStretch() layout.addLayout(buttons_layout) def load_categories(self): diff --git a/modules/sampler_manager.py b/modules/sampler_manager.py index 19da4b4..78d1ce3 100644 --- a/modules/sampler_manager.py +++ b/modules/sampler_manager.py @@ -13,8 +13,50 @@ class SamplerManager(QWidget): self.load_samplers() def setup_ui(self): + self.setStyleSheet(""" + QWidget { + background-color: transparent; + } + QLabel { + color: #d4d4d4; + font-size: 13px; + font-weight: 500; + margin-right: 8px; + } + QComboBox { + background-color: #252526; + color: #d4d4d4; + border: 1px solid #3e3e3e; + border-radius: 6px; + padding: 6px 12px; + min-width: 180px; + font-size: 13px; + } + QComboBox:hover { + border-color: #565656; + } + QComboBox:focus { + border-color: #007acc; + } + QComboBox::drop-down { + border: none; + width: 20px; + } + QComboBox::down-arrow { + image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMTFMNCBTTDEyIDUiIHN0cm9rZT0iI2Q0ZDRkNCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+); + } + QComboBox QAbstractItemView { + background-color: #252526; + color: #d4d4d4; + border: 1px solid #3e3e3e; + selection-background-color: #094771; + outline: none; + } + """) + layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(8) # Метка label = QLabel("Сэмплер:") @@ -22,6 +64,7 @@ class SamplerManager(QWidget): # Выпадающий список сэмплеров self.sampler_combo = QComboBox() + self.sampler_combo.setFixedHeight(32) self.sampler_combo.currentTextChanged.connect(self.on_sampler_changed) layout.addWidget(self.sampler_combo) -- 2.54.0