256 lines
8.3 KiB
Python
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}")
|