Changes:
- Added 'Open' button to each plugin in the Installed plugins list
- Clicking Open tries: show_ui(), open(), or get_widget() methods
- Added _open_plugin() method to both PluginsView and PerfectMainWindow
- Added Settings button for plugins that have settings
- Shows error messages if plugin can't be opened
This fixes the issue where plugins couldn't be opened or viewed.
New file: core/game_overlay_integration.py
- Detects EU game process by name (entropia.exe, entropiauniverse.exe)
- Attaches Activity Bar as child window of game window
- Overlay moves and resizes with game window ('burned in' effect)
- Shows/hides based on game process running
- 2-second polling interval to check game status
Integration:
- Added to main.py alongside overlay_controller
- Properly starts and stops with app
- Console messages when game detected/ended
This makes the overlay truly part of the game window!
Changes:
- Plugin cards now 320x220 minimum (was 300x200 fixed)
- Cards have maximum width of 400px to prevent stretching too wide
- PluginStoreUI now fills available space with stretch factor
- Grid layout calculates columns based on available width
- Removed hardcoded margins that were causing cramped layout
- Search input now has minimum width of 300px
- Buttons have minimum widths for consistent sizing
Changes:
- EU_WINDOW_TITLE: 'Entropia Universe' -> 'Entropia Universe Client'
Now matches 'Entropia Universe Client (64-bit) PlanetName' or
'Entropia Universe Client (32-bit) PlanetName'
- EU_PROCESS_NAMES: Removed 'clientloader.exe' (launcher only)
Now only looks for 'entropia.exe' or 'entropiauniverse.exe'
This fixes the issue where the Client Loader was detected instead of the actual game.
1. Added QCheckBox to perfect_ux.py imports (was missing)
2. Fixed dashboard_view.py: Qt.QSize -> QSize (QtCore import)
These fix the NameError and AttributeError that prevented the app from starting.
Activity Bar Improvements:
- Draggable: Grab left handle to move anywhere on screen
- Resizable: Grab right handle to change width (400-1600px)
- Background Opacity: Now actually works (20-100%)
- Search toggle: Right-click menu to show/hide search box
- Clock toggle: Right-click menu to show/hide clock
- Reset Position: Right-click menu to reset to default position
- Settings dialog: Added opacity slider, width, search/clock toggles
Config additions:
- x, y: Custom position
- width: Bar width (400-1600)
- background_opacity: 20-100%
- show_search: Toggle search visibility
- show_clock: Toggle clock visibility
Bug Fixes:
- OverlayController now inherits QObject (fixes 'cannot be converted' error)
- Activity bar saves position when dragged
- Activity bar saves width when resized
Hotkey Changes:
- Ctrl+Shift+U: Now toggles Activity Bar (in-game overlay) instead of dashboard
- Ctrl+Shift+H: Still hides all overlays
- Ctrl+Shift+B: Also toggles Activity Bar (kept for compatibility)
UI Updates:
- Tray menu shows 'Activity Bar (Ctrl+Shift+U)' to indicate hotkey
- Dashboard no longer has a global hotkey (use tray icon or window)
- Updated startup messages to reflect new hotkey setup
- Plugins view now has 'Installed' and 'Store' tabs with real content
- Widgets view shows Clock, System Monitor, Skill Tracker with enable/disable
- Views embedded directly to avoid import issues
- Plugin list shows name, version, description with checkboxes
- Widget cards show name, source plugin, description, preview button
- Added debug output to diagnose why PluginsView isn't loading
- Added PluginsView and WidgetsView to core/ui/__init__.py exports
- Removed plugin_manager check that was causing fallback
- Will show console output to diagnose the issue
1. Sidebar toggle: Now uses arrows (chevron-right when collapsed, chevron-left when expanded)
2. Dashboard: Quick actions filtered to show only installed plugins
3. Plugins page: New tabs - 'Installed' (enable/disable plugins) and 'Store' (browse/install)
4. Widgets page: Now shows registered widgets from plugins with enable/disable
5. Settings page: Removed Plugin Store and My Plugins tabs (moved to Plugins page)
6. Settings: Changed 'Overlay Opacity' to 'Background Opacity' for clarity
7. Status bar: Shows plugin count, EU window status (Not Running/Running/Focused), version
8. New files: plugins_view.py, widgets_view.py with proper functionality
Changes:
- Default mode now OVERLAY_GAME_FOCUSED (Blish HUD style)
- Activity bar ONLY shows when EU window is focused
- Completely hidden on desktop and other windows
- Non-blocking focus detection with QTimer.singleShot
- Auto-disables if window detection is too slow (>500ms)
- Added Overlay Mode dropdown in Settings > General
- Options: Game Focused, Always Visible, Hotkey Toggle, Temporary, Desktop Only
Settings:
- activity_bar.overlay_mode: 'overlay_game' (default)
- Game Focused: Overlay strictly tied to EU window focus
- Import actual views from core.ui (DashboardView, SettingsView, PluginsView)
- Update _create_settings_view() to use SettingsView with full tabs
- Update _create_plugins_view() to use PluginsView with plugin management
- Keep fallback placeholders if views fail to load
- Add settings attribute to PerfectMainWindow for SettingsView compatibility
Views now show:
- Settings: General, Plugin Store, My Plugins, Hotkeys, Data & Backup, Updates tabs
- Plugins: Installed plugin list with enable/disable checkboxes
New OverlayController (core/overlay_controller.py):
- DESKTOP_APP: Activity bar only in desktop app
- OVERLAY_ALWAYS: Always visible as overlay
- OVERLAY_GAME_FOCUSED: Only when EU game window focused
- OVERLAY_HOTKEY_TOGGLE: Toggle with Ctrl+Shift+B (default)
- OVERLAY_TEMPORARY: Show 8 seconds on hotkey, then auto-hide
Changes:
- Activity bar now controlled by OverlayController
- Removed old _start_eu_focus_detection/_check_eu_focus methods
- Updated quit() to stop overlay controller
- Startup messages show current mode
Settings key: activity_bar.overlay_mode
Default: overlay_toggle
NavigationRail now supports expanded/collapsed states:
- Click menu toggle button to expand/collapse
- Expanded: Shows icon + label (200px width)
- Collapsed: Shows icon only (80px width)
- Smooth animated width transition
- Orange accent on active item maintained
NavigationDestination updated:
- Shows QLabel with text when expanded
- Icon-only when collapsed
- Proper styling for both states
Changes:
- Fixed is_focused property (was calling as method)
- EU focus detection now DISABLED by default
- Added auto_show_on_focus setting (default: false)
- Hard disable if focus check takes >1 second
- ActivityBarConfig now includes auto_show_on_focus setting
This prevents the EnumWindows blocking that was causing 4.5s freezes.
Users can manually enable in settings if they want auto-show behavior.
Problem: EnumWindows was iterating through ALL windows on system
when EU wasn't running, causing 4.5s blocking delays every 5s.
Changes:
- _find_window_by_title: 100ms timeout, 500 window limit
- _find_window_by_process: 150ms timeout, 300 window limit
- Skip empty window titles (performance)
- Slow down focus detection to 60s when EU not found 3x
This should eliminate the 2s menu + 7s click delays.
- New debug_logger.py with timing and stack trace capabilities
- Tray icon now logs all interactions with millisecond timing
- Main app startup is fully instrumented
- EU focus detection logs and warns if slow (>100ms)
- Menu interactions use QTimer.singleShot to avoid blocking
- Log file saved to Documents/Entropia Universe/Logs/
This will help identify the source of UI slowness (2s menu delay, 7s click delay)
The tray icon was blocking the main UI thread because:
1. QTimer was updating menu state every second
2. Complex stylesheet on menu may cause blocking
3. Emojis in menu items might cause encoding issues
Simplified:
- Removed update timer (no longer needed)
- Removed complex stylesheet (use default)
- Removed emojis from menu items
- Made TrayIcon inherit QWidget for proper parent
- Simplified signal connections
1. System Tray Icon (replaces floating button):
- Right-click menu with: Dashboard, Activity Bar, Settings, Quit
- Orange 'EU' icon
- Double-click to open dashboard
- Notifications support
2. Removed Floating Icon:
- No more floating button on desktop
- All interaction through tray icon
3. EU Window Focus Detection:
- Activity bar auto-shows when EU is focused
- Activity bar auto-hides when EU loses focus
- Checks every 500ms for focus changes
- Tray icon checkbox reflects activity bar state
New Files:
- core/tray_icon.py: System tray implementation
Modified:
- core/main.py: Use tray instead of floating icon, add focus detection
Usage:
- Start EU-Utility: Tray icon appears in system tray
- Open EU game: Activity bar appears automatically
- Alt-tab away from EU: Activity bar hides
- Right-click tray icon: Access settings, toggle bar, quit
The hide_timer QTimer was being created after _apply_config() was called,
but _apply_config() tries to set the timer interval. This caused:
AttributeError: 'WindowsTaskbar' object has no attribute 'hide_timer'
Fix: Move hide_timer creation to before _apply_config() call.
Complete redesign of the in-game Activity Bar:
- Transparent background (no visible background)
- Windows-style start button (⊞ icon)
- Search box with rounded corners (Windows 11 style)
- Pinned plugins expand the bar dynamically
- Clean minimal design
- System clock display
- Right-click context menu for settings
- Auto-hide functionality
- Draggable positioning
Features:
- Click ⊞ button to open app drawer
- Type in search box to find plugins
- Pin plugins to taskbar for quick access
- Clock shows current time (updates every minute)
- Right-click for settings
The bar now looks like a floating Windows taskbar
perfect for in-game overlay use.
1. Removed box-shadow CSS properties (not supported by Qt)
2. Fixed TypeError: 'QVBoxLayout' object is not callable
- Removed redundant placeholder.layout() call
- Layout was already set up correctly
App should launch without errors now.
Line 351 had malformed docstring with 8 quotes instead of 3:
- Before: """Handle incoming webhooks."""""" (8 quotes)
- After: """Handle incoming webhooks.""" (3 quotes)
This caused Python to report an unterminated string at EOF.
File now parses correctly.
- Created compatibility shim at core/plugin_api.py
- Imports from new core/api/plugin_api.py
- Existing plugins continue to work without changes
- Encourages migration to: from core.api import get_api
NEW: core/api/ directory with comprehensive three-tier API
PluginAPI (core/api/plugin_api.py):
- 12 core service integrations (Log, Window, OCR, Screenshot, Nexus, HTTP, Audio, Notifications, Clipboard, Event Bus, Data Store, Tasks)
- Full docstrings with examples for every method
- Thread-safe design with Qt signal marshaling
- Proper error handling with custom exceptions
- Service availability checking
WidgetAPI (core/api/widget_api.py):
- Widget creation and management
- WidgetConfig dataclass for configuration
- WidgetType enum (MINI, CONTROL, CHART, ALERT, CUSTOM)
- WidgetAnchor enum for positioning
- Event system (moved, resized, closing, closed, update)
- Layout helpers (grid, horizontal, vertical, cascade)
- Persistence (save/load widget states)
- Widget presets for reuse
ExternalAPI (core/api/external_api.py):
- REST API server with aiohttp
- API endpoint registration (decorator and programmatic)
- Incoming webhooks with HMAC verification
- Outgoing webhook POST support
- API key authentication
- IPC (inter-process communication)
- File watcher for config changes
- Server-Sent Events (SSE) support
- CORS configuration
- Webhook history tracking
core/api/__init__.py:
- Unified imports for all three APIs
- Version tracking (2.2.0)
- Clean namespace exports
docs/API_REFERENCE.md:
- Comprehensive 12,000+ word reference
- Quick start examples for each API
- Service-by-service documentation
- Error handling guide
- Integration examples (Discord, custom widget)
Integration:
- Updated core/main.py to import from new API structure
- All three APIs available via: from core.api import get_api, get_widget_api, get_external_api
Benefits:
- Clear separation of concerns (plugins vs widgets vs external)
- Well-documented APIs for developers
- Easy to extend with new services
- Type hints throughout
- Production-ready error handling
- Third-party integration support out of the box
- Added Ctrl+Shift+B hotkey to toggle activity bar visibility
- Added _on_activity_bar_hotkey() handler method
- Updated startup messages to show all hotkeys including activity bar
Hotkeys:
- Ctrl+Shift+U: Toggle main overlay
- Ctrl+Shift+H: Hide all overlays
- Ctrl+Shift+B: Toggle activity bar
NEW: core/activity_bar.py
- ActivityBar class for in-game overlay
- Configurable layouts: Horizontal, Vertical, Grid
- Pinned plugins in bar
- Plugin drawer (app drawer style)
- Draggable, resizable
- Opacity and size controls
- Auto-hide feature
- Settings dialog
Features:
- Horizontal/Vertical/Grid layouts
- Adjustable icon size (32-96px)
- Opacity slider (20-100%)
- Auto-hide when not in use
- Plugin drawer with all enabled plugins
- Click plugin to open mini widget or full UI
- Drag to reposition anywhere on screen
INTEGRATION:
- Added to core/main.py
- Auto-created on startup if enabled
- Toggle with Ctrl+Shift+B (configurable)
- Integrated with plugin manager
Usage:
- Install plugins
- They appear in Activity Bar (if pinned) or Drawer
- Click to open mini widget or full UI
- Right-click for settings
This provides a macOS-style dock experience for in-game use,
while keeping the desktop app for configuration.
ISSUE: Widgets tab was built once at startup. If a plugin was installed
after the app started, the widget wouldn't show up until restart.
FIX:
1. Added _refresh_widgets_tab() method that rebuilds the tab content
2. Called _refresh_widgets_tab() when switching to Widgets tab
3. Added debug logging to show registered widgets count
4. Lists all found widgets in console for debugging
Now when you:
1. Install Clock Widget plugin
2. Click on 🎨 Widgets tab
3. The tab refreshes and shows the Clock Widget
The widget appears immediately without needing to restart!
Widgets have Qt::WindowDoesNotAcceptFocus flag set so they don't
steal focus from the game. Calling activateWindow() on them
produces a warning.
Removed activateWindow() call since:
1. Widgets should not accept focus (they're overlays)
2. raise_() is sufficient to bring them to front
3. WindowDoesNotAcceptFocus is intentional for game overlay widgets
ISSUE: Clock and System Monitor widgets were created but not visible.
The widgets were being garbage collected because they weren't stored.
FIX:
1. Store widget in self._active_widgets list to prevent GC
2. Set parent=self to keep widget alive with overlay
3. Position widget at center of screen (visible location)
4. Call raise_() and activateWindow() to bring to front
5. Added debug output showing widget position
WIDGET CREATION NOW:
- Creates widget with parent
- Positions at center of screen
- Shows, raises, activates
- Stores reference in list
- Prints position for debugging
The issue was that installed plugins (calculator, clock_widget, etc.)
could not import 'plugins.base_plugin' because the plugins package
wasn't properly in Python's module path when loading via
spec_from_file_location.
FIX:
1. Added project root to sys.path so 'plugins' package is findable
2. Added _ensure_plugins_package() method to preload plugins module
3. Modified discover_plugins() to try normal import first
4. Added proper error logging with traceback for debugging
This ensures installed plugins can properly import BasePlugin
from plugins.base_plugin as expected.
NEW UI LAYOUT:
- Added tab bar at top of content area with 3 tabs:
* 🔌 Plugins - Shows plugin list from sidebar + plugin content
* 🎨 Widgets - Widget gallery to add overlay widgets
* ⚙️ Settings - All settings in one place
WIDGETS TAB FEATURES:
- Built-in widgets section with Clock and System Monitor
- Each widget has Add button to create overlay
- Plugin widgets section (placeholder for plugin-added widgets)
- Descriptions for each widget type
SETTINGS TAB FEATURES:
- Moved settings from dialog into dedicated tab
- Sub-tabs: Plugins, Plugin Store, Hotkeys, Appearance, About
- Removed Settings button from header (now in tabs)
CHANGES:
- _create_content_area() replaced with _create_content_area_with_tabs()
- Added _switch_tab() method
- Added _create_plugins_tab(), _create_widgets_tab(), _create_settings_tab()
- Added _create_widget_button() helper
- Added _add_clock_widget() and _add_system_monitor_widget()
- Removed Settings button from header bar
- Removed old _open_settings() dialog approach
The UI is now organized with clear navigation between
plugins, widgets, and settings via top tabs.