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)