# -*- coding: utf-8 -*- # hub/ticket/ui/cards/task_card_pixmap_factory.py """Pixmap-хелперы для карточки Ticket.""" from __future__ import annotations from PySide6.QtCore import Qt from PySide6.QtGui import QColor, QFont, QPainter, QPainterPath, QPixmap def compute_square_size(width: int, height: int, padding: int = 0) -> int: """Вернуть квадратный размер по меньшей стороне с учётом внутреннего отступа.""" available = min(width, height) - padding return max(0, available) def build_avatar_pixmap(source: QPixmap, size: int) -> QPixmap: """Построить круглый avatar-pixmap из исходной фотографии.""" avatar = QPixmap(size, size) avatar.fill(Qt.GlobalColor.transparent) painter = QPainter(avatar) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) outer_padding = 1 outer_size = size - (outer_padding * 2) outer_path = QPainterPath() outer_path.addEllipse(outer_padding, outer_padding, outer_size, outer_size) painter.fillPath(outer_path, QColor("#A3A3A3")) inner_padding = outer_padding + 2 inner_size = size - (inner_padding * 2) inner_path = QPainterPath() inner_path.addEllipse(inner_padding, inner_padding, inner_size, inner_size) painter.setClipPath(inner_path) scaled = source.scaled( inner_size, inner_size, Qt.AspectRatioMode.KeepAspectRatioByExpanding, Qt.TransformationMode.SmoothTransformation, ) source_x = max(0, (scaled.width() - inner_size) // 2) source_y = max(0, (scaled.height() - inner_size) // 2) painter.drawPixmap(inner_padding, inner_padding, scaled, source_x, source_y, inner_size, inner_size) painter.end() return avatar def build_placeholder_avatar_pixmap(size: int) -> QPixmap: """Построить круглый placeholder-аватар с вопросительным знаком.""" avatar = QPixmap(size, size) avatar.fill(Qt.GlobalColor.transparent) painter = QPainter(avatar) painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) outer_padding = 1 circle_size = size - (outer_padding * 2) circle_path = QPainterPath() circle_path.addEllipse(outer_padding, outer_padding, circle_size, circle_size) painter.fillPath(circle_path, QColor("#F6A493")) painter.setPen(QColor("#FFFFFF")) painter.drawPath(circle_path) font = QFont() font.setPixelSize(18) font.setBold(True) painter.setFont(font) painter.setPen(QColor("#172B4D")) painter.drawText(outer_padding, outer_padding, circle_size, circle_size, Qt.AlignmentFlag.AlignCenter, "?") painter.end() return avatar def load_scaled_icon_pixmap(image_path: str, width: int, height: int, padding: int = 0) -> QPixmap | None: """Загрузить и отмасштабировать stage-icon по фактическому размеру ячейки.""" if not image_path: return None pixmap = QPixmap(image_path) if pixmap.isNull(): return None icon_size = compute_square_size(width, height, padding) if icon_size <= 0: return None return pixmap.scaled( icon_size, icon_size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation, ) def load_tinted_icon_pixmap( image_path: str, width: int, height: int, color_hex: str, padding: int = 0, ) -> QPixmap | None: """Загрузить stage-icon и перекрасить его в нужный цвет.""" scaled = load_scaled_icon_pixmap(image_path, width, height, padding) if scaled is None: return None tinted = QPixmap(scaled.size()) tinted.fill(Qt.GlobalColor.transparent) painter = QPainter(tinted) painter.drawPixmap(0, 0, scaled) painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceIn) painter.fillRect(tinted.rect(), QColor(color_hex)) painter.end() return tinted def load_avatar_pixmap(image_path: str, width: int, height: int, padding: int = 0) -> QPixmap | None: """Загрузить фото специалиста и подготовить круглый avatar-pixmap.""" if not image_path: return None pixmap = QPixmap(image_path) if pixmap.isNull(): return None avatar_size = compute_square_size(width, height, padding) if avatar_size <= 0: return None return build_avatar_pixmap(pixmap, avatar_size)