All checks were successful
Python CI / test (push) Successful in 1m31s
Lint / lint (push) Successful in 1m7s
Tests / test (3.11) (push) Successful in 1m43s
Tests / test (3.12) (push) Successful in 1m44s
Tests / test (3.13) (push) Successful in 1m38s
Tests / test (3.14) (push) Successful in 1m17s
145 lines
4.8 KiB
Python
145 lines
4.8 KiB
Python
"""
|
|
Edit operations mixin for pyPhotoAlbum
|
|
"""
|
|
|
|
from pyPhotoAlbum.decorators import ribbon_action
|
|
from pyPhotoAlbum.commands import DeleteElementCommand, RotateElementCommand
|
|
|
|
|
|
class EditOperationsMixin:
|
|
"""Mixin providing edit-related operations"""
|
|
|
|
@ribbon_action(label="Undo", tooltip="Undo last action (Ctrl+Z)", tab="Home", group="Edit", shortcut="Ctrl+Z")
|
|
def undo(self):
|
|
"""Undo last action"""
|
|
if self.project.history.undo():
|
|
self.update_view()
|
|
self.show_status("Undo successful", 2000)
|
|
print("Undo successful")
|
|
else:
|
|
self.show_status("Nothing to undo", 2000)
|
|
print("Nothing to undo")
|
|
|
|
@ribbon_action(
|
|
label="Redo", tooltip="Redo last action (Ctrl+Y or Ctrl+Shift+Z)", tab="Home", group="Edit", shortcut="Ctrl+Y"
|
|
)
|
|
def redo(self):
|
|
"""Redo last action"""
|
|
if self.project.history.redo():
|
|
self.update_view()
|
|
self.show_status("Redo successful", 2000)
|
|
print("Redo successful")
|
|
else:
|
|
self.show_status("Nothing to redo", 2000)
|
|
print("Nothing to redo")
|
|
|
|
@ribbon_action(
|
|
label="Delete",
|
|
tooltip="Delete selected element (Delete key)",
|
|
tab="Home",
|
|
group="Edit",
|
|
shortcut="Delete",
|
|
requires_selection=True,
|
|
)
|
|
def delete_selected_element(self):
|
|
"""Delete the currently selected element"""
|
|
if not self.require_selection(min_count=1):
|
|
return
|
|
|
|
current_page = self.get_current_page()
|
|
if not current_page:
|
|
return
|
|
|
|
# Delete the first selected element (for backward compatibility)
|
|
# In the future, we could delete all selected elements
|
|
selected_element = next(iter(self.gl_widget.selected_elements))
|
|
|
|
try:
|
|
cmd = DeleteElementCommand(current_page.layout, selected_element, asset_manager=self.project.asset_manager)
|
|
self.project.history.execute(cmd)
|
|
|
|
# Clear selection
|
|
self.gl_widget.selected_elements.clear()
|
|
|
|
# Update display
|
|
self.update_view()
|
|
|
|
self.show_status("Element deleted (Ctrl+Z to undo)", 2000)
|
|
print("Deleted selected element")
|
|
|
|
except Exception as e:
|
|
self.show_error("Error", f"Failed to delete element: {str(e)}")
|
|
print(f"Error deleting element: {e}")
|
|
|
|
@ribbon_action(
|
|
label="Rotate Left",
|
|
tooltip="Rotate selected element 90° counter-clockwise",
|
|
tab="Arrange",
|
|
group="Transform",
|
|
requires_selection=True,
|
|
)
|
|
def rotate_left(self):
|
|
"""Rotate selected element 90 degrees counter-clockwise"""
|
|
if not self.require_selection(min_count=1):
|
|
return
|
|
|
|
selected_element = next(iter(self.gl_widget.selected_elements))
|
|
old_rotation = selected_element.rotation
|
|
new_rotation = (old_rotation - 90) % 360
|
|
|
|
cmd = RotateElementCommand(selected_element, old_rotation, new_rotation)
|
|
self.project.history.execute(cmd)
|
|
|
|
self.update_view()
|
|
self.show_status(f"Rotated left (Ctrl+Z to undo)", 2000)
|
|
print(f"Rotated element left: {old_rotation}° → {new_rotation}°")
|
|
|
|
@ribbon_action(
|
|
label="Rotate Right",
|
|
tooltip="Rotate selected element 90° clockwise",
|
|
tab="Arrange",
|
|
group="Transform",
|
|
requires_selection=True,
|
|
)
|
|
def rotate_right(self):
|
|
"""Rotate selected element 90 degrees clockwise"""
|
|
if not self.require_selection(min_count=1):
|
|
return
|
|
|
|
selected_element = next(iter(self.gl_widget.selected_elements))
|
|
old_rotation = selected_element.rotation
|
|
new_rotation = (old_rotation + 90) % 360
|
|
|
|
cmd = RotateElementCommand(selected_element, old_rotation, new_rotation)
|
|
self.project.history.execute(cmd)
|
|
|
|
self.update_view()
|
|
self.show_status(f"Rotated right (Ctrl+Z to undo)", 2000)
|
|
print(f"Rotated element right: {old_rotation}° → {new_rotation}°")
|
|
|
|
@ribbon_action(
|
|
label="Reset Rotation",
|
|
tooltip="Reset selected element rotation to 0°",
|
|
tab="Arrange",
|
|
group="Transform",
|
|
requires_selection=True,
|
|
)
|
|
def reset_rotation(self):
|
|
"""Reset selected element rotation to 0 degrees"""
|
|
if not self.require_selection(min_count=1):
|
|
return
|
|
|
|
selected_element = next(iter(self.gl_widget.selected_elements))
|
|
old_rotation = selected_element.rotation
|
|
|
|
if old_rotation == 0:
|
|
self.show_status("Element already at 0°", 2000)
|
|
return
|
|
|
|
cmd = RotateElementCommand(selected_element, old_rotation, 0)
|
|
self.project.history.execute(cmd)
|
|
|
|
self.update_view()
|
|
self.show_status("Reset rotation to 0° (Ctrl+Z to undo)", 2000)
|
|
print(f"Reset element rotation: {old_rotation}° → 0°")
|