Mercurial > fife-parpg
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() |