"""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.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; 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.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) 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 get_selected_indices(self): """Retourne les indices des pages selectionnees.""" return sorted(set(self._list.row(item) for item in self._list.selectedItems())) def _context_menu(self, pos): item = self._list.itemAt(pos) if not item: return row = self._list.row(item) selected = self.get_selected_indices() if row not in selected: selected = [row] count = len(selected) label_pages = f"{count} page(s)" if count > 1 else "cette page" 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(f"Pivoter +90° ({label_pages})") act_rot_left = menu.addAction(f"Pivoter -90° ({label_pages})") act_rot_180 = menu.addAction(f"Pivoter 180° ({label_pages})") menu.addSeparator() act_insert = menu.addAction("Inserer une page blanche apres") act_delete = menu.addAction(f"Supprimer {label_pages}") action = menu.exec(self._list.mapToGlobal(pos)) if action == act_delete: for idx in reversed(selected): self.page_delete_requested.emit(idx) elif action == act_insert: self.page_insert_requested.emit(row) elif action == act_rot_right: for idx in selected: self.page_rotate_requested.emit(idx, 90) elif action == act_rot_left: for idx in selected: self.page_rotate_requested.emit(idx, -90) elif action == act_rot_180: for idx in selected: self.page_rotate_requested.emit(idx, 180)