diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clients/editor/scripts/gui/mapeditor.py	Mon Jun 08 16:00:02 2009 +0000
@@ -0,0 +1,470 @@
+# MapEditor is a plugin for Fifedit. It allows for selection and visual editing of maps.
+
+import math
+
+import fife
+import pychan
+import pychan.widgets as widgets
+import scripts
+import scripts.events as events
+import action
+from toolbar import ToolBar
+from menubar import Menu, MenuBar
+from action import Action, ActionGroup
+from scripts.mapcontroller import MapController
+
+states = (u'SELECTING', u'INSERTING', u'REMOVING', u'MOVING', u'OBJECTPICKER')
+for s in states:
+	globals()[s] = s
+NOT_INITIALIZED = -9999999
+
+class MapEditor:
+	def __init__(self):	
+		self._ignoreToggles = False # A hack to avoid infinite recursion when toggling a button
+		self._controller = None
+		self._mode = SELECTING
+		
+		self._editor = scripts.editor.getEditor()
+		self._eventlistener = self._editor.getEventListener()
+		self._statusbar = self._editor.getStatusBar()
+		self._toolbar = self._editor.getToolBar()
+		self._object = None
+		self._startDragPos = None
+		self._lastDragPos = None
+		self._lastDragPosExact = None
+		
+		self._toolbox = self._editor.getToolbox()
+		
+		self._initToolbuttons()
+		
+		self._toolbox.show()
+		self._instances = []
+		
+		events.postMapShown.connect(self._mapChanged)
+		events.onObjectSelected.connect(self.setObject)
+		self._undogroup = False
+		
+		self._scrollX = 0
+		self._scrollY = 0
+		
+	def _init(self):
+		self._dragx = NOT_INITIALIZED
+		self._dragy = NOT_INITIALIZED
+		
+		self._setMode(SELECTING)
+		
+		self._initToolbarbuttons()
+		
+		events.keyPressed.connect(self.keyPressed)
+		events.keyReleased.connect(self.keyReleased)
+		
+		events.mousePressed.connect(self.mousePressed)
+		events.mouseDragged.connect(self.mouseDragged)
+		events.mouseReleased.connect(self.mouseReleased)
+		events.mouseMoved.connect(self.mouseMoved)
+		events.mouseWheelMovedUp.connect(self.mouseWheelMovedUp)
+		events.mouseWheelMovedDown.connect(self.mouseWheelMovedDown)
+		events.mouseExited.connect(self.mouseExited)
+		events.onPump.connect(self.pump)
+		
+	def _clear(self):
+		self._clearToolbarButtons()
+		
+		events.keyPressed.disconnect(self.keyPressed)
+		events.keyReleased.disconnect(self.keyReleased)
+		
+		events.mousePressed.disconnect(self.mousePressed)
+		events.mouseDragged.disconnect(self.mouseDragged)
+		events.mouseReleased.disconnect(self.mouseReleased)
+		events.mouseMoved.disconnect(self.mouseMoved)
+		events.mouseWheelMovedUp.disconnect(self.mouseWheelMovedUp)
+		events.mouseWheelMovedDown.disconnect(self.mouseWheelMovedDown)
+		events.mouseExited.disconnect(self.mouseExited)
+		events.onPump.disconnect(self.pump)
+		
+	def _mapChanged(self, sender, mapview):
+		self.setController(mapview.getController())
+		
+	def setObject(self, object):
+		self._object = object
+		
+	def setController(self, controller):
+		if self._controller is not None:
+			self._clear()
+
+		if controller is not None:
+			self._init()
+			
+		self._controller = controller
+		
+	def _initToolbuttons(self):
+		self._selectAction = Action(text=u"Select", icon="gui/icons/select_instance.png", checkable=True)
+		self._drawAction = Action(text=u"Draw", icon="gui/icons/add_instance.png", checkable=True)
+		self._removeAction = Action(text=u"Remove", icon="gui/icons/erase_instance.png", checkable=True)
+		self._moveAction = Action(text=u"Move", icon="gui/icons/move_instance.png", checkable=True)
+		self._objectpickerAction = Action(text=u"Pick object", icon="gui/icons/objectpicker.png", checkable=True)
+		
+		self._selectAction.helptext = u"Select cells on layer"
+		self._moveAction.helptext = u"Moves instances"
+		self._drawAction.helptext = u"Adds new instances based on currently selected object"
+		self._removeAction.helptext = u"Deletes instances"
+		self._objectpickerAction.helptext = u"Click an instance to set the current object to the one used by instance"
+		
+		action.toggled.connect(self._buttonToggled, sender=self._selectAction)
+		action.toggled.connect(self._buttonToggled, sender=self._moveAction)
+		action.toggled.connect(self._buttonToggled, sender=self._drawAction)
+		action.toggled.connect(self._buttonToggled, sender=self._removeAction)
+		action.toggled.connect(self._buttonToggled, sender=self._objectpickerAction)
+		
+		self._toolgroup = ActionGroup(exclusive=True, name=u"Tool group")
+		self._toolgroup.addAction(self._selectAction)
+		self._toolgroup.addAction(self._moveAction)
+		self._toolgroup.addAction(self._drawAction)
+		self._toolgroup.addAction(self._removeAction)
+		self._toolgroup.addAction(self._objectpickerAction)
+		
+		
+		self._toolbox.addAction(self._toolgroup)
+		self._toolbox.adaptLayout()
+		
+		self._editor._editMenu.addAction(self._toolgroup)
+		
+	def _initToolbarbuttons(self):
+		rotateLeftAction = Action(text=u"Rotate counterclockwise", icon="gui/icons/rotate_countercw.png")
+		rotateRightAction = Action(text=u"Rotate clockwise", icon="gui/icons/rotate_clockwise.png")
+		zoomInAction = Action(text=u"Zoom in", icon="gui/icons/zoom_in.png")
+		zoomOutAction = Action(text=u"Zoom out", icon="gui/icons/zoom_out.png")
+		zoomResetAction = Action(text=u"Reset zoom", icon="gui/icons/zoom_default.png")
+		
+		action.activated.connect(self.rotateCounterClockwise, sender=rotateLeftAction)
+		action.activated.connect(self.rotateClockwise, sender=rotateRightAction)
+		action.activated.connect(self.zoomIn, sender=zoomInAction)
+		action.activated.connect(self.zoomOut, sender=zoomOutAction)
+		action.activated.connect(self.resetZoom, sender=zoomResetAction)
+	
+		self._viewGroup = ActionGroup(name=u"View group")
+		self._viewGroup.addAction(rotateLeftAction)
+		self._viewGroup.addAction(rotateRightAction)
+		self._viewGroup.addAction(zoomInAction)
+		self._viewGroup.addAction(zoomOutAction)
+		self._viewGroup.addAction(zoomResetAction)
+		
+		self._toolbar.addAction(self._viewGroup)
+		self._toolbar.adaptLayout()
+		
+	def _clearToolbarButtons(self):
+		self._toolbar.removeAction(self._viewGroup)
+		self._toolbar.adaptLayout()
+		self._viewGroup = None
+		
+		
+	def _setMode(self, mode):
+		if (mode == INSERTING) and (not self._object):
+			self._statusbar.setText(u'Please select object first')
+			mode = self._mode
+
+		self._ignoreToggles = True
+		# Update toolbox buttons
+		if (mode == INSERTING):
+			self._drawAction.setChecked(True)
+		elif mode == REMOVING:
+			self._removeAction.setChecked(True)
+		elif mode == MOVING:
+			self._moveAction.setChecked(True)
+		elif mode == OBJECTPICKER:
+			self._objectpickerAction.setChecked(True)
+		else:
+			self._selectAction.setChecked(True)
+		self._ignoreToggles = False
+
+		self._mode = mode
+		print "Entered mode " + mode
+		self._statusbar.setText(mode.replace('_', ' ').capitalize())
+		
+	def _buttonToggled(self, sender, toggled):
+		if self._controller is None: return
+		if self._ignoreToggles is True: return
+	
+		mode = SELECTING
+		
+		if toggled:
+			if sender == self._selectAction:
+				mode = SELECTING
+			elif sender == self._moveAction:
+				mode = MOVING
+			elif sender == self._drawAction:
+				mode = INSERTING
+			elif sender == self._removeAction:
+				mode = REMOVING
+			elif sender == self._objectpickerAction:
+				mode = OBJECTPICKER
+
+		self._setMode(mode)
+		
+	def mouseExited(self, sender, event):
+		pass
+
+
+	def mousePressed(self, sender, event):
+		if event.isConsumedByWidgets():
+			return
+
+		realCoords = self._getRealCoords(sender, event)
+
+		if event.getButton() == fife.MouseEvent.MIDDLE:
+			self._dragx = realCoords[0]
+			self._dragy = realCoords[1]
+			
+		else:
+			if event.getButton() == fife.MouseEvent.RIGHT:
+				self._controller.deselectSelection()
+				
+			if self._mode == SELECTING:
+				if event.getButton() == fife.MouseEvent.LEFT:
+					if self._eventlistener.shiftPressed:
+						self._controller.deselectCell(realCoords[0], realCoords[1])
+					else:
+						if self._eventlistener.controlPressed is False:
+							self._controller.deselectSelection()
+						self._controller.selectCell(realCoords[0], realCoords[1])
+					
+				elif event.getButton() == fife.MouseEvent.RIGHT:
+					self._controller.deselectSelection()
+					
+			elif self._mode == INSERTING:
+				if event.getButton() == fife.MouseEvent.LEFT:
+					self._controller.deselectSelection()
+					self._controller.selectCell(realCoords[0], realCoords[1])
+					self._controller.getUndoManager().startGroup("Inserted instances")
+					self._undogroup = True
+					
+					position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
+					position = self._controller._layer.getCellGrid().toLayerCoordinates(position)
+					
+					self._controller.selectCell(realCoords[0], realCoords[1])
+					self._controller.placeInstance(position, self._object)
+				
+			elif self._mode == REMOVING:
+				if event.getButton() == fife.MouseEvent.LEFT:
+					self._controller.deselectSelection()
+					self._controller.selectCell(realCoords[0], realCoords[1])
+					self._controller.getUndoManager().startGroup("Removed instances")
+					self._undogroup = True
+					
+					self._controller.removeInstances(self._controller.getInstancesFromSelection())
+				
+			elif self._mode == MOVING:
+				if event.getButton() == fife.MouseEvent.LEFT:
+				
+					position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
+
+					self._lastDragPos = self._controller._layer.getCellGrid().toLayerCoordinates(position)
+					self._lastDragPosExact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position)
+	
+					for loc in self._controller._selection:
+						if loc.getLayerCoordinates() == self._lastDragPos:
+							break
+					else:
+						self._controller.deselectSelection()
+						self._controller.selectCell(realCoords[0], realCoords[1])
+						
+					self._instances = self._controller.getInstancesFromSelection()
+					
+					self._controller.getUndoManager().startGroup("Moved instances")
+					self._undogroup = True
+					
+			elif self._mode == OBJECTPICKER:
+				position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
+				exact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position)
+				instances = self._controller.getInstancesFromPosition(exact)
+				if len(instances) >= 1:
+					object = instances[0].getObject()
+					if object.getId() != self._object.getId() or object.getNamespace() != self._object.getNamespace():
+						events.onObjectSelected.send(sender=self, object=object)
+
+	def mouseDragged(self, sender, event):
+		if event.isConsumedByWidgets():
+			return
+			
+		realCoords = self._getRealCoords(sender, event)
+			
+		if event.getButton() == fife.MouseEvent.MIDDLE:
+			self._scrollX = (self._dragx-realCoords[0])/10.0
+			self._scrollY = (self._dragy-realCoords[1])/10.0
+		else:
+			if self._mode != SELECTING:
+				self._controller.deselectSelection()
+				
+			if self._mode == SELECTING:
+				if event.getButton() == fife.MouseEvent.LEFT:
+					if self._eventlistener.shiftPressed:
+						self._controller.deselectCell(realCoords[0], realCoords[1])
+					else:
+						self._controller.selectCell(realCoords[0], realCoords[1])
+					
+			elif self._mode == INSERTING:
+				position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
+				position = self._controller._layer.getCellGrid().toLayerCoordinates(position)
+				
+				self._controller.selectCell(realCoords[0], realCoords[1])
+				self._controller.placeInstance(position, self._object)
+				
+			elif self._mode == REMOVING:
+				self._controller.selectCell(realCoords[0], realCoords[1])
+				self._controller.removeInstances(self._controller.getInstancesFromSelection())
+				
+			elif self._mode == MOVING:
+				position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
+				
+				positionExact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position)
+				position = self._controller._layer.getCellGrid().toLayerCoordinates(position)
+				
+				if self._eventlistener.shiftPressed:
+					self._controller.moveInstances(self._instances, positionExact-self._lastDragPosExact, True)
+				else:
+					self._controller.moveInstances(self._instances, position-self._lastDragPos, False)
+				self._lastDragPos = position
+				self._lastDragPosExact = positionExact
+				
+				# Update selection
+				self._controller.deselectSelection()
+				
+				for i in self._instances:
+					pos = i.getLocation().getMapCoordinates()
+					pos = self._controller._camera.toScreenCoordinates(pos)
+					self._controller.selectCell(pos.x, pos.y)
+			elif self._mode == OBJECTPICKER:
+				pass
+
+	def mouseReleased(self, sender, event):
+		if event.isConsumedByWidgets():
+			return
+			
+		if self._mode == SELECTING or self._mode == MOVING:
+			instances = self._controller.getInstancesFromSelection()
+			if len(instances) > 0:
+				events.onInstancesSelected.send(sender=self, instances=instances)
+			
+		if event.getButton() == fife.MouseEvent.MIDDLE:
+			self._scrollX = 0
+			self._scrollY = 0
+			
+		realCoords = self._getRealCoords(sender, event)
+
+		if self._undogroup:
+			self._controller.getUndoManager().endGroup()
+			self._undogroup = False
+
+		self._dragx = NOT_INITIALIZED
+		self._dragy = NOT_INITIALIZED
+
+	def mouseMoved(self, sender, event):
+		pass
+				
+	def mouseWheelMovedUp(self, event):
+		if self._eventlistener.controlPressed and self._controller._camera:
+			self._controller._camera.setZoom(self._controller._camera.getZoom() * 1.10)
+
+	def mouseWheelMovedDown(self, event):
+		if self._eventlistener.controlPressed and self._controller._camera:
+			self._controller._camera.setZoom(self._controller._camera.getZoom() / 1.10)
+
+
+	def keyPressed(self, event):
+		keyval = event.getKey().getValue()
+		keystr = event.getKey().getAsString().lower()
+		
+		if keyval == fife.Key.LEFT:
+			self._controller.moveCamera(50, 0)
+		elif keyval == fife.Key.RIGHT:
+			self._controller.moveCamera(-50, 0)
+		elif keyval == fife.Key.UP:
+			self._controller.moveCamera(0, 50)
+		elif keyval == fife.Key.DOWN:
+			self._controller.moveCamera(0, -50)
+		
+		elif keyval == fife.Key.INSERT:
+			self._controller.fillSelection(self._object)
+
+		elif keyval == fife.Key.DELETE:
+			self._controller.clearSelection()
+			
+		elif keystr == "s":
+			self._setMode(SELECTING)
+			
+		elif keystr == "i":
+			if self._mode != INSERTING:
+				self._setMode(INSERTING)
+			else:
+				self._setMode(SELECTING)
+			
+		elif keystr == "r":
+			if self._mode != REMOVING:
+				self._setMode(REMOVING)
+			else:
+				self._setMode(SELECTING)
+
+		elif keystr == 'm':
+			if self._mode != MOVING:
+				self._setMode(MOVING)
+			else:
+				self._setMode(SELECTING)
+
+		elif keystr == 't':
+			gridrenderer = self._controller._camera.getRenderer('GridRenderer')
+			gridrenderer.setEnabled(not gridrenderer.isEnabled())
+
+		elif keystr == 'b':
+			blockrenderer = self._controller._camera.getRenderer('BlockingInfoRenderer')
+			blockrenderer.setEnabled(not blockrenderer.isEnabled())
+
+		elif keystr == 'z':
+			if self._eventlistener.controlPressed:
+				if self._eventlistener.altPressed:
+					if self._eventlistener.shiftPressed:
+						self._controller.getUndoManager().previousBranch()
+					else:
+						self._controller.getUndoManager().nextBranch()
+				else:
+					if self._eventlistener.shiftPressed:
+						self._controller.redo()
+					else:
+						self._controller.undo()
+			
+
+	def keyReleased(self, event):		
+		pass
+		
+	def zoomIn(self, zoom=1.10):
+		self._controller.setZoom(self._controller.getZoom()*zoom)
+		
+	def zoomOut(self, zoom=1.10):
+		self._controller.setZoom(self._controller.getZoom()/zoom)
+		
+	def resetZoom(self):
+		self._controller.setZoom(1)
+		
+	def rotateCounterClockwise(self):
+		self._controller.rotateCounterClockwise()
+		
+	def rotateClockwise(self):
+		self._controller.rotateClockwise()
+			
+	def _getRealCoords(self, sender, event):
+		cw = sender
+		offsetX = event.getX()
+		offsetY = event.getY()
+		
+		parent = cw
+		while parent is not None:
+			if isinstance(parent, widgets.Widget):
+				offsetX += parent.x
+				offsetY += parent.y
+				parent = parent.parent
+			else:
+				break
+			
+		return (offsetX, offsetY)
+		
+	def pump(self):
+		self._controller.moveCamera(self._scrollX, self._scrollY)
\ No newline at end of file