diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/clients/editor/scripts/mapcontroller.py	Mon Jun 08 16:00:02 2009 +0000
@@ -0,0 +1,289 @@
+import editor
+import pdb
+
+import math
+
+import fife
+import editor
+import events
+import undomanager
+
+class MapController(object):
+	""" MapController provides an interface for editing maps """
+	def __init__(self, map):
+		
+		self._editor = editor.getEditor()
+		self._engine = self._editor.getEngine()
+
+		self._camera = None     # currently selected camera
+		self._layer = None      # currently selected layer
+		self._selection = []	# currently selected cells
+		self._map = None
+		self._undo = False
+		self._undomanager = undomanager.UndoManager()
+		undomanager.preUndo.connect(self._startUndo, sender=self._undomanager)
+		undomanager.preRedo.connect(self._startUndo, sender=self._undomanager)
+		undomanager.postUndo.connect(self._endUndo, sender=self._undomanager)
+		undomanager.postRedo.connect(self._endUndo, sender=self._undomanager)
+		self.debug = False
+		
+		self.overwriteInstances = True # Remove instances on cell before placing new instance
+		
+		if map is not None:
+			self.setMap(map.getId())
+		
+	def setMap(self, mapid):
+		""" Set the map to be edited """
+		self._camera = None
+		self._map = None
+		self._layer = None
+		self._selection = []
+
+		self._map = self._engine.getModel().getMap(mapid)
+		if not self._map.getLayers():
+			raise AttributeError('Editor error: map ' + self._map.getId() + ' has no layers. Cannot edit.')
+
+		for cam in self._engine.getView().getCameras():
+			if cam.getLocationRef().getMap().getId() == self._map.getId():
+				self._camera = cam
+				break
+
+		self._layer = self._map.getLayers()[0]
+
+	def selectLayer(self, layerid):
+		""" Select layer to be edited """
+		self.deselectSelection()
+		self._layer = None
+		layers = [l for l in self._map.getLayers() if l.getId() == layerid]
+		if len(layers) == 1:
+			self._layer = layers[0]
+
+	def deselectSelection(self):
+		""" Deselects all selected cells """
+		if not self._camera: 
+			if self.debug: print 'No camera bind yet, cannot select any cell'
+			return
+		self._selection = []
+		fife.CellSelectionRenderer.getInstance(self._camera).reset()
+		
+	def clearSelection(self):
+		""" Removes all instances on selected cells """
+		instances = self.getInstancesFromSelection()
+		self._undomanager.startGroup("Cleared selection")
+		self.removeInstances(instances)
+		self._undomanager.endGroup()
+		
+	def fillSelection(self, object):
+		""" Adds an instance of object on each selected cell """
+		self._undomanager.startGroup("Filled selection")
+		for loc in self._selection:
+			self.placeInstance(loc.getLayerCoordinates(), object)
+		self._undomanager.endGroup()
+
+	def selectCell(self, screenx, screeny):
+		""" Selects a cell at a position on screen """
+		if not self._camera: 
+			if self.debug: print 'No camera bind yet, cannot select any cell'
+			return
+		if not self._layer:
+			if self.debug: print 'No layer assigned in selectCell'
+			return
+
+		mapCoords = self._camera.toMapCoordinates(fife.ScreenPoint(screenx, screeny), False)
+		position = self._layer.getCellGrid().toLayerCoordinates(mapCoords)
+		
+		loc = fife.Location(self._layer)
+		loc.setLayerCoordinates(position)
+		
+		for i in self._selection:
+			if loc == i: return
+			
+		self._selection.append( loc )
+		fife.CellSelectionRenderer.getInstance(self._camera).selectLocation(loc)
+		
+	def deselectCell(self, screenx, screeny):
+		""" Deselects a cell at a position on screen """
+		if not self._camera: 
+			if self.debug: print 'No camera bind yet, cannot select any cell'
+			return
+		if not self._layer:
+			if self.debug: print 'No layer assigned in selectCell'
+			return
+
+		mapCoords = self._camera.toMapCoordinates(fife.ScreenPoint(screenx, screeny), False)
+		position = self._layer.getCellGrid().toLayerCoordinates(mapCoords)
+		
+		loc = fife.Location(self._layer)
+		loc.setLayerCoordinates(position)
+		
+		for i in self._selection:
+			if loc == i:
+				self._selection.remove( loc )
+				fife.CellSelectionRenderer.getInstance(self._camera).deselectLocation(loc)
+				return
+		
+		
+	def getInstancesFromSelection(self):
+		""" Returns all instances in the selected cells """
+		instances = []
+		
+		for loc in self._selection:
+			instances.extend(self.getInstancesFromPosition(loc.getLayerCoordinates()))
+
+		return instances
+
+	def getInstancesFromPosition(self, position):
+		""" Returns all instances on a specified position """
+		if not self._layer:
+			if self.debug: print 'No layer assigned in getInstancesFromPosition'
+			return
+		if not position:
+			if self.debug: print 'No position assigned in getInstancesFromPosition'
+			return
+
+		loc = fife.Location(self._layer)
+		if type(position) == fife.ExactModelCoordinate:
+			loc.setExactLayerCoordinates(position)
+		else:
+			loc.setLayerCoordinates(position)
+			
+		instances = self._layer.getInstancesAt(loc)
+
+		return instances
+
+	def getUndoManager(self):
+		""" Returns undo manager """
+		return self._undomanager
+
+	def undo(self):
+		""" Undo one level """
+		self._undomanager.undo()
+
+	def redo(self):
+		""" Redo one level """
+		self._undomanager.redo()
+		
+	def _startUndo(self):
+		""" Called before a undo operation is performed. Makes sure undo stack does not get corrupted """
+		self._undo = True
+		
+	def _endUndo(self):
+		""" Called when a undo operation is done """
+		self._undo = False
+
+	def placeInstance(self, position, object):
+		""" Places an instance of object at position. Any existing instances on position are removed. """
+		mname = 'placeInstance'
+		if not object:
+			if self.debug: print 'No object assigned in %s' % mname
+			return
+		if not position:
+			if self.debug: print 'No position assigned in %s' % mname
+			return
+		if not self._layer:
+			if self.debug: print 'No layer assigned in %s' % mname
+			return
+
+		if self.debug: print 'Placing instance of ' + object.getId() + ' at ' + str(position)
+
+		# Remove instances from target position
+		if not self._undo:
+			self._undomanager.startGroup("Placed instance")
+			self.removeInstances(self.getInstancesFromPosition(position))
+
+		inst = self._layer.createInstance(object, position)
+		fife.InstanceVisual.create(inst)
+		
+		if not self._undo:
+			redocall = lambda: self.placeInstance(position, object)
+			undocall = lambda: self.removeInstances([inst])
+			undoobject = undomanager.UndoObject(undocall, redocall, "Placed instance")
+			self._undomanager.addAction(undoobject)
+			self._undomanager.endGroup()
+			
+	def removeInstances(self, instances):
+		""" Removes all provided instances """
+		mname = 'removeInstances'
+		if not instances:
+			if self.debug: print 'No instances assigned in %s' % mname
+			return
+			
+		for i in instances:
+			if self.debug: print 'Deleting instance ' + i.getObject().getId() + ' at ' + str(i.getLocation().getExactLayerCoordinates())
+			
+			if not self._undo:
+				object = i.getObject()
+				
+				position = i.getLocation().getExactLayerCoordinates()
+				undocall = lambda: self.placeInstance(position, object)
+				redocall = lambda: self.removeInstances([i])
+				undoobject = undomanager.UndoObject(undocall, redocall, "Removed instance")
+				self._undomanager.addAction(undoobject)
+				
+			self._layer.deleteInstance(i)
+
+	def moveInstances(self, instances, moveBy, exact=False):
+		""" Moves provided instances by moveBy. If exact is false, the instances are
+		snapped to closest cell. """
+		mname = 'moveInstances'
+		if not self._layer:
+			if self.debug: print 'No layer assigned in %s' % mname
+			return
+			
+		if exact and type(moveBy) != fife.ExactModelCoordinate:
+			moveBy = fife.ExactModelCoordinate(float(moveBy.x), float(moveBy.y), float(moveBy.z))
+		elif exact is False and type(moveBy) != fife.ModelCoordinate:
+			moveBy = fife.ModelCoordinate(int(round(moveBy.x)), int(round(moveBy.y)), int(round(moveBy.z)))
+			
+		for i in instances:
+			loc = i.getLocation()
+			f = i.getFacingLocation()
+			if exact:
+				newCoords = loc.getExactLayerCoordinates() + moveBy
+				loc.setExactLayerCoordinates(newCoords)
+				f.setExactLayerCoordinates(f.getExactLayerCoordinates() + moveBy)
+			else:
+				# Move instance and snap to closest cell
+				newCoords = loc.getLayerCoordinates() + moveBy
+				loc.setLayerCoordinates(newCoords)
+				f.setLayerCoordinates(f.getLayerCoordinates() + moveBy)
+			i.setLocation(loc)
+			i.setFacingLocation(f)
+
+	def rotateCounterClockwise(self):
+		""" Rotates map counterclockwise by 90 degrees """
+		currot = self._camera.getRotation()
+		self._camera.setRotation((currot + 270) % 360)
+		
+	def rotateClockwise(self):
+		""" Rotates map clockwise by 90 degrees """
+		currot = self._camera.getRotation()
+		self._camera.setRotation((currot + 90) % 360)
+		
+	def getZoom(self):
+		""" Returns camera zoom """
+		if not self._camera: 
+			if self.debug: print 'No camera bind yet, cannot get zoom'
+			return 0
+		return self._camera.getZoom()
+		
+	def setZoom(self, zoom):
+		""" Sets camera zoom """
+		if not self._camera: 
+			if self.debug: print 'No camera bind yet, cannot get zoom'
+			return
+		self._camera.setZoom(zoom)
+
+	def moveCamera(self, screen_x, screen_y):
+		""" Move camera (scroll) by screen_x, screen_y """
+		coords = self._camera.getLocationRef().getMapCoordinates()
+		z = self._camera.getZoom()
+		r = self._camera.getRotation()
+		if screen_x:
+			coords.x -= screen_x / z * math.cos(r / 180.0 * math.pi) / 100;
+			coords.y -= screen_x / z * math.sin(r / 180.0 * math.pi) / 100;
+		if screen_y:
+			coords.x -= screen_y / z * math.sin(-r / 180.0 * math.pi) / 100;
+			coords.y -= screen_y / z * math.cos(-r / 180.0 * math.pi) / 100;
+		coords = self._camera.getLocationRef().setMapCoordinates(coords)
+		self._camera.refresh()