summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2011-11-21 05:35:41 +0100
committerTreeki <treeki@gmail.com>2011-11-21 05:35:41 +0100
commit5e0804a65cefec0283bb0809c1fb18bcad4746cf (patch)
tree1a28add68c67a92adc1ce31ce51d415b10360e7e
parente6efa1b751316ed5c2fbb6ad8c5360d7cf7d576d (diff)
downloadkoopatlas-5e0804a65cefec0283bb0809c1fb18bcad4746cf.tar.gz
koopatlas-5e0804a65cefec0283bb0809c1fb18bcad4746cf.zip
wonderful, wonderful paths
-rw-r--r--src/editorui.py326
-rw-r--r--src/mapdata.py76
-rw-r--r--src/ui.py2
3 files changed, 284 insertions, 120 deletions
diff --git a/src/editorui.py b/src/editorui.py
index 3b0f0d9..b05cbe2 100644
--- a/src/editorui.py
+++ b/src/editorui.py
@@ -94,6 +94,9 @@ class KPEditorObject(KPEditorItem):
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
@@ -118,7 +121,7 @@ class KPEditorObject(KPEditorItem):
def paint(self, painter, option, widget):
if self.isSelected():
- painter.setPen(QtGui.QPen(Qt.white, 1, Qt.DotLine))
+ painter.setPen(self.SELECTION_PEN)
painter.drawRect(self._selectionRect)
@@ -172,9 +175,6 @@ class KPEditorObject(KPEditorItem):
objPosition = obj.position[axisIndex]
objSize = obj.size[axisIndex]
- mousePosition = int(mousePosition / 12) * 12
-
-
if stationarySide == 0:
# Resize the right/bottom side
relativeMousePosition = mousePosition - objPosition
@@ -246,24 +246,22 @@ class KPEditorObject(KPEditorItem):
self._layerRef().updateCache()
- def remove(self):
+ 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)
- self.setFlags(
- self.ItemSendsGeometryChanges |
- self.ItemIsSelectable |
- self.ItemIsMovable
- )
doodad.qtItem = self
self._doodadRef = weakref.ref(doodad)
@@ -281,8 +279,12 @@ class KPEditorDoodad(KPEditorItem):
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])
@@ -316,14 +318,9 @@ class KPEditorDoodad(KPEditorItem):
self.setRotation(doodad.angle)
- def itemChange(self, change, value):
-
- return QtGui.QGraphicsItem.itemChange(self, change, value)
-
-
def paint(self, painter, option, widget):
if self.isSelected():
- painter.setPen(QtGui.QPen(Qt.red, 1, Qt.DotLine))
+ painter.setPen(self.SELECTION_PEN)
painter.drawRect(self._selectionRect)
@@ -490,102 +487,144 @@ class KPEditorDoodad(KPEditorItem):
KPEditorItem.mouseReleaseEvent(self, event)
- def remove(self):
+ def remove(self, withItem=False):
doodad = self._doodadRef()
layer = self._layerRef()
layer.objects.remove(doodad)
- del doodad
+ if withItem:
+ self.scene().removeItem(self)
-class KPEditorNode(QtGui.QGraphicsPixmapItem):
- def __init__(self, node, layer):
- QtGui.QGraphicsPixmapItem.__init__(self)
- self.setFlags(
- self.ItemSendsGeometryChanges |
- self.ItemIsSelectable |
- self.ItemIsMovable
- )
-class KPEditorPathSegment(QtGui.QGraphicsPathItem):
- def __init__(self, node, layer):
- QtGui.QGraphicsPathItem.__init__(self)
- self.setFlags(
- self.ItemSendsGeometryChanges |
- self.ItemIsSelectable |
- self.ItemIsMovable
- )
+class KPEditorNode(KPEditorItem):
+ SNAP_TO = (12,12)
- self.path = QtGui.QPainterPath()
- self.brush = None
- self.pen = None
+ def __init__(self, node):
+ KPEditorItem.__init__(self)
- self.rotation = 0
+ node.qtItem = self
+ self._nodeRef = weakref.ref(node)
+
+ self.setZValue(101)
+
+ self._boundingRect = QtCore.QRectF(-12, -12, 24, 24)
+ self._selectionRect = QtCore.QRectF(-12, -12, 23, 23)
+ self._updatePosition()
+
+ if not hasattr(KPEditorNode, 'SELECTION_PEN'):
+ KPEditorNode.SELECTION_PEN = QtGui.QPen(Qt.blue, 1, Qt.DotLine)
+
+ def _updatePosition(self):
+ node = self._nodeRef()
+ x, y = node.position
+ self.setPos(x+12, y+12)
+
+ def _itemMoved(self, oldX, oldY, newX, newY):
+ node = self._nodeRef()
+ node.position = (newX-12, newY-12)
+
+ for exit in node.exits:
+ exit.qtItem.updatePosition()
+
+
+ def paint(self, painter, option, widget):
+ painter.fillRect(self._boundingRect, Qt.white)
+ if self.isSelected():
+ painter.setPen(self.SELECTION_PEN)
+ painter.drawRect(self._selectionRect)
- def makeStraight(self, start, end):
+ def remove(self, withItem=False):
+ node = self._nodeRef()
+ layer = KP.map.pathLayer
- self.path.moveTo(start)
- self.path.addPolygon(QtGui.QPolygon([QtCore.QPointF(start.x(), start.y()-5.0),
- QtCore.QPointF(end.x(), end.y()-5.0),
- QtCore.QPointF(end.x(), end.y()+5.0),
- QtCore.QPointF(start.x(), start.y()+5.0),
- QtCore.QPointF(start.x(), start.y()-5.0)]))
+ layer.nodes.remove(node)
+ if len(node.exits) == 2:
+ # let's try to join the two!
+ pathOne, pathTwo = node.exits
- center = QtCore.QPointF((end.x()/2)-(start.x()/2), (end.y()/2)-((start.y()/2) + 16))
- graduate = QtGui.QRadialGradiant(center, float((end.x()/2)-(start.x()/2)))
- graduate.setColorA(QtGui.QColor(200, 210, 240))
- graduate.setColorB(QtGui.QColor(150, 160, 190))
+ start1, end1 = pathOne._startNodeRef(), pathOne._endNodeRef()
+ start2, end2 = pathTwo._startNodeRef(), pathTwo._endNodeRef()
- self.brush = QtGui.QBrush(graduate)
+ if start1 == node:
+ start = end1
+ else:
+ start = start1
- self.pen = QtGui.QPen(QColor(120, 130, 160))
- self.pen.setWidth(4)
- self.pen.setCapStyle(Qt.RoundCap)
- self.pen.setJoinStyle(Qt.RoundJoin)
-
+ if start2 == node:
+ end = end2
+ else:
+ end = start2
- def makeArc(self, start, end):
+ joinedPath = KPPath(start, end, pathOne)
+ layer.paths.append(joinedPath)
+ item = KPEditorPath(joinedPath)
+ self.scene().addItem(item)
- self.path.moveTo(start)
- self.path.addEllipse(start.x(), start.y(), end.x()-start.x(), end.y()-start.y())
- r = QtGui.QPainterPath()
- r.addEllipse(start.x(), start.y()-4, end.x()-start.x(), end.y()-start.y()-16)
+ # whatever happened, delete the old paths anyway
+ for exit in node.exits:
+ exit.qtItem.remove(True)
- self.path.subtracted(r)
+ if withItem:
+ self.scene().removeItem(self)
- center = QtCore.QPointF((end.x()/2)-(start.x()/2), (end.y()/2)-((start.y()/2) + 16))
- graduate = QtGui.QRadialGradiant(center, float((end.x()/2)-(start.x()/2)))
- graduate.setColorA(QtGui.QColor(200, 210, 240))
- graduate.setColorB(QtGui.QColor(150, 160, 190))
+class KPEditorPath(QtGui.QGraphicsLineItem):
+ def __init__(self, path):
+ QtGui.QGraphicsLineItem.__init__(self)
- self.brush = QtGui.QBrush(graduate)
+ self.setFlag(self.ItemIsSelectable, True)
- self.pen = QtGui.QPen(QColor(120, 130, 160))
- self.pen.setWidth(4)
- self.pen.setCapStyle(Qt.RoundCap)
- self.pen.setJoinStyle(Qt.RoundJoin)
+ self.setZValue(100)
+ startNode = path._startNodeRef().qtItem
+ endNode = path._endNodeRef().qtItem
- sX = start.x()
- sY = start.y()
+ self._startNodeRef = weakref.ref(startNode)
+ self._endNodeRef = weakref.ref(endNode)
+ self._pathRef = weakref.ref(path)
- eX = end.x()
- eY = end.y()
+ path.qtItem = self
- dy = eY - sY
- dx = eX - sX
- rads = math.atan2(dy, dx)
+ self.updatePosition()
- self.rotate = math.degrees(rads)
+ 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)
@@ -692,25 +731,18 @@ class KPMapScene(QtGui.QGraphicsScene):
def setCurrentLayer(self, layer):
if self.currentLayer is not None:
- self.setLayerObjectsFlag(self.currentLayer, QtGui.QGraphicsItem.ItemIsSelectable, False)
- self.setLayerObjectsFlag(self.currentLayer, QtGui.QGraphicsItem.ItemIsMovable, False)
+ self.currentLayer.setActivated(False)
self.currentLayer = layer
- self.setLayerObjectsFlag(layer, QtGui.QGraphicsItem.ItemIsSelectable, True)
- self.setLayerObjectsFlag(layer, QtGui.QGraphicsItem.ItemIsMovable, True)
-
-
- def setLayerObjectsFlag(self, layer, flag, value):
- for obj in layer.objects:
- item = obj.qtItem
- if item:
- item.setFlag(flag, value)
+ 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)
@@ -735,10 +767,13 @@ class KPEditorWidget(QtGui.QGraphicsView):
def _tryToPaint(self, event):
'''Called when a paint attempt is initiated'''
- if self.paintNext is None: return
paint = self.paintNext
+ layer = self.scene().currentLayer
+ if not layer.visible: return
+
+ if isinstance(layer, KPTileLayer):
+ if paint is None: return
- if isinstance(paint, KPTileObject):
clicked = self.mapToScene(event.x(), event.y())
x, y = clicked.x(), clicked.y()
if x < 0: x = 0
@@ -747,10 +782,6 @@ class KPEditorWidget(QtGui.QGraphicsView):
x = int(x / 24)
y = int(y / 24)
- layer = self.scene().currentLayer
- if not layer.visible: return
- if not isinstance(layer, KPTileLayer): return
-
obj = KPObject()
obj.position = (x,y)
obj.size = (1,1)
@@ -767,16 +798,14 @@ class KPEditorWidget(QtGui.QGraphicsView):
self.paintingItem = item
self.paintBeginPosition = (x, y)
- if isinstance(paint, QtGui.QListWidgetItem):
+ 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
- layer = self.scene().currentLayer
- if not layer.visible: return
- if not isinstance(layer, KPDoodadLayer): return
-
obj = KPDoodad()
obj.position = [x,y]
obj.index = self.paintNextID
@@ -790,6 +819,94 @@ class KPEditorWidget(QtGui.QGraphicsView):
self.paintingItem = item
self.paintBeginPosition = (x, y)
+ elif isinstance(layer, KPPathLayer):
+ print "Going to paint something related to paths"
+
+ # 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):
+ print "Trying a line"
+ # 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()
+ print "Got source"
+ 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
+
+ path = KPPath(sourceNode, destNode)
+
+ KP.map.pathLayer.paths.append(path)
+ print "Done!"
+
+ 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.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.isStop = True
+ node.position = (x - 12, y - 12)
+ KP.map.pathLayer.nodes.append(node)
+
+ print "Painting a node at %r" % (node.position,)
+ item = KPEditorNode(node)
+ self.scene().addItem(item)
+
+ self.painting = node
+ self.paintingItem = item
+ self.paintBeginPosition = (x - 12, y - 12)
+
def _movedWhilePainting(self, event):
@@ -868,9 +985,8 @@ class KPEditorWidget(QtGui.QGraphicsView):
selection = scene.selectedItems()
if len(selection) > 0:
for obj in selection:
- obj.remove()
obj.setSelected(False)
- scene.removeItem(obj)
+ obj.remove(True)
scene.update()
self.update()
return
diff --git a/src/mapdata.py b/src/mapdata.py
index 85549e2..e864df0 100644
--- a/src/mapdata.py
+++ b/src/mapdata.py
@@ -1,4 +1,5 @@
from common import *
+import weakref
TILE_SIZE = (24,24)
MAP_SIZE_IN_TILES = (512,512)
@@ -27,6 +28,19 @@ class KPLayer(object):
def _visibilityChanged(self, value):
pass
+ def setActivated(self, value, listToUse=None):
+ flag1 = QtGui.QGraphicsItem.ItemIsSelectable
+ flag2 = QtGui.QGraphicsItem.ItemIsMovable
+
+ if listToUse is None:
+ listToUse = self.objects
+
+ for obj in listToUse:
+ item = obj.qtItem
+ if item:
+ item.setFlag(flag1, value)
+ item.setFlag(flag2, value)
+
class KPObject(object):
def __init__(self):
@@ -150,20 +164,38 @@ class KPNode(object):
def __init__(self):
self.position = (0,0)
self.actions = []
+ self.exits = []
+ self.isStop = False
-class KPPathSegment(object):
- def __init__(self):
- self.start = None
- self.end = None
- self.animation = None # default
+class KPPath(object):
+ def __init__(self, startNode, endNode, cloneFrom=None):
+ self._startNodeRef = weakref.ref(startNode)
+ self._endNodeRef = weakref.ref(endNode)
+ startNode.exits.append(self)
+ endNode.exits.append(self)
-class KPPath(object):
- def __init__(self):
- self.startNode = None
- self.endNode = None
- self.segments = []
+ if cloneFrom is None:
+ self.animation = None
+ else:
+ self.animation = cloneFrom.animation
+
+ def setStart(self, newStart):
+ currentStart = self._startNodeRef()
+ if currentStart is not None:
+ currentStart.exits.remove(self)
+
+ newStart.exits.append(self)
+ self._startNodeRef = weakref.ref(newStart)
+
+ def setEnd(self, newEnd):
+ currentEnd = self._endNodeRef()
+ if currentEnd is not None:
+ currentEnd.exits.remove(self)
+
+ newEnd.exits.append(self)
+ self._endNodeRef = weakref.ref(newEnd)
class KPPathLayer(KPLayer):
@@ -176,10 +208,20 @@ class KPPathLayer(KPLayer):
self.paths = []
def _visibilityChanged(self, value):
- for obj in self.objects:
- item = obj.qtItem
+ for objList in (self.nodes, self.paths):
+ for obj in objList:
+ item = obj.qtItem
+ if item:
+ item.setVisible(value)
+
+ def setActivated(self, value):
+ KPLayer.setActivated(self, value, self.nodes)
+
+ flag = QtGui.QGraphicsItem.ItemIsSelectable
+ for path in self.paths:
+ item = path.qtItem
if item:
- item.setVisible(value)
+ item.setFlag(flag, value)
@@ -189,7 +231,8 @@ class KPMap(object):
def __init__(self):
self.nextLayerNumber = 1
- self.layers = [self.createNewTileLayer('Test') for x in range(4)]
+ self.pathLayer = self._createPathLayer()
+ self.layers = [self.pathLayer]
self.layerModel = KPMap.LayerModel(self.layers)
self.nodes = []
self.paths = []
@@ -259,6 +302,11 @@ class KPMap(object):
return False
+ def _createPathLayer(self):
+ layer = KPPathLayer()
+ layer.name = 'Paths'
+ return layer
+
def createNewTileLayer(self, tilesetName):
layer = KPTileLayer()
layer.name = "Tilemap - Layer %d" % self.nextLayerNumber
diff --git a/src/ui.py b/src/ui.py
index e96b062..0eaddc0 100644
--- a/src/ui.py
+++ b/src/ui.py
@@ -446,7 +446,7 @@ class KPMainWindow(QtGui.QMainWindow):
self.objectSelectorDock.hide()
self.doodadSelectorDock.show()
- else:
+ elif isinstance(layer, KPTileLayer):
self.doodadSelectorDock.hide()
self.objectSelectorDock.show()