""" EU-Utility - Perfect UX Design System ==================================== Based on Nielsen's 10 Usability Heuristics and Material Design 3 principles. Key Principles Applied: 1. Visibility of System Status - Clear feedback everywhere 2. Match Real World - Familiar gaming tool patterns 3. User Control - Easy undo, clear exits 4. Consistency - Unified design language 5. Error Prevention - Confirmation dialogs, validation 6. Recognition > Recall - Visual icons, clear labels 7. Flexibility - Shortcuts for experts 8. Aesthetic & Minimal - Clean, focused UI 9. Error Recovery - Clear error messages 10. Help - Contextual tooltips, onboarding Material Design 3: - Elevation and depth - Consistent spacing (8dp grid) - Rounded corners (12dp, 16dp, 28dp) - Motion and transitions (150-300ms) - Color roles (primary, secondary, surface, error) """ from PyQt6.QtWidgets import ( QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QStackedWidget, QLabel, QPushButton, QFrame, QScrollArea, QGridLayout, QSizePolicy, QSpacerItem, QGraphicsDropShadowEffect, QProgressBar, QToolTip, QDialog, QLineEdit, QTextEdit ) from PyQt6.QtCore import ( Qt, QTimer, pyqtSignal, QSize, QPropertyAnimation, QEasingCurve, QPoint, QParallelAnimationGroup ) from PyQt6.QtGui import ( QColor, QPainter, QLinearGradient, QFont, QIcon, QFontDatabase, QPalette, QCursor, QKeySequence, QShortcut ) from PyQt6.QtWidgets import QGraphicsOpacityEffect from core.eu_styles import get_all_colors from core.icon_manager import get_icon_manager # ============================================================ # DESIGN TOKENS - Material Design 3 Inspired # ============================================================ class DesignTokens: """Central design tokens for consistent UI.""" # EU Color Palette EU_DARK_BLUE = "#141f23" EU_ORANGE = "#ff8c42" EU_SURFACE = "rgba(28, 35, 45, 0.95)" # Elevation (shadows) ELEVATION_0 = "0 0 0 rgba(0,0,0,0)" ELEVATION_1 = "0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)" ELEVATION_2 = "0 3px 6px rgba(0,0,0,0.15), 0 2px 4px rgba(0,0,0,0.12)" ELEVATION_3 = "0 10px 20px rgba(0,0,0,0.15), 0 3px 6px rgba(0,0,0,0.1)" ELEVATION_4 = "0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.1)" # Spacing (8dp grid) SPACE_XS = 4 SPACE_S = 8 SPACE_M = 16 SPACE_L = 24 SPACE_XL = 32 SPACE_XXL = 48 # Border Radius RADIUS_S = 8 RADIUS_M = 12 RADIUS_L = 16 RADIUS_XL = 24 RADIUS_FULL = 9999 # Motion Duration DURATION_FAST = 150 DURATION_NORMAL = 250 DURATION_SLOW = 350 # Typography Scale FONT_FAMILY = "Inter, SF Pro Display, Segoe UI, sans-serif" @classmethod def get_color(cls, name: str) -> str: c = get_all_colors() return c.get(name, "#ffffff") # ============================================================ # COMPONENT LIBRARY # ============================================================ class Surface(QFrame): """Material Design Surface component with glassmorphism.""" def __init__(self, elevation: int = 1, radius: int = 16, parent=None): super().__init__(parent) self.elevation = elevation self.radius = radius self._setup_style() self._setup_shadow() def _setup_style(self): """Apply surface styling with glassmorphism.""" c = get_all_colors() bg_opacity = 0.90 + (self.elevation * 0.02) bg = f"rgba(20, 31, 35, {min(bg_opacity, 0.98)})" border_opacity = 0.08 + (self.elevation * 0.02) border = f"rgba(255, 140, 66, {min(border_opacity, 0.2)})" self.setStyleSheet(f""" Surface {{ background: {bg}; border: 1px solid {border}; border-radius: {self.radius}px; }} """) def _setup_shadow(self): """Apply drop shadow based on elevation.""" if self.elevation > 0: shadow = QGraphicsDropShadowEffect(self) shadow.setBlurRadius(self.elevation * 12) shadow.setXOffset(0) shadow.setYOffset(self.elevation * 3) opacity = min(self.elevation * 0.1, 0.5) shadow.setColor(QColor(0, 0, 0, int(255 * opacity))) self.setGraphicsEffect(shadow) class Button(QPushButton): """Material Design 3 button with proper states and motion.""" clicked_animation = pyqtSignal() def __init__(self, text: str, variant: str = "filled", icon: str = None, parent=None): super().__init__(text, parent) self.variant = variant self.icon_text = icon self._hovered = False self._pressed = False self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.setFixedHeight(44) self._setup_style() self._setup_animations() # Load icon if provided if icon: self._load_icon(icon) def _load_icon(self, icon_name: str): """Load SVG icon for button.""" icon_mgr = get_icon_manager() pixmap = icon_mgr.get_pixmap(icon_name, size=20) self.setIcon(QIcon(pixmap)) self.setIconSize(QSize(20, 20)) def _setup_style(self): """Apply button styling based on variant.""" c = get_all_colors() orange = DesignTokens.EU_ORANGE styles = { "filled": f""" QPushButton {{ background: {orange}; color: white; border: none; border-radius: 22px; padding: 0 24px; font-size: 14px; font-weight: 600; font-family: {DesignTokens.FONT_FAMILY}; }} QPushButton:hover {{ background: #ffa366; }} QPushButton:pressed {{ background: #e67a3a; }} QPushButton:disabled {{ background: rgba(255, 255, 255, 0.12); color: rgba(255, 255, 255, 0.38); }} """, "tonal": f""" QPushButton {{ background: rgba(255, 140, 66, 0.15); color: {orange}; border: none; border-radius: 22px; padding: 0 24px; font-size: 14px; font-weight: 600; }} QPushButton:hover {{ background: rgba(255, 140, 66, 0.25); }} QPushButton:pressed {{ background: rgba(255, 140, 66, 0.35); }} """, "outlined": f""" QPushButton {{ background: transparent; color: {orange}; border: 1px solid rgba(255, 140, 66, 0.5); border-radius: 22px; padding: 0 24px; font-size: 14px; font-weight: 600; }} QPushButton:hover {{ background: rgba(255, 140, 66, 0.08); border: 1px solid {orange}; }} """, "text": f""" QPushButton {{ background: transparent; color: {orange}; border: none; border-radius: 8px; padding: 0 16px; font-size: 14px; font-weight: 600; }} QPushButton:hover {{ background: rgba(255, 140, 66, 0.08); }} """, "elevated": f""" QPushButton {{ background: rgba(45, 55, 72, 0.9); color: {c['text_primary']}; border: 1px solid rgba(255, 140, 66, 0.08); border-radius: 22px; padding: 0 24px; font-size: 14px; font-weight: 600; }} QPushButton:hover {{ background: rgba(55, 65, 82, 0.95); border: 1px solid rgba(255, 140, 66, 0.15); }} """ } self.setStyleSheet(styles.get(self.variant, styles["filled"])) def _setup_animations(self): """Setup press/hover animations.""" self._scale_anim = QPropertyAnimation(self, b"minimumWidth") self._scale_anim.setDuration(DesignTokens.DURATION_FAST) self._scale_anim.setEasingCurve(QEasingCurve.Type.OutCubic) def enterEvent(self, event): """Hover start animation.""" self._hovered = True super().enterEvent(event) def leaveEvent(self, event): """Hover end animation.""" self._hovered = False super().leaveEvent(event) def mousePressEvent(self, event): """Press animation.""" self._pressed = True self.clicked_animation.emit() super().mousePressEvent(event) class Card(Surface): """Material Design Card component with EU aesthetic.""" def __init__(self, title: str = None, subtitle: str = None, parent=None): super().__init__(elevation=2, radius=16, parent=parent) self.layout = QVBoxLayout(self) self.layout.setContentsMargins(24, 24, 24, 24) self.layout.setSpacing(16) # Header if title: self._create_header(title, subtitle) def _create_header(self, title: str, subtitle: str = None): """Create card header.""" c = get_all_colors() title_label = QLabel(title) title_label.setStyleSheet(f""" color: {c['text_primary']}; font-size: 18px; font-weight: 600; font-family: {DesignTokens.FONT_FAMILY}; """) self.layout.addWidget(title_label) if subtitle: subtitle_label = QLabel(subtitle) subtitle_label.setStyleSheet(f""" color: {c['text_secondary']}; font-size: 13px; font-family: {DesignTokens.FONT_FAMILY}; """) self.layout.addWidget(subtitle_label) # Separator separator = QFrame() separator.setFixedHeight(1) separator.setStyleSheet("background: rgba(255, 140, 66, 0.1);") self.layout.addWidget(separator) def set_content(self, widget: QWidget): """Set card content.""" self.layout.addWidget(widget, 1) class NavigationRail(QFrame): """Material Design Navigation Rail with EU styling.""" destination_changed = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) self.destinations = [] self.active_destination = None self.icon_manager = get_icon_manager() self._setup_style() self._setup_layout() def _setup_style(self): """Apply navigation rail styling.""" self.setFixedWidth(80) self.setStyleSheet(""" NavigationRail { background: rgba(20, 31, 35, 0.98); border-right: 1px solid rgba(255, 140, 66, 0.08); } """) def _setup_layout(self): """Setup vertical layout.""" self.layout = QVBoxLayout(self) self.layout.setContentsMargins(12, 24, 12, 24) self.layout.setSpacing(8) self.layout.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignHCenter) # Add spacer at bottom self.layout.addStretch() def add_destination(self, icon_name: str, label: str, destination_id: str): """Add a navigation destination with SVG icon.""" btn = NavigationDestination(icon_name, label, destination_id, self.icon_manager) btn.clicked.connect(lambda: self._on_destination_clicked(destination_id)) self.destinations.append(btn) self.layout.insertWidget(len(self.destinations) - 1, btn) def _on_destination_clicked(self, destination_id: str): """Handle destination selection.""" self.set_active_destination(destination_id) self.destination_changed.emit(destination_id) def set_active_destination(self, destination_id: str): """Set active destination.""" self.active_destination = destination_id for dest in self.destinations: dest.set_active(dest.destination_id == destination_id) class NavigationDestination(QPushButton): """Single navigation destination with SVG icon.""" def __init__(self, icon_name: str, label: str, destination_id: str, icon_manager, parent=None): super().__init__(parent) self.destination_id = destination_id self.icon_manager = icon_manager self.icon_name = icon_name self.label = label self._setup_style() self._create_content() def _setup_style(self): """Apply destination styling.""" self.setFixedSize(56, 56) self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self._update_style(False) def _create_content(self): """Create icon from SVG.""" self.setIcon(self.icon_manager.get_icon(self.icon_name)) self.setIconSize(QSize(24, 24)) self.setToolTip(self.label) def _update_style(self, active: bool): """Update style based on active state with orange accent border.""" c = get_all_colors() orange = DesignTokens.EU_ORANGE if active: self.setStyleSheet(f""" QPushButton {{ background: rgba(255, 140, 66, 0.15); border: none; border-left: 3px solid {orange}; border-radius: 0 16px 16px 0; }} """) else: self.setStyleSheet(f""" QPushButton {{ background: transparent; border: none; border-left: 3px solid transparent; border-radius: 0 16px 16px 0; }} QPushButton:hover {{ background: rgba(255, 255, 255, 0.05); border-left: 3px solid rgba(255, 140, 66, 0.3); }} """) def set_active(self, active: bool): """Set active state.""" self._update_style(active) class StatusIndicator(QFrame): """System status indicator with SVG icons.""" STATUS_COLORS = { "active": "#4ecca3", "warning": "#ffd93d", "error": "#ff6b6b", "idle": "#6b7280", "busy": "#3b82f6" } def __init__(self, name: str, status: str = "idle", parent=None): super().__init__(parent) self.name = name self.status = status self.icon_manager = get_icon_manager() self._setup_ui() def _setup_ui(self): """Setup indicator UI.""" layout = QHBoxLayout(self) layout.setContentsMargins(12, 8, 12, 8) layout.setSpacing(10) # Status dot icon self.dot = QLabel() dot_pixmap = self.icon_manager.get_pixmap("check", size=10) self.dot.setPixmap(dot_pixmap) layout.addWidget(self.dot) # Name self.name_label = QLabel(self.name) self.name_label.setStyleSheet("font-size: 13px; font-weight: 500;") layout.addWidget(self.name_label) layout.addStretch() # Status text self.status_label = QLabel(self.status.title()) self.status_label.setStyleSheet("font-size: 12px; opacity: 0.7;") layout.addWidget(self.status_label) self._update_style() def set_status(self, status: str): """Update status with animation.""" old_status = self.status self.status = status self.status_label.setText(status.title()) self._update_style() if old_status != status: self._pulse_animation() def _update_style(self): """Update colors based on status.""" c = get_all_colors() color = self.STATUS_COLORS.get(self.status, c['text_secondary']) self.dot.setStyleSheet(f"color: {color}; font-size: 10px;") self.name_label.setStyleSheet(f"color: {c['text_primary']}; font-size: 13px; font-weight: 500;") self.status_label.setStyleSheet(f"color: {color}; font-size: 12px;") def _pulse_animation(self): """Pulse animation on status change.""" anim = QPropertyAnimation(self, b"minimumHeight") anim.setDuration(300) anim.setStartValue(self.height()) anim.setEndValue(self.height() + 4) anim.setEasingCurve(QEasingCurve.Type.OutBounce) anim.start() class IconButton(QPushButton): """Icon-only button with SVG support.""" def __init__(self, icon_name: str, tooltip: str = None, size: int = 40, parent=None): super().__init__(parent) self.icon_manager = get_icon_manager() self.setFixedSize(size, size) self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) # Load icon self.setIcon(self.icon_manager.get_icon(icon_name)) self.setIconSize(QSize(size - 16, size - 16)) if tooltip: self.setToolTip(tooltip) self._setup_style() def _setup_style(self): """Apply icon button styling.""" self.setStyleSheet(""" QPushButton { background: transparent; border: none; border-radius: 8px; } QPushButton:hover { background: rgba(255, 255, 255, 0.1); } QPushButton:pressed { background: rgba(255, 255, 255, 0.05); } """) # ============================================================ # PERFECT MAIN WINDOW # ============================================================ class PerfectMainWindow(QMainWindow): """Perfect UX Main Window - emoji-free, professional UI.""" def __init__(self, plugin_manager, parent=None): super().__init__(parent) self.plugin_manager = plugin_manager self._current_view = "dashboard" self.icon_manager = get_icon_manager() self._setup_window() self._setup_ui() self._setup_shortcuts() def _setup_window(self): """Setup window with proper sizing and positioning.""" self.setWindowTitle("EU-Utility") self.setMinimumSize(1280, 800) self.resize(1440, 900) # Center on screen screen = self.screen().geometry() self.move( (screen.width() - self.width()) // 2, (screen.height() - self.height()) // 2 ) # Apply global stylesheet self._apply_global_styles() def _apply_global_styles(self): """Apply global Material Design 3 styles.""" c = get_all_colors() self.setStyleSheet(f""" QMainWindow {{ background: {DesignTokens.EU_DARK_BLUE}; }} QToolTip {{ background: rgba(20, 31, 35, 0.98); color: {c['text_primary']}; border: 1px solid rgba(255, 140, 66, 0.2); border-radius: 8px; padding: 8px 12px; font-size: 13px; }} QScrollBar:vertical {{ background: transparent; width: 8px; margin: 0; }} QScrollBar::handle:vertical {{ background: rgba(255, 140, 66, 0.3); border-radius: 4px; min-height: 40px; }} QScrollBar::handle:vertical:hover {{ background: rgba(255, 140, 66, 0.5); }} QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{ height: 0; }} """) def _setup_ui(self): """Setup the professional UI structure.""" central = QWidget() self.setCentralWidget(central) layout = QHBoxLayout(central) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # Navigation Rail with SVG icons self.nav_rail = NavigationRail() self.nav_rail.add_destination("dashboard", "Dashboard", "dashboard") self.nav_rail.add_destination("plugins", "Plugins", "plugins") self.nav_rail.add_destination("widgets", "Widgets", "widgets") self.nav_rail.add_destination("settings", "Settings", "settings") self.nav_rail.destination_changed.connect(self._on_nav_changed) layout.addWidget(self.nav_rail) # Main Content Area self.content_stack = QStackedWidget() self.content_stack.setStyleSheet("background: transparent;") # Create views self.dashboard_view = self._create_dashboard_view() self.plugins_view = self._create_plugins_view() self.widgets_view = self._create_widgets_view() self.settings_view = self._create_settings_view() self.content_stack.addWidget(self.dashboard_view) self.content_stack.addWidget(self.plugins_view) self.content_stack.addWidget(self.widgets_view) self.content_stack.addWidget(self.settings_view) layout.addWidget(self.content_stack, 1) # Status Bar self._create_status_bar() def _create_dashboard_view(self) -> QWidget: """Create the polished Dashboard view.""" scroll = QScrollArea() scroll.setWidgetResizable(True) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) scroll.setStyleSheet("background: transparent; border: none;") container = QWidget() container.setStyleSheet("background: transparent;") layout = QVBoxLayout(container) layout.setContentsMargins(32, 32, 32, 32) layout.setSpacing(24) c = get_all_colors() # Header header = QLabel("Dashboard") header.setStyleSheet(f""" color: {c['text_primary']}; font-size: 36px; font-weight: 700; font-family: {DesignTokens.FONT_FAMILY}; """) layout.addWidget(header) subtitle = QLabel("Monitor your game, track progress, and access tools quickly.") subtitle.setStyleSheet(f"color: {c['text_secondary']}; font-size: 14px;") subtitle.setWordWrap(True) layout.addWidget(subtitle) # System Status Card status_card = Card("System Status", "Live service monitoring") status_widget = QWidget() status_layout = QVBoxLayout(status_widget) status_layout.setSpacing(8) self.status_indicators = { "log_reader": StatusIndicator("Log Reader", "active"), "ocr": StatusIndicator("OCR Service", "idle"), "event_bus": StatusIndicator("Event Bus", "active"), "nexus_api": StatusIndicator("Nexus API", "idle"), } for indicator in self.status_indicators.values(): status_layout.addWidget(indicator) status_card.set_content(status_widget) layout.addWidget(status_card) # Quick Actions Grid actions_card = Card("Quick Actions", "Frequently used tools") actions_widget = QWidget() actions_layout = QGridLayout(actions_widget) actions_layout.setSpacing(12) # Actions with SVG icons actions = [ ("camera", "Scan Skills", "Use OCR to scan skill levels"), ("package", "Check Loot", "Review recent loot data"), ("globe", "Search Nexus", "Find items and prices"), ("bar-chart", "View Stats", "See your hunting analytics"), ] for i, (icon, title, tooltip) in enumerate(actions): btn = Button(title, variant="elevated", icon=icon) btn.setToolTip(tooltip) btn.setFixedHeight(56) actions_layout.addWidget(btn, i // 2, i % 2) actions_card.set_content(actions_widget) layout.addWidget(actions_card) # Recent Activity activity_card = Card("Recent Activity", "Latest events and updates") activity_widget = QWidget() activity_layout = QVBoxLayout(activity_widget) activity_layout.setSpacing(12) activities = [ ("Plugin updated", "Clock Widget v1.0.1 installed", "2m ago", "check"), ("Scan completed", "Found 12 skills on page 1", "15m ago", "info"), ("Settings changed", "Theme set to Dark", "1h ago", "more"), ] for title, detail, time, icon_name in activities: item = self._create_activity_item(title, detail, time, icon_name) activity_layout.addWidget(item) activity_card.set_content(activity_widget) layout.addWidget(activity_card) layout.addStretch() scroll.setWidget(container) return scroll def _create_activity_item(self, title: str, detail: str, time: str, icon_name: str) -> QFrame: """Create a single activity item with SVG icon.""" c = get_all_colors() item = QFrame() item.setStyleSheet(""" QFrame { background: rgba(255, 255, 255, 0.03); border-radius: 12px; } QFrame:hover { background: rgba(255, 255, 255, 0.06); } """) layout = QHBoxLayout(item) layout.setContentsMargins(16, 12, 16, 12) # Icon icon_label = QLabel() icon_pixmap = self.icon_manager.get_pixmap(icon_name, size=16) icon_label.setPixmap(icon_pixmap) layout.addWidget(icon_label) # Content content_layout = QVBoxLayout() content_layout.setSpacing(2) title_label = QLabel(title) title_label.setStyleSheet(f"color: {c['text_primary']}; font-size: 14px; font-weight: 500;") content_layout.addWidget(title_label) detail_label = QLabel(detail) detail_label.setStyleSheet(f"color: {c['text_secondary']}; font-size: 12px;") content_layout.addWidget(detail_label) layout.addLayout(content_layout, 1) # Time time_label = QLabel(time) time_label.setStyleSheet(f"color: {c['text_muted']}; font-size: 11px;") layout.addWidget(time_label) return item def _create_plugins_view(self) -> QWidget: """Create the Plugins view.""" container = QWidget() layout = QVBoxLayout(container) layout.setContentsMargins(32, 32, 32, 32) c = get_all_colors() header = QLabel("Plugins") header.setStyleSheet(f"font-size: 36px; font-weight: 700; color: {c['text_primary']};") layout.addWidget(header) subtitle = QLabel("Manage and configure plugins to extend functionality.") subtitle.setStyleSheet(f"color: {c['text_secondary']}; font-size: 14px;") layout.addWidget(subtitle) # Placeholder for plugin grid placeholder = Card("Plugin Manager", "Browse, install, and configure plugins") placeholder_layout = QVBoxLayout() placeholder_text = QLabel("Plugin grid and management interface will be displayed here.") placeholder_text.setStyleSheet(f"color: {c['text_secondary']}; padding: 40px;") placeholder_text.setAlignment(Qt.AlignmentFlag.AlignCenter) placeholder_layout.addWidget(placeholder_text) layout.addWidget(placeholder) layout.addStretch() return container def _create_widgets_view(self) -> QWidget: """Create the Widgets view.""" container = QWidget() layout = QVBoxLayout(container) layout.setContentsMargins(32, 32, 32, 32) c = get_all_colors() header = QLabel("Widgets") header.setStyleSheet(f"font-size: 36px; font-weight: 700; color: {c['text_primary']};") layout.addWidget(header) subtitle = QLabel("Manage overlay widgets for in-game use.") subtitle.setStyleSheet(f"color: {c['text_secondary']}; font-size: 14px;") layout.addWidget(subtitle) layout.addStretch() return container def _create_settings_view(self) -> QWidget: """Create the Settings view.""" container = QWidget() layout = QVBoxLayout(container) layout.setContentsMargins(32, 32, 32, 32) c = get_all_colors() header = QLabel("Settings") header.setStyleSheet(f"font-size: 36px; font-weight: 700; color: {c['text_primary']};") layout.addWidget(header) subtitle = QLabel("Configure application preferences and options.") subtitle.setStyleSheet(f"color: {c['text_secondary']}; font-size: 14px;") layout.addWidget(subtitle) layout.addStretch() return container def _create_status_bar(self): """Create bottom status bar.""" self.status_bar = QFrame() self.status_bar.setFixedHeight(32) self.status_bar.setStyleSheet(""" QFrame { background: rgba(15, 20, 25, 0.98); border-top: 1px solid rgba(255, 140, 66, 0.06); } """) layout = QHBoxLayout(self.status_bar) layout.setContentsMargins(16, 0, 16, 0) self.status_text = QLabel("Ready") self.status_text.setStyleSheet("color: rgba(255, 255, 255, 0.5); font-size: 12px;") layout.addWidget(self.status_text) layout.addStretch() self.version_text = QLabel("EU-Utility v2.2.0") self.version_text.setStyleSheet("color: rgba(255, 255, 255, 0.3); font-size: 11px;") layout.addWidget(self.version_text) self.centralWidget().layout().addWidget(self.status_bar) def _setup_shortcuts(self): """Setup keyboard shortcuts.""" for i, view in enumerate(["dashboard", "plugins", "widgets", "settings"]): shortcut = QShortcut(QKeySequence(f"Ctrl+{i+1}"), self) shortcut.activated.connect(lambda v=view: self._navigate_to(v)) def _on_nav_changed(self, destination_id: str): """Handle navigation change with animation.""" self._current_view = destination_id view_map = { "dashboard": 0, "plugins": 1, "widgets": 2, "settings": 3 } if destination_id in view_map: self._animate_transition(view_map[destination_id]) self.status_text.setText(f"View: {destination_id.title()}") def _animate_transition(self, index: int): """Animate view transition.""" self.content_stack.setCurrentIndex(index) def _navigate_to(self, view: str): """Navigate to specific view.""" self.nav_rail.set_active_destination(view) self._on_nav_changed(view) def show_plugin(self, plugin_id: str): """Show specific plugin view.""" self._navigate_to("plugins") def create_perfect_window(plugin_manager) -> PerfectMainWindow: """Factory function for creating the perfect main window.""" return PerfectMainWindow(plugin_manager)