summaryrefslogtreecommitdiff
path: root/src/editorui
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2011-11-21 15:25:54 +0100
committerTreeki <treeki@gmail.com>2011-11-21 15:25:54 +0100
commit30188c779e1b419f6818596a29f7f3c7edad42bb (patch)
tree4bf37618ec1721b6f41b1686d71a9d727333e104 /src/editorui
parent63ba5f8a58bd26f42712ca61d7d18a1858083443 (diff)
downloadkoopatlas-30188c779e1b419f6818596a29f7f3c7edad42bb.tar.gz
koopatlas-30188c779e1b419f6818596a29f7f3c7edad42bb.zip
some refactoring of editorui and co
Diffstat (limited to '')
-rw-r--r--src/editorui.py1227
-rw-r--r--src/editorui/__init__.py0
-rw-r--r--src/editorui/doodads.py248
-rw-r--r--src/editorui/editorcommon.py77
-rw-r--r--src/editorui/editormain.py419
-rw-r--r--src/editorui/objects.py182
-rw-r--r--src/editorui/paths.py319
7 files changed, 1245 insertions, 1227 deletions
diff --git a/src/editorui.py b/src/editorui.py
deleted file mode 100644
index 2ab3774..0000000
--- a/src/editorui.py
+++ /dev/null
@@ -1,1227 +0,0 @@
-from common import *
-from math import floor, ceil
-import weakref
-import math
-
-
-class KPEditorItem(QtGui.QGraphicsItem):
- def __init__(self):
- QtGui.QGraphicsItem.__init__(self)
- self.setFlags(
- self.ItemSendsGeometryChanges |
- self.ItemIsSelectable |
- self.ItemIsMovable
- )
-
- self.ignoreMovement = False
- self.overrideSnap = False
-
- def itemChange(self, change, value):
- if change == self.ItemPositionChange and not self.ignoreMovement:
- currentX, currentY = self.x(), self.y()
-
- newpos = value.toPyObject()
-
- x, y = newpos.x(), newpos.y()
-
- if self.overrideSnap:
- snapX, snapY = 1, 1
- else:
- # snap the item
- snapX, snapY = self.SNAP_TO
- x = int((x + (snapX/2)) / snapX) * snapX
- y = int((y + (snapY/2)) / snapY) * snapY
-
- if x < 0: x = 0
- if x >= (12288+snapX): x = (12288+snapX-1)
- if y < 0: y = 0
- if y >= (12288+snapY): y = (12288+snapY-1)
-
- if x != currentX or y != currentY:
- self._itemMoved(currentX, currentY, x, y)
-
- newpos.setX(x)
- newpos.setY(y)
- return newpos
-
- return QtGui.QGraphicsItem.itemChange(self, change, value)
-
- def boundingRect(self):
- return self._boundingRect
-
-
- def resizerPortionAt(self, x, y, originX=0, originY=0):
- try:
- leftBound, topBound = originX+5, originY+5
- rightBound, bottomBound = self._resizerEndXY
- except AttributeError:
- rect = self._boundingRect
- leftBound, topBound = rect.x() + 5, rect.y() + 5
- rightBound, bottomBound = rect.right() - 5, rect.bottom() - 5
-
- if y < topBound:
- if x < leftBound: return 1 # TOP_LEFT
- elif x >= rightBound: return 2 # TOP_RIGHT
- else: return 5 # TOP
-
- elif y >= bottomBound:
- if x < leftBound: return 3 # BOTTOM_LEFT
- elif x >= rightBound: return 4 # BOTTOM_RIGHT
- else: return 6 # BOTTOM
-
- else:
- if x < leftBound: return 7 # LEFT
- elif x >= rightBound: return 8 # RIGHT
- else: return None
-
-
- def _itemMoved(self, oldX, oldY, newX, newY):
- pass
-
-
-class KPEditorObject(KPEditorItem):
- SNAP_TO = (24,24)
-
- def __init__(self, obj, layer):
- KPEditorItem.__init__(self)
- obj.qtItem = self
- self._objRef = weakref.ref(obj)
- self._layerRef = weakref.ref(layer)
- self._updatePosition()
- self._updateSize()
-
- self.setAcceptHoverEvents(True)
-
- self.resizing = None
-
- if not hasattr(KPEditorObject, 'SELECTION_PEN'):
- KPEditorObject.SELECTION_PEN = QtGui.QPen(Qt.white, 1, Qt.DotLine)
-
- # I don't bother setting the ZValue because it doesn't quite matter:
- # only one layer's objects are ever clickable, and drawBackground takes
- # care of the layered drawing
-
- def _updatePosition(self):
- self.ignoreMovement = True
- x,y = self._objRef().position
- self.setPos(x*24, y*24)
- self.ignoreMovement = False
-
- def _updateSize(self):
- self.prepareGeometryChange()
-
- obj = self._objRef()
- w,h = obj.size
-
- self._boundingRect = QtCore.QRectF(0, 0, w*24, h*24)
- self._selectionRect = QtCore.QRectF(0, 0, w*24-1, h*24-1)
-
- self._resizerEndXY = (w*24-5, h*24-5)
-
-
- def paint(self, painter, option, widget):
- if self.isSelected():
- painter.setPen(self.SELECTION_PEN)
- painter.drawRect(self._selectionRect)
-
-
- def hoverMoveEvent(self, event):
- if self._layerRef() != KP.mapScene.currentLayer:
- self.setCursor(Qt.ArrowCursor)
- return
-
- pos = event.pos()
- bit = self.resizerPortionAt(pos.x(), pos.y())
-
- if bit == 1 or bit == 4:
- self.setCursor(Qt.SizeFDiagCursor)
- elif bit == 2 or bit == 3:
- self.setCursor(Qt.SizeBDiagCursor)
- elif bit == 7 or bit == 8:
- self.setCursor(Qt.SizeHorCursor)
- elif bit == 5 or bit == 6:
- self.setCursor(Qt.SizeVerCursor)
- else:
- self.setCursor(Qt.ArrowCursor)
-
-
- def mousePressEvent(self, event):
- if event.button() == Qt.LeftButton:
- pos = event.pos()
- bit = self.resizerPortionAt(pos.x(), pos.y())
-
- if self._layerRef() == KP.mapScene.currentLayer and bit:
- event.accept()
-
- x, xSide, y, ySide = False, None, False, None
-
- if bit == 1 or bit == 7 or bit == 3:
- x, xSide = True, 1
- elif bit == 2 or bit == 4 or bit == 8:
- x, xSide = True, 0
-
- if bit == 1 or bit == 2 or bit == 5:
- y, ySide = True, 1
- elif bit == 3 or bit == 4 or bit == 6:
- y, ySide = True, 0
-
- self.resizing = (x, xSide, y, ySide)
- return
-
- KPEditorItem.mousePressEvent(self, event)
-
-
- def _tryAndResize(self, obj, axisIndex, mousePosition, stationarySide):
- objPosition = obj.position[axisIndex]
- objSize = obj.size[axisIndex]
-
- if stationarySide == 0:
- # Resize the right/bottom side
- relativeMousePosition = mousePosition - objPosition
- newSize = relativeMousePosition + 1
- if newSize == objSize or newSize < 1:
- return False
-
- if axisIndex == 1:
- obj.size = (obj.size[0], newSize)
- else:
- obj.size = (newSize, obj.size[1])
-
- else:
- # Resize the left/top side
- rightSide = objPosition + objSize - 1
- newLeftSide = mousePosition
-
- newPosition = newLeftSide
- newSize = rightSide - newLeftSide + 1
-
- if newSize < 1:
- return False
- if newPosition == objPosition and newSize == objSize:
- return False
-
- if axisIndex == 1:
- obj.position = (obj.position[0], newPosition)
- obj.size = (obj.size[0], newSize)
- else:
- obj.position = (newPosition, obj.position[1])
- obj.size = (newSize, obj.size[1])
-
- return True
-
-
- def mouseMoveEvent(self, event):
- if self.resizing:
- obj = self._objRef()
- scenePos = event.scenePos()
-
- hasChanged = False
- resizeX, xSide, resizeY, ySide = self.resizing
-
- if resizeX:
- hasChanged |= self._tryAndResize(obj, 0, int(scenePos.x() / 24), xSide)
- if resizeY:
- hasChanged |= self._tryAndResize(obj, 1, int(scenePos.y() / 24), ySide)
-
- if hasChanged:
- obj.updateCache()
- self._layerRef().updateCache()
- self._updatePosition()
- self._updateSize()
-
- else:
- KPEditorItem.mouseMoveEvent(self, event)
-
-
- def mouseReleaseEvent(self, event):
- if self.resizing and event.button() == Qt.LeftButton:
- self.resizing = None
- else:
- KPEditorItem.mouseReleaseEvent(self, event)
-
-
- def _itemMoved(self, oldX, oldY, newX, newY):
- obj = self._objRef()
- obj.position = (newX/24, newY/24)
- self._layerRef().updateCache()
-
-
- def remove(self, withItem=False):
- obj = self._objRef()
- layer = self._layerRef()
-
- layer.objects.remove(obj)
- layer.updateCache()
-
- if withItem:
- self.scene().removeItem(self)
-
-
-class KPEditorDoodad(KPEditorItem):
- SNAP_TO = (12,12)
-
- def __init__(self, doodad, layer):
- KPEditorItem.__init__(self)
-
- doodad.qtItem = self
- self._doodadRef = weakref.ref(doodad)
- self._layerRef = weakref.ref(layer)
-
- # TODO: refactor this to store source doodad data under KP.map
- sourceItem = KP.mainWindow.doodadSelector.getDoodad(doodad.index)
- self._sourceRef = weakref.ref(sourceItem)
-
- self.resizing = None
- self.rotating = None
-
- self._updatePixmap()
- self._updatePosition()
- self._updateSize()
-
- self.setAcceptHoverEvents(True)
-
- if not hasattr(KPEditorDoodad, 'SELECTION_PEN'):
- KPEditorDoodad.SELECTION_PEN = QtGui.QPen(Qt.red, 1, Qt.DotLine)
-
-
-
- def _updatePixmap(self):
- source = self._sourceRef()
- pixmap = source.icon().pixmap(source.icon().availableSizes()[0])
-
- self.prepareGeometryChange()
- w, h = pixmap.width(), pixmap.height()
-
- self.pixmap = pixmap
-
-
- def _updatePosition(self):
- # NOTE: EditorDoodads originate at the centre, not the top left like the others
- doodad = self._doodadRef()
- x,y = doodad.position
- w,h = doodad.size
- self.setPos(x+floor(w/2.0), y+floor(h/2.0))
-
-
- def _updateSize(self):
- self.prepareGeometryChange()
-
- w,h = self._doodadRef().size
-
- self._boundingRect = QtCore.QRectF(-w/2, -h/2, w, h)
- self._selectionRect = self._boundingRect.adjusted(0, 0, -1, -1)
-
-
- def _updateTransform(self):
- doodad = self._doodadRef()
-
- self.setRotation(doodad.angle)
-
-
- def paint(self, painter, option, widget):
- if self.isSelected():
- painter.setPen(self.SELECTION_PEN)
- painter.drawRect(self._selectionRect)
-
-
- def _itemMoved(self, oldX, oldY, newX, newY):
- doodad = self._doodadRef()
- w,h = doodad.size
- doodad.position = [newX-floor(w/2.0), newY-floor(h/2.0)]
-
-
- def hoverMoveEvent(self, event):
- if self._layerRef() != KP.mapScene.currentLayer:
- self.setCursor(Qt.ArrowCursor)
- return
-
- pos = event.pos()
- bit = self.resizerPortionAt(pos.x(), pos.y())
-
-
- if (event.modifiers() == Qt.ShiftModifier):
-
- if bit:
- self.setCursor(Qt.OpenHandCursor)
- else:
- self.setCursor(Qt.ArrowCursor)
-
- else:
-
- if bit == 1 or bit == 4:
- self.setCursor(Qt.SizeFDiagCursor)
- elif bit == 2 or bit == 3:
- self.setCursor(Qt.SizeBDiagCursor)
- elif bit == 7 or bit == 8:
- self.setCursor(Qt.SizeHorCursor)
- elif bit == 5 or bit == 6:
- self.setCursor(Qt.SizeVerCursor)
- else:
- self.setCursor(Qt.ArrowCursor)
-
-
- def mousePressEvent(self, event):
- if event.button() == Qt.LeftButton:
- pos = event.pos()
- bit = self.resizerPortionAt(pos.x(), pos.y())
-
- if self._layerRef() == KP.mapScene.currentLayer and bit:
- event.accept()
-
- if (event.modifiers() & Qt.ShiftModifier):
- self.rotating = self.mapToScene(pos), self._doodadRef().angle
- self.setCursor(Qt.ClosedHandCursor)
- return
-
- else:
- x, xSide, y, ySide = False, None, False, None
-
- if bit == 1 or bit == 7 or bit == 3: # left
- x, xSide = True, 1
-
- elif bit == 2 or bit == 4 or bit == 8: # right
- x, xSide = True, 0
-
- if bit == 1 or bit == 2 or bit == 5: # top
- y, ySide = True, 1
-
- elif bit == 3 or bit == 4 or bit == 6: # bottom
- y, ySide = True, 0
-
- self._updateSize()
- self.resizing = (x, xSide, y, ySide)
- return
-
-
- KPEditorItem.mousePressEvent(self, event)
-
-
- def _tryAndResize(self, obj, axisIndex, mousePosition, stationarySide):
-
- newSize = abs(mousePosition) * 2
-
- if newSize < 10:
- return False
-
- obj.size[axisIndex] = newSize
-
- return True
-
-
- def _tryAndRotate(self, obj, mouseX, mouseY, originalPos, oldAngle, modifiers):
- center = self.mapToScene(self.boundingRect().center())
-
- objX = center.x()
- objY = center.y()
-
-
- origX = originalPos.x()
- origY = originalPos.y()
-
- dy = origY - objY
- dx = origX - objX
- rads = math.atan2(dy, dx)
-
- origAngle = math.degrees(rads)
-
- dy = mouseY - objY
- dx = mouseX - objX
- rads = math.atan2(dy, dx)
-
- angle = math.degrees(rads)
-
-
- # Move this to ItemChange() or something at some point.
- finalAngle = angle - origAngle + oldAngle
-
- if (modifiers & Qt.ControlModifier):
- finalAngle = int(finalAngle / 45.0) * 45.0
-
- return True, finalAngle
-
-
- def mouseMoveEvent(self, event):
- if self.resizing:
- obj = self._doodadRef()
-
- hasChanged = False
- resizeX, xSide, resizeY, ySide = self.resizing
-
- if resizeX:
- hasChanged |= self._tryAndResize(obj, 0, event.pos().x(), xSide)
- if resizeY:
- hasChanged |= self._tryAndResize(obj, 1, event.pos().y(), ySide)
-
- if hasChanged:
- # Doodads aren't supposed to snap, they're all free flowing like the wind.
- self._updateSize()
-
-
- elif self.rotating:
- obj = self._doodadRef()
- scenePos = event.scenePos()
- self.setTransformOriginPoint(self.boundingRect().center())
-
- hasChanged = False
-
- hasChanged, angle = self._tryAndRotate(obj, scenePos.x(), scenePos.y(), self.rotating[0], self.rotating[1], event.modifiers())
-
- if hasChanged:
- obj.angle = angle
- self._updateTransform()
-
-
- else:
- KPEditorItem.mouseMoveEvent(self, event)
-
-
- def mouseReleaseEvent(self, event):
- if self.resizing and event.button() == Qt.LeftButton:
- self.resizing = None
- # self._doodadRef().position = [self.x(), self.y()]
-
- elif self.rotating and event.button() == Qt.LeftButton:
- self.rotating = None
-
- else:
- KPEditorItem.mouseReleaseEvent(self, event)
-
-
- def remove(self, withItem=False):
- doodad = self._doodadRef()
- layer = self._layerRef()
-
- layer.objects.remove(doodad)
-
- if withItem:
- self.scene().removeItem(self)
-
-
-class KPEditorNode(KPEditorItem):
- SNAP_TO = (12,12)
-
-
- class toggleButton(QtGui.QPushButton):
-
- stateToggled = QtCore.pyqtSignal(int)
-
-
- def __init__(self):
- QtGui.QPushButton.__init__(self)
-
- self.setIconSize(QtCore.QSize(24, 24))
- self.setFixedSize(24, 24)
-
- self.iconList = [QtGui.QIcon("Resources/Through.png"),
- QtGui.QIcon("Resources/Level.png"),
- QtGui.QIcon("Resources/Stop.png")]
-
- self.state = 0
-
- self.setPalette(QtGui.QPalette(QtGui.QColor(0,0,0,0)))
-
- self.released.connect(self.toggle)
-
-
- def toggle(self):
-
- self.state += 1
- if self.state == 3:
- self.state = 0
-
- self.stateToggled.emit(self.state)
-
-
- def paintEvent(self, event):
-
- painter = QtGui.QPainter(self)
-
- painter.setBackgroundMode(Qt.TransparentMode)
- painter.setBrush(QtGui.QColor(0,0,0,0))
- painter.setPen(QtGui.QColor(0,0,0,0))
-
- if self.isDown():
- self.iconList[self.state].paint(painter, self.contentsRect(), Qt.AlignCenter, QtGui.QIcon.Disabled)
- else:
- self.iconList[self.state].paint(painter, self.contentsRect())
- painter.end()
-
-
- class hiddenProxy(QtGui.QGraphicsProxyWidget):
- def __init__(self, button):
- QtGui.QGraphicsProxyWidget.__init__(self)
-
- self.setWidget(button)
- self.setZValue(self.zValue()+1000)
- self.hide()
-
-
- class levelSlotSpinner(QtGui.QSpinBox):
-
- def __init__(self):
- QtGui.QSpinBox.__init__(self)
-
- self.setRange(1, 99)
-
- self.setPalette(QtGui.QPalette(QtGui.QColor(0,0,0,0)))
-
-
-
- def __init__(self, node):
- KPEditorItem.__init__(self)
-
- node.qtItem = self
- self._nodeRef = weakref.ref(node)
-
- self.setZValue(101)
-
- self._boundingRect = QtCore.QRectF(-24, -24, 48, 48)
- self._tinyRect = QtCore.QRectF(-12, -12, 24, 24)
-
-
- if not hasattr(KPEditorNode, 'SELECTION_PEN'):
- KPEditorNode.SELECTION_PEN = QtGui.QPen(Qt.blue, 1, Qt.DotLine)
-
- self.button = self.toggleButton()
- self.buttonProxy = self.hiddenProxy(self.button)
- self.button.stateToggled.connect(self.stateChange)
-
-
- self.world = self.levelSlotSpinner()
- self.worldProxy = self.hiddenProxy(self.world)
- self.world.valueChanged.connect(self.worldChange)
-
- self.stage = self.levelSlotSpinner()
- self.stageProxy = self.hiddenProxy(self.stage)
- self.stage.valueChanged.connect(self.stageChange)
-
-
- self._updatePosition()
-
-
-
- @QtCore.pyqtSlot(int)
- def stateChange(self, state):
-
- node = self._nodeRef()
-
- if state == 1:
- node.level = [1, 1]
- self.world.setValue(node.level[0])
- self.stage.setValue(node.level[1])
-
- elif state == 2:
- node.isStop = True
- node.level = [0,0]
-
- else:
- node.isStop = False
- node.level = [0,0]
-
- self.update()
-
-
- @QtCore.pyqtSlot(int)
- def worldChange(self, world):
-
- node = self._nodeRef()
- node.level[0] = world
-
-
- @QtCore.pyqtSlot(int)
- def stageChange(self, stage):
-
- node = self._nodeRef()
- node.level[1] = stage
-
-
-
- def _updatePosition(self):
- node = self._nodeRef()
- x, y = node.position
- self.setPos(x+12, y+12)
- self.buttonProxy.setPos(self.x()+12, self.y()-24)
- self.worldProxy.setPos(self.x()-42, self.y()+24)
- self.stageProxy.setPos(self.x()+6, self.y()+24)
-
-
- def _itemMoved(self, oldX, oldY, newX, newY):
- node = self._nodeRef()
- node.position = (newX-12, newY-12)
-
- self.buttonProxy.setPos(newX+12, newY-24)
- self.worldProxy.setPos(newX-42, newY+24)
- self.stageProxy.setPos(newX+6, newY+24)
-
- for exit in node.exits:
- exit.qtItem.updatePosition()
-
-
- def paint(self, painter, option, widget):
-
- node = self._nodeRef()
-
- selectionRect = None
-
- if node.level != [0,0]:
- painter.setBrush(QtGui.QColor(0, 0, 0, 0))
- painter.setPen(QtGui.QColor(0, 0, 0, 0))
- painter.drawPixmap(self._boundingRect.topLeft(), QtGui.QPixmap("Resources/BlackLevel.png"))
- selectionRect = self._boundingRect.adjusted(-1,-1,1,1)
-
- elif node.isStop:
- brush = QtGui.QBrush(QtGui.QColor(255, 220, 220))
- painter.setPen(QtGui.QColor(255, 255, 255))
- painter.setBrush(brush)
- painter.drawEllipse(self._tinyRect)
- selectionRect = self._tinyRect.adjusted(-1,-1,1,1)
-
- else:
- brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
- painter.setPen(QtGui.QColor(255, 255, 255))
- painter.setBrush(brush)
- painter.drawEllipse(self._tinyRect)
- selectionRect = self._tinyRect.adjusted(-1,-1,1,1)
-
-
- if self.isSelected():
- painter.setPen(self.SELECTION_PEN)
- painter.setBrush(QtGui.QColor(0,0,0,0))
- painter.drawEllipse(selectionRect)
-
- self.buttonProxy.show()
-
- if node.level != [0,0]:
- self.worldProxy.show()
- self.stageProxy.show()
-
- else:
- self.worldProxy.hide()
- self.stageProxy.hide()
-
- else:
- self.buttonProxy.hide()
- self.worldProxy.hide()
- self.stageProxy.hide()
-
-
-
-
- def remove(self, withItem=False):
- node = self._nodeRef()
- layer = KP.map.pathLayer
-
- layer.nodes.remove(node)
-
- self.scene().removeItem(self.buttonProxy)
- self.scene().removeItem(self.stageProxy)
- self.scene().removeItem(self.worldProxy)
-
- if len(node.exits) == 2:
- # let's try to join the two!
- pathOne, pathTwo = node.exits
-
- start1, end1 = pathOne._startNodeRef(), pathOne._endNodeRef()
- start2, end2 = pathTwo._startNodeRef(), pathTwo._endNodeRef()
-
- if start1 == node:
- start = end1
- else:
- start = start1
-
- if start2 == node:
- end = end2
- else:
- end = start2
-
- # make sure no path already exists between these nodes
- nope = False
-
- for pathToCheck in start.exits:
- if pathToCheck._startNodeRef() == end:
- nope = True
- elif pathToCheck._endNodeRef() == end:
- nope = True
-
- if not nope:
- joinedPath = KPPath(start, end, pathOne)
- layer.paths.append(joinedPath)
- item = KPEditorPath(joinedPath)
- self.scene().addItem(item)
-
- for path in (pathOne, pathTwo):
- path.qtItem.remove(True)
- else:
- # we can't join them so just nuke them
- for exit in node.exits[:]:
- exit.qtItem.remove(True)
-
- if withItem:
- self.scene().removeItem(self)
-
-
-
-class KPEditorPath(QtGui.QGraphicsLineItem):
- def __init__(self, path):
- QtGui.QGraphicsLineItem.__init__(self)
-
- self.setFlag(self.ItemIsSelectable, True)
-
- self.setZValue(100)
-
- startNode = path._startNodeRef().qtItem
- endNode = path._endNodeRef().qtItem
-
- self._startNodeRef = weakref.ref(startNode)
- self._endNodeRef = weakref.ref(endNode)
- self._pathRef = weakref.ref(path)
-
- path.qtItem = self
-
- self.updatePosition()
-
- if not hasattr(KPEditorPath, 'PEN'):
- KPEditorPath.BRUSH = QtGui.QBrush(QtGui.QColor(255, 255, 255, 140))
- KPEditorPath.PEN = QtGui.QPen(KPEditorPath.BRUSH, 8, Qt.SolidLine, Qt.RoundCap)
- self.setPen(KPEditorPath.PEN)
-
-
- def updatePosition(self):
- path = self._pathRef()
-
- x1, y1 = path._startNodeRef().position
- x2, y2 = path._endNodeRef().position
-
- self.setLine(QtCore.QLineF(x1+12, y1+12, x2+12, y2+12))
-
-
- def remove(self, withItem=False):
- path = self._pathRef()
- layer = KP.map.pathLayer
-
- layer.paths.remove(path)
-
- for ref in (self._startNodeRef, self._endNodeRef):
- node = ref()._nodeRef()
- try:
- node.exits.remove(path)
- except ValueError:
- pass
-
- if withItem:
- self.scene().removeItem(self)
-
-
-
-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)
-
-
-
-
diff --git a/src/editorui/__init__.py b/src/editorui/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/editorui/__init__.py
diff --git a/src/editorui/doodads.py b/src/editorui/doodads.py
new file mode 100644
index 0000000..5a02248
--- /dev/null
+++ b/src/editorui/doodads.py
@@ -0,0 +1,248 @@
+from common import *
+from editorcommon import *
+import weakref
+from math import floor, ceil
+import math
+
+
+class KPEditorDoodad(KPEditorItem):
+ SNAP_TO = (12,12)
+
+ def __init__(self, doodad, layer):
+ KPEditorItem.__init__(self)
+
+ doodad.qtItem = self
+ self._doodadRef = weakref.ref(doodad)
+ self._layerRef = weakref.ref(layer)
+
+ # TODO: refactor this to store source doodad data under KP.map
+ sourceItem = KP.mainWindow.doodadSelector.getDoodad(doodad.index)
+ self._sourceRef = weakref.ref(sourceItem)
+
+ self.resizing = None
+ self.rotating = None
+
+ self._updatePixmap()
+ self._updatePosition()
+ self._updateSize()
+
+ self.setAcceptHoverEvents(True)
+
+ if not hasattr(KPEditorDoodad, 'SELECTION_PEN'):
+ KPEditorDoodad.SELECTION_PEN = QtGui.QPen(Qt.red, 1, Qt.DotLine)
+
+
+
+ def _updatePixmap(self):
+ source = self._sourceRef()
+ pixmap = source.icon().pixmap(source.icon().availableSizes()[0])
+
+ self.prepareGeometryChange()
+ w, h = pixmap.width(), pixmap.height()
+
+ self.pixmap = pixmap
+
+
+ def _updatePosition(self):
+ # NOTE: EditorDoodads originate at the centre, not the top left like the others
+ doodad = self._doodadRef()
+ x,y = doodad.position
+ w,h = doodad.size
+ self.setPos(x+floor(w/2.0), y+floor(h/2.0))
+
+
+ def _updateSize(self):
+ self.prepareGeometryChange()
+
+ w,h = self._doodadRef().size
+
+ self._boundingRect = QtCore.QRectF(-w/2, -h/2, w, h)
+ self._selectionRect = self._boundingRect.adjusted(0, 0, -1, -1)
+
+
+ def _updateTransform(self):
+ doodad = self._doodadRef()
+
+ self.setRotation(doodad.angle)
+
+
+ def paint(self, painter, option, widget):
+ if self.isSelected():
+ painter.setPen(self.SELECTION_PEN)
+ painter.drawRect(self._selectionRect)
+
+
+ def _itemMoved(self, oldX, oldY, newX, newY):
+ doodad = self._doodadRef()
+ w,h = doodad.size
+ doodad.position = [newX-floor(w/2.0), newY-floor(h/2.0)]
+
+
+ def hoverMoveEvent(self, event):
+ if self._layerRef() != KP.mapScene.currentLayer:
+ self.setCursor(Qt.ArrowCursor)
+ return
+
+ pos = event.pos()
+ bit = self.resizerPortionAt(pos.x(), pos.y())
+
+
+ if (event.modifiers() == Qt.ShiftModifier):
+
+ if bit:
+ self.setCursor(Qt.OpenHandCursor)
+ else:
+ self.setCursor(Qt.ArrowCursor)
+
+ else:
+
+ if bit == 1 or bit == 4:
+ self.setCursor(Qt.SizeFDiagCursor)
+ elif bit == 2 or bit == 3:
+ self.setCursor(Qt.SizeBDiagCursor)
+ elif bit == 7 or bit == 8:
+ self.setCursor(Qt.SizeHorCursor)
+ elif bit == 5 or bit == 6:
+ self.setCursor(Qt.SizeVerCursor)
+ else:
+ self.setCursor(Qt.ArrowCursor)
+
+
+ def mousePressEvent(self, event):
+ if event.button() == Qt.LeftButton:
+ pos = event.pos()
+ bit = self.resizerPortionAt(pos.x(), pos.y())
+
+ if self._layerRef() == KP.mapScene.currentLayer and bit:
+ event.accept()
+
+ if (event.modifiers() & Qt.ShiftModifier):
+ self.rotating = self.mapToScene(pos), self._doodadRef().angle
+ self.setCursor(Qt.ClosedHandCursor)
+ return
+
+ else:
+ x, xSide, y, ySide = False, None, False, None
+
+ if bit == 1 or bit == 7 or bit == 3: # left
+ x, xSide = True, 1
+
+ elif bit == 2 or bit == 4 or bit == 8: # right
+ x, xSide = True, 0
+
+ if bit == 1 or bit == 2 or bit == 5: # top
+ y, ySide = True, 1
+
+ elif bit == 3 or bit == 4 or bit == 6: # bottom
+ y, ySide = True, 0
+
+ self._updateSize()
+ self.resizing = (x, xSide, y, ySide)
+ return
+
+
+ KPEditorItem.mousePressEvent(self, event)
+
+
+ def _tryAndResize(self, obj, axisIndex, mousePosition, stationarySide):
+
+ newSize = abs(mousePosition) * 2
+
+ if newSize < 10:
+ return False
+
+ obj.size[axisIndex] = newSize
+
+ return True
+
+
+ def _tryAndRotate(self, obj, mouseX, mouseY, originalPos, oldAngle, modifiers):
+ center = self.mapToScene(self.boundingRect().center())
+
+ objX = center.x()
+ objY = center.y()
+
+
+ origX = originalPos.x()
+ origY = originalPos.y()
+
+ dy = origY - objY
+ dx = origX - objX
+ rads = math.atan2(dy, dx)
+
+ origAngle = math.degrees(rads)
+
+ dy = mouseY - objY
+ dx = mouseX - objX
+ rads = math.atan2(dy, dx)
+
+ angle = math.degrees(rads)
+
+
+ # Move this to ItemChange() or something at some point.
+ finalAngle = angle - origAngle + oldAngle
+
+ if (modifiers & Qt.ControlModifier):
+ finalAngle = int(finalAngle / 45.0) * 45.0
+
+ return True, finalAngle
+
+
+ def mouseMoveEvent(self, event):
+ if self.resizing:
+ obj = self._doodadRef()
+
+ hasChanged = False
+ resizeX, xSide, resizeY, ySide = self.resizing
+
+ if resizeX:
+ hasChanged |= self._tryAndResize(obj, 0, event.pos().x(), xSide)
+ if resizeY:
+ hasChanged |= self._tryAndResize(obj, 1, event.pos().y(), ySide)
+
+ if hasChanged:
+ # Doodads aren't supposed to snap, they're all free flowing like the wind.
+ self._updateSize()
+
+
+ elif self.rotating:
+ obj = self._doodadRef()
+ scenePos = event.scenePos()
+ self.setTransformOriginPoint(self.boundingRect().center())
+
+ hasChanged = False
+
+ hasChanged, angle = self._tryAndRotate(obj, scenePos.x(), scenePos.y(), self.rotating[0], self.rotating[1], event.modifiers())
+
+ if hasChanged:
+ obj.angle = angle
+ self._updateTransform()
+
+
+ else:
+ KPEditorItem.mouseMoveEvent(self, event)
+
+
+ def mouseReleaseEvent(self, event):
+ if self.resizing and event.button() == Qt.LeftButton:
+ self.resizing = None
+ # self._doodadRef().position = [self.x(), self.y()]
+
+ elif self.rotating and event.button() == Qt.LeftButton:
+ self.rotating = None
+
+ else:
+ KPEditorItem.mouseReleaseEvent(self, event)
+
+
+ def remove(self, withItem=False):
+ doodad = self._doodadRef()
+ layer = self._layerRef()
+
+ layer.objects.remove(doodad)
+
+ if withItem:
+ self.scene().removeItem(self)
+
+
+
diff --git a/src/editorui/editorcommon.py b/src/editorui/editorcommon.py
new file mode 100644
index 0000000..945375e
--- /dev/null
+++ b/src/editorui/editorcommon.py
@@ -0,0 +1,77 @@
+from common import *
+
+class KPEditorItem(QtGui.QGraphicsItem):
+ def __init__(self):
+ QtGui.QGraphicsItem.__init__(self)
+ self.setFlags(
+ self.ItemSendsGeometryChanges |
+ self.ItemIsSelectable |
+ self.ItemIsMovable
+ )
+
+ self.ignoreMovement = False
+ self.overrideSnap = False
+
+ def itemChange(self, change, value):
+ if change == self.ItemPositionChange and not self.ignoreMovement:
+ currentX, currentY = self.x(), self.y()
+
+ newpos = value.toPyObject()
+
+ x, y = newpos.x(), newpos.y()
+
+ if self.overrideSnap:
+ snapX, snapY = 1, 1
+ else:
+ # snap the item
+ snapX, snapY = self.SNAP_TO
+ x = int((x + (snapX/2)) / snapX) * snapX
+ y = int((y + (snapY/2)) / snapY) * snapY
+
+ if x < 0: x = 0
+ if x >= (12288+snapX): x = (12288+snapX-1)
+ if y < 0: y = 0
+ if y >= (12288+snapY): y = (12288+snapY-1)
+
+ if x != currentX or y != currentY:
+ self._itemMoved(currentX, currentY, x, y)
+
+ newpos.setX(x)
+ newpos.setY(y)
+ return newpos
+
+ return QtGui.QGraphicsItem.itemChange(self, change, value)
+
+ def boundingRect(self):
+ return self._boundingRect
+
+
+ def resizerPortionAt(self, x, y, originX=0, originY=0):
+ try:
+ leftBound, topBound = originX+5, originY+5
+ rightBound, bottomBound = self._resizerEndXY
+ except AttributeError:
+ rect = self._boundingRect
+ leftBound, topBound = rect.x() + 5, rect.y() + 5
+ rightBound, bottomBound = rect.right() - 5, rect.bottom() - 5
+
+ if y < topBound:
+ if x < leftBound: return 1 # TOP_LEFT
+ elif x >= rightBound: return 2 # TOP_RIGHT
+ else: return 5 # TOP
+
+ elif y >= bottomBound:
+ if x < leftBound: return 3 # BOTTOM_LEFT
+ elif x >= rightBound: return 4 # BOTTOM_RIGHT
+ else: return 6 # BOTTOM
+
+ else:
+ if x < leftBound: return 7 # LEFT
+ elif x >= rightBound: return 8 # RIGHT
+ else: return None
+
+
+ def _itemMoved(self, oldX, oldY, newX, newY):
+ pass
+
+
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)
+
+
+
+
diff --git a/src/editorui/objects.py b/src/editorui/objects.py
new file mode 100644
index 0000000..1ae46f7
--- /dev/null
+++ b/src/editorui/objects.py
@@ -0,0 +1,182 @@
+from common import *
+from editorcommon import *
+import weakref
+
+class KPEditorObject(KPEditorItem):
+ SNAP_TO = (24,24)
+
+ def __init__(self, obj, layer):
+ KPEditorItem.__init__(self)
+ obj.qtItem = self
+ self._objRef = weakref.ref(obj)
+ self._layerRef = weakref.ref(layer)
+ self._updatePosition()
+ self._updateSize()
+
+ self.setAcceptHoverEvents(True)
+
+ self.resizing = None
+
+ if not hasattr(KPEditorObject, 'SELECTION_PEN'):
+ KPEditorObject.SELECTION_PEN = QtGui.QPen(Qt.white, 1, Qt.DotLine)
+
+ # I don't bother setting the ZValue because it doesn't quite matter:
+ # only one layer's objects are ever clickable, and drawBackground takes
+ # care of the layered drawing
+
+ def _updatePosition(self):
+ self.ignoreMovement = True
+ x,y = self._objRef().position
+ self.setPos(x*24, y*24)
+ self.ignoreMovement = False
+
+ def _updateSize(self):
+ self.prepareGeometryChange()
+
+ obj = self._objRef()
+ w,h = obj.size
+
+ self._boundingRect = QtCore.QRectF(0, 0, w*24, h*24)
+ self._selectionRect = QtCore.QRectF(0, 0, w*24-1, h*24-1)
+
+ self._resizerEndXY = (w*24-5, h*24-5)
+
+
+ def paint(self, painter, option, widget):
+ if self.isSelected():
+ painter.setPen(self.SELECTION_PEN)
+ painter.drawRect(self._selectionRect)
+
+
+ def hoverMoveEvent(self, event):
+ if self._layerRef() != KP.mapScene.currentLayer:
+ self.setCursor(Qt.ArrowCursor)
+ return
+
+ pos = event.pos()
+ bit = self.resizerPortionAt(pos.x(), pos.y())
+
+ if bit == 1 or bit == 4:
+ self.setCursor(Qt.SizeFDiagCursor)
+ elif bit == 2 or bit == 3:
+ self.setCursor(Qt.SizeBDiagCursor)
+ elif bit == 7 or bit == 8:
+ self.setCursor(Qt.SizeHorCursor)
+ elif bit == 5 or bit == 6:
+ self.setCursor(Qt.SizeVerCursor)
+ else:
+ self.setCursor(Qt.ArrowCursor)
+
+
+ def mousePressEvent(self, event):
+ if event.button() == Qt.LeftButton:
+ pos = event.pos()
+ bit = self.resizerPortionAt(pos.x(), pos.y())
+
+ if self._layerRef() == KP.mapScene.currentLayer and bit:
+ event.accept()
+
+ x, xSide, y, ySide = False, None, False, None
+
+ if bit == 1 or bit == 7 or bit == 3:
+ x, xSide = True, 1
+ elif bit == 2 or bit == 4 or bit == 8:
+ x, xSide = True, 0
+
+ if bit == 1 or bit == 2 or bit == 5:
+ y, ySide = True, 1
+ elif bit == 3 or bit == 4 or bit == 6:
+ y, ySide = True, 0
+
+ self.resizing = (x, xSide, y, ySide)
+ return
+
+ KPEditorItem.mousePressEvent(self, event)
+
+
+ def _tryAndResize(self, obj, axisIndex, mousePosition, stationarySide):
+ objPosition = obj.position[axisIndex]
+ objSize = obj.size[axisIndex]
+
+ if stationarySide == 0:
+ # Resize the right/bottom side
+ relativeMousePosition = mousePosition - objPosition
+ newSize = relativeMousePosition + 1
+ if newSize == objSize or newSize < 1:
+ return False
+
+ if axisIndex == 1:
+ obj.size = (obj.size[0], newSize)
+ else:
+ obj.size = (newSize, obj.size[1])
+
+ else:
+ # Resize the left/top side
+ rightSide = objPosition + objSize - 1
+ newLeftSide = mousePosition
+
+ newPosition = newLeftSide
+ newSize = rightSide - newLeftSide + 1
+
+ if newSize < 1:
+ return False
+ if newPosition == objPosition and newSize == objSize:
+ return False
+
+ if axisIndex == 1:
+ obj.position = (obj.position[0], newPosition)
+ obj.size = (obj.size[0], newSize)
+ else:
+ obj.position = (newPosition, obj.position[1])
+ obj.size = (newSize, obj.size[1])
+
+ return True
+
+
+ def mouseMoveEvent(self, event):
+ if self.resizing:
+ obj = self._objRef()
+ scenePos = event.scenePos()
+
+ hasChanged = False
+ resizeX, xSide, resizeY, ySide = self.resizing
+
+ if resizeX:
+ hasChanged |= self._tryAndResize(obj, 0, int(scenePos.x() / 24), xSide)
+ if resizeY:
+ hasChanged |= self._tryAndResize(obj, 1, int(scenePos.y() / 24), ySide)
+
+ if hasChanged:
+ obj.updateCache()
+ self._layerRef().updateCache()
+ self._updatePosition()
+ self._updateSize()
+
+ else:
+ KPEditorItem.mouseMoveEvent(self, event)
+
+
+ def mouseReleaseEvent(self, event):
+ if self.resizing and event.button() == Qt.LeftButton:
+ self.resizing = None
+ else:
+ KPEditorItem.mouseReleaseEvent(self, event)
+
+
+ def _itemMoved(self, oldX, oldY, newX, newY):
+ obj = self._objRef()
+ obj.position = (newX/24, newY/24)
+ self._layerRef().updateCache()
+
+
+ def remove(self, withItem=False):
+ obj = self._objRef()
+ layer = self._layerRef()
+
+ layer.objects.remove(obj)
+ layer.updateCache()
+
+ if withItem:
+ self.scene().removeItem(self)
+
+
diff --git a/src/editorui/paths.py b/src/editorui/paths.py
new file mode 100644
index 0000000..4dca31e
--- /dev/null
+++ b/src/editorui/paths.py
@@ -0,0 +1,319 @@
+from common import *
+from editorcommon import *
+import weakref
+
+class KPEditorNode(KPEditorItem):
+ SNAP_TO = (12,12)
+
+
+ class toggleButton(QtGui.QPushButton):
+
+ stateToggled = QtCore.pyqtSignal(int)
+
+
+ def __init__(self):
+ QtGui.QPushButton.__init__(self)
+
+ self.setIconSize(QtCore.QSize(24, 24))
+ self.setFixedSize(24, 24)
+
+ self.iconList = [QtGui.QIcon("Resources/Through.png"),
+ QtGui.QIcon("Resources/Level.png"),
+ QtGui.QIcon("Resources/Stop.png")]
+
+ self.state = 0
+
+ self.setPalette(QtGui.QPalette(QtGui.QColor(0,0,0,0)))
+
+ self.released.connect(self.toggle)
+
+
+ def toggle(self):
+
+ self.state += 1
+ if self.state == 3:
+ self.state = 0
+
+ self.stateToggled.emit(self.state)
+
+
+ def paintEvent(self, event):
+
+ painter = QtGui.QPainter(self)
+
+ painter.setBackgroundMode(Qt.TransparentMode)
+ painter.setBrush(QtGui.QColor(0,0,0,0))
+ painter.setPen(QtGui.QColor(0,0,0,0))
+
+ if self.isDown():
+ self.iconList[self.state].paint(painter, self.contentsRect(), Qt.AlignCenter, QtGui.QIcon.Disabled)
+ else:
+ self.iconList[self.state].paint(painter, self.contentsRect())
+ painter.end()
+
+
+ class hiddenProxy(QtGui.QGraphicsProxyWidget):
+ def __init__(self, button):
+ QtGui.QGraphicsProxyWidget.__init__(self)
+
+ self.setWidget(button)
+ self.setZValue(self.zValue()+1000)
+ self.hide()
+
+
+ class levelSlotSpinner(QtGui.QSpinBox):
+
+ def __init__(self):
+ QtGui.QSpinBox.__init__(self)
+
+ self.setRange(1, 99)
+
+ self.setPalette(QtGui.QPalette(QtGui.QColor(0,0,0,0)))
+
+
+
+ def __init__(self, node):
+ KPEditorItem.__init__(self)
+
+ node.qtItem = self
+ self._nodeRef = weakref.ref(node)
+
+ self.setZValue(101)
+
+ self._boundingRect = QtCore.QRectF(-24, -24, 48, 48)
+ self._tinyRect = QtCore.QRectF(-12, -12, 24, 24)
+
+
+ if not hasattr(KPEditorNode, 'SELECTION_PEN'):
+ KPEditorNode.SELECTION_PEN = QtGui.QPen(Qt.blue, 1, Qt.DotLine)
+
+ self.button = self.toggleButton()
+ self.buttonProxy = self.hiddenProxy(self.button)
+ self.button.stateToggled.connect(self.stateChange)
+
+
+ self.world = self.levelSlotSpinner()
+ self.worldProxy = self.hiddenProxy(self.world)
+ self.world.valueChanged.connect(self.worldChange)
+
+ self.stage = self.levelSlotSpinner()
+ self.stageProxy = self.hiddenProxy(self.stage)
+ self.stage.valueChanged.connect(self.stageChange)
+
+
+ self._updatePosition()
+
+
+
+ @QtCore.pyqtSlot(int)
+ def stateChange(self, state):
+
+ node = self._nodeRef()
+
+ if state == 1:
+ node.level = [1, 1]
+ self.world.setValue(node.level[0])
+ self.stage.setValue(node.level[1])
+
+ elif state == 2:
+ node.isStop = True
+ node.level = [0,0]
+
+ else:
+ node.isStop = False
+ node.level = [0,0]
+
+ self.update()
+
+
+ @QtCore.pyqtSlot(int)
+ def worldChange(self, world):
+
+ node = self._nodeRef()
+ node.level[0] = world
+
+
+ @QtCore.pyqtSlot(int)
+ def stageChange(self, stage):
+
+ node = self._nodeRef()
+ node.level[1] = stage
+
+
+
+ def _updatePosition(self):
+ node = self._nodeRef()
+ x, y = node.position
+ self.setPos(x+12, y+12)
+ self.buttonProxy.setPos(self.x()+12, self.y()-24)
+ self.worldProxy.setPos(self.x()-42, self.y()+24)
+ self.stageProxy.setPos(self.x()+6, self.y()+24)
+
+
+ def _itemMoved(self, oldX, oldY, newX, newY):
+ node = self._nodeRef()
+ node.position = (newX-12, newY-12)
+
+ self.buttonProxy.setPos(newX+12, newY-24)
+ self.worldProxy.setPos(newX-42, newY+24)
+ self.stageProxy.setPos(newX+6, newY+24)
+
+ for exit in node.exits:
+ exit.qtItem.updatePosition()
+
+
+ def paint(self, painter, option, widget):
+
+ node = self._nodeRef()
+
+ selectionRect = None
+
+ if node.level != [0,0]:
+ painter.setBrush(QtGui.QColor(0, 0, 0, 0))
+ painter.setPen(QtGui.QColor(0, 0, 0, 0))
+ painter.drawPixmap(self._boundingRect.topLeft(), QtGui.QPixmap("Resources/BlackLevel.png"))
+ selectionRect = self._boundingRect.adjusted(-1,-1,1,1)
+
+ elif node.isStop:
+ brush = QtGui.QBrush(QtGui.QColor(255, 220, 220))
+ painter.setPen(QtGui.QColor(255, 255, 255))
+ painter.setBrush(brush)
+ painter.drawEllipse(self._tinyRect)
+ selectionRect = self._tinyRect.adjusted(-1,-1,1,1)
+
+ else:
+ brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
+ painter.setPen(QtGui.QColor(255, 255, 255))
+ painter.setBrush(brush)
+ painter.drawEllipse(self._tinyRect)
+ selectionRect = self._tinyRect.adjusted(-1,-1,1,1)
+
+
+ if self.isSelected():
+ painter.setPen(self.SELECTION_PEN)
+ painter.setBrush(QtGui.QColor(0,0,0,0))
+ painter.drawEllipse(selectionRect)
+
+ self.buttonProxy.show()
+
+ if node.level != [0,0]:
+ self.worldProxy.show()
+ self.stageProxy.show()
+
+ else:
+ self.worldProxy.hide()
+ self.stageProxy.hide()
+
+ else:
+ self.buttonProxy.hide()
+ self.worldProxy.hide()
+ self.stageProxy.hide()
+
+
+
+
+ def remove(self, withItem=False):
+ node = self._nodeRef()
+ layer = KP.map.pathLayer
+
+ layer.nodes.remove(node)
+
+ self.scene().removeItem(self.buttonProxy)
+ self.scene().removeItem(self.stageProxy)
+ self.scene().removeItem(self.worldProxy)
+
+ if len(node.exits) == 2:
+ # let's try to join the two!
+ pathOne, pathTwo = node.exits
+
+ start1, end1 = pathOne._startNodeRef(), pathOne._endNodeRef()
+ start2, end2 = pathTwo._startNodeRef(), pathTwo._endNodeRef()
+
+ if start1 == node:
+ start = end1
+ else:
+ start = start1
+
+ if start2 == node:
+ end = end2
+ else:
+ end = start2
+
+ # make sure no path already exists between these nodes
+ nope = False
+
+ for pathToCheck in start.exits:
+ if pathToCheck._startNodeRef() == end:
+ nope = True
+ elif pathToCheck._endNodeRef() == end:
+ nope = True
+
+ if not nope:
+ joinedPath = KPPath(start, end, pathOne)
+ layer.paths.append(joinedPath)
+ item = KPEditorPath(joinedPath)
+ self.scene().addItem(item)
+
+ for path in (pathOne, pathTwo):
+ path.qtItem.remove(True)
+ else:
+ # we can't join them so just nuke them
+ for exit in node.exits[:]:
+ exit.qtItem.remove(True)
+
+ if withItem:
+ self.scene().removeItem(self)
+
+
+
+class KPEditorPath(QtGui.QGraphicsLineItem):
+ def __init__(self, path):
+ QtGui.QGraphicsLineItem.__init__(self)
+
+ self.setFlag(self.ItemIsSelectable, True)
+
+ self.setZValue(100)
+
+ startNode = path._startNodeRef().qtItem
+ endNode = path._endNodeRef().qtItem
+
+ self._startNodeRef = weakref.ref(startNode)
+ self._endNodeRef = weakref.ref(endNode)
+ self._pathRef = weakref.ref(path)
+
+ path.qtItem = self
+
+ self.updatePosition()
+
+ if not hasattr(KPEditorPath, 'PEN'):
+ KPEditorPath.BRUSH = QtGui.QBrush(QtGui.QColor(255, 255, 255, 140))
+ KPEditorPath.PEN = QtGui.QPen(KPEditorPath.BRUSH, 8, Qt.SolidLine, Qt.RoundCap)
+ self.setPen(KPEditorPath.PEN)
+
+
+ def updatePosition(self):
+ path = self._pathRef()
+
+ x1, y1 = path._startNodeRef().position
+ x2, y2 = path._endNodeRef().position
+
+ self.setLine(QtCore.QLineF(x1+12, y1+12, x2+12, y2+12))
+
+
+ def remove(self, withItem=False):
+ path = self._pathRef()
+ layer = KP.map.pathLayer
+
+ layer.paths.remove(path)
+
+ for ref in (self._startNodeRef, self._endNodeRef):
+ node = ref()._nodeRef()
+ try:
+ node.exits.remove(path)
+ except ValueError:
+ pass
+
+ if withItem:
+ self.scene().removeItem(self)
+
+