feat: Widget Registry - plugins register widgets dynamically
This commit is contained in:
parent
3ee405475f
commit
defb83d213
|
|
@ -1590,14 +1590,20 @@ class OverlayWindow(QMainWindow):
|
|||
layout.addWidget(header)
|
||||
|
||||
# Description
|
||||
desc = QLabel("Add overlay widgets to your game. Drag to position, resize, and configure.")
|
||||
desc = QLabel("Add overlay widgets to your game. Install plugins to get more widgets.")
|
||||
desc.setStyleSheet(f"color: {c['text_secondary']}; font-size: 12px;")
|
||||
desc.setWordWrap(True)
|
||||
layout.addWidget(desc)
|
||||
|
||||
# Built-in widgets section
|
||||
builtin_header = QLabel("Built-in Widgets")
|
||||
builtin_header.setStyleSheet(f"""
|
||||
# Get registered widgets
|
||||
from core.widget_registry import get_widget_registry
|
||||
registry = get_widget_registry()
|
||||
widgets = registry.get_all_widgets()
|
||||
|
||||
if widgets:
|
||||
# Available widgets section
|
||||
available_header = QLabel("Available Widgets")
|
||||
available_header.setStyleSheet(f"""
|
||||
color: {c['text_primary']};
|
||||
font-weight: {EU_TYPOGRAPHY['weight_bold']};
|
||||
font-size: 14px;
|
||||
|
|
@ -1605,40 +1611,34 @@ class OverlayWindow(QMainWindow):
|
|||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid {c['border_default']};
|
||||
""")
|
||||
layout.addWidget(builtin_header)
|
||||
layout.addWidget(available_header)
|
||||
|
||||
# Clock widget button
|
||||
clock_btn = self._create_widget_button(
|
||||
"⏰ Clock",
|
||||
"A customizable clock with 12/24h format and date display",
|
||||
lambda: self._add_clock_widget()
|
||||
# Create buttons for each registered widget
|
||||
for widget_info in widgets:
|
||||
widget_btn = self._create_widget_button(
|
||||
f"{widget_info.icon} {widget_info.name}",
|
||||
widget_info.description,
|
||||
lambda wid=widget_info.id: self._add_registered_widget(wid)
|
||||
)
|
||||
layout.addWidget(clock_btn)
|
||||
|
||||
# System monitor widget button
|
||||
monitor_btn = self._create_widget_button(
|
||||
"📊 System Monitor",
|
||||
"Monitor CPU and RAM usage in real-time",
|
||||
lambda: self._add_system_monitor_widget()
|
||||
)
|
||||
layout.addWidget(monitor_btn)
|
||||
|
||||
# Plugin widgets section
|
||||
plugin_header = QLabel("Plugin Widgets")
|
||||
plugin_header.setStyleSheet(f"""
|
||||
color: {c['text_primary']};
|
||||
font-weight: {EU_TYPOGRAPHY['weight_bold']};
|
||||
layout.addWidget(widget_btn)
|
||||
else:
|
||||
# No widgets available
|
||||
no_widgets = QLabel("No widgets available")
|
||||
no_widgets.setStyleSheet(f"""
|
||||
color: {c['text_muted']};
|
||||
font-size: 14px;
|
||||
font-style: italic;
|
||||
margin-top: 24px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid {c['border_default']};
|
||||
""")
|
||||
layout.addWidget(plugin_header)
|
||||
no_widgets.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
layout.addWidget(no_widgets)
|
||||
|
||||
plugin_info = QLabel("Install plugins from the Plugin Store to add more widgets here.")
|
||||
plugin_info.setStyleSheet(f"color: {c['text_muted']}; font-size: 12px; font-style: italic;")
|
||||
plugin_info.setWordWrap(True)
|
||||
layout.addWidget(plugin_info)
|
||||
# Install info
|
||||
install_info = QLabel("Install plugins from the Plugin Store to add widgets here.")
|
||||
install_info.setStyleSheet(f"color: {c['text_muted']}; font-size: 12px;")
|
||||
install_info.setWordWrap(True)
|
||||
install_info.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
layout.addWidget(install_info)
|
||||
|
||||
layout.addStretch()
|
||||
|
||||
|
|
@ -1732,13 +1732,17 @@ class OverlayWindow(QMainWindow):
|
|||
|
||||
return tab
|
||||
|
||||
def _add_clock_widget(self):
|
||||
"""Add a clock widget to the overlay."""
|
||||
def _add_registered_widget(self, widget_id: str):
|
||||
"""Add a registered widget to the overlay."""
|
||||
try:
|
||||
from core.widget_system import ClockWidget
|
||||
from core.widget_registry import get_widget_registry
|
||||
registry = get_widget_registry()
|
||||
|
||||
# Create widget with self as parent
|
||||
widget = ClockWidget(parent=self)
|
||||
# Create widget using registry
|
||||
widget = registry.create_widget(widget_id)
|
||||
if not widget:
|
||||
print(f"[Overlay] Failed to create widget: {widget_id}")
|
||||
return
|
||||
|
||||
# Position near center of screen
|
||||
screen = QApplication.primaryScreen().geometry()
|
||||
|
|
@ -1756,38 +1760,8 @@ class OverlayWindow(QMainWindow):
|
|||
self._active_widgets = []
|
||||
self._active_widgets.append(widget)
|
||||
|
||||
print(f"[Overlay] Clock widget added at ({x}, {y})")
|
||||
print(f"[Overlay] Widget {widget_id} added at ({x}, {y})")
|
||||
except Exception as e:
|
||||
print(f"[Overlay] Error adding clock widget: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _add_system_monitor_widget(self):
|
||||
"""Add a system monitor widget to the overlay."""
|
||||
try:
|
||||
from core.widget_system import SystemMonitorWidget
|
||||
|
||||
# Create widget with self as parent
|
||||
widget = SystemMonitorWidget(parent=self)
|
||||
|
||||
# Position below the clock
|
||||
screen = QApplication.primaryScreen().geometry()
|
||||
x = (screen.width() - 200) // 2
|
||||
y = (screen.height() - 100) // 2 + 120
|
||||
widget.move(x, y)
|
||||
|
||||
# Show and raise
|
||||
widget.show()
|
||||
widget.raise_()
|
||||
widget.activateWindow()
|
||||
|
||||
# Store reference to prevent garbage collection
|
||||
if not hasattr(self, '_active_widgets'):
|
||||
self._active_widgets = []
|
||||
self._active_widgets.append(widget)
|
||||
|
||||
print(f"[Overlay] System monitor widget added at ({x}, {y})")
|
||||
except Exception as e:
|
||||
print(f"[Overlay] Error adding system monitor widget: {e}")
|
||||
print(f"[Overlay] Error adding widget {widget_id}: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
"""
|
||||
EU-Utility - Widget Registry
|
||||
|
||||
Allows plugins to register widgets that appear in the Widgets tab.
|
||||
"""
|
||||
|
||||
from typing import Dict, List, Callable, Optional
|
||||
from dataclasses import dataclass
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
|
||||
|
||||
@dataclass
|
||||
class WidgetInfo:
|
||||
"""Information about a registered widget."""
|
||||
id: str
|
||||
name: str
|
||||
description: str
|
||||
icon: str # emoji or icon name
|
||||
creator: Callable[[], QWidget] # Function that creates the widget
|
||||
plugin_id: str # Which plugin registered this
|
||||
|
||||
|
||||
class WidgetRegistry:
|
||||
"""Registry for plugin-provided widgets."""
|
||||
|
||||
_instance = None
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance._widgets: Dict[str, WidgetInfo] = {}
|
||||
return cls._instance
|
||||
|
||||
def register_widget(
|
||||
self,
|
||||
widget_id: str,
|
||||
name: str,
|
||||
description: str,
|
||||
icon: str,
|
||||
creator: Callable[[], QWidget],
|
||||
plugin_id: str = "unknown"
|
||||
):
|
||||
"""Register a widget.
|
||||
|
||||
Args:
|
||||
widget_id: Unique identifier for this widget type
|
||||
name: Display name
|
||||
description: Short description shown in UI
|
||||
icon: Emoji or icon name
|
||||
creator: Function that returns a QWidget instance
|
||||
plugin_id: ID of the plugin registering this widget
|
||||
"""
|
||||
self._widgets[widget_id] = WidgetInfo(
|
||||
id=widget_id,
|
||||
name=name,
|
||||
description=description,
|
||||
icon=icon,
|
||||
creator=creator,
|
||||
plugin_id=plugin_id
|
||||
)
|
||||
print(f"[WidgetRegistry] Registered widget: {name} (from {plugin_id})")
|
||||
|
||||
def unregister_widget(self, widget_id: str):
|
||||
"""Unregister a widget."""
|
||||
if widget_id in self._widgets:
|
||||
del self._widgets[widget_id]
|
||||
print(f"[WidgetRegistry] Unregistered widget: {widget_id}")
|
||||
|
||||
def get_widget(self, widget_id: str) -> Optional[WidgetInfo]:
|
||||
"""Get widget info by ID."""
|
||||
return self._widgets.get(widget_id)
|
||||
|
||||
def get_all_widgets(self) -> List[WidgetInfo]:
|
||||
"""Get all registered widgets."""
|
||||
return list(self._widgets.values())
|
||||
|
||||
def get_widgets_by_plugin(self, plugin_id: str) -> List[WidgetInfo]:
|
||||
"""Get all widgets registered by a specific plugin."""
|
||||
return [w for w in self._widgets.values() if w.plugin_id == plugin_id]
|
||||
|
||||
def create_widget(self, widget_id: str) -> Optional[QWidget]:
|
||||
"""Create an instance of a registered widget."""
|
||||
info = self._widgets.get(widget_id)
|
||||
if info:
|
||||
try:
|
||||
return info.creator()
|
||||
except Exception as e:
|
||||
print(f"[WidgetRegistry] Error creating widget {widget_id}: {e}")
|
||||
return None
|
||||
|
||||
def clear(self):
|
||||
"""Clear all registered widgets."""
|
||||
self._widgets.clear()
|
||||
|
||||
|
||||
# Global registry instance
|
||||
def get_widget_registry() -> WidgetRegistry:
|
||||
"""Get the global widget registry."""
|
||||
return WidgetRegistry()
|
||||
Loading…
Reference in New Issue