Fix runner and fox issue where text editor did not open
Some checks failed
Python CI / test (push) Successful in 34s
Lint / lint (push) Successful in 1m3s
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.9) (push) Has been cancelled
Tests / test (3.10) (push) Has been cancelled

This commit is contained in:
Duncan Tourolle 2025-10-24 23:40:04 +02:00
parent ea4e653e66
commit 8a9a2a73f4
3 changed files with 199 additions and 10 deletions

View File

@ -356,15 +356,18 @@ class GLWidget(QOpenGLWidget):
# No rotation - draw normally # No rotation - draw normally
rect = QRectF(screen_x, screen_y, screen_w, screen_h) rect = QRectF(screen_x, screen_y, screen_w, screen_h)
# Set text alignment # Set text alignment with proper support for multiline text
alignment = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter alignment = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop
if element.alignment == 'center': if element.alignment == 'center':
alignment = Qt.AlignmentFlag.AlignCenter | Qt.AlignmentFlag.AlignVCenter alignment = Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignTop
elif element.alignment == 'right': elif element.alignment == 'right':
alignment = Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter alignment = Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop
# Draw the text # Enable word wrapping for multiline text support
painter.drawText(rect, alignment, element.text_content) text_flags = Qt.TextFlag.TextWordWrap
# Draw the text with wrapping enabled
painter.drawText(rect, int(alignment | text_flags), element.text_content)
# Restore painter state if we rotated # Restore painter state if we rotated
if element.rotation != 0: if element.rotation != 0:
@ -373,6 +376,40 @@ class GLWidget(QOpenGLWidget):
finally: finally:
painter.end() painter.end()
def mouseDoubleClickEvent(self, event):
"""Handle mouse double-click events"""
if event.button() == Qt.MouseButton.LeftButton:
x, y = event.position().x(), event.position().y()
element = self._get_element_at(x, y)
# Check if double-clicked on a TextBoxData element
from pyPhotoAlbum.models import TextBoxData
if isinstance(element, TextBoxData):
self._edit_text_element(element)
return
# Call parent implementation for default behavior
super().mouseDoubleClickEvent(event)
def _edit_text_element(self, text_element):
"""Open dialog to edit text element"""
from pyPhotoAlbum.text_edit_dialog import TextEditDialog
dialog = TextEditDialog(text_element, self)
if dialog.exec() == TextEditDialog.DialogCode.Accepted:
# Get new values
values = dialog.get_values()
# Update text element
text_element.text_content = values['text_content']
text_element.font_settings = values['font_settings']
text_element.alignment = values['alignment']
# Update view
self.update()
print(f"Updated text element: {values['text_content'][:50]}...")
def mousePressEvent(self, event): def mousePressEvent(self, event):
"""Handle mouse press events""" """Handle mouse press events"""
if event.button() == Qt.MouseButton.LeftButton: if event.button() == Qt.MouseButton.LeftButton:

View File

@ -9,6 +9,7 @@ from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader from reportlab.lib.utils import ImageReader
from PIL import Image from PIL import Image
import math import math
from pyPhotoAlbum.models import ImageData, TextBoxData, PlaceholderData
class PDFExporter: class PDFExporter:
@ -172,8 +173,6 @@ class PDFExporter:
page_height_pt: Page height in points page_height_pt: Page height in points
page_number: Current page number (for error messages) page_number: Current page number (for error messages)
""" """
from pyPhotoAlbum.models import ImageData, TextBoxData, PlaceholderData
# Skip placeholders # Skip placeholders
if isinstance(element, PlaceholderData): if isinstance(element, PlaceholderData):
return return
@ -219,8 +218,6 @@ class PDFExporter:
page_number: Current page number page_number: Current page number
side: 'left' or 'right' side: 'left' or 'right'
""" """
from pyPhotoAlbum.models import ImageData, TextBoxData, PlaceholderData
# Skip placeholders # Skip placeholders
if isinstance(element, PlaceholderData): if isinstance(element, PlaceholderData):
return return

View File

@ -0,0 +1,155 @@
"""
Text editing dialog for pyPhotoAlbum
"""
from PyQt6.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QPushButton,
QTextEdit, QLabel, QComboBox, QSpinBox, QColorDialog
)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QFont, QColor
class TextEditDialog(QDialog):
"""Dialog for editing text box content and properties"""
def __init__(self, text_element, parent=None):
super().__init__(parent)
self.text_element = text_element
self.setWindowTitle("Edit Text")
self.resize(500, 400)
# Create UI
self._init_ui()
# Load current values
self._load_values()
def _init_ui(self):
"""Initialize the user interface"""
layout = QVBoxLayout()
# Text editor
text_label = QLabel("Text:")
self.text_edit = QTextEdit()
self.text_edit.setAcceptRichText(False) # Plain text only
layout.addWidget(text_label)
layout.addWidget(self.text_edit)
# Font settings
font_layout = QHBoxLayout()
# Font family
font_layout.addWidget(QLabel("Font:"))
self.font_combo = QComboBox()
self.font_combo.addItems([
"Arial", "Times New Roman", "Courier New",
"Helvetica", "Verdana", "Georgia", "Comic Sans MS"
])
font_layout.addWidget(self.font_combo)
# Font size
font_layout.addWidget(QLabel("Size:"))
self.font_size_spin = QSpinBox()
self.font_size_spin.setRange(6, 72)
self.font_size_spin.setValue(12)
font_layout.addWidget(self.font_size_spin)
# Text color
self.color_button = QPushButton("Color")
self.color_button.clicked.connect(self._choose_color)
self.current_color = QColor(0, 0, 0) # Default black
font_layout.addWidget(self.color_button)
font_layout.addStretch()
layout.addLayout(font_layout)
# Alignment
alignment_layout = QHBoxLayout()
alignment_layout.addWidget(QLabel("Alignment:"))
self.alignment_combo = QComboBox()
self.alignment_combo.addItems(["left", "center", "right"])
alignment_layout.addWidget(self.alignment_combo)
alignment_layout.addStretch()
layout.addLayout(alignment_layout)
# Buttons
button_layout = QHBoxLayout()
button_layout.addStretch()
cancel_button = QPushButton("Cancel")
cancel_button.clicked.connect(self.reject)
button_layout.addWidget(cancel_button)
ok_button = QPushButton("OK")
ok_button.clicked.connect(self.accept)
ok_button.setDefault(True)
button_layout.addWidget(ok_button)
layout.addLayout(button_layout)
self.setLayout(layout)
def _load_values(self):
"""Load current values from text element"""
# Load text content
self.text_edit.setPlainText(self.text_element.text_content)
# Load font settings
font_family = self.text_element.font_settings.get('family', 'Arial')
index = self.font_combo.findText(font_family)
if index >= 0:
self.font_combo.setCurrentIndex(index)
font_size = self.text_element.font_settings.get('size', 12)
self.font_size_spin.setValue(int(font_size))
# Load color
color = self.text_element.font_settings.get('color', (0, 0, 0))
if all(isinstance(c, int) and c > 1 for c in color):
# Color in 0-255 range
self.current_color = QColor(*color)
else:
# Color in 0-1 range
self.current_color = QColor(
int(color[0] * 255),
int(color[1] * 255),
int(color[2] * 255)
)
self._update_color_button()
# Load alignment
alignment = self.text_element.alignment
index = self.alignment_combo.findText(alignment)
if index >= 0:
self.alignment_combo.setCurrentIndex(index)
def _choose_color(self):
"""Open color picker dialog"""
color = QColorDialog.getColor(self.current_color, self, "Choose Text Color")
if color.isValid():
self.current_color = color
self._update_color_button()
def _update_color_button(self):
"""Update color button appearance"""
self.color_button.setStyleSheet(
f"background-color: {self.current_color.name()}; "
f"color: {'white' if self.current_color.lightness() < 128 else 'black'};"
)
def get_values(self):
"""Get the edited values"""
return {
'text_content': self.text_edit.toPlainText(),
'font_settings': {
'family': self.font_combo.currentText(),
'size': self.font_size_spin.value(),
'color': (
self.current_color.red(),
self.current_color.green(),
self.current_color.blue()
)
},
'alignment': self.alignment_combo.currentText()
}