Coverage for pyPhotoAlbum/mixins/operations/zorder_ops.py: 92%

107 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-20 12:55 +0000

1""" 

2Z-order operations mixin for pyPhotoAlbum 

3""" 

4 

5from pyPhotoAlbum.decorators import ribbon_action 

6from pyPhotoAlbum.commands import ChangeZOrderCommand 

7 

8 

9class 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}")