feat: EU-styled floating icon positioned near game UI

- Floating icon now matches Entropia Universe aesthetic
- Dark blue/gray background with subtle border
- Positioned at top-left (250, 10) near other game icons
- Click vs drag detection (5px threshold)
- Hover effect with lighter border
- Subtle blue glow effect
This commit is contained in:
LemonNexus 2026-02-13 13:17:11 +00:00
parent d74de07110
commit b00792726d
1 changed files with 59 additions and 33 deletions

View File

@ -1,64 +1,80 @@
""" """
EU-Utility - Floating Icon EU-Utility - Floating Icon
A draggable floating button for easy access in-game. In-game floating button styled to match Entropia Universe UI.
""" """
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QApplication from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QApplication
from PyQt6.QtCore import Qt, QPoint, pyqtSignal from PyQt6.QtCore import Qt, QPoint, pyqtSignal, QSize
from PyQt6.QtGui import QMouseEvent, QEnterEvent, QPainter, QBrush, QColor from PyQt6.QtGui import QMouseEvent, QEnterEvent, QFont, QGraphicsDropShadowEffect, QColor
class FloatingIcon(QWidget): class FloatingIcon(QWidget):
"""Draggable floating icon for in-game use.""" """Draggable floating icon that matches Entropia Universe UI."""
clicked = pyqtSignal() clicked = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
# Frameless, always on top # Frameless, always on top, click-through when not interacting
self.setWindowFlags( self.setWindowFlags(
Qt.WindowType.FramelessWindowHint | Qt.WindowType.FramelessWindowHint |
Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.WindowStaysOnTopHint |
Qt.WindowType.Tool | Qt.WindowType.Tool
Qt.WindowType.WindowTransparentForInput
) )
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
self.setFixedSize(48, 48) self.setFixedSize(42, 42)
# Position - top left with offset # Position - near top-left game icons (offset from corner)
screen = QApplication.primaryScreen().geometry() screen = QApplication.primaryScreen().geometry()
self.move(10, 10) # Position near other game UI elements (top left area)
self.move(250, 10)
self.dragging = False self.dragging = False
self.drag_position = QPoint() self.drag_position = QPoint()
self.click_threshold = 5 # pixels
self.click_start_pos = QPoint()
self._setup_ui() self._setup_ui()
def _setup_ui(self): def _setup_ui(self):
"""Setup the floating icon.""" """Setup the floating icon with EU-style."""
layout = QVBoxLayout(self) layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0) layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
self.icon_label = QLabel("") self.icon_label = QLabel("")
self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.icon_label.setFixedSize(42, 42)
# EU-style: dark background with subtle border, hexagonal or square with rounded corners
# Matching the game's dark blue/gray aesthetic
self.icon_label.setStyleSheet(""" self.icon_label.setStyleSheet("""
QLabel { QLabel {
font-size: 24px; font-size: 20px;
background-color: rgba(30, 30, 30, 200); background-color: rgba(20, 25, 35, 220);
border-radius: 24px; border-radius: 8px;
border: 2px solid rgba(74, 158, 255, 150); border: 1px solid rgba(100, 150, 200, 80);
} }
""") """)
# Add subtle glow effect
shadow = QGraphicsDropShadowEffect()
shadow.setBlurRadius(10)
shadow.setColor(QColor(74, 158, 255, 100))
shadow.setOffset(0, 0)
self.icon_label.setGraphicsEffect(shadow)
layout.addWidget(self.icon_label) layout.addWidget(self.icon_label)
def mousePressEvent(self, event: QMouseEvent): def mousePressEvent(self, event: QMouseEvent):
"""Handle mouse press.""" """Handle mouse press."""
if event.button() == Qt.MouseButton.LeftButton: if event.button() == Qt.MouseButton.LeftButton:
self.dragging = True self.dragging = True
self.drag_position = event.globalPosition().toPoint() - self.frameGeometry().topLeft() self.click_start_pos = event.globalPosition().toPoint()
self.drag_position = self.click_start_pos - self.frameGeometry().topLeft()
event.accept() event.accept()
def mouseMoveEvent(self, event: QMouseEvent): def mouseMoveEvent(self, event: QMouseEvent):
@ -69,35 +85,45 @@ class FloatingIcon(QWidget):
event.accept() event.accept()
def mouseReleaseEvent(self, event: QMouseEvent): def mouseReleaseEvent(self, event: QMouseEvent):
"""Handle mouse release.""" """Handle mouse release - detect click vs drag."""
if event.button() == Qt.MouseButton.LeftButton: if event.button() == Qt.MouseButton.LeftButton:
self.dragging = False release_pos = event.globalPosition().toPoint()
# If didn't move much, treat as click distance = (release_pos - self.click_start_pos).manhattanLength()
event.accept()
def mouseDoubleClickEvent(self, event: QMouseEvent): self.dragging = False
"""Handle double click."""
# If moved less than threshold, treat as click
if distance < self.click_threshold:
self.clicked.emit() self.clicked.emit()
event.accept() event.accept()
def enterEvent(self, event: QEnterEvent): def enterEvent(self, event: QEnterEvent):
"""Mouse entered - highlight.""" """Mouse entered - highlight like EU UI."""
self.icon_label.setStyleSheet(""" self.icon_label.setStyleSheet("""
QLabel { QLabel {
font-size: 24px; font-size: 20px;
background-color: rgba(74, 158, 255, 200); background-color: rgba(40, 55, 75, 240);
border-radius: 24px; border-radius: 8px;
border: 2px solid rgba(255, 255, 255, 200); border: 1px solid rgba(100, 180, 255, 150);
} }
""") """)
# Change cursor to indicate clickable
self.setCursor(Qt.CursorShape.PointingHandCursor)
def leaveEvent(self, event): def leaveEvent(self, event):
"""Mouse left - normal.""" """Mouse left - normal EU style."""
self.icon_label.setStyleSheet(""" self.icon_label.setStyleSheet("""
QLabel { QLabel {
font-size: 24px; font-size: 20px;
background-color: rgba(30, 30, 30, 200); background-color: rgba(20, 25, 35, 220);
border-radius: 24px; border-radius: 8px;
border: 2px solid rgba(74, 158, 255, 150); border: 1px solid rgba(100, 150, 200, 80);
} }
""") """)
self.setCursor(Qt.CursorShape.ArrowCursor)
def show_tooltip(self):
"""Show tooltip near icon."""
# Could implement a custom tooltip here
pass