Galerie : crayon édition + compteur quantité +/- + bouton Valider

- PhotoCard : miniature + crayon bleu (ouvre éditeur) + boutons -/+
- Quantité par photo, bordure verte quand qty > 0
- Résumé en haut : "X photos sélectionnées — Y impressions"
- Bouton Valider en haut à droite
- Responsive (tailles adaptatives)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 22:16:31 +01:00
parent 622b55bcd1
commit 528e6bdfad

View File

@@ -1,11 +1,185 @@
"""Écran d'import — galerie de photos importées."""
"""Écran d'import — galerie avec édition et quantités."""
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
QLabel, QScrollArea, QGridLayout
QLabel, QScrollArea, QGridLayout, QFrame
)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QFont, QPixmap
from PyQt6.QtCore import Qt, QSize
from PyQt6.QtGui import QFont, QPixmap, QIcon
from ui.style import scale, scaled_font, Sizes, back_btn_style, green_btn
class PhotoCard(QFrame):
"""Carte photo : miniature + crayon édition + compteur quantité."""
def __init__(self, path, main_window, parent=None):
super().__init__(parent)
self.path = path
self.main_window = main_window
self.quantity = 0
self._setup_ui()
def _setup_ui(self):
self.setStyleSheet("""
PhotoCard {
background: white;
border: 2px solid #ddd;
border-radius: 10px;
}
""")
layout = QVBoxLayout(self)
layout.setContentsMargins(5, 5, 5, 5)
layout.setSpacing(4)
# Miniature
self.thumb_label = QLabel()
self.thumb_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.thumb_label.setMinimumSize(150, 120)
pixmap = QPixmap(self.path)
if not pixmap.isNull():
scaled = pixmap.scaled(
200, 150,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation
)
self.thumb_label.setPixmap(scaled)
layout.addWidget(self.thumb_label)
# Barre du bas : crayon + quantité
bar = QHBoxLayout()
bar.setSpacing(4)
# Crayon édition
self.edit_btn = QPushButton("✎")
self.edit_btn.setFixedSize(36, 36)
self.edit_btn.setStyleSheet("""
QPushButton {
background: #2196F3; color: white;
border-radius: 18px; font-size: 18px;
}
QPushButton:pressed { background: #1976D2; }
""")
self.edit_btn.setToolTip("Éditer")
self.edit_btn.clicked.connect(self._edit)
bar.addWidget(self.edit_btn)
bar.addStretch()
# Compteur quantité
self.minus_btn = QPushButton("−")
self.minus_btn.setFixedSize(32, 32)
self.minus_btn.setStyleSheet("""
QPushButton {
background: #eee; color: #333;
border-radius: 16px; font-size: 18px; font-weight: bold;
}
QPushButton:pressed { background: #ccc; }
""")
self.minus_btn.clicked.connect(self._decrement)
bar.addWidget(self.minus_btn)
self.qty_label = QLabel("0")
self.qty_label.setFont(QFont("", 14, QFont.Weight.Bold))
self.qty_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.qty_label.setMinimumWidth(30)
bar.addWidget(self.qty_label)
self.plus_btn = QPushButton("+")
self.plus_btn.setFixedSize(32, 32)
self.plus_btn.setStyleSheet("""
QPushButton {
background: #4CAF50; color: white;
border-radius: 16px; font-size: 18px; font-weight: bold;
}
QPushButton:pressed { background: #388E3C; }
""")
self.plus_btn.clicked.connect(self._increment)
bar.addWidget(self.plus_btn)
layout.addLayout(bar)
def _edit(self):
self.main_window.show_editor(self.path)
def _increment(self):
self.quantity += 1
self._update_qty()
def _decrement(self):
if self.quantity > 0:
self.quantity -= 1
self._update_qty()
def _update_qty(self):
self.qty_label.setText(str(self.quantity))
if self.quantity > 0:
self.setStyleSheet("""
PhotoCard {
background: white;
border: 3px solid #4CAF50;
border-radius: 10px;
}
""")
self.qty_label.setStyleSheet("color: #4CAF50;")
else:
self.setStyleSheet("""
PhotoCard {
background: white;
border: 2px solid #ddd;
border-radius: 10px;
}
""")
self.qty_label.setStyleSheet("color: #333;")
def apply_responsive(self, window_height):
"""Adapte les tailles au responsive."""
thumb_h = max(80, int(window_height * 0.15))
thumb_w = max(100, int(thumb_h * 1.4))
self.thumb_label.setMinimumSize(thumb_w, thumb_h)
# Re-scale la miniature
pixmap = QPixmap(self.path)
if not pixmap.isNull():
scaled = pixmap.scaled(
thumb_w, thumb_h,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation
)
self.thumb_label.setPixmap(scaled)
btn_size = max(28, int(window_height * 0.04))
font_size = max(12, int(window_height * 0.02))
self.edit_btn.setFixedSize(btn_size, btn_size)
self.edit_btn.setStyleSheet(f"""
QPushButton {{
background: #2196F3; color: white;
border-radius: {btn_size//2}px; font-size: {font_size+2}px;
}}
QPushButton:pressed {{ background: #1976D2; }}
""")
self.minus_btn.setFixedSize(btn_size, btn_size)
self.minus_btn.setStyleSheet(f"""
QPushButton {{
background: #eee; color: #333;
border-radius: {btn_size//2}px; font-size: {font_size+2}px; font-weight: bold;
}}
QPushButton:pressed {{ background: #ccc; }}
""")
self.plus_btn.setFixedSize(btn_size, btn_size)
self.plus_btn.setStyleSheet(f"""
QPushButton {{
background: #4CAF50; color: white;
border-radius: {btn_size//2}px; font-size: {font_size+2}px; font-weight: bold;
}}
QPushButton:pressed {{ background: #388E3C; }}
""")
self.qty_label.setFont(QFont("", font_size, QFont.Weight.Bold))
self._update_qty()
class ImportScreen(QWidget):
@@ -13,76 +187,124 @@ class ImportScreen(QWidget):
super().__init__()
self.main_window = main_window
self.photos = []
self.cards = []
self._setup_ui()
def _setup_ui(self):
layout = QVBoxLayout(self)
layout.setContentsMargins(10, 10, 10, 10)
layout.setSpacing(8)
# Header
header = QHBoxLayout()
back_btn = QPushButton("Retour")
back_btn.setFont(QFont("", 14))
back_btn.clicked.connect(self.main_window.show_home)
header.addWidget(back_btn)
title = QLabel("Sélectionnez une photo")
title.setFont(QFont("", 24, QFont.Weight.Bold))
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
header.addWidget(title, 1)
self.back_btn = QPushButton("< Retour")
self.back_btn.clicked.connect(self.main_window.show_home)
header.addWidget(self.back_btn)
self.title = QLabel("Sélectionnez vos photos")
self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
header.addWidget(self.title, 1)
self.validate_btn = QPushButton("Valider")
self.validate_btn.clicked.connect(self._validate)
header.addWidget(self.validate_btn)
header.addSpacing(80) # Balance le bouton retour
layout.addLayout(header)
# Grille de photos (scrollable)
# Résumé sélection
self.summary_label = QLabel("")
self.summary_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.summary_label.setStyleSheet("color: #666;")
layout.addWidget(self.summary_label)
# Grille scrollable
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
scroll.setStyleSheet("QScrollArea { border: none; }")
self.grid_widget = QWidget()
self.grid_layout = QGridLayout(self.grid_widget)
self.grid_layout.setSpacing(10)
self.grid_layout.setSpacing(8)
scroll.setWidget(self.grid_widget)
layout.addWidget(scroll)
layout.addWidget(scroll, 1)
def showEvent(self, event):
super().showEvent(event)
from PyQt6.QtCore import QTimer
QTimer.singleShot(0, self._apply_responsive)
def resizeEvent(self, event):
super().resizeEvent(event)
self._apply_responsive()
def _apply_responsive(self):
h = self.window().height() if self.window() else 768
self.back_btn.setFont(scaled_font(self, Sizes.BUTTON_TEXT, bold=True))
self.back_btn.setMinimumHeight(scale(self, Sizes.BTN_HEIGHT))
self.back_btn.setStyleSheet(back_btn_style(self))
self.title.setFont(scaled_font(self, Sizes.HEADING, bold=True))
self.validate_btn.setFont(scaled_font(self, Sizes.BUTTON_TEXT, bold=True))
self.validate_btn.setMinimumHeight(scale(self, Sizes.BTN_HEIGHT))
self.validate_btn.setStyleSheet(green_btn(self))
self.summary_label.setFont(scaled_font(self, Sizes.HINT))
for card in self.cards:
card.apply_responsive(h)
def set_photos(self, photo_paths):
"""Affiche les photos dans la grille."""
# Clear existing
# Clear
while self.grid_layout.count():
item = self.grid_layout.takeAt(0)
if item.widget():
item.widget().deleteLater()
self.photos = photo_paths
self.cards = []
cols = 4
for i, path in enumerate(photo_paths):
row, col = divmod(i, cols)
thumb = self._create_thumbnail(path)
self.grid_layout.addWidget(thumb, row, col)
card = PhotoCard(path, self.main_window)
card.plus_btn.clicked.connect(self._update_summary)
card.minus_btn.clicked.connect(self._update_summary)
self.grid_layout.addWidget(card, row, col)
self.cards.append(card)
def _create_thumbnail(self, path):
btn = QPushButton()
btn.setMinimumSize(180, 180)
btn.setStyleSheet("""
QPushButton {
border: 3px solid transparent;
border-radius: 10px;
}
QPushButton:pressed {
border-color: #2196F3;
}
""")
pixmap = QPixmap(path)
if not pixmap.isNull():
scaled = pixmap.scaled(
170, 170,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation
self._update_summary()
def _update_summary(self):
total = sum(c.quantity for c in self.cards)
selected = sum(1 for c in self.cards if c.quantity > 0)
if total > 0:
self.summary_label.setText(
f"{selected} photo{'s' if selected > 1 else ''} sélectionnée{'s' if selected > 1 else ''} — {total} impression{'s' if total > 1 else ''}"
)
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import QSize
btn.setIcon(QIcon(scaled))
btn.setIconSize(QSize(170, 170))
self.summary_label.setStyleSheet("color: #4CAF50; font-weight: bold;")
else:
self.summary_label.setText("Appuyez sur + pour sélectionner des photos à imprimer")
self.summary_label.setStyleSheet("color: #999;")
btn.clicked.connect(lambda checked, p=path: self.main_window.show_editor(p))
return btn
def _validate(self):
"""Envoie les photos sélectionnées à l'impression."""
to_print = []
for card in self.cards:
if card.quantity > 0:
to_print.append((card.path, card.quantity))
if not to_print:
return
# TODO: envoyer à l'écran d'impression avec les quantités
# Pour l'instant, on envoie la première photo
self.main_window.show_print(to_print[0][0])
def get_print_list(self):
"""Retourne la liste [(path, quantity), ...] pour l'impression."""
return [(c.path, c.quantity) for c in self.cards if c.quantity > 0]