comparison clients/editor/scripts/mapcontroller.py @ 255:51cc05d862f2

Merged editor_rewrite branch to trunk. This contains changes that may break compatibility against existing clients. For a list of changes that may affect your client, see: http://wiki.fifengine.de/Changes_to_pychan_and_FIFE_in_editor_rewrite_branch
author cheesesucker@33b003aa-7bff-0310-803a-e67f0ece8222
date Mon, 08 Jun 2009 16:00:02 +0000
parents
children 475f83e227e0
comparison
equal deleted inserted replaced
254:10b5f7f36dd4 255:51cc05d862f2
1 import editor
2 import pdb
3
4 import math
5
6 import fife
7 import editor
8 import events
9 import undomanager
10
11 class MapController(object):
12 """ MapController provides an interface for editing maps """
13 def __init__(self, map):
14
15 self._editor = editor.getEditor()
16 self._engine = self._editor.getEngine()
17
18 self._camera = None # currently selected camera
19 self._layer = None # currently selected layer
20 self._selection = [] # currently selected cells
21 self._map = None
22 self._undo = False
23 self._undomanager = undomanager.UndoManager()
24 undomanager.preUndo.connect(self._startUndo, sender=self._undomanager)
25 undomanager.preRedo.connect(self._startUndo, sender=self._undomanager)
26 undomanager.postUndo.connect(self._endUndo, sender=self._undomanager)
27 undomanager.postRedo.connect(self._endUndo, sender=self._undomanager)
28 self.debug = False
29
30 self.overwriteInstances = True # Remove instances on cell before placing new instance
31
32 if map is not None:
33 self.setMap(map.getId())
34
35 def setMap(self, mapid):
36 """ Set the map to be edited """
37 self._camera = None
38 self._map = None
39 self._layer = None
40 self._selection = []
41
42 self._map = self._engine.getModel().getMap(mapid)
43 if not self._map.getLayers():
44 raise AttributeError('Editor error: map ' + self._map.getId() + ' has no layers. Cannot edit.')
45
46 for cam in self._engine.getView().getCameras():
47 if cam.getLocationRef().getMap().getId() == self._map.getId():
48 self._camera = cam
49 break
50
51 self._layer = self._map.getLayers()[0]
52
53 def selectLayer(self, layerid):
54 """ Select layer to be edited """
55 self.deselectSelection()
56 self._layer = None
57 layers = [l for l in self._map.getLayers() if l.getId() == layerid]
58 if len(layers) == 1:
59 self._layer = layers[0]
60
61 def deselectSelection(self):
62 """ Deselects all selected cells """
63 if not self._camera:
64 if self.debug: print 'No camera bind yet, cannot select any cell'
65 return
66 self._selection = []
67 fife.CellSelectionRenderer.getInstance(self._camera).reset()
68
69 def clearSelection(self):
70 """ Removes all instances on selected cells """
71 instances = self.getInstancesFromSelection()
72 self._undomanager.startGroup("Cleared selection")
73 self.removeInstances(instances)
74 self._undomanager.endGroup()
75
76 def fillSelection(self, object):
77 """ Adds an instance of object on each selected cell """
78 self._undomanager.startGroup("Filled selection")
79 for loc in self._selection:
80 self.placeInstance(loc.getLayerCoordinates(), object)
81 self._undomanager.endGroup()
82
83 def selectCell(self, screenx, screeny):
84 """ Selects a cell at a position on screen """
85 if not self._camera:
86 if self.debug: print 'No camera bind yet, cannot select any cell'
87 return
88 if not self._layer:
89 if self.debug: print 'No layer assigned in selectCell'
90 return
91
92 mapCoords = self._camera.toMapCoordinates(fife.ScreenPoint(screenx, screeny), False)
93 position = self._layer.getCellGrid().toLayerCoordinates(mapCoords)
94
95 loc = fife.Location(self._layer)
96 loc.setLayerCoordinates(position)
97
98 for i in self._selection:
99 if loc == i: return
100
101 self._selection.append( loc )
102 fife.CellSelectionRenderer.getInstance(self._camera).selectLocation(loc)
103
104 def deselectCell(self, screenx, screeny):
105 """ Deselects a cell at a position on screen """
106 if not self._camera:
107 if self.debug: print 'No camera bind yet, cannot select any cell'
108 return
109 if not self._layer:
110 if self.debug: print 'No layer assigned in selectCell'
111 return
112
113 mapCoords = self._camera.toMapCoordinates(fife.ScreenPoint(screenx, screeny), False)
114 position = self._layer.getCellGrid().toLayerCoordinates(mapCoords)
115
116 loc = fife.Location(self._layer)
117 loc.setLayerCoordinates(position)
118
119 for i in self._selection:
120 if loc == i:
121 self._selection.remove( loc )
122 fife.CellSelectionRenderer.getInstance(self._camera).deselectLocation(loc)
123 return
124
125
126 def getInstancesFromSelection(self):
127 """ Returns all instances in the selected cells """
128 instances = []
129
130 for loc in self._selection:
131 instances.extend(self.getInstancesFromPosition(loc.getLayerCoordinates()))
132
133 return instances
134
135 def getInstancesFromPosition(self, position):
136 """ Returns all instances on a specified position """
137 if not self._layer:
138 if self.debug: print 'No layer assigned in getInstancesFromPosition'
139 return
140 if not position:
141 if self.debug: print 'No position assigned in getInstancesFromPosition'
142 return
143
144 loc = fife.Location(self._layer)
145 if type(position) == fife.ExactModelCoordinate:
146 loc.setExactLayerCoordinates(position)
147 else:
148 loc.setLayerCoordinates(position)
149
150 instances = self._layer.getInstancesAt(loc)
151
152 return instances
153
154 def getUndoManager(self):
155 """ Returns undo manager """
156 return self._undomanager
157
158 def undo(self):
159 """ Undo one level """
160 self._undomanager.undo()
161
162 def redo(self):
163 """ Redo one level """
164 self._undomanager.redo()
165
166 def _startUndo(self):
167 """ Called before a undo operation is performed. Makes sure undo stack does not get corrupted """
168 self._undo = True
169
170 def _endUndo(self):
171 """ Called when a undo operation is done """
172 self._undo = False
173
174 def placeInstance(self, position, object):
175 """ Places an instance of object at position. Any existing instances on position are removed. """
176 mname = 'placeInstance'
177 if not object:
178 if self.debug: print 'No object assigned in %s' % mname
179 return
180 if not position:
181 if self.debug: print 'No position assigned in %s' % mname
182 return
183 if not self._layer:
184 if self.debug: print 'No layer assigned in %s' % mname
185 return
186
187 if self.debug: print 'Placing instance of ' + object.getId() + ' at ' + str(position)
188
189 # Remove instances from target position
190 if not self._undo:
191 self._undomanager.startGroup("Placed instance")
192 self.removeInstances(self.getInstancesFromPosition(position))
193
194 inst = self._layer.createInstance(object, position)
195 fife.InstanceVisual.create(inst)
196
197 if not self._undo:
198 redocall = lambda: self.placeInstance(position, object)
199 undocall = lambda: self.removeInstances([inst])
200 undoobject = undomanager.UndoObject(undocall, redocall, "Placed instance")
201 self._undomanager.addAction(undoobject)
202 self._undomanager.endGroup()
203
204 def removeInstances(self, instances):
205 """ Removes all provided instances """
206 mname = 'removeInstances'
207 if not instances:
208 if self.debug: print 'No instances assigned in %s' % mname
209 return
210
211 for i in instances:
212 if self.debug: print 'Deleting instance ' + i.getObject().getId() + ' at ' + str(i.getLocation().getExactLayerCoordinates())
213
214 if not self._undo:
215 object = i.getObject()
216
217 position = i.getLocation().getExactLayerCoordinates()
218 undocall = lambda: self.placeInstance(position, object)
219 redocall = lambda: self.removeInstances([i])
220 undoobject = undomanager.UndoObject(undocall, redocall, "Removed instance")
221 self._undomanager.addAction(undoobject)
222
223 self._layer.deleteInstance(i)
224
225 def moveInstances(self, instances, moveBy, exact=False):
226 """ Moves provided instances by moveBy. If exact is false, the instances are
227 snapped to closest cell. """
228 mname = 'moveInstances'
229 if not self._layer:
230 if self.debug: print 'No layer assigned in %s' % mname
231 return
232
233 if exact and type(moveBy) != fife.ExactModelCoordinate:
234 moveBy = fife.ExactModelCoordinate(float(moveBy.x), float(moveBy.y), float(moveBy.z))
235 elif exact is False and type(moveBy) != fife.ModelCoordinate:
236 moveBy = fife.ModelCoordinate(int(round(moveBy.x)), int(round(moveBy.y)), int(round(moveBy.z)))
237
238 for i in instances:
239 loc = i.getLocation()
240 f = i.getFacingLocation()
241 if exact:
242 newCoords = loc.getExactLayerCoordinates() + moveBy
243 loc.setExactLayerCoordinates(newCoords)
244 f.setExactLayerCoordinates(f.getExactLayerCoordinates() + moveBy)
245 else:
246 # Move instance and snap to closest cell
247 newCoords = loc.getLayerCoordinates() + moveBy
248 loc.setLayerCoordinates(newCoords)
249 f.setLayerCoordinates(f.getLayerCoordinates() + moveBy)
250 i.setLocation(loc)
251 i.setFacingLocation(f)
252
253 def rotateCounterClockwise(self):
254 """ Rotates map counterclockwise by 90 degrees """
255 currot = self._camera.getRotation()
256 self._camera.setRotation((currot + 270) % 360)
257
258 def rotateClockwise(self):
259 """ Rotates map clockwise by 90 degrees """
260 currot = self._camera.getRotation()
261 self._camera.setRotation((currot + 90) % 360)
262
263 def getZoom(self):
264 """ Returns camera zoom """
265 if not self._camera:
266 if self.debug: print 'No camera bind yet, cannot get zoom'
267 return 0
268 return self._camera.getZoom()
269
270 def setZoom(self, zoom):
271 """ Sets camera zoom """
272 if not self._camera:
273 if self.debug: print 'No camera bind yet, cannot get zoom'
274 return
275 self._camera.setZoom(zoom)
276
277 def moveCamera(self, screen_x, screen_y):
278 """ Move camera (scroll) by screen_x, screen_y """
279 coords = self._camera.getLocationRef().getMapCoordinates()
280 z = self._camera.getZoom()
281 r = self._camera.getRotation()
282 if screen_x:
283 coords.x -= screen_x / z * math.cos(r / 180.0 * math.pi) / 100;
284 coords.y -= screen_x / z * math.sin(r / 180.0 * math.pi) / 100;
285 if screen_y:
286 coords.x -= screen_y / z * math.sin(-r / 180.0 * math.pi) / 100;
287 coords.y -= screen_y / z * math.cos(-r / 180.0 * math.pi) / 100;
288 coords = self._camera.getLocationRef().setMapCoordinates(coords)
289 self._camera.refresh()