- Добавлена подложка с видимостью, прозрачностью, масштабом, перемещением и редактированием через отдельное меню. - Добавлен инструмент создания свободных светодиодов и редактирование X/Y для вручную созданных точек в таблице. - Упрощена таблица выбранных LED: единый ID, координаты X/Y и UID в конце. - Добавлены настраиваемые горячие клавиши для всех действий и переключатель отображения id светодиодов. - Улучшена отрисовка линий: стрелки направления, изгибы при полном и частичном визуальном наложении сегментов. - Оптимизировано переключение активных линий, выбор точек и поиск наложений соединений для снижения подвисаний. - Исправлена логика ручных LED: row/col рассчитываются по сетке 34 мм, а ручные точки не сдвигают якорь сетки. - Обновлена сборка EXE: имя использует тег, короткий хэш или дату/время для dirty-репозитория. - Расширен smoke-набор до 113 проверок для новых функций и регрессий.
55 lines
4.8 KiB
Python
55 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
from PySide6.QtCore import QByteArray, QSize, Qt
|
|
from PySide6.QtGui import QColor, QIcon, QPainter, QPixmap
|
|
from PySide6.QtSvg import QSvgRenderer
|
|
|
|
|
|
LUCIDE_PATHS = {
|
|
"archive-restore": '<rect width="20" height="5" x="2" y="3" rx="1"/><path d="M4 8v11a2 2 0 0 0 2 2h2"/><path d="M20 8v11a2 2 0 0 1-2 2h-2"/><path d="m9 15 3-3 3 3"/><path d="M12 12v9"/>',
|
|
"arrow-right": '<path d="M5 12h14"/><path d="m12 5 7 7-7 7"/>',
|
|
"brush": '<path d="m9.06 11.9 8.07-8.06a2.85 2.85 0 1 1 4.03 4.03l-8.06 8.08"/><path d="M7.07 14.94c-1.66 0-3 1.35-3 3.01 0 1.1-.89 2-2 2 1.4 1.4 3.67 1.4 5.07 0l2.94-2.94a2.93 2.93 0 0 0-4.14-4.14z"/>',
|
|
"chevron-right": '<path d="m9 18 6-6-6-6"/>',
|
|
"eraser": '<path d="m7 21-4.3-4.3c-.9-.9-.9-2.4 0-3.3L14 2l8 8-11 11Z"/><path d="M22 21H7"/><path d="m5 11 8 8"/>',
|
|
"eye": '<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',
|
|
"file-plus": '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6"/><path d="M12 18v-6"/><path d="M9 15h6"/>',
|
|
"file-code": '<path d="M14 2v6h6"/><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="m10 13-2 2 2 2"/><path d="m14 17 2-2-2-2"/>',
|
|
"folder-open": '<path d="m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6A2 2 0 0 1 18.46 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4.9a2 2 0 0 1 1.69.9L12 6h8a2 2 0 0 1 2 2v2"/><path d="M2 13h4"/>',
|
|
"git-branch": '<line x1="6" x2="6" y1="3" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>',
|
|
"grid-2x2": '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M3 12h18"/><path d="M12 3v18"/>',
|
|
"image": '<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21"/>',
|
|
"layers": '<path d="m12.83 2.18 8.34 4.66a1 1 0 0 1 0 1.74l-8.34 4.66a1.7 1.7 0 0 1-1.66 0L2.83 8.58a1 1 0 0 1 0-1.74l8.34-4.66a1.7 1.7 0 0 1 1.66 0Z"/><path d="m22 12.5-9.17 5.12a1.7 1.7 0 0 1-1.66 0L2 12.5"/><path d="m22 17.5-9.17 5.12a1.7 1.7 0 0 1-1.66 0L2 17.5"/>',
|
|
"list-plus": '<path d="M11 12H3"/><path d="M16 6H3"/><path d="M16 18H3"/><path d="M18 9v6"/><path d="M21 12h-6"/>',
|
|
"paintbrush": '<path d="m14.62 17.9-1.48 1.48a2.12 2.12 0 1 1-3-3l1.48-1.48"/><path d="m16.1 16.42 5.15-5.15a4.95 4.95 0 0 0-7-7L9.1 9.42"/><path d="m7.5 11 5.5 5.5"/><path d="m9 9-6 6v4h4l6-6"/>',
|
|
"plus": '<path d="M5 12h14"/><path d="M12 5v14"/>',
|
|
"redo-2": '<path d="m15 14 5-5-5-5"/><path d="M20 9H9.5A5.5 5.5 0 0 0 4 14.5 5.5 5.5 0 0 0 9.5 20H13"/>',
|
|
"rotate-cw": '<path d="M21 12a9 9 0 1 1-2.64-6.36L21 8"/><path d="M21 3v5h-5"/>',
|
|
"save": '<path d="M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z"/><path d="M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7"/><path d="M7 3v4a1 1 0 0 0 1 1h7"/>',
|
|
"save-all": '<path d="M10 2v3a1 1 0 0 0 1 1h5"/><path d="M18 18v-6a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v6"/><path d="M18 22H6a2 2 0 0 1-2-2V6"/><path d="M8 2h8l4 4v12a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2"/>',
|
|
"settings": '<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.38a2 2 0 0 0-.73-2.73l-.15-.09a2 2 0 0 1-1-1.74v-.51a2 2 0 0 1 1-1.72l.15-.1a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/>',
|
|
"trash-2": '<path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/>',
|
|
"undo-2": '<path d="M9 14 4 9l5-5"/><path d="M4 9h10.5A5.5 5.5 0 0 1 20 14.5 5.5 5.5 0 0 1 14.5 20H11"/>',
|
|
}
|
|
|
|
|
|
def lucide_icon(name: str, color: str = "#e5e7eb", size: int = 22) -> QIcon:
|
|
path = LUCIDE_PATHS.get(name)
|
|
if path is None:
|
|
path = LUCIDE_PATHS["plus"]
|
|
svg = (
|
|
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" '
|
|
'viewBox="0 0 24 24" fill="none" stroke="{color}" stroke-width="2" '
|
|
'stroke-linecap="round" stroke-linejoin="round">{path}</svg>'
|
|
).format(color=color, path=path)
|
|
renderer = QSvgRenderer(QByteArray(svg.encode("utf-8")))
|
|
pixmap = QPixmap(QSize(size, size))
|
|
pixmap.fill(Qt.transparent)
|
|
painter = QPainter(pixmap)
|
|
renderer.render(painter)
|
|
painter.end()
|
|
return QIcon(pixmap)
|
|
|
|
|
|
def recolor_icon(name: str, color: QColor | str) -> QIcon:
|
|
return lucide_icon(name, QColor(color).name() if isinstance(color, QColor) else color)
|