""" EU-Utility - Classy Dashboard UI ================================ A refined, elegant dashboard interface for second monitor use. Features a clean layout with a proper Dashboard for widgets, removing the sidebar for a more modern feel. Design Philosophy: - Clean, minimalist aesthetic - Premium dark theme with subtle accents - Glassmorphism effects - Smooth animations - Widget-focused dashboard """ from PyQt6.QtWidgets import ( QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QStackedWidget, QLabel, QPushButton, QFrame, QScrollArea, QGridLayout, QSizePolicy, QSpacerItem ) from PyQt6.QtCore import Qt, QTimer, pyqtSignal, QSize, QPropertyAnimation, QEasingCurve from PyQt6.QtGui import QColor, QPainter, QLinearGradient, QFont, QIcon from core.eu_styles import get_all_colors, EU_TYPOGRAPHY, EU_SIZES class GlassCard(QFrame): """Glassmorphism card widget.""" def __init__(self, parent=None): super().__init__(parent) self.setObjectName("glassCard") self._setup_style() def _setup_style(self): c = get_all_colors() self.setStyleSheet(f""" QFrame#glassCard {{ background: rgba(45, 55, 72, 0.6); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 16px; }} QFrame#glassCard:hover {{ background: rgba(45, 55, 72, 0.75); border: 1px solid rgba(255, 140, 66, 0.3); }} """) class ElegantTabButton(QPushButton): """Elegant tab button with smooth hover effects.""" clicked_tab = pyqtSignal(str) def __init__(self, text: str, icon: str = None, tab_id: str = None, parent=None): super().__init__(text, parent) self.tab_id = tab_id or text.lower() self._active = False self.setCursor(Qt.CursorShape.PointingHandCursor) self.setFixedHeight(44) self.clicked.connect(lambda: self.clicked_tab.emit(self.tab_id)) self._update_style() def set_active(self, active: bool): self._active = active self._update_style() def _update_style(self): c = get_all_colors() if self._active: self.setStyleSheet(f""" QPushButton {{ background: transparent; color: {c['accent_orange']}; border: none; border-bottom: 2px solid {c['accent_orange']}; padding: 0 24px; font-size: 14px; font-weight: 600; }} """) else: self.setStyleSheet(f""" QPushButton {{ background: transparent; color: {c['text_secondary']}; border: none; border-bottom: 2px solid transparent; padding: 0 24px; font-size: 14px; font-weight: 500; }} QPushButton:hover {{ color: {c['text_primary']}; }} """) class DashboardWidget(QFrame): """A widget container for the Dashboard grid.""" def __init__(self, title: str, content_widget=None, parent=None): super().__init__(parent) self.title = title self._setup_ui(content_widget) def _setup_ui(self, content_widget): c = get_all_colors() self.setStyleSheet(f""" QFrame {{ background: rgba(35, 41, 54, 0.8); border: 1px solid rgba(255, 255, 255, 0.06); border-radius: 20px; }} """) layout = QVBoxLayout(self) layout.setContentsMargins(20, 20, 20, 20) layout.setSpacing(16) # Header with title header = QLabel(self.title) header.setStyleSheet(f""" color: {c['text_primary']}; font-size: 16px; font-weight: 600; """) layout.addWidget(header) # Separator line separator = QFrame() separator.setFixedHeight(1) separator.setStyleSheet(f"background: rgba(255, 255, 255, 0.08);") layout.addWidget(separator) # Content if content_widget: layout.addWidget(content_widget, 1) self.setMinimumSize(280, 200) class ClassyDashboardWindow(QMainWindow): """ Refined EU-Utility main window with elegant Dashboard. Features: - Clean, sidebar-free layout - Dashboard tab for widgets (second monitor friendly) - Elegant glassmorphism design - Smooth animations and transitions """ def __init__(self, plugin_manager, parent=None): super().__init__(parent) self.plugin_manager = plugin_manager self.current_tab = "dashboard" self.tab_buttons = {} self._setup_window() self._setup_central_widget() self._create_header() self._create_tabs() self._create_content_area() # Show Dashboard by default self._switch_tab("dashboard") def _setup_window(self): """Setup window properties.""" self.setWindowTitle("EU-Utility") self.setMinimumSize(1200, 800) self.resize(1400, 900) # Center window screen = self.screen().geometry() self.move( (screen.width() - self.width()) // 2, (screen.height() - self.height()) // 2 ) # Dark, elegant background c = get_all_colors() self.setStyleSheet(f""" QMainWindow {{ background: #0f1419; }} """) def _setup_central_widget(self): """Create central widget with gradient background.""" self.central = QWidget() self.setCentralWidget(self.central) layout = QVBoxLayout(self.central) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) def _create_header(self): """Create elegant header with logo and controls.""" c = get_all_colors() header = QFrame() header.setFixedHeight(72) header.setStyleSheet(f""" QFrame {{ background: rgba(15, 20, 25, 0.95); border-bottom: 1px solid rgba(255, 255, 255, 0.06); }} """) layout = QHBoxLayout(header) layout.setContentsMargins(32, 0, 32, 0) layout.setSpacing(24) # Logo logo = QLabel("◆ EU-Utility") logo.setStyleSheet(f""" color: {c['accent_orange']}; font-size: 22px; font-weight: 700; letter-spacing: 0.5px; """) layout.addWidget(logo) # Spacer layout.addStretch() # Window controls minimize_btn = QPushButton("−") minimize_btn.setFixedSize(40, 32) minimize_btn.setStyleSheet(f""" QPushButton {{ background: transparent; color: {c['text_secondary']}; border: none; font-size: 18px; border-radius: 6px; }} QPushButton:hover {{ background: rgba(255, 255, 255, 0.1); color: {c['text_primary']}; }} """) minimize_btn.clicked.connect(self.showMinimized) close_btn = QPushButton("×") close_btn.setFixedSize(40, 32) close_btn.setStyleSheet(f""" QPushButton {{ background: transparent; color: {c['text_secondary']}; border: none; font-size: 20px; border-radius: 6px; }} QPushButton:hover {{ background: #e53e3e; color: white; }} """) close_btn.clicked.connect(self.close) layout.addWidget(minimize_btn) layout.addWidget(close_btn) self.central.layout().addWidget(header) def _create_tabs(self): """Create elegant tab bar.""" c = get_all_colors() tab_bar = QFrame() tab_bar.setFixedHeight(64) tab_bar.setStyleSheet(f""" QFrame {{ background: rgba(15, 20, 25, 0.9); border-bottom: 1px solid rgba(255, 255, 255, 0.04); }} """) layout = QHBoxLayout(tab_bar) layout.setContentsMargins(32, 0, 32, 0) layout.setSpacing(8) layout.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) # Tab definitions tabs = [ ("Dashboard", "dashboard"), ("Plugins", "plugins"), ("Widgets", "widgets"), ("Settings", "settings"), ] for text, tab_id in tabs: btn = ElegantTabButton(text, tab_id=tab_id) btn.clicked_tab.connect(self._switch_tab) self.tab_buttons[tab_id] = btn layout.addWidget(btn) layout.addStretch() self.central.layout().addWidget(tab_bar) def _create_content_area(self): """Create main content stack.""" self.content_stack = QStackedWidget() self.content_stack.setStyleSheet("background: transparent;") # Create all tabs self.dashboard_tab = self._create_dashboard_tab() self.plugins_tab = self._create_plugins_tab() self.widgets_tab = self._create_widgets_tab() self.settings_tab = self._create_settings_tab() self.content_stack.addWidget(self.dashboard_tab) self.content_stack.addWidget(self.plugins_tab) self.content_stack.addWidget(self.widgets_tab) self.content_stack.addWidget(self.settings_tab) self.central.layout().addWidget(self.content_stack, 1) def _create_dashboard_tab(self) -> QWidget: """Create the Dashboard tab - a grid for widgets.""" scroll = QScrollArea() scroll.setWidgetResizable(True) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) scroll.setStyleSheet(""" QScrollArea { background: transparent; border: none; } QScrollBar:vertical { background: transparent; width: 8px; margin: 0; } QScrollBar::handle:vertical { background: rgba(255, 255, 255, 0.1); border-radius: 4px; min-height: 40px; } QScrollBar::handle:vertical:hover { background: rgba(255, 255, 255, 0.2); } """) container = QWidget() container.setStyleSheet("background: transparent;") layout = QVBoxLayout(container) layout.setContentsMargins(32, 32, 32, 32) layout.setSpacing(24) # Welcome header c = get_all_colors() welcome = QLabel("Dashboard") welcome.setStyleSheet(f""" color: {c['text_primary']}; font-size: 32px; font-weight: 700; """) layout.addWidget(welcome) subtitle = QLabel("Your personal command center. Add widgets to track what's important.") subtitle.setStyleSheet(f""" color: {c['text_secondary']}; font-size: 14px; margin-bottom: 16px; """) layout.addWidget(subtitle) # Widget grid grid = QGridLayout() grid.setSpacing(20) grid.setColumnStretch(0, 1) grid.setColumnStretch(1, 1) grid.setColumnStretch(2, 1) # Add some default widgets widgets = [ ("System Status", self._create_system_widget()), ("Quick Actions", self._create_actions_widget()), ("Recent Activity", self._create_activity_widget()), ] for i, (title, content) in enumerate(widgets): widget = DashboardWidget(title, content) grid.addWidget(widget, i // 3, i % 3) layout.addLayout(grid) layout.addStretch() scroll.setWidget(container) return scroll def _create_system_widget(self) -> QWidget: """Create system status widget content.""" c = get_all_colors() widget = QWidget() layout = QVBoxLayout(widget) layout.setSpacing(12) status_items = [ ("●", "Log Reader", "Active", "#4ecca3"), ("●", "OCR Service", "Ready", "#4ecca3"), ("●", "Event Bus", "Running", "#4ecca3"), ("○", "Nexus API", "Idle", "#ffd93d"), ] for icon, name, status, color in status_items: row = QHBoxLayout() icon_label = QLabel(icon) icon_label.setStyleSheet(f"color: {color}; font-size: 12px;") row.addWidget(icon_label) name_label = QLabel(name) name_label.setStyleSheet(f"color: {c['text_primary']}; font-size: 13px;") row.addWidget(name_label) row.addStretch() status_label = QLabel(status) status_label.setStyleSheet(f"color: {c['text_secondary']}; font-size: 12px;") row.addWidget(status_label) layout.addLayout(row) return widget def _create_actions_widget(self) -> QWidget: """Create quick actions widget content.""" c = get_all_colors() widget = QWidget() layout = QVBoxLayout(widget) layout.setSpacing(10) actions = [ ("Scan Skills", "📷"), ("Check Loot", "📦"), ("Search Nexus", "🔍"), ("Settings", "⚙️"), ] for text, emoji in actions: btn = QPushButton(f"{emoji} {text}") btn.setFixedHeight(40) btn.setStyleSheet(f""" QPushButton {{ background: rgba(255, 255, 255, 0.05); color: {c['text_primary']}; border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 10px; font-size: 13px; text-align: left; padding-left: 16px; }} QPushButton:hover {{ background: rgba(255, 140, 66, 0.15); border: 1px solid rgba(255, 140, 66, 0.3); }} """) layout.addWidget(btn) return widget def _create_activity_widget(self) -> QWidget: """Create recent activity widget content.""" c = get_all_colors() widget = QWidget() layout = QVBoxLayout(widget) layout.setSpacing(10) activities = [ ("Plugin updated", "Clock Widget v1.0.1", "2m ago"), ("Scan completed", "Found 12 skills", "15m ago"), ("Settings changed", "Theme: Dark", "1h ago"), ] for title, detail, time in activities: item = QFrame() item.setStyleSheet("background: transparent;") row = QVBoxLayout(item) row.setSpacing(2) top = QHBoxLayout() title_label = QLabel(title) title_label.setStyleSheet(f"color: {c['text_primary']}; font-size: 13px; font-weight: 500;") top.addWidget(title_label) top.addStretch() time_label = QLabel(time) time_label.setStyleSheet(f"color: {c['text_muted']}; font-size: 11px;") top.addWidget(time_label) row.addLayout(top) detail_label = QLabel(detail) detail_label.setStyleSheet(f"color: {c['text_secondary']}; font-size: 12px;") row.addWidget(detail_label) layout.addWidget(item) layout.addStretch() return widget def _create_plugins_tab(self) -> QWidget: """Create Plugins tab content.""" widget = QWidget() layout = QVBoxLayout(widget) layout.setContentsMargins(32, 32, 32, 32) c = get_all_colors() title = QLabel("Plugins") title.setStyleSheet(f""" color: {c['text_primary']}; font-size: 32px; font-weight: 700; """) layout.addWidget(title) # Plugin list placeholder placeholder = QLabel("Plugin management interface - to be implemented") placeholder.setStyleSheet(f"color: {c['text_secondary']}; padding: 40px;") layout.addWidget(placeholder) layout.addStretch() return widget def _create_widgets_tab(self) -> QWidget: """Create Widgets tab content.""" widget = QWidget() layout = QVBoxLayout(widget) layout.setContentsMargins(32, 32, 32, 32) c = get_all_colors() title = QLabel("Widgets") title.setStyleSheet(f""" color: {c['text_primary']}; font-size: 32px; font-weight: 700; """) layout.addWidget(title) placeholder = QLabel("Widget gallery - to be implemented") placeholder.setStyleSheet(f"color: {c['text_secondary']}; padding: 40px;") layout.addWidget(placeholder) layout.addStretch() return widget def _create_settings_tab(self) -> QWidget: """Create Settings tab content.""" widget = QWidget() layout = QVBoxLayout(widget) layout.setContentsMargins(32, 32, 32, 32) c = get_all_colors() title = QLabel("Settings") title.setStyleSheet(f""" color: {c['text_primary']}; font-size: 32px; font-weight: 700; """) layout.addWidget(title) placeholder = QLabel("Settings interface - to be implemented") placeholder.setStyleSheet(f"color: {c['text_secondary']}; padding: 40px;") layout.addWidget(placeholder) layout.addStretch() return widget def _switch_tab(self, tab_id: str): """Switch to the specified tab.""" self.current_tab = tab_id # Update button states for btn_id, btn in self.tab_buttons.items(): btn.set_active(btn_id == tab_id) # Update content stack tab_map = { "dashboard": 0, "plugins": 1, "widgets": 2, "settings": 3, } if tab_id in tab_map: self.content_stack.setCurrentIndex(tab_map[tab_id]) # Factory function for creating the main window def create_classy_dashboard(plugin_manager) -> ClassyDashboardWindow: """Create and return the classy dashboard window.""" return ClassyDashboardWindow(plugin_manager)