• Facebook
  • Twitter
  • Reddit
  • StumbleUpon
  • Digg
  • email

#!/usr/bin/env python2.6
# -*- coding: utf-8 -*-
 
 
#    Copyright (C) 2010 by RoboLab
#
#    This file is part of RoboComp
#
#    RoboComp is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    RoboComp is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with RoboComp.  If not, see <http://www.gnu.org/licenses/>.
#
 
from PyQt4 import QtGui
from PyQt4 import QtCore
import PyQt4
import random
import sys
import math
import managerCompConfig2
import managerNode
from logger import logger
 
class visualNode(QtGui.QGraphicsEllipseItem):
	def __init__(self, _parent, _contextMenu=None):
		QtGui.QGraphicsEllipseItem.__init__(self)
		#.parent() es una built function de QGraphicsEllipseItem
		self.nParent=_parent
		self.tl = QtCore.QTimeLine(50)
		self.tl.setFrameRange(0, 100)
		self.a = QtGui.QGraphicsItemAnimation()
		self.a.setItem(self)
		self.a.setTimeLine(self.tl)
		self.animated=False
 
		self.menu = None
		self.setFlag(QtGui.QGraphicsItem.ItemIsMovable);
		self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable);
		#~ self.setFlag(QtGui.QGraphicsItem.ItemSendsScenePositionChanges)
		self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges)
		self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache)
		self.setZValue(1);
		self.id=''
		self.text = QtGui.QGraphicsTextItem(self)
 
		self.setPos(random.randint(0, 400), random.randint(0, 400))
		#~ self.setRect(self.pos().x(), self.pos().y() , 20, 20)
		self.vel_x = 0.
		self.vel_y = 0.
		self.scale=200
 
		self.weight=30
		self.repulsion=300
		self.radius=30
		self.newPos=self.pos()
 
		self.contextMenu= _contextMenu
		self.stopAnimation()
 
 
 
	def boundingRect(self):
		adjust = 2
		return  QtCore.QRectF((-1*self.radius/2) -adjust, (-1*self.radius/2) -adjust, self.radius+ 3 + adjust, self.radius+ 3 +adjust)
 
	def shape(self):
		path= QtGui.QPainterPath()
		path.addEllipse((-1*self.radius/2) , (-1*self.radius/2) , self.radius, self.radius)
		return path
 
	def paint(self, painter, option, widget = None):
		if self.radius < 30:
			self.radius = 30
		gradient=QtGui.QRadialGradient(-3, -3, 10)
		if self.isSelected():
			gradient.setColorAt(1, QtCore.Qt.white)
			gradient.setColorAt(0, QtCore.Qt.black)
		else:
			if self.nParent and self.nParent.active:
				gradient.setColorAt(0, QtCore.Qt.green)
				gradient.setColorAt(1, QtCore.Qt.darkGreen)
			else:
				if self.nParent.data.failed == False:
					gradient.setColorAt(0, QtCore.Qt.red)
					gradient.setColorAt(1, QtCore.Qt.darkRed)
				else:
					gradient.setColorAt(0, QtCore.Qt.darkGray)
					gradient.setColorAt(1, QtCore.Qt.darkMagenta)
		painter.setBrush(gradient)
		painter.setPen(QtGui.QPen(QtCore.Qt.black, 0));
		painter.drawEllipse((-1*self.radius/2), (-1*self.radius/2), self.radius, self.radius);
		if self.nParent and self.nParent.active:
			painter.setBrush(QtGui.QColor(0, 255, 0, 0))
			painter.setPen(QtGui.QColor(0, 255, 0))
		else:
			painter.setBrush(QtGui.QColor(255, 0, 0, 0))
			painter.setPen(QtGui.QColor(255, 0, 0))
		painter.drawEllipse(-1*self.radius/2, -1*self.radius/2, self.radius, self.radius)
		font = painter.font()
		font.setBold(True);
		font.setPointSize(14);
		painter.setFont(font);
		if self.nParent:
			name = self.nParent.data.alias
			#~ name = self.nParent.data.endpoint
			self.text.setPlainText(name)
			self.text.setPos(-1*self.text.boundingRect().width()/2, -1*self.radius-3)
		#~ if self.parent.data.alias is not None:
		#~ painter.drawRect(self.boundingRect())
 
	#~ def advance(self, step):
		#~ print "visualNode.advance(): step="+str(step)
		#~ if self.newPos == self.pos():
			#~ return False
		#~ return True
 
	def itemChange(self, change, value):
		self.a.setPosAt(0, self.scenePos())
		if change == QtGui.QGraphicsItem.ItemPositionHasChanged and self.nParent is not None:
			for edge in self.nParent.edges:
				edge.view.adjust()
			self.itemMoved()
			if self.menu:
				self.menu.setGeometry(self.pos().x(), self.pos().y(), 100, 75)
		return QtGui.QGraphicsItem.itemChange(self,change, value)
 
	def mousePressEvent(self, event):
		print "visualNode.mousePressEvent"
		oldpos=self.scenePos()
 
		#~ self.update()
		if event.button() == 2:
			self.showNodeMenu(event)
		QtGui.QGraphicsItem.mousePressEvent(self, event)
 
 
	#~ def randomAnimation(self):
		#~ self.a.setPosAt(0, self.scenePos())
		#~ self.a.setPosAt(0.25, QtCore.QPointF(random.randint(0,500),random.randint(0,300)))
		#~ self.a.setPosAt(0.50, QtCore.QPointF(random.randint(0,500),random.randint(0,300)))
		#~ self.a.setPosAt(0.75, QtCore.QPointF(random.randint(0,500),random.randint(0,300)))
		#~ self.a.setPosAt(1, oldpos)
		#~ self.tl.start()
 
	def mouseReleaseEvent(self, event):
		#~ self.update()
		QtGui.QGraphicsItem.mouseReleaseEvent(self, event)
 
 
	def itemMoved(self):
		##~ print str(self)+" "+str(self.animated)
		if self.animated == True:
			if self.nParent.parent:
				for node in self.nParent.parent.nodes:
					node.view.pruebaAnim()
 
	def stopAnimation(self):
		self.tl.setPaused(True)
		self.animated=False
 
	def startAnimation(self):
		self.tl.setPaused(False)
		self.animated=True
		self.itemMoved()
 
 
	def pruebaAnim(self):
		self.a.setPosAt(0, self.scenePos())
		if not self.scene() or self.scene().mouseGrabberItem() == self or self.tl.state() != QtCore.QTimeLine.NotRunning:
			return
		##Sum up all forces pushing this item away
		xvel = 0
		yvel = 0
		for node in self.nParent.parent.nodes:
			line = QtCore.QLineF(self.mapFromItem(node.view, 0, 0), QtCore.QPointF(0, 0))
			dx = line.dx()
			dy = line.dy()
			l = 2.0 * (dx * dx + dy * dy)
			if l > 0 :
				xvel += (dx * self.repulsion) / l
				yvel += (dy * self.repulsion) / l
		##Now subtract all forces pulling items together
		weight = (len(self.nParent.edges) + 1) * self.weight
		for edge in self.nParent.edges:
			if edge.fromNode == self.nParent:
				pos = self.mapFromItem(edge.toNode.view, 0, 0)
			else:
				pos = self.mapFromItem(edge.fromNode.view, 0, 0)
			xvel += pos.x() / weight
			yvel += pos.y() / weight
		if math.fabs(xvel) < 0.3 and math.fabs(yvel) < 0.3:
			xvel = yvel = 0
 
		sceneRect = self.scene().sceneRect();
		self.newPos = self.pos() + QtCore.QPointF(xvel, yvel)
		#~ self.newPos.setX(min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10))
		#~ self.newPos.setY(min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))
		#~ self.newPos.setX(self.pos().x()+random.randint(-10,10))
		#~ self.newPos.setY(self.pos().y()+random.randint(-10,10))
 
		if self.scene():
			rect = self.scene().views()[-1].sceneRect()
			nodeWidth = max(self.boundingRect().width(),self.text.boundingRect().width())
			nodeHeight = self.boundingRect().height()+self.text.boundingRect().height()
			self.newPos.setX(min(rect.right()-(nodeWidth/2), max(self.newPos.x(), rect.left()+(nodeWidth/2))))
			self.newPos.setY(min(rect.bottom()-(nodeHeight/2), max(self.newPos.y(), rect.top()+(nodeHeight/2)+5)))
 
		self.a.setPosAt(1, self.newPos)
		self.tl.start()
 
 
	#def animate(self):
		#print "Main.animate()"
 
		#def animate_to(t,item,x,y,angle):
 
			#animation=QtGui.QGraphicsItemAnimation()
 
			#timeline=QtCore.QTimeLine(1000)
			#timeline.setFrameRange(0,100)
			#animation.setItem(item)
			#animation.setPosAt(t,QtCore.QPointF(x,y))
			#animation.setRotationAt(t,angle)
			#animation.setTimeLine(timeline)
			#return animation
		## Random animations
		#animation=animate_to(1,self,random.randint(0,500),random.randint(0,300),random.randint(0,0))
		#animation.setPosAt(0,self.pos())
		#print animation.posList()
		#animation.timeLine().start()
		#~ self.animator.start(1000)
 
 
	#~ def mouseReleaseEvent(self, event):
		#~ self.update()
		#~ QtGui.QGraphicsItem.mouseReleaseEvent(self, event)
	#~ def animate_to(self,t,item,x,y):
			#~ animation=QtGui.QGraphicsItemAnimation()
			#~ timeline=QtCore.QTimeLine(1000)
			#~ timeline.setFrameRange(0,100)
			#~ animation.setPosAt(t,QtCore.QPointF(x,y))
			#~ animation.setItem(item)
			#~ animation.setTimeLine(timeline)
			#~ return animation
 
 
	#def calculateForces(self):
		#print "visualNode.calculateForces() en "+str(self.nParent.data.alias)
		#self.animator.start(1000)
		#if not self.scene() or self.scene().mouseGrabberItem() == self:
			##~ self.animator.stop()
			#return
		#print "oldpos "+str(self.pos())
		##~ if self.newPos == self.pos():
			##~ return
		##Sum up all forces pushing this item away
		#xvel = 0
		#yvel = 0
		#for node in self.nParent.parent.nodes:
			#line = QtCore.QLineF(self.mapFromItem(node.view, 0, 0), QtCore.QPointF(0, 0))
			#dx = line.dx()
			#dy = line.dy()
			#l = 2.0 * (dx * dx + dy * dy)
			##~ print "Distancia "+str(l)
			#if l > 0 :
				#xvel += (dx * self.repulsion) / l
				#yvel += (dy * self.repulsion) / l
 
		##~ print "velx "+str(xvel)+" yvel "+str(yvel)
		##Now subtract all forces pulling items together
		#weight = (len(self.nParent.edges) + 1) * self.weight
		#for edge in self.nParent.edges:
			#if edge.fromNode == self.nParent:
				#pos = self.mapFromItem(edge.toNode.view, 0, 0)
			#else:
				#pos = self.mapFromItem(edge.fromNode.view, 0, 0)
			#xvel += pos.x() / weight
			#yvel += pos.y() / weight
		#if math.fabs(xvel) < 0.1 and math.fabs(yvel) < 0.1:
			#xvel = yvel = 0
		##~ print "velx "+str(xvel)+" yvel "+str(yvel)
 
 
		#sceneRect = self.scene().sceneRect();
		#self.newPos = self.pos() + QtCore.QPointF(xvel, yvel)
		#self.newPos.setX(min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10))
		#self.newPos.setY(min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))
		#self.newPos.setX(self.pos().x()+random.randint(-10,10))
		#self.newPos.setY(self.pos().y()+random.randint(-10,10))
 
		#animation = self.animate_to(1,self, self.newPos.x(),self.newPos.y())
 
		#print "\t "+str(animation.posList())
		#print str(animation)+"-----------"
		#animation.timeLine().start()
		##~ self.setPos(self.newPos)
 
 
	def showNodeMenu(self, event):
		self.scene().clearSelection()
		self.setSelected(True)
		self.contextMenu.exec_(event.screenPos())
 
	#~ def __repr__(self):
		#~ string = ''
		#~ string = string + 'vel_x:         \t' + str(self.vel_x) + '\n'
		#~ string = string + 'vel_x:         \t' + str(self.vel_y) + '\n'
		#~ return string
 
def getVisualNodesFromData(dataNodes):
	nodeList=[]
	for dNode in dataNodes:
		newNode = managerNode.managerNode()
		newNode.visual = visualNode(newNode)
		newNode.id = dNode.alias
		nodeList.append(newNode)
	return nodeList
 
 
if __name__ == "__main__":
	app = QtGui.QApplication(sys.argv)
	a = visualNode(None)
	b = visualNode(None)
	c = visualNode(None)
	d = visualNode(None)
	e = visualNode(None)
	f = visualNode(None)
	g = visualNode(None)
	h = visualNode(None)
 
	grview = QtGui.QGraphicsView()
	grview.setRenderHints(QtGui.QPainter.Antialiasing)
	scene = QtGui.QGraphicsScene()
	#~ for node in datanodeList.nodes:
		#~ for edge in node.edges:
			#~ scene.addItem(edge.view)
		#~ scene.addItem(node.view)
		#~ node.view.timeLine.start()
	scene.addItem(a)
	scene.addItem(b)
	scene.addItem(c)
	scene.addItem(d)
	scene.addItem(e)
	scene.addItem(f)
	scene.addItem(g)
	scene.addItem(h)
	grview.setScene(scene)
 
	grview.show()
 
	sys.exit(app.exec_())