Mercurial > fife-parpg
comparison clients/editor/scripts/gui/mapeditor.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 | f2195628947b |
comparison
equal
deleted
inserted
replaced
254:10b5f7f36dd4 | 255:51cc05d862f2 |
---|---|
1 # MapEditor is a plugin for Fifedit. It allows for selection and visual editing of maps. | |
2 | |
3 import math | |
4 | |
5 import fife | |
6 import pychan | |
7 import pychan.widgets as widgets | |
8 import scripts | |
9 import scripts.events as events | |
10 import action | |
11 from toolbar import ToolBar | |
12 from menubar import Menu, MenuBar | |
13 from action import Action, ActionGroup | |
14 from scripts.mapcontroller import MapController | |
15 | |
16 states = (u'SELECTING', u'INSERTING', u'REMOVING', u'MOVING', u'OBJECTPICKER') | |
17 for s in states: | |
18 globals()[s] = s | |
19 NOT_INITIALIZED = -9999999 | |
20 | |
21 class MapEditor: | |
22 def __init__(self): | |
23 self._ignoreToggles = False # A hack to avoid infinite recursion when toggling a button | |
24 self._controller = None | |
25 self._mode = SELECTING | |
26 | |
27 self._editor = scripts.editor.getEditor() | |
28 self._eventlistener = self._editor.getEventListener() | |
29 self._statusbar = self._editor.getStatusBar() | |
30 self._toolbar = self._editor.getToolBar() | |
31 self._object = None | |
32 self._startDragPos = None | |
33 self._lastDragPos = None | |
34 self._lastDragPosExact = None | |
35 | |
36 self._toolbox = self._editor.getToolbox() | |
37 | |
38 self._initToolbuttons() | |
39 | |
40 self._toolbox.show() | |
41 self._instances = [] | |
42 | |
43 events.postMapShown.connect(self._mapChanged) | |
44 events.onObjectSelected.connect(self.setObject) | |
45 self._undogroup = False | |
46 | |
47 self._scrollX = 0 | |
48 self._scrollY = 0 | |
49 | |
50 def _init(self): | |
51 self._dragx = NOT_INITIALIZED | |
52 self._dragy = NOT_INITIALIZED | |
53 | |
54 self._setMode(SELECTING) | |
55 | |
56 self._initToolbarbuttons() | |
57 | |
58 events.keyPressed.connect(self.keyPressed) | |
59 events.keyReleased.connect(self.keyReleased) | |
60 | |
61 events.mousePressed.connect(self.mousePressed) | |
62 events.mouseDragged.connect(self.mouseDragged) | |
63 events.mouseReleased.connect(self.mouseReleased) | |
64 events.mouseMoved.connect(self.mouseMoved) | |
65 events.mouseWheelMovedUp.connect(self.mouseWheelMovedUp) | |
66 events.mouseWheelMovedDown.connect(self.mouseWheelMovedDown) | |
67 events.mouseExited.connect(self.mouseExited) | |
68 events.onPump.connect(self.pump) | |
69 | |
70 def _clear(self): | |
71 self._clearToolbarButtons() | |
72 | |
73 events.keyPressed.disconnect(self.keyPressed) | |
74 events.keyReleased.disconnect(self.keyReleased) | |
75 | |
76 events.mousePressed.disconnect(self.mousePressed) | |
77 events.mouseDragged.disconnect(self.mouseDragged) | |
78 events.mouseReleased.disconnect(self.mouseReleased) | |
79 events.mouseMoved.disconnect(self.mouseMoved) | |
80 events.mouseWheelMovedUp.disconnect(self.mouseWheelMovedUp) | |
81 events.mouseWheelMovedDown.disconnect(self.mouseWheelMovedDown) | |
82 events.mouseExited.disconnect(self.mouseExited) | |
83 events.onPump.disconnect(self.pump) | |
84 | |
85 def _mapChanged(self, sender, mapview): | |
86 self.setController(mapview.getController()) | |
87 | |
88 def setObject(self, object): | |
89 self._object = object | |
90 | |
91 def setController(self, controller): | |
92 if self._controller is not None: | |
93 self._clear() | |
94 | |
95 if controller is not None: | |
96 self._init() | |
97 | |
98 self._controller = controller | |
99 | |
100 def _initToolbuttons(self): | |
101 self._selectAction = Action(text=u"Select", icon="gui/icons/select_instance.png", checkable=True) | |
102 self._drawAction = Action(text=u"Draw", icon="gui/icons/add_instance.png", checkable=True) | |
103 self._removeAction = Action(text=u"Remove", icon="gui/icons/erase_instance.png", checkable=True) | |
104 self._moveAction = Action(text=u"Move", icon="gui/icons/move_instance.png", checkable=True) | |
105 self._objectpickerAction = Action(text=u"Pick object", icon="gui/icons/objectpicker.png", checkable=True) | |
106 | |
107 self._selectAction.helptext = u"Select cells on layer" | |
108 self._moveAction.helptext = u"Moves instances" | |
109 self._drawAction.helptext = u"Adds new instances based on currently selected object" | |
110 self._removeAction.helptext = u"Deletes instances" | |
111 self._objectpickerAction.helptext = u"Click an instance to set the current object to the one used by instance" | |
112 | |
113 action.toggled.connect(self._buttonToggled, sender=self._selectAction) | |
114 action.toggled.connect(self._buttonToggled, sender=self._moveAction) | |
115 action.toggled.connect(self._buttonToggled, sender=self._drawAction) | |
116 action.toggled.connect(self._buttonToggled, sender=self._removeAction) | |
117 action.toggled.connect(self._buttonToggled, sender=self._objectpickerAction) | |
118 | |
119 self._toolgroup = ActionGroup(exclusive=True, name=u"Tool group") | |
120 self._toolgroup.addAction(self._selectAction) | |
121 self._toolgroup.addAction(self._moveAction) | |
122 self._toolgroup.addAction(self._drawAction) | |
123 self._toolgroup.addAction(self._removeAction) | |
124 self._toolgroup.addAction(self._objectpickerAction) | |
125 | |
126 | |
127 self._toolbox.addAction(self._toolgroup) | |
128 self._toolbox.adaptLayout() | |
129 | |
130 self._editor._editMenu.addAction(self._toolgroup) | |
131 | |
132 def _initToolbarbuttons(self): | |
133 rotateLeftAction = Action(text=u"Rotate counterclockwise", icon="gui/icons/rotate_countercw.png") | |
134 rotateRightAction = Action(text=u"Rotate clockwise", icon="gui/icons/rotate_clockwise.png") | |
135 zoomInAction = Action(text=u"Zoom in", icon="gui/icons/zoom_in.png") | |
136 zoomOutAction = Action(text=u"Zoom out", icon="gui/icons/zoom_out.png") | |
137 zoomResetAction = Action(text=u"Reset zoom", icon="gui/icons/zoom_default.png") | |
138 | |
139 action.activated.connect(self.rotateCounterClockwise, sender=rotateLeftAction) | |
140 action.activated.connect(self.rotateClockwise, sender=rotateRightAction) | |
141 action.activated.connect(self.zoomIn, sender=zoomInAction) | |
142 action.activated.connect(self.zoomOut, sender=zoomOutAction) | |
143 action.activated.connect(self.resetZoom, sender=zoomResetAction) | |
144 | |
145 self._viewGroup = ActionGroup(name=u"View group") | |
146 self._viewGroup.addAction(rotateLeftAction) | |
147 self._viewGroup.addAction(rotateRightAction) | |
148 self._viewGroup.addAction(zoomInAction) | |
149 self._viewGroup.addAction(zoomOutAction) | |
150 self._viewGroup.addAction(zoomResetAction) | |
151 | |
152 self._toolbar.addAction(self._viewGroup) | |
153 self._toolbar.adaptLayout() | |
154 | |
155 def _clearToolbarButtons(self): | |
156 self._toolbar.removeAction(self._viewGroup) | |
157 self._toolbar.adaptLayout() | |
158 self._viewGroup = None | |
159 | |
160 | |
161 def _setMode(self, mode): | |
162 if (mode == INSERTING) and (not self._object): | |
163 self._statusbar.setText(u'Please select object first') | |
164 mode = self._mode | |
165 | |
166 self._ignoreToggles = True | |
167 # Update toolbox buttons | |
168 if (mode == INSERTING): | |
169 self._drawAction.setChecked(True) | |
170 elif mode == REMOVING: | |
171 self._removeAction.setChecked(True) | |
172 elif mode == MOVING: | |
173 self._moveAction.setChecked(True) | |
174 elif mode == OBJECTPICKER: | |
175 self._objectpickerAction.setChecked(True) | |
176 else: | |
177 self._selectAction.setChecked(True) | |
178 self._ignoreToggles = False | |
179 | |
180 self._mode = mode | |
181 print "Entered mode " + mode | |
182 self._statusbar.setText(mode.replace('_', ' ').capitalize()) | |
183 | |
184 def _buttonToggled(self, sender, toggled): | |
185 if self._controller is None: return | |
186 if self._ignoreToggles is True: return | |
187 | |
188 mode = SELECTING | |
189 | |
190 if toggled: | |
191 if sender == self._selectAction: | |
192 mode = SELECTING | |
193 elif sender == self._moveAction: | |
194 mode = MOVING | |
195 elif sender == self._drawAction: | |
196 mode = INSERTING | |
197 elif sender == self._removeAction: | |
198 mode = REMOVING | |
199 elif sender == self._objectpickerAction: | |
200 mode = OBJECTPICKER | |
201 | |
202 self._setMode(mode) | |
203 | |
204 def mouseExited(self, sender, event): | |
205 pass | |
206 | |
207 | |
208 def mousePressed(self, sender, event): | |
209 if event.isConsumedByWidgets(): | |
210 return | |
211 | |
212 realCoords = self._getRealCoords(sender, event) | |
213 | |
214 if event.getButton() == fife.MouseEvent.MIDDLE: | |
215 self._dragx = realCoords[0] | |
216 self._dragy = realCoords[1] | |
217 | |
218 else: | |
219 if event.getButton() == fife.MouseEvent.RIGHT: | |
220 self._controller.deselectSelection() | |
221 | |
222 if self._mode == SELECTING: | |
223 if event.getButton() == fife.MouseEvent.LEFT: | |
224 if self._eventlistener.shiftPressed: | |
225 self._controller.deselectCell(realCoords[0], realCoords[1]) | |
226 else: | |
227 if self._eventlistener.controlPressed is False: | |
228 self._controller.deselectSelection() | |
229 self._controller.selectCell(realCoords[0], realCoords[1]) | |
230 | |
231 elif event.getButton() == fife.MouseEvent.RIGHT: | |
232 self._controller.deselectSelection() | |
233 | |
234 elif self._mode == INSERTING: | |
235 if event.getButton() == fife.MouseEvent.LEFT: | |
236 self._controller.deselectSelection() | |
237 self._controller.selectCell(realCoords[0], realCoords[1]) | |
238 self._controller.getUndoManager().startGroup("Inserted instances") | |
239 self._undogroup = True | |
240 | |
241 position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False) | |
242 position = self._controller._layer.getCellGrid().toLayerCoordinates(position) | |
243 | |
244 self._controller.selectCell(realCoords[0], realCoords[1]) | |
245 self._controller.placeInstance(position, self._object) | |
246 | |
247 elif self._mode == REMOVING: | |
248 if event.getButton() == fife.MouseEvent.LEFT: | |
249 self._controller.deselectSelection() | |
250 self._controller.selectCell(realCoords[0], realCoords[1]) | |
251 self._controller.getUndoManager().startGroup("Removed instances") | |
252 self._undogroup = True | |
253 | |
254 self._controller.removeInstances(self._controller.getInstancesFromSelection()) | |
255 | |
256 elif self._mode == MOVING: | |
257 if event.getButton() == fife.MouseEvent.LEFT: | |
258 | |
259 position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False) | |
260 | |
261 self._lastDragPos = self._controller._layer.getCellGrid().toLayerCoordinates(position) | |
262 self._lastDragPosExact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position) | |
263 | |
264 for loc in self._controller._selection: | |
265 if loc.getLayerCoordinates() == self._lastDragPos: | |
266 break | |
267 else: | |
268 self._controller.deselectSelection() | |
269 self._controller.selectCell(realCoords[0], realCoords[1]) | |
270 | |
271 self._instances = self._controller.getInstancesFromSelection() | |
272 | |
273 self._controller.getUndoManager().startGroup("Moved instances") | |
274 self._undogroup = True | |
275 | |
276 elif self._mode == OBJECTPICKER: | |
277 position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False) | |
278 exact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position) | |
279 instances = self._controller.getInstancesFromPosition(exact) | |
280 if len(instances) >= 1: | |
281 object = instances[0].getObject() | |
282 if object.getId() != self._object.getId() or object.getNamespace() != self._object.getNamespace(): | |
283 events.onObjectSelected.send(sender=self, object=object) | |
284 | |
285 def mouseDragged(self, sender, event): | |
286 if event.isConsumedByWidgets(): | |
287 return | |
288 | |
289 realCoords = self._getRealCoords(sender, event) | |
290 | |
291 if event.getButton() == fife.MouseEvent.MIDDLE: | |
292 self._scrollX = (self._dragx-realCoords[0])/10.0 | |
293 self._scrollY = (self._dragy-realCoords[1])/10.0 | |
294 else: | |
295 if self._mode != SELECTING: | |
296 self._controller.deselectSelection() | |
297 | |
298 if self._mode == SELECTING: | |
299 if event.getButton() == fife.MouseEvent.LEFT: | |
300 if self._eventlistener.shiftPressed: | |
301 self._controller.deselectCell(realCoords[0], realCoords[1]) | |
302 else: | |
303 self._controller.selectCell(realCoords[0], realCoords[1]) | |
304 | |
305 elif self._mode == INSERTING: | |
306 position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False) | |
307 position = self._controller._layer.getCellGrid().toLayerCoordinates(position) | |
308 | |
309 self._controller.selectCell(realCoords[0], realCoords[1]) | |
310 self._controller.placeInstance(position, self._object) | |
311 | |
312 elif self._mode == REMOVING: | |
313 self._controller.selectCell(realCoords[0], realCoords[1]) | |
314 self._controller.removeInstances(self._controller.getInstancesFromSelection()) | |
315 | |
316 elif self._mode == MOVING: | |
317 position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False) | |
318 | |
319 positionExact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position) | |
320 position = self._controller._layer.getCellGrid().toLayerCoordinates(position) | |
321 | |
322 if self._eventlistener.shiftPressed: | |
323 self._controller.moveInstances(self._instances, positionExact-self._lastDragPosExact, True) | |
324 else: | |
325 self._controller.moveInstances(self._instances, position-self._lastDragPos, False) | |
326 self._lastDragPos = position | |
327 self._lastDragPosExact = positionExact | |
328 | |
329 # Update selection | |
330 self._controller.deselectSelection() | |
331 | |
332 for i in self._instances: | |
333 pos = i.getLocation().getMapCoordinates() | |
334 pos = self._controller._camera.toScreenCoordinates(pos) | |
335 self._controller.selectCell(pos.x, pos.y) | |
336 elif self._mode == OBJECTPICKER: | |
337 pass | |
338 | |
339 def mouseReleased(self, sender, event): | |
340 if event.isConsumedByWidgets(): | |
341 return | |
342 | |
343 if self._mode == SELECTING or self._mode == MOVING: | |
344 instances = self._controller.getInstancesFromSelection() | |
345 if len(instances) > 0: | |
346 events.onInstancesSelected.send(sender=self, instances=instances) | |
347 | |
348 if event.getButton() == fife.MouseEvent.MIDDLE: | |
349 self._scrollX = 0 | |
350 self._scrollY = 0 | |
351 | |
352 realCoords = self._getRealCoords(sender, event) | |
353 | |
354 if self._undogroup: | |
355 self._controller.getUndoManager().endGroup() | |
356 self._undogroup = False | |
357 | |
358 self._dragx = NOT_INITIALIZED | |
359 self._dragy = NOT_INITIALIZED | |
360 | |
361 def mouseMoved(self, sender, event): | |
362 pass | |
363 | |
364 def mouseWheelMovedUp(self, event): | |
365 if self._eventlistener.controlPressed and self._controller._camera: | |
366 self._controller._camera.setZoom(self._controller._camera.getZoom() * 1.10) | |
367 | |
368 def mouseWheelMovedDown(self, event): | |
369 if self._eventlistener.controlPressed and self._controller._camera: | |
370 self._controller._camera.setZoom(self._controller._camera.getZoom() / 1.10) | |
371 | |
372 | |
373 def keyPressed(self, event): | |
374 keyval = event.getKey().getValue() | |
375 keystr = event.getKey().getAsString().lower() | |
376 | |
377 if keyval == fife.Key.LEFT: | |
378 self._controller.moveCamera(50, 0) | |
379 elif keyval == fife.Key.RIGHT: | |
380 self._controller.moveCamera(-50, 0) | |
381 elif keyval == fife.Key.UP: | |
382 self._controller.moveCamera(0, 50) | |
383 elif keyval == fife.Key.DOWN: | |
384 self._controller.moveCamera(0, -50) | |
385 | |
386 elif keyval == fife.Key.INSERT: | |
387 self._controller.fillSelection(self._object) | |
388 | |
389 elif keyval == fife.Key.DELETE: | |
390 self._controller.clearSelection() | |
391 | |
392 elif keystr == "s": | |
393 self._setMode(SELECTING) | |
394 | |
395 elif keystr == "i": | |
396 if self._mode != INSERTING: | |
397 self._setMode(INSERTING) | |
398 else: | |
399 self._setMode(SELECTING) | |
400 | |
401 elif keystr == "r": | |
402 if self._mode != REMOVING: | |
403 self._setMode(REMOVING) | |
404 else: | |
405 self._setMode(SELECTING) | |
406 | |
407 elif keystr == 'm': | |
408 if self._mode != MOVING: | |
409 self._setMode(MOVING) | |
410 else: | |
411 self._setMode(SELECTING) | |
412 | |
413 elif keystr == 't': | |
414 gridrenderer = self._controller._camera.getRenderer('GridRenderer') | |
415 gridrenderer.setEnabled(not gridrenderer.isEnabled()) | |
416 | |
417 elif keystr == 'b': | |
418 blockrenderer = self._controller._camera.getRenderer('BlockingInfoRenderer') | |
419 blockrenderer.setEnabled(not blockrenderer.isEnabled()) | |
420 | |
421 elif keystr == 'z': | |
422 if self._eventlistener.controlPressed: | |
423 if self._eventlistener.altPressed: | |
424 if self._eventlistener.shiftPressed: | |
425 self._controller.getUndoManager().previousBranch() | |
426 else: | |
427 self._controller.getUndoManager().nextBranch() | |
428 else: | |
429 if self._eventlistener.shiftPressed: | |
430 self._controller.redo() | |
431 else: | |
432 self._controller.undo() | |
433 | |
434 | |
435 def keyReleased(self, event): | |
436 pass | |
437 | |
438 def zoomIn(self, zoom=1.10): | |
439 self._controller.setZoom(self._controller.getZoom()*zoom) | |
440 | |
441 def zoomOut(self, zoom=1.10): | |
442 self._controller.setZoom(self._controller.getZoom()/zoom) | |
443 | |
444 def resetZoom(self): | |
445 self._controller.setZoom(1) | |
446 | |
447 def rotateCounterClockwise(self): | |
448 self._controller.rotateCounterClockwise() | |
449 | |
450 def rotateClockwise(self): | |
451 self._controller.rotateClockwise() | |
452 | |
453 def _getRealCoords(self, sender, event): | |
454 cw = sender | |
455 offsetX = event.getX() | |
456 offsetY = event.getY() | |
457 | |
458 parent = cw | |
459 while parent is not None: | |
460 if isinstance(parent, widgets.Widget): | |
461 offsetX += parent.x | |
462 offsetY += parent.y | |
463 parent = parent.parent | |
464 else: | |
465 break | |
466 | |
467 return (offsetX, offsetY) | |
468 | |
469 def pump(self): | |
470 self._controller.moveCamera(self._scrollX, self._scrollY) |