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:
LemonNexus 2026-02-13 17:47:16 +00:00
parent bcd4574b7f
commit 7f6547f8de
1 changed files with 199 additions and 24 deletions

View File

@ -55,11 +55,18 @@ class OverlayWindow(QMainWindow):
"""Configure window - resizable and shows in taskbar."""
self.setWindowTitle("EU-Utility")
# Resizable window (no FramelessWindowHint), stays on top
# Resizable window, stays on top
self.setWindowFlags(
Qt.WindowType.WindowStaysOnTopHint
)
# Apply dark background to window itself
self.setStyleSheet(f"""
QMainWindow {{
background-color: {EU_COLORS['bg_dark']};
}}
""")
self.setMinimumSize(600, 400)
self.resize(850, 600)
self._center_window()
@ -72,69 +79,80 @@ class OverlayWindow(QMainWindow):
self.move(x, y)
def _setup_ui(self):
"""Setup clean EU-styled UI."""
"""Setup clean EU-styled UI - fills window, no box-in-box."""
central = QWidget()
self.setCentralWidget(central)
# NO MARGINS - fill entire window
layout = QVBoxLayout(central)
layout.setContentsMargins(20, 20, 20, 20)
layout.setContentsMargins(0, 0, 0, 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.setObjectName("euContainer")
self.container.setStyleSheet(f"""
#euContainer {{
background-color: {EU_COLORS['bg_dark']};
border: 1px solid {EU_COLORS['border_window']};
border-radius: 8px;
border: none;
}}
""")
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.setContentsMargins(0, 0, 0, 0)
container_layout.setSpacing(0)
# Header with centered title - CLEAN (no weird lines)
# Header with settings button
header = QWidget()
header.setObjectName("header")
header.setStyleSheet(f"""
QWidget {{
QWidget#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']};
}}
""")
header_layout = QHBoxLayout(header)
header_layout.setContentsMargins(15, 12, 15, 12)
header_layout.setContentsMargins(15, 8, 15, 8)
header_layout.setSpacing(10)
# App icon
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.setFixedSize(20, 20)
app_icon.setFixedSize(18, 18)
header_layout.addWidget(app_icon)
# Centered title
title = QLabel("EU-UTILITY")
# Title
title = QLabel("EU-Utility")
title.setStyleSheet(f"""
color: {EU_COLORS['text_primary']};
font-size: 14px;
font-size: 13px;
font-weight: bold;
letter-spacing: 2px;
""")
header_layout.addWidget(title)
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_group = QButtonGroup(self)
view_group.setExclusive(True)
@ -142,7 +160,7 @@ class OverlayWindow(QMainWindow):
self.icon_view_btn = QPushButton("Grid")
self.icon_view_btn.setCheckable(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.clicked.connect(lambda: self._set_view_mode("icons"))
header_layout.addWidget(self.icon_view_btn)
@ -336,6 +354,19 @@ class OverlayWindow(QMainWindow):
"""Load plugins into sidebar and stack - FIXED indexing."""
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):
# Get icon name
icon_name = get_plugin_icon_name(plugin.name)
@ -534,6 +565,150 @@ class OverlayWindow(QMainWindow):
self.tray_icon.hide()
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):
"""Handle ESC key."""
if event.key() == Qt.Key.Key_Escape: