diff options
author | Treeki <treeki@gmail.com> | 2011-11-21 05:35:41 +0100 |
---|---|---|
committer | Treeki <treeki@gmail.com> | 2011-11-21 05:35:41 +0100 |
commit | 5e0804a65cefec0283bb0809c1fb18bcad4746cf (patch) | |
tree | 1a28add68c67a92adc1ce31ce51d415b10360e7e | |
parent | e6efa1b751316ed5c2fbb6ad8c5360d7cf7d576d (diff) | |
download | koopatlas-5e0804a65cefec0283bb0809c1fb18bcad4746cf.tar.gz koopatlas-5e0804a65cefec0283bb0809c1fb18bcad4746cf.zip |
wonderful, wonderful paths
-rw-r--r-- | src/editorui.py | 326 | ||||
-rw-r--r-- | src/mapdata.py | 76 | ||||
-rw-r--r-- | src/ui.py | 2 |
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 @@ -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() |