fix: Box-in-box UI, add Settings button to header
FIXES: - Removed margins causing 'box in a box' effect - Removed inner container border (window has OS frame) - Window now fills properly without nested boxes NEW: - Added Settings button to header (always accessible) - Settings dialog shows all available plugins - Check/uncheck to enable/disable - Shows message when no plugins enabled - Save & Apply reloads plugins immediately
This commit is contained in:
parent
bcd4574b7f
commit
7f6547f8de
|
|
@ -55,11 +55,18 @@ class OverlayWindow(QMainWindow):
|
||||||
"""Configure window - resizable and shows in taskbar."""
|
"""Configure window - resizable and shows in taskbar."""
|
||||||
self.setWindowTitle("EU-Utility")
|
self.setWindowTitle("EU-Utility")
|
||||||
|
|
||||||
# Resizable window (no FramelessWindowHint), stays on top
|
# Resizable window, stays on top
|
||||||
self.setWindowFlags(
|
self.setWindowFlags(
|
||||||
Qt.WindowType.WindowStaysOnTopHint
|
Qt.WindowType.WindowStaysOnTopHint
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Apply dark background to window itself
|
||||||
|
self.setStyleSheet(f"""
|
||||||
|
QMainWindow {{
|
||||||
|
background-color: {EU_COLORS['bg_dark']};
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
self.setMinimumSize(600, 400)
|
self.setMinimumSize(600, 400)
|
||||||
self.resize(850, 600)
|
self.resize(850, 600)
|
||||||
self._center_window()
|
self._center_window()
|
||||||
|
|
@ -72,69 +79,80 @@ class OverlayWindow(QMainWindow):
|
||||||
self.move(x, y)
|
self.move(x, y)
|
||||||
|
|
||||||
def _setup_ui(self):
|
def _setup_ui(self):
|
||||||
"""Setup clean EU-styled UI."""
|
"""Setup clean EU-styled UI - fills window, no box-in-box."""
|
||||||
central = QWidget()
|
central = QWidget()
|
||||||
self.setCentralWidget(central)
|
self.setCentralWidget(central)
|
||||||
|
|
||||||
|
# NO MARGINS - fill entire window
|
||||||
layout = QVBoxLayout(central)
|
layout = QVBoxLayout(central)
|
||||||
layout.setContentsMargins(20, 20, 20, 20)
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
layout.setSpacing(0)
|
layout.setSpacing(0)
|
||||||
|
|
||||||
# Main container with orange window border like Skills window
|
# Main container - NO BORDER (window already has frame), fills window
|
||||||
self.container = QFrame()
|
self.container = QFrame()
|
||||||
self.container.setObjectName("euContainer")
|
self.container.setObjectName("euContainer")
|
||||||
self.container.setStyleSheet(f"""
|
self.container.setStyleSheet(f"""
|
||||||
#euContainer {{
|
#euContainer {{
|
||||||
background-color: {EU_COLORS['bg_dark']};
|
background-color: {EU_COLORS['bg_dark']};
|
||||||
border: 1px solid {EU_COLORS['border_window']};
|
border: none;
|
||||||
border-radius: 8px;
|
|
||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
shadow = QGraphicsDropShadowEffect()
|
|
||||||
shadow.setBlurRadius(30)
|
|
||||||
shadow.setColor(QColor(0, 0, 0, 150))
|
|
||||||
shadow.setOffset(0, 8)
|
|
||||||
self.container.setGraphicsEffect(shadow)
|
|
||||||
|
|
||||||
container_layout = QVBoxLayout(self.container)
|
container_layout = QVBoxLayout(self.container)
|
||||||
container_layout.setContentsMargins(0, 0, 0, 0)
|
container_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
container_layout.setSpacing(0)
|
container_layout.setSpacing(0)
|
||||||
|
|
||||||
# Header with centered title - CLEAN (no weird lines)
|
# Header with settings button
|
||||||
header = QWidget()
|
header = QWidget()
|
||||||
header.setObjectName("header")
|
header.setObjectName("header")
|
||||||
header.setStyleSheet(f"""
|
header.setStyleSheet(f"""
|
||||||
QWidget {{
|
QWidget#header {{
|
||||||
background-color: {EU_COLORS['bg_header']};
|
background-color: {EU_COLORS['bg_header']};
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-bottom: 1px solid {EU_COLORS['border_medium']};
|
border-bottom: 1px solid {EU_COLORS['border_medium']};
|
||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
header_layout = QHBoxLayout(header)
|
header_layout = QHBoxLayout(header)
|
||||||
header_layout.setContentsMargins(15, 12, 15, 12)
|
header_layout.setContentsMargins(15, 8, 15, 8)
|
||||||
header_layout.setSpacing(10)
|
header_layout.setSpacing(10)
|
||||||
|
|
||||||
# App icon
|
# App icon
|
||||||
app_icon = QLabel()
|
app_icon = QLabel()
|
||||||
app_icon_pixmap = self.icon_manager.get_pixmap("target", size=20)
|
app_icon_pixmap = self.icon_manager.get_pixmap("target", size=18)
|
||||||
app_icon.setPixmap(app_icon_pixmap)
|
app_icon.setPixmap(app_icon_pixmap)
|
||||||
app_icon.setFixedSize(20, 20)
|
app_icon.setFixedSize(18, 18)
|
||||||
header_layout.addWidget(app_icon)
|
header_layout.addWidget(app_icon)
|
||||||
|
|
||||||
# Centered title
|
# Title
|
||||||
title = QLabel("EU-UTILITY")
|
title = QLabel("EU-Utility")
|
||||||
title.setStyleSheet(f"""
|
title.setStyleSheet(f"""
|
||||||
color: {EU_COLORS['text_primary']};
|
color: {EU_COLORS['text_primary']};
|
||||||
font-size: 14px;
|
font-size: 13px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
letter-spacing: 2px;
|
|
||||||
""")
|
""")
|
||||||
header_layout.addWidget(title)
|
header_layout.addWidget(title)
|
||||||
|
|
||||||
header_layout.addStretch()
|
header_layout.addStretch()
|
||||||
|
|
||||||
|
# Settings button (always accessible)
|
||||||
|
settings_btn = QPushButton("Settings")
|
||||||
|
settings_btn.setStyleSheet(f"""
|
||||||
|
QPushButton {{
|
||||||
|
background-color: {EU_COLORS['bg_panel']};
|
||||||
|
color: {EU_COLORS['text_secondary']};
|
||||||
|
border: 1px solid {EU_COLORS['border_subtle']};
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
}}
|
||||||
|
QPushButton:hover {{
|
||||||
|
background-color: {EU_COLORS['bg_hover']};
|
||||||
|
border-color: {EU_COLORS['accent_orange']};
|
||||||
|
color: {EU_COLORS['text_primary']};
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
settings_btn.clicked.connect(self._open_settings)
|
||||||
|
header_layout.addWidget(settings_btn)
|
||||||
|
|
||||||
# View toggle buttons
|
# View toggle buttons
|
||||||
view_group = QButtonGroup(self)
|
view_group = QButtonGroup(self)
|
||||||
view_group.setExclusive(True)
|
view_group.setExclusive(True)
|
||||||
|
|
@ -142,7 +160,7 @@ class OverlayWindow(QMainWindow):
|
||||||
self.icon_view_btn = QPushButton("Grid")
|
self.icon_view_btn = QPushButton("Grid")
|
||||||
self.icon_view_btn.setCheckable(True)
|
self.icon_view_btn.setCheckable(True)
|
||||||
self.icon_view_btn.setChecked(True)
|
self.icon_view_btn.setChecked(True)
|
||||||
self.icon_view_btn.setFixedSize(50, 24)
|
self.icon_view_btn.setFixedSize(45, 22)
|
||||||
self.icon_view_btn.setStyleSheet(self._view_toggle_style())
|
self.icon_view_btn.setStyleSheet(self._view_toggle_style())
|
||||||
self.icon_view_btn.clicked.connect(lambda: self._set_view_mode("icons"))
|
self.icon_view_btn.clicked.connect(lambda: self._set_view_mode("icons"))
|
||||||
header_layout.addWidget(self.icon_view_btn)
|
header_layout.addWidget(self.icon_view_btn)
|
||||||
|
|
@ -336,6 +354,19 @@ class OverlayWindow(QMainWindow):
|
||||||
"""Load plugins into sidebar and stack - FIXED indexing."""
|
"""Load plugins into sidebar and stack - FIXED indexing."""
|
||||||
plugins_list = list(self.plugin_manager.get_all_plugins().items())
|
plugins_list = list(self.plugin_manager.get_all_plugins().items())
|
||||||
|
|
||||||
|
# Show message if no plugins enabled
|
||||||
|
if not plugins_list:
|
||||||
|
# Add placeholder message
|
||||||
|
placeholder = QLabel("No plugins enabled\n\nClick Settings to enable plugins")
|
||||||
|
placeholder.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
placeholder.setStyleSheet(f"""
|
||||||
|
color: {EU_COLORS['text_muted']};
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 40px;
|
||||||
|
""")
|
||||||
|
self.plugin_stack.addWidget(placeholder)
|
||||||
|
return
|
||||||
|
|
||||||
for idx, (plugin_id, plugin) in enumerate(plugins_list):
|
for idx, (plugin_id, plugin) in enumerate(plugins_list):
|
||||||
# Get icon name
|
# Get icon name
|
||||||
icon_name = get_plugin_icon_name(plugin.name)
|
icon_name = get_plugin_icon_name(plugin.name)
|
||||||
|
|
@ -534,6 +565,150 @@ class OverlayWindow(QMainWindow):
|
||||||
self.tray_icon.hide()
|
self.tray_icon.hide()
|
||||||
QApplication.quit()
|
QApplication.quit()
|
||||||
|
|
||||||
|
def _open_settings(self):
|
||||||
|
"""Open Settings dialog - works even when Settings plugin not loaded."""
|
||||||
|
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QTabWidget, QListWidget, QListWidgetItem, QCheckBox, QHBoxLayout
|
||||||
|
|
||||||
|
dialog = QDialog(self)
|
||||||
|
dialog.setWindowTitle("EU-Utility Settings")
|
||||||
|
dialog.setMinimumSize(500, 400)
|
||||||
|
dialog.setStyleSheet(f"""
|
||||||
|
QDialog {{
|
||||||
|
background-color: {EU_COLORS['bg_dark']};
|
||||||
|
color: white;
|
||||||
|
}}
|
||||||
|
QLabel {{
|
||||||
|
color: white;
|
||||||
|
}}
|
||||||
|
QTabWidget::pane {{
|
||||||
|
background-color: {EU_COLORS['bg_panel']};
|
||||||
|
border: 1px solid {EU_COLORS['border_medium']};
|
||||||
|
border-radius: 6px;
|
||||||
|
}}
|
||||||
|
QTabBar::tab {{
|
||||||
|
background-color: {EU_COLORS['bg_header']};
|
||||||
|
color: {EU_COLORS['text_secondary']};
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-top-left-radius: 6px;
|
||||||
|
border-top-right-radius: 6px;
|
||||||
|
}}
|
||||||
|
QTabBar::tab:selected {{
|
||||||
|
background-color: {EU_COLORS['accent_orange']};
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
|
||||||
|
layout = QVBoxLayout(dialog)
|
||||||
|
|
||||||
|
tabs = QTabWidget()
|
||||||
|
|
||||||
|
# Plugins tab
|
||||||
|
plugins_tab = QWidget()
|
||||||
|
plugins_layout = QVBoxLayout(plugins_tab)
|
||||||
|
|
||||||
|
info = QLabel("Check plugins to enable them:")
|
||||||
|
info.setStyleSheet(f"color: {EU_COLORS['text_muted']};")
|
||||||
|
plugins_layout.addWidget(info)
|
||||||
|
|
||||||
|
self.settings_checkboxes = {}
|
||||||
|
|
||||||
|
if self.plugin_manager:
|
||||||
|
all_plugins = self.plugin_manager.get_all_discovered_plugins()
|
||||||
|
sorted_plugins = sorted(all_plugins.items(), key=lambda x: x[1].name)
|
||||||
|
|
||||||
|
for plugin_id, plugin_class in sorted_plugins:
|
||||||
|
row = QHBoxLayout()
|
||||||
|
|
||||||
|
cb = QCheckBox(f"{plugin_class.name} (v{plugin_class.version})")
|
||||||
|
cb.setChecked(self.plugin_manager.is_plugin_enabled(plugin_id))
|
||||||
|
cb.setStyleSheet("color: white;")
|
||||||
|
self.settings_checkboxes[plugin_id] = cb
|
||||||
|
row.addWidget(cb)
|
||||||
|
|
||||||
|
desc = QLabel(plugin_class.description)
|
||||||
|
desc.setStyleSheet(f"color: {EU_COLORS['text_muted']}; font-size: 11px;")
|
||||||
|
row.addWidget(desc, 1)
|
||||||
|
|
||||||
|
plugins_layout.addLayout(row)
|
||||||
|
|
||||||
|
plugins_layout.addStretch()
|
||||||
|
|
||||||
|
# Buttons
|
||||||
|
btn_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
save_btn = QPushButton("Save & Apply")
|
||||||
|
save_btn.setStyleSheet(f"""
|
||||||
|
QPushButton {{
|
||||||
|
background-color: {EU_COLORS['accent_orange']};
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
save_btn.clicked.connect(lambda: self._save_plugin_settings(dialog))
|
||||||
|
btn_layout.addWidget(save_btn)
|
||||||
|
|
||||||
|
btn_layout.addStretch()
|
||||||
|
plugins_layout.addLayout(btn_layout)
|
||||||
|
|
||||||
|
tabs.addTab(plugins_tab, "Plugins")
|
||||||
|
|
||||||
|
# Add info tab
|
||||||
|
info_tab = QWidget()
|
||||||
|
info_layout = QVBoxLayout(info_tab)
|
||||||
|
info_text = QLabel(
|
||||||
|
"EU-Utility v2.0\n\n"
|
||||||
|
"Loaded plugins will appear in the sidebar.\n"
|
||||||
|
"Enable plugins above to use them.\n\n"
|
||||||
|
"Hotkeys:\n"
|
||||||
|
"Ctrl+Shift+U - Toggle overlay\n"
|
||||||
|
"Ctrl+Shift+H - Hide all overlays"
|
||||||
|
)
|
||||||
|
info_text.setStyleSheet("color: white;")
|
||||||
|
info_layout.addWidget(info_text)
|
||||||
|
info_layout.addStretch()
|
||||||
|
tabs.addTab(info_tab, "About")
|
||||||
|
|
||||||
|
layout.addWidget(tabs)
|
||||||
|
dialog.exec()
|
||||||
|
|
||||||
|
def _save_plugin_settings(self, dialog):
|
||||||
|
"""Save plugin enable/disable settings."""
|
||||||
|
if not self.plugin_manager:
|
||||||
|
return
|
||||||
|
|
||||||
|
for plugin_id, cb in self.settings_checkboxes.items():
|
||||||
|
if cb.isChecked():
|
||||||
|
self.plugin_manager.enable_plugin(plugin_id)
|
||||||
|
else:
|
||||||
|
self.plugin_manager.disable_plugin(plugin_id)
|
||||||
|
|
||||||
|
# Reload plugins in UI
|
||||||
|
self._reload_plugins()
|
||||||
|
dialog.accept()
|
||||||
|
|
||||||
|
def _reload_plugins(self):
|
||||||
|
"""Reload plugins in UI after enabling/disabling."""
|
||||||
|
# Clear existing
|
||||||
|
while self.plugin_stack.count() > 0:
|
||||||
|
widget = self.plugin_stack.widget(0)
|
||||||
|
self.plugin_stack.removeWidget(widget)
|
||||||
|
|
||||||
|
self.plugin_list.clear()
|
||||||
|
self.plugin_buttons = []
|
||||||
|
|
||||||
|
# Clear icon grid
|
||||||
|
while self.icon_grid_layout.count():
|
||||||
|
item = self.icon_grid_layout.takeAt(0)
|
||||||
|
if item.widget():
|
||||||
|
item.widget().deleteLater()
|
||||||
|
|
||||||
|
# Reload
|
||||||
|
self._load_plugins()
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
"""Handle ESC key."""
|
"""Handle ESC key."""
|
||||||
if event.key() == Qt.Key.Key_Escape:
|
if event.key() == Qt.Key.Key_Escape:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue