summaryrefslogtreecommitdiff
path: root/src/editorui/editormain.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/editorui/editormain.py')
-rw-r--r--src/editorui/editormain.py419
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)
+
+
+
+