Borealis-Legacy/borealis_overlay.py

204 lines
8.2 KiB
Python

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QCheckBox, QPushButton
from PyQt5.QtCore import Qt, QRect, QPoint
from PyQt5.QtGui import QPainter, QPen, QColor, QFont
from ctypes import windll
HANDLE_SIZE = 10 # Size of the resize handle squares
LABEL_HEIGHT = 20 # Height of the label area above the rectangle
class Region:
def __init__(self, x, y, w, h, label="Region", color=QColor(0, 0, 255)):
self.x = x
self.y = y
self.w = w
self.h = h
self.label = label
self.color = color
def rect(self):
return QRect(self.x, self.y, self.w, self.h)
def label_rect(self):
"""The rectangle representing the label area."""
return QRect(self.x, self.y - LABEL_HEIGHT, self.w, LABEL_HEIGHT)
def resize_handles(self):
"""Calculate the positions of the resize handles."""
return [
QRect(self.x - HANDLE_SIZE // 2, self.y - HANDLE_SIZE // 2, HANDLE_SIZE, HANDLE_SIZE), # Top-left
QRect(self.x + self.w - HANDLE_SIZE // 2, self.y - HANDLE_SIZE // 2, HANDLE_SIZE, HANDLE_SIZE), # Top-right
QRect(self.x - HANDLE_SIZE // 2, self.y + self.h - HANDLE_SIZE // 2, HANDLE_SIZE, HANDLE_SIZE), # Bottom-left
QRect(self.x + self.w - HANDLE_SIZE // 2, self.y + self.h - HANDLE_SIZE // 2, HANDLE_SIZE, HANDLE_SIZE), # Bottom-right
]
class OverlayCanvas(QWidget):
"""
A canvas to draw, resize, and interact with rectangular regions.
"""
def __init__(self, regions, parent=None):
super().__init__(parent)
self.regions = regions
self.edit_mode = False
self.selected_region = None
self.selected_handle = None # Track which handle is being dragged
self.drag_offset = QPoint()
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
for region in self.regions:
# Draw the rectangle
pen = QPen(region.color)
pen.setWidth(3)
painter.setPen(pen)
painter.drawRect(region.x, region.y, region.w, region.h)
# Draw the label above the rectangle
painter.setFont(QFont("Arial", 12, QFont.Bold))
painter.setPen(region.color)
painter.drawText(region.x + 5, region.y - 5, region.label)
# Draw resize handles if in edit mode
if self.edit_mode:
for handle in region.resize_handles():
painter.fillRect(handle, region.color)
def mousePressEvent(self, event):
if not self.edit_mode:
return # Ignore clicks if not in edit mode
if event.button() == Qt.LeftButton:
for region in reversed(self.regions): # Check regions from topmost to bottommost
# Check if a resize handle is clicked
for i, handle in enumerate(region.resize_handles()):
if handle.contains(event.pos()):
self.selected_region = region
self.selected_handle = i
return
# Check if the label area is clicked (for dragging)
if region.label_rect().contains(event.pos()):
self.selected_region = region
self.selected_handle = None # No resize handle, just dragging the rectangle
self.drag_offset = event.pos() - QPoint(region.x, region.y)
return
# Check if the main rectangle is clicked (fallback for dragging)
if region.rect().contains(event.pos()):
self.selected_region = region
self.selected_handle = None
self.drag_offset = event.pos() - QPoint(region.x, region.y)
return
def mouseMoveEvent(self, event):
if not self.edit_mode or self.selected_region is None:
return
if self.selected_handle is None:
# Dragging the entire rectangle
self.selected_region.x = event.x() - self.drag_offset.x()
self.selected_region.y = event.y() - self.drag_offset.y()
else:
# Resizing the rectangle
if self.selected_handle == 0: # Top-left
self.selected_region.w += self.selected_region.x - event.x()
self.selected_region.h += self.selected_region.y - event.y()
self.selected_region.x = event.x()
self.selected_region.y = event.y()
elif self.selected_handle == 1: # Top-right
self.selected_region.w = event.x() - self.selected_region.x
self.selected_region.h += self.selected_region.y - event.y()
self.selected_region.y = event.y()
elif self.selected_handle == 2: # Bottom-left
self.selected_region.w += self.selected_region.x - event.x()
self.selected_region.h = event.y() - self.selected_region.y
self.selected_region.x = event.x()
elif self.selected_handle == 3: # Bottom-right
self.selected_region.w = event.x() - self.selected_region.x
self.selected_region.h = event.y() - self.selected_region.y
# Prevent negative width/height
self.selected_region.w = max(self.selected_region.w, 10)
self.selected_region.h = max(self.selected_region.h, 10)
self.update() # Trigger a repaint
def mouseReleaseEvent(self, event):
if not self.edit_mode:
return
if event.button() == Qt.LeftButton:
self.selected_region = None
self.selected_handle = None # Deselect handle
class BorealisOverlay(QWidget):
def __init__(self):
super().__init__()
# Set window properties to cover the full screen
screen_geometry = QApplication.primaryScreen().geometry()
self.setGeometry(screen_geometry)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground, True) # Transparent background
# Use Win32 API to keep the window on top
hwnd = self.winId().__int__()
windll.user32.SetWindowPos(hwnd, -1, 0, 0, 0, 0, 0x0001 | 0x0002)
# Create regions to draw and interact with
self.regions = [
Region(200, 200, 150, 50, label="Region 01"),
Region(400, 300, 200, 80, label="Region 02"),
]
# Create canvas and attach to window
self.canvas = OverlayCanvas(self.regions, self)
self.canvas.setGeometry(self.rect()) # Match the canvas size to the full window
# Add title, Edit Mode UI, and close button
self.init_ui()
def init_ui(self):
"""Initialize UI components."""
# Title label
self.title_label = QLabel("Borealis Overlay", self)
self.title_label.setStyleSheet("QLabel { color: white; font-size: 18px; font-weight: bold; }")
self.title_label.move(10, 5)
# Edit mode checkbox
self.mode_toggle = QCheckBox("Edit Mode", self)
self.mode_toggle.setStyleSheet("QCheckBox { color: white; }")
self.mode_toggle.move(10, 30)
self.mode_toggle.stateChanged.connect(self.toggle_edit_mode)
# Close button
self.close_button = QPushButton("Close", self)
self.close_button.setStyleSheet(
"QPushButton { background-color: #40E0D0; color: white; font-weight: bold; border-radius: 5px; }"
) # Turquoise color
self.close_button.move(10, 60) # Place it below the Edit Mode checkbox
self.close_button.clicked.connect(self.close)
def toggle_edit_mode(self, state):
"""Enable or disable edit mode for dragging and resizing rectangles."""
editing = (state == 2)
self.canvas.edit_mode = editing # Pass the state to the canvas
print(f"Borealis Overlay Edit Mode: {'ON' if editing else 'OFF'}") # Debugging output
def main():
app = QApplication(sys.argv)
window = BorealisOverlay()
window.setWindowTitle("Borealis Overlay") # Set application window title
window.show() # Explicitly show the window
sys.exit(app.exec_())
if __name__ == "__main__":
main()