V2.5.1 — Dialogue licence custom + fix recadrage + style

- Dialogue de licence custom (remplace QInputDialog moche)
  - Logo CopyDev, champ stylise, bouton Activer cyan
  - Messages erreur/succes en dialogues custom colores
- Fix recadrage : reference au dialogue preservee avant destruction
- Splash screen sans bordure carree
- Style coherent gris/cyan sur tous les dialogues

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jules
2026-03-21 14:49:29 +01:00
parent d7a538aa8c
commit e94158aae8
6 changed files with 228 additions and 34 deletions

187
app/license_dialog.py Normal file
View File

@@ -0,0 +1,187 @@
"""Dialogue de saisie de licence — style moderne."""
import os
import sys
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
QLineEdit, QPushButton, QApplication)
from PyQt6.QtGui import QPixmap, QFont
from PyQt6.QtCore import Qt
class LicenseDialog(QDialog):
"""Dialogue de saisie de cle de licence."""
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("CopyDev Imposing Tool — Activation")
self.setFixedSize(420, 340)
self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint)
self._key = ""
self._setup_ui()
self._apply_style()
def _setup_ui(self):
layout = QVBoxLayout(self)
layout.setContentsMargins(32, 24, 32, 24)
layout.setSpacing(0)
# Logo
logo_label = QLabel()
base = sys._MEIPASS if getattr(sys, 'frozen', False) else os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
logo_path = os.path.join(base, "resources", "logo.png")
if os.path.exists(logo_path):
pixmap = QPixmap(logo_path).scaled(80, 80,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation)
logo_label.setPixmap(pixmap)
logo_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(logo_label)
layout.addSpacing(12)
title = QLabel("Activation")
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
title.setFont(QFont("Segoe UI", 16, QFont.Weight.Bold))
layout.addWidget(title)
layout.addSpacing(4)
subtitle = QLabel("Entrez votre cle de licence pour activer le logiciel")
subtitle.setAlignment(Qt.AlignmentFlag.AlignCenter)
subtitle.setFont(QFont("Segoe UI", 10))
subtitle.setStyleSheet("color: #888;")
subtitle.setWordWrap(True)
layout.addWidget(subtitle)
layout.addSpacing(20)
# Champ de saisie
self._input = QLineEdit()
self._input.setPlaceholderText("COPYDEV-XXXX-XXXX-XXXX")
self._input.setFont(QFont("Consolas", 13))
self._input.setAlignment(Qt.AlignmentFlag.AlignCenter)
self._input.setMinimumHeight(40)
self._input.returnPressed.connect(self._on_activate)
layout.addWidget(self._input)
layout.addSpacing(16)
# Boutons
btn_layout = QHBoxLayout()
btn_layout.setSpacing(10)
self._btn_cancel = QPushButton("Annuler")
self._btn_cancel.setMinimumHeight(36)
self._btn_cancel.clicked.connect(self.reject)
btn_layout.addWidget(self._btn_cancel)
self._btn_activate = QPushButton("Activer")
self._btn_activate.setMinimumHeight(36)
self._btn_activate.setDefault(True)
self._btn_activate.clicked.connect(self._on_activate)
btn_layout.addWidget(self._btn_activate)
layout.addLayout(btn_layout)
layout.addStretch()
# Contact
contact = QLabel("contact@copydev.fr — www.copydev.fr")
contact.setAlignment(Qt.AlignmentFlag.AlignCenter)
contact.setFont(QFont("Segoe UI", 8))
contact.setStyleSheet("color: #aaa;")
layout.addWidget(contact)
def _apply_style(self):
self.setStyleSheet("""
QDialog { background: #f5f5f5; }
QLabel { color: #2d2d2d; }
QLineEdit {
background: #fff; color: #2d2d2d;
border: 2px solid #d0d0d0; border-radius: 8px;
padding: 8px; font-size: 13px;
}
QLineEdit:focus { border-color: #00b4d8; }
QPushButton#cancel {
background: #e8e8e8; color: #555; border: 1px solid #d0d0d0;
border-radius: 8px; font-size: 13px;
}
QPushButton#cancel:hover { background: #ddd; }
""")
self._btn_activate.setStyleSheet("""
QPushButton {
background: #00b4d8; color: white; border: none;
border-radius: 8px; font-size: 13px; font-weight: bold;
}
QPushButton:hover { background: #0096b7; }
QPushButton:pressed { background: #007a96; }
""")
self._btn_cancel.setStyleSheet("""
QPushButton {
background: #e8e8e8; color: #555; border: 1px solid #d0d0d0;
border-radius: 8px; font-size: 13px;
}
QPushButton:hover { background: #ddd; }
""")
def _on_activate(self):
self._key = self._input.text().strip()
if self._key:
self.accept()
def get_key(self):
return self._key
class LicenseMessageDialog(QDialog):
"""Dialogue de message stylise (remplace QMessageBox)."""
def __init__(self, title, message, msg_type="info", parent=None):
super().__init__(parent)
self.setWindowTitle(title)
self.setFixedWidth(400)
self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint)
layout = QVBoxLayout(self)
layout.setContentsMargins(28, 24, 28, 20)
layout.setSpacing(12)
# Icone couleur selon le type
colors = {"info": "#00b4d8", "success": "#2ecc71", "error": "#e74c3c", "warning": "#f39c12"}
color = colors.get(msg_type, "#00b4d8")
bar = QLabel()
bar.setFixedHeight(4)
bar.setStyleSheet(f"background: {color}; border-radius: 2px;")
layout.addWidget(bar)
title_lbl = QLabel(title)
title_lbl.setFont(QFont("Segoe UI", 14, QFont.Weight.Bold))
title_lbl.setStyleSheet(f"color: {color};")
layout.addWidget(title_lbl)
msg_lbl = QLabel(message)
msg_lbl.setFont(QFont("Segoe UI", 11))
msg_lbl.setWordWrap(True)
msg_lbl.setStyleSheet("color: #444; line-height: 1.4;")
layout.addWidget(msg_lbl)
layout.addSpacing(8)
btn = QPushButton("OK")
btn.setMinimumHeight(36)
btn.setStyleSheet(f"""
QPushButton {{
background: {color}; color: white; border: none;
border-radius: 8px; font-size: 13px; font-weight: bold;
min-width: 100px;
}}
QPushButton:hover {{ background: {color}cc; }}
""")
btn.clicked.connect(self.accept)
btn_layout = QHBoxLayout()
btn_layout.addStretch()
btn_layout.addWidget(btn)
layout.addLayout(btn_layout)
self.setStyleSheet("QDialog { background: #f5f5f5; }")

View File

@@ -714,16 +714,27 @@ class MainWindow(QMainWindow):
)
def on_crop_accepted():
if not hasattr(self, '_crop_dlg') or not self._crop_dlg:
return
dlg_ref = self._crop_dlg
self._crop_dlg = None
try:
settings = dlg_ref.get_settings()
except Exception:
return
if not settings.get("pages"):
return
self._show_progress()
settings = self._crop_dlg.get_settings()
output = self._make_temp()
try:
crop_pages(self._current_file, output, **settings)
self._show_result(output)
self._status_label.setText(
f"Recadrage applique — {len(settings['pages'])} page(s)"
)
except Exception as e:
self._hide_progress()
QMessageBox.critical(self, "Erreur", str(e))
self._crop_dlg = None
self._crop_dlg.accepted.connect(on_crop_accepted)
self._crop_dlg.rejected.connect(lambda: setattr(self, '_crop_dlg', None))

View File

@@ -13,7 +13,12 @@ class SplashScreen(QWidget):
self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, False)
self.setFixedSize(500, 400)
self.setStyleSheet("background-color: #f5f5f5; border: 1px solid #d0d0d0;")
self.setStyleSheet("""
QWidget {
background-color: #f5f5f5;
border-radius: 16px;
}
""")
layout = QVBoxLayout(self)
layout.setContentsMargins(40, 30, 40, 30)

View File

@@ -14,7 +14,7 @@ REPO = "jules/copydev-imposing-tool"
BRANCH = "master"
# Version actuelle (incrementee a chaque release)
VERSION = "2.5.0"
VERSION = "2.5.1"
def get_remote_version():