def _initToolbarbuttons(self): """ Sets up and connects buttons related to the toolbar """ 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") screenshotAction = Action(text=u"Take screenshot", icon="gui/icons/take_screenshot.png") rotateLeftAction.helptext = u"Rotate counterclockwise by 90 degrees" rotateRightAction.helptext = u"Rotate clockwise by 90 degrees" zoomInAction.helptext = u"Zoom in (CTRL + Mousewheel up)" zoomOutAction.helptext = u"Zoom out (CTRL + Mousewheel down)" zoomResetAction.helptext = u"Reset zoom to default level" screenshotAction.helptext = u"Take screenshot (F7)" 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) action.activated.connect(self._captureScreen, sender=screenshotAction) 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._viewGroup.addAction(screenshotAction) self._toolbar.addAction(self._viewGroup) self._toolbar.adaptLayout()
def _initToolboxButtons(self): """ Sets up and connects buttons related to the toolbox """ 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 (S)" self._moveAction.helptext = u"Moves instances (M)" self._drawAction.helptext = u"Adds new instances based on currently selected object (I)" self._removeAction.helptext = u"Deletes instances (R)" 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._edit_menu.addAction(self._toolgroup)
def __init__(self): self.editor = scripts.editor.getEditor() self.engine = self.editor.getEngine() self._map = None self._layer = None self._mapdlg = None self._layerdlg = None self._cameradlg = None self._filebrowser = None self._importbrowser = None self._savebrowser = None newAction = Action(u"New map", "gui/icons/new_map.png") loadAction = Action(u"Open", "gui/icons/load_map.png") closeAction = Action(u"Close", "gui/icons/close_map.png") saveAction = Action(u"Save", "gui/icons/save_map.png") saveAsAction = Action(u"Save as", "gui/icons/save_mapas.png") saveAllAction = Action(u"Save all", "gui/icons/save_allmaps.png") importFileAction = Action(u"Import file", "gui/icons/import_file.png") importDirAction = Action(u"Import directory", "gui/icons/import_dir.png") newAction.helptext = u"Create new map" loadAction.helptext = u"Open existing map" closeAction.helptext = u"Close map" saveAction.helptext = u"Save map" saveAsAction.helptext = u"Save map as" saveAllAction.helptext = u"Save all opened maps" importFileAction.helptext = u"Imports an object file" importDirAction.helptext = u"Recursively imports all objects from a directory" action.activated.connect(self.showMapWizard, sender=newAction) action.activated.connect(self.showLoadDialog, sender=loadAction) action.activated.connect(self.closeCurrentMap, sender=closeAction) action.activated.connect(self.save, sender=saveAction) action.activated.connect(self.saveAs, sender=saveAsAction) action.activated.connect(self.editor.saveAll, sender=saveAllAction) self._importFileCallback = cbwa(self.showImportDialog, self.importFile, False) self._importDirCallback = cbwa(self.showImportDialog, self.importDir, True) action.activated.connect(self._importFileCallback, sender=importFileAction) action.activated.connect(self._importDirCallback, sender=importDirAction) eventlistener = self.editor.getEventListener() eventlistener.getKeySequenceSignal(fife.Key.N, ["ctrl"]).connect(self.showMapWizard) eventlistener.getKeySequenceSignal(fife.Key.O, ["ctrl"]).connect(self.showLoadDialog) eventlistener.getKeySequenceSignal(fife.Key.W, ["ctrl"]).connect(self.closeCurrentMap) eventlistener.getKeySequenceSignal(fife.Key.S, ["ctrl"]).connect(self.save) eventlistener.getKeySequenceSignal(fife.Key.S, ["ctrl", "shift"]).connect(self.editor.saveAll) fileGroup = ActionGroup() fileGroup.addAction(newAction) fileGroup.addAction(loadAction) fileGroup.addSeparator() fileGroup.addAction(closeAction) fileGroup.addSeparator() fileGroup.addAction(saveAction) fileGroup.addAction(saveAsAction) fileGroup.addAction(saveAllAction) fileGroup.addSeparator() fileGroup.addAction(importFileAction) fileGroup.addAction(importDirAction) self.editor.getToolBar().insertAction(fileGroup, 0) self.editor.getToolBar().insertSeparator(None, 1) self.editor._file_menu.insertAction(fileGroup, 0) self.editor._file_menu.insertSeparator(None, 1)
class MapEditor: """ This class provides a basic user interface for map editing. It allows the user to visually edit a map. """ # Editor states SELECTING = u"Selecting" INSERTING = u"Inserting" REMOVING = u"Removing" MOVING = u"Moving" OBJECTPICKER = u"Objectpicking" def __init__(self): """ Set up all variables and call some initial functions """ self._ignoreToggles = False # A hack to avoid infinite recursion when toggling a button self._controller = None self._mode = MapEditor.SELECTING self._debug = False # TODO: We should have a central system for activating debug messages # GUI self._editor = scripts.editor.getEditor() self._eventlistener = self._editor.getEventListener() self._statusbar = self._editor.getStatusBar() self._toolbar = self._editor.getToolBar() self._toolbox = self._editor.getToolbox() # Currently selected object type self._object = None # Variables used for moving instances self._last_drag_pos_exact = fife.ExactModelCoordinate(0,0,0) self._selected_instances = [] self._undogroup = False # Variables for scrolling the map self._dragx = 0 self._dragy = 0 self._scrollX = 0 self._scrollY = 0 self._initToolboxButtons() self._toolbox.show() events.postMapShown.connect(self._mapChanged) events.preMapClosed.connect(self._mapClosed) events.onObjectSelected.connect(self.setObject) def setObject(self, object): """ Set the object type to be paint onto map """ self._object = object def getObject(self): """ Return the current object """ return self._object def setController(self, controller): """ Set the controller to use. """ if self._controller is not None: self._clear() self._controller = controller if self._controller is not None: self._init() def _init(self): """ Sets up the mapeditor to work with the selected controller """ self._debug = self._controller.debug self._setMode(MapEditor.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.mouseEntered.connect(self.mouseEntered) events.mouseExited.connect(self.mouseExited) events.mouseWheelMovedUp.connect(self.mouseWheelMovedUp) events.mouseWheelMovedDown.connect(self.mouseWheelMovedDown) events.onPump.connect(self.pump) def _clear(self): """ Remove any functionality set up by _init """ 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.mouseExited.disconnect(self.mouseExited) events.mouseEntered.disconnect(self.mouseEntered) events.mouseWheelMovedUp.disconnect(self.mouseWheelMovedUp) events.mouseWheelMovedDown.disconnect(self.mouseWheelMovedDown) events.onPump.disconnect(self.pump) def _mapChanged(self, sender, mapview): """ Called when a new map is selected. Sets the mapeditor to control the mapcontroller in the new map """ self.setController(mapview.getController()) def _mapClosed(self, sender, mapview): """ Called when a map is closed. """ if mapview.getMap().getId() == self._controller.getMap().getId(): self.setController(None) def _updateCursor(self): """ Updates the cursor to reflect the mode of the editor """ engine = self._editor.getEngine() cursor = engine.getCursor() id = -1 if self._mode == MapEditor.SELECTING: image = engine.getImageManager().get("gui/icons/select_instance.png") id = image.getHandle() image.setXShift(-7) image.setYShift(-7) elif self._mode == MapEditor.INSERTING: image = engine.getImageManager().get("gui/icons/add_instance.png") id = image.getHandle() image.setXShift(-2) image.setYShift(-20) elif self._mode == MapEditor.REMOVING: image = engine.getImageManager().get("gui/icons/erase_instance.png") id = image.getHandle() image.setXShift(-2) image.setYShift(-19) elif self._mode == MapEditor.MOVING: image = engine.getImageManager().get("gui/icons/move_instance.png") id = image.getHandle() image.setXShift(-11) image.setYShift(-11) elif self._mode == MapEditor.OBJECTPICKER: image = engine.getImageManager().get("gui/icons/objectpicker.png") id = image.getHandle() image.setXShift(-0) image.setYShift(-22) if id < 0: self._resetCursor() else: cursor.set(image) def _resetCursor(self): """ Reset the cursor to the standard native one """ cursor = self._editor.getEngine().getCursor() cursor.set(fife.NC_ARROW) def _initToolboxButtons(self): """ Sets up and connects buttons related to the toolbox """ 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 (S)" self._moveAction.helptext = u"Moves instances (M)" self._drawAction.helptext = u"Adds new instances based on currently selected object (I)" self._removeAction.helptext = u"Deletes instances (R)" 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._edit_menu.addAction(self._toolgroup) def _initToolbarbuttons(self): """ Sets up and connects buttons related to the toolbar """ 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") screenshotAction = Action(text=u"Take screenshot", icon="gui/icons/take_screenshot.png") rotateLeftAction.helptext = u"Rotate counterclockwise by 90 degrees" rotateRightAction.helptext = u"Rotate clockwise by 90 degrees" zoomInAction.helptext = u"Zoom in (CTRL + Mousewheel up)" zoomOutAction.helptext = u"Zoom out (CTRL + Mousewheel down)" zoomResetAction.helptext = u"Reset zoom to default level" screenshotAction.helptext = u"Take screenshot (F7)" 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) action.activated.connect(self._captureScreen, sender=screenshotAction) 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._viewGroup.addAction(screenshotAction) self._toolbar.addAction(self._viewGroup) self._toolbar.adaptLayout() def _clearToolbarButtons(self): """ Remove toolbar buttons """ self._toolbar.removeAction(self._viewGroup) self._toolbar.adaptLayout() self._viewGroup = None def _setMode(self, mode): """ Set the editor mode """ if (mode == MapEditor.INSERTING) and (not self._object): self._statusbar.setText(u'Please select object first') mode = self._mode self._ignoreToggles = True # Update toolbox buttons if (mode == MapEditor.INSERTING): self._drawAction.setChecked(True) elif mode == MapEditor.REMOVING: self._removeAction.setChecked(True) elif mode == MapEditor.MOVING: self._moveAction.setChecked(True) elif mode == MapEditor.OBJECTPICKER: self._objectpickerAction.setChecked(True) else: self._selectAction.setChecked(True) self._ignoreToggles = False self._mode = mode if self._debug: print "Entered mode " + mode self._statusbar.setText(mode) self._updateCursor() 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): """ Resets zoom level to 1:1 """ self._controller.setZoom(1) def _rotateCounterClockwise(self): """ Rotates map counterclockwise """ self._controller.rotateCounterClockwise() def _rotateClockwise(self): """ Rotates map clockwise """ self._controller.rotateClockwise() def _captureScreen(self): """ Saves a screenshot to the users data directory """ userDir = fife_utils.getUserDataDirectory("fife", "editor") t = userDir+"/screenshots" if not os.path.isdir(t): os.makedirs(t) t += "/screen-%s-%s.png" % (date.today().strftime('%Y-%m-%d'), time.strftime('%H-%M-%S')) self._editor.getEngine().getRenderBackend().captureScreen(t) print "Saved screenshot to:", t def _buttonToggled(self, sender, toggled): """ Called when a button controlling the editor mode was activated """ if self._controller is None: return if self._ignoreToggles is True: return mode = MapEditor.SELECTING if toggled: if sender == self._selectAction: mode = MapEditor.SELECTING elif sender == self._moveAction: mode = MapEditor.MOVING elif sender == self._drawAction: mode = MapEditor.INSERTING elif sender == self._removeAction: mode = MapEditor.REMOVING elif sender == self._objectpickerAction: mode = MapEditor.OBJECTPICKER self._setMode(mode) def mousePressed(self, sender, event): if event.isConsumedByWidgets(): return if not self._controller._layer: if self._debug: print 'No layers active. Cancelling map action' 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 == MapEditor.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 == MapEditor.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.screenToMapCoordinates(realCoords[0], realCoords[1]) position = self._controller._layer.getCellGrid().toLayerCoordinates(position) self._controller.selectCell(realCoords[0], realCoords[1]) self._controller.placeInstance(position, self._object) elif self._mode == MapEditor.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 == MapEditor.MOVING: if event.getButton() == fife.MouseEvent.LEFT: self._last_drag_pos = self._controller.screenToMapCoordinates(realCoords[0], realCoords[1]) self._last_drag_cell = self._controller._layer.getCellGrid().toLayerCoordinates(self._last_drag_pos) if self._controller._single_instance: self._selected_instances = self._controller.getInstance() else: self._selected_instances = self._controller.getInstancesFromSelection() self._controller.getUndoManager().startGroup("Moved instances") self._undogroup = True elif self._mode == MapEditor.OBJECTPICKER: position = self._controller.screenToMapCoordinates(realCoords[0], realCoords[1]) 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 if not self._controller._layer: if self._debug: print 'No layers active. Cancelling map action' 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 != MapEditor.SELECTING: self._controller.deselectSelection() if self._mode == MapEditor.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 == MapEditor.INSERTING: position = self._controller.screenToMapCoordinates(realCoords[0], realCoords[1]) position = self._controller._layer.getCellGrid().toLayerCoordinates(position) self._controller.selectCell(realCoords[0], realCoords[1]) self._controller.placeInstance(position, self._object) elif self._mode == MapEditor.REMOVING: self._controller.selectCell(realCoords[0], realCoords[1]) self._controller.removeInstances(self._controller.getInstancesFromSelection()) elif self._mode == MapEditor.MOVING: position = self._controller.screenToMapCoordinates(realCoords[0], realCoords[1]) cell = self._controller._layer.getCellGrid().toLayerCoordinates(position) if self._eventlistener.shiftPressed: res = self._controller.moveInstances( self._selected_instances, position - self._last_drag_pos, exact = True) else: res = self._controller.moveInstances( self._selected_instances, self._controller._layer.getCellGrid().toMapCoordinates(cell) - self._controller._layer.getCellGrid().toMapCoordinates(self._last_drag_cell), exact = False) # update only if the instances moved if res: self._last_drag_pos = position self._last_drag_cell = cell # Update selection self._controller.deselectSelection() for i in self._selected_instances: pos = i.getLocation().getMapCoordinates() pos = self._controller._camera.toScreenCoordinates(pos) self._controller.selectCell(pos.x, pos.y) elif self._mode == MapEditor.OBJECTPICKER: pass def mouseReleased(self, sender, event): if event.isConsumedByWidgets(): return if not self._controller._layer: if self._debug: print 'No layers active. Cancelling map action' return if self._mode == MapEditor.SELECTING or self._mode == MapEditor.MOVING: instances = self._controller.getInstancesFromSelection() if len(instances) > 0: events.onInstancesSelected.send(sender=self, instances=instances) if self._mode == MapEditor.SELECTING: locations = self._controller.getLocationsFromSelection() if len(locations) > 0: events.onCellSelected.send(sender=self, locations=locations) 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 def mouseMoved(self, sender, event): pass def mouseEntered(self, sender, event): # Mouse has entered map area. Set cursor to reflect current mode self._updateCursor() def mouseExited(self, sender, event): # Mouse has exited the map area. Set the cursor to native arrow self._resetCursor() def mouseWheelMovedUp(self, event): # Zoom in if self._eventlistener.controlPressed and self._controller._camera: self._controller._camera.setZoom(self._controller._camera.getZoom() * 1.10) def mouseWheelMovedDown(self, event): # Zoom out 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 keyval == fife.Key.PAGE_UP: if self._eventlistener.controlPressed: if self._controller._single_instance: self._selected_instances = self._controller.getInstance() elif self._controller.getInstancesFromSelection(): self._selected_instances = self._controller.getInstancesFromSelection() elif self._controller.getAllInstances(): self._selected_instances = self._controller.getAllInstances() if self._selected_instances: self._controller.moveInstances(self._selected_instances, fife.ExactModelCoordinate(0, 0, 1), exact=False) elif keyval == fife.Key.PAGE_DOWN: if self._eventlistener.controlPressed: if self._controller._single_instance: self._selected_instances = self._controller.getInstance() elif self._controller.getInstancesFromSelection(): self._selected_instances = self._controller.getInstancesFromSelection() elif self._controller.getAllInstances(): self._selected_instances = self._controller.getAllInstances() if self._selected_instances: self._controller.moveInstances(self._selected_instances, fife.ExactModelCoordinate(0, 0, -1), exact=False) elif keyval == fife.Key.F7: self.captureScreen() elif keystr == "s": self._setMode(MapEditor.SELECTING) elif keystr == "i": if self._mode != MapEditor.INSERTING: self._setMode(MapEditor.INSERTING) else: self._setMode(MapEditor.SELECTING) elif keystr == "r": if self._mode != MapEditor.REMOVING: self._setMode(MapEditor.REMOVING) else: self._setMode(MapEditor.SELECTING) elif keystr == 'm': if self._mode != MapEditor.MOVING: self._setMode(MapEditor.MOVING) else: self._setMode(MapEditor.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 == 'c': self._editor.toggleCoordinates("Toggle Coordinates") 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 _getRealCoords(self, sender, event): """ Converts relative widget coordinate to absolute coordinates """ 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): """ Called each frame """ # Scroll camera self._controller.moveCamera(self._scrollX, self._scrollY)
def __init__(self): from fife import fife self.editor = scripts.editor.getEditor() self.engine = self.editor.getEngine() self._map = None self._layer = None self._mapdlg = None self._layerdlg = None self._cameradlg = None self._filebrowser = None self._importbrowser = None self._savebrowser = None newAction = Action(u"New map", "gui/icons/new_map.png") loadAction = Action(u"Open", "gui/icons/load_map.png") closeAction = Action(u"Close", "gui/icons/close_map.png") saveAction = Action(u"Save", "gui/icons/save_map.png") saveAsAction = Action(u"Save as", "gui/icons/save_mapas.png") saveAllAction = Action(u"Save all", "gui/icons/save_allmaps.png") importFileAction = Action(u"Import file", "gui/icons/import_file.png") importDirAction = Action(u"Import directory", "gui/icons/import_dir.png") newAction.helptext = u"Create new map" loadAction.helptext = u"Open existing map" closeAction.helptext = u"Close map" saveAction.helptext = u"Save map" saveAsAction.helptext = u"Save map as" saveAllAction.helptext = u"Save all opened maps" importFileAction.helptext = u"Imports an object file" importDirAction.helptext = u"Recursively imports all objects from a directory" action.activated.connect(self.showMapWizard, sender=newAction) action.activated.connect(self.showLoadDialog, sender=loadAction) action.activated.connect(self.closeCurrentMap, sender=closeAction) action.activated.connect(self.save, sender=saveAction) action.activated.connect(self.saveAs, sender=saveAsAction) action.activated.connect(self.editor.saveAll, sender=saveAllAction) self._importFileCallback = cbwa(self.showImportDialog, self.importFile, False) self._importDirCallback = cbwa(self.showImportDialog, self.importDir, True) action.activated.connect(self._importFileCallback, sender=importFileAction) action.activated.connect(self._importDirCallback, sender=importDirAction) eventlistener = self.editor.getEventListener() eventlistener.getKeySequenceSignal(fife.Key.N, ["ctrl"]).connect( self.showMapWizard) eventlistener.getKeySequenceSignal(fife.Key.O, ["ctrl"]).connect( self.showLoadDialog) eventlistener.getKeySequenceSignal(fife.Key.W, ["ctrl"]).connect( self.closeCurrentMap) eventlistener.getKeySequenceSignal(fife.Key.S, ["ctrl"]).connect(self.save) eventlistener.getKeySequenceSignal( fife.Key.S, ["ctrl", "shift"]).connect(self.editor.saveAll) fileGroup = ActionGroup() fileGroup.addAction(newAction) fileGroup.addAction(loadAction) fileGroup.addSeparator() fileGroup.addAction(closeAction) fileGroup.addSeparator() fileGroup.addAction(saveAction) fileGroup.addAction(saveAsAction) fileGroup.addAction(saveAllAction) fileGroup.addSeparator() fileGroup.addAction(importFileAction) fileGroup.addAction(importDirAction) self.editor.getToolBar().insertAction(fileGroup, 0) self.editor.getToolBar().insertSeparator(None, 1) self.editor._file_menu.insertAction(fileGroup, 0) self.editor._file_menu.insertSeparator(None, 1)
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.preMapClosed.connect(self._mapClosed) 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.mouseEntered.connect(self.mouseEntered) events.mouseExited.connect(self.mouseExited) events.mouseWheelMovedUp.connect(self.mouseWheelMovedUp) events.mouseWheelMovedDown.connect(self.mouseWheelMovedDown) events.onPump.connect(self.pump) events.layerSelected.connect(self._layerSelected) 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.mouseExited.disconnect(self.mouseExited) events.mouseEntered.disconnect(self.mouseEntered) events.mouseWheelMovedUp.disconnect(self.mouseWheelMovedUp) events.mouseWheelMovedDown.disconnect(self.mouseWheelMovedDown) events.onPump.disconnect(self.pump) events.layerSelected.disconnect(self._layerSelected) def _mapChanged(self, sender, mapview): self.setController(mapview.getController()) def _mapClosed(self, sender, mapview): self.setController(None) def _setCursor(self): engine = self._editor.getEngine() cursor = engine.getCursor() id = -1 if self._mode == SELECTING: id = engine.getImagePool().addResourceFromFile("gui/icons/select_instance.png") image = engine.getImagePool().getImage(id) image.setXShift(-7) image.setYShift(-7) elif self._mode == INSERTING: id = engine.getImagePool().addResourceFromFile("gui/icons/add_instance.png") image = engine.getImagePool().getImage(id) image.setXShift(-2) image.setYShift(-20) elif self._mode == REMOVING: id = engine.getImagePool().addResourceFromFile("gui/icons/erase_instance.png") image = engine.getImagePool().getImage(id) image.setXShift(-2) image.setYShift(-19) elif self._mode == MOVING: id = engine.getImagePool().addResourceFromFile("gui/icons/move_instance.png") image = engine.getImagePool().getImage(id) image.setXShift(-11) image.setYShift(-11) elif self._mode == OBJECTPICKER: id = engine.getImagePool().addResourceFromFile("gui/icons/objectpicker.png") image = engine.getImagePool().getImage(id) image.setXShift(-0) image.setYShift(-22) if id < 0: self._resetCursor() else: cursor.set(fife.CURSOR_IMAGE, id) def _resetCursor(self): cursor = self._editor.getEngine().getCursor() cursor.set(fife.CURSOR_NATIVE, fife.NC_ARROW) def _layerSelected(self, sender, mapcontroller, layer): gridrenderer = self._controller._camera.getRenderer('GridRenderer') gridrenderer.clearActiveLayers() if layer is not None: gridrenderer.addActiveLayer(self._controller.getLayer()) blockrenderer = self._controller._camera.getRenderer('BlockingInfoRenderer') blockrenderer.clearActiveLayers() if layer is not None: blockrenderer.addActiveLayer(self._controller.getLayer()) 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 (S)" self._moveAction.helptext = u"Moves instances (M)" self._drawAction.helptext = u"Adds new instances based on currently selected object (I)" self._removeAction.helptext = u"Deletes instances (R)" 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._edit_menu.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") screenshotAction = Action(text=u"Take screenshot", icon="gui/icons/take_screenshot.png") rotateLeftAction.helptext = u"Rotate counterclockwise by 90 degrees" rotateRightAction.helptext = u"Rotate clockwise by 90 degrees" zoomInAction.helptext = u"Zoom in (CTRL + Mousewheel up)" zoomOutAction.helptext = u"Zoom out (CTRL + Mousewheel down)" zoomResetAction.helptext = u"Reset zoom to default level" screenshotAction.helptext = u"Take screenshot (F7)" 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) action.activated.connect(self.captureScreen, sender=screenshotAction) 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._viewGroup.addAction(screenshotAction) 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()) self._setCursor() 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 mousePressed(self, sender, event): if event.isConsumedByWidgets(): return if not self._controller._layer: if self._controller.debug: print 'No layers active. Cancelling map action' 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 if not self._controller._layer: if self._controller.debug: print 'No layers active. Cancelling map action' 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 not self._controller._layer: if self._controller.debug: print 'No layers active. Cancelling map action' 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 mouseEntered(self, sender, event): self._setCursor() def mouseExited(self, sender, event): self._resetCursor() 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 keyval == fife.Key.F7: self.captureScreen() 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()) gridrenderer.clearActiveLayers() if self._controller.getLayer() is not None: gridrenderer.addActiveLayer(self._controller.getLayer()) 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 captureScreen(self): userDir = fife_utils.getUserDataDirectory("fife", "editor") t = userDir+"/screenshots" if not os.path.isdir(t): os.makedirs(t) t += "/screen-%s-%s.png" % (date.today().strftime('%Y-%m-%d'), time.strftime('%H-%M-%S')) self._editor.getEngine().getRenderBackend().captureScreen(t) print "Saved screenshot to:", t def pump(self): self._controller.moveCamera(self._scrollX, self._scrollY)