219 lines
No EOL
7.7 KiB
Python
219 lines
No EOL
7.7 KiB
Python
"""
|
|
Виджет для управления слоями изображений
|
|
"""
|
|
|
|
from PySide6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QListWidget, QListWidgetItem,
|
|
QHBoxLayout, QCheckBox, QSlider, QLabel, QPushButton,
|
|
QFrame
|
|
)
|
|
from PySide6.QtCore import Qt, Signal, QSize
|
|
|
|
|
|
class LayerWidgetItem(QWidget):
|
|
"""Виджет для отдельного слоя в списке"""
|
|
|
|
visibility_toggled = Signal(int, bool)
|
|
opacity_changed = Signal(int, float)
|
|
|
|
def __init__(self, layer_id: int, name: str, visible: bool = True):
|
|
super().__init__()
|
|
self.layer_id = layer_id
|
|
self.init_ui(name, visible)
|
|
|
|
def init_ui(self, name: str, visible: bool):
|
|
layout = QHBoxLayout(self)
|
|
layout.setContentsMargins(8, 6, 8, 6)
|
|
layout.setSpacing(8)
|
|
|
|
# Чекбокс видимости
|
|
self.visibility_checkbox = QCheckBox()
|
|
self.visibility_checkbox.setChecked(visible)
|
|
self.visibility_checkbox.setFixedSize(22, 22)
|
|
self.visibility_checkbox.toggled.connect(self.on_visibility_toggled)
|
|
layout.addWidget(self.visibility_checkbox)
|
|
|
|
# Название слоя
|
|
self.name_label = QLabel(name)
|
|
self.name_label.setStyleSheet("font-size: 11px; font-weight: 500;")
|
|
self.name_label.setWordWrap(True)
|
|
layout.addWidget(self.name_label, 2)
|
|
|
|
# Слайдер прозрачности
|
|
self.opacity_slider = QSlider(Qt.Orientation.Horizontal)
|
|
self.opacity_slider.setRange(0, 100)
|
|
self.opacity_slider.setValue(100)
|
|
self.opacity_slider.setFixedWidth(100)
|
|
self.opacity_slider.valueChanged.connect(self.on_opacity_changed)
|
|
layout.addWidget(self.opacity_slider)
|
|
|
|
# Метка прозрачности
|
|
self.opacity_label = QLabel("100%")
|
|
self.opacity_label.setFixedWidth(35)
|
|
self.opacity_label.setStyleSheet("font-size: 10px; font-family: monospace;")
|
|
layout.addWidget(self.opacity_label)
|
|
|
|
# Кнопка удаления
|
|
remove_button = QPushButton("✖")
|
|
remove_button.setFixedSize(26, 26)
|
|
remove_button.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #e74c3c;
|
|
color: white;
|
|
border-radius: 13px;
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #c0392b;
|
|
}
|
|
""")
|
|
remove_button.clicked.connect(lambda: self.visibility_toggled.emit(self.layer_id, False))
|
|
layout.addWidget(remove_button)
|
|
|
|
def on_visibility_toggled(self, checked):
|
|
self.visibility_toggled.emit(self.layer_id, checked)
|
|
|
|
def on_opacity_changed(self, value):
|
|
opacity = value / 100.0
|
|
self.opacity_label.setText(f"{value}%")
|
|
self.opacity_changed.emit(self.layer_id, opacity)
|
|
|
|
def set_visible(self, visible: bool):
|
|
self.visibility_checkbox.setChecked(visible)
|
|
|
|
def set_opacity(self, opacity: float):
|
|
value = int(opacity * 100)
|
|
self.opacity_slider.setValue(value)
|
|
self.opacity_label.setText(f"{value}%")
|
|
|
|
|
|
class LayerWidget(QWidget):
|
|
"""Виджет для отображения списка слоев"""
|
|
|
|
def __init__(self, controller):
|
|
super().__init__()
|
|
self.controller = controller
|
|
self.layer_widgets = {}
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
layout.setSpacing(5)
|
|
|
|
# Список слоев
|
|
self.list_widget = QListWidget()
|
|
self.list_widget.setStyleSheet("""
|
|
QListWidget {
|
|
border: 1px solid #555;
|
|
border-radius: 5px;
|
|
background-color: #2b2b2b;
|
|
outline: none;
|
|
}
|
|
QListWidget::item {
|
|
border-bottom: 1px solid #444;
|
|
}
|
|
QListWidget::item:selected {
|
|
background-color: #3c5a8c;
|
|
}
|
|
QListWidget::item:hover {
|
|
background-color: #3c3c3c;
|
|
}
|
|
""")
|
|
layout.addWidget(self.list_widget)
|
|
|
|
# Кнопка очистки
|
|
clear_button = QPushButton("🗑️ Очистить все слои")
|
|
clear_button.setMinimumHeight(32)
|
|
clear_button.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #555;
|
|
color: white;
|
|
padding: 5px;
|
|
border-radius: 4px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #e74c3c;
|
|
}
|
|
""")
|
|
clear_button.clicked.connect(self.clear_all_layers)
|
|
layout.addWidget(clear_button)
|
|
|
|
# Пустое состояние
|
|
self.empty_label = QLabel("📭 Нет загруженных слоев\n\nНажмите 'Загрузить изображение'")
|
|
self.empty_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
self.empty_label.setStyleSheet("color: #888; padding: 30px; background-color: #2b2b2b; border-radius: 5px;")
|
|
self.empty_label.setVisible(True)
|
|
layout.addWidget(self.empty_label)
|
|
|
|
def add_layer(self, layer_id: int, name: str, visible: bool = True):
|
|
"""Добавляет новый слой в список"""
|
|
self.empty_label.setVisible(False)
|
|
self.list_widget.setVisible(True)
|
|
|
|
item = QListWidgetItem()
|
|
item.setSizeHint(QSize(0, 55))
|
|
self.list_widget.addItem(item)
|
|
|
|
widget = LayerWidgetItem(layer_id, name, visible)
|
|
widget.visibility_toggled.connect(self.on_visibility_toggled)
|
|
widget.opacity_changed.connect(self.on_opacity_changed)
|
|
|
|
self.list_widget.setItemWidget(item, widget)
|
|
self.layer_widgets[layer_id] = (item, widget)
|
|
self.list_widget.setCurrentItem(item)
|
|
self.list_widget.scrollToItem(item)
|
|
|
|
def remove_layer(self, layer_id: int):
|
|
"""Удаляет слой из списка"""
|
|
if layer_id in self.layer_widgets:
|
|
item, _ = self.layer_widgets[layer_id]
|
|
row = self.list_widget.row(item)
|
|
self.list_widget.takeItem(row)
|
|
del self.layer_widgets[layer_id]
|
|
|
|
if len(self.layer_widgets) == 0:
|
|
self.empty_label.setVisible(True)
|
|
self.list_widget.setVisible(False)
|
|
|
|
def update_layers(self, layers):
|
|
"""Обновляет весь список слоев"""
|
|
self.clear_all_layers(keep_controller=False)
|
|
for layer in layers:
|
|
self.add_layer(layer.id, layer.name, layer.visible)
|
|
|
|
if layers:
|
|
self.empty_label.setVisible(False)
|
|
self.list_widget.setVisible(True)
|
|
else:
|
|
self.empty_label.setVisible(True)
|
|
self.list_widget.setVisible(False)
|
|
|
|
def clear_all_layers(self, keep_controller: bool = True):
|
|
"""Очищает список слоев"""
|
|
self.list_widget.clear()
|
|
self.layer_widgets.clear()
|
|
|
|
if keep_controller:
|
|
self.controller.clear_all_layers()
|
|
|
|
self.empty_label.setVisible(True)
|
|
self.list_widget.setVisible(False)
|
|
|
|
def on_visibility_toggled(self, layer_id: int, visible: bool):
|
|
self.controller.set_layer_visibility(layer_id, visible)
|
|
|
|
def on_opacity_changed(self, layer_id: int, opacity: float):
|
|
self.controller.set_layer_opacity(layer_id, opacity)
|
|
|
|
def get_selected_layer_id(self) -> int:
|
|
current_item = self.list_widget.currentItem()
|
|
if current_item:
|
|
for layer_id, (item, _) in self.layer_widgets.items():
|
|
if item == current_item:
|
|
return layer_id
|
|
return None
|
|
|
|
def get_layers_count(self) -> int:
|
|
return len(self.layer_widgets) |