1 """

2 Z-order operations mixin for pyPhotoAlbum

3 """

4

5 from pyPhotoAlbum.decorators import ribbon_action

6 from pyPhotoAlbum.commands import ChangeZOrderCommand

7

8

9 class ZOrderOperationsMixin:

10 """Mixin providing z-order/layer control operations"""

11

12 @ribbon_action(

13 label="Bring to Front",

14 tooltip="Bring selected element to front",

15 tab="Arrange",

16 group="Order",

17 shortcut="Ctrl+Shift+]",

18 requires_selection=True,

19 )

20 def bring_to_front(self):

21 """Bring selected element to front (end of list)"""

22 if not self.gl_widget.selected_element:

23 return

24

25 current_page = self.get_current_page()

26 if not current_page:

27 return

28

29 element = self.gl_widget.selected_element

30 elements = current_page.layout.elements

31

32 if element not in elements:

33 return

34

35 old_index = elements.index(element)

36 new_index = len(elements) - 1

37

38 if old_index == new_index:

39 self.show_status("Element is already at front", 2000)

40 return

41

42 # Create and execute command

43 cmd = ChangeZOrderCommand(current_page.layout, element, old_index, new_index)

44 self.project.history.execute(cmd)

45

46 self.update_view()

47 self.show_status("Brought element to front (Ctrl+Z to undo)", 2000)

48 print(f"Brought element to front: {old_index} → {new_index}")

49

50 @ribbon_action(

51 label="Send to Back",

52 tooltip="Send selected element to back",

53 tab="Arrange",

54 group="Order",

55 shortcut="Ctrl+Shift+[",

56 requires_selection=True,

57 )

58 def send_to_back(self):

59 """Send selected element to back (start of list)"""

60 if not self.gl_widget.selected_element:

61 return

62

63 current_page = self.get_current_page()

64 if not current_page:

65 return

66

67 element = self.gl_widget.selected_element

68 elements = current_page.layout.elements

69

70 if element not in elements:

71 return

72

73 old_index = elements.index(element)

74 new_index = 0

75

76 if old_index == new_index:

77 self.show_status("Element is already at back", 2000)

78 return

79

80 # Create and execute command

81 cmd = ChangeZOrderCommand(current_page.layout, element, old_index, new_index)

82 self.project.history.execute(cmd)

83

84 self.update_view()

85 self.show_status("Sent element to back (Ctrl+Z to undo)", 2000)

86 print(f"Sent element to back: {old_index} → {new_index}")

87

88 @ribbon_action(

89 label="Bring Forward",

90 tooltip="Bring selected element forward one layer",

91 tab="Arrange",

92 group="Order",

93 shortcut="Ctrl+]",

94 requires_selection=True,

95 )

96 def bring_forward(self):

97 """Move selected element forward one position in list"""

98 if not self.gl_widget.selected_element:

99 return

100

101 current_page = self.get_current_page()

102 if not current_page:

103 return

104

105 element = self.gl_widget.selected_element

106 elements = current_page.layout.elements

107

108 if element not in elements:

109 return

110

111 old_index = elements.index(element)

112 new_index = old_index + 1

113

114 if new_index >= len(elements):

115 self.show_status("Element is already at front", 2000)

116 return

117

118 # Create and execute command

119 cmd = ChangeZOrderCommand(current_page.layout, element, old_index, new_index)

120 self.project.history.execute(cmd)

121

122 self.update_view()

123 self.show_status("Brought element forward (Ctrl+Z to undo)", 2000)

124 print(f"Brought element forward: {old_index} → {new_index}")

125

126 @ribbon_action(

127 label="Send Backward",

128 tooltip="Send selected element backward one layer",

129 tab="Arrange",

130 group="Order",

131 shortcut="Ctrl+[",

132 requires_selection=True,

133 )

134 def send_backward(self):

135 """Move selected element backward one position in list"""

136 if not self.gl_widget.selected_element:

137 return

138

139 current_page = self.get_current_page()

140 if not current_page:

141 return

142

143 element = self.gl_widget.selected_element

144 elements = current_page.layout.elements

145

146 if element not in elements:

147 return

148

149 old_index = elements.index(element)

150 new_index = old_index - 1

151

152 if new_index < 0:

153 self.show_status("Element is already at back", 2000)

154 return

155

156 # Create and execute command

157 cmd = ChangeZOrderCommand(current_page.layout, element, old_index, new_index)

158 self.project.history.execute(cmd)

159

160 self.update_view()

161 self.show_status("Sent element backward (Ctrl+Z to undo)", 2000)

162 print(f"Sent element backward: {old_index} → {new_index}")

163

164 @ribbon_action(

165 label="Swap Order",

166 tooltip="Swap z-order of two selected elements",

167 tab="Arrange",

168 group="Order",

169 shortcut="Ctrl+Shift+X",

170 requires_selection=True,

171 min_selection=2,

172 )

173 def swap_order(self):

174 """Swap the z-order of two selected elements"""

175 if len(self.gl_widget.selected_elements) != 2:

176 self.show_status("Please select exactly 2 elements to swap", 2000)

177 return

178

179 current_page = self.get_current_page()

180 if not current_page:

181 return

182

183 elements = current_page.layout.elements

184 selected = list(self.gl_widget.selected_elements)

185

186 # Get indices of both elements

187 try:

188 index1 = elements.index(selected[0])

189 index2 = elements.index(selected[1])

190 except ValueError:

191 self.show_status("Selected elements not found on current page", 2000)

192 return

193

194 # Swap them in the list

195 elements[index1], elements[index2] = elements[index2], elements[index1]

196

197 self.update_view()

198 self.show_status(f"Swapped z-order of elements", 2000)

199 print(f"Swapped elements at indices {index1} and {index2}")