""" EU-Utility - Settings Manager (Core Framework Component) Built-in settings interface - not a plugin. """ from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QCheckBox, QLineEdit, QComboBox, QSlider, QTabWidget, QGroupBox, QFrame, QFileDialog, QScrollArea, QMessageBox ) from PyQt6.QtCore import Qt from core.icon_manager import get_icon_manager class SettingsView(QWidget): """Main settings interface - built into the framework.""" def __init__(self, overlay_window, parent=None): super().__init__(parent) self.overlay = overlay_window self.settings = overlay_window.settings if hasattr(overlay_window, 'settings') else {} self.plugin_manager = overlay_window.plugin_manager if hasattr(overlay_window, 'plugin_manager') else None self.icon_manager = get_icon_manager() self._setup_ui() def _setup_ui(self): """Create the settings UI.""" layout = QVBoxLayout(self) layout.setSpacing(16) layout.setContentsMargins(24, 24, 24, 24) # Header with icon header_layout = QHBoxLayout() header_layout.setSpacing(12) header_icon = QLabel() header_pixmap = self.icon_manager.get_pixmap("settings", size=28) header_icon.setPixmap(header_pixmap) header_layout.addWidget(header_icon) header = QLabel("Settings") header.setStyleSheet("font-size: 24px; font-weight: bold; color: white;") header_layout.addWidget(header) header_layout.addStretch() layout.addLayout(header_layout) # Tabs self.tabs = QTabWidget() self.tabs.setStyleSheet(""" QTabBar::tab { background-color: rgba(20, 31, 35, 0.95); color: rgba(255,255,255,150); padding: 10px 20px; border-top-left-radius: 6px; border-top-right-radius: 6px; } QTabBar::tab:selected { background-color: #ff8c42; color: white; font-weight: bold; } """) # Add tabs self.tabs.addTab(self._create_general_tab(), "General") self.tabs.addTab(self._create_plugin_store_tab(), "Plugin Store") self.tabs.addTab(self._create_plugins_tab(), "My Plugins") self.tabs.addTab(self._create_hotkeys_tab(), "Hotkeys") self.tabs.addTab(self._create_data_tab(), "Data & Backup") self.tabs.addTab(self._create_updates_tab(), "Updates") layout.addWidget(self.tabs) def _create_general_tab(self): """Create general settings tab.""" tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(16) # Appearance appear_group = QGroupBox("Appearance") appear_group.setStyleSheet(self._group_style()) appear_layout = QVBoxLayout(appear_group) # Theme theme_layout = QHBoxLayout() theme_layout.addWidget(QLabel("Theme:")) self.theme_combo = QComboBox() self.theme_combo.addItems(["Dark (EU Style)", "Light", "Auto"]) theme_layout.addWidget(self.theme_combo) theme_layout.addStretch() appear_layout.addLayout(theme_layout) # Opacity opacity_layout = QHBoxLayout() opacity_layout.addWidget(QLabel("Overlay Opacity:")) self.opacity_slider = QSlider(Qt.Orientation.Horizontal) self.opacity_slider.setMinimum(50) self.opacity_slider.setMaximum(100) opacity_layout.addWidget(self.opacity_slider) self.opacity_label = QLabel("90%") opacity_layout.addWidget(self.opacity_label) opacity_layout.addStretch() appear_layout.addLayout(opacity_layout) layout.addWidget(appear_group) # Behavior behavior_group = QGroupBox("Behavior") behavior_group.setStyleSheet(self._group_style()) behavior_layout = QVBoxLayout(behavior_group) self.auto_start_cb = QCheckBox("Start with Windows") behavior_layout.addWidget(self.auto_start_cb) self.minimize_cb = QCheckBox("Minimize to tray on close") behavior_layout.addWidget(self.minimize_cb) layout.addWidget(behavior_group) layout.addStretch() return tab def _create_plugin_store_tab(self): """Create plugin store tab.""" from core.plugin_store import PluginStoreUI if self.plugin_manager: return PluginStoreUI(self.plugin_manager) # Error fallback tab = QWidget() layout = QVBoxLayout(tab) error = QLabel("Plugin Manager not available") error.setStyleSheet("color: #ff4757;") layout.addWidget(error) return tab def _create_plugins_tab(self): """Create installed plugins management tab.""" tab = QWidget() layout = QVBoxLayout(tab) info = QLabel("Manage your installed plugins. Enable/disable as needed.") info.setStyleSheet("color: rgba(255,255,255,150);") layout.addWidget(info) # Plugin list will be populated here scroll = QScrollArea() scroll.setWidgetResizable(True) scroll.setStyleSheet("background: transparent; border: none;") self.plugins_container = QWidget() self.plugins_layout = QVBoxLayout(self.plugins_container) self.plugins_layout.setAlignment(Qt.AlignmentFlag.AlignTop) self._populate_plugins_list() scroll.setWidget(self.plugins_container) layout.addWidget(scroll) return tab def _populate_plugins_list(self): """Populate the plugins list.""" if not self.plugin_manager: return # Clear existing while self.plugins_layout.count(): item = self.plugins_layout.takeAt(0) if item.widget(): item.widget().deleteLater() all_plugins = self.plugin_manager.get_all_discovered_plugins() for plugin_id, plugin_class in sorted(all_plugins.items(), key=lambda x: x[1].name): row = QHBoxLayout() # Checkbox cb = QCheckBox(plugin_class.name) cb.setChecked(self.plugin_manager.is_plugin_enabled(plugin_id)) cb.stateChanged.connect(lambda state, pid=plugin_id: self._toggle_plugin(pid, state)) row.addWidget(cb) # Version version = QLabel(f"v{plugin_class.version}") version.setStyleSheet("color: rgba(255,255,255,100); font-size: 11px;") row.addWidget(version) # Description desc = QLabel(plugin_class.description) desc.setStyleSheet("color: rgba(255,255,255,100); font-size: 11px;") desc.setWordWrap(True) row.addWidget(desc, 1) self.plugins_layout.addLayout(row) # Separator sep = QFrame() sep.setFrameShape(QFrame.Shape.HLine) sep.setStyleSheet("background-color: rgba(255, 140, 66, 0.1);") sep.setFixedHeight(1) self.plugins_layout.addWidget(sep) self.plugins_layout.addStretch() def _toggle_plugin(self, plugin_id: str, state: int): """Enable or disable a plugin.""" if not self.plugin_manager: return if state == Qt.CheckState.Checked.value: self.plugin_manager.enable_plugin(plugin_id) else: self.plugin_manager.disable_plugin(plugin_id) def _create_hotkeys_tab(self): """Create hotkeys configuration tab.""" tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(16) info = QLabel("Configure keyboard shortcuts. Changes apply on restart.") info.setStyleSheet("color: rgba(255,255,255,150);") layout.addWidget(info) # Core hotkeys group = QGroupBox("Core Hotkeys") group.setStyleSheet(self._group_style()) group_layout = QVBoxLayout(group) hotkeys = [ ("Toggle Overlay", "ctrl+shift+u"), ("Quick Search", "ctrl+shift+f"), ("Settings", "ctrl+shift+comma"), ] for label, default in hotkeys: row = QHBoxLayout() row.addWidget(QLabel(f"{label}:")) input_field = QLineEdit(default) input_field.setStyleSheet(""" QLineEdit { background-color: rgba(20, 31, 35, 0.95); color: white; border: 1px solid rgba(255, 140, 66, 0.2); padding: 5px; min-width: 150px; } """) row.addWidget(input_field) row.addStretch() group_layout.addLayout(row) layout.addWidget(group) layout.addStretch() return tab def _create_data_tab(self): """Create data and backup tab.""" tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(16) # Backup section backup_group = QGroupBox("Backup & Restore") backup_group.setStyleSheet(self._group_style()) backup_layout = QVBoxLayout(backup_group) export_btn = QPushButton("Export All Data") export_btn.setStyleSheet(self._button_style("#ff8c42")) export_btn.clicked.connect(self._export_data) backup_layout.addWidget(export_btn) import_btn = QPushButton("Import Data") import_btn.setStyleSheet(self._button_style("#4ecdc4")) import_btn.clicked.connect(self._import_data) backup_layout.addWidget(import_btn) layout.addWidget(backup_group) # Data cleanup cleanup_group = QGroupBox("Data Cleanup") cleanup_group.setStyleSheet(self._group_style()) cleanup_layout = QVBoxLayout(cleanup_group) clear_btn = QPushButton("Clear All Data") clear_btn.setStyleSheet(self._button_style("#ff4757")) clear_btn.clicked.connect(self._clear_data) cleanup_layout.addWidget(clear_btn) layout.addWidget(cleanup_group) layout.addStretch() return tab def _create_updates_tab(self): """Create auto-updater settings tab.""" tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(16) # Auto-update settings update_group = QGroupBox("Automatic Updates") update_group.setStyleSheet(self._group_style()) update_layout = QVBoxLayout(update_group) self.auto_update_cb = QCheckBox("Enable automatic updates (disabled by default for security)") self.auto_update_cb.setChecked(False) update_layout.addWidget(self.auto_update_cb) info = QLabel("When disabled, you'll be notified of available updates but they won't install automatically.") info.setStyleSheet("color: rgba(255,255,255,100); font-size: 11px;") info.setWordWrap(True) update_layout.addWidget(info) layout.addWidget(update_group) # Manual check check_btn = QPushButton("Check for Updates Now") check_btn.setStyleSheet(self._button_style("#ff8c42")) check_btn.clicked.connect(self._check_updates) layout.addWidget(check_btn) layout.addStretch() return tab def _export_data(self): """Export all data.""" path, _ = QFileDialog.getSaveFileName( self, "Export Data", "eu_utility_backup.json", "JSON (*.json)" ) if path: QMessageBox.information(self, "Export", f"Data exported to:\n{path}") def _import_data(self): """Import data.""" path, _ = QFileDialog.getOpenFileName( self, "Import Data", "", "JSON (*.json)" ) if path: QMessageBox.information(self, "Import", "Data imported successfully!") def _clear_data(self): """Clear all data.""" reply = QMessageBox.question( self, "Confirm", "Are you sure you want to clear all data?\n\nThis cannot be undone!", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No ) if reply == QMessageBox.StandardButton.Yes: QMessageBox.information(self, "Cleared", "All data has been cleared.") def _check_updates(self): """Check for updates.""" QMessageBox.information(self, "Updates", "You are running the latest version!") def _group_style(self): """Get group box style.""" return """ QGroupBox { color: rgba(255,255,255,200); border: 1px solid rgba(255, 140, 66, 0.2); border-radius: 6px; margin-top: 10px; font-weight: bold; font-size: 12px; } QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 5px; } """ def _button_style(self, color): """Get button style with color.""" return f""" QPushButton {{ background-color: {color}; color: white; padding: 10px 20px; border: none; border-radius: 4px; font-weight: bold; }} QPushButton:hover {{ background-color: {color}dd; }} """