Files
copydev-imposing-tool/app/page_panel.py
Jules 673d76caa2 V3.0.0 — Rotation, Annuler/Refaire, Delivretiser, Trim&Shift, Inverser
- Rotation de pages : clic droit sur vignette → Pivoter +90/-90/180
  Aussi dans le menu Pages
- Ctrl+Z / Ctrl+Y : annuler et refaire (pile de 20 etats)
- Delivretiser : coupe les pages en 2 et remet dans l'ordre sequentiel
  (inverse de la creation de livret)
- Trim & Shift : decaler le contenu des pages
  - Decalage X/Y different pages paires/impaires
  - Compensation de creep progressive pour livrets epais
- Inverser l'ordre des pages (menu Pages)
- Fix impression : ouvre le PDF dans le lecteur par defaut
- Barre outils droite : ajout Delivretiser, Trim/Shift, Inverser

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:02:07 +01:00

128 lines
4.6 KiB
Python

"""Panneau lateral de vignettes des pages — V2."""
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QListWidget, QListWidgetItem,
QAbstractItemView, QMenu, QSizePolicy)
from PyQt6.QtGui import QIcon, QPixmap
from PyQt6.QtCore import Qt, pyqtSignal, QSize
class PagePanel(QWidget):
"""Panneau de vignettes avec drag & drop, suppression, insertion."""
page_selected = pyqtSignal(int)
pages_reordered = pyqtSignal(list)
page_delete_requested = pyqtSignal(int)
page_insert_requested = pyqtSignal(int)
page_rotate_requested = pyqtSignal(int, int) # page_index, degrees (90, -90, 180)
def __init__(self, parent=None):
super().__init__(parent)
self.setMinimumWidth(100)
self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
self._setup_ui()
def _setup_ui(self):
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
self._list = QListWidget()
self._list.setIconSize(QSize(120, 170))
self._list.setSpacing(4)
self._list.setStyleSheet("""
QListWidget {
background: #e0e0e0;
border: none;
border-right: 1px solid #d0d0d0;
padding: 4px;
}
QListWidget::item {
background: #ffffff;
border: 1px solid #d0d0d0;
border-radius: 6px;
padding: 4px;
color: #555;
font-size: 10px;
margin: 2px 0;
}
QListWidget::item:hover {
background: #e0f4ff;
border-color: #00b4d8;
}
QListWidget::item:selected {
background: #d8f0f8;
border: 2px solid #00b4d8;
color: #006fa6;
}
""")
self._list.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
self._list.setDefaultDropAction(Qt.DropAction.MoveAction)
self._list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self._list.customContextMenuRequested.connect(self._context_menu)
self._list.currentRowChanged.connect(self._on_row_changed)
self._list.model().rowsMoved.connect(self._on_rows_moved)
layout.addWidget(self._list)
def load_thumbnails(self, viewer):
"""Charger les miniatures depuis le viewer."""
self._list.clear()
for i in range(viewer.total_pages):
thumb = viewer.get_page_thumbnail(i, 120)
item = QListWidgetItem()
item.setText(f" Page {i + 1}")
item.setData(Qt.ItemDataRole.UserRole, i)
if thumb:
item.setIcon(QIcon(thumb))
self._list.addItem(item)
def select_page(self, index):
"""Selectionner une page sans emettre le signal."""
self._list.blockSignals(True)
self._list.setCurrentRow(index)
self._list.blockSignals(False)
def _on_row_changed(self, row):
if row >= 0:
self.page_selected.emit(row)
def _on_rows_moved(self):
indices = []
for i in range(self._list.count()):
item = self._list.item(i)
original_index = item.data(Qt.ItemDataRole.UserRole)
indices.append(original_index)
self.pages_reordered.emit(indices)
def _context_menu(self, pos):
item = self._list.itemAt(pos)
if not item:
return
row = self._list.row(item)
menu = QMenu(self)
menu.setStyleSheet("""
QMenu { background: #fff; color: #2d2d2d; border: 1px solid #d0d0d0; border-radius: 8px; padding: 4px; }
QMenu::item { padding: 6px 20px; border-radius: 4px; }
QMenu::item:selected { background: #e0f4ff; color: #006fa6; }
""")
act_rot_right = menu.addAction("Pivoter +90°")
act_rot_left = menu.addAction("Pivoter -90°")
act_rot_180 = menu.addAction("Pivoter 180°")
menu.addSeparator()
act_insert = menu.addAction("Inserer une page blanche apres")
act_delete = menu.addAction("Supprimer cette page")
action = menu.exec(self._list.mapToGlobal(pos))
if action == act_delete:
self.page_delete_requested.emit(row)
elif action == act_insert:
self.page_insert_requested.emit(row)
elif action == act_rot_right:
self.page_rotate_requested.emit(row, 90)
elif action == act_rot_left:
self.page_rotate_requested.emit(row, -90)
elif action == act_rot_180:
self.page_rotate_requested.emit(row, 180)