HelioParser/views/layer_widget.py

219 lines
7.7 KiB
Python
Raw Normal View History

2026-06-10 17:33:12 +03:00
"""
Виджет для управления слоями изображений
"""
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)