diff options
Diffstat (limited to 'src/editorui/editormain.py')
-rw-r--r-- | src/editorui/editormain.py | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/src/editorui/editormain.py b/src/editorui/editormain.py new file mode 100644 index 0000000..d11642a --- /dev/null +++ b/src/editorui/editormain.py @@ -0,0 +1,419 @@ +from common import * +from math import floor, ceil + +from objects import * +from doodads import * +from paths import * + +class KPMapScene(QtGui.QGraphicsScene): + def __init__(self): + QtGui.QGraphicsScene.__init__(self, 0, 0, 512*24, 512*24) + + # todo: handle selectionChanged + # todo: look up why I used setItemIndexMethod(self.NoIndex) in Reggie + + self.currentLayer = None + KP.mapScene = self + + + def drawBackground(self, painter, rect): + painter.fillRect(rect, QtGui.QColor(209, 218, 236)) + + areaLeft, areaTop = rect.x(), rect.y() + areaWidth, areaHeight = rect.width(), rect.height() + areaRight, areaBottom = areaLeft+areaWidth, areaTop+areaHeight + + areaLeftT = floor(areaLeft / 24) + areaTopT = floor(areaTop / 24) + areaRightT = ceil(areaRight / 24) + areaBottomT = ceil(areaBottom / 24) + + # compile a list of doodads + visibleDoodadsByLayer = {} + + for obj in self.items(rect): + if not isinstance(obj, KPEditorDoodad): continue + + layer = obj._layerRef() + + try: + doodadList = visibleDoodadsByLayer[layer] + except KeyError: + doodadList = [] + visibleDoodadsByLayer[layer] = doodadList + + doodadList.append(obj) + + # now draw everything! + for layer in reversed(KP.map.layers): + if not layer.visible: continue + + if isinstance(layer, KPDoodadLayer): + try: + toDraw = visibleDoodadsByLayer[layer] + except KeyError: + continue + + for item in reversed(toDraw): + painter.save() + painter.setWorldTransform(item.sceneTransform(), True) + w, h = item._doodadRef().size + p = item._boundingRect + painter.drawPixmap(p.x(), p.y(), p.width(), p.height(), item.pixmap) + painter.restore() + + elif isinstance(layer, KPTileLayer): + left, top = layer.cacheBasePos + width, height = layer.cacheSize + right, bottom = left+width, top+height + + if width == 0 and height == 0: continue + + if right < areaLeftT: continue + if left > areaRightT: continue + + if bottom < areaTopT: continue + if top > areaBottomT: continue + + # decide how much of the layer we'll actually draw + 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 = layer.cache + tileset = KP.map.loadedTilesets[layer.tileset] + 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 + + + def setCurrentLayer(self, layer): + if self.currentLayer is not None: + self.currentLayer.setActivated(False) + + self.currentLayer = layer + self.currentLayer.setActivated(True) + + +class KPEditorWidget(QtGui.QGraphicsView): + def __init__(self, scene, parent=None): + QtGui.QGraphicsView.__init__(self, scene, parent) + + self.setRenderHints(QtGui.QPainter.Antialiasing) + + self.setAlignment(Qt.AlignLeft | Qt.AlignTop) + self.setDragMode(self.RubberBandDrag) + + self.xScrollBar = QtGui.QScrollBar(Qt.Horizontal, parent) + self.setHorizontalScrollBar(self.xScrollBar) + + self.yScrollBar = QtGui.QScrollBar(Qt.Vertical, parent) + self.setVerticalScrollBar(self.yScrollBar) + + self.centerOn(0,0) + + # set up stuff for painting + self.paintNext = None + self.paintNextID = None + self._resetPaintVars() + + def _resetPaintVars(self): + self.painting = None + self.paintingItem = None + self.paintBeginPosition = None + + def _tryToPaint(self, event): + '''Called when a paint attempt is initiated''' + + paint = self.paintNext + layer = self.scene().currentLayer + if not layer.visible: return + + if isinstance(layer, KPTileLayer): + 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 isinstance(layer, KPDoodadLayer): + 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.index = self.paintNextID + obj.setDefaultSize() + layer.objects.append(obj) + + item = KPEditorDoodad(obj, layer) + self.scene().addItem(item) + + self.painting = obj + self.paintingItem = item + self.paintBeginPosition = (x, y) + + elif isinstance(layer, KPPathLayer): + # decide what's under the mouse + clicked = self.mapToScene(event.x(), event.y()) + x, y = clicked.x(), clicked.y() + itemsUnder = self.scene().items(clicked) + + for item in itemsUnder: + if isinstance(item, KPEditorNode): + # Paint a path to this node (if one is selected) + sourceItem, sourceNode = None, None + selected = self.scene().selectedItems() + + for selItem in selected: + if isinstance(item, KPEditorNode) and selItem != item: + sourceItem = selItem + sourceNode = selItem._nodeRef() + break + + if sourceItem is None: return + + # Make sure that no path already exists between these nodes + destNode = item._nodeRef() + + for pathToCheck in sourceNode.exits: + if pathToCheck._startNodeRef() == destNode: + return + if pathToCheck._endNodeRef() == destNode: + return + + # No node can have more than four paths, because there are only + # four directions registered by a Wiimote DPad. + + if len(sourceNode.exits) > 3: + return + + if len(destNode.exits) > 3: + return + + path = KPPath(sourceNode, destNode) + + KP.map.pathLayer.paths.append(path) + + item = KPEditorPath(path) + self.scene().addItem(item) + + return + + elif isinstance(item, KPEditorPath): + # Split this path into two... at this point + + origPath = item._pathRef() + + node = KPNode() + node.position = (x - 12, y - 12) + KP.map.pathLayer.nodes.append(node) + + # Start node => Original path => New node => New path => End node + + endNode = origPath._endNodeRef() + + origPath.setEnd(node) + origPath.qtItem.updatePosition() + + nodeItem = KPEditorNode(node) + self.scene().addItem(nodeItem) + self.scene().addItem(nodeItem.buttonProxy) + self.scene().addItem(nodeItem.stageProxy) + self.scene().addItem(nodeItem.worldProxy) + + self.painting = node + self.paintingItem = item + self.paintBeginPosition = (x - 12, y - 12) + + newPath = KPPath(node, endNode, origPath) + KP.map.pathLayer.paths.append(newPath) + + pathItem = KPEditorPath(newPath) + self.scene().addItem(pathItem) + + return + + # Paint a new node + node = KPNode() + node.position = (x - 12, y - 12) + KP.map.pathLayer.nodes.append(node) + + item = KPEditorNode(node) + self.scene().addItem(item) + self.scene().addItem(item.buttonProxy) + self.scene().addItem(item.stageProxy) + self.scene().addItem(item.worldProxy) + + # Paint a path to this node (if one is selected) + sourceItem, sourceNode = None, None + selected = self.scene().selectedItems() + + for selItem in selected: + if isinstance(item, KPEditorNode) and selItem != item: + sourceItem = selItem + sourceNode = selItem._nodeRef() + break + + # No node can have more than four paths, because there are only + # four directions registered by a Wiimote DPad. + + if not sourceItem is None: + if len(sourceNode.exits) > 3: + return + + # There, now you can draw paths easily in a row. + path = KPPath(sourceNode, node) + + KP.map.pathLayer.paths.append(path) + + pathitem = KPEditorPath(path) + self.scene().addItem(pathitem) + + + # Switch the selection to the recently drawn node, so you can keep on rolling. + self.scene().clearSelection() + item.setSelected(True) + + self.painting = node + self.paintingItem = item + self.paintBeginPosition = (x - 12, y - 12) + + + + def _movedWhilePainting(self, event): + '''Called when the mouse is moved while painting something''' + + obj = self.painting + item = self.paintingItem + + if isinstance(obj, KPObject): + 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) + + beginX, beginY = self.paintBeginPosition + + if x >= beginX: + objX = beginX + width = x - beginX + 1 + else: + objX = x + width = beginX - x + 1 + + if y >= beginY: + objY = beginY + height = y - beginY + 1 + else: + objY = y + height = beginY - y + 1 + + currentX, currentY = obj.position + currentWidth, currentHeight = obj.size + + # update everything if changed + changed = False + + if currentX != objX or currentY != objY: + obj.position = (objX, objY) + item._updatePosition() + changed = True + + if currentWidth != width or currentHeight != height: + obj.size = (width, height) + obj.updateCache() + item._updateSize() + changed = True + + if not changed: return + + item._layerRef().updateCache() + + + def mousePressEvent(self, event): + if event.button() == Qt.RightButton: + self._tryToPaint(event) + event.accept() + + else: + QtGui.QGraphicsView.mousePressEvent(self, event) + + + def mouseMoveEvent(self, event): + if event.buttons() == Qt.RightButton and self.painting: + self._movedWhilePainting(event) + event.accept() + + else: + QtGui.QGraphicsView.mouseMoveEvent(self, event) + + + def keyPressEvent(self, event): + if event.key() == QtCore.Qt.Key_Delete or event.key() == QtCore.Qt.Key_Backspace: + scene = self.scene() + + selection = scene.selectedItems() + if len(selection) > 0: + for obj in selection: + obj.setSelected(False) + obj.remove(True) + scene.update() + self.update() + return + + else: + QtGui.QGraphicsView.keyPressEvent(self, event) + + + + |