EU-Utility/core/ui/settings_panel.py

821 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 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
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