summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/editorui/editormain.py126
-rw-r--r--src/editorui/paths.py4
-rw-r--r--src/mapdata.py95
-rw-r--r--src/ui.py222
4 files changed, 408 insertions, 39 deletions
diff --git a/src/editorui/editormain.py b/src/editorui/editormain.py
index 5575453..46660f4 100644
--- a/src/editorui/editormain.py
+++ b/src/editorui/editormain.py
@@ -20,7 +20,7 @@ class KPMapScene(QtGui.QGraphicsScene):
self.ticker.setLoopCount(0)
self.ticker.setCurveShape(4)
self.ticker.setFrameRange(0,100000)
- self.ticker.valueChanged.connect(self.thing)
+ self.ticker.valueChanged.connect(self.viewportUpdateProxy)
self.ticker.setUpdateInterval(16.6666666666667)
self.grid = False
@@ -64,7 +64,7 @@ class KPMapScene(QtGui.QGraphicsScene):
@QtCore.pyqtSlot(int)
- def thing(self, value):
+ def viewportUpdateProxy(self, value):
self.views()[0].viewport().update()
@@ -249,6 +249,68 @@ class KPMapScene(QtGui.QGraphicsScene):
srcY += 1
destY += 24
+
+ elif isinstance(layer, KPPathLayer):
+ for pnLayer in reversed(KP.mainWindow.pathNodeList.getLayers()):
+
+ # Render Tiles
+ left, top = pnLayer.cacheBasePos
+ width, height = pnLayer.cacheSize
+ right, bottom = left+width, top+height
+
+ if not (width == 0) or (height == 0) or (right < areaLeftT) or (left > areaRightT) or (bottom < areaTopT) or (top > areaBottomT):
+
+ drawLeft = int(max(areaLeftT, left))
+ drawRight = int(min(areaRightT, right))
+
+ drawTop = int(max(areaTopT, top))
+ drawBottom = int(min(areaBottomT, bottom))
+
+ srcY = drawTop - top
+ destY = drawTop * 24
+
+ baseSrcX = drawLeft - left
+ baseDestX = drawLeft * 24
+
+ rows = pnLayer.cache
+ tileset = KP.map.loadedTilesets[KP.map.pathNodeTileset]
+ tileList = tileset.tiles
+
+ for y in xrange(drawTop, drawBottom):
+ srcX = baseSrcX
+ destX = baseDestX
+ row = rows[srcY]
+
+ for x in xrange(drawLeft, drawRight):
+ tile = row[srcX]
+ if tile != -1:
+ painter.drawPixmap(destX, destY, tileList[tile])
+
+ srcX += 1
+ destX += 24
+
+ srcY += 1
+ destY += 24
+
+ # Render Doodads
+ try:
+ toDraw = visibleDoodadsByLayer[pnLayer]
+ except KeyError:
+ continue
+
+ for item in reversed(toDraw):
+
+ painter.save()
+
+ if self.playing == False:
+ painter.setWorldTransform(item.sceneTransform(), True)
+ p = item._boundingRect
+ painter.drawPixmap(p.x(), p.y(), p.width(), p.height(), item.pixmap)
+
+ else:
+ self.animateDoodad(painter, item)
+ painter.restore()
+
def animateDoodad(self, painter, item):
@@ -317,7 +379,7 @@ class KPEditorWidget(QtGui.QGraphicsView):
self.setVerticalScrollBar(self.yScrollBar)
self.assignNewScene(scene)
-
+
def assignNewScene(self, scene):
self.setScene(scene)
self.centerOn(0,0)
@@ -326,6 +388,8 @@ class KPEditorWidget(QtGui.QGraphicsView):
self.objectToPaint = None
self.objectIDToPaint = None
self.doodadToPaint = None
+ self.typeToPaint = None
+
self._resetPaintVars()
def _resetPaintVars(self):
@@ -430,6 +494,7 @@ class KPEditorWidget(QtGui.QGraphicsView):
path = KPPath(sourceNode, destNode)
KP.map.pathLayer.paths.append(path)
+ KP.mainWindow.pathNodeList.addLayer(path)
item = KPEditorPath(path)
self.scene().addItem(item)
@@ -444,6 +509,7 @@ class KPEditorWidget(QtGui.QGraphicsView):
node = KPNode()
node.position = (x - 12, y - 12)
KP.map.pathLayer.nodes.append(node)
+ KP.mainWindow.pathNodeList.addLayer(node)
# Start node => Original path => New node => New path => End node
@@ -464,6 +530,7 @@ class KPEditorWidget(QtGui.QGraphicsView):
newPath = KPPath(node, endNode, origPath)
KP.map.pathLayer.paths.append(newPath)
+ KP.mainWindow.pathNodeList.addLayer(newPath)
pathItem = KPEditorPath(newPath)
self.scene().addItem(pathItem)
@@ -474,6 +541,7 @@ class KPEditorWidget(QtGui.QGraphicsView):
node = KPNode()
node.position = (x - 12, y - 12)
KP.map.pathLayer.nodes.append(node)
+ KP.mainWindow.pathNodeList.addLayer(node)
item = KPEditorNode(node)
self.scene().addItem(item)
@@ -499,6 +567,7 @@ class KPEditorWidget(QtGui.QGraphicsView):
path = KPPath(sourceNode, node)
KP.map.pathLayer.paths.append(path)
+ KP.mainWindow.pathNodeList.addLayer(path)
pathItem = KPEditorPath(path)
self.scene().addItem(pathItem)
@@ -512,6 +581,57 @@ class KPEditorWidget(QtGui.QGraphicsView):
self.paintingItem = item
self.paintBeginPosition = (x - 12, y - 12)
+ elif isinstance(layer, KPPathTileLayer):
+ if self.typeToPaint == 'object':
+ paint = self.objectToPaint
+ if paint is None: return
+
+ clicked = self.mapToScene(event.x(), event.y())
+ x, y = clicked.x(), clicked.y()
+ if x < 0: x = 0
+ if y < 0: y = 0
+
+ x = int(x / 24)
+ y = int(y / 24)
+
+ obj = KPObject()
+ obj.position = (x,y)
+ obj.size = (1,1)
+ obj.tileset = layer.tileset
+ obj.kind = paint
+ obj.updateCache()
+ layer.objects.append(obj)
+ layer.updateCache()
+
+ item = KPEditorObject(obj, layer)
+ self.scene().addItem(item)
+
+ self.painting = obj
+ self.paintingItem = item
+ self.paintBeginPosition = (x, y)
+
+ elif self.typeToPaint == 'doodad':
+
+ paint = self.doodadToPaint
+ if paint is None: return
+
+ clicked = self.mapToScene(event.x(), event.y())
+ x, y = clicked.x(), clicked.y()
+ if x < 0: x = 0
+ if y < 0: y = 0
+
+ obj = KPDoodad()
+ obj.position = [x,y]
+ obj.source = paint
+ obj.setDefaultSize()
+ layer.doodads.append(obj)
+
+ item = KPEditorDoodad(obj, layer)
+ self.scene().addItem(item)
+
+ self.painting = obj
+ self.paintingItem = item
+ self.paintBeginPosition = (x, y)
def _movedWhilePainting(self, event):
diff --git a/src/editorui/paths.py b/src/editorui/paths.py
index 617e981..55bfac0 100644
--- a/src/editorui/paths.py
+++ b/src/editorui/paths.py
@@ -325,6 +325,7 @@ class KPEditorNode(KPEditorItem):
layer = KP.map.pathLayer
layer.nodes.remove(node)
+ KP.mainWindow.pathNodeList.removeLayer(node)
if len(node.exits) == 2:
# let's try to join the two!
@@ -354,6 +355,7 @@ class KPEditorNode(KPEditorItem):
if not nope:
joinedPath = KPPath(start, end, pathOne)
+ KP.mainWindow.pathNodeList.addLayer(joinedPath)
layer.paths.append(joinedPath)
item = KPEditorPath(joinedPath)
self.scene().addItem(item)
@@ -501,7 +503,6 @@ class KPEditorPath(QtGui.QGraphicsLineItem):
self.setPalette(palette)
-
class UnlockButton(QtGui.QPushButton):
def __init__(self, pathRef):
QtGui.QPushButton.__init__(self)
@@ -682,6 +683,7 @@ class KPEditorPath(QtGui.QGraphicsLineItem):
path = self._pathRef()
layer = KP.map.pathLayer
+ KP.mainWindow.pathNodeList.removeLayer(path)
layer.paths.remove(path)
diff --git a/src/mapdata.py b/src/mapdata.py
index b8ab263..6f71daf 100644
--- a/src/mapdata.py
+++ b/src/mapdata.py
@@ -147,27 +147,30 @@ class KPTileLayer(KPLayer):
y += 1
-@mapfile.dumpable('tile_layer')
-class KPPathTileLayer(KPTileLayer):
- __dump_attribs__ = KPLayer.__dump_attribs__ + ('tileset', 'objects')
+@mapfile.dumpable('associate_layer')
+class KPPathTileLayer(KPLayer):
+ __dump_attribs__ = KPLayer.__dump_attribs__ + ('tileset', 'objects', 'doodads', 'associate')
+
+ def _load(self, mapObj, src):
+ self.updateCache()
def __repr__(self):
- return "<KPPathTileLayer %r with %r connected to %r>" % (self.name, self.tileset, self.pathnode)
+ return "<KPPathTileLayer with %r connected to %r>" % (self.tileset, self.associate)
def __init__(self, pathnode):
KPLayer.__init__(self)
self.tileset = KP.map.pathNodeTileset
self.objects = []
self.doodads = []
- self.pathnode = pathnode
+ self.associate = pathnode
self.cache = ['DUMMY_FLAG']
self.updateCache()
self.icon = KP.icon('LayerTile')
- def getPathNode(self):
- return self.pathnode
+ def associate(self):
+ return self.associate
def _visibilityChanged(self, value):
for obj in self.objects:
@@ -180,6 +183,71 @@ class KPPathTileLayer(KPTileLayer):
if item:
item.setVisible(value)
+ def setActivated(self, value, listToUse=None):
+ flag1 = QtGui.QGraphicsItem.ItemIsSelectable
+ flag2 = QtGui.QGraphicsItem.ItemIsMovable
+
+ if listToUse is None:
+ listToUse = self.objects + self.doodads
+
+ for obj in listToUse:
+ item = obj.qtItem
+ if item:
+ item.setFlag(flag1, value)
+ item.setFlag(flag2, value)
+
+ def updateCache(self):
+ if len(self.objects) == 0:
+ if len(self.cache) != 0:
+ self.cache = []
+ self.cacheBasePos = (0,0)
+ self.cacheSize = (0,0)
+ return
+
+ x1, x2 = MAP_SIZE_IN_TILES[0] - 1, 0
+ y1, y2 = MAP_SIZE_IN_TILES[1] - 1, 0
+
+ for obj in self.objects:
+ x, y = obj.position
+ w, h = obj.size
+ right, bottom = (x+w-1), (y+h-1)
+
+ if x < x1:
+ x1 = x
+ if y < y1:
+ y1 = y
+ if right > x2:
+ x2 = right
+ if bottom > y2:
+ y2 = bottom
+
+
+ # create the cache
+ # I was going to just resize it, but setting every tile to -1
+ # in Python would probably be slower than creating a new one ...
+ size = (x2 - x1 + 1, y2 - y1 + 1)
+ width, height = size
+
+ cache = [[-1 for i in xrange(width)] for j in xrange(height)]
+ self.cache = cache
+
+ self.cacheBasePos = (x1, y1)
+ self.cacheSize = size
+
+ # now generate the thing
+ for obj in self.objects:
+ oX, oY = obj.position
+ baseX = oX - x1
+ y = oY - y1
+
+ for row in obj.cache:
+ destRow = cache[y]
+ x = baseX
+ for tile in row:
+ destRow[x] = tile
+ x += 1
+ y += 1
+
@mapfile.dumpable('doodad')
class KPDoodad(object):
@@ -275,11 +343,6 @@ class KPDoodadLayer(KPLayer):
item.setVisible(value)
-class KPNodeAction(object):
- def __init__(self):
- pass
-
-
@mapfile.dumpable('node')
class KPNode(object):
__dump_attribs__ = (
@@ -402,7 +465,7 @@ class KPPathLayer(KPLayer):
@mapfile.dumpable('map_root')
class KPMap(object):
- __dump_attribs__ = ('layers', 'nextLayerNumber', 'doodadDefinitions')
+ __dump_attribs__ = ('layers', 'nextLayerNumber', 'doodadDefinitions', 'pathNodeTileset')
def _preload(self, src):
# we need this early so we can use the deref methods!
@@ -447,13 +510,15 @@ class KPMap(object):
self.loadTilesets()
try:
- self.pathNodeTileset = self.tilesets[0]
+ self.pathNodeTileset = self.tilesets.keys()[0]
except:
+ # TODO: This should probably error out or something. Seriously.
+ # It'll ruin the path or object layers if there are NO tilesets.
self.pathNodeTileset = ''
# LAYERS
- class LayerModel(QtCore.QAbstractItemModel):
+ class LayerModel(QtCore.QAbstractListModel):
def __init__(self, layerList):
QtCore.QAbstractListModel.__init__(self)
self.list = layerList
diff --git a/src/ui.py b/src/ui.py
index db9d409..13d0039 100644
--- a/src/ui.py
+++ b/src/ui.py
@@ -8,6 +8,76 @@ 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)
+
+
+ def data(self, index, role=Qt.DisplayRole):
+
+ if role == Qt.DecorationRole:
+ if isinstance(self.associate, KPNode):
+ node = self.associate
+
+ if node.level:
+ return QtGui.QIcon('LevelNodeIcon')
+ elif node.mapChange != None:
+ return QtGui.QIcon('ExitNodeIcon')
+ elif len(node.exits) != 2:
+ return QtGui.QIcon('StopNodeIcon')
+ else:
+ return QtGui.QIcon('ThroughNodeIcon')
+
+ else:
+ return QtGui.QIcon('PathIcon')
+
+ elif role == Qt.DisplayRole:
+ if isinstance(self.associate, KPNode):
+ node = self.associate
+
+ if node.level:
+ return "Level Node: {0}".format(node.level)
+ elif node.mapChange != None:
+ return "Exit to World {0}, entrance {1}".format(mapID, foreignID)
+ elif len(node.exits) == 3:
+ return "3-way Junction"
+ elif len(node.exits) == 4:
+ return "4-way Junction"
+ elif len(node.exits) > 4:
+ return "Illegal Node"
+ else:
+ return "Pass Through Node"
+
+ 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)
+
+ else:
+ return QtGui.QTreeWidgetItem.data(self, index, role)
+
+
+ def layer(self):
+ return self.layer
+
+ def associate(self):
+ return self.associate
+
+
def __init__(self):
QtGui.QWidget.__init__(self)
@@ -15,6 +85,10 @@ class KPPathNodeList(QtGui.QWidget):
self.layout.setSpacing(0)
self.tree = QtGui.QTreeWidget()
+ self.tree.setColumnCount(1)
+ self.tree.setDragEnabled(True)
+ self.tree.setDragDropMode(self.tree.InternalMove)
+ self.tree.itemClicked.connect(self.handleRowChanged)
self.layout.addWidget(self.tree)
self.toolbar = QtGui.QToolBar()
@@ -25,30 +99,108 @@ class KPPathNodeList(QtGui.QWidget):
def setupToolbar(self, tb):
- self.actAddFolder = tb.addAction(KP.icon('LayerNewTile'), 'Add Folder', self.addTileLayer)
- self.actRemoveFolder = tb.addAction(KP.icon('LayerNewObjects'), 'Remove Folder', self.addDoodadLayer)
- self.actMoveUp = tb.addAction(QtGui.QIcon(), 'Move Up', self.moveUp)
- self.actMoveDown = tb.addAction(QtGui.QIcon(), 'Move Down', self.moveDown)
-
+ self.actAddFolder = tb.addAction(KP.icon('LayerNewTile'), 'Add Folder', self.addFolder)
+ self.actRemoveFolder = tb.addAction(KP.icon('LayerNewObjects'), 'Remove Folder', self.removeFolder)
+ self.selectTileset = tb.addAction(KP.icon('LayerNewTile'), 'Select Tileset', self.setTileset)
selectedLayerChanged = QtCore.pyqtSignal(KPLayer)
- @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex)
- def handleRowChanged(self, current, previous):
- self.selectedLayerChanged.emit(KP.map.layers[current.row()])
- self.setButtonStates()
+ @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, QtGui.QIcon('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())
- def moveUp(self):
- index = self.selectedLayerIndex()
- KP.map.moveLayer(index, index - 1)
- KP.mainWindow.editor.viewport().update()
+ self.tree.addTopLevelItems(kids)
- def moveDown(self):
- index = self.selectedLayerIndex()
- KP.map.moveLayer(index, index + 2)
- KP.mainWindow.editor.viewport().update()
+ 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 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):
@@ -73,7 +225,7 @@ class KPLayerList(QtGui.QWidget):
def updateModel(self):
self.model = KP.map.layerModel
self.listView.setModel(self.model)
- self.listView.selectionModel().currentRowChanged.connect(self.handleRowChanged)
+ self.listView.clicked.connect(self.handleRowChanged)
self.setButtonStates()
@@ -111,8 +263,8 @@ class KPLayerList(QtGui.QWidget):
selectedLayerChanged = QtCore.pyqtSignal(KPLayer)
- @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex)
- def handleRowChanged(self, current, previous):
+ @QtCore.pyqtSlot(QtCore.QModelIndex)
+ def handleRowChanged(self, current):
self.selectedLayerChanged.emit(KP.map.layers[current.row()])
self.setButtonStates()
@@ -557,6 +709,11 @@ class KPMainWindow(QtGui.QMainWindow):
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)
@@ -572,6 +729,7 @@ class KPMainWindow(QtGui.QMainWindow):
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)
@@ -604,6 +762,8 @@ class KPMainWindow(QtGui.QMainWindow):
@QtCore.pyqtSlot(KPLayer)
def handleSelectedLayerChanged(self, layer):
+ self.pathNodeList.tree.selectionModel().clearSelection()
+
self.scene.setCurrentLayer(layer)
showObjects, showDoodads = False, False
@@ -621,15 +781,37 @@ class KPMainWindow(QtGui.QMainWindow):
self.doodadSelectorDock.setVisible(showDoodads)
+ @QtCore.pyqtSlot(KPLayer)
+ def handleSelectedPathNodeLayerChanged(self, layer):
+
+ self.layerList.listView.selectionModel().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):
+ self.doodadSelector.listView.selectionModel().clearSelection()
+
self.editor.objectToPaint = obj
self.editor.objectIDToPaint = index
+ self.editor.typeToPaint = 'object'
@QtCore.pyqtSlot(object)
def handleSelectedDoodadChanged(self, doodad):
+ self.objectSelector.listView.selectionModel().clearSelection()
+
self.editor.doodadToPaint = doodad
+ self.editor.typeToPaint = 'doodad'
########################