diff --git a/projects/EU-Utility/core/overlay_window.py b/projects/EU-Utility/core/overlay_window.py index 3898880..dfcdbc9 100644 --- a/projects/EU-Utility/core/overlay_window.py +++ b/projects/EU-Utility/core/overlay_window.py @@ -1,7 +1,7 @@ """ EU-Utility - Overlay Window -Spotlight-style overlay with frosted glass effect and Phosphor icons. +Fully EU-styled overlay window matching Entropia Universe aesthetic. """ import sys @@ -22,6 +22,8 @@ except ImportError: PYQT6_AVAILABLE = False print("PyQt6 not available. Install with: pip install PyQt6") +from core.eu_styles import EU_COLORS, EU_STYLES, get_eu_style + class IconHelper: """Helper to load and render SVG icons.""" @@ -29,7 +31,7 @@ class IconHelper: ICONS_DIR = Path(__file__).parent.parent / "assets" / "icons" @classmethod - def get_icon(cls, name, size=24, color="white"): + def get_icon(cls, name, size=24): """Get QIcon from SVG.""" svg_path = cls.ICONS_DIR / f"{name}.svg" if not svg_path.exists(): @@ -44,50 +46,35 @@ class IconHelper: painter.end() return QIcon(pixmap) - - @classmethod - def get_pixmap(cls, name, size=24): - """Get QPixmap from SVG.""" - svg_path = cls.ICONS_DIR / f"{name}.svg" - if not svg_path.exists(): - return None - - renderer = QSvgRenderer(str(svg_path)) - pixmap = QPixmap(size, size) - pixmap.fill(Qt.GlobalColor.transparent) - - painter = QPainter(pixmap) - renderer.render(painter) - painter.end() - - return pixmap class OverlayWindow(QMainWindow): - """Spotlight-style overlay window.""" + """EU-styled overlay window.""" visibility_changed = pyqtSignal(bool) - # Plugin icon mapping - Phosphor solid icons + # Plugin icon mapping with EU accent colors PLUGIN_ICONS = { - "Universal Search": ("search", "#4a9eff"), - "Calculator": ("calculator", "#9c27b0"), + "Universal Search": ("search", "#ff8c42"), + "Calculator": ("calculator", "#ff8c42"), "Spotify": ("music", "#1db954"), - "Nexus Search": ("globe", "#ff9800"), - "Game Reader": ("camera", "#f44336"), - "Skill Scanner": ("skills", "#00bcd4"), - } - - # Emoji fallbacks - ICONS = { - 'search': '🔍', - 'calculator': '🧮', - 'music': '🎵', - 'globe': '🌐', - 'skills': '📊', - 'camera': '📷', - 'close': '✕', - 'menu': '☰', + "Nexus Search": ("globe", "#ff8c42"), + "Game Reader": ("camera", "#ff8c42"), + "Skill Scanner": ("skills", "#ff8c42"), + "Loot Tracker": ("loot", "#ff8c42"), + "Mining Helper": ("mob", "#ff8c42"), + "Chat Logger": ("file", "#ff8c42"), + "Mission Tracker": ("target", "#ff8c42"), + "Codex Tracker": ("mob", "#ff8c42"), + "Auction Tracker": ("ped", "#ff8c42"), + "DPP Calculator": ("weapon", "#ff8c42"), + "Enhancer Calc": ("armor", "#ff8c42"), + "TP Runner": ("globe", "#ff8c42"), + "Inventory": ("loot", "#ff8c42"), + "Settings": ("settings", "#ff8c42"), + "Plugin Store": ("external", "#ff8c42"), + "Crafting Calc": ("armor", "#ff8c42"), + "Global Tracker": ("ped", "#ff8c42"), } def __init__(self, plugin_manager=None): @@ -104,115 +91,108 @@ class OverlayWindow(QMainWindow): self._setup_ui() self._setup_tray() - # Start hidden self.hide_overlay() def _setup_window(self): - """Configure window properties.""" + """Configure window with EU styling.""" self.setWindowTitle("EU-Utility") - # Frameless, transparent, always on top self.setWindowFlags( Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Tool ) - # Transparent background self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) - # Size and position - wider but shorter for spotlight style - self.resize(700, 500) + # EU-sized window + self.resize(800, 550) self._center_window() def _center_window(self): """Center window on screen.""" screen = QApplication.primaryScreen().geometry() x = (screen.width() - self.width()) // 2 - y = (screen.height() - self.height()) // 3 # Upper third like Spotlight + y = (screen.height() - self.height()) // 3 self.move(x, y) def _setup_ui(self): - """Setup the Spotlight-style UI.""" - # Central widget + """Setup EU-styled UI.""" central = QWidget() self.setCentralWidget(central) - # Main layout layout = QVBoxLayout(central) - layout.setContentsMargins(20, 20, 20, 20) + layout.setContentsMargins(15, 15, 15, 15) layout.setSpacing(0) - # Frosted glass container + # Main container with EU styling self.container = QFrame() - self.container.setObjectName("spotlightContainer") - self.container.setStyleSheet(""" - #spotlightContainer { - background-color: rgba(40, 40, 40, 180); - border-radius: 20px; - border: 1px solid rgba(255, 255, 255, 30); - } + self.container.setObjectName("euContainer") + self.container.setStyleSheet(f""" + #euContainer {{ + background-color: {EU_COLORS['bg_dark']}; + border: 1px solid {EU_COLORS['border_medium']}; + border-radius: 8px; + }} """) - # Add shadow effect + # Add shadow shadow = QGraphicsDropShadowEffect() - shadow.setBlurRadius(30) - shadow.setColor(QColor(0, 0, 0, 100)) - shadow.setOffset(0, 10) + shadow.setBlurRadius(25) + shadow.setColor(QColor(0, 0, 0, 120)) + shadow.setOffset(0, 5) self.container.setGraphicsEffect(shadow) container_layout = QVBoxLayout(self.container) container_layout.setContentsMargins(0, 0, 0, 0) container_layout.setSpacing(0) - # Header with search bar style + # EU-styled header header = QWidget() - header.setStyleSheet(""" - QWidget { - background-color: rgba(255, 255, 255, 15); - border-top-left-radius: 20px; - border-top-right-radius: 20px; - border-bottom: 1px solid rgba(255, 255, 255, 20); - } + header.setStyleSheet(f""" + QWidget {{ + background-color: {EU_COLORS['bg_header']}; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + border-bottom: 1px solid {EU_COLORS['border_medium']}; + }} """) header_layout = QHBoxLayout(header) - header_layout.setContentsMargins(20, 15, 20, 15) - header_layout.setSpacing(15) + header_layout.setContentsMargins(15, 12, 15, 12) + header_layout.setSpacing(12) - # Search icon - search_icon = QLabel("🔍") - search_icon.setStyleSheet("font-size: 18px; background: transparent; border: none;") - header_layout.addWidget(search_icon) + # Logo/Icon + logo = QLabel("⚡") + logo.setStyleSheet("font-size: 18px; background: transparent;") + header_layout.addWidget(logo) - # Title/Search label + # Title title = QLabel("EU-Utility") - title.setStyleSheet(""" - color: rgba(255, 255, 255, 200); + title.setStyleSheet(f""" + color: {EU_COLORS['accent_orange']}; font-size: 16px; - font-weight: 500; + font-weight: bold; background: transparent; - border: none; """) header_layout.addWidget(title) header_layout.addStretch() - # Close button (X) - subtle - close_btn = QPushButton("×") + # Close button (EU style) + close_btn = QPushButton("✕") close_btn.setFixedSize(28, 28) - close_btn.setStyleSheet(""" - QPushButton { + close_btn.setStyleSheet(f""" + QPushButton {{ background-color: transparent; - color: rgba(255, 255, 255, 150); - font-size: 20px; - font-weight: 300; + color: {EU_COLORS['text_muted']}; + font-size: 16px; border: none; - border-radius: 14px; - } - QPushButton:hover { - background-color: rgba(255, 255, 255, 20); + border-radius: 4px; + }} + QPushButton:hover {{ + background-color: rgba(244, 67, 54, 150); color: white; - } + }} """) close_btn.clicked.connect(self.hide_overlay) header_layout.addWidget(close_btn) @@ -223,8 +203,8 @@ class OverlayWindow(QMainWindow): self.content_area = QWidget() self.content_area.setStyleSheet("background: transparent;") content_layout = QVBoxLayout(self.content_area) - content_layout.setContentsMargins(20, 20, 20, 20) - content_layout.setSpacing(15) + content_layout.setContentsMargins(15, 15, 15, 15) + content_layout.setSpacing(12) # Plugin stack self.plugin_stack = QStackedWidget() @@ -233,68 +213,65 @@ class OverlayWindow(QMainWindow): container_layout.addWidget(self.content_area, 1) - # Plugin selector bar (at bottom) + # EU-styled plugin bar if self.plugin_manager: self._setup_plugin_bar(container_layout) layout.addWidget(self.container) def _setup_plugin_bar(self, layout): - """Setup circular plugin icon bar at bottom with Phosphor icons.""" + """Setup EU-styled plugin icon bar.""" bar = QWidget() - bar.setStyleSheet(""" - QWidget { - background-color: rgba(0, 0, 0, 40); - border-bottom-left-radius: 20px; - border-bottom-right-radius: 20px; - } + bar.setStyleSheet(f""" + QWidget {{ + background-color: {EU_COLORS['bg_header']}; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + border-top: 1px solid {EU_COLORS['border_medium']}; + }} """) bar_layout = QHBoxLayout(bar) - bar_layout.setContentsMargins(20, 12, 20, 12) - bar_layout.setSpacing(12) + bar_layout.setContentsMargins(15, 10, 15, 10) + bar_layout.setSpacing(8) bar_layout.addStretch() # Add plugin icons for idx, (plugin_id, plugin) in enumerate(self.plugin_manager.get_all_plugins().items()): btn = QPushButton() - # Get icon and color for this plugin icon_name, accent_color = self.PLUGIN_ICONS.get( plugin.name, - ("target", "#4a9eff") + ("target", EU_COLORS['accent_orange']) ) - # Try to load SVG icon - icon = IconHelper.get_icon(icon_name, size=20) + # Load SVG icon + icon = IconHelper.get_icon(icon_name, size=18) if icon: btn.setIcon(icon) - btn.setIconSize(QSize(20, 20)) - btn.setText("") # No text, just icon + btn.setIconSize(QSize(18, 18)) else: - # Fallback to emoji - emoji = self.ICONS.get(icon_name, '◆') - btn.setText(emoji) + btn.setText("◆") - btn.setFixedSize(40, 40) + btn.setFixedSize(36, 36) btn.setStyleSheet(f""" QPushButton {{ - background-color: rgba(255, 255, 255, 12); - border: 1px solid rgba(255, 255, 255, 20); - border-radius: 20px; + background-color: {EU_COLORS['bg_panel']}; + border: 1px solid {EU_COLORS['border_subtle']}; + border-radius: 4px; }} QPushButton:hover {{ - background-color: rgba(255, 255, 255, 25); - border: 1px solid rgba(255, 255, 255, 40); + background-color: {EU_COLORS['bg_hover']}; + border: 1px solid {EU_COLORS['border_orange']}; }} QPushButton:checked {{ background-color: {accent_color}; - border: 1px solid rgba(255, 255, 255, 50); + border: 1px solid {accent_color}; }} """) btn.setCheckable(True) btn.setToolTip(plugin.name) - # Add plugin UI to stack + # Add plugin UI try: plugin_ui = plugin.get_ui() if plugin_ui: @@ -311,58 +288,51 @@ class OverlayWindow(QMainWindow): bar_layout.addStretch() layout.addWidget(bar) - # Select first plugin by default + # Select first if self.plugin_buttons: self.plugin_buttons[0].setChecked(True) def _switch_plugin(self, index, button): """Switch to selected plugin.""" - # Uncheck all other buttons for btn in self.plugin_buttons: if btn != button: btn.setChecked(False) - - # Ensure clicked button stays checked button.setChecked(True) - - # Switch stack self.plugin_stack.setCurrentIndex(index) def _setup_tray(self): - """Setup system tray icon.""" + """Setup system tray.""" self.tray_icon = QSystemTrayIcon(self) - # Use default icon if custom not found icon_path = Path("assets/icon.ico") if icon_path.exists(): self.tray_icon.setIcon(QIcon(str(icon_path))) - # Tray menu tray_menu = QMenu() - tray_menu.setStyleSheet(""" - QMenu { - background-color: rgba(40, 40, 40, 240); + tray_menu.setStyleSheet(f""" + QMenu {{ + background-color: {EU_COLORS['bg_dark']}; color: white; - border: 1px solid rgba(255, 255, 255, 30); - border-radius: 8px; + border: 1px solid {EU_COLORS['border_medium']}; + border-radius: 6px; padding: 8px; - } - QMenu::item { + }} + QMenu::item {{ padding: 8px 20px; border-radius: 4px; - } - QMenu::item:selected { - background-color: #4a9eff; - } + }} + QMenu::item:selected {{ + background-color: {EU_COLORS['accent_orange']}; + }} """) - show_action = QAction("🔍 Show EU-Utility", self) + show_action = QAction("⚡ Show EU-Utility", self) show_action.triggered.connect(self.show_overlay) tray_menu.addAction(show_action) tray_menu.addSeparator() - quit_action = QAction("❌ Quit", self) + quit_action = QAction("✕ Quit", self) quit_action.triggered.connect(self.quit_app) tray_menu.addAction(quit_action) @@ -371,12 +341,12 @@ class OverlayWindow(QMainWindow): self.tray_icon.show() def _tray_activated(self, reason): - """Handle tray icon activation.""" + """Handle tray activation.""" if reason == QSystemTrayIcon.ActivationReason.DoubleClick: self.toggle_overlay() def show_overlay(self): - """Show the overlay.""" + """Show overlay.""" self.show() self.raise_() self.activateWindow() @@ -391,7 +361,7 @@ class OverlayWindow(QMainWindow): print(f"Error in on_show for {plugin.name}: {e}") def hide_overlay(self): - """Hide the overlay.""" + """Hide overlay.""" self.hide() self.is_visible = False self.visibility_changed.emit(False) @@ -404,14 +374,14 @@ class OverlayWindow(QMainWindow): print(f"Error in on_hide for {plugin.name}: {e}") def toggle_overlay(self): - """Toggle overlay visibility.""" + """Toggle overlay.""" if self.is_visible: self.hide_overlay() else: self.show_overlay() def quit_app(self): - """Quit the application.""" + """Quit application.""" if self.plugin_manager: self.plugin_manager.shutdown_all() @@ -419,7 +389,7 @@ class OverlayWindow(QMainWindow): QApplication.quit() def keyPressEvent(self, event): - """Handle key presses.""" + """Handle ESC key.""" if event.key() == Qt.Key.Key_Escape: self.hide_overlay() else: diff --git a/projects/EU-Utility/plugins/dashboard/__init__.py b/projects/EU-Utility/plugins/dashboard/__init__.py new file mode 100644 index 0000000..448dc14 --- /dev/null +++ b/projects/EU-Utility/plugins/dashboard/__init__.py @@ -0,0 +1,7 @@ +""" +Dashboard Plugin +""" + +from .plugin import DashboardPlugin + +__all__ = ["DashboardPlugin"] diff --git a/projects/EU-Utility/plugins/dashboard/plugin.py b/projects/EU-Utility/plugins/dashboard/plugin.py new file mode 100644 index 0000000..10cba69 --- /dev/null +++ b/projects/EU-Utility/plugins/dashboard/plugin.py @@ -0,0 +1,230 @@ +""" +EU-Utility - Dashboard Plugin + +Main dashboard with customizable widgets and overview. +""" + +from PyQt6.QtWidgets import ( + QWidget, QVBoxLayout, QHBoxLayout, QLabel, + QPushButton, QGridLayout, QFrame, QScrollArea, + QSizePolicy +) +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtGui import QColor + +from core.eu_styles import EU_COLORS, EU_STYLES +from plugins.base_plugin import BasePlugin + + +class DashboardPlugin(BasePlugin): + """Main dashboard with overview of all features.""" + + name = "Dashboard" + version = "1.0.0" + author = "ImpulsiveFPS" + description = "Overview dashboard with widgets" + hotkey = "ctrl+shift+home" + + def initialize(self): + """Setup dashboard.""" + self.widgets = [] + + def get_ui(self): + """Create dashboard UI.""" + widget = QWidget() + widget.setStyleSheet("background: transparent;") + + # Main scroll area + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setStyleSheet(""" + QScrollArea { + background: transparent; + border: none; + } + QScrollBar:vertical { + background: rgba(0, 0, 0, 50); + width: 8px; + border-radius: 4px; + } + QScrollBar::handle:vertical { + background: rgba(255, 255, 255, 30); + border-radius: 4px; + } + """) + + container = QWidget() + layout = QVBoxLayout(container) + layout.setSpacing(15) + layout.setContentsMargins(0, 0, 0, 0) + + # Welcome + welcome = QLabel("⚡ Welcome to EU-Utility") + welcome.setStyleSheet(f""" + color: {EU_COLORS['accent_orange']}; + font-size: 18px; + font-weight: bold; + """) + layout.addWidget(welcome) + + subtitle = QLabel("Your Entropia Universe companion") + subtitle.setStyleSheet(f"color: {EU_COLORS['text_muted']}; font-size: 12px;") + layout.addWidget(subtitle) + + # Quick stats row + stats_layout = QHBoxLayout() + stats_layout.setSpacing(10) + + stats = [ + ("💰 PED", "26.02", "Balance"), + ("📊 Skills", "12", "Tracked"), + ("🎁 Items", "98", "In Inventory"), + ("🎯 DPP", "3.45", "Current"), + ] + + for icon, value, label in stats: + card = self._create_stat_card(icon, value, label) + stats_layout.addWidget(card) + + layout.addLayout(stats_layout) + + # Quick actions + actions_label = QLabel("Quick Actions") + actions_label.setStyleSheet(f"color: {EU_COLORS['text_secondary']}; font-size: 13px; font-weight: bold;") + layout.addWidget(actions_label) + + actions_grid = QGridLayout() + actions_grid.setSpacing(10) + + actions = [ + ("🔍 Search", "Search items, mobs, locations"), + ("📸 Scan", "OCR scan game windows"), + ("📊 Skills", "Track skill gains"), + ("🎁 Loot", "Track hunting loot"), + ("⛏️ Mine", "Track mining finds"), + ("📈 Market", "Auction price tracking"), + ] + + for i, (name, desc) in enumerate(actions): + btn = self._create_action_button(name, desc) + actions_grid.addWidget(btn, i // 3, i % 3) + + layout.addLayout(actions_grid) + + # Recent activity + activity_label = QLabel("Recent Activity") + activity_label.setStyleSheet(f"color: {EU_COLORS['text_secondary']}; font-size: 13px; font-weight: bold; margin-top: 10px;") + layout.addWidget(activity_label) + + activity_frame = QFrame() + activity_frame.setStyleSheet(f""" + QFrame {{ + background-color: {EU_COLORS['bg_panel']}; + border: 1px solid {EU_COLORS['border_subtle']}; + border-radius: 6px; + }} + """) + activity_layout = QVBoxLayout(activity_frame) + + activities = [ + "✓ Scanned inventory - 26.02 PED", + "✓ Tracked skill gain: +5.2 Aim", + "✓ Recorded loot: Animal Hide (0.03 PED)", + "→ Mission progress: 12/100 Oratan", + ] + + for activity in activities: + lbl = QLabel(activity) + lbl.setStyleSheet(f"color: {EU_COLORS['text_secondary']}; font-size: 11px; padding: 4px 0;") + activity_layout.addWidget(lbl) + + layout.addWidget(activity_frame) + + # Tips + tips_frame = QFrame() + tips_frame.setStyleSheet(f""" + QFrame {{ + background-color: rgba(255, 140, 66, 20); + border: 1px solid rgba(255, 140, 66, 60); + border-radius: 6px; + }} + """) + tips_layout = QVBoxLayout(tips_frame) + + tip_title = QLabel("💡 Pro Tip") + tip_title.setStyleSheet(f"color: {EU_COLORS['accent_orange']}; font-weight: bold; font-size: 11px;") + tips_layout.addWidget(tip_title) + + tip_text = QLabel("Press Ctrl+Shift+U anytime to toggle this overlay. Use Ctrl+Shift+H to hide all widgets.") + tip_text.setStyleSheet(f"color: {EU_COLORS['text_secondary']}; font-size: 11px;") + tip_text.setWordWrap(True) + tips_layout.addWidget(tip_text) + + layout.addWidget(tips_frame) + layout.addStretch() + + scroll.setWidget(container) + + main_layout = QVBoxLayout(widget) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addWidget(scroll) + + return widget + + def _create_stat_card(self, icon, value, label): + """Create a stat card widget.""" + card = QFrame() + card.setStyleSheet(f""" + QFrame {{ + background-color: {EU_COLORS['bg_panel']}; + border: 1px solid {EU_COLORS['border_subtle']}; + border-radius: 6px; + }} + """) + layout = QVBoxLayout(card) + layout.setContentsMargins(12, 10, 12, 10) + layout.setSpacing(4) + + value_lbl = QLabel(f"{icon} {value}") + value_lbl.setStyleSheet(f"color: {EU_COLORS['accent_orange']}; font-size: 16px; font-weight: bold;") + layout.addWidget(value_lbl) + + label_lbl = QLabel(label) + label_lbl.setStyleSheet(f"color: {EU_COLORS['text_muted']}; font-size: 10px;") + layout.addWidget(label_lbl) + + return card + + def _create_action_button(self, name, description): + """Create an action button.""" + btn = QPushButton() + btn.setFixedHeight(60) + btn.setStyleSheet(f""" + QPushButton {{ + background-color: {EU_COLORS['bg_panel']}; + border: 1px solid {EU_COLORS['border_subtle']}; + border-radius: 6px; + text-align: left; + padding: 10px; + }} + QPushButton:hover {{ + background-color: {EU_COLORS['bg_hover']}; + border: 1px solid {EU_COLORS['border_orange']}; + }} + """) + + # Layout for button content + btn_widget = QWidget() + btn_layout = QVBoxLayout(btn_widget) + btn_layout.setContentsMargins(0, 0, 0, 0) + btn_layout.setSpacing(2) + + name_lbl = QLabel(name) + name_lbl.setStyleSheet(f"color: white; font-weight: bold; font-size: 12px;") + btn_layout.addWidget(name_lbl) + + desc_lbl = QLabel(description) + desc_lbl.setStyleSheet(f"color: {EU_COLORS['text_muted']}; font-size: 9px;") + btn_layout.addWidget(desc_lbl) + + return btn