"""
Icon Management System
=====================
Comprehensive icon system with SVG icons, Material Design icons,
and utility functions for the Traffic Monitoring Application.
Features:
- Material Design icon set
- SVG icon generation
- Icon theming and colorization
- Size variants and scaling
- Custom icon registration
"""
from PySide6.QtGui import QIcon, QPixmap, QPainter, QColor, QBrush, QPen
from PySide6.QtCore import Qt, QSize
from PySide6.QtSvg import QSvgRenderer
from typing import Dict, Optional, Tuple
import base64
from io import BytesIO
class IconTheme:
"""Icon theme management"""
# Icon colors for dark theme
PRIMARY = "#FFFFFF"
SECONDARY = "#B0B0B0"
ACCENT = "#00BCD4"
SUCCESS = "#4CAF50"
WARNING = "#FF9800"
ERROR = "#F44336"
INFO = "#2196F3"
class SVGIcons:
"""Collection of SVG icons as base64 encoded strings"""
# Navigation icons
HOME = """
"""
PLAY = """
"""
PAUSE = """
"""
STOP = """
"""
RECORD = """
"""
# Detection and monitoring icons
CAMERA = """
"""
MONITOR = """
"""
TRAFFIC_LIGHT = """
"""
VIOLATION = """
"""
# Analytics and statistics icons
CHART_BAR = """
"""
CHART_LINE = """
"""
CHART_PIE = """
"""
DASHBOARD = """
"""
# System and settings icons
SETTINGS = """
"""
EXPORT = """
"""
IMPORT = """
"""
SAVE = """
"""
# Status and alert icons
CHECK_CIRCLE = """
"""
WARNING_CIRCLE = """
"""
ERROR_CIRCLE = """
"""
INFO_CIRCLE = """
"""
# Action icons
REFRESH = """
"""
DELETE = """
"""
EDIT = """
"""
FILTER = """
"""
SEARCH = """
"""
class IconManager:
"""Manages icons for the application"""
def __init__(self):
self._icon_cache: Dict[str, QIcon] = {}
self.theme = IconTheme()
def get_icon(self, name: str, color: str = IconTheme.PRIMARY, size: int = 24) -> QIcon:
"""Get an icon by name with specified color and size"""
cache_key = f"{name}_{color}_{size}"
if cache_key in self._icon_cache:
return self._icon_cache[cache_key]
# Get SVG content
svg_content = getattr(SVGIcons, name.upper(), None)
if not svg_content:
return QIcon() # Return empty icon if not found
# Replace currentColor with specified color
svg_content = svg_content.replace('currentColor', color)
# Create icon from SVG
icon = self._create_icon_from_svg(svg_content, size)
self._icon_cache[cache_key] = icon
return icon
def _create_icon_from_svg(self, svg_content: str, size: int) -> QIcon:
"""Create QIcon from SVG content"""
# Create QSvgRenderer from SVG content
svg_bytes = svg_content.encode('utf-8')
renderer = QSvgRenderer(svg_bytes)
# Create pixmap
pixmap = QPixmap(size, size)
pixmap.fill(Qt.transparent)
# Paint SVG onto pixmap
painter = QPainter(pixmap)
renderer.render(painter)
painter.end()
return QIcon(pixmap)
def get_status_icon(self, status: str, size: int = 16) -> QIcon:
"""Get icon for specific status"""
status_map = {
'success': ('CHECK_CIRCLE', IconTheme.SUCCESS),
'warning': ('WARNING_CIRCLE', IconTheme.WARNING),
'error': ('ERROR_CIRCLE', IconTheme.ERROR),
'info': ('INFO_CIRCLE', IconTheme.INFO),
'violation': ('VIOLATION', IconTheme.ERROR),
'active': ('PLAY', IconTheme.SUCCESS),
'inactive': ('PAUSE', IconTheme.SECONDARY),
'recording': ('RECORD', IconTheme.ERROR)
}
icon_name, color = status_map.get(status, ('INFO_CIRCLE', IconTheme.INFO))
return self.get_icon(icon_name, color, size)
def get_action_icon(self, action: str, size: int = 20) -> QIcon:
"""Get icon for specific action"""
action_map = {
'play': 'PLAY',
'pause': 'PAUSE',
'stop': 'STOP',
'record': 'RECORD',
'settings': 'SETTINGS',
'export': 'EXPORT',
'import': 'IMPORT',
'save': 'SAVE',
'refresh': 'REFRESH',
'delete': 'DELETE',
'edit': 'EDIT',
'filter': 'FILTER',
'search': 'SEARCH'
}
icon_name = action_map.get(action, 'INFO_CIRCLE')
return self.get_icon(icon_name, IconTheme.PRIMARY, size)
def get_navigation_icon(self, view: str, size: int = 24) -> QIcon:
"""Get icon for navigation views"""
nav_map = {
'home': 'HOME',
'detection': 'CAMERA',
'violations': 'VIOLATION',
'analytics': 'DASHBOARD',
'export': 'EXPORT',
'monitor': 'MONITOR',
'chart': 'CHART_BAR'
}
icon_name = nav_map.get(view, 'HOME')
return self.get_icon(icon_name, IconTheme.ACCENT, size)
def create_colored_icon(self, base_icon: str, color: str, size: int = 24) -> QIcon:
"""Create a colored version of an icon"""
return self.get_icon(base_icon, color, size)
def set_theme_color(self, color: str):
"""Set the theme accent color"""
self.theme.ACCENT = color
# Clear cache to regenerate icons with new color
self._icon_cache.clear()
# Global icon manager instance
icon_manager = IconManager()
# Convenience functions
def get_icon(name: str, color: str = IconTheme.PRIMARY, size: int = 24) -> QIcon:
"""Get an icon - convenience function"""
return icon_manager.get_icon(name, color, size)
def get_status_icon(status: str, size: int = 16) -> QIcon:
"""Get status icon - convenience function"""
return icon_manager.get_status_icon(status, size)
def get_action_icon(action: str, size: int = 20) -> QIcon:
"""Get action icon - convenience function"""
return icon_manager.get_action_icon(action, size)
def get_navigation_icon(view: str, size: int = 24) -> QIcon:
"""Get navigation icon - convenience function"""
return icon_manager.get_navigation_icon(view, size)
# Common icon sets for easy access
class CommonIcons:
"""Commonly used icon combinations"""
@staticmethod
def toolbar_icons() -> Dict[str, QIcon]:
"""Get all toolbar icons"""
return {
'play': get_action_icon('play'),
'pause': get_action_icon('pause'),
'stop': get_action_icon('stop'),
'record': get_action_icon('record'),
'settings': get_action_icon('settings'),
'export': get_action_icon('export'),
'refresh': get_action_icon('refresh')
}
@staticmethod
def status_icons() -> Dict[str, QIcon]:
"""Get all status icons"""
return {
'success': get_status_icon('success'),
'warning': get_status_icon('warning'),
'error': get_status_icon('error'),
'info': get_status_icon('info'),
'violation': get_status_icon('violation'),
'active': get_status_icon('active'),
'inactive': get_status_icon('inactive'),
'recording': get_status_icon('recording')
}
@staticmethod
def navigation_icons() -> Dict[str, QIcon]:
"""Get all navigation icons"""
return {
'detection': get_navigation_icon('detection'),
'violations': get_navigation_icon('violations'),
'analytics': get_navigation_icon('analytics'),
'export': get_navigation_icon('export'),
'monitor': get_navigation_icon('monitor')
}
# Traffic light specific icons
def create_traffic_light_icon(red_on: bool = False, yellow_on: bool = False, green_on: bool = False, size: int = 32) -> QIcon:
"""Create a traffic light icon with specific lights on/off"""
svg_template = f"""
"""
svg_bytes = svg_template.encode('utf-8')
renderer = QSvgRenderer(svg_bytes)
pixmap = QPixmap(size, size)
pixmap.fill(Qt.transparent)
painter = QPainter(pixmap)
renderer.render(painter)
painter.end()
return QIcon(pixmap)
# New FinaleIcons class to wrap the existing functionality
class FinaleIcons:
"""
Wrapper class for icon management to maintain compatibility
with existing code that references FinaleIcons.get_icon() etc.
"""
@staticmethod
def get_icon(name: str, color: str = IconTheme.PRIMARY, size: int = 24) -> QIcon:
"""Get an icon by name"""
return get_icon(name, color, size)
@staticmethod
def get_status_icon(status: str, size: int = 16) -> QIcon:
"""Get a status icon"""
return get_status_icon(status, size)
@staticmethod
def get_action_icon(action: str, size: int = 20) -> QIcon:
"""Get an action icon"""
return get_action_icon(action, size)
@staticmethod
def get_navigation_icon(view: str, size: int = 24) -> QIcon:
"""Get a navigation icon"""
return get_navigation_icon(view, size)
@staticmethod
def create_colored_icon(base_icon: str, color: str, size: int = 24) -> QIcon:
"""Create a colored version of an icon"""
return get_icon(base_icon, color, size)
@staticmethod
def traffic_light_icon(red_on: bool = False, yellow_on: bool = False, green_on: bool = False, size: int = 32) -> QIcon:
"""Create a traffic light icon with specific lights on/off"""
return create_traffic_light_icon(red_on, yellow_on, green_on, size)