169 lines
6.1 KiB
Python
169 lines
6.1 KiB
Python
import sys
|
||
from PySide6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout,
|
||
QLabel, QPushButton, QWidget, QGraphicsDropShadowEffect)
|
||
from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve
|
||
from PySide6.QtGui import QColor
|
||
|
||
|
||
class CustomMessageBox(QDialog):
|
||
# Enums pour la configuration
|
||
INFO = "info"
|
||
WARNING = "warning"
|
||
OK = "ok"
|
||
OK_CANCEL = "ok_cancel"
|
||
|
||
def __init__(self, title="Notification", message="", icon_type="info", buttons="ok", parent=None):
|
||
super().__init__(parent)
|
||
|
||
# --- CONFIGURATION FENÊTRE ---
|
||
self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog)
|
||
self.setAttribute(Qt.WA_TranslucentBackground)
|
||
self.setMinimumWidth(400)
|
||
|
||
color_main = "#101624"
|
||
color_accent = "#248277" if icon_type == self.INFO else "#cf5b16"
|
||
|
||
# --- ANIMATION DE FONDU ---
|
||
self.setWindowOpacity(0)
|
||
self.fade_anim = QPropertyAnimation(self, b"windowOpacity")
|
||
self.fade_anim.setDuration(350)
|
||
self.fade_anim.setStartValue(0)
|
||
self.fade_anim.setEndValue(1)
|
||
self.fade_anim.setEasingCurve(QEasingCurve.OutCubic)
|
||
|
||
# --- UI SETUP ---
|
||
self.container = QWidget(self)
|
||
self.container.setObjectName("MainContainer")
|
||
self.container.setStyleSheet(f"""
|
||
QWidget#MainContainer {{
|
||
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
|
||
stop:0 {color_main}, stop:1 {color_accent});
|
||
border-radius: 15px;
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
}}
|
||
QLabel {{ color: white; font-family: 'Segoe UI'; }}
|
||
""")
|
||
|
||
# LAYOUT PRINCIPAL DU CONTAINER (Marges à 0 pour coller le bouton au bord)
|
||
layout = QVBoxLayout(self.container)
|
||
layout.setContentsMargins(0, 0, 0, 0)
|
||
layout.setSpacing(0)
|
||
|
||
# 1. Barre de titre (Contenu collé en haut et à droite)
|
||
title_bar_layout = QHBoxLayout()
|
||
title_bar_layout.setContentsMargins(15, 0, 0, 0)
|
||
title_bar_layout.setSpacing(0)
|
||
|
||
title_label = QLabel(title.upper())
|
||
title_label.setStyleSheet(
|
||
"font-weight: bold; font-size: 10px; color: rgba(255,255,255,0.7); letter-spacing: 1px;")
|
||
|
||
self.close_btn = QPushButton("✕")
|
||
self.close_btn.setFixedSize(45, 35)
|
||
self.close_btn.clicked.connect(self.reject)
|
||
self.close_btn.setCursor(Qt.PointingHandCursor)
|
||
self.close_btn.setStyleSheet("""
|
||
QPushButton {
|
||
background: transparent;
|
||
color: white;
|
||
border: none;
|
||
font-size: 14px;
|
||
/* Rayon identique au container (15px) pour épouser parfaitement le coin */
|
||
border-top-right-radius: 15px;
|
||
border-bottom-left-radius: 10px;
|
||
}
|
||
QPushButton:hover {
|
||
background-color: #e74c3c;
|
||
color: white;
|
||
}
|
||
""")
|
||
|
||
title_bar_layout.addWidget(title_label)
|
||
title_bar_layout.addStretch()
|
||
title_bar_layout.addWidget(self.close_btn)
|
||
layout.addLayout(title_bar_layout)
|
||
|
||
# 2. SOUS-LAYOUT POUR LE CONTENU (Ici on remet des marges pour le texte)
|
||
body_layout = QVBoxLayout()
|
||
body_layout.setContentsMargins(20, 10, 20, 20)
|
||
body_layout.setSpacing(15)
|
||
|
||
# Contenu central (Icône + Message)
|
||
content_layout = QHBoxLayout()
|
||
icon_label = QLabel()
|
||
icon_text = "ℹ️" if icon_type == self.INFO else "⚠️"
|
||
icon_label.setText(icon_text)
|
||
icon_label.setStyleSheet("font-size: 35px; margin-right: 10px;")
|
||
|
||
msg_label = QLabel(message)
|
||
msg_label.setStyleSheet("font-size: 14px; color: #f0f0f0;")
|
||
msg_label.setWordWrap(True)
|
||
|
||
content_layout.addWidget(icon_label)
|
||
content_layout.addWidget(msg_label, 1)
|
||
body_layout.addLayout(content_layout)
|
||
|
||
# Boutons d'action
|
||
btn_layout = QHBoxLayout()
|
||
btn_layout.setSpacing(10)
|
||
btn_layout.addStretch()
|
||
|
||
style_btn_base = """
|
||
QPushButton {
|
||
background: #2a313d; border-radius: 6px; color: white;
|
||
padding: 8px 20px; font-weight: bold; font-size: 12px;
|
||
border: 1px solid rgba(255,255,255,0.05);
|
||
}
|
||
QPushButton:hover { background: #363d4a; border: 1px solid white; }
|
||
"""
|
||
|
||
if buttons == self.OK_CANCEL:
|
||
self.btn_cancel = QPushButton("ANNULER")
|
||
self.btn_cancel.setStyleSheet(style_btn_base)
|
||
self.btn_cancel.clicked.connect(self.reject)
|
||
btn_layout.addWidget(self.btn_cancel)
|
||
|
||
self.btn_ok = QPushButton("COMPRIS")
|
||
style_btn_ok = style_btn_base.replace("#2a313d", "#248277")
|
||
self.btn_ok.setStyleSheet(style_btn_ok)
|
||
self.btn_ok.setCursor(Qt.PointingHandCursor)
|
||
self.btn_ok.clicked.connect(self.accept)
|
||
btn_layout.addWidget(self.btn_ok)
|
||
|
||
body_layout.addLayout(btn_layout)
|
||
|
||
# Ajout du body_layout dans le layout principal
|
||
layout.addLayout(body_layout)
|
||
|
||
# --- OMBRE PORTÉE ---
|
||
shadow = QGraphicsDropShadowEffect(self)
|
||
shadow.setBlurRadius(20)
|
||
shadow.setXOffset(0)
|
||
shadow.setYOffset(8)
|
||
shadow.setColor(QColor(0, 0, 0, 180))
|
||
self.container.setGraphicsEffect(shadow)
|
||
|
||
final_layout = QVBoxLayout(self)
|
||
final_layout.addWidget(self.container)
|
||
|
||
self.old_pos = None
|
||
|
||
def showEvent(self, event):
|
||
super().showEvent(event)
|
||
self.fade_anim.start()
|
||
|
||
def mousePressEvent(self, e):
|
||
# On permet le déplacement uniquement si on clique sur la barre de titre
|
||
# ou n'importe où sauf sur les boutons
|
||
if e.button() == Qt.LeftButton:
|
||
self.old_pos = e.globalPosition().toPoint()
|
||
|
||
def mouseMoveEvent(self, e):
|
||
if self.old_pos:
|
||
delta = e.globalPosition().toPoint() - self.old_pos
|
||
self.move(self.x() + delta.x(), self.y() + delta.y())
|
||
self.old_pos = e.globalPosition().toPoint()
|
||
|
||
def mouseReleaseEvent(self, e):
|
||
self.old_pos = None
|