111 lines
3.8 KiB
Python
111 lines
3.8 KiB
Python
|
|
"""
|
||
|
|
Модель для управления слоями изображений
|
||
|
|
"""
|
||
|
|
|
||
|
|
from PySide6.QtCore import QObject, Signal
|
||
|
|
from typing import List, Optional, Dict
|
||
|
|
from pathlib import Path
|
||
|
|
from dataclasses import dataclass
|
||
|
|
from datetime import datetime
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class ImageLayer:
|
||
|
|
"""Модель слоя изображения"""
|
||
|
|
id: int
|
||
|
|
name: str
|
||
|
|
filepath: Path
|
||
|
|
source_id: int
|
||
|
|
date: datetime
|
||
|
|
wavelength: str
|
||
|
|
visible: bool = True
|
||
|
|
opacity: float = 1.0
|
||
|
|
image_data: Optional[any] = None
|
||
|
|
metadata: Optional[Dict] = None
|
||
|
|
|
||
|
|
|
||
|
|
class ImageModel(QObject):
|
||
|
|
"""Модель для хранения и управления слоями изображений"""
|
||
|
|
|
||
|
|
# Сигналы для оповещения View
|
||
|
|
layer_added = Signal(object) # ImageLayer
|
||
|
|
layer_removed = Signal(int) # layer_id
|
||
|
|
layer_visibility_changed = Signal(int, bool) # layer_id, visible
|
||
|
|
layer_opacity_changed = Signal(int, float) # layer_id, opacity
|
||
|
|
layer_selected = Signal(int) # layer_id
|
||
|
|
|
||
|
|
def __init__(self):
|
||
|
|
super().__init__()
|
||
|
|
self._layers: List[ImageLayer] = []
|
||
|
|
self._next_id = 1
|
||
|
|
self._selected_layer_id: Optional[int] = None
|
||
|
|
|
||
|
|
def add_layer(self, filepath: Path, source_id: int, date: datetime,
|
||
|
|
wavelength: str, image_data: any, metadata: Dict = None) -> int:
|
||
|
|
"""Добавляет новый слой"""
|
||
|
|
layer = ImageLayer(
|
||
|
|
id=self._next_id,
|
||
|
|
name=f"{wavelength} - {date.strftime('%Y-%m-%d %H:%M')}",
|
||
|
|
filepath=filepath,
|
||
|
|
source_id=source_id,
|
||
|
|
date=date,
|
||
|
|
wavelength=wavelength,
|
||
|
|
image_data=image_data,
|
||
|
|
metadata=metadata
|
||
|
|
)
|
||
|
|
self._layers.append(layer)
|
||
|
|
self._next_id += 1
|
||
|
|
self.layer_added.emit(layer)
|
||
|
|
return layer.id
|
||
|
|
|
||
|
|
def remove_layer(self, layer_id: int):
|
||
|
|
"""Удаляет слой"""
|
||
|
|
self._layers = [l for l in self._layers if l.id != layer_id]
|
||
|
|
self.layer_removed.emit(layer_id)
|
||
|
|
|
||
|
|
if self._selected_layer_id == layer_id:
|
||
|
|
self._selected_layer_id = None
|
||
|
|
|
||
|
|
def set_layer_visibility(self, layer_id: int, visible: bool):
|
||
|
|
"""Изменяет видимость слоя"""
|
||
|
|
for layer in self._layers:
|
||
|
|
if layer.id == layer_id:
|
||
|
|
layer.visible = visible
|
||
|
|
self.layer_visibility_changed.emit(layer_id, visible)
|
||
|
|
break
|
||
|
|
|
||
|
|
def set_layer_opacity(self, layer_id: int, opacity: float):
|
||
|
|
"""Изменяет прозрачность слоя"""
|
||
|
|
for layer in self._layers:
|
||
|
|
if layer.id == layer_id:
|
||
|
|
layer.opacity = opacity
|
||
|
|
self.layer_opacity_changed.emit(layer_id, opacity) # ← ЭМИИМ СИГНАЛ
|
||
|
|
break
|
||
|
|
|
||
|
|
def select_layer(self, layer_id: int):
|
||
|
|
"""Выбирает слой"""
|
||
|
|
self._selected_layer_id = layer_id
|
||
|
|
self.layer_selected.emit(layer_id)
|
||
|
|
|
||
|
|
def get_selected_layer(self) -> Optional[ImageLayer]:
|
||
|
|
"""Возвращает выбранный слой"""
|
||
|
|
if self._selected_layer_id:
|
||
|
|
for layer in self._layers:
|
||
|
|
if layer.id == self._selected_layer_id:
|
||
|
|
return layer
|
||
|
|
return None
|
||
|
|
|
||
|
|
def get_visible_layers(self) -> List[ImageLayer]:
|
||
|
|
"""Возвращает все видимые слои"""
|
||
|
|
return [layer for layer in self._layers if layer.visible]
|
||
|
|
|
||
|
|
def get_all_layers(self) -> List[ImageLayer]:
|
||
|
|
"""Возвращает все слои"""
|
||
|
|
return self._layers.copy()
|
||
|
|
|
||
|
|
def clear(self):
|
||
|
|
"""Очищает все слои"""
|
||
|
|
layer_ids = [layer.id for layer in self._layers]
|
||
|
|
self._layers.clear()
|
||
|
|
for layer_id in layer_ids:
|
||
|
|
self.layer_removed.emit(layer_id)
|