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