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)