194 lines
7.1 KiB
Python
194 lines
7.1 KiB
Python
from __future__ import annotations
|
|
|
|
from app.qt_compat import (
|
|
QColor,
|
|
QFont,
|
|
QLinearGradient,
|
|
QPainter,
|
|
QPainterPath,
|
|
QPen,
|
|
QRectF,
|
|
Qt,
|
|
Signal,
|
|
QWidget,
|
|
event_posf,
|
|
)
|
|
|
|
from app.config.device_assignment import tile_matches_device
|
|
from app.config.models import InfinityMirrorConfig
|
|
from app.network.wled import DiscoveredWledDevice, normalize_mac_address
|
|
from app.ui.preview_layout import compute_preview_layout
|
|
|
|
|
|
class MappingAssignmentPreview(QWidget):
|
|
tileClicked = Signal(str)
|
|
|
|
def __init__(self, parent: QWidget | None = None) -> None:
|
|
super().__init__(parent)
|
|
self._config = InfinityMirrorConfig()
|
|
self._discovered_devices: list[DiscoveredWledDevice] = []
|
|
self._active_device: DiscoveredWledDevice | None = None
|
|
self._selected_tile_id: str | None = None
|
|
self._tile_rects: dict[str, QRectF] = {}
|
|
|
|
self.setMinimumSize(520, 360)
|
|
self.setMouseTracking(True)
|
|
|
|
def set_assignment_state(
|
|
self,
|
|
config: InfinityMirrorConfig,
|
|
discovered_devices: list[DiscoveredWledDevice],
|
|
*,
|
|
active_device: DiscoveredWledDevice | None = None,
|
|
selected_tile_id: str | None = None,
|
|
) -> None:
|
|
self._config = config
|
|
self._discovered_devices = list(discovered_devices)
|
|
self._active_device = active_device
|
|
self._selected_tile_id = selected_tile_id
|
|
self.update()
|
|
|
|
def mousePressEvent(self, event) -> None:
|
|
point = event_posf(event)
|
|
for tile_id, rect in self._tile_rects.items():
|
|
if rect.contains(point):
|
|
self.tileClicked.emit(tile_id)
|
|
break
|
|
super().mousePressEvent(event)
|
|
|
|
def paintEvent(self, event) -> None: # type: ignore[override]
|
|
painter = QPainter(self)
|
|
painter.setRenderHint(QPainter.Antialiasing, True)
|
|
painter.setRenderHint(QPainter.TextAntialiasing, True)
|
|
|
|
rect = QRectF(self.rect())
|
|
background = QLinearGradient(rect.topLeft(), rect.bottomRight())
|
|
background.setColorAt(0.0, QColor("#12161D"))
|
|
background.setColorAt(1.0, QColor("#1B2230"))
|
|
painter.fillRect(rect, background)
|
|
|
|
if not self._config.tiles:
|
|
painter.setPen(QColor("#A8B3C7"))
|
|
painter.drawText(rect, Qt.AlignCenter, "Open a mapping to assign WLED devices.")
|
|
return
|
|
|
|
layout = compute_preview_layout(rect, self._config)
|
|
self._tile_rects = layout.tile_rects
|
|
self._draw_canvas_shell(painter, layout.canvas_rect)
|
|
|
|
discovered_ips = {device.ip_address for device in self._discovered_devices}
|
|
discovered_macs = {normalize_mac_address(device.mac_address) for device in self._discovered_devices if device.mac_address}
|
|
active_tile_id = None
|
|
if self._active_device is not None:
|
|
for tile in self._config.sorted_tiles():
|
|
if tile_matches_device(tile, self._active_device):
|
|
active_tile_id = tile.tile_id
|
|
break
|
|
|
|
for tile in self._config.sorted_tiles():
|
|
tile_rect = layout.tile_rects[tile.tile_id]
|
|
tile_assigned = bool(tile.controller_ip.strip() or tile.controller_mac.strip())
|
|
tile_is_active = active_tile_id == tile.tile_id
|
|
tile_is_selected = self._selected_tile_id == tile.tile_id
|
|
|
|
if tile_is_active:
|
|
fill_color = QColor("#1D4E89")
|
|
outline_color = QColor("#90CAF9")
|
|
subtitle = self._active_device.instance_name or self._active_device.ip_address
|
|
status = "Active Device"
|
|
elif not tile_assigned:
|
|
fill_color = QColor("#2A2F3A")
|
|
outline_color = QColor("#4A5568")
|
|
subtitle = "Unmapped"
|
|
status = "Click to assign"
|
|
elif (tile.controller_mac and normalize_mac_address(tile.controller_mac) in discovered_macs) or tile.controller_ip.strip() in discovered_ips:
|
|
fill_color = QColor("#1D5A45")
|
|
outline_color = QColor("#81E6D9")
|
|
subtitle = tile.controller_name or tile.controller_host or tile.controller_ip
|
|
status = "Mapped"
|
|
else:
|
|
fill_color = QColor("#6B4F1D")
|
|
outline_color = QColor("#F6AD55")
|
|
subtitle = tile.controller_name or tile.controller_host or tile.controller_ip
|
|
status = "Assigned, not seen"
|
|
|
|
self._draw_tile(
|
|
painter,
|
|
rect=tile_rect,
|
|
tile_id=tile.tile_id,
|
|
row=tile.row,
|
|
col=tile.col,
|
|
subtitle=subtitle,
|
|
status=status,
|
|
fill_color=fill_color,
|
|
outline_color=outline_color,
|
|
selected=tile_is_selected,
|
|
)
|
|
|
|
def _draw_canvas_shell(self, painter: QPainter, rect: QRectF) -> None:
|
|
path = QPainterPath()
|
|
path.addRoundedRect(rect, 10.0, 10.0)
|
|
painter.fillPath(path, QColor("#202632"))
|
|
painter.setPen(QPen(QColor("#334155"), 1.0))
|
|
painter.drawPath(path)
|
|
|
|
def _draw_tile(
|
|
self,
|
|
painter: QPainter,
|
|
*,
|
|
rect: QRectF,
|
|
tile_id: str,
|
|
row: int,
|
|
col: int,
|
|
subtitle: str,
|
|
status: str,
|
|
fill_color: QColor,
|
|
outline_color: QColor,
|
|
selected: bool,
|
|
) -> None:
|
|
base = min(rect.width(), rect.height())
|
|
rounding = max(4.0, base * 0.045)
|
|
tile_path = QPainterPath()
|
|
tile_path.addRoundedRect(rect, rounding, rounding)
|
|
|
|
painter.fillPath(tile_path, fill_color)
|
|
|
|
highlight = QLinearGradient(rect.topLeft(), rect.bottomLeft())
|
|
highlight.setColorAt(0.0, QColor(255, 255, 255, 24))
|
|
highlight.setColorAt(0.18, QColor(255, 255, 255, 8))
|
|
highlight.setColorAt(1.0, QColor(0, 0, 0, 0))
|
|
painter.fillPath(tile_path, highlight)
|
|
|
|
painter.setPen(QPen(outline_color, 1.3))
|
|
painter.drawPath(tile_path)
|
|
|
|
if selected:
|
|
painter.setPen(QPen(QColor("#E2E8F0"), 2.1))
|
|
painter.drawRoundedRect(rect.adjusted(-3, -3, 3, 3), rounding + 2.0, rounding + 2.0)
|
|
|
|
padding_x = max(12.0, rect.width() * 0.08)
|
|
padding_top = max(10.0, rect.height() * 0.08)
|
|
padding_bottom = max(12.0, rect.height() * 0.08)
|
|
|
|
title_font = QFont()
|
|
title_font.setPointSizeF(max(13.0, base * 0.1))
|
|
title_font.setWeight(QFont.DemiBold)
|
|
painter.setFont(title_font)
|
|
painter.setPen(QColor("#F8FAFC"))
|
|
painter.drawText(
|
|
rect.adjusted(padding_x, padding_top, -padding_x, -rect.height() * 0.56),
|
|
Qt.AlignLeft | Qt.AlignTop | Qt.TextWordWrap,
|
|
tile_id,
|
|
)
|
|
|
|
meta_font = QFont(title_font)
|
|
meta_font.setPointSizeF(max(9.2, base * 0.06))
|
|
meta_font.setWeight(QFont.Normal)
|
|
painter.setFont(meta_font)
|
|
painter.setPen(QColor(235, 244, 249, 175))
|
|
painter.drawText(
|
|
rect.adjusted(padding_x, rect.height() * 0.48, -padding_x, -padding_bottom),
|
|
Qt.AlignLeft | Qt.AlignBottom | Qt.TextWordWrap,
|
|
f"{subtitle}\n{status} | R{row} C{col}",
|
|
)
|