1 """

2 Edit operations mixin for pyPhotoAlbum

3 """

4

5 from pyPhotoAlbum.decorators import ribbon_action

6 from pyPhotoAlbum.commands import DeleteElementCommand, RotateElementCommand

7

8

9 class EditOperationsMixin:

10 """Mixin providing edit-related operations"""

11

12 @ribbon_action(label="Undo", tooltip="Undo last action (Ctrl+Z)", tab="Home", group="Edit", shortcut="Ctrl+Z")

13 def undo(self):

14 """Undo last action"""

15 if self.project.history.undo():

16 self.update_view()

17 self.show_status("Undo successful", 2000)

18 print("Undo successful")

19 else:

20 self.show_status("Nothing to undo", 2000)

21 print("Nothing to undo")

22

23 @ribbon_action(

24 label="Redo", tooltip="Redo last action (Ctrl+Y or Ctrl+Shift+Z)", tab="Home", group="Edit", shortcut="Ctrl+Y"

25 )

26 def redo(self):

27 """Redo last action"""

28 if self.project.history.redo():

29 self.update_view()

30 self.show_status("Redo successful", 2000)

31 print("Redo successful")

32 else:

33 self.show_status("Nothing to redo", 2000)

34 print("Nothing to redo")

35

36 @ribbon_action(

37 label="Delete",

38 tooltip="Delete selected element (Delete key)",

39 tab="Home",

40 group="Edit",

41 shortcut="Delete",

42 requires_selection=True,

43 )

44 def delete_selected_element(self):

45 """Delete the currently selected element"""

46 if not self.require_selection(min_count=1):

47 return

48

49 current_page = self.get_current_page()

50 if not current_page:

51 return

52

53 # Delete the first selected element (for backward compatibility)

54 # In the future, we could delete all selected elements

55 selected_element = next(iter(self.gl_widget.selected_elements))

56

57 try:

58 cmd = DeleteElementCommand(current_page.layout, selected_element, asset_manager=self.project.asset_manager)

59 self.project.history.execute(cmd)

60

61 # Clear selection

62 self.gl_widget.selected_elements.clear()

63

64 # Update display

65 self.update_view()

66

67 self.show_status("Element deleted (Ctrl+Z to undo)", 2000)

68 print("Deleted selected element")

69

70 except Exception as e:

71 self.show_error("Error", f"Failed to delete element: {str(e)}")

72 print(f"Error deleting element: {e}")

73

74 @ribbon_action(

75 label="Rotate Left",

76 tooltip="Rotate selected element 90° counter-clockwise",

77 tab="Arrange",

78 group="Transform",

79 requires_selection=True,

80 )

81 def rotate_left(self):

82 """Rotate selected element 90 degrees counter-clockwise"""

83 if not self.require_selection(min_count=1):

84 return

85

86 selected_element = next(iter(self.gl_widget.selected_elements))

87 old_rotation = selected_element.rotation

88 new_rotation = (old_rotation - 90) % 360

89

90 cmd = RotateElementCommand(selected_element, old_rotation, new_rotation)

91 self.project.history.execute(cmd)

92

93 self.update_view()

94 self.show_status(f"Rotated left (Ctrl+Z to undo)", 2000)

95 print(f"Rotated element left: {old_rotation}° → {new_rotation}°")

96

97 @ribbon_action(

98 label="Rotate Right",

99 tooltip="Rotate selected element 90° clockwise",

100 tab="Arrange",

101 group="Transform",

102 requires_selection=True,

103 )

104 def rotate_right(self):

105 """Rotate selected element 90 degrees clockwise"""

106 if not self.require_selection(min_count=1):

107 return

108

109 selected_element = next(iter(self.gl_widget.selected_elements))

110 old_rotation = selected_element.rotation

111 new_rotation = (old_rotation + 90) % 360

112

113 cmd = RotateElementCommand(selected_element, old_rotation, new_rotation)

114 self.project.history.execute(cmd)

115

116 self.update_view()

117 self.show_status(f"Rotated right (Ctrl+Z to undo)", 2000)

118 print(f"Rotated element right: {old_rotation}° → {new_rotation}°")

119

120 @ribbon_action(

121 label="Reset Rotation",

122 tooltip="Reset selected element rotation to 0°",

123 tab="Arrange",

124 group="Transform",

125 requires_selection=True,

126 )

127 def reset_rotation(self):

128 """Reset selected element rotation to 0 degrees"""

129 if not self.require_selection(min_count=1):

130 return

131

132 selected_element = next(iter(self.gl_widget.selected_elements))

133 old_rotation = selected_element.rotation

134

135 if old_rotation == 0:

136 self.show_status("Element already at 0°", 2000)

137 return

138

139 cmd = RotateElementCommand(selected_element, old_rotation, 0)

140 self.project.history.execute(cmd)

141

142 self.update_view()

143 self.show_status("Reset rotation to 0° (Ctrl+Z to undo)", 2000)

144 print(f"Reset element rotation: {old_rotation}° → 0°")