# -*- coding: UTF-8 -*- from common import * from editorui.editorcommon import * from editorui.editormain import * import os import os.path class KPPathNodeList(QtGui.QWidget): class KPPathNodeItem(QtGui.QTreeWidgetItem): def __init__(self, parent, layer, associate): QtGui.QTreeWidgetItem.__init__(self, parent) self.layer = layer self.associate = associate self.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) def data(self, index, role=Qt.DisplayRole): if role == Qt.DecorationRole: if isinstance(self.associate, KPNode): node = self.associate if node.level: return KP.icon('BlackLevel') elif node.mapChange != None: return KP.icon('Exit') elif len(node.exits) != 2: return KP.icon('Stop') else: return KP.icon('Through') else: return KP.icon('LayerPath') elif role == Qt.DisplayRole: if isinstance(self.associate, KPNode): node = self.associate if node.level: return "Level: {0}".format(node.level) elif node.mapChange != None: return "Exit: World {0}, entrance {1}".format(node.mapID, node.foreignID) elif len(node.exits) == 3: return "Node: 3-way Junction" elif len(node.exits) == 4: return "Node: 4-way Junction" elif (len(node.exits) == 1) or (len(node.exits) == 0): return "Node: End Point" elif len(node.exits) > 4: return "Illegal Node" else: return "Node: Pass-Through" else: AnimationList = ["Walk", "WalkSand", "WalkSnow", "WalkIce", "Jump", "JumpSand", "JumpSnow", "SpinJump", "Ladder", "LadderLeft", "LadderRight", "Fall", "Swim", "Run", "Pipe", "Door"] animation = AnimationList[self.associate.animation] if self.associate.secret == 0: unlock = 'Normal' else: unlock = 'Secret' return 'Path: {0} Exit, {1}'.format(unlock, animation) elif role == Qt.CheckStateRole: return (Qt.Checked if self.layer.visible else Qt.Unchecked) else: return QtGui.QTreeWidgetItem.data(self, index, role) def setData(self, column, role = Qt.EditRole, value = None): if role == Qt.CheckStateRole: self.layer.visible = value.toBool() def layer(self): return self.layer def associate(self): return self.associate def __init__(self): QtGui.QWidget.__init__(self) self.layout = QtGui.QVBoxLayout() self.layout.setSpacing(0) self.tree = QtGui.QTreeWidget() self.tree.setColumnCount(1) self.tree.setDragEnabled(True) self.tree.setDragDropMode(self.tree.InternalMove) self.tree.setHeaderHidden(True) self.tree.itemClicked.connect(self.handleRowChanged) self.layout.addWidget(self.tree) self.toolbar = QtGui.QToolBar() self.layout.addWidget(self.toolbar) self.setupToolbar(self.toolbar) self.setLayout(self.layout) def reset(self): self.tree.clear() for layer in KP.map.associateLayers: self.loadLayer(layer) def setupToolbar(self, tb): self.actAddFolder = tb.addAction(KP.icon('NewFolder'), 'Add Folder', self.addFolder) self.actRemoveFolder = tb.addAction(KP.icon('DelFolder'), 'Remove Folder', self.removeFolder) self.selectTileset = tb.addAction(KP.icon('LayerNewTile'), 'Select Tileset', self.setTileset) selectedLayerChanged = QtCore.pyqtSignal(KPLayer) @QtCore.pyqtSlot() def handleRowChanged(self): item = self.tree.currentItem() try: self.selectedLayerChanged.emit(item.layer) except: pass def addFolder(self): item = QtGui.QTreeWidgetItem(self.tree) item.setIcon(0, KP.icon('Folder')) item.setText(0, 'Untitled Folder') item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled | Qt.ItemIsEditable | Qt.ItemIsEnabled) def removeFolder(self): item = self.tree.currentItem() if not isinstance(item, self.KPPathNodeItem): kids = item.takeChildren() parent = item.parent() if parent: parent.takeChild(item) else: self.tree.takeTopLevelItem(self.tree.currentIndex().row()) self.tree.addTopLevelItems(kids) def setTileset(self): from dialogs import KPTilesetChooserDialog tilesetName = KPTilesetChooserDialog.run('Choose a tileset for the path/node layers') if tilesetName is None: return KP.map.pathNodeTileset = tilesetName def addLayer(self, associate): layer = KPPathTileLayer(associate) item = self.KPPathNodeItem(self.tree, layer, associate) def loadLayer(self, layer): item = self.KPPathNodeItem(self.tree, layer, layer.associate) def removeLayer(self, associate): trash = None for itemI in xrange(self.tree.topLevelItemCount()): item = self.tree.topLevelItem(itemI) if item.associate == associate: trash = item else: trash = self.removeRecursor(item, associate) if trash != None: break parent = trash.parent() if parent: parent.takeChild(trash) else: self.tree.takeTopLevelItem(self.tree.indexOfTopLevelItem(trash)) def removeRecursor(self, parent, associate): trash = None for itemI in xrange(parent.childCount()): item = parent.child(itemI) if item.associate == associate: trash = item else: trash = self.removeRecursor(item, associate) if trash != None: return trash return None def getLayers(self): layerList = [] for itemI in xrange(self.tree.topLevelItemCount()): item = self.tree.topLevelItem(itemI) if not isinstance(item, self.KPPathNodeItem): self.recursiveLayerRetriever(item, layerList) else: layerList.append(item.layer) return layerList def recursiveLayerRetriever(self, parent, layerList): for itemI in xrange(parent.childCount()): item = parent.child(itemI) if not isinstance(item, self.KPPathNodeItem): self.recursiveLayerRetriever(item, layerList) else: layerList.append(item.layer) class KPLayerList(QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) self.layout = QtGui.QVBoxLayout() self.layout.setSpacing(0) self.listView = QtGui.QListView() self.layout.addWidget(self.listView) self.toolbar = QtGui.QToolBar() self.layout.addWidget(self.toolbar) self.setupToolbar(self.toolbar) self.updateModel() self.setLayout(self.layout) def updateModel(self): self.model = KP.map.layerModel self.listView.setModel(self.model) self.listView.clicked.connect(self.handleRowChanged) self.setButtonStates() def setupToolbar(self, tb): self.actAddTile = tb.addAction(KP.icon('LayerNewTile'), 'Add Tile Layer', self.addTileLayer) self.actAddDoodad = tb.addAction(KP.icon('LayerNewObjects'), 'Add Doodad Layer', self.addDoodadLayer) self.actRemove = tb.addAction(KP.icon('LayerRemove'), 'Remove', self.removeLayer) self.actMoveUp = tb.addAction(QtGui.QIcon(), 'Move Up', self.moveUp) self.actMoveDown = tb.addAction(QtGui.QIcon(), 'Move Down', self.moveDown) self.actPlayPause = tb.addAction(KP.icon('APlay'), 'Play', self.toggleAnimatingScene) playPaused = QtCore.pyqtSignal() def toggleAnimatingScene(self): self.playPaused.emit() def setButtonStates(self): index = self.selectedLayerIndex() layer = KP.map.layers[index] self.actRemove.setEnabled( (index != -1) and (len(KP.map.layers) > 1) and (not isinstance(layer, KPPathLayer))) self.actMoveUp.setEnabled(index > 0) self.actMoveDown.setEnabled((index != -1) and (index < (len(KP.map.layers) - 1))) def selectedLayerIndex(self): return self.listView.selectionModel().currentIndex().row() def selectedLayer(self): return KP.map.layers[self.selectedLayerIndex()] selectedLayerChanged = QtCore.pyqtSignal(KPLayer) @QtCore.pyqtSlot(QtCore.QModelIndex) def handleRowChanged(self, current): self.selectedLayerChanged.emit(KP.map.layers[current.row()]) self.setButtonStates() def addTileLayer(self): from dialogs import KPTilesetChooserDialog tilesetName = KPTilesetChooserDialog.run('Choose a tileset for the new layer') if tilesetName is None: return layer = KP.map.createNewTileLayer(tilesetName) KP.map.appendLayer(layer) self.setButtonStates() def addDoodadLayer(self): layer = KP.map.createNewDoodadLayer() KP.map.appendLayer(layer) self.setButtonStates() def removeLayer(self): layer = self.selectedLayer() scene = KP.mainWindow.scene if isinstance(layer, KPPathLayer): return for obj in layer.objects: item = obj.qtItem if item: scene.removeItem(item) KP.map.removeLayer(self.selectedLayer()) self.setButtonStates() def moveUp(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, index - 1) KP.mainWindow.editor.viewport().update() def moveDown(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, index + 2) KP.mainWindow.editor.viewport().update() def moveTop(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, 0) KP.mainWindow.editor.viewport().update() def moveBottom(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, len(KP.map.layers)) KP.mainWindow.editor.viewport().update() class KPDoodadSelector(QtGui.QWidget): def __init__(self): """Initialises the widget.""" QtGui.QWidget.__init__(self) self.layout = QtGui.QVBoxLayout() self.layout.setSpacing(0) self.listView = QtGui.QListView() self.listView.setViewMode(self.listView.IconMode) self.listView.setWrapping(True) self.listView.setDragDropMode(self.listView.DragOnly) self.listView.setSelectionMode(self.listView.SingleSelection) self.listView.setResizeMode(self.listView.Adjust) self.listView.setGridSize(QtCore.QSize(128, 128)) self.listView.setIconSize(QtCore.QSize(100, 100)) self.listView.setSpacing(4) self.toolbar = QtGui.QToolBar() self.addDoodadButton = self.toolbar.addAction(QtGui.QIcon(), 'Add', self.addDoodadFromFile) self.removeDoodadButton = self.toolbar.addAction(QtGui.QIcon(), 'Remove', self.removeDoodad) self.updateModel() self.layout.addWidget(self.toolbar) self.layout.addWidget(self.listView) self.setLayout(self.layout) def updateModel(self): self.model = KP.map.doodadModel self.listView.setModel(self.model) self.listView.selectionModel().currentRowChanged.connect(self.handleRowChanged) self.setButtonStates() def keyPressEvent(self, event): self.listView.keyPressEvent(event) if event.key() == QtCore.Qt.Key_Delete or event.key() == QtCore.Qt.Key_Backspace: doodad = self.selectedDoodad() if doodad is None: return # TODO: Check if selected msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Warning, "Delete Doodad?", "Are you sure you want to delete this doodad? This action cannot be undone.", QtGui.QMessageBox.NoButton, self) msgBox.addButton("Delete", QtGui.QMessageBox.AcceptRole) msgBox.addButton("Cancel", QtGui.QMessageBox.RejectRole) if msgBox.exec_() == QtGui.QMessageBox.AcceptRole: KP.map.removeDoodad(doodad) # def addDoodad(self, image, name): # # TODO: REMOVE # """Takes a name and a QPixmap and turns it into an icon, then goes ahead and makes a doodad. # Doodads are QListWidget items with an index number as Qt.UserRole #32.""" # doodie = QtGui.QListWidgetItem(QtGui.QIcon(image), name) # # !! # doodie.setSizeHint(QtCore.QSize(128,128)) # doodie.setData(32, self.nextIndex) # doodie.setToolTip(name) # doodie.setTextAlignment(Qt.AlignBottom | Qt.AlignHCenter) # self.doodadList.addItem(doodie) # self.nextIndex += 1 def addDoodadFromFile(self): """Asks the user for files to load in as doodads.""" files = QtGui.QFileDialog.getOpenFileNames(self, "Choose an image or several image files.", "", "Images (*.png *.jpeg *.jpg *.bmp)") if files: for image in files: name = os.path.basename(unicode(image)).split('.')[0] pix = QtGui.QPixmap() pix.load(image) KP.map.addDoodad(name, pix) def removeDoodad(self): """Removes selected doodad""" item = self.selectedDoodad() if item: KP.map.removeDoodad(item) def setButtonStates(self): index = self.selectedDoodadIndex() self.removeDoodadButton.setEnabled(index != -1) def selectedDoodadIndex(self): return self.listView.selectionModel().currentIndex().row() def selectedDoodad(self): return KP.map.doodadDefinitions[self.listView.selectionModel().currentIndex().row()] selectedDoodadChanged = QtCore.pyqtSignal(object) @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex) def handleRowChanged(self, current, previous): self.selectedDoodadChanged.emit(KP.map.doodadDefinitions[current.row()]) self.setButtonStates() class KPObjectSelector(QtGui.QWidget): def __init__(self): """Initialises the widget. Remember to call setModel() on it with a KPGroupModel whenever the layer changes.""" QtGui.QWidget.__init__(self) self.menuSetup = False self.sorterButton = QtGui.QToolButton() self.sorterButton.setText('Pick a Layer') self.sorterButton.setEnabled(False) self.sorterButton.setPopupMode(self.sorterButton.InstantPopup) self.sorterButton.setToolButtonStyle(Qt.ToolButtonTextOnly) self.sorterButton.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.sorterMenu = QtGui.QMenu() self.sorterButton.setMenu(self.sorterMenu) self.layout = QtGui.QVBoxLayout() self.layout.setSpacing(0) self.toolbar = QtGui.QToolBar() self.toolbar.setFixedHeight(28) self.toolbar.addWidget(self.sorterButton) self.layout.addWidget(self.toolbar) self.listView = QtGui.QListView() self.listView.setFlow(QtGui.QListView.LeftToRight) self.listView.setLayoutMode(QtGui.QListView.SinglePass) self.listView.setMovement(QtGui.QListView.Static) self.listView.setResizeMode(QtGui.QListView.Adjust) self.listView.setWrapping(True) self.listView.setEnabled(False) self.layout.addWidget(self.listView) self.setLayout(self.layout) self.model = None # Borrowed the signals and junk from Reggie, figure we'll need em' # Some more signals are set in setModel self.listView.clicked.connect(self.handleObjReplace) self.sorterMenu.aboutToShow.connect(self.fixUpMenuSize) self.sorterMenu.triggered.connect(self.toggleTopLevel) def beginUsingMenu(self): if self.menuSetup: return font = QtGui.QFont() font.setPixelSize(18) font.setBold(True) self.sorterButton.setFont(font) self.sorterButton.setEnabled(True) self.menuSetup = True def fixUpMenuSize(self): self.sorterMenu.setFixedWidth(self.sorterButton.width()) def currentSelectedObject(self): """Returns the currently selected object reference, for painting purposes.""" index = self.listView.currentIndex().row() object = self.model.groupItem().getItem(index) return object def setModel(self, model): """Sets the model and the menu sorting list""" if model == self.model: return self.model = model self.listView.setModel(model) self.listView.setEnabled(True) model.view = self.listView menuList = model.groupItem().getGroupList() self.beginUsingMenu() string = QtCore.QString(QtCore.QChar(0x25BE)) string.append(' All Groups') self.sorterButton.setText(string) self.sorterMenu.clear() for item in menuList: actionMan = self.sorterMenu.addAction(item[0]) actionMan.setData((item[1], item[2])) # a Quick Fix self.listView.setRowHidden(0, True) # set up signals self.listView.selectionModel().currentRowChanged.connect(self.handleRowChanged) def toggleTopLevel(self, action): """Changes the top level group in the list view.""" name = str(action.text()).strip() startRow = action.data().toPyObject()[0] + 1 endRow = action.data().toPyObject()[1] for row in xrange(self.model.rowCount()): if (row < startRow) or (row > endRow): self.listView.setRowHidden(row, True) else: self.listView.setRowHidden(row, False) string = QtCore.QString(QtCore.QChar(0x25BE)) string.append(' ' + name) self.sorterButton.setText(string) @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex) def handleRowChanged(self, current, previous): """Throws a signal emitting the current object when changed""" i = current.row() object, depth = self.model.groupItem().getItem(i) self.objChanged.emit(i, object) def handleObjReplace(self, index): """Throws a signal when the selected object is used as a replacement""" if QtGui.QApplication.keyboardModifiers() == QtCore.Qt.AltModifier: i = current.row() object, depth = self.model.groupItem().getItem(i) self.objReplaced.emit(i, object) objChanged = QtCore.pyqtSignal(int, KPTileObject) objReplaced = QtCore.pyqtSignal(int, KPTileObject) class KPMainWindow(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) self.setWindowTitle('Koopatlas') self.setWindowIcon(QtGui.QIcon('Resources/Koopatlas.png')) self.setIconSize(QtCore.QSize(16, 16)) self.scene = KPMapScene() self.editor = KPEditorWidget(self.scene) self.setCentralWidget(self.editor) self.ZoomLevel = 5 self.setupDocks() self.setupMenuBar() self.refreshMapState() def _createAction(self, internalName, callback, title): act = QtGui.QAction(title, self) act.triggered.connect(callback) self.actions[internalName] = act return act def setupActions(self): self.actions = {} self._createAction('new', self.newMap, '&New') self._createAction('open', self.openMap, '&Open...') self._createAction('save', self.saveMap, '&Save') self._createAction('saveAs', self.saveMapAs, 'Save &As...') def setupMenuBar(self): mb = self.menuBar() from PyQt4.QtGui import QKeySequence f = mb.addMenu('&File') self.fa = f.addAction('New', self.newMap, QKeySequence("Ctrl+N")) self.fb = f.addAction('Open...', self.openMap, QKeySequence("Ctrl+O")) self.fc = f.addAction('Open Recent') # f.addSeparator() self.fd = f.addAction('Save', self.saveMap, QKeySequence("Ctrl+S")) self.fe = f.addAction('Save As...', self.saveMapAs, QKeySequence("Ctrl+Shift+S")) self.ff = f.addAction('Export...', self.exportMap, QKeySequence("Ctrl+Shift+E")) f.addSeparator() self.fg = f.addAction('Take Screenshot...', self.screenshot, QKeySequence("Ctrl+Alt+S")) f.addSeparator() # self.fi = f.addAction('Quit') e = mb.addMenu('Edit') self.ea = e.addAction('Copy') # C self.eb = e.addAction('Cut') # X self.ec = e.addAction('Paste') # V e.addSeparator() self.ed = e.addAction('Select All', self.selectAll, QKeySequence.SelectAll) self.ee = e.addAction('Deselect', self.deSelect, QKeySequence("Ctrl+D")) l = mb.addMenu('Layers') self.la = l.addAction('Add Tileset Layer', self.layerList.addTileLayer, QKeySequence("Ctrl+T")) self.lb = l.addAction('Add Doodad Layer', self.layerList.addDoodadLayer, QKeySequence("Ctrl+R")) self.lc = l.addAction('Remove Layer', self.layerList.removeLayer, QKeySequence("Ctrl+Del")) l.addSeparator() self.ld = l.addAction('Move Layer Up', self.layerList.moveUp, QKeySequence("Ctrl+Up")) self.le = l.addAction('Move Layer Down', self.layerList.moveDown, QKeySequence("Ctrl+Down")) self.lf = l.addAction('Move Layer to Top', self.layerList.moveTop, QKeySequence("Ctrl+Shift+Up")) self.lg = l.addAction('Move Layer to Bottom', self.layerList.moveBottom, QKeySequence("Ctrl+Shift+Down")) l.addSeparator() self.li = l.addAction('Add Doodad...', self.doodadSelector.addDoodadFromFile, QKeySequence("Ctrl+Shift+R")) self.lh = l.addAction('Add Tileset...', self.moveTilesetToFolder, QKeySequence("Ctrl+Shift+T")) self.lj = l.addAction('Change Tileset...', self.changeTileset, QKeySequence("Ctrl+Shift+Alt+T")) a = mb.addMenu('Animate') self.aa = a.addAction('Play Animations', self.playAnim, QKeySequence("Ctrl+P")) self.ac = a.addAction('Reset Animations', self.resetAnim, QKeySequence("Ctrl+Shift+P")) a.addSeparator() self.ad = a.addAction('Load Animation Presets...', self.loadAnimPresets) self.ae = a.addAction('Save Animation Presets...', self.saveAnimPresets) self.af = a.addAction('Clear Animation Presets', self.clearAnimPresets) w = mb.addMenu('Window') self.wa = w.addAction('Show Grid', self.showGrid, QKeySequence("Ctrl+G")) w.addSeparator() self.wb = w.addAction('Zoom In', self.ZoomIn, QKeySequence.ZoomIn) self.wc = w.addAction('Zoom Out', self.ZoomOut, QKeySequence.ZoomOut) self.wd = w.addAction('Actual Size', self.ZoomActual, QKeySequence("Ctrl+=")) self.wh = w.addAction('Show Wii Zoom', self.showWiiZoom) w.addSeparator() layerAction = self.layerListDock.toggleViewAction() layerAction.setShortcut(QKeySequence("Ctrl+1")) w.addAction(layerAction) objectAction = self.objectSelectorDock.toggleViewAction() objectAction.setShortcut(QKeySequence("Ctrl+2")) w.addAction(objectAction) doodadAction = self.doodadSelectorDock.toggleViewAction() doodadAction.setShortcut(QKeySequence("Ctrl+3")) w.addAction(doodadAction) h = mb.addMenu('Help') self.ha = h.addAction('About Koopatlas', self.aboutDialog) self.hb = h.addAction('Koopatlas Documentation', self.goToHelp) # self.hc = h.addAction('Keyboard Shortcuts') def setupDocks(self): self.layerList = KPLayerList() self.layerListDock = QtGui.QDockWidget('Layers') self.layerListDock.setWidget(self.layerList) self.layerList.selectedLayerChanged.connect(self.handleSelectedLayerChanged) self.layerList.playPaused.connect(self.playAnim) self.pathNodeList = KPPathNodeList() self.pathNodeDock = QtGui.QDockWidget('Path/Node Layers') self.pathNodeDock.setWidget(self.pathNodeList) self.pathNodeList.selectedLayerChanged.connect(self.handleSelectedPathNodeLayerChanged) self.objectSelector = KPObjectSelector() self.objectSelector.objChanged.connect(self.handleSelectedObjectChanged) self.objectSelectorDock = QtGui.QDockWidget('Objects') self.objectSelectorDock.setWidget(self.objectSelector) self.objectSelectorDock.hide() self.doodadSelector = KPDoodadSelector() self.doodadSelector.selectedDoodadChanged.connect(self.handleSelectedDoodadChanged) self.doodadSelectorDock = QtGui.QDockWidget('Doodads') self.doodadSelectorDock.setWidget(self.doodadSelector) self.doodadSelectorDock.hide() self.addDockWidget(Qt.RightDockWidgetArea, self.layerListDock) self.addDockWidget(Qt.RightDockWidgetArea, self.pathNodeDock) self.addDockWidget(Qt.RightDockWidgetArea, self.objectSelectorDock) self.addDockWidget(Qt.RightDockWidgetArea, self.doodadSelectorDock) def refreshMapState(self): self.layerList.updateModel() self.doodadSelector.updateModel() self.pathNodeList.reset() self.scene = KPMapScene() self.editor.assignNewScene(self.scene) self.updateTitlebar() def updateTitlebar(self): path = KP.map.filePath if path is None: effectiveName = 'Untitled Map' else: effectiveName = os.path.basename(path) self.setWindowTitle('%s - Koopatlas' % effectiveName) def checkDirty(self): return False ##################### # Slots for Widgets # ##################### @QtCore.pyqtSlot(KPLayer) def handleSelectedLayerChanged(self, layer): sel = self.pathNodeList.tree.selectionModel() if sel: sel.clearSelection() self.scene.setCurrentLayer(layer) showObjects, showDoodads = False, False if isinstance(layer, KPDoodadLayer): showDoodads = True elif isinstance(layer, KPTileLayer): KP.map.reloadTileset(layer.tileset) showObjects = True self.objectSelector.setModel(KP.map.loadedTilesets[layer.tileset].getModel()) self.objectSelectorDock.setVisible(showObjects) self.doodadSelectorDock.setVisible(showDoodads) @QtCore.pyqtSlot(KPLayer) def handleSelectedPathNodeLayerChanged(self, layer): sel = self.layerList.listView.selectionModel() if sel: sel.clearSelection() self.scene.setCurrentLayer(layer) KP.map.reloadTileset(KP.map.pathNodeTileset) self.objectSelector.setModel(KP.map.loadedTilesets[KP.map.pathNodeTileset].getModel()) self.objectSelectorDock.setVisible(True) self.doodadSelectorDock.setVisible(True) @QtCore.pyqtSlot(int, KPTileObject) def handleSelectedObjectChanged(self, index, obj): sel = self.doodadSelector.listView.selectionModel() if sel: sel.clearSelection() self.editor.objectToPaint = obj self.editor.objectIDToPaint = index self.editor.typeToPaint = 'object' @QtCore.pyqtSlot(object) def handleSelectedDoodadChanged(self, doodad): sel = self.objectSelector.listView.selectionModel() if sel: sel.clearSelection() self.editor.doodadToPaint = doodad self.editor.typeToPaint = 'doodad' ######################## # Slots for Menu Items # ######################## # File ######################## def newMap(self): if self.checkDirty(): return KP.map = KPMap() self.refreshMapState() def openMap(self): if self.checkDirty(): return target = unicode(QtGui.QFileDialog.getOpenFileName( self, 'Open Map', '', 'Koopatlas map (*.kpmap)')) if len(target) == 0: return import mapfile obj = mapfile.load(open(target, 'rb').read()) obj.filePath = target KP.map = obj self.refreshMapState() def saveMap(self, forceNewName=False): target = KP.map.filePath if target is None or forceNewName: dialogDir = '' if target is None else os.path.dirname(target) target = unicode(QtGui.QFileDialog.getSaveFileName( self, 'Save Map', dialogDir, 'Koopatlas map (*.kpmap)')) if len(target) == 0: return KP.map.filePath = target self.updateTitlebar() KP.map.save() def saveMapAs(self): self.saveMap(True) def exportMap(self): target = KP.map.filePath dialogDir = '' if target is None else os.path.dirname(target) target = unicode(QtGui.QFileDialog.getSaveFileName( self, 'Export Map', dialogDir, 'Koopatlas binary map (*.kpbin)')) if len(target) == 0: return KP.map.export(target) @QtCore.pyqtSlot() def screenshot(self): items = ("Current Window", "Entire Map") item, ok = QtGui.QInputDialog.getItem(self, "QInputDialog.getItem()", "Choose a Screenshot Source:", items, 0, False) if ok and item: fn = QtGui.QFileDialog.getSaveFileName(self, 'Choose a new filename', 'untitled.png', 'Portable Network Graphics (*.png)') if fn == '': return fn = unicode(fn) if item == "Current Window": ScreenshotImage = QtGui.QImage(self.editor.width(), self.editor.height(), QtGui.QImage.Format_ARGB32) ScreenshotImage.fill(QtCore.Qt.transparent) RenderPainter = QtGui.QPainter(ScreenshotImage) self.editor.render(RenderPainter, QtCore.QRectF(0,0,self.editor.width(), self.editor.height()), QtCore.QRect(QtCore.QPoint(0,0), QtCore.QSize(self.editor.width(), self.editor.height()))) RenderPainter.end() else: ScreenshotImage = QtGui.QImage(self.scene.itemsBoundingRect().width()+100, self.scene.itemsBoundingRect().height()+100, QtGui.QImage.Format_ARGB32) ScreenshotImage.fill(QtCore.Qt.transparent) RenderPainter = QtGui.QPainter(ScreenshotImage) self.scene.render(RenderPainter, QtCore.QRectF(ScreenshotImage.rect()), self.scene.itemsBoundingRect().adjusted(-50.0, -50.0, 50.0, 50.0)) RenderPainter.end() ScreenshotImage.save(fn, 'PNG', 50) # Edit ######################## @QtCore.pyqtSlot() def selectAll(self): path = QtGui.QPainterPath() path.addRect(self.scene.sceneRect()) self.scene.setSelectionArea(path) @QtCore.pyqtSlot() def deSelect(self): self.scene.clearSelection() # Layers ######################## @QtCore.pyqtSlot() def moveTilesetToFolder(self): path = QtGui.QFileDialog.getOpenFileName(self, "Choose a tileset. Tileset will be copied to the Koopatlas Tilesets Folder.", "", "Koopuzzle Tilesets (*.arc)") if path: import shutil import os from hashlib import sha256 as sha name = os.path.basename(path[:-4]) shutil.copy(path, 'Tilesets') filehandler = open(path) data = filehandler.read() filehandler.close() hash = sha(data).hexdigest() KP.map.tilesets[name] = {'path': path, 'hash': hash} KP.map.loadedTilesets[name] = KPTileset.loadFromArc(path) @QtCore.pyqtSlot() def changeTileset(self): layer = self.layerList.selectedLayer() if not isinstance(layer, KPTileLayer): return from dialogs import KPTilesetChooserDialog tilesetName = KPTilesetChooserDialog.run('Choose a tileset to change to') if tilesetName is None: return KPTileLayer.tileset = tilesetName self.objectSelector.setModel(KP.map.loadedTilesets[layer.tileset].getModel()) # Animate ######################## @QtCore.pyqtSlot() def playAnim(self): self.scene.playPause() self.playButtonChanged() @QtCore.pyqtSlot() def playButtonChanged(self): if self.scene.playing: self.aa.setText('Stop Animations') self.layerList.actPlayPause.setIcon(KP.icon('AStop')) self.layerList.actPlayPause.setText('Stop') else: self.aa.setText('Play Animations') self.layerList.actPlayPause.setIcon(KP.icon('APlay')) self.layerList.actPlayPause.setText('Play') @QtCore.pyqtSlot() def resetAnim(self): if self.scene.playing == True: self.scene.playPause() self.scene.playPause() @QtCore.pyqtSlot() def loadAnimPresets(self): path = QtGui.QFileDialog.getOpenFileName(self, "Choose a Koopatlas Animation Preset File.", "", "Koopatlas Animation Preset (*.kpa)") if path: import mapfile file = open(path, 'rb') data = file.read() loaded = mapfile.load(data) file.close() print loaded settings = KP.app.settings presetList = [] presets = [] if settings.contains('AnimationPresets'): presetList = mapfile.load(str(settings.value('AnimationPresets').toPyObject())) presets = mapfile.load(str(settings.value('AnimationPresetData').toPyObject())) if presetList == None: presetList = [] presets = [] print presetList, presets print dir(presetList) presetList.extend(loaded[0]) presets.extend(loaded[1]) print presetList print presets settings.setValue('AnimationPresets', mapfile.dump(presetList)) settings.setValue('AnimationPresetData', mapfile.dump(presets)) @QtCore.pyqtSlot() def saveAnimPresets(self): settings = KP.app.settings import mapfile msg = QtGui.QMessageBox() msg.setText("No Animation Presets Found.") if settings.contains('AnimationPresets'): presetList = mapfile.load(str(settings.value('AnimationPresets').toPyObject())) presets = mapfile.load(str(settings.value('AnimationPresetData').toPyObject())) else: msg._exec() return if len(presetList) == 0: msg._exec() return path = QtGui.QFileDialog.getSaveFileName(self, "Choose a tileset. Tileset will be copied to the Koopatlas Tilesets Folder.", "KP Preset.kpa", "Koopatlas Animation Preset (*.kpa)") if path: import mapfile output = [presetList, presets] file = open(path, 'wb') file.write(mapfile.dump(output)) file.close() @QtCore.pyqtSlot() def clearAnimPresets(self): settings = KP.app.settings import mapfile settings.setValue('AnimationPresets', mapfile.dump([])) settings.setValue('AnimationPresetData', mapfile.dump([])) # Window ######################## @QtCore.pyqtSlot() def ZoomActual(self): """Handle zooming to the editor size""" self.ZoomLevel = 5 self.ZoomTo() @QtCore.pyqtSlot() def ZoomIn(self): """Handle zooming in""" self.ZoomLevel += 1 self.ZoomTo() @QtCore.pyqtSlot() def ZoomOut(self): """Handle zooming out""" self.ZoomLevel -= 1 self.ZoomTo() def ZoomTo(self): """Zoom to a specific level""" tr = QtGui.QTransform() zooms = [5.0, 10.0, 25.0, 50.0, 75.0, 100.0, 150.0, 200.0, 400.0] scale = zooms[self.ZoomLevel] / 100.0 tr.scale(scale, scale) self.editor.setTransform(tr) self.wb.setEnabled(self.ZoomLevel != 8) self.wc.setEnabled(self.ZoomLevel != 0) self.wd.setEnabled(self.ZoomLevel != 5) self.scene.update() @QtCore.pyqtSlot() def showGrid(self): """Handle toggling of the grid being showed""" # settings.setValue('GridEnabled', checked) if self.scene.grid == True: self.scene.grid = False else: self.scene.grid = True print self.scene.grid self.scene.update() @QtCore.pyqtSlot(bool) def showWiiZoom(self): pass # Help ######################## @QtCore.pyqtSlot(bool) def aboutDialog(self): caption = "About Koopatlas" text = "Koopatlas

The Koopatlas Editor is an editor for custom two dimensional world maps, for use with the Newer SMBWii world map engine. It should be included with its companion program, Koopuzzle, which will create tilesets compatible with Koopatlas.

Koopatlas was programmed by Treeki and Tempus of the Newer Team.

Find the website at html://www.newerteam.com for more information." msg = QtGui.QMessageBox.about(KP.mainWindow, caption, text) @QtCore.pyqtSlot(bool) def goToHelp(self): QtGui.QDesktopServices().openUrl(QtCore.QUrl('http://www.newerteam.com/koopatlas-help'))