1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """
22 Module for undoing and redoing actions in the map editor
23 """
24
25 import copy
26
27
28 __undoList = []
29 __redoList = []
30
31
33 """
34 Don't use this directly. Call the addUndoAction function of MapController.
35 Doing so will update the status of the undo and redo buttons on the window.
36 @type action: UndoAction
37 @param action: the action to add to the undo stack
38 """
39 __undoList.append(action)
40 __redoList = []
41
42
54
55
67
68
70 """
71 @rtype: bool
72 @return: True if there are any actions that can be undone
73 """
74 return len(__undoList) > 0
75
76
78 """
79 @rtype: bool
80 @return: True if there are any actions that can be redone
81 """
82 return len(__redoList) > 0
83
84
86 """
87 @rtype: str
88 @return: a textual description of the next action that can be redone, or
89 None. It's a good idea to call canRedo before this.
90 """
91 if canRedo():
92 return __redoList[-1].getRedoString()
93 else:
94 return None
95
96
98 """
99 @rtype: str
100 @return: a textual description of the next action taht can be redone, or
101 None. It's a good idea to call canUndo before this.
102 """
103 if canUndo():
104 return __undoList[-1].getUndoString()
105 else:
106 return None
107
108
110 """
111 Base class for undo actions
112 """
114 self.__controller = controller
115 self.__description = "REPLACE THIS TEXT"
116
118 return self.__controller
119
121 """
122 Only derived classes should call this
123 @type desc: str
124 @param desc: A description of the action to be taken
125 """
126 self.__description = desc
127
129 """
130 Undo the action
131 """
132 raise NameError("UndoAction.undo is abstract.")
133
135 """
136 Redo the action
137 """
138 raise NameError("UndoAction.redo is abstract.")
139
141 """
142 @rtype: str
143 @return: A string describing the action to be done
144 """
145 return "Undo " + self.__description
146
148 """
149 @rtype: str
150 @return: A string describing the action to be done
151 """
152 return "Redo " + self.__description
153
154
156 """
157 UndoAction for moving physics shapes around the map
158 """
159 - def __init__(self, controller, shape, dx, dy):
165
167 self.__shape.shift(-self.__dx, -self.__dy)
168
170 self.__shape.shift(self.__dx, self.__dy)
171
172
174 """
175 UndoAction for deleting a shape from the map
176 """
181
184
187
188
190 """
191 UndoAction for adding a shape to the map
192 """
197
200
203
204
206 """
207 UndoAction for adjusting the geometry of a shape
208 """
209 - def __init__(self, controller, shape, index, oldX, oldY, newX, newY):
210 """
211 @type controller: mapcontroller.MapController
212 @param controller: the map controller
213 @type index: int
214 @param index: the index of the shape's handle being adjusted
215 @type oldX: int
216 @param oldX: old x-coordinate of the handle
217 @type oldY: int
218 @param oldY: old y-coordinate of the handle
219 @type newX: int
220 @param newX: new x-coordinate of the handle
221 @type newY: int
222 @param newY: new y-coordinate of the handle
223 """
224 UndoAction.__init__(self, controller)
225 self.__oldX = oldX
226 self.__oldY = oldY
227 self.__newX = newX
228 self.__newY = newY
229 self.__shape = shape
230 self.__index = index
231 self.setDescription("adjust shape")
232
234 self.__shape.adjust(self.__oldX, self.__oldY, self.__index)
235
237 self.__shape.adjust(self.__newX, self.__newY, self.__index)
238
239
241 """
242 Action for adding tiles to the map. Because tiles are often added in chunks,
243 the appendTileAdd method must be used. This way the entire chunk can be
244 undone at once
245 """
251
252 - def appendTileAdd(self, coords, newImageCoords, oldImageCoords):
253 """
254 Adds a tile add operation to this undo action
255 @type coords: (int, int, int)
256 @param coords: x-coordinate, y-coordinate, and layer
257 @type newImageCoords: (int, int, int)
258 @param newImageCoords: x-coordinate of new tile's image,
259 x-coordinate of new tile's image, and image index of new tile's
260 image
261 @type oldImageCoords: (int, int, int)
262 @param oldImageCoords: x-coordinate of old tile's image,
263 x-coordinate of old tile's image, and image index of old tile's
264 image
265 """
266 self.__addedTiles[coords] = newImageCoords
267 self.__oldTiles[coords] = oldImageCoords
268
270 for coord, imageCoord in self.__oldTiles.iteritems():
271 x = coord[0]
272 y = coord[1]
273 z = coord[2]
274 controller = self.getController()
275 if self.__oldTiles[coord] == None:
276 controller.removeTile(x, y, z)
277 else:
278 ix = imageCoord[0]
279 iy = imageCoord[1]
280 ii = imageCoord[2]
281 controller.addTile(x, y, z, ix, iy, ii)
282
284 for coord, imageCoord in self.__addedTiles.iteritems():
285 x = coord[0]
286 y = coord[1]
287 z = coord[2]
288 controller = self.getController()
289 ix = imageCoord[0]
290 iy = imageCoord[1]
291 ii = imageCoord[2]
292 controller.addTile(x, y, z, ix, iy, ii)
293
294
296 """
297 Action for removing tiles from the map
298 """
303
305 """
306 Adds a tile remove operation to this undo action
307 @type coords: (int, int, int)
308 @param coords: x-coordinate, y-coordinate, and layer
309 @type oldImageCoords: (int, int, int)
310 @param oldImageCoords: x-coordinate of old tile's image,
311 x-coordinate of old tile's image, and image index of old tile's
312 image
313 """
314 if coords in self.__oldTiles:
315 return
316 self.__oldTiles[coords] = oldImageCoords
317
319 for coord, imageCoord in self.__oldTiles.iteritems():
320 x = coord[0]
321 y = coord[1]
322 z = coord[2]
323 controller = self.getController()
324 if self.__oldTiles[coord] != None:
325 ix = imageCoord[0]
326 iy = imageCoord[1]
327 ii = imageCoord[2]
328 controller.addTile(x, y, z, ix, iy, ii)
329
331 controller = self.getController()
332 for coord in self.__oldTiles:
333 x = coord[0]
334 y = coord[1]
335 z = coord[2]
336 controller.removeTile(x, y, z)
337
338
340 - def __init__(self, controller, newWidth, newHeight, xOffset, yOffset,
341 oldWidth, oldHeight):
342 UndoAction.__init__(self, controller)
343 self.setDescription("resize map")
344 self.__newWidth = newWidth
345 self.__newHeight = newHeight
346 self.__xOffset = xOffset
347 self.__yOffset = yOffset
348 self.__oldWidth = oldWidth
349 self.__oldHeight = oldHeight
350
351 self.__tileRemove = TileRemoveAction(controller)
352
353 def addTileRange(x1, x2, y1, y2):
354 for x in range(x1, x2):
355 for y in range(y1, y2):
356 for z in range(controller.mapLayers()):
357 r = controller.removeTile(x, y, z)
358 self.__tileRemove.appendTileRemove((x, y, z), r)
359
360
361 if xOffset < 0:
362 addTileRange(0, -xOffset, 0, oldHeight)
363
364
365 if yOffset < 0:
366 addTileRange(0, oldWidth, 0, -yOffset)
367
368
369 rightStart = oldWidth - (oldWidth - newWidth + xOffset)
370 addTileRange(rightStart, oldWidth, 0, oldHeight)
371
372
373 bottomStart = oldHeight - (oldHeight - newHeight + yOffset)
374 addTileRange(0, oldWidth, bottomStart, oldHeight)
375
377 self.getController().resize(self.__oldWidth, self.__oldHeight,
378 -self.__xOffset, -self.__yOffset)
379 self.__tileRemove.undo()
380
382 self.__tileRemove.redo()
383 self.getController().resize(self.__newWidth, self.__newHeight,
384 self.__xOffset, self.__yOffset)
385