Mercurial > fife-parpg
view clients/editor/scripts/mapcontroller.py @ 260:a0068e00f076
* Really fixed proper support for non-ascii filenames for FileBrowser
* Adjusted selection cursor hotspot
author | cheesesucker@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Mon, 08 Jun 2009 21:04:43 +0000 |
parents | 51cc05d862f2 |
children | 475f83e227e0 |
line wrap: on
line source
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()