Initial commit — Copydev Imposing Tool
Outil d'imposition PDF desktop (PyQt6) remplacant Quite Imposing Plus. 9 fonctions : livret, n-up, step & repeat, imposition manuelle, jointure pages, pages blanches, numerotation, masquage, fonds perdus. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
0
app/dialogs/__init__.py
Normal file
0
app/dialogs/__init__.py
Normal file
53
app/dialogs/bleeds_dialog.py
Normal file
53
app/dialogs/bleeds_dialog.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""Dialogue Definition des fonds perdus."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QGroupBox, QDoubleSpinBox, QDialogButtonBox)
|
||||
|
||||
|
||||
class BleedsDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Fonds perdus (Bleeds)")
|
||||
self.setMinimumWidth(350)
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
layout.addWidget(QLabel(
|
||||
"Definir la zone de fond perdu autour de chaque page.\n"
|
||||
"Cette zone sera prise en compte par les fonctions N-Up et Repetition."
|
||||
))
|
||||
|
||||
grp = QGroupBox("Fonds perdus (mm)")
|
||||
gl = QVBoxLayout(grp)
|
||||
|
||||
self.spins = {}
|
||||
for label in ["Haut", "Bas", "Gauche", "Droite"]:
|
||||
hl = QHBoxLayout()
|
||||
hl.addWidget(QLabel(f"{label} :"))
|
||||
spin = QDoubleSpinBox()
|
||||
spin.setRange(0, 50)
|
||||
spin.setValue(3)
|
||||
spin.setSuffix(" mm")
|
||||
hl.addWidget(spin)
|
||||
hl.addStretch()
|
||||
gl.addLayout(hl)
|
||||
self.spins[label.lower()] = spin
|
||||
|
||||
layout.addWidget(grp)
|
||||
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def get_settings(self):
|
||||
return {
|
||||
"bleed_top": self.spins["haut"].value(),
|
||||
"bleed_bottom": self.spins["bas"].value(),
|
||||
"bleed_left": self.spins["gauche"].value(),
|
||||
"bleed_right": self.spins["droite"].value(),
|
||||
}
|
||||
104
app/dialogs/booklet_dialog.py
Normal file
104
app/dialogs/booklet_dialog.py
Normal file
@@ -0,0 +1,104 @@
|
||||
"""Dialogue Creer un livret."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QComboBox, QGroupBox, QRadioButton, QSpinBox,
|
||||
QDialogButtonBox, QDoubleSpinBox)
|
||||
from app.engine.pdf_utils import PAGE_SIZES
|
||||
|
||||
|
||||
class BookletDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Creer un livret")
|
||||
self.setMinimumWidth(400)
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Type de reliure
|
||||
grp_binding = QGroupBox("Type de reliure")
|
||||
bl = QVBoxLayout(grp_binding)
|
||||
self.rb_saddle = QRadioButton("Piqure a cheval (livret agrafe)")
|
||||
self.rb_saddle.setChecked(True)
|
||||
self.rb_perfect = QRadioButton("Dos carre colle (livre)")
|
||||
self.rb_continuous = QRadioButton("Continu (pages sequentielles)")
|
||||
self.rb_cut_stacks = QRadioButton("Cut stacks (couper et empiler)")
|
||||
bl.addWidget(self.rb_saddle)
|
||||
bl.addWidget(self.rb_perfect)
|
||||
bl.addWidget(self.rb_continuous)
|
||||
bl.addWidget(self.rb_cut_stacks)
|
||||
layout.addWidget(grp_binding)
|
||||
|
||||
# Taille signature (perfect bound)
|
||||
sig_layout = QHBoxLayout()
|
||||
sig_layout.addWidget(QLabel("Pages par cahier :"))
|
||||
self.spin_signature = QSpinBox()
|
||||
self.spin_signature.setRange(4, 128)
|
||||
self.spin_signature.setValue(32)
|
||||
self.spin_signature.setSingleStep(4)
|
||||
self.spin_signature.setEnabled(False)
|
||||
sig_layout.addWidget(self.spin_signature)
|
||||
sig_layout.addStretch()
|
||||
layout.addLayout(sig_layout)
|
||||
|
||||
self.rb_perfect.toggled.connect(self.spin_signature.setEnabled)
|
||||
|
||||
# Taille de feuille
|
||||
grp_sheet = QGroupBox("Taille de la feuille")
|
||||
sl = QHBoxLayout(grp_sheet)
|
||||
sl.addWidget(QLabel("Format :"))
|
||||
self.combo_sheet = QComboBox()
|
||||
self.combo_sheet.addItem("Automatique (2x page)")
|
||||
for name in PAGE_SIZES:
|
||||
self.combo_sheet.addItem(name)
|
||||
sl.addWidget(self.combo_sheet)
|
||||
layout.addWidget(grp_sheet)
|
||||
|
||||
# Alignement
|
||||
grp_align = QGroupBox("Alignement")
|
||||
al = QVBoxLayout(grp_align)
|
||||
self.rb_center = QRadioButton("Centrer")
|
||||
self.rb_center.setChecked(True)
|
||||
self.rb_pull = QRadioButton("Vers le dos (centre)")
|
||||
self.rb_bl = QRadioButton("Bas-gauche")
|
||||
al.addWidget(self.rb_center)
|
||||
al.addWidget(self.rb_pull)
|
||||
al.addWidget(self.rb_bl)
|
||||
layout.addWidget(grp_align)
|
||||
|
||||
# Boutons OK/Annuler
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def get_settings(self):
|
||||
"""Retourner les parametres selectionnes."""
|
||||
if self.rb_saddle.isChecked():
|
||||
binding = "saddle_stitch"
|
||||
elif self.rb_perfect.isChecked():
|
||||
binding = "perfect_bound"
|
||||
elif self.rb_continuous.isChecked():
|
||||
binding = "continuous"
|
||||
else:
|
||||
binding = "cut_stacks"
|
||||
|
||||
sheet_text = self.combo_sheet.currentText()
|
||||
sheet_size = PAGE_SIZES.get(sheet_text, None)
|
||||
|
||||
if self.rb_center.isChecked():
|
||||
alignment = "center"
|
||||
elif self.rb_pull.isChecked():
|
||||
alignment = "pull_center"
|
||||
else:
|
||||
alignment = "bottom_left"
|
||||
|
||||
return {
|
||||
"binding": binding,
|
||||
"sheet_size": sheet_size,
|
||||
"signature_size": self.spin_signature.value(),
|
||||
"alignment": alignment,
|
||||
}
|
||||
82
app/dialogs/insert_blank_dialog.py
Normal file
82
app/dialogs/insert_blank_dialog.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""Dialogue Inserer des pages blanches."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QGroupBox, QRadioButton, QSpinBox,
|
||||
QDialogButtonBox)
|
||||
|
||||
|
||||
class InsertBlankDialog(QDialog):
|
||||
def __init__(self, total_pages=1, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Inserer des pages blanches")
|
||||
self.setMinimumWidth(400)
|
||||
self._total_pages = total_pages
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
grp = QGroupBox("Mode d'insertion")
|
||||
gl = QVBoxLayout(grp)
|
||||
|
||||
self.rb_after = QRadioButton("Apres la page :")
|
||||
self.rb_after.setChecked(True)
|
||||
after_layout = QHBoxLayout()
|
||||
after_layout.addWidget(self.rb_after)
|
||||
self.spin_pos = QSpinBox()
|
||||
self.spin_pos.setRange(1, self._total_pages)
|
||||
self.spin_pos.setValue(1)
|
||||
after_layout.addWidget(self.spin_pos)
|
||||
after_layout.addStretch()
|
||||
gl.addLayout(after_layout)
|
||||
|
||||
self.rb_before = QRadioButton("Avant la page selectionnee")
|
||||
gl.addWidget(self.rb_before)
|
||||
|
||||
every_layout = QHBoxLayout()
|
||||
self.rb_every = QRadioButton("Toutes les")
|
||||
every_layout.addWidget(self.rb_every)
|
||||
self.spin_every = QSpinBox()
|
||||
self.spin_every.setRange(1, 100)
|
||||
self.spin_every.setValue(2)
|
||||
self.spin_every.setEnabled(False)
|
||||
every_layout.addWidget(self.spin_every)
|
||||
every_layout.addWidget(QLabel("pages"))
|
||||
every_layout.addStretch()
|
||||
gl.addLayout(every_layout)
|
||||
|
||||
pad_layout = QHBoxLayout()
|
||||
self.rb_pad = QRadioButton("Completer au multiple de")
|
||||
pad_layout.addWidget(self.rb_pad)
|
||||
self.spin_multiple = QSpinBox()
|
||||
self.spin_multiple.setRange(2, 32)
|
||||
self.spin_multiple.setValue(4)
|
||||
self.spin_multiple.setEnabled(False)
|
||||
pad_layout.addWidget(self.spin_multiple)
|
||||
pad_layout.addWidget(QLabel("pages"))
|
||||
pad_layout.addStretch()
|
||||
gl.addLayout(pad_layout)
|
||||
|
||||
layout.addWidget(grp)
|
||||
|
||||
# Activer/desactiver les spinbox
|
||||
self.rb_every.toggled.connect(self.spin_every.setEnabled)
|
||||
self.rb_pad.toggled.connect(self.spin_multiple.setEnabled)
|
||||
|
||||
# Boutons
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def get_settings(self):
|
||||
if self.rb_after.isChecked():
|
||||
return {"mode": "after", "position": self.spin_pos.value()}
|
||||
elif self.rb_before.isChecked():
|
||||
return {"mode": "before", "position": self.spin_pos.value()}
|
||||
elif self.rb_every.isChecked():
|
||||
return {"mode": "every_n", "every_n": self.spin_every.value()}
|
||||
else:
|
||||
return {"mode": "pad_to_multiple", "target_multiple": self.spin_multiple.value()}
|
||||
38
app/dialogs/join_pages_dialog.py
Normal file
38
app/dialogs/join_pages_dialog.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""Dialogue Joindre deux pages."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QLabel, QGroupBox,
|
||||
QRadioButton, QDialogButtonBox)
|
||||
|
||||
|
||||
class JoinPagesDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Joindre deux pages")
|
||||
self.setMinimumWidth(300)
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
layout.addWidget(QLabel("Les pages seront jointes par paires (1+2, 3+4, ...)."))
|
||||
|
||||
grp = QGroupBox("Direction")
|
||||
gl = QVBoxLayout(grp)
|
||||
self.rb_horizontal = QRadioButton("Cote a cote (horizontal)")
|
||||
self.rb_horizontal.setChecked(True)
|
||||
self.rb_vertical = QRadioButton("Dessus/dessous (vertical)")
|
||||
gl.addWidget(self.rb_horizontal)
|
||||
gl.addWidget(self.rb_vertical)
|
||||
layout.addWidget(grp)
|
||||
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def get_settings(self):
|
||||
return {
|
||||
"direction": "horizontal" if self.rb_horizontal.isChecked() else "vertical"
|
||||
}
|
||||
122
app/dialogs/manual_impose_dialog.py
Normal file
122
app/dialogs/manual_impose_dialog.py
Normal file
@@ -0,0 +1,122 @@
|
||||
"""Dialogue Imposition manuelle."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QGroupBox, QComboBox, QSpinBox, QDoubleSpinBox,
|
||||
QDialogButtonBox, QPushButton, QListWidget,
|
||||
QCheckBox)
|
||||
from app.engine.pdf_utils import PAGE_SIZES, mm_to_pt
|
||||
|
||||
|
||||
class ManualImposeDialog(QDialog):
|
||||
def __init__(self, total_pages=1, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Imposition manuelle")
|
||||
self.setMinimumWidth(500)
|
||||
self._total_pages = total_pages
|
||||
self._placements = []
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Taille feuille
|
||||
grp_sheet = QGroupBox("Taille de la feuille cible")
|
||||
sl = QHBoxLayout(grp_sheet)
|
||||
sl.addWidget(QLabel("Format :"))
|
||||
self.combo_sheet = QComboBox()
|
||||
for name in PAGE_SIZES:
|
||||
self.combo_sheet.addItem(name)
|
||||
self.combo_sheet.setCurrentText("A3 Paysage")
|
||||
sl.addWidget(self.combo_sheet)
|
||||
layout.addWidget(grp_sheet)
|
||||
|
||||
# Placement
|
||||
grp_place = QGroupBox("Placer une page")
|
||||
pl = QHBoxLayout(grp_place)
|
||||
|
||||
pl.addWidget(QLabel("Page:"))
|
||||
self.spin_page = QSpinBox()
|
||||
self.spin_page.setRange(1, self._total_pages)
|
||||
pl.addWidget(self.spin_page)
|
||||
|
||||
pl.addWidget(QLabel("X:"))
|
||||
self.spin_x = QDoubleSpinBox()
|
||||
self.spin_x.setRange(0, 2000)
|
||||
self.spin_x.setSuffix(" mm")
|
||||
pl.addWidget(self.spin_x)
|
||||
|
||||
pl.addWidget(QLabel("Y:"))
|
||||
self.spin_y = QDoubleSpinBox()
|
||||
self.spin_y.setRange(0, 2000)
|
||||
self.spin_y.setSuffix(" mm")
|
||||
pl.addWidget(self.spin_y)
|
||||
|
||||
pl.addWidget(QLabel("Rot:"))
|
||||
self.combo_rot = QComboBox()
|
||||
self.combo_rot.addItems(["0", "90", "180", "270"])
|
||||
pl.addWidget(self.combo_rot)
|
||||
|
||||
pl.addWidget(QLabel("Ech:"))
|
||||
self.spin_scale = QDoubleSpinBox()
|
||||
self.spin_scale.setRange(0.1, 10.0)
|
||||
self.spin_scale.setValue(1.0)
|
||||
self.spin_scale.setSingleStep(0.1)
|
||||
pl.addWidget(self.spin_scale)
|
||||
|
||||
layout.addWidget(grp_place)
|
||||
|
||||
# Boutons
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_add = QPushButton("Ajouter")
|
||||
btn_add.clicked.connect(self._add_placement)
|
||||
btn_layout.addWidget(btn_add)
|
||||
btn_del = QPushButton("Supprimer")
|
||||
btn_del.clicked.connect(self._del_placement)
|
||||
btn_layout.addWidget(btn_del)
|
||||
btn_layout.addStretch()
|
||||
layout.addLayout(btn_layout)
|
||||
|
||||
# Liste
|
||||
self.list_placements = QListWidget()
|
||||
layout.addWidget(self.list_placements)
|
||||
|
||||
# Crop marks
|
||||
self.chk_crop = QCheckBox("Reperes de coupe")
|
||||
layout.addWidget(self.chk_crop)
|
||||
|
||||
# Boutons OK/Annuler
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def _add_placement(self):
|
||||
p = {
|
||||
"page": self.spin_page.value(),
|
||||
"x": mm_to_pt(self.spin_x.value()),
|
||||
"y": mm_to_pt(self.spin_y.value()),
|
||||
"rotation": int(self.combo_rot.currentText()),
|
||||
"scale": self.spin_scale.value(),
|
||||
}
|
||||
self._placements.append(p)
|
||||
self.list_placements.addItem(
|
||||
f"Page {p['page']} - X={self.spin_x.value():.1f} Y={self.spin_y.value():.1f} mm "
|
||||
f"Rot={self.combo_rot.currentText()} Ech={self.spin_scale.value():.1f}"
|
||||
)
|
||||
|
||||
def _del_placement(self):
|
||||
row = self.list_placements.currentRow()
|
||||
if row >= 0:
|
||||
self.list_placements.takeItem(row)
|
||||
self._placements.pop(row)
|
||||
|
||||
def get_settings(self):
|
||||
sheet_text = self.combo_sheet.currentText()
|
||||
sheet_size = PAGE_SIZES[sheet_text]
|
||||
return {
|
||||
"sheet_size": sheet_size,
|
||||
"placements": self._placements,
|
||||
"crop_marks": self.chk_crop.isChecked(),
|
||||
}
|
||||
112
app/dialogs/masking_dialog.py
Normal file
112
app/dialogs/masking_dialog.py
Normal file
@@ -0,0 +1,112 @@
|
||||
"""Dialogue Masquage (rectangles blancs)."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QGroupBox, QComboBox, QDoubleSpinBox,
|
||||
QDialogButtonBox, QPushButton, QListWidget,
|
||||
QListWidgetItem)
|
||||
from app.engine.pdf_utils import mm_to_pt
|
||||
|
||||
|
||||
class MaskingDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Masquage (ruban blanc)")
|
||||
self.setMinimumWidth(450)
|
||||
self._rectangles = []
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Definition rectangle
|
||||
grp_rect = QGroupBox("Definir un rectangle de masquage (mm)")
|
||||
rl = QHBoxLayout(grp_rect)
|
||||
|
||||
rl.addWidget(QLabel("X:"))
|
||||
self.spin_x = QDoubleSpinBox()
|
||||
self.spin_x.setRange(0, 1000)
|
||||
self.spin_x.setSuffix(" mm")
|
||||
rl.addWidget(self.spin_x)
|
||||
|
||||
rl.addWidget(QLabel("Y:"))
|
||||
self.spin_y = QDoubleSpinBox()
|
||||
self.spin_y.setRange(0, 1000)
|
||||
self.spin_y.setSuffix(" mm")
|
||||
rl.addWidget(self.spin_y)
|
||||
|
||||
rl.addWidget(QLabel("L:"))
|
||||
self.spin_w = QDoubleSpinBox()
|
||||
self.spin_w.setRange(1, 1000)
|
||||
self.spin_w.setValue(50)
|
||||
self.spin_w.setSuffix(" mm")
|
||||
rl.addWidget(self.spin_w)
|
||||
|
||||
rl.addWidget(QLabel("H:"))
|
||||
self.spin_h = QDoubleSpinBox()
|
||||
self.spin_h.setRange(1, 1000)
|
||||
self.spin_h.setValue(10)
|
||||
self.spin_h.setSuffix(" mm")
|
||||
rl.addWidget(self.spin_h)
|
||||
|
||||
layout.addWidget(grp_rect)
|
||||
|
||||
# Boutons ajouter/supprimer
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_add = QPushButton("Ajouter")
|
||||
btn_add.clicked.connect(self._add_rect)
|
||||
btn_layout.addWidget(btn_add)
|
||||
btn_del = QPushButton("Supprimer")
|
||||
btn_del.clicked.connect(self._del_rect)
|
||||
btn_layout.addWidget(btn_del)
|
||||
btn_layout.addStretch()
|
||||
layout.addLayout(btn_layout)
|
||||
|
||||
# Liste des rectangles
|
||||
self.list_rects = QListWidget()
|
||||
layout.addWidget(self.list_rects)
|
||||
|
||||
# Appliquer a
|
||||
grp_apply = QGroupBox("Appliquer a")
|
||||
al = QHBoxLayout(grp_apply)
|
||||
self.combo_apply = QComboBox()
|
||||
self.combo_apply.addItems(["Toutes les pages", "Pages paires", "Pages impaires"])
|
||||
al.addWidget(self.combo_apply)
|
||||
layout.addWidget(grp_apply)
|
||||
|
||||
# Boutons
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def _add_rect(self):
|
||||
rect = {
|
||||
"x": mm_to_pt(self.spin_x.value()),
|
||||
"y": mm_to_pt(self.spin_y.value()),
|
||||
"width": mm_to_pt(self.spin_w.value()),
|
||||
"height": mm_to_pt(self.spin_h.value()),
|
||||
}
|
||||
self._rectangles.append(rect)
|
||||
self.list_rects.addItem(
|
||||
f"X={self.spin_x.value():.1f} Y={self.spin_y.value():.1f} "
|
||||
f"L={self.spin_w.value():.1f} H={self.spin_h.value():.1f} mm"
|
||||
)
|
||||
|
||||
def _del_rect(self):
|
||||
row = self.list_rects.currentRow()
|
||||
if row >= 0:
|
||||
self.list_rects.takeItem(row)
|
||||
self._rectangles.pop(row)
|
||||
|
||||
def get_settings(self):
|
||||
apply_map = {
|
||||
"Toutes les pages": "all",
|
||||
"Pages paires": "even",
|
||||
"Pages impaires": "odd"
|
||||
}
|
||||
return {
|
||||
"rectangles": self._rectangles,
|
||||
"apply_to": apply_map[self.combo_apply.currentText()],
|
||||
}
|
||||
131
app/dialogs/nup_dialog.py
Normal file
131
app/dialogs/nup_dialog.py
Normal file
@@ -0,0 +1,131 @@
|
||||
"""Dialogue N pages par feuille."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QComboBox, QGroupBox, QSpinBox, QCheckBox,
|
||||
QDialogButtonBox, QDoubleSpinBox, QFileDialog)
|
||||
from app.engine.pdf_utils import PAGE_SIZES, mm_to_pt
|
||||
|
||||
|
||||
class NupDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("N pages par feuille")
|
||||
self.setMinimumWidth(450)
|
||||
self._bg_path = None
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Grille
|
||||
grp_grid = QGroupBox("Disposition")
|
||||
gl = QHBoxLayout(grp_grid)
|
||||
gl.addWidget(QLabel("Colonnes :"))
|
||||
self.spin_cols = QSpinBox()
|
||||
self.spin_cols.setRange(1, 10)
|
||||
self.spin_cols.setValue(2)
|
||||
gl.addWidget(self.spin_cols)
|
||||
gl.addWidget(QLabel("Lignes :"))
|
||||
self.spin_rows = QSpinBox()
|
||||
self.spin_rows.setRange(1, 10)
|
||||
self.spin_rows.setValue(2)
|
||||
gl.addWidget(self.spin_rows)
|
||||
layout.addWidget(grp_grid)
|
||||
|
||||
# Taille feuille
|
||||
grp_sheet = QGroupBox("Taille de la feuille")
|
||||
sl = QHBoxLayout(grp_sheet)
|
||||
sl.addWidget(QLabel("Format :"))
|
||||
self.combo_sheet = QComboBox()
|
||||
for name in PAGE_SIZES:
|
||||
self.combo_sheet.addItem(name)
|
||||
self.combo_sheet.setCurrentText("A4 Paysage")
|
||||
sl.addWidget(self.combo_sheet)
|
||||
layout.addWidget(grp_sheet)
|
||||
|
||||
# Marges
|
||||
grp_margins = QGroupBox("Marges (mm)")
|
||||
ml = QHBoxLayout(grp_margins)
|
||||
self.margins = {}
|
||||
for label in ["Haut", "Bas", "Gauche", "Droite"]:
|
||||
ml.addWidget(QLabel(f"{label}:"))
|
||||
spin = QDoubleSpinBox()
|
||||
spin.setRange(0, 100)
|
||||
spin.setValue(5)
|
||||
spin.setSuffix(" mm")
|
||||
ml.addWidget(spin)
|
||||
self.margins[label.lower()] = spin
|
||||
layout.addWidget(grp_margins)
|
||||
|
||||
# Gouttiere
|
||||
grp_gutter = QGroupBox("Gouttiere (mm)")
|
||||
gutl = QHBoxLayout(grp_gutter)
|
||||
gutl.addWidget(QLabel("Horizontale :"))
|
||||
self.spin_gutter_h = QDoubleSpinBox()
|
||||
self.spin_gutter_h.setRange(0, 50)
|
||||
self.spin_gutter_h.setValue(0)
|
||||
self.spin_gutter_h.setSuffix(" mm")
|
||||
gutl.addWidget(self.spin_gutter_h)
|
||||
gutl.addWidget(QLabel("Verticale :"))
|
||||
self.spin_gutter_v = QDoubleSpinBox()
|
||||
self.spin_gutter_v.setRange(0, 50)
|
||||
self.spin_gutter_v.setValue(0)
|
||||
self.spin_gutter_v.setSuffix(" mm")
|
||||
gutl.addWidget(self.spin_gutter_v)
|
||||
layout.addWidget(grp_gutter)
|
||||
|
||||
# Options
|
||||
grp_opts = QGroupBox("Options")
|
||||
ol = QVBoxLayout(grp_opts)
|
||||
self.chk_fit = QCheckBox("Ajuster les pages a la cellule")
|
||||
self.chk_fit.setChecked(True)
|
||||
ol.addWidget(self.chk_fit)
|
||||
self.chk_crop = QCheckBox("Reperes de coupe")
|
||||
ol.addWidget(self.chk_crop)
|
||||
|
||||
bg_layout = QHBoxLayout()
|
||||
self.chk_bg = QCheckBox("Fond PDF :")
|
||||
bg_layout.addWidget(self.chk_bg)
|
||||
self.lbl_bg = QLabel("Aucun")
|
||||
bg_layout.addWidget(self.lbl_bg)
|
||||
from PyQt6.QtWidgets import QPushButton
|
||||
btn_bg = QPushButton("Choisir...")
|
||||
btn_bg.clicked.connect(self._choose_bg)
|
||||
bg_layout.addWidget(btn_bg)
|
||||
bg_layout.addStretch()
|
||||
ol.addLayout(bg_layout)
|
||||
|
||||
layout.addWidget(grp_opts)
|
||||
|
||||
# Boutons
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def _choose_bg(self):
|
||||
path, _ = QFileDialog.getOpenFileName(self, "Choisir un fond PDF", "", "PDF (*.pdf)")
|
||||
if path:
|
||||
self._bg_path = path
|
||||
self.lbl_bg.setText(path.split("/")[-1].split("\\")[-1])
|
||||
self.chk_bg.setChecked(True)
|
||||
|
||||
def get_settings(self):
|
||||
sheet_text = self.combo_sheet.currentText()
|
||||
sheet_size = PAGE_SIZES[sheet_text]
|
||||
return {
|
||||
"cols": self.spin_cols.value(),
|
||||
"rows": self.spin_rows.value(),
|
||||
"sheet_size": sheet_size,
|
||||
"margin_top": mm_to_pt(self.margins["haut"].value()),
|
||||
"margin_bottom": mm_to_pt(self.margins["bas"].value()),
|
||||
"margin_left": mm_to_pt(self.margins["gauche"].value()),
|
||||
"margin_right": mm_to_pt(self.margins["droite"].value()),
|
||||
"gutter_h": mm_to_pt(self.spin_gutter_h.value()),
|
||||
"gutter_v": mm_to_pt(self.spin_gutter_v.value()),
|
||||
"scale_mode": "fit" if self.chk_fit.isChecked() else "none",
|
||||
"crop_marks": self.chk_crop.isChecked(),
|
||||
"background_path": self._bg_path if self.chk_bg.isChecked() else None,
|
||||
}
|
||||
120
app/dialogs/page_numbers_dialog.py
Normal file
120
app/dialogs/page_numbers_dialog.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""Dialogue Numerotation de pages."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QGroupBox, QComboBox, QSpinBox, QLineEdit,
|
||||
QDialogButtonBox, QDoubleSpinBox)
|
||||
from reportlab.lib.units import mm
|
||||
|
||||
|
||||
class PageNumbersDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Numerotation de pages")
|
||||
self.setMinimumWidth(400)
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Position
|
||||
grp_pos = QGroupBox("Position")
|
||||
pl = QHBoxLayout(grp_pos)
|
||||
pl.addWidget(QLabel("Emplacement :"))
|
||||
self.combo_pos = QComboBox()
|
||||
positions = [
|
||||
"haut-gauche", "haut-centre", "haut-droite",
|
||||
"milieu-gauche", "milieu-centre", "milieu-droite",
|
||||
"bas-gauche", "bas-centre", "bas-droite"
|
||||
]
|
||||
self.combo_pos.addItems(positions)
|
||||
self.combo_pos.setCurrentText("bas-centre")
|
||||
pl.addWidget(self.combo_pos)
|
||||
layout.addWidget(grp_pos)
|
||||
|
||||
# Police
|
||||
grp_font = QGroupBox("Police")
|
||||
fl = QHBoxLayout(grp_font)
|
||||
fl.addWidget(QLabel("Police :"))
|
||||
self.combo_font = QComboBox()
|
||||
self.combo_font.addItems(["Helvetica", "Times-Roman", "Courier"])
|
||||
fl.addWidget(self.combo_font)
|
||||
fl.addWidget(QLabel("Taille :"))
|
||||
self.spin_size = QSpinBox()
|
||||
self.spin_size.setRange(4, 72)
|
||||
self.spin_size.setValue(10)
|
||||
fl.addWidget(self.spin_size)
|
||||
layout.addWidget(grp_font)
|
||||
|
||||
# Texte
|
||||
grp_text = QGroupBox("Texte")
|
||||
tl = QHBoxLayout(grp_text)
|
||||
tl.addWidget(QLabel("Prefixe :"))
|
||||
self.edit_prefix = QLineEdit()
|
||||
self.edit_prefix.setPlaceholderText("ex: Page ")
|
||||
tl.addWidget(self.edit_prefix)
|
||||
tl.addWidget(QLabel("Suffixe :"))
|
||||
self.edit_suffix = QLineEdit()
|
||||
self.edit_suffix.setPlaceholderText("ex: / 24")
|
||||
tl.addWidget(self.edit_suffix)
|
||||
layout.addWidget(grp_text)
|
||||
|
||||
# Numero de depart
|
||||
start_layout = QHBoxLayout()
|
||||
start_layout.addWidget(QLabel("Commencer a :"))
|
||||
self.spin_start = QSpinBox()
|
||||
self.spin_start.setRange(0, 9999)
|
||||
self.spin_start.setValue(1)
|
||||
start_layout.addWidget(self.spin_start)
|
||||
start_layout.addStretch()
|
||||
layout.addLayout(start_layout)
|
||||
|
||||
# Marges
|
||||
margin_layout = QHBoxLayout()
|
||||
margin_layout.addWidget(QLabel("Marge X :"))
|
||||
self.spin_mx = QDoubleSpinBox()
|
||||
self.spin_mx.setRange(0, 100)
|
||||
self.spin_mx.setValue(10)
|
||||
self.spin_mx.setSuffix(" mm")
|
||||
margin_layout.addWidget(self.spin_mx)
|
||||
margin_layout.addWidget(QLabel("Marge Y :"))
|
||||
self.spin_my = QDoubleSpinBox()
|
||||
self.spin_my.setRange(0, 100)
|
||||
self.spin_my.setValue(10)
|
||||
self.spin_my.setSuffix(" mm")
|
||||
margin_layout.addWidget(self.spin_my)
|
||||
layout.addLayout(margin_layout)
|
||||
|
||||
# Appliquer a
|
||||
grp_apply = QGroupBox("Appliquer a")
|
||||
al = QHBoxLayout(grp_apply)
|
||||
self.combo_apply = QComboBox()
|
||||
self.combo_apply.addItems(["Toutes les pages", "Pages paires", "Pages impaires"])
|
||||
al.addWidget(self.combo_apply)
|
||||
layout.addWidget(grp_apply)
|
||||
|
||||
# Boutons
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def get_settings(self):
|
||||
apply_map = {
|
||||
"Toutes les pages": "all",
|
||||
"Pages paires": "even",
|
||||
"Pages impaires": "odd"
|
||||
}
|
||||
return {
|
||||
"position": self.combo_pos.currentText(),
|
||||
"font_name": self.combo_font.currentText(),
|
||||
"font_size": self.spin_size.value(),
|
||||
"color": (0, 0, 0),
|
||||
"prefix": self.edit_prefix.text(),
|
||||
"suffix": self.edit_suffix.text(),
|
||||
"start_number": self.spin_start.value(),
|
||||
"margin_x": self.spin_mx.value() * mm,
|
||||
"margin_y": self.spin_my.value() * mm,
|
||||
"apply_to": apply_map[self.combo_apply.currentText()],
|
||||
}
|
||||
95
app/dialogs/step_repeat_dialog.py
Normal file
95
app/dialogs/step_repeat_dialog.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""Dialogue Repetition (Step & Repeat)."""
|
||||
|
||||
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QComboBox, QGroupBox, QSpinBox, QCheckBox,
|
||||
QDialogButtonBox, QDoubleSpinBox)
|
||||
from app.engine.pdf_utils import PAGE_SIZES, mm_to_pt
|
||||
|
||||
|
||||
class StepRepeatDialog(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("Repetition (Step & Repeat)")
|
||||
self.setMinimumWidth(400)
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# Taille feuille
|
||||
grp_sheet = QGroupBox("Taille de la feuille")
|
||||
sl = QHBoxLayout(grp_sheet)
|
||||
sl.addWidget(QLabel("Format :"))
|
||||
self.combo_sheet = QComboBox()
|
||||
for name in PAGE_SIZES:
|
||||
self.combo_sheet.addItem(name)
|
||||
self.combo_sheet.setCurrentText("A3 Paysage")
|
||||
sl.addWidget(self.combo_sheet)
|
||||
layout.addWidget(grp_sheet)
|
||||
|
||||
# Nombre de copies
|
||||
grp_copies = QGroupBox("Nombre de copies")
|
||||
cl = QVBoxLayout(grp_copies)
|
||||
self.chk_auto = QCheckBox("Automatique (remplir la feuille)")
|
||||
self.chk_auto.setChecked(True)
|
||||
cl.addWidget(self.chk_auto)
|
||||
|
||||
manual = QHBoxLayout()
|
||||
manual.addWidget(QLabel("Horizontal :"))
|
||||
self.spin_h = QSpinBox()
|
||||
self.spin_h.setRange(1, 20)
|
||||
self.spin_h.setValue(2)
|
||||
self.spin_h.setEnabled(False)
|
||||
manual.addWidget(self.spin_h)
|
||||
manual.addWidget(QLabel("Vertical :"))
|
||||
self.spin_v = QSpinBox()
|
||||
self.spin_v.setRange(1, 20)
|
||||
self.spin_v.setValue(2)
|
||||
self.spin_v.setEnabled(False)
|
||||
manual.addWidget(self.spin_v)
|
||||
cl.addLayout(manual)
|
||||
layout.addWidget(grp_copies)
|
||||
|
||||
self.chk_auto.toggled.connect(lambda checked: self.spin_h.setEnabled(not checked))
|
||||
self.chk_auto.toggled.connect(lambda checked: self.spin_v.setEnabled(not checked))
|
||||
|
||||
# Espacement
|
||||
grp_spacing = QGroupBox("Espacement (mm)")
|
||||
spl = QHBoxLayout(grp_spacing)
|
||||
spl.addWidget(QLabel("Horizontal :"))
|
||||
self.spin_sp_h = QDoubleSpinBox()
|
||||
self.spin_sp_h.setRange(0, 50)
|
||||
self.spin_sp_h.setValue(0)
|
||||
self.spin_sp_h.setSuffix(" mm")
|
||||
spl.addWidget(self.spin_sp_h)
|
||||
spl.addWidget(QLabel("Vertical :"))
|
||||
self.spin_sp_v = QDoubleSpinBox()
|
||||
self.spin_sp_v.setRange(0, 50)
|
||||
self.spin_sp_v.setValue(0)
|
||||
self.spin_sp_v.setSuffix(" mm")
|
||||
spl.addWidget(self.spin_sp_v)
|
||||
layout.addWidget(grp_spacing)
|
||||
|
||||
# Options
|
||||
self.chk_crop = QCheckBox("Reperes de coupe")
|
||||
layout.addWidget(self.chk_crop)
|
||||
|
||||
# Boutons
|
||||
buttons = QDialogButtonBox(
|
||||
QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
|
||||
)
|
||||
buttons.accepted.connect(self.accept)
|
||||
buttons.rejected.connect(self.reject)
|
||||
layout.addWidget(buttons)
|
||||
|
||||
def get_settings(self):
|
||||
sheet_text = self.combo_sheet.currentText()
|
||||
sheet_size = PAGE_SIZES[sheet_text]
|
||||
return {
|
||||
"sheet_size": sheet_size,
|
||||
"copies_h": None if self.chk_auto.isChecked() else self.spin_h.value(),
|
||||
"copies_v": None if self.chk_auto.isChecked() else self.spin_v.value(),
|
||||
"spacing_h": mm_to_pt(self.spin_sp_h.value()),
|
||||
"spacing_v": mm_to_pt(self.spin_sp_v.value()),
|
||||
"crop_marks": self.chk_crop.isChecked(),
|
||||
}
|
||||
Reference in New Issue
Block a user