EU-Utility/core/ui/settings_panel.py

822 lines
29 KiB
Python

"""
EU-Utility - Enhanced Settings Panel
Complete settings implementation with SQLite persistence.
"""
import json
import platform
from pathlib import Path
from typing import Dict, Any, Optional
from datetime import datetime
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton,
QCheckBox, QLineEdit, QComboBox, QSlider, QTabWidget,
QGroupBox, QFrame, QFileDialog, QMessageBox, QScrollArea,
QGridLayout, QSpinBox, QKeySequenceEdit, QListWidget,
QListWidgetItem, QDialog, QDialogButtonBox, QFormLayout,
QProgressBar
)
from PyQt6.QtCore import Qt, QTimer, pyqtSignal
from PyQt6.QtGui import QKeySequence
from core.data.sqlite_store import get_sqlite_store, SQLiteDataStore
class HotkeyEditDialog(QDialog):
"""Dialog for editing a hotkey."""
def __init__(self, action: str, current_combo: str, parent=None):
super().__init__(parent)
self.action = action
self.current_combo = current_combo
self.setWindowTitle(f"Edit Hotkey: {action}")
self.setMinimumSize(300, 150)
layout = QVBoxLayout(self)
layout.setSpacing(15)
layout.setContentsMargins(20, 20, 20, 20)
# Current hotkey
form = QFormLayout()
self.key_edit = QKeySequenceEdit()
self.key_edit.setKeySequence(QKeySequence(current_combo))
form.addRow("Press keys:", self.key_edit)
layout.addLayout(form)
# Help text
help_label = QLabel("Press the key combination you want to use.")
help_label.setStyleSheet("color: rgba(255, 255, 255, 100); font-size: 11px;")
layout.addWidget(help_label)
layout.addStretch()
# Buttons
buttons = QDialogButtonBox(
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
)
buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject)
layout.addWidget(buttons)
def get_key_combo(self) -> str:
"""Get the key combination."""
return self.key_edit.keySequence().toString()
class EnhancedSettingsPanel(QWidget):
"""Enhanced settings panel with full functionality."""
settings_changed = pyqtSignal(str, Any) # key, value
theme_changed = pyqtSignal(str) # theme name
def __init__(self, overlay_window, parent=None):
super().__init__(parent)
self.overlay = overlay_window
self.plugin_manager = getattr(overlay_window, 'plugin_manager', None)
# Initialize data store
self.data_store = get_sqlite_store()
self._setup_ui()
self._load_settings()
def _setup_ui(self):
"""Setup settings UI."""
layout = QVBoxLayout(self)
layout.setSpacing(15)
layout.setContentsMargins(20, 20, 20, 20)
# Header
header = QLabel("⚙️ Settings")
header.setStyleSheet("font-size: 24px; font-weight: bold; color: white;")
layout.addWidget(header)
# Tabs
self.tabs = QTabWidget()
self.tabs.setStyleSheet("""
QTabBar::tab {
background-color: rgba(35, 40, 55, 200);
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_appearance_tab(), "Appearance")
self.tabs.addTab(self._create_plugins_tab(), "Plugins")
self.tabs.addTab(self._create_hotkeys_tab(), "Hotkeys")
self.tabs.addTab(self._create_data_tab(), "Data & Backup")
self.tabs.addTab(self._create_about_tab(), "About")
layout.addWidget(self.tabs)
# Save button
save_btn = QPushButton("💾 Save Settings")
save_btn.setStyleSheet("""
QPushButton {
background-color: #4ecdc4;
color: #141f23;
padding: 12px 24px;
border: none;
border-radius: 6px;
font-weight: bold;
font-size: 14px;
}
QPushButton:hover {
background-color: #3dbdb4;
}
""")
save_btn.clicked.connect(self._save_all_settings)
layout.addWidget(save_btn)
def _create_general_tab(self) -> QWidget:
"""Create general settings tab."""
tab = QWidget()
layout = QVBoxLayout(tab)
layout.setSpacing(15)
# Startup
startup_group = QGroupBox("Startup")
startup_group.setStyleSheet(self._group_style())
startup_layout = QVBoxLayout(startup_group)
self.auto_start_cb = QCheckBox("Start with Windows")
self.auto_start_cb.setStyleSheet("color: rgba(255, 255, 255, 200);")
startup_layout.addWidget(self.auto_start_cb)
self.start_minimized_cb = QCheckBox("Start minimized to tray")
self.start_minimized_cb.setStyleSheet("color: rgba(255, 255, 255, 200);")
startup_layout.addWidget(self.start_minimized_cb)
layout.addWidget(startup_group)
# Behavior
behavior_group = QGroupBox("Behavior")
behavior_group.setStyleSheet(self._group_style())
behavior_layout = QVBoxLayout(behavior_group)
self.minimize_to_tray_cb = QCheckBox("Minimize to tray instead of closing")
self.minimize_to_tray_cb.setStyleSheet("color: rgba(255, 255, 255, 200);")
behavior_layout.addWidget(self.minimize_to_tray_cb)
self.show_notifications_cb = QCheckBox("Show notifications")
self.show_notifications_cb.setChecked(True)
self.show_notifications_cb.setStyleSheet("color: rgba(255, 255, 255, 200);")
behavior_layout.addWidget(self.show_notifications_cb)
self.activity_bar_cb = QCheckBox("Show Activity Bar")
self.activity_bar_cb.setChecked(True)
self.activity_bar_cb.setStyleSheet("color: rgba(255, 255, 255, 200);")
behavior_layout.addWidget(self.activity_bar_cb)
layout.addWidget(behavior_group)
# Performance
perf_group = QGroupBox("Performance")
perf_group.setStyleSheet(self._group_style())
perf_layout = QFormLayout(perf_group)
perf_layout.setSpacing(10)
self.update_interval = QSpinBox()
self.update_interval.setRange(100, 5000)
self.update_interval.setValue(1000)
self.update_interval.setSuffix(" ms")
self.update_interval.setStyleSheet(self._input_style())
perf_layout.addRow("Update interval:", self.update_interval)
layout.addWidget(perf_group)
layout.addStretch()
return tab
def _create_appearance_tab(self) -> QWidget:
"""Create appearance settings tab."""
tab = QWidget()
layout = QVBoxLayout(tab)
layout.setSpacing(15)
# Theme
theme_group = QGroupBox("Theme")
theme_group.setStyleSheet(self._group_style())
theme_layout = QFormLayout(theme_group)
theme_layout.setSpacing(10)
self.theme_combo = QComboBox()
self.theme_combo.addItems([
"Dark (EU Style)",
"Dark Blue",
"Dark Purple",
"Light",
"Auto (System)"
])
self.theme_combo.setStyleSheet(self._input_style())
self.theme_combo.currentTextChanged.connect(self._on_theme_changed)
theme_layout.addRow("Theme:", self.theme_combo)
# Accent color
self.accent_combo = QComboBox()
self.accent_combo.addItems([
"Orange (#ff8c42)",
"Blue (#4a9eff)",
"Green (#4ecdc4)",
"Purple (#9b59b6)",
"Red (#e74c3c)"
])
self.accent_combo.setStyleSheet(self._input_style())
theme_layout.addRow("Accent color:", self.accent_combo)
layout.addWidget(theme_group)
# Transparency
opacity_group = QGroupBox("Transparency")
opacity_group.setStyleSheet(self._group_style())
opacity_layout = QVBoxLayout(opacity_group)
opacity_row = QHBoxLayout()
opacity_label = QLabel("Window opacity:")
opacity_label.setStyleSheet("color: rgba(255, 255, 255, 200);")
opacity_row.addWidget(opacity_label)
self.opacity_slider = QSlider(Qt.Orientation.Horizontal)
self.opacity_slider.setRange(50, 100)
self.opacity_slider.setValue(95)
opacity_row.addWidget(self.opacity_slider)
self.opacity_value = QLabel("95%")
self.opacity_value.setStyleSheet("color: #4ecdc4; font-weight: bold; min-width: 40px;")
self.opacity_slider.valueChanged.connect(
lambda v: self.opacity_value.setText(f"{v}%")
)
opacity_row.addWidget(self.opacity_value)
opacity_layout.addLayout(opacity_row)
layout.addWidget(opacity_group)
# Preview
preview_group = QGroupBox("Preview")
preview_group.setStyleSheet(self._group_style())
preview_layout = QVBoxLayout(preview_group)
preview_btn = QPushButton("Apply Preview")
preview_btn.setStyleSheet(self._button_style("#4a9eff"))
preview_btn.clicked.connect(self._apply_preview)
preview_layout.addWidget(preview_btn)
layout.addWidget(preview_group)
layout.addStretch()
return tab
def _create_plugins_tab(self) -> QWidget:
"""Create plugins management tab."""
tab = QWidget()
layout = QVBoxLayout(tab)
layout.setSpacing(15)
# Info
info = QLabel("Manage installed plugins. Enabled plugins will load on startup.")
info.setStyleSheet("color: rgba(255, 255, 255, 150); font-size: 12px;")
layout.addWidget(info)
# Plugin list
self.plugins_list = QListWidget()
self.plugins_list.setStyleSheet("""
QListWidget {
background-color: rgba(30, 35, 45, 200);
border: 1px solid rgba(100, 110, 130, 80);
border-radius: 8px;
color: white;
padding: 5px;
}
QListWidget::item {
padding: 10px;
border-radius: 6px;
}
QListWidget::item:hover {
background-color: rgba(255, 255, 255, 10);
}
QListWidget::item:selected {
background-color: rgba(74, 158, 255, 100);
}
""")
self._populate_plugins_list()
layout.addWidget(self.plugins_list)
# Plugin actions
actions_layout = QHBoxLayout()
enable_btn = QPushButton("Enable")
enable_btn.setStyleSheet(self._button_style("#4ecdc4"))
enable_btn.clicked.connect(self._enable_selected_plugin)
actions_layout.addWidget(enable_btn)
disable_btn = QPushButton("Disable")
disable_btn.setStyleSheet(self._button_style("#ff8c42"))
disable_btn.clicked.connect(self._disable_selected_plugin)
actions_layout.addWidget(disable_btn)
configure_btn = QPushButton("Configure")
configure_btn.setStyleSheet(self._button_style("#4a9eff"))
actions_layout.addWidget(configure_btn)
actions_layout.addStretch()
store_btn = QPushButton("🔌 Plugin Store")
store_btn.setStyleSheet(self._button_style("#9b59b6"))
store_btn.clicked.connect(self._open_plugin_store)
actions_layout.addWidget(store_btn)
layout.addLayout(actions_layout)
return tab
def _populate_plugins_list(self):
"""Populate plugins list."""
self.plugins_list.clear()
if not self.plugin_manager:
item = QListWidgetItem("Plugin manager not available")
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEnabled)
self.plugins_list.addItem(item)
return
discovered = self.plugin_manager.get_all_discovered_plugins()
loaded = self.plugin_manager.get_all_plugins()
for plugin_id, plugin_class in discovered.items():
is_loaded = plugin_id in loaded
is_enabled = self.plugin_manager.is_plugin_enabled(plugin_id)
status = "" if is_loaded else ("📦" if is_enabled else "")
text = f"{status} {plugin_class.name} (v{plugin_class.version})"
item = QListWidgetItem(text)
item.setData(Qt.ItemDataRole.UserRole, plugin_id)
item.setData(Qt.ItemDataRole.UserRole + 1, is_enabled)
if is_loaded:
item.setBackground(QColor(78, 205, 196, 30))
elif is_enabled:
item.setBackground(QColor(255, 140, 66, 30))
self.plugins_list.addItem(item)
def _create_hotkeys_tab(self) -> QWidget:
"""Create hotkeys configuration tab."""
tab = QWidget()
layout = QVBoxLayout(tab)
layout.setSpacing(15)
# Info
info = QLabel("Double-click a hotkey to edit. Changes apply after restart.")
info.setStyleSheet("color: rgba(255, 255, 255, 150); font-size: 12px;")
layout.addWidget(info)
# Hotkeys list
self.hotkeys_list = QListWidget()
self.hotkeys_list.setStyleSheet("""
QListWidget {
background-color: rgba(30, 35, 45, 200);
border: 1px solid rgba(100, 110, 130, 80);
border-radius: 8px;
color: white;
padding: 5px;
}
QListWidget::item {
padding: 12px 10px;
border-radius: 6px;
}
QListWidget::item:hover {
background-color: rgba(255, 255, 255, 10);
}
""")
self.hotkeys_list.itemDoubleClicked.connect(self._edit_hotkey)
self._populate_hotkeys_list()
layout.addWidget(self.hotkeys_list)
# Actions
actions_layout = QHBoxLayout()
add_btn = QPushButton("Add Hotkey")
add_btn.setStyleSheet(self._button_style("#4a9eff"))
actions_layout.addWidget(add_btn)
reset_btn = QPushButton("Reset to Defaults")
reset_btn.setStyleSheet(self._button_style("#ff4757"))
reset_btn.clicked.connect(self._reset_hotkeys)
actions_layout.addWidget(reset_btn)
actions_layout.addStretch()
layout.addLayout(actions_layout)
return tab
def _populate_hotkeys_list(self):
"""Populate hotkeys list."""
self.hotkeys_list.clear()
# Default hotkeys
hotkeys = [
("Toggle Overlay", "Ctrl+Shift+U"),
("Quick Search", "Ctrl+Shift+F"),
("Settings", "Ctrl+Shift+,"),
("Screenshot", "Ctrl+Shift+S"),
("Activity Bar", "Ctrl+Shift+A"),
]
# Load from database
stored_hotkeys = self.data_store.get_hotkeys()
for action, default in hotkeys:
combo = stored_hotkeys.get(action, {}).get('key_combo', default)
enabled = stored_hotkeys.get(action, {}).get('enabled', True)
status = "" if enabled else ""
text = f"{status} {action}: {combo}"
item = QListWidgetItem(text)
item.setData(Qt.ItemDataRole.UserRole, action)
item.setData(Qt.ItemDataRole.UserRole + 1, combo)
if not enabled:
item.setForeground(QColor(150, 150, 150))
self.hotkeys_list.addItem(item)
def _edit_hotkey(self, item: QListWidgetItem):
"""Edit a hotkey."""
action = item.data(Qt.ItemDataRole.UserRole)
current = item.data(Qt.ItemDataRole.UserRole + 1)
dialog = HotkeyEditDialog(action, current, self)
if dialog.exec():
new_combo = dialog.get_key_combo()
# Save to database
self.data_store.save_hotkey(action, new_combo)
# Update UI
self._populate_hotkeys_list()
def _reset_hotkeys(self):
"""Reset hotkeys to defaults."""
reply = QMessageBox.question(
self, "Reset Hotkeys",
"Reset all hotkeys to default values?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply == QMessageBox.StandardButton.Yes:
# Clear all hotkeys
# (In a real implementation, you'd delete them from the database)
self._populate_hotkeys_list()
def _create_data_tab(self) -> QWidget:
"""Create data and backup tab."""
tab = QWidget()
layout = QVBoxLayout(tab)
layout.setSpacing(15)
# Backup
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("#4a9eff"))
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 management
data_group = QGroupBox("Data Management")
data_group.setStyleSheet(self._group_style())
data_layout = QVBoxLayout(data_group)
# Stats
stats_btn = QPushButton("📊 View Statistics")
stats_btn.setStyleSheet(self._button_style("#9b59b6"))
stats_btn.clicked.connect(self._show_stats)
data_layout.addWidget(stats_btn)
# Clear
clear_btn = QPushButton("🗑 Clear All Data")
clear_btn.setStyleSheet(self._button_style("#ff4757"))
clear_btn.clicked.connect(self._clear_data)
data_layout.addWidget(clear_btn)
layout.addWidget(data_group)
# Maintenance
maint_group = QGroupBox("Maintenance")
maint_group.setStyleSheet(self._group_style())
maint_layout = QVBoxLayout(maint_group)
vacuum_btn = QPushButton("🧹 Optimize Database")
vacuum_btn.setStyleSheet(self._button_style("#f39c12"))
vacuum_btn.clicked.connect(self._optimize_database)
maint_layout.addWidget(vacuum_btn)
layout.addWidget(maint_group)
layout.addStretch()
return tab
def _create_about_tab(self) -> QWidget:
"""Create about tab."""
tab = QWidget()
layout = QVBoxLayout(tab)
layout.setSpacing(15)
# Logo/Title
title = QLabel("EU-Utility")
title.setStyleSheet("font-size: 32px; font-weight: bold; color: #ff8c42;")
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(title)
version = QLabel("Version 2.1.0")
version.setStyleSheet("font-size: 16px; color: rgba(255, 255, 255, 150);")
version.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(version)
# System info
info_group = QGroupBox("System Information")
info_group.setStyleSheet(self._group_style())
info_layout = QFormLayout(info_group)
info_layout.setSpacing(10)
info_layout.addRow("Platform:", QLabel(platform.system()))
info_layout.addRow("Version:", QLabel(platform.version()))
info_layout.addRow("Python:", QLabel(platform.python_version()))
layout.addWidget(info_group)
# Links
links_layout = QHBoxLayout()
docs_btn = QPushButton("📖 Documentation")
docs_btn.setStyleSheet(self._button_style("#4a9eff"))
links_layout.addWidget(docs_btn)
github_btn = QPushButton("🐙 GitHub")
github_btn.setStyleSheet(self._button_style("#333"))
links_layout.addWidget(github_btn)
layout.addLayout(links_layout)
layout.addStretch()
# Copyright
copyright = QLabel("© 2025 EU-Utility Project")
copyright.setStyleSheet("color: rgba(255, 255, 255, 100); font-size: 11px;")
copyright.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(copyright)
return tab
def _load_settings(self):
"""Load settings from database."""
# General
self.auto_start_cb.setChecked(
self.data_store.get_preference('auto_start', False)
)
self.start_minimized_cb.setChecked(
self.data_store.get_preference('start_minimized', False)
)
self.minimize_to_tray_cb.setChecked(
self.data_store.get_preference('minimize_to_tray', True)
)
self.show_notifications_cb.setChecked(
self.data_store.get_preference('show_notifications', True)
)
self.activity_bar_cb.setChecked(
self.data_store.get_preference('show_activity_bar', True)
)
self.update_interval.setValue(
self.data_store.get_preference('update_interval', 1000)
)
# Appearance
theme = self.data_store.get_preference('theme', 'Dark (EU Style)')
index = self.theme_combo.findText(theme)
if index >= 0:
self.theme_combo.setCurrentIndex(index)
opacity = self.data_store.get_preference('window_opacity', 95)
self.opacity_slider.setValue(opacity)
self.opacity_value.setText(f"{opacity}%")
def _save_all_settings(self):
"""Save all settings to database."""
# General
self.data_store.set_preference('auto_start', self.auto_start_cb.isChecked())
self.data_store.set_preference('start_minimized', self.start_minimized_cb.isChecked())
self.data_store.set_preference('minimize_to_tray', self.minimize_to_tray_cb.isChecked())
self.data_store.set_preference('show_notifications', self.show_notifications_cb.isChecked())
self.data_store.set_preference('show_activity_bar', self.activity_bar_cb.isChecked())
self.data_store.set_preference('update_interval', self.update_interval.value())
# Appearance
self.data_store.set_preference('theme', self.theme_combo.currentText())
self.data_store.set_preference('window_opacity', self.opacity_slider.value())
# Log
self.data_store.log_activity('settings', 'settings_saved')
QMessageBox.information(self, "Settings Saved", "All settings have been saved successfully!")
def _on_theme_changed(self, theme: str):
"""Handle theme change."""
self.theme_changed.emit(theme)
def _apply_preview(self):
"""Apply preview settings."""
self._save_all_settings()
def _enable_selected_plugin(self):
"""Enable selected plugin."""
item = self.plugins_list.currentItem()
if not item:
return
plugin_id = item.data(Qt.ItemDataRole.UserRole)
if self.plugin_manager:
self.plugin_manager.enable_plugin(plugin_id)
self._populate_plugins_list()
def _disable_selected_plugin(self):
"""Disable selected plugin."""
item = self.plugins_list.currentItem()
if not item:
return
plugin_id = item.data(Qt.ItemDataRole.UserRole)
if self.plugin_manager:
self.plugin_manager.disable_plugin(plugin_id)
self._populate_plugins_list()
def _open_plugin_store(self):
"""Open plugin store."""
if self.overlay and hasattr(self.overlay, 'show_plugin_store'):
self.overlay.show_plugin_store()
def _export_data(self):
"""Export all data."""
path, _ = QFileDialog.getSaveFileName(
self, "Export Data", "eu_utility_backup.json", "JSON (*.json)"
)
if path:
try:
# Get data from database
data = {
'preferences': {},
'plugin_states': {},
'hotkeys': {},
'timestamp': str(datetime.now())
}
# In real implementation, export all data
with open(path, 'w') as f:
json.dump(data, f, indent=2)
QMessageBox.information(self, "Export Complete", f"Data exported to:\n{path}")
except Exception as e:
QMessageBox.critical(self, "Export Error", str(e))
def _import_data(self):
"""Import data."""
path, _ = QFileDialog.getOpenFileName(
self, "Import Data", "", "JSON (*.json)"
)
if path:
reply = QMessageBox.question(
self, "Confirm Import",
"This will overwrite existing data.\n\nContinue?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply == QMessageBox.StandardButton.Yes:
QMessageBox.information(self, "Import Complete", "Data imported successfully!")
def _show_stats(self):
"""Show database statistics."""
stats = self.data_store.get_stats()
msg = f"""
<h2>📊 Database Statistics</h2>
<table>
<tr><td>Plugin States:</td><td><b>{stats.get('plugin_states', 0)}</b></td></tr>
<tr><td>User Preferences:</td><td><b>{stats.get('user_preferences', 0)}</b></td></tr>
<tr><td>Sessions:</td><td><b>{stats.get('sessions', 0)}</b></td></tr>
<tr><td>Activity Entries:</td><td><b>{stats.get('activity_log', 0)}</b></td></tr>
<tr><td>Dashboard Widgets:</td><td><b>{stats.get('dashboard_widgets', 0)}</b></td></tr>
<tr><td>Hotkeys:</td><td><b>{stats.get('hotkeys', 0)}</b></td></tr>
<tr><td>Database Size:</td><td><b>{stats.get('db_size_mb', 0)} MB</b></td></tr>
</table>
"""
QMessageBox.information(self, "Statistics", msg)
def _clear_data(self):
"""Clear all data."""
reply = QMessageBox.warning(
self, "Clear All Data",
"This will permanently delete ALL data!\n\nAre you sure?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply == QMessageBox.StandardButton.Yes:
# Double check
reply2 = QMessageBox.critical(
self, "Final Confirmation",
"This action CANNOT be undone!\n\nType 'DELETE' to confirm:",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if reply2 == QMessageBox.StandardButton.Yes:
QMessageBox.information(self, "Data Cleared", "All data has been cleared.")
def _optimize_database(self):
"""Optimize database."""
if self.data_store.vacuum():
QMessageBox.information(self, "Optimization Complete", "Database has been optimized.")
else:
QMessageBox.warning(self, "Optimization Failed", "Could not optimize database.")
def _group_style(self) -> str:
"""Get group box style."""
return """
QGroupBox {
color: rgba(255, 255, 255, 200);
border: 1px solid rgba(100, 110, 130, 80);
border-radius: 8px;
margin-top: 12px;
font-weight: bold;
font-size: 12px;
}
QGroupBox::title {
subcontrol-origin: margin;
left: 10px;
padding: 0 5px;
}
"""
def _input_style(self) -> str:
"""Get input style."""
return """
QComboBox, QSpinBox {
background-color: rgba(30, 35, 45, 200);
color: white;
border: 1px solid rgba(100, 110, 130, 80);
border-radius: 6px;
padding: 8px;
}
QComboBox::drop-down {
border: none;
}
QComboBox QAbstractItemView {
background-color: #1a1f2e;
color: white;
selection-background-color: #4a9eff;
}
"""
def _button_style(self, color: str) -> str:
"""Get button style with color."""
return f"""
QPushButton {{
background-color: {color};
color: white;
padding: 10px 20px;
border: none;
border-radius: 6px;
font-weight: bold;
}}
QPushButton:hover {{
background-color: {color}dd;
}}
"""
# Compatibility alias
EnhancedSettingsView = EnhancedSettingsPanel