Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import sys
- import weakref
- import math
- from PySide import QtCore, QtGui
- ###
- class Edge(QtGui.QGraphicsItem):
- Type = QtGui.QGraphicsItem.UserType + 2
- def __init__(self, sourceNode, destNode):
- QtGui.QGraphicsItem.__init__(self)
- #
- self.sourcePoint = QtCore.QPointF()
- self.destPoint = QtCore.QPointF()
- self.setAcceptedMouseButtons(QtCore.Qt.NoButton)
- self.source = weakref.ref(sourceNode)
- self.dest = weakref.ref(destNode)
- self.source().addEdge(self)
- self.dest().addEdge(self)
- self.adjust()
- def type(self):
- return Edge.Type
- def sourceNode(self):
- return self.source()
- def destNode(self):
- return self.dest()
- def adjust(self):
- # do we have a line to draw ?
- if self.source() and self.dest():
- line = QtCore.QLineF(self.mapFromItem(self.source(), 0, 0), self.mapFromItem(self.dest(), 0, 0))
- length = line.length()
- if length > 20:
- edgeOffset = QtCore.QPointF((line.dx() * 10) / length, (line.dy() * 10) / length)
- self.prepareGeometryChange()
- self.sourcePoint = line.p1() + edgeOffset
- self.destPoint = line.p2() - edgeOffset
- else: # want to make sure line not drawn over node blob
- self.prepareGeometryChange()
- self.sourcePoint = self.destPoint
- def boundingRect(self):
- # do we have a line to draw ?
- if not self.source() or not self.dest():
- return QtCore.QRectF()
- else:
- extra = 1
- return QtCore.QRectF(self.sourcePoint,
- QtCore.QSizeF(self.destPoint.x() - self.sourcePoint.x(),
- self.destPoint.y() - self.sourcePoint.y())).normalized().adjusted(-extra, -extra, extra, extra)
- def paint(self, painter, option, widget):
- if self.source() and self.dest():
- # Draw the line itself.
- line = QtCore.QLineF(self.sourcePoint, self.destPoint)
- if line.length() > 0.0:
- painter.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
- painter.drawLine(line)
- ###
- class Node(QtGui.QGraphicsItem):
- Type = QtGui.QGraphicsItem.UserType + 1
- def __init__(self, graphWidget, time, temp, pos):
- QtGui.QGraphicsItem.__init__(self)
- self.graph = weakref.ref(graphWidget)
- self.edgeList = []
- self.set_index(pos)
- self.setFlag(QtGui.QGraphicsItem.ItemIsMovable)
- self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges)
- self.setCacheMode(self.DeviceCoordinateCache)
- self.setZValue(-1)
- #
- self.temp = temp
- self.time = time
- x,y = self.map_temptime_to_pos()
- self.setPos(x,y)
- self.marker = False
- def type(self):
- return Node.Type
- def edges(self):
- return self.edgeList
- def addEdge(self, edge):
- self.edgeList.append(weakref.ref(edge))
- def set_index(self, index):
- self.index = index
- def get_prev_edge(self):
- index = 1000
- edge = False
- for e in self.edgeList:
- sn = e().source().index
- dn = e().dest().index
- if sn < index:
- index = sn
- edge = e
- if dn < index:
- index = dn
- edge = e
- return edge
- def get_next_edge(self):
- index = -1
- edge = False
- for e in self.edgeList:
- sn = e().source().index
- dn = e().dest().index
- if sn > index:
- index = sn
- edge = e
- if dn > index:
- index = dn
- edge = e
- return edge
- def map_pos_to_temptime(self, value=False):
- """ given screen pos return temp,time
- - optional value indicates actual pos from event
- failed attempt to correct for 0,0 position after deletion """
- if value:
- x = value.x()
- y = value.y()
- else:
- x = self.x()
- y = self.y()
- print "node at",x,y
- height = self.graph().size[3]
- time = x / self.graph().graph_width_ratio
- temp = (height - y ) / self.graph().graph_height_ratio
- return (time, temp)
- def map_temptime_to_pos(self):
- x = self.time * self.graph().graph_width_ratio
- y = self.graph().size[3] - self.temp * self.graph().graph_height_ratio
- return (x,y)
- def boundingRect(self):
- adjust = 2.0
- return QtCore.QRectF(-10 - adjust, -10 - adjust,
- 22 + adjust, 23 + adjust)
- def paint(self, painter, option, widget):
- painter.drawLine(QtCore.QLineF(6,-40,6,-2))
- painter.setPen(QtCore.Qt.NoPen)
- painter.setBrush(QtCore.Qt.lightGray)
- painter.drawEllipse(-10, -10, 20, 20)
- gradient = QtGui.QRadialGradient(0, 0, 22)
- if option.state & QtGui.QStyle.State_Sunken: # selected
- gradient.setColorAt(0, QtGui.QColor(QtCore.Qt.darkGreen).lighter(120))
- else:
- gradient.setColorAt(1, QtCore.Qt.blue)
- painter.setBrush(QtGui.QBrush(gradient))
- painter.setPen(QtGui.QPen(QtCore.Qt.black, 0))
- painter.drawEllipse(-6, -6, 12, 12)
- def itemChange(self, change, value):
- if change == QtGui.QGraphicsItem.ItemPositionChange:
- print "redraw my edges", value
- print "current:",self.temp, self.time
- for edge in self.edgeList:
- edge().adjust()
- #return super(Node, self).itemChange(change, value)
- return value
- def mousePressEvent(self, event):
- if not self.graph().inhibit_edit:
- self.update()
- print "\nNode pressed"
- QtGui.QGraphicsItem.mousePressEvent(self, event)
- def mouseReleaseEvent(self, event):
- if not self.graph().inhibit_edit:
- timetemp = self.map_pos_to_temptime()
- self.time = timetemp[0]
- self.temp = timetemp[1]
- #self.update()
- print "Node released\n"
- #
- nodes = self.graph().get_ordered_nodes()
- # Check for delete
- i = self.index
- prevtime = -1000
- nexttime = 1000
- if i > 1:
- prevtime = nodes[i-2].time
- if i < len(nodes):
- nexttime = nodes[i].time
- print prevtime, self.time, nexttime
- if not (prevtime < self.time < nexttime):
- print "deleting"
- self.graph().delete_node(i)
- #
- self.update() #! not required
- QtGui.QGraphicsItem.mouseReleaseEvent(self, event)
- ###
- class GraphWidget(QtGui.QGraphicsView):
- def __init__(self):
- QtGui.QGraphicsView.__init__(self)
- self.size = (-30, 30, 600, 400)
- #
- scene = QtGui.QGraphicsScene(self)
- scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex)
- scene.setSceneRect(self.size[0],self.size[1],self.size[2],self.size[3])
- self.setScene(scene)
- self.setCacheMode(QtGui.QGraphicsView.CacheBackground)
- self.setRenderHint(QtGui.QPainter.Antialiasing)
- self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
- self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
- #
- self.maxtemp = 300
- self.maxtime = 160
- self.nodecount = 0
- self.calc_upper_limits()
- #
- self.scale(0.8, 0.8)
- self.setMinimumSize(600, 400)
- self.setWindowTitle(self.tr("Elastic Nodes"))
- self.inhibit_edit = False
- def calc_upper_limits(self):
- self.toptemp = (self.maxtemp / 100 + 1) * 100
- self.toptime = (int(self.maxtime) / 30 + 1) * 30
- self.graph_width_ratio = float(self.size[2]) /self.toptime
- self.graph_height_ratio = float(self.size[3]) / self.toptemp
- def add_node(self, time, temp, marker=False, pos=-1):
- self.nodecount += 1
- scene = self.scene()
- # Insert Node into scene
- node = Node(self, time, temp, self.nodecount)
- scene.addItem(node)
- # Insert new edges
- nodes = self.get_ordered_nodes()
- if len(nodes) > 1:
- e = Edge(nodes[-2], node)
- scene.addItem(e)
- def delete_node(self, index):
- """ delete node at index
- - reindex nodes, edges
- """
- nodes = self.get_ordered_nodes()
- node = nodes[index-1]
- # find preceding and next nodes
- pn = False
- nn = False
- if index > 1:
- pn = nodes[index-2]
- if index < len(nodes):
- nn = nodes[index]
- # disconnect edges between pn->node and node->nn
- if pn:
- e_index = pn.edges().index(pn.get_next_edge())
- print " removing edge",e_index,'from pn', pn.edges()
- pn.edges().pop(e_index)
- if nn:
- e_index = nn.edges().index(nn.get_prev_edge())
- print " removing edge",e_index,'from nn', nn.edges()
- nn.edges().pop(e_index)
- # add new edge between pn,nn -if node not an end
- if pn and nn:
- self.scene().addItem(Edge(pn, nn))
- # force first node to time=0
- if not pn:
- nn.force_to_Tzero()
- # remove edges belonging to node
- for e in node.edges():
- e().hide()
- self.scene().removeItem(e())
- del(e)
- node.hide()
- # remove node from scene
- self.scene().removeItem(node)
- del(node)
- # start from fresh nodes list
- # correct node numbering for this and following nodes and edges
- nodes = self.get_ordered_nodes()
- for i in range(len(nodes)):
- n = nodes[i]
- print "reindexing", n.index,i+1
- #n.prepareGeometryChange()
- n.set_index(i+1)
- self.nodecount -= 1
- def get_ordered_nodes(self):
- nodes = [item for item in self.scene().items() if isinstance(item, Node)]
- nodes.sort(key=lambda n: n.index)
- return nodes
- def mousePressEvent(self, event):
- print "GraphWidget mouse"
- QtGui.QGraphicsView.mousePressEvent(self, event)
- def drawBackground(self, painter, rect):
- sceneRect = self.sceneRect()
- if __name__ == "__main__":
- app = QtGui.QApplication(sys.argv)
- widget = GraphWidget()
- widget.add_node(0, 25)
- widget.add_node(30, 40)
- widget.add_node(80, 60)
- widget.add_node(100, 80)
- widget.show()
- sys.exit(app.exec_())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement