forked from Support/sp-hydra-veil-gui
200 lines
8.1 KiB
Python
Executable file
200 lines
8.1 KiB
Python
Executable file
from PyQt6.QtCore import Qt, QTimer, pyqtSignal
|
|
from PyQt6.QtGui import QFont, QGuiApplication
|
|
from PyQt6.QtWidgets import (
|
|
QDialog,
|
|
QFrame,
|
|
QHBoxLayout,
|
|
QLabel,
|
|
QPushButton,
|
|
QScrollArea,
|
|
QVBoxLayout,
|
|
QWidget,
|
|
)
|
|
|
|
from gui.v2.ui.styles.styles import (
|
|
POPUP_ACTION_BUTTON_RED_QSS,
|
|
POPUP_BG_QSS,
|
|
POPUP_CANCEL_BUTTON_QSS,
|
|
)
|
|
|
|
|
|
class OperationResultPopup(QDialog):
|
|
action_selected = pyqtSignal(bool)
|
|
|
|
def __init__(self, parent=None, message="", title="Operation Failed", action_button_text="Yes", cancel_button_text="No", action_result=True):
|
|
super().__init__(parent)
|
|
self.parent_window = parent
|
|
self.title_text = title or "Operation Failed"
|
|
self.message = message or "The operation could not be completed."
|
|
self.action_button_text = action_button_text
|
|
self.cancel_button_text = cancel_button_text
|
|
self.action_result = action_result
|
|
self._completed = False
|
|
self._use_parent_local_geometry = QGuiApplication.platformName().lower().startswith("wayland")
|
|
self.initUI()
|
|
|
|
def initUI(self):
|
|
self.setFixedSize(560, 300)
|
|
if self._use_parent_local_geometry:
|
|
if self.parent_window is not None:
|
|
self.setParent(self.parent_window)
|
|
self.setWindowFlags(Qt.WindowType.Widget)
|
|
else:
|
|
self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.FramelessWindowHint)
|
|
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
|
|
|
outer = QVBoxLayout(self)
|
|
outer.setContentsMargins(0, 0, 0, 0)
|
|
|
|
bg_widget = QWidget(self)
|
|
bg_widget.setStyleSheet(POPUP_BG_QSS)
|
|
outer.addWidget(bg_widget)
|
|
|
|
content_layout = QVBoxLayout(bg_widget)
|
|
content_layout.setContentsMargins(22, 14, 22, 18)
|
|
content_layout.setSpacing(12)
|
|
|
|
top_row = QHBoxLayout()
|
|
top_row.setContentsMargins(0, 0, 0, 0)
|
|
top_row.setSpacing(10)
|
|
|
|
title_label = QLabel(self.title_text)
|
|
title_label.setFont(QFont("Arial", 18, QFont.Weight.Bold))
|
|
title_label.setStyleSheet("color: #d62828; background: transparent; border: none;")
|
|
title_label.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
|
|
title_label.setMinimumWidth(0)
|
|
top_row.addWidget(title_label, 1)
|
|
|
|
close_button = QPushButton("X")
|
|
close_button.setFixedSize(36, 36)
|
|
close_button.setFont(QFont("Arial", 14, QFont.Weight.Bold))
|
|
close_button.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: transparent;
|
|
color: #444444;
|
|
font-size: 18px;
|
|
font-weight: 900;
|
|
border: none;
|
|
}
|
|
QPushButton:hover {
|
|
color: #d62828;
|
|
}
|
|
""")
|
|
close_button.clicked.connect(lambda: self._choose(False))
|
|
top_row.addWidget(close_button, 0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop)
|
|
|
|
content_layout.addLayout(top_row)
|
|
|
|
scroll_area = QScrollArea()
|
|
scroll_area.setWidgetResizable(True)
|
|
scroll_area.setFrameShape(QFrame.Shape.NoFrame)
|
|
scroll_area.setStyleSheet("background: transparent; border: none;")
|
|
content_layout.addWidget(scroll_area, 1)
|
|
|
|
scroll_content = QWidget()
|
|
scroll_content.setStyleSheet("background: transparent; border: none;")
|
|
scroll_layout = QVBoxLayout(scroll_content)
|
|
scroll_layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
message_label = QLabel(self.message)
|
|
message_label.setFont(QFont("Arial", 12))
|
|
message_label.setStyleSheet("color: #333333; background: transparent; border: none;")
|
|
message_label.setWordWrap(True)
|
|
message_label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
|
message_label.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
|
|
scroll_layout.addWidget(message_label)
|
|
scroll_layout.addStretch()
|
|
scroll_area.setWidget(scroll_content)
|
|
|
|
button_row = QHBoxLayout()
|
|
button_row.addStretch()
|
|
|
|
if self.cancel_button_text is not None:
|
|
cancel_button = QPushButton(self.cancel_button_text)
|
|
cancel_button.setFixedSize(max(110, min(180, 22 + len(self.cancel_button_text) * 8)), 42)
|
|
cancel_button.setFont(QFont("Arial", 11, QFont.Weight.Bold))
|
|
cancel_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
cancel_button.setStyleSheet(POPUP_CANCEL_BUTTON_QSS)
|
|
cancel_button.clicked.connect(lambda: self._choose(False))
|
|
button_row.addWidget(cancel_button)
|
|
|
|
action_button = QPushButton(self.action_button_text)
|
|
action_button.setFixedSize(max(110, min(180, 22 + len(self.action_button_text) * 8)), 42)
|
|
action_button.setFont(QFont("Arial", 11, QFont.Weight.Bold))
|
|
action_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
action_button.setStyleSheet(POPUP_ACTION_BUTTON_RED_QSS)
|
|
action_button.clicked.connect(lambda: self._choose(self.action_result))
|
|
button_row.addWidget(action_button)
|
|
content_layout.addLayout(button_row)
|
|
|
|
if not self._use_parent_local_geometry:
|
|
self.setWindowModality(Qt.WindowModality.ApplicationModal)
|
|
|
|
def _choose(self, accepted):
|
|
if self._completed:
|
|
return
|
|
self._completed = True
|
|
self.action_selected.emit(accepted)
|
|
self.accept()
|
|
|
|
def closeEvent(self, event):
|
|
if not self._completed:
|
|
self._completed = True
|
|
self.action_selected.emit(False)
|
|
event.accept()
|
|
|
|
def show(self):
|
|
self._center_on_parent()
|
|
super().show()
|
|
|
|
def showEvent(self, event):
|
|
super().showEvent(event)
|
|
self._center_on_parent()
|
|
QTimer.singleShot(0, self._center_on_parent)
|
|
|
|
def _center_on_parent(self):
|
|
parent = self.parent_window
|
|
if parent is None:
|
|
return
|
|
try:
|
|
if not hasattr(parent, 'mapToGlobal') or not hasattr(parent, 'rect'):
|
|
return
|
|
parent_local_rect = parent.rect()
|
|
if parent_local_rect.isEmpty():
|
|
return
|
|
my_size = self.size()
|
|
if my_size.isEmpty() or my_size.width() <= 0 or my_size.height() <= 0:
|
|
my_size = self.sizeHint()
|
|
if self._use_parent_local_geometry:
|
|
target_x = parent_local_rect.x() + (parent_local_rect.width() - my_size.width()) // 2
|
|
target_y = parent_local_rect.y() + (parent_local_rect.height() - my_size.height()) // 2
|
|
target_x = max(parent_local_rect.left(), min(target_x, parent_local_rect.right() - my_size.width() + 1))
|
|
target_y = max(parent_local_rect.top(), min(target_y, parent_local_rect.bottom() - my_size.height() + 1))
|
|
else:
|
|
parent_center = parent.mapToGlobal(parent_local_rect.center())
|
|
target_x = parent_center.x() - my_size.width() // 2
|
|
target_y = parent_center.y() - my_size.height() // 2
|
|
screen = None
|
|
if hasattr(parent, 'screen'):
|
|
try:
|
|
screen = parent.screen()
|
|
except Exception:
|
|
screen = None
|
|
if screen is not None:
|
|
avail = screen.availableGeometry()
|
|
target_x = max(avail.left(), min(target_x, avail.right() - my_size.width()))
|
|
target_y = max(avail.top(), min(target_y, avail.bottom() - my_size.height()))
|
|
self.setGeometry(target_x, target_y, my_size.width(), my_size.height())
|
|
if self._use_parent_local_geometry:
|
|
self.raise_()
|
|
self.setFocus(Qt.FocusReason.PopupFocusReason)
|
|
except Exception:
|
|
pass
|
|
|
|
def mousePressEvent(self, event):
|
|
self.oldPos = event.globalPosition().toPoint()
|
|
|
|
def mouseMoveEvent(self, event):
|
|
delta = event.globalPosition().toPoint() - self.oldPos
|
|
self.move(self.x() + delta.x(), self.y() + delta.y())
|
|
self.oldPos = event.globalPosition().toPoint()
|