Mercurial > fife-parpg
comparison tools/editor/scripts/mapcontroller.py @ 378:64738befdf3b
bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author | vtchill@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Mon, 11 Jan 2010 23:34:52 +0000 |
parents | |
children | 9d94f4676d17 |
comparison
equal
deleted
inserted
replaced
377:fe6fb0e0ed23 | 378:64738befdf3b |
---|---|
1 # -*- coding: utf-8 -*- | |
2 | |
3 # #################################################################### | |
4 # Copyright (C) 2005-2009 by the FIFE team | |
5 # http://www.fifengine.de | |
6 # This file is part of FIFE. | |
7 # | |
8 # FIFE is free software; you can redistribute it and/or | |
9 # modify it under the terms of the GNU Lesser General Public | |
10 # License as published by the Free Software Foundation; either | |
11 # version 2.1 of the License, or (at your option) any later version. | |
12 # | |
13 # This library is distributed in the hope that it will be useful, | |
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 # Lesser General Public License for more details. | |
17 # | |
18 # You should have received a copy of the GNU Lesser General Public | |
19 # License along with this library; if not, write to the | |
20 # Free Software Foundation, Inc., | |
21 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 # #################################################################### | |
23 | |
24 import editor | |
25 import pdb | |
26 | |
27 import math | |
28 | |
29 from fife import fife | |
30 import editor | |
31 import events | |
32 import undomanager | |
33 | |
34 from fife.extensions.pychan.tools import callbackWithArguments as cbwa | |
35 | |
36 class MapController(object): | |
37 """ MapController provides an interface for editing maps """ | |
38 def __init__(self, map): | |
39 | |
40 self._editor = editor.getEditor() | |
41 self._engine = self._editor.getEngine() | |
42 | |
43 self._camera = None # currently selected camera | |
44 self._layer = None # currently selected layer | |
45 self._selection = [] # currently selected cells | |
46 self._map = None | |
47 self._undo = False | |
48 self._undomanager = undomanager.UndoManager() | |
49 undomanager.preUndo.connect(self._startUndo, sender=self._undomanager) | |
50 undomanager.preRedo.connect(self._startUndo, sender=self._undomanager) | |
51 undomanager.postUndo.connect(self._endUndo, sender=self._undomanager) | |
52 undomanager.postRedo.connect(self._endUndo, sender=self._undomanager) | |
53 self.debug = False | |
54 | |
55 self.overwriteInstances = True # Remove instances on cell before placing new instance | |
56 | |
57 if map is not None: | |
58 self.setMap(map.getId()) | |
59 | |
60 def cleanUp(self): | |
61 undomanager.preUndo.disconnect(self._startUndo, sender=self._undomanager) | |
62 undomanager.preRedo.disconnect(self._startUndo, sender=self._undomanager) | |
63 undomanager.postUndo.disconnect(self._endUndo, sender=self._undomanager) | |
64 undomanager.postRedo.disconnect(self._endUndo, sender=self._undomanager) | |
65 self._undomanager.clear() | |
66 | |
67 self._editor = None | |
68 self._engine = None | |
69 self._map = None | |
70 self._selection = [] | |
71 self._layer = None | |
72 self._camera = None | |
73 | |
74 def setMap(self, mapid): | |
75 """ Set the map to be edited """ | |
76 self._camera = None | |
77 self._map = None | |
78 self._layer = None | |
79 self._selection = [] | |
80 | |
81 self._map = self._engine.getModel().getMap(mapid) | |
82 if not self._map.getLayers(): | |
83 raise AttributeError('Editor error: map ' + self._map.getId() + ' has no layers. Cannot edit.') | |
84 | |
85 for cam in self._engine.getView().getCameras(): | |
86 if cam.getLocationRef().getMap().getId() == self._map.getId(): | |
87 self._camera = cam | |
88 break | |
89 | |
90 self._layer = self._map.getLayers()[0] | |
91 | |
92 def selectLayer(self, layerid): | |
93 """ Select layer to be edited """ | |
94 self.deselectSelection() | |
95 self._layer = None | |
96 layers = [l for l in self._map.getLayers() if l.getId() == layerid] | |
97 if len(layers) == 1: | |
98 self._layer = layers[0] | |
99 | |
100 def deselectSelection(self): | |
101 """ Deselects all selected cells """ | |
102 if not self._camera: | |
103 if self.debug: print 'No camera bind yet, cannot select any cell' | |
104 return | |
105 self._selection = [] | |
106 fife.CellSelectionRenderer.getInstance(self._camera).reset() | |
107 | |
108 def clearSelection(self): | |
109 """ Removes all instances on selected cells """ | |
110 instances = self.getInstancesFromSelection() | |
111 self._undomanager.startGroup("Cleared selection") | |
112 self.removeInstances(instances) | |
113 self._undomanager.endGroup() | |
114 | |
115 def fillSelection(self, object): | |
116 """ Adds an instance of object on each selected cell """ | |
117 self._undomanager.startGroup("Filled selection") | |
118 for loc in self._selection: | |
119 self.placeInstance(loc.getLayerCoordinates(), object) | |
120 self._undomanager.endGroup() | |
121 | |
122 def selectCell(self, screenx, screeny): | |
123 """ Selects a cell at a position on screen """ | |
124 if not self._camera: | |
125 if self.debug: print 'No camera bind yet, cannot select any cell' | |
126 return | |
127 if not self._layer: | |
128 if self.debug: print 'No layer assigned in selectCell' | |
129 return | |
130 | |
131 mapCoords = self._camera.toMapCoordinates(fife.ScreenPoint(screenx, screeny), False) | |
132 position = self._layer.getCellGrid().toLayerCoordinates(mapCoords) | |
133 | |
134 loc = fife.Location(self._layer) | |
135 loc.setLayerCoordinates(position) | |
136 | |
137 for i in self._selection: | |
138 if loc == i: return | |
139 | |
140 self._selection.append( loc ) | |
141 fife.CellSelectionRenderer.getInstance(self._camera).selectLocation(loc) | |
142 | |
143 def deselectCell(self, screenx, screeny): | |
144 """ Deselects a cell at a position on screen """ | |
145 if not self._camera: | |
146 if self.debug: print 'No camera bind yet, cannot select any cell' | |
147 return | |
148 if not self._layer: | |
149 if self.debug: print 'No layer assigned in selectCell' | |
150 return | |
151 | |
152 mapCoords = self._camera.toMapCoordinates(fife.ScreenPoint(screenx, screeny), False) | |
153 position = self._layer.getCellGrid().toLayerCoordinates(mapCoords) | |
154 | |
155 loc = fife.Location(self._layer) | |
156 loc.setLayerCoordinates(position) | |
157 | |
158 for i in self._selection: | |
159 if loc == i: | |
160 self._selection.remove( loc ) | |
161 fife.CellSelectionRenderer.getInstance(self._camera).deselectLocation(loc) | |
162 return | |
163 | |
164 | |
165 def getInstancesFromSelection(self): | |
166 """ Returns all instances in the selected cells """ | |
167 instances = [] | |
168 | |
169 for loc in self._selection: | |
170 instances.extend(self.getInstancesFromPosition(loc.getLayerCoordinates())) | |
171 | |
172 return instances | |
173 | |
174 def getInstancesFromPosition(self, position): | |
175 """ Returns all instances on a specified position """ | |
176 if not self._layer: | |
177 if self.debug: print 'No layer assigned in getInstancesFromPosition' | |
178 return | |
179 if not position: | |
180 if self.debug: print 'No position assigned in getInstancesFromPosition' | |
181 return | |
182 | |
183 loc = fife.Location(self._layer) | |
184 if type(position) == fife.ExactModelCoordinate: | |
185 loc.setExactLayerCoordinates(position) | |
186 else: | |
187 loc.setLayerCoordinates(position) | |
188 | |
189 instances = self._layer.getInstancesAt(loc) | |
190 | |
191 return instances | |
192 | |
193 def getUndoManager(self): | |
194 """ Returns undo manager """ | |
195 return self._undomanager | |
196 | |
197 def undo(self): | |
198 """ Undo one level """ | |
199 self._undomanager.undo() | |
200 | |
201 def redo(self): | |
202 """ Redo one level """ | |
203 self._undomanager.redo() | |
204 | |
205 def _startUndo(self): | |
206 """ Called before a undo operation is performed. Makes sure undo stack does not get corrupted """ | |
207 self._undo = True | |
208 | |
209 def _endUndo(self): | |
210 """ Called when a undo operation is done """ | |
211 self._undo = False | |
212 | |
213 def placeInstance(self, position, object): | |
214 """ Places an instance of object at position. Any existing instances on position are removed. """ | |
215 mname = 'placeInstance' | |
216 if not object: | |
217 if self.debug: print 'No object assigned in %s' % mname | |
218 return | |
219 if not position: | |
220 if self.debug: print 'No position assigned in %s' % mname | |
221 return | |
222 if not self._layer: | |
223 if self.debug: print 'No layer assigned in %s' % mname | |
224 return | |
225 | |
226 if self.debug: print 'Placing instance of ' + object.getId() + ' at ' + str(position) | |
227 | |
228 # Remove instances from target position | |
229 if not self._undo: | |
230 instances = self.getInstancesFromPosition(position) | |
231 if len(instances) == 1: | |
232 # Check if the only instance at position has the same object | |
233 objectId = instances[0].getObject().getId() | |
234 objectNs = instances[0].getObject().getNamespace() | |
235 if objectId == object.getId() and objectNs == object.getNamespace(): | |
236 if self.debug: print "Tried to place duplicate instance" | |
237 return | |
238 | |
239 self._undomanager.startGroup("Placed instance") | |
240 self.removeInstances(instances) | |
241 | |
242 inst = self._layer.createInstance(object, position) | |
243 fife.InstanceVisual.create(inst) | |
244 | |
245 if not self._undo: | |
246 redocall = cbwa(self.placeInstance, position, object) | |
247 undocall = cbwa(self.removeInstanceOfObjectAt, position, object) | |
248 undoobject = undomanager.UndoObject(undocall, redocall, "Placed instance") | |
249 self._undomanager.addAction(undoobject) | |
250 self._undomanager.endGroup() | |
251 | |
252 def removeInstanceOfObjectAt(self, position, object): | |
253 """ Removes the first instance of object it can find on position """ | |
254 instances = self.getInstancesFromPosition(position) | |
255 for i in instances: | |
256 if i.getObject().getId() == object.getId() and i.getObject().getNamespace() == object.getNamespace(): | |
257 self.removeInstances([i]) | |
258 return | |
259 | |
260 def removeInstances(self, instances): | |
261 """ Removes all provided instances """ | |
262 mname = 'removeInstances' | |
263 if not instances: | |
264 if self.debug: print 'No instances assigned in %s' % mname | |
265 return | |
266 | |
267 for i in instances: | |
268 if self.debug: print 'Deleting instance ' + i.getObject().getId() + ' at ' + str(i.getLocation().getExactLayerCoordinates()) | |
269 | |
270 if not self._undo: | |
271 object = i.getObject() | |
272 position = i.getLocation().getExactLayerCoordinates() | |
273 undocall = cbwa(self.placeInstance, position, object) | |
274 redocall = cbwa(self.removeInstanceOfObjectAt, position, object) | |
275 undoobject = undomanager.UndoObject(undocall, redocall, "Removed instance") | |
276 self._undomanager.addAction(undoobject) | |
277 | |
278 self._layer.deleteInstance(i) | |
279 | |
280 def moveInstances(self, instances, moveBy, exact=False): | |
281 """ Moves provided instances by moveBy. If exact is false, the instances are | |
282 snapped to closest cell. """ | |
283 mname = 'moveInstances' | |
284 if not self._layer: | |
285 if self.debug: print 'No layer assigned in %s' % mname | |
286 return | |
287 | |
288 if exact and type(moveBy) != fife.ExactModelCoordinate: | |
289 moveBy = fife.ExactModelCoordinate(float(moveBy.x), float(moveBy.y), float(moveBy.z)) | |
290 elif exact is False and type(moveBy) != fife.ModelCoordinate: | |
291 moveBy = fife.ModelCoordinate(int(round(moveBy.x)), int(round(moveBy.y)), int(round(moveBy.z))) | |
292 | |
293 for i in instances: | |
294 loc = i.getLocation() | |
295 f = i.getFacingLocation() | |
296 if exact: | |
297 newCoords = loc.getExactLayerCoordinates() + moveBy | |
298 loc.setExactLayerCoordinates(newCoords) | |
299 f.setExactLayerCoordinates(f.getExactLayerCoordinates() + moveBy) | |
300 else: | |
301 # Move instance and snap to closest cell | |
302 newCoords = loc.getLayerCoordinates() + moveBy | |
303 loc.setLayerCoordinates(newCoords) | |
304 f.setLayerCoordinates(f.getLayerCoordinates() + moveBy) | |
305 i.setLocation(loc) | |
306 i.setFacingLocation(f) | |
307 | |
308 def rotateCounterClockwise(self): | |
309 """ Rotates map counterclockwise by 90 degrees """ | |
310 currot = self._camera.getRotation() | |
311 self._camera.setRotation((currot + 270) % 360) | |
312 | |
313 def rotateClockwise(self): | |
314 """ Rotates map clockwise by 90 degrees """ | |
315 currot = self._camera.getRotation() | |
316 self._camera.setRotation((currot + 90) % 360) | |
317 | |
318 def getZoom(self): | |
319 """ Returns camera zoom """ | |
320 if not self._camera: | |
321 if self.debug: print 'No camera bind yet, cannot get zoom' | |
322 return 0 | |
323 return self._camera.getZoom() | |
324 | |
325 def setZoom(self, zoom): | |
326 """ Sets camera zoom """ | |
327 if not self._camera: | |
328 if self.debug: print 'No camera bind yet, cannot get zoom' | |
329 return | |
330 self._camera.setZoom(zoom) | |
331 | |
332 def moveCamera(self, screen_x, screen_y): | |
333 """ Move camera (scroll) by screen_x, screen_y """ | |
334 if not self._camera: | |
335 return | |
336 | |
337 coords = self._camera.getLocationRef().getMapCoordinates() | |
338 z = self._camera.getZoom() | |
339 r = self._camera.getRotation() | |
340 if screen_x: | |
341 coords.x -= screen_x / z * math.cos(r / 180.0 * math.pi) / 100; | |
342 coords.y -= screen_x / z * math.sin(r / 180.0 * math.pi) / 100; | |
343 if screen_y: | |
344 coords.x -= screen_y / z * math.sin(-r / 180.0 * math.pi) / 100; | |
345 coords.y -= screen_y / z * math.cos(-r / 180.0 * math.pi) / 100; | |
346 coords = self._camera.getLocationRef().setMapCoordinates(coords) | |
347 self._camera.refresh() |