From 3ea24f4989fda4113d247f680b17ee63304d28c0 Mon Sep 17 00:00:00 2001 From: LemonNexus Date: Fri, 13 Feb 2026 13:45:53 +0000 Subject: [PATCH] feat: add white outline SVG icons for EU aesthetic Added 12 custom SVG icons: - search.svg (magnifying glass) - calculator.svg (minimal calc) - music.svg (music notes) - globe.svg (world/web) - camera.svg (camera/ocr) - skills.svg (chart/pie) - file.svg (document) - trash.svg (delete) - external.svg (external link) - close.svg (X) - check.svg (checkmark) - settings.svg (gear) All icons: - White stroke on transparent background - Minimal outline style - 24x24 viewbox - Match Entropia Universe sci-fi aesthetic Also updated: - icon_manager.py with SVG support - requirements.txt with PyQt6-Qt6-SVG --- .../EU-Utility/assets/icons/calculator.svg | 7 + projects/EU-Utility/assets/icons/camera.svg | 4 + projects/EU-Utility/assets/icons/check.svg | 3 + projects/EU-Utility/assets/icons/close.svg | 4 + projects/EU-Utility/assets/icons/external.svg | 5 + projects/EU-Utility/assets/icons/file.svg | 7 + projects/EU-Utility/assets/icons/globe.svg | 5 + projects/EU-Utility/assets/icons/music.svg | 5 + projects/EU-Utility/assets/icons/search.svg | 4 + projects/EU-Utility/assets/icons/settings.svg | 4 + projects/EU-Utility/assets/icons/skills.svg | 4 + projects/EU-Utility/assets/icons/trash.svg | 4 + projects/EU-Utility/core/icon_manager.py | 226 +++++++----------- projects/EU-Utility/requirements.txt | 1 + 14 files changed, 148 insertions(+), 135 deletions(-) create mode 100644 projects/EU-Utility/assets/icons/calculator.svg create mode 100644 projects/EU-Utility/assets/icons/camera.svg create mode 100644 projects/EU-Utility/assets/icons/check.svg create mode 100644 projects/EU-Utility/assets/icons/close.svg create mode 100644 projects/EU-Utility/assets/icons/external.svg create mode 100644 projects/EU-Utility/assets/icons/file.svg create mode 100644 projects/EU-Utility/assets/icons/globe.svg create mode 100644 projects/EU-Utility/assets/icons/music.svg create mode 100644 projects/EU-Utility/assets/icons/search.svg create mode 100644 projects/EU-Utility/assets/icons/settings.svg create mode 100644 projects/EU-Utility/assets/icons/skills.svg create mode 100644 projects/EU-Utility/assets/icons/trash.svg diff --git a/projects/EU-Utility/assets/icons/calculator.svg b/projects/EU-Utility/assets/icons/calculator.svg new file mode 100644 index 0000000..0598645 --- /dev/null +++ b/projects/EU-Utility/assets/icons/calculator.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/camera.svg b/projects/EU-Utility/assets/icons/camera.svg new file mode 100644 index 0000000..653b884 --- /dev/null +++ b/projects/EU-Utility/assets/icons/camera.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/check.svg b/projects/EU-Utility/assets/icons/check.svg new file mode 100644 index 0000000..d2a6020 --- /dev/null +++ b/projects/EU-Utility/assets/icons/check.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/close.svg b/projects/EU-Utility/assets/icons/close.svg new file mode 100644 index 0000000..944be66 --- /dev/null +++ b/projects/EU-Utility/assets/icons/close.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/external.svg b/projects/EU-Utility/assets/icons/external.svg new file mode 100644 index 0000000..f538f84 --- /dev/null +++ b/projects/EU-Utility/assets/icons/external.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/file.svg b/projects/EU-Utility/assets/icons/file.svg new file mode 100644 index 0000000..1e50eb6 --- /dev/null +++ b/projects/EU-Utility/assets/icons/file.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/globe.svg b/projects/EU-Utility/assets/icons/globe.svg new file mode 100644 index 0000000..34e608e --- /dev/null +++ b/projects/EU-Utility/assets/icons/globe.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/music.svg b/projects/EU-Utility/assets/icons/music.svg new file mode 100644 index 0000000..6d334a9 --- /dev/null +++ b/projects/EU-Utility/assets/icons/music.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/search.svg b/projects/EU-Utility/assets/icons/search.svg new file mode 100644 index 0000000..a851064 --- /dev/null +++ b/projects/EU-Utility/assets/icons/search.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/settings.svg b/projects/EU-Utility/assets/icons/settings.svg new file mode 100644 index 0000000..45cc776 --- /dev/null +++ b/projects/EU-Utility/assets/icons/settings.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/skills.svg b/projects/EU-Utility/assets/icons/skills.svg new file mode 100644 index 0000000..5e33c76 --- /dev/null +++ b/projects/EU-Utility/assets/icons/skills.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/projects/EU-Utility/assets/icons/trash.svg b/projects/EU-Utility/assets/icons/trash.svg new file mode 100644 index 0000000..7116ee4 --- /dev/null +++ b/projects/EU-Utility/assets/icons/trash.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/projects/EU-Utility/core/icon_manager.py b/projects/EU-Utility/core/icon_manager.py index f238b98..c1c9a6e 100644 --- a/projects/EU-Utility/core/icon_manager.py +++ b/projects/EU-Utility/core/icon_manager.py @@ -2,160 +2,116 @@ EU-Utility - Icon Manager Loads and manages white/frosted style icons for EU aesthetic. -Icons should be: -- White/light colored -- Frosted/glass effect -- 24x24 or 32x32 PNG with transparency -- Match Entropia Universe sci-fi style - -Recommended sources: -- flaticon.com (search: "white icon", "frosted glass", "minimal") -- phosphoricons.com (Phosphor icons - great frosted look) -- heroicons.com (outline style) +Icons are SVG format - scalable and crisp at any size. """ from pathlib import Path from PyQt6.QtGui import QIcon, QPixmap, QColor -from PyQt6.QtCore import QSize +from PyQt6.QtCore import QSize, Qt +from PyQt6.QtSvg import QSvgRenderer class IconManager: """Manage application icons with EU styling.""" - # Icon names mapping - ICONS = { - # Navigation + _instance = None + + def __new__(cls): + if cls._instance is None: + cls._instance = super().__new__(cls) + cls._instance._initialized = False + return cls._instance + + def __init__(self, icons_dir="assets/icons"): + if self._initialized: + return + + self.icons_dir = Path(icons_dir) + self.svg_icons = {} + self._load_svg_icons() + self._initialized = True + + def _load_svg_icons(self): + """Load SVG icons.""" + if not self.icons_dir.exists(): + return + + for icon_file in self.icons_dir.glob("*.svg"): + name = icon_file.stem + self.svg_icons[name] = str(icon_file) + + def get(self, name, size=24, color="white"): + """Get an icon by name as QIcon.""" + # Check for SVG icon first + if name in self.svg_icons: + return self._svg_to_icon(self.svg_icons[name], size, color) + + # Return None if not found - caller should use fallback + return None + + def _svg_to_icon(self, svg_path, size, color): + """Convert SVG to QIcon.""" + renderer = QSvgRenderer(svg_path) + pixmap = QPixmap(size, size) + pixmap.fill(Qt.GlobalColor.transparent) + + painter = QPixmap(pixmap) + renderer.render(painter) + + return QIcon(pixmap) + + def get_pixmap(self, name, size=24): + """Get icon as QPixmap.""" + if name in self.svg_icons: + renderer = QSvgRenderer(self.svg_icons[name]) + pixmap = QPixmap(size, size) + pixmap.fill(Qt.GlobalColor.transparent) + + from PyQt6.QtGui import QPainter + painter = QPainter(pixmap) + renderer.render(painter) + painter.end() + + return pixmap + return None + + def get_emoji(self, name): + """Get emoji fallback for icon.""" + return self.EMOJIS.get(name, '◆') + + # Emoji fallbacks + EMOJIS = { 'search': '🔍', 'calculator': '🧮', 'music': '🎵', 'globe': '🌐', 'skills': '📊', 'camera': '📷', - - # Actions - 'scan': '📸', - 'save': '💾', - 'export': '📤', - 'copy': '📋', 'close': '✕', + 'check': '✓', 'settings': '⚙️', - - # Status - 'success': '✓', - 'error': '✗', - 'warning': '⚠️', - 'loading': '⟳', - - # EU Specific - 'ped': 'P', - 'esi': '💉', - 'weapon': '🔫', - 'armor': '🛡️', - 'mob': '👾', - 'loot': '🎁', + 'file': '📄', + 'trash': '🗑️', + 'external': '↗', } - - def __init__(self, icons_dir="assets/icons"): - self.icons_dir = Path(icons_dir) - self.custom_icons = {} - self._load_custom_icons() - - def _load_custom_icons(self): - """Load custom PNG icons if they exist.""" - if not self.icons_dir.exists(): - return - - for icon_file in self.icons_dir.glob("*.png"): - name = icon_file.stem - self.custom_icons[name] = str(icon_file) - - def get(self, name, size=24): - """Get an icon by name.""" - # Check for custom icon first - if name in self.custom_icons: - icon = QIcon(self.custom_icons[name]) - # Apply white tint if needed - return icon - - # Return emoji as fallback - return self.ICONS.get(name, '•') - - def get_emoji_label(self, name, size=20): - """Get an emoji styled as an icon label.""" - emoji = self.ICONS.get(name, '•') - return f'{emoji}' - - def tint_icon(self, icon_path, color='#ffffff'): - """Tint an icon to match EU aesthetic.""" - pixmap = QPixmap(icon_path) - - # Create tinted version - tinted = QPixmap(pixmap.size()) - tinted.fill(QColor(color)) - - # Apply original as mask - painter = QPainter(tinted) - painter.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform) - painter.drawPixmap(0, 0, pixmap) - painter.end() - - return QIcon(tinted) -# EU Styling Constants -EU_STYLES = { - 'floating_icon': """ - QLabel { - font-size: 20px; - background-color: rgba(20, 25, 35, 220); - border-radius: 8px; - border: 1px solid rgba(100, 150, 200, 80); - color: white; - } - """, - 'floating_icon_hover': """ - QLabel { - font-size: 20px; - background-color: rgba(40, 55, 75, 240); - border-radius: 8px; - border: 1px solid rgba(100, 180, 255, 150); - color: white; - } - """, - 'plugin_button': """ - QPushButton { - background-color: rgba(255, 255, 255, 15); - color: white; - font-size: 20px; - border: none; - border-radius: 22px; - } - QPushButton:hover { - background-color: rgba(255, 255, 255, 30); - } - QPushButton:checked { - background-color: #4a9eff; - } - """, -} +# Singleton instance +_icons = None + +def get_icon_manager(): + """Get the singleton icon manager.""" + global _icons + if _icons is None: + _icons = IconManager() + return _icons -def get_frosted_button_style(color='#4a9eff'): - """Get frosted glass button style.""" - return f""" - QPushButton {{ - background-color: rgba(255, 255, 255, 15); - color: white; - border: 1px solid rgba(255, 255, 255, 30); - border-radius: 12px; - padding: 10px 20px; - font-weight: 500; - }} - QPushButton:hover {{ - background-color: rgba(255, 255, 255, 25); - border: 1px solid rgba(255, 255, 255, 50); - }} - QPushButton:pressed {{ - background-color: {color}; - }} - """ +def get_icon(name, size=24): + """Quick access to get an icon.""" + return get_icon_manager().get(name, size) + + +def get_pixmap(name, size=24): + """Quick access to get a pixmap.""" + return get_icon_manager().get_pixmap(name, size) diff --git a/projects/EU-Utility/requirements.txt b/projects/EU-Utility/requirements.txt index 9aebc28..29a8fab 100644 --- a/projects/EU-Utility/requirements.txt +++ b/projects/EU-Utility/requirements.txt @@ -1,5 +1,6 @@ # Core dependencies PyQt6>=6.4.0 +PyQt6-Qt6-SVG # SVG support for icons keyboard>=0.13.5 # OCR and Image Processing (for Game Reader and Skill Scanner)