Duncan Tourolle 5257c6654a
All checks were successful
Python CI / test (push) Successful in 55s
Lint / lint (push) Successful in 1m4s
Tests / test (3.10) (push) Successful in 42s
Tests / test (3.11) (push) Successful in 45s
Tests / test (3.9) (push) Successful in 41s
Improved undo-redo system
2025-10-28 21:03:30 +01:00

256 lines
8.3 KiB
Python

"""
Template operations mixin for pyPhotoAlbum
"""
from PyQt6.QtWidgets import (
QInputDialog, QDialog, QVBoxLayout, QLabel, QComboBox,
QRadioButton, QButtonGroup, QPushButton, QHBoxLayout
)
from pyPhotoAlbum.decorators import ribbon_action, undoable_operation
class TemplateOperationsMixin:
"""Mixin providing template-related operations"""
@ribbon_action(
label="Save as Template",
tooltip="Save current page as a reusable template",
tab="Layout",
group="Templates",
requires_page=True
)
def save_page_as_template(self):
"""Save current page as a template"""
current_page = self.get_current_page()
if not current_page:
return
# Check if page has any elements
if not current_page.layout.elements:
self.show_warning("Empty Page", "Cannot save an empty page as a template.")
return
# Ask for template name
name, ok = QInputDialog.getText(
self,
"Save Template",
"Enter template name:",
text=f"Template_{len(self.template_manager.list_templates()) + 1}"
)
if not ok or not name:
return
# Ask for optional description
description, ok = QInputDialog.getText(
self,
"Template Description",
"Enter description (optional):"
)
if not ok:
description = ""
try:
# Create template from page
template = self.template_manager.create_template_from_page(
current_page,
name,
description
)
# Save template
self.template_manager.save_template(template)
self.show_info(
"Template Saved",
f"Template '{name}' has been saved successfully."
)
print(f"Saved template: {name}")
except Exception as e:
self.show_error("Error", f"Failed to save template: {str(e)}")
print(f"Error saving template: {e}")
@ribbon_action(
label="New from Template",
tooltip="Create a new page from a template",
tab="Layout",
group="Templates"
)
def new_page_from_template(self):
"""Create a new page from a template"""
# Get available templates
templates = self.template_manager.list_templates()
if not templates:
self.show_info(
"No Templates",
"No templates available. Create a template first by using 'Save as Template'."
)
return
# Ask user to select template
template_name, ok = QInputDialog.getItem(
self,
"Select Template",
"Choose a template:",
templates,
0,
False
)
if not ok:
return
try:
# Load template
template = self.template_manager.load_template(template_name)
# Create new page from template
new_page_number = len(self.project.pages) + 1
new_page = self.template_manager.create_page_from_template(
template,
page_number=new_page_number,
target_size_mm=self.project.page_size_mm
)
# Add to project
self.project.add_page(new_page)
# Switch to new page
self.gl_widget.current_page_index = len(self.project.pages) - 1
self.update_view()
self.show_status(f"Created page {new_page_number} from template '{template_name}'", 3000)
print(f"Created page from template: {template_name}")
except Exception as e:
self.show_error("Error", f"Failed to create page from template: {str(e)}")
print(f"Error creating page from template: {e}")
@ribbon_action(
label="Apply Template",
tooltip="Apply a template layout to current page",
tab="Layout",
group="Templates",
requires_page=True
)
@undoable_operation(capture='page_elements', description='Apply Template')
def apply_template_to_page(self):
"""Apply a template to the current page"""
current_page = self.get_current_page()
if not current_page:
return
# Get available templates
templates = self.template_manager.list_templates()
if not templates:
self.show_info(
"No Templates",
"No templates available. Create a template first by using 'Save as Template'."
)
return
# Create dialog for template application options
dialog = QDialog(self)
dialog.setWindowTitle("Apply Template")
dialog.setMinimumWidth(400)
layout = QVBoxLayout()
# Template selection
layout.addWidget(QLabel("Select Template:"))
template_combo = QComboBox()
template_combo.addItems(templates)
layout.addWidget(template_combo)
layout.addSpacing(10)
# Mode selection
layout.addWidget(QLabel("Mode:"))
mode_group = QButtonGroup(dialog)
replace_radio = QRadioButton("Replace with placeholders")
replace_radio.setChecked(True)
replace_radio.setToolTip("Clear page and add template placeholders")
mode_group.addButton(replace_radio, 0)
layout.addWidget(replace_radio)
reflow_radio = QRadioButton("Reflow existing content")
reflow_radio.setToolTip("Keep existing images and reposition to template slots")
mode_group.addButton(reflow_radio, 1)
layout.addWidget(reflow_radio)
layout.addSpacing(10)
# Scaling selection
layout.addWidget(QLabel("Scaling:"))
scale_group = QButtonGroup(dialog)
proportional_radio = QRadioButton("Proportional (maintain aspect ratio)")
proportional_radio.setChecked(True)
scale_group.addButton(proportional_radio, 0)
layout.addWidget(proportional_radio)
stretch_radio = QRadioButton("Stretch to fit")
scale_group.addButton(stretch_radio, 1)
layout.addWidget(stretch_radio)
center_radio = QRadioButton("Center (no scaling)")
scale_group.addButton(center_radio, 2)
layout.addWidget(center_radio)
layout.addSpacing(20)
# Buttons
button_layout = QHBoxLayout()
cancel_btn = QPushButton("Cancel")
cancel_btn.clicked.connect(dialog.reject)
apply_btn = QPushButton("Apply")
apply_btn.clicked.connect(dialog.accept)
apply_btn.setDefault(True)
button_layout.addStretch()
button_layout.addWidget(cancel_btn)
button_layout.addWidget(apply_btn)
layout.addLayout(button_layout)
dialog.setLayout(layout)
# Show dialog
if dialog.exec() != QDialog.DialogCode.Accepted:
return
# Get selections
template_name = template_combo.currentText()
mode_id = mode_group.checkedId()
scale_id = scale_group.checkedId()
mode = "replace" if mode_id == 0 else "reflow"
scale_mode = ["proportional", "stretch", "center"][scale_id]
try:
# Load template
template = self.template_manager.load_template(template_name)
# Apply template to page
self.template_manager.apply_template_to_page(
template,
current_page,
mode=mode,
scale_mode=scale_mode
)
# Update display
self.update_view()
self.show_status(f"Applied template '{template_name}' to current page", 3000)
print(f"Applied template '{template_name}' with mode={mode}, scale_mode={scale_mode}")
except Exception as e:
self.show_error("Error", f"Failed to apply template: {str(e)}")
print(f"Error applying template: {e}")