Init projet Photostation - borne impression photo tactile PyQt6
Structure : 4 écrans (accueil, import, éditeur, impression), navigation QStackedWidget, base éditeur QGraphicsScene. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
144
src/ui/screens/editor_screen.py
Normal file
144
src/ui/screens/editor_screen.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""Écran éditeur — recadrage, goodies, effets, multi-pose."""
|
||||
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QLabel, QGraphicsScene, QGraphicsView, QGraphicsPixmapItem,
|
||||
QToolBar
|
||||
)
|
||||
from PyQt6.QtCore import Qt, QRectF
|
||||
from PyQt6.QtGui import QFont, QPixmap, QImage, QPainter
|
||||
|
||||
|
||||
class EditorScreen(QWidget):
|
||||
def __init__(self, main_window):
|
||||
super().__init__()
|
||||
self.main_window = main_window
|
||||
self.current_image_path = None
|
||||
self.pixmap_item = None
|
||||
self._setup_ui()
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setSpacing(10)
|
||||
|
||||
# Header
|
||||
header = QHBoxLayout()
|
||||
back_btn = QPushButton("Retour")
|
||||
back_btn.setFont(QFont("", 14))
|
||||
back_btn.clicked.connect(self.main_window.show_import)
|
||||
header.addWidget(back_btn)
|
||||
|
||||
title = QLabel("Éditeur")
|
||||
title.setFont(QFont("", 24, QFont.Weight.Bold))
|
||||
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
header.addWidget(title, 1)
|
||||
|
||||
print_btn = QPushButton("Imprimer")
|
||||
print_btn.setFont(QFont("", 14))
|
||||
print_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
QPushButton:pressed { background-color: #388E3C; }
|
||||
""")
|
||||
print_btn.clicked.connect(self._go_print)
|
||||
header.addWidget(print_btn)
|
||||
layout.addLayout(header)
|
||||
|
||||
# Zone d'édition (QGraphicsScene)
|
||||
self.scene = QGraphicsScene()
|
||||
self.view = QGraphicsView(self.scene)
|
||||
self.view.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||
self.view.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
|
||||
self.view.setDragMode(QGraphicsView.DragMode.ScrollHandDrag)
|
||||
self.view.setStyleSheet("background-color: #333;")
|
||||
layout.addWidget(self.view, 1)
|
||||
|
||||
# Barre d'outils
|
||||
tools = QHBoxLayout()
|
||||
tools.setSpacing(10)
|
||||
|
||||
tool_buttons = [
|
||||
("Recadrer", self._crop),
|
||||
("Rotation", self._rotate),
|
||||
("N&B", self._filter_grayscale),
|
||||
("Sépia", self._filter_sepia),
|
||||
("Goodies", self._add_goodies),
|
||||
("Multi-pose", self._multipose),
|
||||
("Texte", self._add_text),
|
||||
]
|
||||
|
||||
for label, callback in tool_buttons:
|
||||
btn = QPushButton(label)
|
||||
btn.setFont(QFont("", 13))
|
||||
btn.setMinimumHeight(50)
|
||||
btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #555;
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
padding: 8px 15px;
|
||||
}
|
||||
QPushButton:pressed { background-color: #777; }
|
||||
""")
|
||||
btn.clicked.connect(callback)
|
||||
tools.addWidget(btn)
|
||||
|
||||
layout.addLayout(tools)
|
||||
|
||||
def load_image(self, path):
|
||||
self.current_image_path = path
|
||||
self.scene.clear()
|
||||
pixmap = QPixmap(path)
|
||||
self.pixmap_item = self.scene.addPixmap(pixmap)
|
||||
self.view.fitInView(self.pixmap_item, Qt.AspectRatioMode.KeepAspectRatio)
|
||||
|
||||
def _go_print(self):
|
||||
# TODO: exporter le canvas édité en image
|
||||
self.main_window.show_print(self.current_image_path)
|
||||
|
||||
def _crop(self):
|
||||
# TODO: outil de recadrage interactif
|
||||
pass
|
||||
|
||||
def _rotate(self):
|
||||
if self.pixmap_item:
|
||||
self.pixmap_item.setRotation(self.pixmap_item.rotation() + 90)
|
||||
|
||||
def _filter_grayscale(self):
|
||||
if not self.current_image_path:
|
||||
return
|
||||
pixmap = QPixmap(self.current_image_path)
|
||||
image = pixmap.toImage().convertToFormat(QImage.Format.Format_Grayscale8)
|
||||
self.scene.clear()
|
||||
self.pixmap_item = self.scene.addPixmap(QPixmap.fromImage(image))
|
||||
self.view.fitInView(self.pixmap_item, Qt.AspectRatioMode.KeepAspectRatio)
|
||||
|
||||
def _filter_sepia(self):
|
||||
if not self.current_image_path:
|
||||
return
|
||||
from PIL import Image, ImageOps
|
||||
img = Image.open(self.current_image_path)
|
||||
sepia = ImageOps.grayscale(img)
|
||||
sepia = ImageOps.colorize(sepia, "#704214", "#C0A080")
|
||||
# Convertir PIL -> QPixmap
|
||||
data = sepia.convert("RGBA").tobytes("raw", "RGBA")
|
||||
qimg = QImage(data, sepia.width, sepia.height, QImage.Format.Format_RGBA8888)
|
||||
self.scene.clear()
|
||||
self.pixmap_item = self.scene.addPixmap(QPixmap.fromImage(qimg))
|
||||
self.view.fitInView(self.pixmap_item, Qt.AspectRatioMode.KeepAspectRatio)
|
||||
|
||||
def _add_goodies(self):
|
||||
# TODO: panneau de sélection de stickers
|
||||
pass
|
||||
|
||||
def _multipose(self):
|
||||
# TODO: sélection de templates multi-photos
|
||||
pass
|
||||
|
||||
def _add_text(self):
|
||||
# TODO: ajout de texte éditable sur le canvas
|
||||
pass
|
||||
Reference in New Issue
Block a user