diff --git a/app/main_window.py b/app/main_window.py index dddf576..f5ce530 100644 --- a/app/main_window.py +++ b/app/main_window.py @@ -229,8 +229,10 @@ class MainWindow(QMainWindow): self._add_action(pages_menu, "Pivoter -90", None, lambda: self._rotate_current(-90)) self._add_action(pages_menu, "Pivoter 180", None, lambda: self._rotate_current(180)) self._add_action(pages_menu, "Inverser l'ordre des pages", None, self._do_reverse_pages) + self._add_action(pages_menu, "Separer paires/impaires", None, self._do_shuffle_even_odd) pages_menu.addSeparator() self._add_action(pages_menu, "Inserer des pages blanches", None, self._do_insert_blank) + self._add_action(pages_menu, "Creer un document test...", None, self._do_create_sample) # Annotations annot_menu = menubar.addMenu("Annotations") @@ -247,6 +249,13 @@ class MainWindow(QMainWindow): self._add_action(annot_menu, "Definir les fonds perdus", None, self._do_bleeds) self._add_action(annot_menu, "Enlever les fonds perdus", None, self._do_remove_bleeds) + # Macros + self._macros_menu = menubar.addMenu("Macros") + self._add_action(self._macros_menu, "Enregistrer la derniere action...", None, self._do_save_macro) + self._add_action(self._macros_menu, "Gerer les macros...", None, self._do_manage_macros) + self._macros_menu.addSeparator() + self._refresh_macros_menu() + # Aide help_menu = menubar.addMenu("Aide") self._add_action(help_menu, "Rechercher une mise a jour...", None, self._do_check_update) @@ -501,10 +510,29 @@ class MainWindow(QMainWindow): os.close(fd) return path + _FUN_MESSAGES = [ + "Pliage des pages en origami...", + "Consultation des esprits de Gutenberg...", + "Negociation avec les pixels...", + "Alignement des atomes de papier...", + "Invocation du dieu de l'imposition...", + "Repassage des pages froissees...", + "Calibrage du massicot virtuel...", + "Appel a un ami imprimeur...", + "Les pages font la queue...", + "Rechauffement de l'encre numerique...", + "Comptage des points par pouce...", + "Meditation sur les marges...", + "Rangement des pages par ordre alphabetique... non, numerique !", + "Verification que le papier est bien a plat...", + ] + def _show_progress(self): + import random self._progress.setRange(0, 0) self._progress.show() - self._status_label.setText("Traitement en cours...") + msg = random.choice(self._FUN_MESSAGES) + self._status_label.setText(msg) QApplication.processEvents() def _hide_progress(self): @@ -612,6 +640,7 @@ class MainWindow(QMainWindow): output = self._make_temp() try: trim_and_shift(self._current_file, output, **settings) + self._last_action = {"action": "trim_shift", "settings": settings} self._show_result(output) except Exception as e: self._hide_progress() @@ -630,6 +659,7 @@ class MainWindow(QMainWindow): try: create_booklet(self._current_file, output, **settings) self._show_result(output) + self._last_action = {"action": "booklet", "settings": settings} except Exception as e: self._hide_progress() QMessageBox.critical(self, "Erreur", str(e)) @@ -644,6 +674,7 @@ class MainWindow(QMainWindow): output = self._make_temp() try: nup_pages(self._current_file, output, **settings) + self._last_action = {"action": "nup", "settings": settings} self._show_result(output) except Exception as e: self._hide_progress() @@ -659,6 +690,7 @@ class MainWindow(QMainWindow): output = self._make_temp() try: step_and_repeat(self._current_file, output, **settings) + self._last_action = {"action": "step_repeat", "settings": settings} self._show_result(output) except Exception as e: self._hide_progress() @@ -981,6 +1013,153 @@ class MainWindow(QMainWindow): # ── A propos ── + # ── Macros ── + + def _last_action_info(self): + return getattr(self, '_last_action', None) + + def _do_save_macro(self): + from PyQt6.QtWidgets import QInputDialog + name, ok = QInputDialog.getText(self, "Enregistrer la macro", "Nom de la macro :") + if ok and name.strip(): + info = self._last_action_info() + if info: + from app.presets.preset_manager import save_preset + save_preset(name.strip(), info["action"], info["settings"]) + self._refresh_macros_menu() + self._status_label.setText(f"Macro '{name.strip()}' enregistree") + else: + QMessageBox.information(self, "Macro", "Effectuez d'abord une action a enregistrer.") + + def _do_manage_macros(self): + from app.presets.preset_manager import list_presets, delete_preset + from PyQt6.QtWidgets import QDialog, QVBoxLayout, QListWidget, QPushButton, QHBoxLayout + presets = list_presets() + if not presets: + QMessageBox.information(self, "Macros", "Aucune macro enregistree.") + return + dlg = QDialog(self) + dlg.setWindowTitle("Gerer les macros") + dlg.setMinimumWidth(350) + layout = QVBoxLayout(dlg) + lst = QListWidget() + lst.addItems(presets.keys()) + layout.addWidget(lst) + bl = QHBoxLayout() + btn_del = QPushButton("Supprimer") + def do_del(): + item = lst.currentItem() + if item: + delete_preset(item.text()) + lst.takeItem(lst.row(item)) + self._refresh_macros_menu() + btn_del.clicked.connect(do_del) + bl.addWidget(btn_del) + btn_close = QPushButton("Fermer") + btn_close.clicked.connect(dlg.close) + bl.addWidget(btn_close) + layout.addLayout(bl) + dlg.exec() + + def _refresh_macros_menu(self): + from app.presets.preset_manager import list_presets + # Supprimer les actions apres le separateur + actions = self._macros_menu.actions() + found_sep = False + for act in actions: + if act.isSeparator(): + found_sep = True + continue + if found_sep: + self._macros_menu.removeAction(act) + # Ajouter les presets + presets = list_presets() + for name in presets: + self._macros_menu.addAction(name, lambda n=name: self._run_macro(n)) + + def _run_macro(self, name): + from app.presets.preset_manager import list_presets + presets = list_presets() + preset = presets.get(name) + if not preset or not self._require_file(): + return + action = preset["action"] + settings = preset["settings"] + self._show_progress() + output = self._make_temp() + try: + if action == "booklet": + create_booklet(self._current_file, output, **settings) + elif action == "nup": + nup_pages(self._current_file, output, **settings) + self._last_action = {"action": "nup", "settings": settings} + elif action == "step_repeat": + step_and_repeat(self._current_file, output, **settings) + self._last_action = {"action": "step_repeat", "settings": settings} + elif action == "crop": + crop_pages(self._current_file, output, **settings) + elif action == "trim_shift": + trim_and_shift(self._current_file, output, **settings) + self._last_action = {"action": "trim_shift", "settings": settings} + else: + self._hide_progress() + QMessageBox.warning(self, "Macro", f"Action inconnue : {action}") + return + self._show_result(output) + self._status_label.setText(f"Macro '{name}' executee") + except Exception as e: + self._hide_progress() + QMessageBox.critical(self, "Erreur", str(e)) + + # ── Pages supplementaires ── + + def _do_shuffle_even_odd(self): + """Separer pages paires et impaires en deux documents.""" + if not self._require_file(): + return + from pypdf import PdfReader, PdfWriter + reader = PdfReader(self._current_file) + writer_odd = PdfWriter() + writer_even = PdfWriter() + for i, page in enumerate(reader.pages): + if (i + 1) % 2 == 0: + writer_even.add_page(page) + else: + writer_odd.add_page(page) + # Sauvegarder les deux + path_odd, _ = QFileDialog.getSaveFileName(self, "Enregistrer pages impaires", "", "PDF (*.pdf)") + if not path_odd: + return + with open(path_odd, "wb") as f: + writer_odd.write(f) + path_even, _ = QFileDialog.getSaveFileName(self, "Enregistrer pages paires", "", "PDF (*.pdf)") + if path_even: + with open(path_even, "wb") as f: + writer_even.write(f) + self._status_label.setText("Pages paires/impaires separees") + + def _do_create_sample(self): + """Creer un document test numerote.""" + from PyQt6.QtWidgets import QInputDialog + num, ok = QInputDialog.getInt(self, "Document test", "Nombre de pages :", 8, 1, 200) + if not ok: + return + from reportlab.pdfgen import canvas as rl_canvas + from reportlab.lib.pagesizes import A4 + output = self._make_temp() + c = rl_canvas.Canvas(output, pagesize=A4) + for i in range(1, num + 1): + c.setFont("Helvetica-Bold", 72) + c.drawCentredString(A4[0] / 2, A4[1] / 2, str(i)) + c.setFont("Helvetica", 14) + c.drawCentredString(A4[0] / 2, A4[1] / 2 - 40, f"Page {i} sur {num}") + c.setFont("Helvetica", 10) + c.drawCentredString(A4[0] / 2, 30, "CopyDev Imposing Tool — Document test") + c.showPage() + c.save() + self._open_pdf(output) + self._status_label.setText(f"Document test de {num} pages cree") + def _do_check_update(self): from app.updater import check_for_update, do_update, VERSION self._status_label.setText("Recherche de mises a jour...") diff --git a/app/page_panel.py b/app/page_panel.py index 1f20c9d..a9596d6 100644 --- a/app/page_panel.py +++ b/app/page_panel.py @@ -28,6 +28,12 @@ class PagePanel(QWidget): self._list = QListWidget() self._list.setIconSize(QSize(120, 170)) self._list.setSpacing(4) + self._list.setViewMode(QListWidget.ViewMode.IconMode) + self._list.setResizeMode(QListWidget.ResizeMode.Adjust) + self._list.setWrapping(True) + self._list.setGridSize(QSize(140, 190)) + self._list.setUniformItemSizes(True) + self._list.setMovement(QListWidget.Movement.Free) self._list.setStyleSheet(""" QListWidget { background: #e0e0e0; diff --git a/app/updater.py b/app/updater.py index be7301a..1516c94 100644 --- a/app/updater.py +++ b/app/updater.py @@ -14,7 +14,7 @@ REPO = "jules/copydev-imposing-tool" BRANCH = "master" # Version actuelle (incrementee a chaque release) -VERSION = "3.1.0" +VERSION = "3.2.0" def get_remote_version(): diff --git a/version.txt b/version.txt index fd2a018..944880f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.1.0 +3.2.0