# -*- 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.LeftDockWidgetArea, self.objectSelectorDock)
self.addDockWidget(Qt.LeftDockWidgetArea, 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'))