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