136 lines
4.7 KiB
Python
136 lines
4.7 KiB
Python
"""
|
|
Alignment operations mixin for pyPhotoAlbum
|
|
"""
|
|
|
|
from pyPhotoAlbum.decorators import ribbon_action
|
|
from pyPhotoAlbum.alignment import AlignmentManager
|
|
from pyPhotoAlbum.commands import AlignElementsCommand, ResizeElementsCommand
|
|
|
|
|
|
class AlignmentOperationsMixin:
|
|
"""Mixin providing element alignment operations"""
|
|
|
|
def _get_selected_elements_list(self):
|
|
"""Get list of selected elements for alignment operations"""
|
|
return list(self.gl_widget.selected_elements) if self.gl_widget.selected_elements else []
|
|
|
|
def _execute_alignment(self, alignment_func, status_msg: str):
|
|
"""
|
|
Execute an alignment operation with common boilerplate.
|
|
|
|
Args:
|
|
alignment_func: AlignmentManager method to call with elements
|
|
status_msg: Status message format string (will receive element count)
|
|
"""
|
|
elements = self._get_selected_elements_list()
|
|
if not self.require_selection(min_count=2): # type: ignore[attr-defined]
|
|
return
|
|
|
|
changes = alignment_func(elements)
|
|
if changes:
|
|
cmd = AlignElementsCommand(changes)
|
|
self.project.history.execute(cmd) # type: ignore[attr-defined]
|
|
self.update_view() # type: ignore[attr-defined]
|
|
self.show_status(status_msg.format(len(elements)), 2000) # type: ignore[attr-defined]
|
|
|
|
@ribbon_action(
|
|
label="Align Left",
|
|
tooltip="Align selected elements to the left",
|
|
tab="Arrange",
|
|
group="Align",
|
|
requires_selection=True,
|
|
min_selection=2,
|
|
)
|
|
def align_left(self):
|
|
"""Align selected elements to the left"""
|
|
self._execute_alignment(AlignmentManager.align_left, "Aligned {} elements to left")
|
|
|
|
@ribbon_action(
|
|
label="Align Right",
|
|
tooltip="Align selected elements to the right",
|
|
tab="Arrange",
|
|
group="Align",
|
|
requires_selection=True,
|
|
min_selection=2,
|
|
)
|
|
def align_right(self):
|
|
"""Align selected elements to the right"""
|
|
self._execute_alignment(AlignmentManager.align_right, "Aligned {} elements to right")
|
|
|
|
@ribbon_action(
|
|
label="Align Top",
|
|
tooltip="Align selected elements to the top",
|
|
tab="Arrange",
|
|
group="Align",
|
|
requires_selection=True,
|
|
min_selection=2,
|
|
)
|
|
def align_top(self):
|
|
"""Align selected elements to the top"""
|
|
self._execute_alignment(AlignmentManager.align_top, "Aligned {} elements to top")
|
|
|
|
@ribbon_action(
|
|
label="Align Bottom",
|
|
tooltip="Align selected elements to the bottom",
|
|
tab="Arrange",
|
|
group="Align",
|
|
requires_selection=True,
|
|
min_selection=2,
|
|
)
|
|
def align_bottom(self):
|
|
"""Align selected elements to the bottom"""
|
|
self._execute_alignment(AlignmentManager.align_bottom, "Aligned {} elements to bottom")
|
|
|
|
@ribbon_action(
|
|
label="Align H-Center",
|
|
tooltip="Align selected elements to horizontal center",
|
|
tab="Arrange",
|
|
group="Align",
|
|
requires_selection=True,
|
|
min_selection=2,
|
|
)
|
|
def align_horizontal_center(self):
|
|
"""Align selected elements to horizontal center"""
|
|
self._execute_alignment(AlignmentManager.align_horizontal_center, "Aligned {} elements to horizontal center")
|
|
|
|
@ribbon_action(
|
|
label="Align V-Center",
|
|
tooltip="Align selected elements to vertical center",
|
|
tab="Arrange",
|
|
group="Align",
|
|
requires_selection=True,
|
|
min_selection=2,
|
|
)
|
|
def align_vertical_center(self):
|
|
"""Align selected elements to vertical center"""
|
|
self._execute_alignment(AlignmentManager.align_vertical_center, "Aligned {} elements to vertical center")
|
|
|
|
@ribbon_action(
|
|
label="Maximize Pattern",
|
|
tooltip="Maximize selected elements using crystal growth algorithm",
|
|
tab="Arrange",
|
|
group="Size",
|
|
requires_selection=True,
|
|
min_selection=1,
|
|
)
|
|
def maximize_pattern(self):
|
|
"""Maximize selected elements until they are close to borders or each other"""
|
|
elements = self._get_selected_elements_list()
|
|
if not self.require_selection(min_count=1):
|
|
return
|
|
|
|
# Get page size from current page
|
|
page = self.get_current_page()
|
|
if not page:
|
|
self.show_warning("No Page", "Please create a page first.")
|
|
return
|
|
|
|
page_size = page.layout.size
|
|
|
|
changes = AlignmentManager.maximize_pattern(elements, page_size)
|
|
if changes:
|
|
cmd = ResizeElementsCommand(changes)
|
|
self.project.history.execute(cmd)
|
|
self.update_view()
|
|
self.show_status(f"Maximized {len(elements)} element(s) using pattern growth", 2000)
|