Beispiel #1
0
    def __init__(self, *args, **kwargs):
        RanaModule.__init__(self, *args, **kwargs)
        self.tt = 0
        self.connected = False
        self.set('speed', None)
        self.set('metersPerSecSpeed', None)
        self.set('bearing', None)
        self.set('elevation', None)
        self.status = "Unknown"
        self._enabled = False
        self.provider = None
        self.startSignal = Signal()
        self.stopSignal = Signal()
        self.positionUpdate = Signal()

        # check if the device handles location by itself
        if not self.modrana.dmod.handles_location:
            method = self.modrana.dmod.location_type
            if method == "qt_mobility":
                self.log.info("using Qt Mobility")
                from . import qt_mobility

                self.provider = qt_mobility.QtMobility(self)
            elif method == "gpsd":  # GPSD
                self.log.info("using GPSD")
                from . import gps_daemon

                self.provider = gps_daemon.GPSD(self)

        # watch if debugging needs to be enabled
        self.modrana.watch("gpsDebugEnabled", self._debugCB, runNow=True)
Beispiel #2
0
 def __init__(self):
     self._objs = {}
     self._objs_lock = threading.RLock()
     self._global_index = 0
     self._errors = {}
     self._main_thread = threading.currentThread()
     # signals
     self.thread_status_changed = Signal()
     self.thread_progress_changed = Signal()
     self.thread_removed = Signal()
 def __init__(self, rendererPreset):
     #
     QtModule.QDialog.__init__(self)
     #
     # Define signals for PyQt5
     #
     if usePySide or usePyQt5:
         #
         self.presetChanged = Signal()
         self.savePreset = Signal()
         #
     self.rendererPreset = rendererPreset
     self.labelsReady = False
     self.buildGui()
	def __init__ ( self, rendererPreset ) :
		#
		QtModule.QDialog.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.presetChanged = Signal ()
			self.savePreset = Signal ()
			#
		self.rendererPreset = rendererPreset
		self.labelsReady = False
		self.buildGui ()
    def __init__(self, parent, editNode=None):
        #
        QtModule.QWidget.__init__(self, parent)
        #
        # Define signals for PyQt5
        #
        if usePySide or usePyQt5:
            #
            self.changeNodeLabel = Signal()
            #
        self.editNode = editNode

        #self.debugPrint()
        self.buildGui()
        self.setNode(editNode)
Beispiel #6
0
	def __init__ ( self, parent ) :
		#
		QtModule.QGraphicsView.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.mouseDoubleClickSignal = Signal ()
			#
		self.state = 'idle' 
		self.panStartPos = None
		self.pixmap = None
		# set scene
		scene = QtModule.QGraphicsScene ( self )
		scene.setSceneRect ( 0, 0, 256, 256 )
		#scene.setItemIndexMethod ( QtGui.QGraphicsScene.NoIndex )
		self.setScene ( scene )
		# qt graphics stuff
		#self.setCacheMode ( QtGui.QGraphicsView.CacheBackground )
		self.setRenderHint ( QtGui.QPainter.Antialiasing )
		self.setTransformationAnchor ( QtModule.QGraphicsView.AnchorUnderMouse )
		self.setResizeAnchor ( QtModule.QGraphicsView.AnchorViewCenter )
		self.setDragMode ( QtModule.QGraphicsView.RubberBandDrag )
		self.setMouseTracking ( False )
		self.BgBrush = QtGui.QBrush ( QtGui.QColor ( 128, 128, 128 ) )  
	def __init__ ( self, parent ) :
		#
		QtModule.QWidget.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.selectionChangedSignal = Signal ()
			self.addItem = Signal ()
			self.removeItem = Signal ()
			self.renameItem = Signal ()
		#
		self.saved_text = ''
		self.approvedNewName = ''
		self.buildGui ()
	def __init__ ( self, parent ) :
		#
		QtModule.QWidget.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.changeParamName = Signal ()
			self.changeParamLabel = Signal ()
			self.changeParamIsShader = Signal ()
			self.changeParamType = Signal ()
			self.changeParamDetail = Signal ()
			self.changeParamProvider = Signal ()
			self.changeParamSubtype = Signal ()
			self.changeParamRange = Signal ()
			
			self.changeParamValue = Signal ()
			self.changeParamDefValue = Signal ()
		#
		self.param = None
		self.param_default = None
		self.paramWidgets = {	 'string'       : StringWidget
													,'image'        : StringWidget
													,'rib'          : StringWidget
													,'surface'      : StringWidget
													,'displacement' : StringWidget
													,'light'        : StringWidget
													,'volume'       : StringWidget
													,'float'        : FloatWidget
													,'int'          : IntWidget
													,'color'        : ColorWidget
													,'normal'       : NormalWidget
													,'transform'    : PointWidget
													,'point'        : PointWidget
													,'vector'       : VectorWidget
													,'matrix'       : MatrixWidget
													,'text'         : TextWidget
													,'control'      : ControlWidget
													,'shader'       : StringWidget
													,'geom'         : StringWidget
												}

		self.buildGui()
Beispiel #9
0
    def buildGui(self):
        #
        # Define signals for PyQt5
        #
        if usePySide or usePyQt5:
            #
            self.clicked = Signal()

        self.ui = Ui_ColorWidget_field()
        self.ui.setupUi(self)
Beispiel #10
0
    def __init__(self, *args, **kwargs):
        RanaModule.__init__(self, *args, **kwargs)
        self.notificationText = ""
        self.timeout = 5000
        self.position = 'middle'
        self.expirationTimestamp = time.time()
        self.draw = False
        self.redrawn = None
        self.wipOverlayEnabled = Signal()
        self._showWorkInProgressOverlay = False
        self.workStartTimestamp = None
        self._wipOverlayText = ""
        # this indicates if the notification about
        # background processing should be shown
        self._tasks = {}
        self._tasksLock = threading.RLock()

        ## for WiP overlay testing
        #self._tasks = {
        #  "foo" : ("foo", None),
        #  "bar" : ("bar", None),
        #  "baz" : ("baz", None)
        #}

        # key is an unique task name (unique for each instance of a task)
        # and value is a (status, progress) tuple
        self.tasksChanged = Signal()

        # connect thread manager signals to task status changes
        threadMgr.threadStatusChanged.connect(self.setTaskStatus)
        threadMgr.threadProgressChanged.connect(self.setTaskProgress)
        threadMgr.threadRemoved.connect(self.removeTask)

        # also with GTK GUI, assure screen is redrawn properly
        # when WiP overlay changes
        if gs.GUIString == "GTK":
            self.wipOverlayEnabled.connect(self._doRefresh)
            self.tasksChanged.connect(self._doRefresh)
            # we handle notification only with the GTK GUI and when the device module does not
            # support showing them
            if not self.modrana.dmod.hasNotificationSupport():
                self.modrana.notificationTriggered.connect(self._startCustomNotificationCB)
Beispiel #11
0
	def __init__ ( self ) :
		#
		QtModule.QWidget.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.nodeParamChangedSignal = Signal ()
			self.nodeLabelChangedSignal = Signal ()
			#
		self.gfxNode = None
		
		self.inputParamListTab = None
		self.outputParamListTab = None
		
		self.showConnected = False
		self.buildGui ()
		self.updateGui ()
		self.connectSignals ()
Beispiel #12
0
	def __init__ ( self, parent ) :
		#
		QtModule.QWidget.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.setActiveNodeList = Signal ()
			self.addNode = Signal ()
			#
		self.nodesLib = ''
		self.nodesDir = ''
		# This is always the same
		self.ui = Ui_nodeList () 
		self.ui.setupUi ( self )
		self.ui.treeView.setDragEnabled ( True )
		#self.ui.treeView.setRootIsDecorated( True )
		self.connectSignals ()
		self.updateGui ()
Beispiel #13
0
 def buildGui(self):
     #
     # Define signals for PyQt5
     #
     if usePySide or usePyQt5:
         #
         self.clicked = Signal()
         #
     if self.param.isArray():
         self.ui = Ui_ColorWidget_array()
     else:
         self.ui = Ui_ColorWidget_field()
     self.ui.setupUi(self)
Beispiel #14
0
 def __init__(self, parent):
     #
     QtModule.QWidget.__init__(self, parent)
     #
     # Define signals for PyQt5
     #
     if usePySide or usePyQt5:
         #
         self.selectionChangedSignal = Signal()
         self.addItem = Signal()
         self.removeItem = Signal()
         self.renameItem = Signal()
     #
     self.saved_text = ''
     self.approvedNewName = ''
     self.buildGui()
Beispiel #15
0
 def __init__(self, parent, value=None, idx=None):
     #
     QtModule.QWidget.__init__(self, parent)
     #
     # Define signals for PyQt5
     #
     if usePySide or usePyQt5:
         #
         self.clicked = Signal()
         #
     #print ( '>>> ColorField.init' )
     self.value = value
     self.idx = idx
     self.buildGui()
    def __init__(self, parent, editNode=None):
        #
        QtModule.QWidget.__init__(self, parent)
        #
        # Define signals for PyQt5
        #
        if usePySide or usePyQt5:
            #
            self.changeNodeLabel = Signal()
            #
        self.editNode = editNode

        # self.debugPrint()
        self.buildGui()
        self.setNode(editNode)
def main():
    parser=ArgumentParser()
    parser.add_argument("--log", "-l", required=True)
    parser.add_argument("--output", "-o", required=True)
    args=parser.parse_args()

    signal=Signal.read_3d_csv(args.log)
    print("Length: %d" % len(signal.time))
    time_diffs=np.diff(signal.time)
    print("dt: %f..%f" % (min(time_diffs), max(time_diffs)))


    cutter=LogCutter(signal)
    working_figure=plt.gcf()
    display_signal(signal, False)
    #print(working_figure.number)
    cutter.connect(working_figure)

    plt.show()

    subsignal=Signal.get_subsignal(signal, cutter.left_bound,
                                   cutter.right_bound)

    Signal.save_csv(subsignal, args.output)
Beispiel #18
0
	def __init__ ( self, param, gfxNode, ignoreSubtype = False ) :
		#
		QtModule.QWidget.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.nodeParamRemoved = Signal ()
			#
		self.param = param
		self.gfxNode = gfxNode
		self.ignoreSubtype = ignoreSubtype # if widget is used in NodeEditor, then ignoreSubtype = True

		self.buildGeneralGui ()
		self.buildGui ()
		self.ui.updateGui ( self.param.value )
Beispiel #19
0
	def __init__ ( self, xml_param = None, isRibParam = False ) :
		#
		super ( NodeParam, self ).__init__ ()
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.paramChangedSignal = Signal ()
			
		self.id = None
		self.name = None
		self.label = None
		self.type = None
		self.help = None  # short description

		self.default = None
		self.value = None
		self.shaderParam = False

		self.isRibParam = isRibParam
		self.display = True
		self.enabled = True
		self.removable = False

		# extra parameter description
		self.detail = '' # variable, uniform
		self.provider = '' # primitive, connection, constant, variable, expression

		# ui decorative parameters
		self.subtype = ''
		self.range = ''

		self.space = None # actual for color, point, vector, normal, matrix
		self.spaceDef = None # default value space

		self.arraySize = None # otherwise, it should be a list of values ( or empty list )

		self.defaultArray = []
		self.valueArray = []
		self.spaceArray = []			# array elements spaces
		self.spaceDefArray = []		# default array elements spaces

		if xml_param != None : self.parseFromXML ( xml_param )
Beispiel #20
0
	def __init__ ( self, view ) :
		#
		QtModule.QGraphicsScene.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.startNodeConnector = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.traceNodeConnector = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.endNodeConnector = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.startNodeLink = Signal () #( QtModule.QGraphicsObject ) # QtModule.QGraphicsItem
			self.traceNodeLink = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.endNodeLink = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.onGfxNodeRemoved = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject )
			self.onGfxLinkRemoved = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject )
			self.nodeUpdated = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsItem )
			self.gfxNodeParamChanged = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsItem, QtCore.QObject )
			#
		self.view = view
		self.connectSignals ()
    def onclick(self, event):
        click_x=event.xdata
        if event.button==1 and click_x<self.right_bound:
            self.left_bound=click_x
        elif event.button==3 and click_x>self.left_bound:
            self.right_bound=click_x
        for subplot_ax in self.figure.axes:
            if len(subplot_ax.lines) > 1:
                subplot_ax.lines[-1].remove()
                subplot_ax.lines[-1].remove()
            subplot_ax.axvline(x=self.left_bound, visible=True, color="yellow")
            subplot_ax.axvline(x=self.right_bound, visible=True, color="red")
        self.figure.canvas.draw()
        
        subsignal=Signal.get_subsignal(self.signal, self.left_bound,
                                       self.right_bound)
        if self.callback:
            plt.close(self.callback)
        self.callback=plt.figure()
        plt.figure(self.callback.number)
        display_signal(subsignal, True)

        plt.figure(self.figure.number)
Beispiel #22
0
class NodeParam ( QtCore.QObject ) :
	#
	isInput = True
	isRibParam = False
	id = 0
	#
	# __init__
	#
	def __init__ ( self, xml_param = None, isRibParam = False ) :
		#
		super ( NodeParam, self ).__init__ ()
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.paramChangedSignal = Signal ()
			
		self.id = None
		self.name = None
		self.label = None
		self.type = None
		self.help = None  # short description

		self.default = None
		self.value = None
		self.shaderParam = False

		self.isRibParam = isRibParam
		self.display = True
		self.enabled = True
		self.removable = False

		# extra parameter description
		self.detail = '' # variable, uniform
		self.provider = '' # primitive, connection, constant, variable, expression

		# ui decorative parameters
		self.subtype = ''
		self.range = ''

		self.space = None # actual for color, point, vector, normal, matrix
		self.spaceDef = None # default value space

		self.arraySize = None # otherwise, it should be a list of values ( or empty list )

		self.defaultArray = []
		self.valueArray = []
		self.spaceArray = []			# array elements spaces
		self.spaceDefArray = []		# default array elements spaces

		if xml_param != None : self.parseFromXML ( xml_param )
	#
	# isArray
	#
	def isArray ( self ) : return ( self.arraySize is not None )
	#
	# setup
	#
	def setup ( self, name, label = '', detail = None, provider = None ) :
		#
		self.name = name
		if label == '' or label is None : 
			self.label = name
		else: 
			self.label = label
		self.detail = detail
		self.provider = provider
	#
	# copy
	#
	def copy ( self ) : assert 0, 'copy needs to be implemented!'
	#
	# copySetup
	#
	def copySetup ( self, newParam ) :
		#
		#if DEBUG_MODE : print '>> NodeParam( %s ).copySetup' % self.label
		newParam.id = self.id
		newParam.name = self.name
		newParam.label = self.label
		newParam.type = self.type
		newParam.help = self.help
		newParam.isInput = self.isInput
		newParam.shaderParam = self.shaderParam
		newParam.isRibParam = self.isRibParam
		newParam.display = self.display
		newParam.enabled = self.enabled
		newParam.removable = self.removable
		newParam.detail = self.detail
		newParam.provider = self.provider
		newParam.subtype = self.subtype
		newParam.range = self.range
		newParam.space = self.space
		newParam.spaceDef = self.spaceDef

		newParam.default = copy.deepcopy ( self.default )
		newParam.value = copy.deepcopy ( self.value )
		newParam.arraySize = self.arraySize
		newParam.defaultArray  = copy.deepcopy ( self.defaultArray )
		newParam.valueArray 	 = copy.deepcopy ( self.valueArray )   
		newParam.spaceArray 	 = copy.deepcopy ( self.spaceArray ) 
		newParam.spaceDefArray = copy.deepcopy ( self.spaceDefArray ) 
	#
	# typeToStr
	#
	def typeToStr ( self ) :
		#
		typeStr = self.detail + ' ' + self.type
		if self.isRibParam :
			if self.isArray () :
				arraySize = ''
				if self.arraySize > 0 :
					arraySize = str ( self.arraySize )
				typeStr += '[%s]' % arraySize
		return typeStr.lstrip ()
	#
	# encodedTypeStr
	#
	def encodedTypeStr ( self ) : assert 0, 'encodedStr needs to be implemented!'
	#
	# setValueFromStr
	#
	def setValueFromStr ( self, strValue ) : self.value = self.valueFromStr ( strValue )
	#
	# setDefaultFromStr
	#
	def setDefaultFromStr ( self, strValue ) : self.default = self.valueFromStr ( strValue )

	#
	# Virtual functions
	#

	#
	# valueFromStr
	#
	def valueFromStr ( self, strValue ) : return strValue
	#
	# getValueToStr
	#
	def getValueToStr ( self ) :
		#
		if self.value != None :
			return self.valueToStr ( self.value )
		else :
			return None
	#
	# getDefaultToStr
	#
	def getDefaultToStr ( self ) :
		#
		if self.default != None :
			return self.valueToStr ( self.default )
		else :
			return None
	#
	# virtual function
	#
	def valueToStr ( self, value ) : return str ( value )
	#
	# paramChanged
	#
	def paramChanged ( self, emitSignal = True ) :
		#
		if DEBUG_MODE : print ( '>> NodeParam.paramChanged (name = %s) emit = ' % self.name ), emitSignal
		if emitSignal :
			if  usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self )
			else :
				self.paramChangedSignal.emit ( self )
	#
	# setupUI
	#
	def setupUI ( self, subtype, range ) :
		#
		self.subtype = subtype
		self.range = range
	#
	# setValue
	#
	def setValue ( self, value, emitSignal = True ) :
		#
		if self.value != value :
			self.value = value
			self.paramChanged ( emitSignal )
	#
	# removeItemFromRange
	#
	def removeItemFromRange ( self, item_label ) :
		#
		newRangeList = []
		if self.range != '' : # and self.subtype == 'selector':
			tmp_list = str ( self.range ).split ( ':' )
			for s in tmp_list :
				pair = s.split ( '=' )
				if len ( pair ) > 1 :
					label = pair [0]
					value = pair [1]
				else :
					label = s
					value = s
				#
				if label != item_label :
					newRangeList.append ( s )
			self.range = ( ':' ).join ( newRangeList )  
	#
	# renameItemInRange
	#
	def renameItemInRange ( self, item_label, newLabel ) :
		#
		newRangeList = []
		if self.range != '' : # and self.subtype == 'selector':
			tmp_list = str ( self.range ).split ( ':' )
			for s in tmp_list :
				pair = s.split ( '=' )
				if len ( pair ) > 1 :
					label = pair [0]
					value = pair [1]
				else :
					label = s
					value = s
				#
				if label == item_label :
					s = s.replace ( label, newLabel, 1 ) # replace only label
				newRangeList.append ( s )
			self.range = ( ':' ).join ( newRangeList )    
	#
	# parseFromXML
	#
	def parseFromXML ( self, xml_param ) :
		#
		self.name        = str ( xml_param.attributes ().namedItem ( 'name' ).nodeValue () )
		self.label       = str ( xml_param.attributes ().namedItem ( 'label' ).nodeValue () )
		if self.label == '' : self.label = self.name
		self.type        = str ( xml_param.attributes ().namedItem ( 'type' ).nodeValue () )
		self.shaderParam = xml_param.attributes ().namedItem ( 'shaderParam' ).nodeValue () == '1'

		self.detail      = str ( xml_param.attributes ().namedItem ( 'detail' ).nodeValue () )
		self.provider    = str ( xml_param.attributes ().namedItem ( 'provider' ).nodeValue () )
		self.subtype     = str ( xml_param.attributes ().namedItem ( 'subtype' ).nodeValue () )
		self.range       = str ( xml_param.attributes ().namedItem ( 'range' ).nodeValue () )

		self.display = True
		if not xml_param.attributes ().namedItem ( 'display' ).isNull () :
			self.display = xml_param.attributes ().namedItem ( 'display' ).nodeValue () == '1'

		self.enabled = True
		if not xml_param.attributes ().namedItem ( 'enabled' ).isNull () :
			self.enabled = xml_param.attributes ().namedItem ( 'enabled' ).nodeValue () == '1'
			
		self.removable = False
		if not xml_param.attributes ().namedItem ( 'removable' ).isNull () :
			self.removable = xml_param.attributes ().namedItem ( 'removable' ).nodeValue () == '1'

		if not xml_param.attributes ().namedItem ( 'space' ).isNull () :
			space = str ( xml_param.attributes ().namedItem ( 'space' ).nodeValue () )
			if space != '' :
				self.space = space
				self.spaceDef = space

		if not xml_param.attributes ().namedItem ( 'spaceDef' ).isNull () :
			spaceDef = str ( xml_param.attributes ().namedItem ( 'spaceDef' ).nodeValue () )
			if spaceDef != '' :
				self.spaceDef = space

		if not xml_param.attributes ().namedItem ( 'arraySize' ).isNull () :
			self.arraySize = int ( xml_param.attributes ().namedItem ( 'arraySize' ).nodeValue () )
		self.setDefaultFromStr ( xml_param.attributes ().namedItem ( 'default' ).nodeValue () )
		# after reading array values, space for each element is stored to self.spaceArray,
		# so we need to copy it to self.spaceDefArray for default value
		self.spaceDefArray 	 = copy.deepcopy ( self.spaceArray )

		if not xml_param.attributes ().namedItem ( 'value' ).isNull () :
			self.setValueFromStr ( xml_param.attributes ().namedItem ( 'value' ).nodeValue () )
		else :
			self.value = copy.deepcopy ( self.default ) 


		help_tag = xml_param.namedItem ( 'help' )

		if not help_tag.isNull () :
			self.help = str ( help_tag.toElement ().text () )
	#
	# parseToXML
	#
	def parseToXML ( self, dom ) :
		#
		xmlnode = dom.createElement( 'property' )

		if self.name != None   : xmlnode.setAttribute ( 'name', self.name )
		if self.label != None  : xmlnode.setAttribute ( 'label', self.label )
		if self.type != None   : xmlnode.setAttribute ( 'type', self.type )
		if self.shaderParam    : xmlnode.setAttribute ( 'shaderParam', True )
		if not self.display    : xmlnode.setAttribute ( 'display', False )
		if not self.enabled    : xmlnode.setAttribute ( 'enabled', False )
		if self.removable      : xmlnode.setAttribute ( 'removable', True )
		if self.detail != ''   : xmlnode.setAttribute ( 'detail', self.detail )
		if self.provider != '' : xmlnode.setAttribute ( 'provider', self.provider )
		# ui decorative parameters
		if self.subtype != ''  : xmlnode.setAttribute ( 'subtype', self.subtype )
		if self.range != ''    : xmlnode.setAttribute ( 'range', self.range )

		if self.space != None  :
			if self.space != ''  : xmlnode.setAttribute ( 'space', self.space )

		# write default value space only if it differs from value space
		if self.spaceDef != None  :
			if self.spaceDef != '' and  self.spaceDef != self.space : 
				xmlnode.setAttribute ( 'spaceDef', self.spaceDef )

		if self.default != None :
			value = self.getDefaultToStr ()
			if not self.type in VALID_RIB_NODE_TYPES : 
				value = value.strip ( '\"' )
			xmlnode.setAttribute ( 'default', value )

		if self.value != None :
			value = self.getValueToStr ()
			if not self.type in VALID_RIB_NODE_TYPES : 
				value = value.strip ( '\"' )
			xmlnode.setAttribute ( 'value', value )

		if self.arraySize != None :
			xmlnode.setAttribute ( 'arraySize', self.arraySize )
		if self.help != None :
			# append node help (short description)
			help_tag = dom.createElement ( 'help' )
			help_text = dom.createTextNode ( self.help )
			help_tag.appendChild ( help_text )
			xmlnode.appendChild ( help_tag )

		return xmlnode
class meRendererSetup ( QtModule.QDialog ) :
	#
	# __init__
	#
	def __init__ ( self, rendererPreset ) :
		#
		QtModule.QDialog.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.presetChanged = Signal ()
			self.savePreset = Signal ()
			#
		self.rendererPreset = rendererPreset
		self.labelsReady = False
		self.buildGui ()
	#
	# buildGui
	#
	def buildGui ( self ) :
		# build the gui created with QtDesigner
		import sys
		self.ui = Ui_meRendererSetup ()
		self.ui.setupUi ( self )
		
		font = QtGui.QFont ()
		if ( sys.platform == 'win32' ) :
			# Runing on windows, override font sizes from Designer to default 
			font.setPointSize ( 8 )
		else :
			font.setPointSize ( 10 )
		self.ui.labelPreset.setFont ( font )
		self.ui.listPreset.setFont ( font )
		self.ui.newButton.setFont ( font )
		self.ui.deleteButton.setFont ( font )
		self.ui.cancelButton.setFont ( font )
		self.ui.okButton.setFont ( font )
		self.ui.saveButton.setFont ( font )
		self.ui.tabs.setFont ( font )
		self.ui.labelName.setFont ( font )
		self.ui.labelCmd.setFont ( font )
		self.ui.labelFlags.setFont ( font )
		self.ui.labelCompiler.setFont ( font )
		self.ui.labelShaderInfo.setFont ( font )
		self.ui.labelDefines.setFont ( font )
		self.ui.labelShaderExt.setFont ( font )
		self.ui.labelShaderExt.setFont ( font )
		self.ui.labelTexMake.setFont ( font )
		self.ui.labelTexInfo.setFont ( font )
		self.ui.labelTexViewer.setFont ( font )
		self.ui.labelTexExt.setFont ( font )

		self.labelsReady = False

		for label in self.rendererPreset.getPresetNames () :
			self.ui.listPreset.addItem ( label )
		
		self.labelsReady = True
		
		presetName = self.rendererPreset.getCurrentPresetName ()
		idx = self.ui.listPreset.findText ( presetName ) 
		print ">> buildGui:: set current renderer to: %s (%d)" % ( presetName, idx )
		#self.ui.listPreset.setCurrentIndex ( -1 )
		self.ui.listPreset.setCurrentIndex ( idx ) 
	#
	# getDataFromGui
	# 
	def getDataFromGui ( self ) :
		# ckeck if current_renderer still exists after deleting preset
		#print ">> getDataFromGui:: current renderer to: %s" % self.rendererPreset.getCurrentPresetName() 
			
		self.rendererPreset.currentPreset.RendererName = str ( self.ui.lineCmd.text () )
		self.rendererPreset.currentPreset.RendererFlags = str ( self.ui.lineFlags.text () )
		self.rendererPreset.currentPreset.ShaderCompiler = str ( self.ui.lineCompiler.text () )
		self.rendererPreset.currentPreset.ShaderInfo = str ( self.ui.lineShaderInfo.text () )
		self.rendererPreset.currentPreset.ShaderDefines = str ( self.ui.lineDefines.text () )
		self.rendererPreset.currentPreset.ShaderExt = str ( self.ui.lineShaderExt.text () )
		self.rendererPreset.currentPreset.TextureMake = str ( self.ui.lineTexMake.text () )
		self.rendererPreset.currentPreset.TextureInfo = str ( self.ui.lineTexInfo.text () )
		self.rendererPreset.currentPreset.TextureViewer = str ( self.ui.lineTexViewer.text () )
		self.rendererPreset.currentPreset.TextureExt = str ( self.ui.lineTexExt.text () )
	#
	# onIndexChanged
	#    
	def onIndexChanged ( self, name ) : 
		if DEBUG_MODE : print ">> onIndexChanged:: nam = %s self.labelsReady == %d" % ( name, self.labelsReady )
		#if DEBUG_MODE : print self.ui.listPreset.currentText ()
		name = self.ui.listPreset.currentText ()
		if ( self.labelsReady and name != '' ) :
			# change current renderer
			self.rendererPreset.setCurrentPresetByName ( str ( name ) )
		self.updateGui ()
	#
	# updateGui
	#  
	def updateGui ( self ) :
		# redraw gui elements
		#print ">> updateGui:: current renderer: %s" % self.rendererPreset.getCurrentPresetName() 
		if len ( self.rendererPreset.presetsList ) > 0 :
			if self.rendererPreset.currentPreset is not None :
				self.ui.lineName.setText ( self.rendererPreset.getCurrentPresetName () )
				self.ui.lineCmd.setText ( self.rendererPreset.currentPreset.RendererName )
				self.ui.lineFlags.setText ( self.rendererPreset.currentPreset.RendererFlags )
				self.ui.lineCompiler.setText ( self.rendererPreset.currentPreset.ShaderCompiler )
				self.ui.lineShaderInfo.setText ( self.rendererPreset.currentPreset.ShaderInfo )
				self.ui.lineDefines.setText ( self.rendererPreset.currentPreset.ShaderDefines )
				self.ui.lineShaderExt.setText ( self.rendererPreset.currentPreset.ShaderExt )
				self.ui.lineTexMake.setText ( self.rendererPreset.currentPreset.TextureMake )
				self.ui.lineTexInfo.setText ( self.rendererPreset.currentPreset.TextureInfo )
				self.ui.lineTexViewer.setText ( self.rendererPreset.currentPreset.TextureViewer )
				self.ui.lineTexExt.setText ( self.rendererPreset.currentPreset.TextureExt )
				self.ui.deleteButton.setEnabled ( True )
				self.ui.tab1.setEnabled ( True )
				self.ui.tab2.setEnabled ( True)
				self.ui.tab3.setEnabled ( True )
		else :
			self.ui.deleteButton.setEnabled ( False )
			self.ui.tab1.setEnabled ( False )
			self.ui.tab2.setEnabled ( False )
			self.ui.tab3.setEnabled ( False )
			self.ui.lineName.clear ()
			self.ui.lineCmd.clear ()
			self.ui.lineFlags.clear ()
			self.ui.lineCompiler.clear ()
			self.ui.lineShaderInfo.clear ()
			self.ui.lineDefines.clear ()
			self.ui.lineShaderExt.clear ()
			self.ui.lineTexMake.clear ()
			self.ui.lineTexInfo.clear ()
			self.ui.lineTexViewer.clear ()
			self.ui.lineTexExt.clear ()
	#
	# onNewPreset
	#
	def onNewPreset ( self ) :
		# create new empty preset
		title = 'Untitled' 
		newLabel = title
		#self.labelsReady = False
		i = 0
		while True :
			if newLabel in self.rendererPreset.getPresetNames () :
				newLabel = title + str ( i )
				i += 1
				continue
			else :
				break;
		self.rendererPreset.addPreset ( newLabel )
		#self.labelsReady = True
		self.ui.listPreset.addItem ( newLabel ) 
		idx = self.ui.listPreset.findText ( newLabel )
		self.ui.listPreset.setCurrentIndex ( -1 )
		self.ui.listPreset.setCurrentIndex ( idx ) 
		#self.updateGui ()
	#  
	# onDeletePreset
	#  
	def onDeletePreset ( self ) :
		# delete existing preset
		if len ( self.rendererPreset.presetsList ) > 0 :
			msgBox = QtModule.QMessageBox ()
			ret = msgBox.warning ( self, 'Warning', "Do you really want to delete this preset?", 
			QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,  QtGui.QMessageBox.No )
			
			if ret ==  QtModule.QMessageBox.Yes :
				self.rendererPreset.deleteCurrentPreset ()
				i = self.ui.listPreset.currentIndex ()
				self.ui.listPreset.removeItem ( i )
				self.rendererPreset.setCurrentPresetByName ( str ( self.ui.listPreset.currentText () ) )
	#
	# onEditLabel
	#    
	def onEditLabel ( self ) :
		# edit label
		newLabel = str ( self.ui.lineName.text () )
		if ( self.rendererPreset.getCurrentPresetName () != newLabel ) :
			if newLabel not in self.rendererPreset.getPresetNames () :
				self.rendererPreset.renameCurrentPreset ( newLabel )
				# rename current preset ComboBox item to new label
				i = self.ui.listPreset.currentIndex ()
				self.ui.listPreset.setItemText ( i, newLabel )
			else :
				# this label already exists, so restore to previose
				self.ui.lineName.setText ( self.rendererPreset.getCurrentPresetName () )
	#
	# onSave
	#  
	def onSave ( self ) :
		# get data from Gui for current renderer before saving
		self.getDataFromGui ()
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'presetChanged' ) )
			self.emit ( QtCore.SIGNAL ( 'savePreset' ) )
		else :
			self.presetChanged.emit ()
			self.savePreset.emit ()
		#self.done ( 0 ) 
	#
	# onSelect
	#  
	def onSelect ( self ) :
		# get data from Gui for current renderer before saving
		self.getDataFromGui ()
		if  usePyQt4 :
			self.emit( QtCore.SIGNAL ( 'presetChanged' ) )
		else :
			self.presetChanged.emit ()
		self.done ( 0 ) 
class NodeNamesEditor ( QtModule.QWidget ) :
	#
	# __init__
	#
	def __init__ ( self, parent ) :
		#
		QtModule.QWidget.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.selectionChangedSignal = Signal ()
			self.addItem = Signal ()
			self.removeItem = Signal ()
			self.renameItem = Signal ()
		#
		self.saved_text = ''
		self.approvedNewName = ''
		self.buildGui ()
	#
	# buildGui
	#
	def buildGui ( self ):
		# build the gui created with QtDesigner
		self.ui = Ui_NodeNamesEditor ( )
		self.ui.setupUi ( self )
	#
	# setName
	#
	def setName ( self, newName ) :
		#
		if newName == '' :
			if self.saved_text != '' :
				newName = self.saved_text

		self.ui.name_lineEdit.setText ( newName )
		self.saved_text = newName     
	#
	# onAddItem
	#
	def onAddItem ( self ) :
		#
		if DEBUG_MODE : print '>> NodeNamesEditor: onAddItem'
		new_text = str ( self.ui.name_lineEdit.text () ).strip ()
		if new_text != '' :
			if  usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'addItem' ), new_text )
			else :
				self.addItem.emit ( new_text ) 
	#  
	# onRemoveItem
	#
	def onRemoveItem ( self ) :
		#
		if DEBUG_MODE : print '>> NodeNamesEditor::onRemoveItem'
		list_item = self.ui.listWidget.currentItem ()
		
		if list_item is not None :
			item_text = str ( list_item.text () )
			#self.ui.listWidget.takeItem ( self.ui.listWidget.currentRow () )
			#self.ui.listWidget.removeItemWidget ( list_item )
			if  usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'removeItem' ), item_text )
			else :
				self.removeItem.emit ( item_text )
	#
	# onRenameItem
	#
	def onRenameItem ( self ) :
		#
		if DEBUG_MODE : print '>> NodeNamesEditor.onRenameItem'
		new_text = str ( self.ui.name_lineEdit.text () ).strip ()
		
		if new_text == '' :
			if self.saved_text != '' :
				new_text = self.saved_text
				self.ui.name_lineEdit.setText ( new_text )  
						
		list_item = self.ui.listWidget.currentItem ()
		
		if list_item is not None : # e.g. listWidget is not empty
			old_text = list_item.text ()
			if new_text != old_text :
				if  usePyQt4 :
					self.emit ( QtCore.SIGNAL( 'renameItem' ), old_text, new_text )
				else :
					self.renameItem.emit ( old_text, new_text )
			else :  
				self.ui.listWidget.clearSelection ()
				self.ui.listWidget.setCurrentItem ( None )
	#    
	# onSelectionChanged
	#
	def onSelectionChanged ( self ) :
		#
		if DEBUG_MODE : print '>> NodeNamesEditor.onSelectionChanged'
		list_item = self.ui.listWidget.currentItem ()
		
		if list_item is not None :
			self.saved_text = str ( list_item.text() )
			self.ui.name_lineEdit.setText ( self.saved_text  )
			if  usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'selectionChangedSignal' ), self.saved_text  ) 
			else :
				self.selectionChangedSignal.emit ( self.saved_text  ) 
Beispiel #25
0
class ImageView ( QtModule.QGraphicsView ) :
	#
	# __init__
	#
	def __init__ ( self, parent ) :
		#
		QtModule.QGraphicsView.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.mouseDoubleClickSignal = Signal ()
			#
		self.state = 'idle' 
		self.panStartPos = None
		self.pixmap = None
		# set scene
		scene = QtModule.QGraphicsScene ( self )
		scene.setSceneRect ( 0, 0, 256, 256 )
		#scene.setItemIndexMethod ( QtGui.QGraphicsScene.NoIndex )
		self.setScene ( scene )
		# qt graphics stuff
		#self.setCacheMode ( QtGui.QGraphicsView.CacheBackground )
		self.setRenderHint ( QtGui.QPainter.Antialiasing )
		self.setTransformationAnchor ( QtModule.QGraphicsView.AnchorUnderMouse )
		self.setResizeAnchor ( QtModule.QGraphicsView.AnchorViewCenter )
		self.setDragMode ( QtModule.QGraphicsView.RubberBandDrag )
		self.setMouseTracking ( False )
		self.BgBrush = QtGui.QBrush ( QtGui.QColor ( 128, 128, 128 ) )  
	#
	# keyPressEvent
	#
	def keyPressEvent ( self, event ) : 
		#
		print ">> ImageView.keyPressEvent"
		QtModule.QGraphicsView.keyPressEvent ( self, event)
	#
	# wheelEvent
	#  
	def wheelEvent ( self, event ) :
		#
		#print ">> ImageView.wheelEvent"
		# QtGui.QGraphicsView.wheelEvent( self, event)
		import sys
		scale = -1.0
		if 'linux' in sys.platform: scale = 1.0     
		import math
		if  not usePyQt5 :
			scaleFactor = math.pow( 2.0, scale * event.delta() / 600.0 )
		else :
			delta = event.angleDelta ()
			#print ( '>> delta rx = %d ry = %d' % ( delta.x (), delta.y () ) )
			scaleFactor = math.pow( 2.0, scale * delta.y () / 600.0 )
		# self.matrix () is depicated
		factor = self.transform ().scale ( scaleFactor, scaleFactor ).mapRect ( QtCore.QRectF ( -1, -1, 2, 2 ) ).width ()
		if factor < 0.07 or factor > 100: return
		self.scale ( scaleFactor, scaleFactor )      
	#
	# mousePressEvent
	#
	def mousePressEvent ( self, event ) :
		#
		#print ">> ImageView.mousePressEvent"
		if ( event.button () == QtCore.Qt.MidButton or 
			 ( event.button () == QtCore.Qt.LeftButton and event.modifiers () == QtCore.Qt.ShiftModifier ) ) :  
			if self.state == 'idle':
				self.panStartPos = self.mapToScene ( event.pos () )
				self.state = 'pan'
				return
		QtModule.QGraphicsView.mousePressEvent ( self, event )        
	#
	# mouseDoubleClickEvent
	#
	def mouseDoubleClickEvent ( self, event ) :
		#
		#print ">> ImageView.mouseDoubleClickEvent"
		if usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'mouseDoubleClickSignal' ) )
		else :
			self.mouseDoubleClickSignal.emit ()
		QtModule.QGraphicsView.mouseDoubleClickEvent ( self, event )
	#
	# mouseMoveEvent
	#
	def mouseMoveEvent ( self, event ) :
		#
		#print ">> ImageView.mouseMoveEvent"
		if self.state == 'pan' :
			panCurrentPos = self.mapToScene ( event.pos () )
			panDeltaPos = panCurrentPos - self.panStartPos
			# update view matrix
			self.setInteractive ( False )
			self.translate ( panDeltaPos.x (), panDeltaPos.y () )        
			self.setInteractive ( True )  
		else :
			QtModule.QGraphicsView.mouseMoveEvent ( self, event )        
	#
	# mouseReleaseEvent
	#
	def mouseReleaseEvent ( self, event ):        
		#
		#print ">> ImageView.mouseReleaseEvent"
		if self.state == 'pan' :
			self.state = 'idle'  
			self.panStartPos = None
		QtModule.QGraphicsView.mouseReleaseEvent ( self, event )   
	#
	# viewportEvent
	#
	def viewportEvent ( self, event ) :
		#case QEvent::TouchBegin:
		# case QEvent::TouchUpdate:
		# case QEvent::TouchEnd:
		if event.type () == QtCore.QEvent.TouchBegin :
			print ">> ImageView: QEvent.TouchBegin"
		return QtModule.QGraphicsView.viewportEvent ( self, event )
	#
	# setImage
	#
	def setImage ( self, imageName ) :
		#
		self.pixmap = QtGui.QPixmap () 
		wi = 256
		hi = 256   

		if imageName != '' :
			print ">> ImageView.setImage name = %s" % imageName

			imageReader = QtGui.QImageReader ( imageName )

			if imageReader.canRead () :
				image = imageReader.read ()
				if not self.pixmap.convertFromImage ( image ) :
					print "!! QPixmap can't convert %s" % imageName  
			else:
				print "!! QImageReader can't read %s..." % imageName   
				# print imageReader.supportedImageFormats ()
				print "!! Lets try PIL module ..."
				import Image
				image = Image.open ( imageName )
				# image.verify()

				import os
				from global_vars import app_global_vars

				tmpname = app_global_vars [ 'TempPath' ] + '/' + os.path.basename ( imageName + '.png' )
				print "** Save %s ..." % tmpname 
				image.save ( tmpname )  

				self.pixmap = QtGui.QPixmap ( tmpname )

		if not self.pixmap.isNull ():
			wi = self.pixmap.width ()
			hi = self.pixmap.height () 
		else:
			print "!! ImageView: isNull()"  

		self.scene ().setSceneRect ( 0, 0, wi, hi )
		self.scene ().update ()
	#
	# drawBackground
	#
	def drawBackground ( self, painter, rect ) :
		#
		painter.setRenderHint ( QtGui.QPainter.Antialiasing )
		painter.setRenderHint ( QtGui.QPainter.SmoothPixmapTransform )
		painter.fillRect ( rect, self.BgBrush )
		if self.pixmap is not None:
			painter.drawPixmap ( 0, 0, self.pixmap )  
	#
	# resetZoom
	#
	def resetZoom ( self ) :
		#
		self.setInteractive ( False )
		self.resetTransform () 
		self.setInteractive ( True )          
class NodeParamEditor ( QtModule.QWidget ) :
	#
	# __init__
	#
	def __init__ ( self, parent ) :
		#
		QtModule.QWidget.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.changeParamName = Signal ()
			self.changeParamLabel = Signal ()
			self.changeParamIsShader = Signal ()
			self.changeParamType = Signal ()
			self.changeParamDetail = Signal ()
			self.changeParamProvider = Signal ()
			self.changeParamSubtype = Signal ()
			self.changeParamRange = Signal ()
			
			self.changeParamValue = Signal ()
			self.changeParamDefValue = Signal ()
		#
		self.param = None
		self.param_default = None
		self.paramWidgets = {	 'string'       : StringWidget
													,'image'        : StringWidget
													,'rib'          : StringWidget
													,'surface'      : StringWidget
													,'displacement' : StringWidget
													,'light'        : StringWidget
													,'volume'       : StringWidget
													,'float'        : FloatWidget
													,'int'          : IntWidget
													,'color'        : ColorWidget
													,'normal'       : NormalWidget
													,'transform'    : PointWidget
													,'point'        : PointWidget
													,'vector'       : VectorWidget
													,'matrix'       : MatrixWidget
													,'text'         : TextWidget
													,'control'      : ControlWidget
													,'shader'       : StringWidget
													,'geom'         : StringWidget
												}

		self.buildGui()
	#
	#
	def __delete__ ( self, obj ) :
		#
		print '* NodeParamEditor closed... %s' % str( obj )
	#
	# buildGui
	#
	def buildGui ( self ) :
		# build the gui created with QtDesigner
		self.ui = Ui_NodeParamEditor ( )
		self.ui.setupUi ( self )

		# correct UI sizes for some controls
		self.ui.check_enabled.setMinimumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )
		self.ui.check_enabled.setMaximumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )
		
		self.ui.check_display.setMinimumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )
		self.ui.check_display.setMaximumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )

		self.ui.check_shader.setMinimumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )
		self.ui.check_shader.setMaximumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )

		for label in VALID_PARAM_TYPES : self.ui.type_comboBox.addItem ( label )
		
		self.ui.type_comboBox.setCurrentIndex ( -1 )
		self.ui.type_comboBox.setMinimumSize ( QtCore.QSize ( UI.COMBO_WIDTH, UI.COMBO_HEIGHT ) )
		self.ui.type_comboBox.setMaximumSize ( QtCore.QSize( UI.MAX, UI.COMBO_HEIGHT ) )

		# temporary disabled, until "how to do it gracefully" will be clear ...
		self.ui.type_comboBox.setEnabled ( False )

		for label in [ 'None', 'uniform', 'varying', ]  :
			self.ui.detail_comboBox.addItem ( label )
		self.ui.detail_comboBox.setCurrentIndex ( -1 )
		self.ui.detail_comboBox.setMinimumSize ( QtCore.QSize ( UI.COMBO_WIDTH, UI.COMBO_HEIGHT ) )
		self.ui.detail_comboBox.setMaximumSize ( QtCore.QSize( UI.MAX, UI.COMBO_HEIGHT ) )

		for label in [ 'None', 'internal', 'external', 'primitive', 'attribute' ]  :
			self.ui.provider_comboBox.addItem ( label )
		self.ui.provider_comboBox.setCurrentIndex ( -1 )
		self.ui.provider_comboBox.setMinimumSize ( QtCore.QSize ( UI.COMBO_WIDTH, UI.COMBO_HEIGHT ) )
		self.ui.provider_comboBox.setMaximumSize ( QtCore.QSize( UI.MAX, UI.COMBO_HEIGHT ) )

		for label in [ 'None', 'slider', 'switch', 'selector', 'file', 'button' ]  :
			self.ui.subtype_comboBox.addItem ( label )
		self.ui.subtype_comboBox.setCurrentIndex ( -1 )
		self.ui.subtype_comboBox.setMinimumSize ( QtCore.QSize ( UI.COMBO_WIDTH, UI.COMBO_HEIGHT ) )
		self.ui.subtype_comboBox.setMaximumSize ( QtCore.QSize( UI.MAX, UI.COMBO_HEIGHT ) )
	#
	# As paramWidet is monitoring a change of param.value only,
	# we need to cynchronize changing of param_default.value with param.default
	#
	def onParamDefValueChanged ( self, param ) :
		#
		if DEBUG_MODE : print '* onParamDefValueChanged'
		self.param.default = self.param_default.value
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamDefValue' ), self.param )
		else :
			self.changeParamDefValue.emit ( self.param )
	#
	# onParamValueChanged
	#
	def onParamValueChanged ( self, param ) :
		#
		if DEBUG_MODE : print '* onParamValueChanged'
		self.param.value = param.value
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamValue' ), self.param )
		else :
			self.changeParamValue.emit ( self.param )
	#
	# connectSignals
	#
	def connectSignals ( self ) :
		#
		if  usePyQt4 :
			self.connect ( self.param_default, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamDefValueChanged )
			self.connect ( self.param, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamValueChanged )
			
			self.connect ( self.ui.name_lineEdit, QtCore.SIGNAL ( 'editingFinished()' ), self.onEditParamName )
			self.connect ( self.ui.label_lineEdit, QtCore.SIGNAL ( 'editingFinished()' ), self.onEditParamLabel )
			self.connect ( self.ui.check_enabled, QtCore.SIGNAL ( 'stateChanged(int)' ), self.onEditParamEnabled )
			self.connect ( self.ui.check_display, QtCore.SIGNAL ( 'stateChanged(int)' ), self.onEditParamDisplay )
			self.connect ( self.ui.check_shader, QtCore.SIGNAL ( 'stateChanged(int)' ), self.onEditParamShader )
			self.connect ( self.ui.type_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamType )
			self.connect ( self.ui.detail_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamDetail )
			self.connect ( self.ui.provider_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamProvider )
			self.connect ( self.ui.subtype_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamSubtype )
			self.connect ( self.ui.range_lineEdit, QtCore.SIGNAL ( 'editingFinished()' ), self.onEditParamRange )
			self.connect ( self.ui.descr_plainTextEdit, QtCore.SIGNAL ( 'textChanged()' ), self.onEditParamHelp )
		else :
			self.param_default.paramChangedSignal.connect ( self.onParamDefValueChanged )
			self.param.paramChangedSignal.connect ( self.onParamValueChanged )
			
			self.ui.name_lineEdit.editingFinished.connect ( self.onEditParamName )
			self.ui.label_lineEdit.editingFinished.connect ( self.onEditParamLabel )
			self.ui.check_enabled.stateChanged.connect ( self.onEditParamEnabled )
			self.ui.check_display.stateChanged.connect ( self.onEditParamDisplay )
			self.ui.check_shader.stateChanged.connect ( self.onEditParamShader )
			self.ui.type_comboBox.activated.connect ( self.onEditParamType )
			self.ui.detail_comboBox.activated.connect ( self.onEditParamDetail )
			self.ui.provider_comboBox.activated.connect ( self.onEditParamProvider )
			self.ui.subtype_comboBox.activated.connect ( self.onEditParamSubtype )
			self.ui.range_lineEdit.editingFinished.connect ( self.onEditParamRange )
			self.ui.descr_plainTextEdit.textChanged.connect ( self.onEditParamHelp )
	#
	# disconnectSignals
	#
	def disconnectSignals ( self ) :
		#
		if  usePyQt4 :
			if self.param_default is not None :
				self.disconnect ( self.param_default, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamDefValueChanged )
			if self.param is not None :
				self.disconnect ( self.param, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamValueChanged )
				
				self.disconnect ( self.ui.name_lineEdit, QtCore.SIGNAL ( 'editingFinished()' ), self.onEditParamName )
				self.disconnect ( self.ui.label_lineEdit, QtCore.SIGNAL ( 'editingFinished()' ), self.onEditParamLabel )
				self.disconnect ( self.ui.check_enabled, QtCore.SIGNAL ( 'stateChanged(int)' ), self.onEditParamEnabled )
				self.disconnect ( self.ui.check_display, QtCore.SIGNAL ( 'stateChanged(int)' ), self.onEditParamDisplay )
				self.disconnect ( self.ui.check_shader, QtCore.SIGNAL ( 'stateChanged(int)' ), self.onEditParamShader )
				self.disconnect ( self.ui.type_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamType )
				self.disconnect ( self.ui.detail_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamDetail )
				self.disconnect ( self.ui.provider_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamProvider )
				self.disconnect ( self.ui.subtype_comboBox, QtCore.SIGNAL ( 'activated(int)' ), self.onEditParamSubtype )
				self.disconnect ( self.ui.descr_plainTextEdit, QtCore.SIGNAL ( 'textChanged()' ), self.onEditParamHelp )
		else :
			if self.param_default is not None :
				self.param_default.paramChangedSignal.disconnect ( self.onParamDefValueChanged )
			if self.param is not None :
				self.param.paramChangedSignal.disconnect ( self.onParamValueChanged )
				
				self.ui.name_lineEdit.editingFinished.disconnect ( self.onEditParamName )
				self.ui.label_lineEdit.editingFinished.disconnect ( self.onEditParamLabel )
				self.ui.check_enabled.stateChanged.disconnect ( self.onEditParamEnabled )
				self.ui.check_display.stateChanged.disconnect ( self.onEditParamDisplay )
				self.ui.check_shader.stateChanged.disconnect ( self.onEditParamShader )
				self.ui.type_comboBox.activated.disconnect ( self.onEditParamType )
				self.ui.detail_comboBox.activated.disconnect ( self.onEditParamDetail )
				self.ui.provider_comboBox.activated.disconnect ( self.onEditParamProvider )
				self.ui.subtype_comboBox.activated.disconnect ( self.onEditParamSubtype )
				self.ui.range_lineEdit.editingFinished.disconnect ( self.onEditParamRange )
				self.ui.descr_plainTextEdit.textChanged.disconnect ( self.onEditParamHelp )
	#
	# reset
	#
	def reset ( self ) :
		#
		self.ui.name_lineEdit.setText ( '' )
		self.ui.label_lineEdit.setText ( '' )
		
		self.ui.check_enabled.setChecked ( True )
		self.ui.check_display.setChecked ( True )
		self.ui.check_shader.setChecked ( False )

		self.ui.type_comboBox.setCurrentIndex( -1 )
		self.ui.detail_comboBox.setCurrentIndex ( -1 )
		self.ui.provider_comboBox.setCurrentIndex ( -1 )
		self.ui.subtype_comboBox.setCurrentIndex ( -1 )
		self.ui.range_lineEdit.setText ( '' )

		doc = QtGui.QTextDocument ()
		doc.setPlainText ( '' )
		layout = QtModule.QPlainTextDocumentLayout ( doc )
		doc.setDocumentLayout ( layout )
		self.ui.descr_plainTextEdit.setDocument ( doc )
	#
	# Remove stackedWidget's layout every time,
	# when current parameter (or it's type) is changing
	#
	def removeValueWidget ( self ) :
		#
		while True :
			currentWidget = self.ui.value_stackedWidget.currentWidget ()
			if currentWidget is not None :
				#print '> removeWidget: %s' % str( currentWidget )
				self.ui.value_stackedWidget.removeWidget ( currentWidget )
			else :
				break
	#
	# setParam
	#
	def setParam ( self, param ) :
		#
		self.removeValueWidget()
		self.disconnectSignals()
		self.param = param
		
		if self.param is not None :
			#import copy
			self.param_default = self.param.copy() # duplicate param for default value editing
			self.param_default.value = param.default

			self.ui.name_lineEdit.setText ( self.param.name )
			self.ui.label_lineEdit.setText ( self.param.label )
			
			self.ui.check_enabled.setChecked ( self.param.enabled )
			self.ui.check_display.setChecked ( self.param.display )
			self.ui.check_shader.setChecked ( self.param.shaderParam )

			self.ui.type_comboBox.setCurrentIndex ( self.ui.type_comboBox.findText ( self.param.type ) )
			self.ui.detail_comboBox.setCurrentIndex ( self.ui.detail_comboBox.findText ( self.param.detail ) )
			self.ui.provider_comboBox.setCurrentIndex ( self.ui.provider_comboBox.findText ( self.param.provider ) )
			self.ui.subtype_comboBox.setCurrentIndex ( self.ui.subtype_comboBox.findText ( self.param.subtype ) )
			self.ui.range_lineEdit.setText ( self.param.range )

			doc = QtGui.QTextDocument ()
			help_text = ''
			if self.param.help != None : help_text = self.param.help

			doc.setPlainText ( help_text )
			layout = QtModule.QPlainTextDocumentLayout ( doc )
			doc.setDocumentLayout( layout )

			self.ui.descr_plainTextEdit.setDocument ( doc )
			#
			# setup param values view
			#
			paramsLayout = QtModule.QGridLayout ()
			paramsLayout.setContentsMargins ( 2, 2, 2, 2 )
			paramsLayout.setSizeConstraint ( QtModule.QLayout.SetNoConstraint )
			paramsLayout.setVerticalSpacing ( 4 )
			paramsLayout.setColumnStretch ( 1, 1 )
			paramsLayout.setRowStretch ( 2, 1 )
			
			frame = QtModule.QFrame ()
			frame.setLayout ( paramsLayout )

			if self.param.type in self.paramWidgets.keys () :
				print '>> Create %s param widget' % self.param.type

				# create paramWidget without GfxNode and ignoreSubtype = True
				self.ui.value_widget = apply ( self.paramWidgets [ self.param.type ], [ self.param, None, True ] )
				self.ui.value_widget.label.setText ( 'Current Value' )
				
				paramsLayout.addLayout ( self.ui.value_widget.label_vl, 0, 0, 1, 1 )
				paramsLayout.addLayout ( self.ui.value_widget.param_vl, 0, 1, 1, 1 )
				
				self.ui.def_value_widget = apply ( self.paramWidgets [ self.param_default.type ], [ self.param_default, None, True ] )
				self.ui.def_value_widget.label.setText ( 'Default Value' )

				paramsLayout.addLayout ( self.ui.def_value_widget.label_vl, 1, 0, 1, 1 )
				paramsLayout.addLayout ( self.ui.def_value_widget.param_vl, 1, 1, 1, 1 )
				
				spacer = QtModule.QSpacerItem ( 20, 20, QtModule.QSizePolicy.Minimum, QtModule.QSizePolicy.Expanding )
				paramsLayout.addItem ( spacer, 2, 0, 1, 1 ) 

			self.ui.value_stackedWidget.addWidget ( frame )
			self.connectSignals ()
		else :
			self.reset ()
	#
	# onEditParamName
	#
	def onEditParamName ( self ) :
		#
		# !!! ListWidget item for param also should be changed
		#
		oldName = self.param.name
		newName = str ( self.ui.name_lineEdit.text () ).strip ()
		if newName == '' :
			newName = oldName
			self.ui.name_lineEdit.setText ( newName )
		if newName != oldName :
			self.param.name = newName
			if  usePyQt4 :
				self.emit( QtCore.SIGNAL ( 'changeParamName' ), oldName, newName )
			else :
				self.changeParamName.emit ( oldName, newName )
	#
	# onEditParamLabel
	#
	def onEditParamLabel ( self ) :
		#
		oldName = self.param.label
		newName  = str ( self.ui.label_lineEdit.text () ).strip ()
		if newName == '' :
			newName = oldName
			self.ui.label_lineEdit.setText ( newName )
		if newName != oldName :
			self.param.label = newName
			if  usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'changeParamLabel' ), oldName, newName )
			else :
				self.changeParamLabel.emit ( oldName, newName )
	#
	# onEditParamEnabled
	#
	def onEditParamEnabled ( self, value ) : 
		#
		self.param.enabled = self.ui.check_enabled.isChecked ()
	#
	# onEditParamEnabled
	#
	def onEditParamDisplay ( self, value ) : 
		#
		self.param.display = self.ui.check_display.isChecked ()
	#
	# onEditParamShader
	#
	def onEditParamShader ( self, value )  : 
		#
		self.param.shaderParam = self.ui.check_shader.isChecked ()
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamIsShader' ), self.param )
		else :
			self.changeParamIsShader.emit ( self.param )
	#
	# onEditParamType
	#	
	def onEditParamType ( self, idx ) :
		#
		# !!! UI for param.value and param.default also should be changed
		#
		self.param.type = str ( self.ui.type_comboBox.itemText ( idx ) )
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamType' ), self.param )
		else :
			self.changeParamType.emit ( self.param )
	#
	# onEditParamDetail
	#	
	def onEditParamDetail ( self, idx ) :
		#
		self.param.detail = str ( self.ui.detail_comboBox.itemText ( idx ) )
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamDetail' ), self.param )
		else :
			self.changeParamDetail.emit ( self.param )
	#
	# onEditParamProvider
	#		
	def onEditParamProvider ( self, idx ) : 
		#
		self.param.provider = str ( self.ui.provider_comboBox.itemText ( idx ) )
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamProvider' ), self.param )
		else :
			self.changeParamProvider.emit ( self.param )
	#
	# onEditParamSubtype
	#		
	def onEditParamSubtype ( self, idx ) : 
		#
		self.param.subtype = str ( self.ui.subtype_comboBox.itemText ( idx ) )
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamSubtype' ), self.param )
		else :
			self.changeParamSubtype.emit ( self.param )
	#
	# onEditParamRange
	#		
	def onEditParamRange ( self ) : 
		#
		self.param.range = str ( self.ui.range_lineEdit.text () )
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'changeParamRange' ), self.param )
		else :
			self.changeParamRange.emit ( self.param )
	#
	# onEditParamHelp
	#			
	def onEditParamHelp ( self ) : 
		#
		self.param.help = str ( self.ui.descr_plainTextEdit.toPlainText () )
class NodePropertiesEditor(QtModule.QWidget):
    #
    # __init__
    #
    def __init__(self, parent, editNode=None):
        #
        QtModule.QWidget.__init__(self, parent)
        #
        # Define signals for PyQt5
        #
        if usePySide or usePyQt5:
            #
            self.changeNodeLabel = Signal()
            #
        self.editNode = editNode

        # self.debugPrint()
        self.buildGui()
        self.setNode(editNode)
        #
        # buildGui
        #

    def buildGui(self):
        # build the gui created with QtDesigner
        self.ui = Ui_NodePropertiesEditor()
        self.ui.setupUi(self)
        #
        # setNode
        #

    def setNode(self, editNode):
        #
        self.disconnectSignals()
        self.editNode = editNode

        if self.editNode is not None:
            #
            name = self.editNode.name
            if self.editNode.name is None:
                name = ""
            self.ui.name_lineEdit.setText(name)

            label = self.editNode.label
            if self.editNode.label is None:
                label = ""
            self.ui.label_lineEdit.setText(label)

            author = self.editNode.author
            if self.editNode.author is None:
                author = ""
            self.ui.author_lineEdit.setText(author)

            master = self.editNode.master
            if self.editNode.master is None:
                master = ""
            self.ui.master_lineEdit.setText(master)

            icon = self.editNode.icon
            if self.editNode.icon is None:
                icon = ""
            self.ui.icon_lineEdit.setText(icon)
            # print '* self.editNode.help = %s' %  self.editNode.help

            doc = QtGui.QTextDocument()
            help_text = ""
            if self.editNode.help != None:
                help_text = self.editNode.help

            doc.setPlainText(help_text)
            layout = QtModule.QPlainTextDocumentLayout(doc)
            doc.setDocumentLayout(layout)

            self.ui.help_plainTextEdit.setDocument(doc)

            self.ui.id_lineEdit.setText(str(self.editNode.id))

            self.ui.type_comboBox.setEditable(False)
            self.ui.type_comboBox.setMinimumSize(QtCore.QSize(UI.COMBO_WIDTH, UI.COMBO_HEIGHT))
            self.ui.type_comboBox.setMaximumSize(QtCore.QSize(UI.MAX, UI.COMBO_HEIGHT))

            currentIdx = -1
            i = 0
            for label in VALID_NODE_TYPES:
                self.ui.type_comboBox.addItem(label)
                if label == self.editNode.type:
                    currentIdx = i
                i += 1

            self.ui.type_comboBox.setCurrentIndex(currentIdx)

            # temporary disabled, until "how to do it gracefully" will be clear ...
            self.ui.type_comboBox.setEnabled(False)

            self.connectSignals()
            #
            # connectSignals
            #

    def connectSignals(self):
        # QtCore.QObject.
        if usePyQt4:
            self.connect(self.ui.name_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrName)
            self.connect(self.ui.label_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrLabel)
            self.connect(self.ui.master_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrMaster)
            self.connect(self.ui.author_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrAuthor)
            self.connect(self.ui.icon_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrIcon)
            self.connect(self.ui.type_comboBox, QtCore.SIGNAL("activated(int)"), self.onEditNodeType)
            self.connect(self.ui.help_plainTextEdit, QtCore.SIGNAL("textChanged()"), self.onEditNodeTxtAttr)
        else:
            self.ui.name_lineEdit.editingFinished.connect(self.onEditNodeStrAttrName)
            self.ui.label_lineEdit.editingFinished.connect(self.onEditNodeStrAttrLabel)
            self.ui.master_lineEdit.editingFinished.connect(self.onEditNodeStrAttrMaster)
            self.ui.author_lineEdit.editingFinished.connect(self.onEditNodeStrAttrAuthor)
            self.ui.icon_lineEdit.editingFinished.connect(self.onEditNodeStrAttrIcon)
            self.ui.type_comboBox.activated.connect(self.onEditNodeType)
            self.ui.help_plainTextEdit.textChanged.connect(self.onEditNodeTxtAttr)
            #
            # disconnectSignals
            #

    def disconnectSignals(self):
        #
        if usePyQt4:
            if self.editNode is not None:
                self.disconnect(self.ui.name_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrName)
                self.disconnect(self.ui.label_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrLabel)
                self.disconnect(
                    self.ui.master_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrMaster
                )
                self.disconnect(
                    self.ui.author_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrAuthor
                )
                self.disconnect(self.ui.icon_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrIcon)
                self.disconnect(self.ui.type_comboBox, QtCore.SIGNAL("activated(int)"), self.onEditNodeType)
                self.disconnect(self.ui.help_plainTextEdit, QtCore.SIGNAL("textChanged()"), self.onEditNodeTxtAttr)
        else:
            if self.editNode is not None:
                self.ui.name_lineEdit.editingFinished.disconnect(self.onEditNodeStrAttrName)
                self.ui.label_lineEdit.editingFinished.disconnect(self.onEditNodeStrAttrLabel)
                self.ui.master_lineEdit.editingFinished.disconnect(self.onEditNodeStrAttrMaster)
                self.ui.author_lineEdit.editingFinished.disconnect(self.onEditNodeStrAttrAuthor)
                self.ui.icon_lineEdit.editingFinished.disconnect(self.onEditNodeStrAttrIcon)
                self.ui.type_comboBox.activated.disconnect(self.onEditNodeType)
                self.ui.help_plainTextEdit.textChanged.disconnect(self.onEditNodeTxtAttr)
                #
                #
                # doesn't work ...
                #

    def onEditNodeStrAttr(self, attr=None):
        #
        if attr is not None and self.editNode is not None:
            if attr == "name":
                self.editNode.name = str(self.ui.name_lineEdit.text())
            elif attr == "label":
                self.editNode.label = str(self.ui.label_lineEdit.text())
            elif attr == "master":
                self.editNode.master = str(self.ui.master_lineEdit.text())
            elif attr == "author":
                self.editNode.author = str(self.ui.author_lineEdit.text())
            elif attr == "icon":
                self.editNode.icon = str(self.ui.icon_lineEdit.text())
                #
                #
                #

    def onEditNodeStrAttrName(self):
        self.editNode.name = str(self.ui.name_lineEdit.text())

    def onEditNodeStrAttrLabel(self):
        #
        oldLabel = self.editNode.label
        newLabel = str(self.ui.label_lineEdit.text()).strip()
        if newLabel == "":
            if usePyQt4:
                self.disconnect(self.ui.label_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrLabel)
            else:
                self.ui.label_lineEdit.editingFinished.disconnect(self.onEditNodeStrAttrLabel)
            newLabel = oldLabel
            self.ui.label_lineEdit.setText(newLabel)
            if usePyQt4:
                self.connect(self.ui.label_lineEdit, QtCore.SIGNAL("editingFinished()"), self.onEditNodeStrAttrLabel)
            else:
                self.ui.label_lineEdit.editingFinished.connect(self.onEditNodeStrAttrLabel)
        if newLabel != oldLabel:
            self.editNode.label = newLabel
            if usePyQt4:
                self.emit(QtCore.SIGNAL("changeNodeLabel"), oldLabel, newLabel)
            else:
                self.changeNodeLabel.emit(oldLabel, newLabel)
                #
                # onEditNodeStrAttrMaster
                #

    def onEditNodeStrAttrMaster(self):
        #
        self.editNode.master = str(self.ui.master_lineEdit.text())
        #
        # onEditNodeStrAttrAuthor
        #

    def onEditNodeStrAttrAuthor(self):
        #
        self.editNode.author = str(self.ui.author_lineEdit.text())
        #
        # onEditNodeStrAttrIcon
        #

    def onEditNodeStrAttrIcon(self):
        #
        self.editNode.icon = str(self.ui.icon_lineEdit.text())
        #
        # onEditNodeTxtAttr
        #

    def onEditNodeTxtAttr(self):
        #
        self.editNode.help = str(self.ui.help_plainTextEdit.toPlainText())
        #
        # onEditNodeType
        #

    def onEditNodeType(self, idx):
        #
        self.editNode.type = str(self.ui.type_comboBox.itemText(idx))
Beispiel #28
0
class WorkAreaScene ( QtModule.QGraphicsScene ) :
	#
	# __init__
	#
	def __init__ ( self, view ) :
		#
		QtModule.QGraphicsScene.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.startNodeConnector = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.traceNodeConnector = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.endNodeConnector = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.startNodeLink = Signal () #( QtModule.QGraphicsObject ) # QtModule.QGraphicsItem
			self.traceNodeLink = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.endNodeLink = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QPointF )
			self.onGfxNodeRemoved = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject )
			self.onGfxLinkRemoved = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject )
			self.nodeUpdated = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsItem )
			self.gfxNodeParamChanged = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsItem, QtCore.QObject )
			#
		self.view = view
		self.connectSignals ()
	#
	# connectSignals
	#
	def connectSignals ( self ) :
		if usePyQt4 :
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'selectionChanged()' ), self.view.onSelectionChanged )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'startNodeLink' ), self.view.onStartNodeLink )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'traceNodeLink' ), self.view.onTraceNodeLink )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'endNodeLink' ), self.view.onEndNodeLink )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'startNodeConnector' ), self.view.onStartNodeConnector )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'traceNodeConnector' ), self.view.onTraceNodeConnector )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'endNodeConnector' ), self.view.onEndNodeConnector )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'onGfxNodeRemoved' ), self.view.onRemoveNode )
			QtCore.QObject.connect ( self, QtCore.SIGNAL ( 'onGfxLinkRemoved' ), self.view.onRemoveLink )
		else :
			self.selectionChanged.connect ( self.view.onSelectionChanged )
			self.startNodeLink.connect ( self.view.onStartNodeLink )
			self.traceNodeLink.connect ( self.view.onTraceNodeLink )
			self.endNodeLink.connect ( self.view.onEndNodeLink )
			self.startNodeConnector.connect ( self.view.onStartNodeConnector )
			self.traceNodeConnector.connect ( self.view.onTraceNodeConnector )
			self.endNodeConnector.connect ( self.view.onEndNodeConnector )
			self.onGfxNodeRemoved.connect ( self.view.onRemoveNode )
			self.onGfxLinkRemoved.connect ( self.view.onRemoveLink )
Beispiel #29
0
class Notification(RanaModule):
    """This module provides notification support."""

    def __init__(self, *args, **kwargs):
        RanaModule.__init__(self, *args, **kwargs)
        self.notificationText = ""
        self.timeout = 5000
        self.position = 'middle'
        self.expirationTimestamp = time.time()
        self.draw = False
        self.redrawn = None
        self.wipOverlayEnabled = Signal()
        self._showWorkInProgressOverlay = False
        self.workStartTimestamp = None
        self._wipOverlayText = ""
        # this indicates if the notification about
        # background processing should be shown
        self._tasks = {}
        self._tasksLock = threading.RLock()

        ## for WiP overlay testing
        #self._tasks = {
        #  "foo" : ("foo", None),
        #  "bar" : ("bar", None),
        #  "baz" : ("baz", None)
        #}

        # key is an unique task name (unique for each instance of a task)
        # and value is a (status, progress) tuple
        self.tasksChanged = Signal()

        # connect thread manager signals to task status changes
        threadMgr.threadStatusChanged.connect(self.setTaskStatus)
        threadMgr.threadProgressChanged.connect(self.setTaskProgress)
        threadMgr.threadRemoved.connect(self.removeTask)

        # also with GTK GUI, assure screen is redrawn properly
        # when WiP overlay changes
        if gs.GUIString == "GTK":
            self.wipOverlayEnabled.connect(self._doRefresh)
            self.tasksChanged.connect(self._doRefresh)
            # we handle notification only with the GTK GUI and when the device module does not
            # support showing them
            if not self.modrana.dmod.hasNotificationSupport():
                self.modrana.notificationTriggered.connect(self._startCustomNotificationCB)

    def _doRefresh(self, ignore):
        self.set('needRedraw', True)

    def handleMessage(self, message, messageType, args):
        """the first part is the message, that will be displayed,
           there can also by some parameters, delimited by #
           NEW: you can also use a message list for the notification
                first goes 'm', the message and then the timeout in seconds


           EXAMPLE: ml:notification:m:Hello world!;5
           """

        if messageType == 'ml' and message == 'm':
            # advanced message list based notification
            if args:
                timeout = self.timeout
                if len(args) >= 2:
                    # convert to float, multiply by 1000 to convert to ms
                    # and then convert to integer number of ms
                    timeout = int(float(args[1])*1000)
                messageText = args[0]
                self.modrana.notify(messageText, timeout)

        elif messageType == 'ml' and message == 'workInProgressOverlay':
            if args:
                if args[0] == "enable":
                    self._startWorkInProgressOverlay()
                if args[0] == "disable":
                    self._stopWorkInProgressOverlay()

        elif messageType and message == "cancelTask":
            if args:
                self.cancelTask(args)

        else:
            parameterList = message.split('#')
            if len(parameterList) >= 2:
                messageText = parameterList[0]
                timeout = self.timeout
                self.modrana.notify(messageText, timeout)
                if len(parameterList) == 2:
                    try:
                         # override the default timeout and convert to ms
                        timeout = int(parameterList[1])*1000
                    except Exception:
                        self.log.exception("wrong timeout, using default 5 seconds")
                self.modrana.notify(messageText, timeout)
            else:
                self.log.error("wrong message: %s", message)

    def setTaskStatus(self, taskName, status):
        """Set textual status of the given WiP task

        :param taskName: task to modify
        :type taskName: str
        :param status: textual task status
        :type status: str
        """
        with self._tasksLock:
            oldStatus, progress = self._tasks.get(taskName, (None, None))
            # replace the task with updated one
            self._tasks[taskName] = (status, progress)
        self.tasksChanged(self._tasks)
        if status:
            self._startWorkInProgressOverlay()

    def setTaskProgress(self, taskName, progress):
        """Set numeric progress of the given WiP task

        :param taskName: task to modify
        :type taskName: str
        :param progress: numeric task progress in the range of 0.0 to 1.0
        :type progress: float
        """
        with self._tasksLock:
            status, oldProgress = self._tasks.get(taskName, (None, None))
            # replace the task with updated one
            self._tasks[taskName] = (status, progress)
        self.tasksChanged(self._tasks)
        if progress is not None:
            self._startWorkInProgressOverlay()

    def removeTask(self, taskName):
        """Remove given task from WiP tracking

        :param taskName: name of the task to cancel
        :type taskName: str
        """
        with self._tasksLock:
            try:
                del self._tasks[taskName]
                self.tasksChanged(self._tasks)
            except KeyError:
                self.log.error("error, can't remove unknown task: %s", taskName)
        if self._tasks == {}:
            self._stopWorkInProgressOverlay()

    def cancelTask(self, taskName):
        """Cancel a task - this both cancels the callback for the thread
        handling the task and removes the task from tracking

        :param taskName: task to cancel
        :type taskName: str
        """
        threadMgr.cancel_thread(taskName)
        # and finally stop tracking the task
        self.removeTask(taskName)
        self.log.info("task %s has been cancelled", taskName)

    def _startWorkInProgressOverlay(self):
        """start background work notification"""
        if not self._showWorkInProgressOverlay:
            self._showWorkInProgressOverlay = True
            self.workStartTimestamp = time.time()
            self.wipOverlayEnabled(True)

    def _stopWorkInProgressOverlay(self):
        """stop background work notification"""
        self._showWorkInProgressOverlay = False
        self.wipOverlayEnabled(False)

    #def getWorkInProgressOverlayText(self):
    #  elapsedSeconds = int(time.time() - self.workStartTimestamp)
    #  if elapsedSeconds: # 0s doesnt look very good :)
    #    return "%s %d s" % (self.wipOverlayText, elapsedSeconds)
    #  else:
    #    return self.wipOverlayText

    def drawWorkInProgressOverlay(self, cr):
        proj = self.m.get('projection', None) # we also need the projection module
        viewport = self.get('viewport', None)
        menus = self.m.get('menu', None)
        with self._tasksLock:
            if self._tasks and proj and viewport and menus:
                # we need to have both the viewport and projection modules available
                # also the menu module for the text

                taskCount = len(self._tasks)

                # background
                cr.set_source_rgba(0.5, 0.5, 1, 0.5)
                (sx, sy, w, h) = viewport
                itemHeight = h * 0.2
                (bx, by, bw, bh) = (0, 0, w, itemHeight * taskCount)
                cr.rectangle(bx, by, bw, bh)
                cr.fill()

                taskIndex = 0
                for taskName, taskState in six.iteritems(self._tasks):
                    # cancel button coordinates
                    cbdx = min(w, h) / 5.0
                    cbdy = cbdx
                    cbx1 = (sx + w) - cbdx
                    cby1 = sy + cbdy * taskIndex

                    # cancel button
                    self.drawCancelButton(cr, coords=(cbx1, cby1, cbdx, cbdy), taskName=taskName)

                    status, progress = taskState

                    # draw the text
                    border = min(w / 20.0, h / 20.0)
                    menus.showText(cr, status, bx + border, by + border + itemHeight * taskIndex,
                                   bw - 2 * border - cbdx, 30, "white")
                    taskIndex += 1

    def drawCancelButton(self, cr, coords=None, taskName=None):
        """draw the cancel button
        TODO: this and the other context buttons should be moved to a separate module,
        named contextMenu or something in the same style"""
        menus = self.m.get('menu', None)
        click = self.m.get('clickHandler', None)
        if menus and click:
            if coords: #use the provided coords
                (x1, y1, dx, dy) = coords
            else: # use the bottom right corner
                (x, y, w, h) = self.get('viewport')
                dx = min(w, h) / 5.0
                dy = dx
                x1 = (x + w) - dx
                y1 = y
                # the cancel button sends a cancel message to onlineServices
            # to disable currently running operation
            menus.drawButton(cr, x1, y1, dx, dy, '#<span foreground="red">cancel</span>', "generic:;0.5;;0.5;;", '')
            if taskName:
                message = "ms:notification:cancelTask:%s" % taskName
                click.registerXYWH(x1, y1, dx, dy, message, layer=2)
            else:
                click.registerXYWH(x1, y1, dx, dy, "onlineServices:cancelOperation", layer=2)

    def _startCustomNotificationCB(self, message, ms_timeout, icon=""):
        self.position = 'middle'
        self.notificationText = message
        self.expirationTimestamp = time.time() + ms_timeout/1000.0
        self.draw = True # enable drawing of notifications
        self.set('needRedraw', True) # make sure the notification is displayed

    def drawMasterOverlay(self, cr):
        """this function is called by the menu module, both in map mode and menu mode
        -> its bit of a hack, but we can """
        self._drawNotification(cr)
        if self._showWorkInProgressOverlay:
            self.drawWorkInProgressOverlay(cr)

    def _drawNotification(self, cr):
        """Draw the notifications on the screen on top of everything."""
        if time.time() <= self.expirationTimestamp:
            menus = self.m.get('menu', None)
            proj = self.m.get('projection', None)
            viewport = self.get('viewport', None)
            if not proj or not menus or not viewport:
                return
            x, y, w, h = viewport
            border = min(w / 20.0, h / 20.0)
            proj = self.m.get('projection', None)
            (x1, y1) = proj.screenPos(0.5, 0.5) # middle fo the screen
            cr.set_source_rgba(0, 0, 1, 0.45) # transparent blue
            font_size = 30
            # compute rendered text size
            textw, texth = menus.measureWrappedText(cr, self.notificationText, w - border * 2, font_size)
            # the background rectangle is as large as the text + borders
            rw = textw + 2 * border
            rh = texth + 2 * border
            # center the rectangle & text to be in the middle of the screen
            rx = (w - rw) / 2.0
            ry = (h - rh) / 2.0
            tx = rx + border
            ty = ry + border
            # draw the background rectangle
            cr.set_line_width(2)
            cr.set_source_rgba(0, 0, 1, 0.45) # transparent blue
            cr.rectangle(rx, ry, rw, rh) # create the transparent background rectangle
            cr.fill()
            # draw the text
            if menus and viewport and proj:
                menus.showWrappedText(cr, self.notificationText, tx, ty, textw, font_size, "white")
        else:
            self.draw = False  # we are finished, disable drawing notifications
Beispiel #30
0
class Notification(RanaModule):
    """This module provides notification support."""

    def __init__(self, m, d, i):
        RanaModule.__init__(self, m, d, i)
        self.notificationText = ""
        self.timeout = 5
        self.position = 'middle'
        self.expirationTimestamp = time.time()
        self.draw = False
        self.redrawn = None
        self.wipOverlayEnabled = Signal()
        self._showWorkInProgressOverlay = False
        self.workStartTimestamp = None
        self._wipOverlayText = ""
        # this indicates if the notification about
        # background processing should be shown
        self._tasks = {}
        self._tasksLock = threading.RLock()

        ## for WiP overlay testing
        #self._tasks = {
        #  "foo" : ("foo", None),
        #  "bar" : ("bar", None),
        #  "baz" : ("baz", None)
        #}

        # key is an unique task name (unique for each instance of a task)
        # and value is a (status, progress) tuple
        self.tasksChanged = Signal()

        # connect thread manager signals to task status changes
        threadMgr.threadStatusChanged.connect(self.setTaskStatus)
        threadMgr.threadProgressChanged.connect(self.setTaskProgress)
        threadMgr.threadRemoved.connect(self.removeTask)

        # also with GTK GUI, assure screen is redrawn properly
        # when WiP overlay changes
        if gs.GUIString == "GTK":
            self.wipOverlayEnabled.connect(self._doRefresh)
            self.tasksChanged.connect(self._doRefresh)

    def _doRefresh(self, ignore):
        self.set('needRedraw', True)

    def handleMessage(self, message, messageType, args):
        """the first part is the message, that will be displayed,
           there can also by some parameters, delimited by #
           NEW: you can also use a message list for the notification
                first goes 'm', the message and then the timeout in seconds


           EXAMPLE: ml:notification:m:Hello world!;5
           """

        if messageType == 'ml' and message == 'm':
            # advanced message list based notification
            if args:
                timeout = self.timeout
                if len(args) >= 2:
                    timeout = float(args[1])
                messageText = args[0]
                self.handleNotification(messageText, timeout)

        elif messageType == 'ml' and message == 'workInProgressOverlay':
            if args:
                if args[0] == "enable":
                    self._startWorkInProgressOverlay()
                if args[0] == "disable":
                    self._stopWorkInProgressOverlay()

        elif messageType and message == "cancelTask":
            if args:
                self.cancelTask(args)

        else:
            parameterList = message.split('#')
            if len(parameterList) >= 2:
                messageText = parameterList[0]
                timeout = self.timeout
                self.handleNotification(messageText, timeout)
                if len(parameterList) == 2:
                    try:
                        timeout = int(parameterList[1]) # override the default timeout
                    except Exception:
                        import sys

                        e = sys.exc_info()[1]
                        print("notification: wrong timeout, using default 5 seconds")
                        print(e)
                self.handleNotification(messageText, timeout)
            else:
                print("notification: wrong message: %s" % message)

    def setTaskStatus(self, taskName, status):
        """Set textual status of the given WiP task

        :param taskName: task to modify
        :type taskName: str
        :param status: textual task status
        :type status: str
        """
        with self._tasksLock:
            oldStatus, progress = self._tasks.get(taskName, (None, None))
            # replace the task with updated one
            self._tasks[taskName] = (status, progress)
        self.tasksChanged(self._tasks)
        if status:
            self._startWorkInProgressOverlay()

    def setTaskProgress(self, taskName, progress):
        """Set numeric progress of the given WiP task

        :param taskName: task to modify
        :type taskName: str
        :param progress: numeric task progress in the range of 0.0 to 1.0
        :type progress: float
        """
        with self._tasksLock:
            status, oldProgress = self._tasks.get(taskName, (None, None))
            # replace the task with updated one
            self._tasks[taskName] = (status, progress)
        self.tasksChanged(self._tasks)
        if progress is not None:
            self._startWorkInProgressOverlay()

    def removeTask(self, taskName):
        """Remove given task from WiP tracking

        :param taskName: name of the task to cancel
        :type taskName: str
        """
        with self._tasksLock:
            try:
                del self._tasks[taskName]
                self.tasksChanged(self._tasks)
            except KeyError:
                print("notification: error, can't remove unknown task: %s" % taskName)
        if self._tasks == {}:
            self._stopWorkInProgressOverlay()

    def cancelTask(self, taskName):
        """Cancel a task - this both cancels the callback for the thread
        handling the task and removes the task from tracking

        :param taskName: task to cancel
        :type taskName: str
        """
        threadMgr.cancel_thread(taskName)
        # and finally stop tracking the task
        self.removeTask(taskName)
        print("notification: task %s has been cancelled" % taskName)

    def _startWorkInProgressOverlay(self):
        """start background work notification"""
        if not self._showWorkInProgressOverlay:
            self._showWorkInProgressOverlay = True
            self.workStartTimestamp = time.time()
            self.wipOverlayEnabled(True)

    def _stopWorkInProgressOverlay(self):
        """stop background work notification"""
        self._showWorkInProgressOverlay = False
        self.wipOverlayEnabled(False)

    #def getWorkInProgressOverlayText(self):
    #  elapsedSeconds = int(time.time() - self.workStartTimestamp)
    #  if elapsedSeconds: # 0s doesnt look very good :)
    #    return "%s %d s" % (self.wipOverlayText, elapsedSeconds)
    #  else:
    #    return self.wipOverlayText

    def drawWorkInProgressOverlay(self, cr):
        proj = self.m.get('projection', None) # we also need the projection module
        viewport = self.get('viewport', None)
        menus = self.m.get('menu', None)
        with self._tasksLock:
            if self._tasks and proj and viewport and menus:
                # we need to have both the viewport and projection modules available
                # also the menu module for the text

                taskCount = len(self._tasks)

                # background
                cr.set_source_rgba(0.5, 0.5, 1, 0.5)
                (sx, sy, w, h) = viewport
                itemHeight = h * 0.2
                (bx, by, bw, bh) = (0, 0, w, itemHeight * taskCount)
                cr.rectangle(bx, by, bw, bh)
                cr.fill()

                taskIndex = 0
                for taskName, taskState in six.iteritems(self._tasks):
                    # cancel button coordinates
                    cbdx = min(w, h) / 5.0
                    cbdy = cbdx
                    cbx1 = (sx + w) - cbdx
                    cby1 = sy + cbdy * taskIndex

                    # cancel button
                    self.drawCancelButton(cr, coords=(cbx1, cby1, cbdx, cbdy), taskName=taskName)

                    status, progress = taskState

                    # draw the text
                    border = min(w / 20.0, h / 20.0)
                    menus.showText(cr, status, bx + border, by + border + itemHeight * taskIndex,
                                   bw - 2 * border - cbdx, 30, "white")
                    taskIndex += 1

    def drawCancelButton(self, cr, coords=None, taskName=None):
        """draw the cancel button
        TODO: this and the other context buttons should be moved to a separate module,
        named contextMenu or something in the same style"""
        menus = self.m.get('menu', None)
        click = self.m.get('clickHandler', None)
        if menus and click:
            if coords: #use the provided coords
                (x1, y1, dx, dy) = coords
            else: # use the bottom right corner
                (x, y, w, h) = self.get('viewport')
                dx = min(w, h) / 5.0
                dy = dx
                x1 = (x + w) - dx
                y1 = y
                # the cancel button sends a cancel message to onlineServices
            # to disable currently running operation
            menus.drawButton(cr, x1, y1, dx, dy, '#<span foreground="red">cancel</span>', "generic:;0.5;;0.5;;", '')
            if taskName:
                message = "ms:notification:cancelTask:%s" % taskName
                click.registerXYWH(x1, y1, dx, dy, message, layer=2)
            else:
                click.registerXYWH(x1, y1, dx, dy, "onlineServices:cancelOperation", layer=2)


    def handleNotification(self, message, timeout=None, icon=""):
        """Handle a notification request

        As on some platforms, such as on Maemo 5 Fremantle, system
        notifications should only be triggered from the main thread,
        we pass the notification request to the main loop, to be
        dispatched once the main GUI thread becomes idle
        """

        cron = self.m.get("cron", None)
        if cron:
            cron.addIdle(self._dispatchNotification, [message, timeout, icon])

    def _dispatchNotification(self, message, timeout, icon):
        """Dispatch a notification using the most optimal method for the
        current device & platform combination

        NOTE: This method should be run from the main thread as there might be
        issues otherwise (such as the "Xlib: unexpected async reply" errors).
        """
        # TODO: icon support
        if timeout is None:
            timeout = self.timeout

        print("notification: message: %s, timeout: %s" % (message, timeout))

        # if some module sends a notification during init, the device module might not be loaded yet
        if self.modrana.dmod and self.modrana.gui:
            if self.dmod.hasNotificationSupport(): # use platform specific method
                print("notification@dmod: message: %s, timeout: %s" % (message, timeout))
                self.dmod.notify(message, int(timeout) * 1000)
            elif self.modrana.gui.hasNotificationSupport():
                self.modrana.gui.notify(message, timeout, icon)
            else:
                self._startCustomNotification(message, timeout, icon)
        else:
            self._startCustomNotification(message, timeout, icon)

    def _startCustomNotification(self, message, timeout, icon=""):
        print("notification: message: %s, timeout: %s" % (message, timeout))
        self.position = 'middle'
        self.notificationText = message
        self.expirationTimestamp = time.time() + timeout
        self.draw = True # enable drawing of notifications
        self.set('needRedraw', True) # make sure the notification is displayed


    def drawMasterOverlay(self, cr):
        """this function is called by the menu module, both in map mode and menu mode
        -> its bit of a hack, but we can """
        self.drawNotification(cr)
        if self._showWorkInProgressOverlay:
            self.drawWorkInProgressOverlay(cr)

    def drawNotification(self, cr):
        """Draw the notifications on the screen on top of everything."""
        if time.time() <= self.expirationTimestamp:
            proj = self.m.get('projection', None)
            (x1, y1) = proj.screenPos(0.5, 0.5) # middle fo the screen
            cr.set_font_size(30)
            text = self.notificationText
            cr.set_source_rgba(0, 0, 1, 0.45) # transparent blue
            extents = cr.text_extents(text)
            (w, h) = (extents[2], extents[3])
            (x, y) = (x1 - w / 2.0, y1 - h / 2.0)
            cr.set_line_width(2)
            cr.set_source_rgba(0, 0, 1, 0.45) # transparent blue
            (rx, ry, rw, rh) = (x - 0.25 * w, y - h * 1.5, w * 1.5, (h * 2))
            cr.rectangle(rx, ry, rw, rh) # create the transparent background rectangle
            cr.fill()
            cr.set_source_rgba(1, 1, 1, 0.95) # slightly transparent white
            cr.move_to(x + 10, y)
            cr.show_text(text) # show the transparent notification text
            cr.stroke()
            cr.fill()
        else:
            self.draw = False # we are finished, disable drawing notifications
Beispiel #31
0
class WorkArea ( QtModule.QGraphicsView ) :
	#
	# __init__
	#
	def __init__ ( self ) :
		#
		QtModule.QGraphicsView.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.selectNodes = Signal () #( list, list )
			self.nodeConnectionChanged = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QObject )

			self.gfxNodeAdded = Signal () #( QtModule.QGraphicsObject )
			self.gfxNodeRemoved = Signal () #( QtModule.QGraphicsObject )
			#
		self.drawGrid = True
		self.gridSnap = False
		self.straightLinks = False
		self.reverseFlow = False

		self.gridSize = 10
		self.minGap = 120
		self.current_Z = 1

		self.state = 'idle'
		self.pressed = False
		self.startPos = None

		self.lastConnectCandidate = None
		self.currentGfxLink = None

		self.inspectedNode = None
		self.nodeNet = None

		self.selectedNodes = []
		self.selectedLinks = []

		# set scene
		scene = WorkAreaScene ( self )

		scene.setSceneRect ( -10000, -10000, 20000, 20000 )
		#scene.setItemIndexMethod ( QtGui.QGraphicsScene.NoIndex )
		self.setScene ( scene )

		# qt graphics stuff
		self.setCacheMode ( QtModule.QGraphicsView.CacheBackground )
		self.setRenderHint ( QtGui.QPainter.Antialiasing )

		self.setTransformationAnchor ( QtModule.QGraphicsView.AnchorUnderMouse ) # QtGui.QGraphicsView.AnchorUnderMouse
		self.setResizeAnchor ( QtModule.QGraphicsView.AnchorUnderMouse )  # AnchorViewCenter
		self.setDragMode ( QtModule.QGraphicsView.RubberBandDrag )

		self.setMouseTracking ( False )
		self.setAcceptDrops ( True )
		"""
		viewport = self.viewport()
		if viewport is not None :
			print ">> WorkArea viewport.setAcceptTouchEvents"
			#proxy = QtGui.QGraphicsProxyWidget ()
			proxy = viewport.graphicsProxyWidget ()
			if proxy is not None :
				proxy.setAcceptTouchEvents ( True )

			#self.setAttribute ( QtGui.AcceptTouchEvents, True )
			#viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
			#setDragMode(ScrollHandDrag);
			#Qt::WA_AcceptTouchEvents
		"""
		self.viewBrush = QtGui.QBrush ( QtGui.QColor ( 148, 148, 148 ) )
		self.setBackgroundBrush ( self.viewBrush )

		# self.connectSignals ()




		if DEBUG_MODE : print ">> WorkArea. __init__"
	#
	# connectSignals
	#
	def connectSignals ( self ) :
		#
		pass
	#
	# drawBackground
	#
	def drawBackground ( self, painter, rect ) :
		#
		sc_rect = self.sceneRect ()
		bbrush = QtGui.QBrush( QtGui.QColor ( 148, 148, 148 ) ) ## painter.background()
		painter.fillRect ( rect, bbrush )

		if self.drawGrid :
		#  print( "grid size = %d" % self.gridSize )
			gr_pen = QtGui.QPen ( QtGui.QColor ( 180, 180, 180 ) )
			gr_pen.setWidth ( 0 )
			painter.setPen ( gr_pen )
			for x in range ( int ( sc_rect.x () ), int ( sc_rect.right () ), self.gridSize ):
				painter.drawLine ( x, sc_rect.y (), x, sc_rect.bottom () )
			for y in range ( int ( sc_rect.y () ), int ( sc_rect.bottom () ), self.gridSize ):
				painter.drawLine ( sc_rect.x (), y, sc_rect.right (), y )
	#
	# Returns a list of GfxNodes in the scene for given type
	# or all nodes if type == None
	#
	def getGfxNodesByType ( self, type = None ) :
		#
		resultList = []
		for item in self.scene ().items () :
			if ( isinstance ( item, GfxNode ) or
					 isinstance ( item, GfxSwatchNode ) or 
					 ( isinstance ( item, GfxNodeConnector ) and item.isNode () ) ) :
				if type is None or item.node.type == type :
					resultList.append ( item )
		return resultList
	#
	# Returns a list of GfxNodes in the scene for given format
	# or all nodes if type == None
	#
	def getGfxNodesByFormat ( self, format = None ) :
		#
		resultList = []
		for item in self.scene ().items () :
			if ( isinstance ( item, GfxNode ) or
					 isinstance ( item, GfxSwatchNode ) or 
					 ( isinstance ( item, GfxNodeConnector ) and item.isNode () ) ) :
				if format is None or item.node.format == format :
					resultList.append ( item )
		return resultList
	#
	# Returns GfxNodes for given Node
	#
	def getGfxNodesByNode ( self, node = None ) :
		#
		gfxNode = None
		for item in self.scene ().items () :
			if ( isinstance ( item, GfxNode ) or
					 isinstance ( item, GfxSwatchNode ) or 
					( isinstance ( item, GfxNodeConnector ) and item.isNode () ) ) :
				if item.node == node :
					gfxNode = item
					break
		return gfxNode
	#
	# selectAllNodes
	#
	def getAllGfxNodes ( self ) : return self.getGfxNodesByType ( None )
	#
	# selectAllNodes
	#
	def selectAllNodes ( self ) :
		#
		for item in self.getAllGfxNodes () : item.setSelected ( True )
	#
	# selectAbove
	#
	def selectAbove ( self, upperGfxNode ) :
		#
		if DEBUG_MODE : print '>> WorkArea::selectAbove node (%s) links:' % upperGfxNode.node.label
		for link_list in upperGfxNode.node.outputLinks.values () :
			for link in link_list :
				# link.printInfo ()
				if self.nodeNet.hasThisLink ( link ) :
					gfxNode = self.getGfxNodesByNode ( link.dstNode )
					gfxNode.setSelected ( True )
					self.selectAbove ( gfxNode )
				else :
					if DEBUG_MODE : print '!! invalid link ...'
	#
	# updateBelow
	#
	def updateBelow ( self, upperGfxNode, removeLinks = False ) :
		#
		if DEBUG_MODE : print '>> WorkArea::updateBelow upperGfxNode.node (%s) children:' % upperGfxNode.node.label
		for node in upperGfxNode.node.childs :
			if DEBUG_MODE : print '* %s' % node.label
			gfxNode = self.getGfxNodesByNode ( node )
			gfxNode.updateGfxNode ( removeLinks )
			self.updateBelow ( gfxNode, removeLinks )
	#
	# selectBelow
	#
	def selectBelow ( self, upperGfxNode ) :
		#
		if DEBUG_MODE : print '>> WorkArea::selectBelow upperGfxNode.node (%s) children:' % upperGfxNode.node.label
		for node in upperGfxNode.node.childs :
			if DEBUG_MODE : print '* %s' % node.label
			gfxNode = self.getGfxNodesByNode ( node )
			gfxNode.setSelected ( True )
			self.selectBelow ( gfxNode )
	#
	# setNodeNetwork
	#
	def setNodeNetwork ( self, nodeNet ) : self.nodeNet = nodeNet
	#
	# clear
	#
	def clear ( self ):
		#
		if DEBUG_MODE : print '>> WorkArea:: clearing nodes ...'
		for item in self.scene ().items () : self.scene ().removeItem ( item )
		self.nodeNet.clear ()
		self.state = 'idle'
		self.panStartPos = None
		self.lastConnectCandidate = None
		self.currentGfxLink = None
		self.inspectedNode = None
	#
	# addGfxLink
	#
	def addGfxLink ( self, link ) :
		#
		if DEBUG_MODE : print '>> WorkArea::addGfxLink (id=%d)' % link.id
		gfxLink = GfxLink ( link )
		( srcNode, srcParam ) = link.getSrc ()
		( dstNode, dstParam ) = link.getDst ()
		srcConnector = None
		dstConnector = None
		for item in self.scene ().items ():
			if isinstance ( item, GfxNode ) or isinstance ( item, GfxSwatchNode ) :
				if item.node == srcNode :
					srcConnector = item.getOutputConnectorByParam ( srcParam )
				elif item.node == dstNode :
					dstConnector = item.getInputConnectorByParam ( dstParam )
			elif isinstance ( item, GfxNodeConnector ) and item.isNode () :
				if item.node == srcNode :
					srcConnector = item
				elif item.node == dstNode :
					dstConnector = item
			if ( srcConnector != None and dstConnector != None ) :
				break
		gfxLink.setSrcConnector ( srcConnector )
		gfxLink.setDstConnector ( dstConnector )
		gfxLink.adjust ()
		self.scene ().addItem ( gfxLink )
	#
	# Node already in NodeNet, so add new GfxNode to scene
	#
	def addGfxNode ( self, node, pos = None ) :
		#
		#print ( ">> WorkArea: addGfxNode %s" % node.label )
		if node.type == 'connector' :
			gfxNode = GfxNodeConnector ( node.inputParams [ 0 ], node = node )
		elif node.type == 'note' :
			gfxNode = GfxNote ( node )
		elif node.type == 'swatch' :
			gfxNode = GfxSwatchNode ( node )
		else :
			gfxNode = GfxNode ( node )
		scene = self.scene ()
		if pos != None : gfxNode.moveBy ( pos.x(), pos.y() )
		#for item in scene.selectedItems (): item.setSelected ( False )
		scene.addItem ( gfxNode )
		gfxNode.setSelected ( True )
		if usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'gfxNodeAdded' ), gfxNode )
		else :
			self.gfxNodeAdded.emit ( gfxNode )
	#
	# adjustLinks
	#
	def adjustLinks ( self ) :
		#
		for item in self.scene ().items () :
			if isinstance ( item, GfxLink ): item.adjust ()
	#
	# fitGfxNodesInView
	#
	def fitGfxNodesInView ( self, gfxNodeList ) :
		#
		nodeNetRect = QtCore.QRectF ()
		for gfxNode in gfxNodeList :
			nodeRect = gfxNode.sceneBoundingRect ()
			if nodeNetRect.isNull () :
				nodeNetRect = nodeRect
			nodeNetRect = nodeNetRect.united ( nodeRect )
		if nodeNetRect.isValid () :
			self.fitInView ( nodeNetRect, QtCore.Qt.KeepAspectRatio ) 
	#
	# onSelectionChanged
	#
	def onSelectionChanged ( self ) :
		#
		#print ">> WorkArea: onSelectionChanged "
		self.selectedNodes = []
		self.selectedLinks = []
		selected = self.scene ().selectedItems ()

		for item in selected:
			if   isinstance ( item, GfxNode ) : self.selectedNodes.append ( item )
			elif isinstance ( item, GfxNote ) : self.selectedNodes.append ( item )
			elif isinstance ( item, GfxNodeConnector ) : self.selectedNodes.append ( item )
			elif isinstance ( item, GfxSwatchNode ) : self.selectedNodes.append ( item )
			elif isinstance ( item, GfxLink ) : self.selectedLinks.append ( item )

		if usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'selectNodes' ), self.selectedNodes, self.selectedLinks )
		else :
			self.selectNodes.emit ( self.selectedNodes, self.selectedLinks )
	#
	# lastConnectCandidateReset
	#
	def lastConnectCandidateReset ( self ) :
		#
		if self.lastConnectCandidate is not None :
			self.lastConnectCandidate.hilite( False )
		self.lastConnectCandidate = None
	#
	# isLinkAcceptable
	#
	def isLinkAcceptable ( self, connector, connectCandidate ) :
		#
		isAcceptable = False
		if isinstance ( connectCandidate, GfxNodeConnector ):
			# do not connect to itself
			if connectCandidate != connector :
				# do not connect to the same node
				if connectCandidate.parentItem () != connector.parentItem () :
					# do not connect the same link to connector twice
					if not connectCandidate.hasThisLink ( self.currentGfxLink ) :
						# connect only to similar type
						if connector.param.encodedTypeStr() == connectCandidate.param.encodedTypeStr () :
							if not connectCandidate.isNode () :
								# connect only input with output and vice versa
								if connector.param.isInput != connectCandidate.param.isInput :
										isAcceptable = True
							else :
								# we have nodeConnector
								isAcceptable = True

		return isAcceptable
	#
	# onStartNodeLink
	#
	#@QtCore.pyqtSlot( GfxNodeConnector )
	def onStartNodeLink ( self, connector ):
		#
		#if DEBUG_MODE : print '>> WorkArea::onStartNodeLink'
		#if DEBUG_MODE : print connector	
		srcNode = connector.getNode ()
		srcParam = connector.param
		if DEBUG_MODE : print '>> WorkArea::onStartNodeLink from %s (%s)' % ( srcNode.label, srcParam.label )

		srcConnector = connector
		self.state = 'traceNodeLink'
		self.lastConnectCandidate = None

		if connector.isInput () and connector.isLinked () :
			oldLink = connector.getFirstGfxLink ()
			srcConnector = oldLink.srcConnector
			oldLink.remove ()

		gfxLink = GfxLink ( None, srcConnector )
		self.scene ().addItem ( gfxLink )
		self.currentGfxLink = gfxLink
		self.currentGfxLink.isLinkSelected = True
	#
	# onTraceNodeLink
	#
	def onTraceNodeLink ( self, connector, scenePos ) :
		# node = connector.parentItem().node
		# print ">> WorkArea: onDrawNodeLink from %s (%d %d)" % ( node.label, scenePos.x(), scenePos.y() )
		if usePyQt4 :
			connectCandidate = self.scene ().itemAt ( scenePos )
		else :
			connectCandidate = self.scene ().itemAt ( scenePos, self.transform () )
		srcConnector = self.currentGfxLink.srcConnector
		swappedLink = False
		if srcConnector is None : # link has swapped connectors
			srcConnector = self.currentGfxLink.dstConnector
			swappedLink = True

		if self.isLinkAcceptable ( srcConnector, connectCandidate ) :
			if connectCandidate != self.lastConnectCandidate :
				self.lastConnectCandidateReset ()
				connectCandidate.hilite ( True )
				self.lastConnectCandidate = connectCandidate
				# link_node = connectCandidate.parentItem ().node
				# print ">> WorkArea: onDrawNodeLink to %s" % link_node.label
			else :
				scenePos = self.lastConnectCandidate.getCenterPoint () # snap to last position
				pass
				# self.lastConnectCandidateReset ()
		else :
			self.lastConnectCandidateReset ()

		#if self.currentGfxLink is not None :
		if swappedLink :
			self.currentGfxLink.setSrcPoint ( scenePos )
		else :
			self.currentGfxLink.setDstPoint ( scenePos )
	#
	# onEndNodeLink
	#
	def onEndNodeLink ( self, connector, scenePos ) :
		#
		srcConnector = self.currentGfxLink.srcConnector
		dstConnector = self.currentGfxLink.dstConnector
		swappedLink = False
		if srcConnector is None : # link has swapped connectors
			swappedLink = True

		if self.lastConnectCandidate is None :
			self.currentGfxLink.remove ()
			#self.emit( QtCore.SIGNAL( 'nodeParamChanged' ), srcConnector.parentItem(), srcConnector.param )
			#self.emit( QtCore.SIGNAL( 'nodeParamChanged' ), dstConnector.parentItem(), dstConnector.param )
		else :
			if self.lastConnectCandidate.isNode () :
				# if connection was made to ConnectorNode
				if dstConnector is None :
					self.lastConnectCandidate.removeInputGfxLinks ()
			else :
				# remove old link first if it exists
				if self.lastConnectCandidate.isInput () and self.lastConnectCandidate.isLinked () :
					#oldLink = self.lastConnectCandidate.getFirstLink ()
					#oldLink.remove ()
					self.lastConnectCandidate.removeInputGfxLinks ()

			self.currentGfxLink.isLinkSelected = False
			self.currentGfxLink.update ()

			srcNode = dstNode = None
			srcParam = dstParam = None

			if swappedLink :
				srcNode = self.lastConnectCandidate.getNode ()
				srcParam = self.lastConnectCandidate.param
				if self.lastConnectCandidate.isNode () :
					srcParam = self.lastConnectCandidate.getFirstOutputParam ()
				dstNode = dstConnector.getNode ()
				dstParam = dstConnector.param
				self.currentGfxLink.setSrcConnector ( self.lastConnectCandidate )
			else :
				srcNode = srcConnector.getNode ()
				srcParam = srcConnector.param
				dstNode = self.lastConnectCandidate.getNode ()
				dstParam = self.lastConnectCandidate.param
				if self.lastConnectCandidate.isNode () :
					dstParam = self.lastConnectCandidate.getFirstInputParam ()
				self.currentGfxLink.setDstConnector ( self.lastConnectCandidate )

			link = NodeLink.build ( srcNode, dstNode, srcParam, dstParam )

			#if not dstParam.isInput :
				# swap source and destination
			#  self.currentGfxLink.swapConnectors ()
			#  link.swapNodes ()

			self.currentGfxLink.link = link
			self.nodeNet.addLink ( link )
			if usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'nodeConnectionChanged' ), self.currentGfxLink.dstConnector.getGfxNode (), self.currentGfxLink.dstConnector.param )
			else :
				self.nodeConnectionChanged.emit ( self.currentGfxLink.dstConnector.getGfxNode (), self.currentGfxLink.dstConnector.param )

		self.lastConnectCandidateReset ()
		self.currentGfxLink = None
		self.state = 'idle'
	#
	# onStartNodeConnector
	#
	def onStartNodeConnector ( self, connector, scenePos  ) :
		#
		if DEBUG_MODE : print '>> WorkArea::onStartNodeConnector'
		self.state = 'traceNodeConnector'

		newNode = ConnectorNode ()
		self.nodeNet.addNode ( newNode )

		newParam = connector.param.copy ()
		newParam.isInput = False
		newInParam = newParam.copy ()
		newOutParam = newParam.copy ()

		newNode.addInputParam ( newInParam )
		newNode.addOutputParam ( newOutParam )

		newConnector = GfxNodeConnector ( newParam, connector.radius, node = newNode )
		newConnector.brush = connector.brush
		newConnector.setPos ( scenePos )
		newConnector.moveBy ( -connector.radius, -connector.radius )

		self.lastConnectCandidate = newConnector
		self.scene ().addItem ( newConnector )
		newConnector.hilite ( True )

		srcNode = connector.getNode ()
		srcParam = connector.getOutputParam ()
		dstNode = newConnector.getNode ()
		dstParam = newConnector.getInputParam ()

		#
		# swap link direction only for connectors
		# in open chain connected to input node parameter
		#
		swappedLink = False
		if connector.isConnectedToInput () and not connector.isConnectedToOutput () :
			if DEBUG_MODE : print '*** swap link direction ***'
			swappedLink = True
			srcNode = newConnector.getNode ()
			srcParam = newConnector.getOutputParam ()
			dstNode = connector.getNode ()
			dstParam = connector.getInputParam ()

		link = NodeLink.build ( srcNode, dstNode, srcParam, dstParam )
		# if swappedLink : link.swapNodes ()
		self.nodeNet.addLink ( link )

		#if DEBUG_MODE : self.nodeNet.printInfo ()

		# preserve existing links for parameter connectors
		if connector.isLinked () and not connector.isNode () :
			if connector.isInput () :
				#print '*** preserve input ***'
				# TODO!!!
				# This is very rough code -- needs to be wrapped in functions
				gfxLinks = connector.getInputGfxLinks ()
				
				for gfxLink in gfxLinks :
					gfxLink.setDstConnector ( newConnector )

					# remove gfxLink from previouse connector
					connector.removeGfxLink ( gfxLink )

					# adjust destination for node link
					newConnector.getNode ().attachInputParamToLink ( newConnector.getInputParam (), gfxLink.link )
					newConnector.getNode ().addChild ( gfxLink.link.srcNode )
					connector.getNode ().removeChild ( gfxLink.link.srcNode )

					gfxLink.link.dstNode = newConnector.getNode ()
					gfxLink.link.dstParam = newConnector.getInputParam ()
			else :
				#print '*** preserve output ***'
				gfxLinks = connector.getOutputGfxLinks ()
				
				for gfxLink in gfxLinks :
					gfxLink.setSrcConnector ( newConnector )

					# remove gfxLink from previouse connector
					connector.removeGfxLink ( gfxLink )

					# adjust source for node link
					connector.getNode ().detachOutputParamFromLink ( gfxLink.link.srcParam, gfxLink.link )
					newConnector.getNode ().attachOutputParamToLink ( newConnector.getOutputParam (), gfxLink.link )
					#newConnector.getNode ().childs.add ( connector.getNode () )
					gfxLink.link.dstNode.addChild ( newConnector.getNode () )
					gfxLink.link.dstNode.removeChild ( connector.getNode () )

					gfxLink.link.srcNode = newConnector.getNode ()
					gfxLink.link.srcParam = newConnector.getOutputParam ()

			#if DEBUG_MODE : self.nodeNet.printInfo ()

		gfxLink = GfxLink ( link, connector, newConnector  )
		self.scene ().addItem ( gfxLink )
	#
	# onTraceNodeConnector
	#
	def onTraceNodeConnector ( self, connector, scenePos ) :
		#
		#if DEBUG_MODE : print '>> WorkArea::onTraceNodeConnector'
		if self.lastConnectCandidate is not None :
			self.lastConnectCandidate.setPos ( scenePos )
			self.lastConnectCandidate.moveBy ( -connector.radius, -connector.radius )
	 #
	# onEndNodeConnector
	#
	def onEndNodeConnector ( self, connector, scenePos ) :
		#
		if DEBUG_MODE : print '>> WorkArea::onEndNodeConnector'
		print '>> lastConnectCandidate.node.type = %s' % self.lastConnectCandidate.node.type
		self.lastConnectCandidateReset ()
		self.state = 'idle'
	#
	# onRemoveNode
	#
	def onRemoveNode ( self, gfxNode ) :
		#
		print ">> WorkArea.onRemoveNode %s (id = %d)" % ( gfxNode.node.label, gfxNode.node.id )
		if usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'gfxNodeRemoved' ), gfxNode )
		else :
			self.gfxNodeRemoved.emit ( gfxNode )
		self.scene ().removeItem ( gfxNode )
		self.nodeNet.removeNode ( gfxNode.node )

		#if DEBUG_MODE : self.nodeNet.printInfo ()
	#
	# onRemoveLink
	#
	def onRemoveLink ( self, gfxLink ) :
		#
		print ">> WorkArea.onRemoveLink ..."
		self.scene ().removeItem ( gfxLink )
		
		if gfxLink.link is not None :
			print "*** (id = %d)" % ( gfxLink.link.id )
			srcConnector = gfxLink.srcConnector
			dstConnector = gfxLink.dstConnector
			self.nodeNet.removeLink ( gfxLink.link )
			if srcConnector is not None :
				if DEBUG_MODE : print '*** srcConnector.parentItem().node.label = %s ' % srcConnector.getNode ().label
				#self.emit( QtCore.SIGNAL( 'nodeConnectionChanged' ), srcConnector.parentItem(), srcConnector.param )
			if dstConnector is not None :
				if DEBUG_MODE : print '*** dstConnector.parentItem().node.label = %s ' % dstConnector.getNode ().label
				if usePyQt4 :
					self.emit ( QtCore.SIGNAL ( 'nodeConnectionChanged' ), dstConnector.getGfxNode (), dstConnector.param )
				else :
					self.nodeConnectionChanged.emit ( dstConnector.getGfxNode (), dstConnector.param )
	#
	# removeSelected
	#
	def removeSelected ( self ) :
		#
		if DEBUG_MODE : print '>> WorkArea.removeSelected: (before) nodes = %d links = %d' % ( len (  self.nodeNet.nodes.values () ), len ( self.nodeNet.links.values () ) )
		selected = self.scene().selectedItems()

		for item in selected:
			if ( isinstance ( item, GfxLink ) or
					 isinstance ( item, GfxNode ) or
					 isinstance ( item, GfxNote ) or
					 isinstance ( item, GfxSwatchNode ) or
				 ( isinstance ( item, GfxNodeConnector ) and item.isNode () ) ) : item.remove ()

		if DEBUG_MODE : print '>> WorkArea.removeSelected (after) nodes = %d links = %d' % ( len ( self.nodeNet.nodes.values ()), len ( self.nodeNet.links.values ()) )
	#
	# dragEnterEvent
	#
	def dragEnterEvent ( self, event ) :
		#
		print '>> WorkArea.onDragEnterEvent'
		#for form_str in event.mimeData().formats():
		#  print str ( form_str )
		#  if form_str == 'text/uri-list' :
		#    print event.mimeData().data( 'text/uri-list' )
		mimedata = event.mimeData ()

		if mimedata.hasFormat ( 'application/x-text' ) or mimedata.hasFormat ( 'text/uri-list' ):
			event.accept ()
		else:
			event.ignore ()
	#
	# dragMoveEvent
	#
	def dragMoveEvent ( self, event ) :
		#print ">> WorkArea.dragMoveEvent"
		mimedata = event.mimeData ()
		if mimedata.hasFormat ( 'application/x-text' ) or mimedata.hasFormat ( 'text/uri-list' ):
			event.setDropAction ( QtCore.Qt.CopyAction )
			event.accept ()
		else:
			event.ignore ()
	#
	# dropEvent
	#
	def dropEvent ( self, event ) :
		#
		import os
		if DEBUG_MODE : print ">> WorkArea.dropEvent"
		file_list = []
		mimedata = event.mimeData ()

		if mimedata.hasFormat ( 'application/x-text' ) :
			# decode drop stuff
			data = mimedata.data ( 'application/x-text' )
			stream = QtCore.QDataStream ( data, QtCore.QIODevice.ReadOnly )
			if usePyQt4 :
				filename = QtCore.QString ()
			else :
				filename = ''
			if not usePyQt5 :
				if usePySide :
					filename = stream.readString ()
				else :
					stream >> filename
			else :
				filename = stream.readBytes ()

			if DEBUG_MODE : print '* read itemFilename = %s' % ( filename )

			file_list.append ( filename )
			event.setDropAction ( QtCore.Qt.CopyAction )
			event.accept ()
		elif mimedata.hasFormat ( 'text/uri-list' ) :
			data = str ( mimedata.data( 'text/uri-list' ).data() )
			#print data
			for item in data.split () :
				filename = str ( QtCore.QUrl( item ).toLocalFile () )

				( name, ext ) = os.path.splitext( os.path.basename( filename ) )
				if DEBUG_MODE : print ':: %s (%s)' % ( filename, ext )
				if ext == '.xml' :
					file_list.append ( filename )
		else:
			event.ignore ()

		for file_name in file_list : self.insertNodeNet ( file_name, self.mapToScene( event.pos () ) )
	#
	# keyPressEvent
	#
	def keyPressEvent ( self, event ) :
		#print ">> WorkArea.keyPressEvent"
		QtModule.QGraphicsView.keyPressEvent ( self, event)
	#
	# wheelEvent
	#
	def wheelEvent ( self, event ) :
		#print ">> WorkArea.wheelEvent"
		# QtGui.QGraphicsView.wheelEvent( self, event)
		import sys, math
		scale = -1.0
		if 'linux' in sys.platform: scale = 1.0
		if  not usePyQt5 :
			scaleFactor = math.pow( 2.0, scale * event.delta () / 600.0 )
		else :
			delta = event.angleDelta ()
			#print ( '>> delta rx = %d ry = %d' % ( delta.x (), delta.y () ) )
			scaleFactor = math.pow( 2.0, scale * delta.y () / 600.0 )
		# self.matrix () is depicated
		factor = self.transform ().scale ( scaleFactor, scaleFactor ).mapRect ( QtCore.QRectF ( -1, -1, 2, 2 ) ).width ()
		if factor < 0.07 or factor > 100: return
		self.scale ( scaleFactor, scaleFactor )
	#
	# mousePressEvent
	#
	def mousePressEvent ( self, event ) :
		#print ">> WorkArea.mousePressEvent"
		#self.setFocus ()
		self.startPos = self.mapToScene ( event.pos () )
		self.pressed = True
		button = event.button ()
		modifiers = event.modifiers ()
		
		if ( button == QtCore.Qt.MidButton or ( button == QtCore.Qt.LeftButton and modifiers == QtCore.Qt.ShiftModifier ) ) :
			self.state = 'pan'
			return
		if button == QtCore.Qt.RightButton and modifiers == QtCore.Qt.ShiftModifier :
			self.state = 'zoom'
			return
		QtModule.QGraphicsView.mousePressEvent ( self, event )
	#
	# mouseDoubleClickEvent
	#
	def mouseDoubleClickEvent ( self, event ) :
		#
		#print ">> WorkArea.mouseDoubleClickEvent"
		selected = self.scene ().selectedItems ()

		QtModule.QGraphicsView.mouseDoubleClickEvent ( self, event )
	#
	# mouseMoveEvent
	#
	def mouseMoveEvent ( self, event ) :
		#print ">> WorkArea.mouseMoveEvent"
		#if self.pressed :
		currentPos = self.mapToScene( event.pos() )
		if self.state == 'pan' :
			deltaPos = currentPos - self.startPos
			self.setInteractive ( False )
			self.translate ( deltaPos.x (), deltaPos.y () )
			self.setInteractive ( True )
		
		elif self.state == 'zoom' :
			#
			import sys, math
			deltaPos = currentPos - self.startPos
			scale = -1.0
			if 'linux' in sys.platform: scale = 1.0
			scaleFactor = math.pow ( 2.0, scale * max ( deltaPos.x (), deltaPos.y () ) / 200.0  ) #
			factor = self.transform ().scale ( scaleFactor, scaleFactor ).mapRect ( QtCore.QRectF( -1, -1, 2, 2 ) ).width ()

			if factor < 0.07 or factor > 100: return
			# update view matrix
			self.setInteractive ( False )
			self.scale ( scaleFactor, scaleFactor )
			self.translate ( -deltaPos.x () * scaleFactor, -deltaPos.y () * scaleFactor )
			self.setInteractive ( True )
			#self.startPos = currentPos
		else :
			QtModule.QGraphicsView.mouseMoveEvent ( self, event )
	#
	# mouseReleaseEvent
	#
	def mouseReleaseEvent ( self, event ) :
		#print ">> WorkArea.mouseReleaseEvent"
		if self.state in [ 'pan', 'zoom' ] :
			self.state = 'idle'
			self.startPos = None
			self.pressed = False
		QtModule.QGraphicsView.mouseReleaseEvent ( self, event )
	#
	# resetZoom
	#
	def resetZoom ( self ) :
		#
		if DEBUG_MODE : print ( ">> WorkArea.resetZoom" )
		self.setInteractive ( False )
		self.resetTransform()
		self.centerOn ( 0.0, 0.0 )
		self.setInteractive ( True )
	#
	# viewportEvent
	#
	def viewportEvent ( self, event ) :
		#case QEvent::TouchBegin:
		# case QEvent::TouchUpdate:
		# case QEvent::TouchEnd:
		if event.type() == QtCore.QEvent.TouchBegin :
			if DEBUG_MODE : print ( ">> WorkArea.QEvent.TouchBegin" )
		return QtModule.QGraphicsView.viewportEvent ( self, event )
	#
	# deselectAllNodes
	#
	def deselectAllNodes ( self ) :
		selected = self.scene().selectedItems()
		for item in selected : item.setSelected ( False )
	#
	# openNodeNet
	#
	def openNodeNet ( self, filename, pos = None ) :
		#
		( nodes, links ) = self.nodeNet.open ( normPath ( filename ) )
		for node in nodes : self.addGfxNode ( node )
		for link in links : self.addGfxLink ( link )
	#
	# insertNodeNet
	#
	# Called by signal 'addNode'
	def insertNodeNet ( self, filename, pos = None ) :
		#
		if DEBUG_MODE : print ( '>> WorkArea.insertNodeNet filename = ' + filename )
		if DEBUG_MODE : print ( ">> WorkArea.insertNodeNet (before) nodes = %d links = %d" % ( len(self.nodeNet.nodes.values()), len(self.nodeNet.links.values()) ) )
		( nodes, links ) = self.nodeNet.insert ( normPath ( filename ) )

		if pos == None :
			# on dblclk -- insert node at left border of sceneBound
			sceneBound = self.scene().itemsBoundingRect ()
			if not sceneBound.isNull () :
				x_offset = sceneBound.x() - self.minGap
				pos = QtCore.QPointF ( x_offset, 0 )

		self.deselectAllNodes ()

		for node in nodes : self.addGfxNode ( node, pos )
		for link in links : self.addGfxLink ( link )

		if DEBUG_MODE : print ( '>> WorkArea.insertNodeNet (after) nodes = %d links = %d' % ( len ( self.nodeNet.nodes.values ()), len ( self.nodeNet.links.values () ) ) )
	#
	# copyNodes
	#
	def copyNodes ( self, clipboard, cutNodes = False ) :
		#
		if DEBUG_MODE : print ( '>> WorkArea.copyNodes ( cutNodes = %s )'  % str ( cutNodes ) )
		
		dupNodeNet = NodeNetwork ( 'clipboard' )
		
		for gfxNode in self.selectedNodes :
			dupNode = gfxNode.node.copy ()
			dupNodeNet.addNode ( dupNode )
			
		for gfxNode in self.selectedNodes :
			for link in gfxNode.node.getInputLinks () :
				#link.printInfo ()
				dupLink = link.copy ()
				dupDstNode = dupNodeNet.getNodeByID ( gfxNode.node.id )

				if dupDstNode is not None :
					dupDstParam = dupDstNode.getInputParamByName ( link.dstParam.name ) 
					dupLink.setDst ( dupDstNode, dupDstParam )
					
					( srcNode, srcParam ) = dupLink.getSrc ()
					dupSrcNode = dupNodeNet.getNodeByID ( srcNode.id )
					
					if dupSrcNode is not None :
						# if srcNode is inside dupNodeNet 
						dupSrcParam = dupSrcNode.getOutputParamByName ( srcParam.name )
						dupLink.setSrc ( dupSrcNode, dupSrcParam )
						dupNodeNet.addLink ( dupLink ) 
						
			
		dom = QtXml.QDomDocument ( dupNodeNet.name )
		dupNodeNet.parseToXML ( dom )
		
		clipboard.clear ()
		clipboard.setText ( dom.toString () ) # .	fromUtf16 () .fromUtf8 () encode( 'utf-8' ) unicode ( dom.toByteArray () ) toString ()
		
		if cutNodes : self.removeSelected ()
	#
	# pasteNodes
	#
	def pasteNodes ( self, clipboard ) :
		#
		if DEBUG_MODE : print ( '>> WorkArea.pasteNodes ...' )
		nodes = []
		links = []
		
		dom = QtXml.QDomDocument ( 'clipboard' )
		dom.setContent ( clipboard.text () ) 
		root = dom.documentElement ()
		if root.nodeName () == 'node' :
			nodes.append ( self.nodeNet.addNodeFromXML ( root ) )
			self.nodeNet.correct_id ( nodes, links )
		elif root.nodeName () == 'nodenet' :
			#print ':: parsing nodenet from XML ...'
			nodeNet = NodeNetwork ( 'tmp', root )
			( nodes, links ) = self.nodeNet.add ( nodeNet )
		else :
			print '!! unknown XML document format'
			return
			
		offsetPos = QtCore.QPointF ( self.minGap, self.minGap / 2 )
		self.deselectAllNodes ()

		for node in nodes : self.addGfxNode ( node, offsetPos )
		for link in links : self.addGfxLink ( link )
	#
	# duplicateNodes
	#
	def duplicateNodes ( self, preserveLinks = False ) :
		#
		if DEBUG_MODE : print ( '>> WorkArea.duplicateNode ( preserveLinks = %s )'  % str ( preserveLinks ) )
		
		dupNodeNet = NodeNetwork ( 'duplicate' )
		
		for gfxNode in self.selectedNodes :
			dupNode = gfxNode.node.copy ()
			dupNodeNet.addNode ( dupNode )
			
		
		for gfxNode in self.selectedNodes :
			for link in gfxNode.node.getInputLinks () :
				#link.printInfo ()
				dupLink = link.copy ()
				dupDstNode = dupNodeNet.getNodeByID ( gfxNode.node.id )

				if dupDstNode is not None :
					dupDstParam = dupDstNode.getInputParamByName ( link.dstParam.name ) 
					dupLink.setDst ( dupDstNode, dupDstParam )
					
					( srcNode, srcParam ) = dupLink.getSrc ()
					dupSrcNode = dupNodeNet.getNodeByID ( srcNode.id )
					
					if dupSrcNode is not None :
						# if srcNode is inside dupNodeNet 
						dupSrcParam = dupSrcNode.getOutputParamByName ( srcParam.name )
						dupLink.setSrc ( dupSrcNode, dupSrcParam )
						dupNodeNet.addLink ( dupLink ) 
					else :
						# if this is outside links
						if preserveLinks :
							dupNodeNet.addLink ( dupLink ) 
						else :
							dupLink.setSrc ( None, None )  
							dupLink.setDst ( None, None )    

		#if DEBUG_MODE : dupNodeNet.printInfo ()
		( nodes, links ) = self.nodeNet.add ( dupNodeNet )

		offsetPos = QtCore.QPointF ( self.minGap, self.minGap / 2 )

		self.deselectAllNodes ()

		for node in nodes : self.addGfxNode ( node, offsetPos )
		for link in links : self.addGfxLink ( link )
	#
	# newNodeNetFromList
	#
	def nodeNetFromSelected ( self, nodeNetName, preserveLinks = False ) :
		#
		if DEBUG_MODE : print ( '>> WorkArea.nodeNetFromSelected ( preserveLinks = %s )'  % str ( preserveLinks ) )
		dupNodeNet = NodeNetwork ( nodeNetName )
		
		for gfxNode in self.selectedNodes :
			dupNode = gfxNode.node.copy ()
			dupNodeNet.addNode ( dupNode )
			
		
		for gfxNode in self.selectedNodes :
			for link in gfxNode.node.getInputLinks () :
				#link.printInfo ()
				dupLink = link.copy ()
				dupDstNode = dupNodeNet.getNodeByID ( gfxNode.node.id )

				if dupDstNode is not None :
					dupDstParam = dupDstNode.getInputParamByName ( link.dstParam.name ) 
					dupLink.setDst ( dupDstNode, dupDstParam )
					
					( srcNode, srcParam ) = dupLink.getSrc ()
					dupSrcNode = dupNodeNet.getNodeByID ( srcNode.id )
					
					if dupSrcNode is not None :
						# if srcNode is inside dupNodeNet 
						dupSrcParam = dupSrcNode.getOutputParamByName ( srcParam.name )
						dupLink.setSrc ( dupSrcNode, dupSrcParam )
						dupNodeNet.addLink ( dupLink ) 
					else :
						# if this is outside links
						if preserveLinks :
							dupNodeNet.addLink ( dupLink ) 
						else :
							dupLink.setSrc ( None, None )  
							dupLink.setDst ( None, None )    
							
		return dupNodeNet          
Beispiel #32
0
class ParamWidget ( QtModule.QWidget ) :
	#
	# __init__
	#
	def __init__ ( self, param, gfxNode, ignoreSubtype = False ) :
		#
		QtModule.QWidget.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.nodeParamRemoved = Signal ()
			#
		self.param = param
		self.gfxNode = gfxNode
		self.ignoreSubtype = ignoreSubtype # if widget is used in NodeEditor, then ignoreSubtype = True

		self.buildGeneralGui ()
		self.buildGui ()
		self.ui.updateGui ( self.param.value )
		#self.connectSignals ()
		#self.connect( self.param, QtCore.SIGNAL( 'paramChanged(QObject)' ), self.onParamChanged )
		#if DEBUG_MODE : print ">> ParamWidget (%s.%s)  __init__" % ( self.gfxNode.node.label, self.param.label )
	#
	#  __del__
	#
	def __del__ ( self ) :
		#
		if DEBUG_MODE : print ( '>> ParamWidget( %s ).__del__ ' % self.param.name )
	#
	# connectSignals
	#
	def connectSignals ( self ) :
		#
		pass
	#
	# setEnabled
	#
	def setEnabled ( self, enabled = True ) :
		#
		for hl in self.param_vl.children () :
			for i in range ( hl.count () ) :
				obj = hl.itemAt ( i ).widget ()
				if obj is not None :
					obj.setEnabled ( enabled )
	#
	# onParamChanged
	#
	def onParamChanged ( self, param ) :
		#
		if DEBUG_MODE : print ( ">> ParamWidget( %s ).onParamChanged" % param.name )
		self.ui.disconnectSignals ( self )
		self.ui.updateGui ( self.param.value )
		self.ui.connectSignals ( self )
		#self.emit ( QtCore.SIGNAL( 'onParamChanged(QObject)' ), param )
	#
	# buildGeneralGui
	#
	def buildGeneralGui ( self ) :
		#if DEBUG_MODE : print ">> ParamWidget buildGeneralGui"
		
		self.label_vl = QtModule.QVBoxLayout ()
		self.label_vl.setSpacing ( UI.SPACING )
		self.label_vl.setContentsMargins ( 0, 0, 0, 0 )
		self.label_vl.setAlignment ( QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft )
		
		
		self.hl = QtModule.QHBoxLayout ()
		self.hl.setSpacing ( UI.SPACING )
		self.hl.setContentsMargins ( 0, 0, 0, 0 )
		self.hl.setAlignment ( QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft )
		
		# vertical layout for parametrs values (e.g. output links or matrix rows)
		self.param_vl = QtModule.QVBoxLayout ()
		self.param_vl.setSpacing ( UI.SPACING )
		self.param_vl.setContentsMargins ( 0, 0, 0, 0 )
		self.param_vl.setAlignment ( QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft )
		#
		# add 'isShaderParam' check box only for RSL nodes
		#
		if self.gfxNode is not None :
			#
			# add "Use as Shader parameter" checkbox
			#
			#if ( self.gfxNode.node.type in VALID_RSL_NODE_TYPES ) and ( self.param.type in VALID_RSL_PARAM_TYPES ) and ( self.param.provider != 'attribute' ) :
			if ( self.gfxNode.node.format == 'rsl' ) and \
				( self.param.type in VALID_RSL_PARAM_TYPES ) and \
				( self.param.provider != 'attribute' ) :
				self.check = QtModule.QCheckBox ( self )
				self.check.setMinimumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )
				self.check.setMaximumSize ( QtCore.QSize ( UI.CHECK_WIDTH, UI.HEIGHT ) )
				self.check.setToolTip ( 'Use as Shader parameter' )
				self.check.setChecked ( self.param.shaderParam )
				if  usePyQt4 :
					self.connect ( self.check, QtCore.SIGNAL ( 'stateChanged(int)' ), self.onShaderParamChanged )
				else :
					self.check.stateChanged.connect ( self.onShaderParamChanged )
				self.hl.addWidget ( self.check )
			else :
				spacer = QtModule.QSpacerItem ( UI.LT_SPACE, UI.HEIGHT, QtModule.QSizePolicy.Minimum, QtModule.QSizePolicy.Minimum )
				self.hl.addItem ( spacer )
			#
			# add 'remove' button for removable parameters
			#
			if self.param.removable :
				self.removeButton = QtModule.QToolButton ( self )
				sizePolicy = QtModule.QSizePolicy ( QtModule.QSizePolicy.Fixed, QtModule.QSizePolicy.Fixed )
				sizePolicy.setHorizontalStretch ( 20 )
				sizePolicy.setVerticalStretch ( 20 )
				sizePolicy.setHeightForWidth ( self.removeButton.sizePolicy().hasHeightForWidth() )
				self.removeButton.setSizePolicy ( sizePolicy )
				self.removeButton.setMaximumSize ( QtCore.QSize ( 20, 20 ) )
				icon = QtGui.QIcon ()
				icon.addPixmap ( QtGui.QPixmap ( ':/edit_icons/resources/del_list.png' ), QtGui.QIcon.Normal, QtGui.QIcon.On )
				self.removeButton.setIcon ( icon )
				self.removeButton.setAutoRaise ( True )
				self.removeButton.setToolTip ( 'Remove parameter' )
				self.removeButton.setIconSize ( QtCore.QSize ( 16, 16 ) )
				self.removeButton.setObjectName ( 'removeButton' )
				self.hl.addWidget ( self.removeButton )
				if usePyQt4 :
					QtCore.QObject.connect ( self.removeButton, QtCore.SIGNAL ( 'clicked()' ), self.onRemoveItem )
				else :
					self.removeButton.clicked.connect ( self.onRemoveItem )

		self.label = ParamLabel ( self, self.param )
		
		self.helpMark = QtModule.QLabel ( self )
		palette = QtGui.QPalette ()
		palette.setColor ( QtGui.QPalette.WindowText, QtGui.QColor ( 0, 140, 0 ) )
		font1 = QtGui.QFont ()
		font1.setBold ( True )
		self.helpMark.setPalette ( palette )
		self.helpMark.setFont ( font1 )
		self.helpMark.setText ( '' )
		
		self.helpMark.setMinimumSize ( QtCore.QSize ( 6, UI.HEIGHT ) )
		self.helpMark.setMaximumSize ( QtCore.QSize ( 6, UI.HEIGHT ) )
		
		self.helpMark.setEnabled ( False )
		
		if self.param.help is not None and self.param.help != '' :
			self.label.setWhatsThis ( self.param.help )
			self.helpMark.setWhatsThis ( self.param.help )
			self.helpMark.setText ( '?' )
			self.helpMark.setEnabled ( True )
		
		self.label.setAlignment ( QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter )
		#self.label.setMinimumSize ( QtCore.QSize ( UI.LABEL_WIDTH, UI.HEIGHT ) )
		#self.label.setMaximumSize ( QtCore.QSize ( UI.LABEL_WIDTH, UI.HEIGHT ) )
		
		#self.vl.addWidget ( self.gui )
		self.hl.addWidget ( self.label )
		self.hl.addWidget ( self.helpMark )
		#self.hl.addLayout ( self.param_vl )
		#sp = QtModule.QSpacerItem ( 20, 20, QtModule.QSizePolicy.Expanding, QtModule.QSizePolicy.Minimum )
		
		self.label_vl.addLayout ( self.hl )
		sp_v = QtModule.QSpacerItem ( 0, 0, QtModule.QSizePolicy.Minimum, QtModule.QSizePolicy.Expanding )
		self.label_vl.addItem ( sp_v )
		
	#
	# onShaderParamChanged
	#
	def onShaderParamChanged ( self, value ) :
		#
		self.param.shaderParam = self.check.isChecked ()
		self.gfxNode.updateGfxNodeParams ( True )
	#
	# buildGui -- virtual method
	# should be overriden in inherited classes
	#
	def buildGui ( self ) :
		#
		pass
		#spacer = QtModule.QSpacerItem ( 20, 20, QtModule.QSizePolicy.Expanding, QtModule.QSizePolicy.Minimum )
		#self.hl.addItem ( spacer )
	#
	# onRemoveItem
	#
	def onRemoveItem ( self ) : 
		#
		if DEBUG_MODE : print '>> ParamWidget( %s ).onRemoveItem ' % self.param.name
		if usePyQt4 :   
			self.emit ( QtCore.SIGNAL ( 'nodeParamRemoved' ), self.param ) 
		else :
			self.nodeParamRemoved.emit ( self.param ) 
Beispiel #33
0
class NodeParamView ( QtModule.QWidget ) :
	#
	# __init__
	#
	def __init__ ( self ) :
		#
		QtModule.QWidget.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.nodeParamChangedSignal = Signal ()
			self.nodeLabelChangedSignal = Signal ()
			#
		self.gfxNode = None
		
		self.inputParamListTab = None
		self.outputParamListTab = None
		
		self.showConnected = False
		self.buildGui ()
		self.updateGui ()
		self.connectSignals ()
	#
	# setNode
	#
	def setNode ( self, gfxNode ) :
		#
		#if DEBUG_MODE : print ">> NodeParamView.setNode"
		self.disconnectParamSignals ()
		self.gfxNode = gfxNode
		self.inputParamListTab.setNode ( gfxNode )
		self.outputParamListTab.setNode ( gfxNode )
		self.nameEdit.setEnabled ( self.gfxNode is not None )
		self.updateGui ()
		self.connectParamSignals ()
	#
	# connectSignals
	#
	def connectSignals ( self ) :
		#
		if usePyQt4 :
			self.connect ( self.nameEdit, QtCore.SIGNAL ( 'editingFinished()' ), self.nodeLabelChanged )
			self.connect ( self.showConnectButton, QtCore.SIGNAL ( 'toggled(bool)' ), self.showConnections )
		else :
			self.nameEdit.editingFinished.connect ( self.nodeLabelChanged )
			self.showConnectButton.toggled.connect ( self.showConnections )
	#
	# disconnectSignals
	#
	def disconnectSignals ( self ) :
		#
		if usePyQt4 :
			self.disconnect ( self.nameEdit, QtCore.SIGNAL ( 'editingFinished()' ), self.nodeLabelChanged )
			self.disconnect ( self.showConnectButton, QtCore.SIGNAL ( 'toggled(bool)' ), self.showConnections )
		else :
			self.nameEdit.editingFinished.disconnect ( self.nodeLabelChanged )
			self.showConnectButton.toggled.disconnect ( self.showConnections )
	#
	# connectParamSignals
	#
	def connectParamSignals ( self ) :
		#print ">> NodeParamView.connectParamSignals"
		if self.gfxNode is not None :
			for inputParam in self.gfxNode.node.inputParams :
				if usePyQt4 :
					self.connect ( inputParam, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamChanged )
				else :
					inputParam.paramChangedSignal.connect ( self.onParamChanged )
			for outputParam in self.gfxNode.node.outputParams :
				if usePyQt4 :
					self.connect ( outputParam, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamChanged )
				else :
					outputParam.paramChangedSignal.connect ( self.onParamChanged )
	#
	# disconnectParamSignals
	#
	def disconnectParamSignals ( self ) :
		#print ">> NodeParamView.disconnectParamSignals"
		if self.gfxNode is not None :
			for inputParam in self.gfxNode.node.inputParams :
				if usePyQt4 :
					self.disconnect ( inputParam, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamChanged )
				else :
					inputParam.paramChangedSignal.disconnect ( self.onParamChanged )
			for outputParam in self.gfxNode.node.outputParams :
				if usePyQt4 :
					self.disconnect ( outputParam, QtCore.SIGNAL ( 'paramChangedSignal(QObject)' ), self.onParamChanged )
				else :
					outputParam.paramChangedSignal.disconnect ( self.onParamChanged )
	#
	# showConnections
	#
	def showConnections ( self, show ) :
		#
		print ">> NodeParamView.showConnections %s" % show
		self.showConnected = show
		self.inputParamListTab.showConnected = show
		self.outputParamListTab.showConnected = show
		self.inputParamListTab.updateGui ()
		self.outputParamListTab.updateGui ()
	#
	# onParamChanged
	#
	def onParamChanged ( self, param ) :
		#
		if DEBUG_MODE : print ( ">> NodeParamView.onParamChanged node = %s param = %s" % ( self.gfxNode.node.label, param.name ) )
		if usePyQt4 :
			self.emit ( QtCore.SIGNAL ( 'nodeParamChangedSignal' ), self.gfxNode, param ) # .node
		else :
			self.nodeParamChangedSignal.emit ( self.gfxNode, param ) # .node
	#
	# nodeLabelChanged
	#
	def nodeLabelChanged ( self ) :
		#
		#if DEBUG_MODE : print ">> NodeParamView.nodeLabelChanged"
		if self.gfxNode is not None :
			from core.meCommon import getParsedLabel
			newLabel = getParsedLabel ( self.nameEdit.text () )
			#if DEBUG_MODE : print "** newLabel = %s" % newLabel
			if newLabel != '' :
				# update label only if realy changed
				if newLabel != self.gfxNode.node.label :
					# rename node label if same name exists in NodeNet
					if usePyQt4 :
						self.emit ( QtCore.SIGNAL ( 'nodeLabelChangedSignal' ), self.gfxNode, newLabel )
					else :
						self.nodeLabelChangedSignal.emit ( self.gfxNode, newLabel )
					self.nameEdit.clear ()
			self.nameEdit.setText ( self.gfxNode.node.label )
	#
	# buildGui
	#
	def buildGui ( self ) :
		#
		label = QtModule.QLabel ()
		label.setMinimumSize ( QtCore.QSize ( UI.NODE_LABEL_WIDTH, UI.HEIGHT ) )
		label.setMaximumSize ( QtCore.QSize ( UI.NODE_LABEL_WIDTH, UI.HEIGHT ) )

		font = QtGui.QFont ()
		label.setFont ( font )
		#label.setAlignment(QtCore.Qt.AlignCenter)
		label.setText ( 'Label' )

		self.nameEdit = QtModule.QLineEdit ()
		self.nameEdit.setMaximumSize ( QtCore.QSize ( UI.MAX, UI.HEIGHT ) )
		self.nameEdit.setEnabled ( False )
		
		self.showConnectButton = QtModule.QToolButton ( self )
		sizePolicy = QtModule.QSizePolicy ( QtModule.QSizePolicy.Fixed, QtModule.QSizePolicy.Fixed )
		sizePolicy.setHorizontalStretch ( 20 )
		sizePolicy.setVerticalStretch ( 20 )
		sizePolicy.setHeightForWidth ( self.showConnectButton.sizePolicy().hasHeightForWidth() )
		self.showConnectButton.setSizePolicy ( sizePolicy )
		self.showConnectButton.setMaximumSize ( QtCore.QSize ( 20, 20 ) )
		icon = QtGui.QIcon ()
		icon.addPixmap ( QtGui.QPixmap ( ':/show_icons/resources/show_connect.png' ), QtGui.QIcon.Normal, QtGui.QIcon.On )
		self.showConnectButton.setIcon ( icon )
		self.showConnectButton.setAutoRaise ( False )
		self.showConnectButton.setCheckable ( True )
		self.showConnectButton.setChecked ( self.showConnected ) 
		self.showConnectButton.setToolTip ( 'Show connected parameters' )
		#self.showConnectButton.setIconSize ( QtCore.QSize ( 16, 16 ) )
		self.showConnectButton.setObjectName ( 'showConnectButton' )

		headerLayout = QtModule.QHBoxLayout ()
		headerLayout.setSpacing ( UI.SPACING )
		headerLayout.setContentsMargins ( UI.SPACING, UI.SPACING, UI.SPACING, UI.SPACING )
		headerLayout.setStretch ( 1, 1 )

		headerLayout.addWidget ( label )
		headerLayout.addWidget ( self.nameEdit )
		headerLayout.addWidget ( self.showConnectButton )

		mainLayout = QtModule.QVBoxLayout ()
		mainLayout.addLayout ( headerLayout )
		
		self.params_tabs = QtModule.QTabWidget ( self )
		
		self.inputParamListTab = NodeParamListTab ( self, self.gfxNode, isInput = True, showConnected = self.showConnected )
		self.params_tabs.addTab ( self.inputParamListTab, 'Input' )
		
		self.outputParamListTab = NodeParamListTab ( self, self.gfxNode, isInput = False, showConnected = self.showConnected )
		self.params_tabs.addTab ( self.outputParamListTab, 'Output' )
		
		self.params_tabs.setCurrentIndex ( 0 )
		
		mainLayout.addWidget ( self.params_tabs )
		
		self.setLayout ( mainLayout )
	#
	# updateGui
	#
	def updateGui ( self ) :
		#
		#if DEBUG_MODE : print '>> NodeParamView.updateGui'
			
		self.nameEdit.clear ()
		if self.gfxNode is not None :
			self.nameEdit.setText ( self.gfxNode.node.label )
		
		self.inputParamListTab.updateGui ()
		self.outputParamListTab.updateGui ()
		
Beispiel #34
0
	def __init__ ( self ) :
		#
		QtModule.QGraphicsView.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.selectNodes = Signal () #( list, list )
			self.nodeConnectionChanged = Signal () #QtCore.pyqtSignal ( QtModule.QGraphicsObject, QtCore.QObject )

			self.gfxNodeAdded = Signal () #( QtModule.QGraphicsObject )
			self.gfxNodeRemoved = Signal () #( QtModule.QGraphicsObject )
			#
		self.drawGrid = True
		self.gridSnap = False
		self.straightLinks = False
		self.reverseFlow = False

		self.gridSize = 10
		self.minGap = 120
		self.current_Z = 1

		self.state = 'idle'
		self.pressed = False
		self.startPos = None

		self.lastConnectCandidate = None
		self.currentGfxLink = None

		self.inspectedNode = None
		self.nodeNet = None

		self.selectedNodes = []
		self.selectedLinks = []

		# set scene
		scene = WorkAreaScene ( self )

		scene.setSceneRect ( -10000, -10000, 20000, 20000 )
		#scene.setItemIndexMethod ( QtGui.QGraphicsScene.NoIndex )
		self.setScene ( scene )

		# qt graphics stuff
		self.setCacheMode ( QtModule.QGraphicsView.CacheBackground )
		self.setRenderHint ( QtGui.QPainter.Antialiasing )

		self.setTransformationAnchor ( QtModule.QGraphicsView.AnchorUnderMouse ) # QtGui.QGraphicsView.AnchorUnderMouse
		self.setResizeAnchor ( QtModule.QGraphicsView.AnchorUnderMouse )  # AnchorViewCenter
		self.setDragMode ( QtModule.QGraphicsView.RubberBandDrag )

		self.setMouseTracking ( False )
		self.setAcceptDrops ( True )
		"""
		viewport = self.viewport()
		if viewport is not None :
			print ">> WorkArea viewport.setAcceptTouchEvents"
			#proxy = QtGui.QGraphicsProxyWidget ()
			proxy = viewport.graphicsProxyWidget ()
			if proxy is not None :
				proxy.setAcceptTouchEvents ( True )

			#self.setAttribute ( QtGui.AcceptTouchEvents, True )
			#viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
			#setDragMode(ScrollHandDrag);
			#Qt::WA_AcceptTouchEvents
		"""
		self.viewBrush = QtGui.QBrush ( QtGui.QColor ( 148, 148, 148 ) )
		self.setBackgroundBrush ( self.viewBrush )

		# self.connectSignals ()




		if DEBUG_MODE : print ">> WorkArea. __init__"
Beispiel #35
0
class Node ( QtCore.QObject ) :
	#
	id = 0
	#
	# __init__
	#
	def __init__ ( self, xml_node = None, nodenet = None ) :
		#
		QtCore.QObject.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.nodeUpdated = Signal () # QtCore.pyqtSignal ( [QtCore.QObject] )
			self.nodeParamsUpdated = Signal () #QtCore.pyqtSignal ( [QtCore.QObject] )
			#
		self.id = None
		self.name = None
		self.label = None
		self.type = None
		
		self.version = None
		self.format = None
		self.parent = None
		self.dirty = False

		self.author = None
		self.help = None
		self.icon = None

		self.master = None

		self.code = None            # Node code (RSL, RIB, ... )
		self.control_code = None    # python code executed before node computation
		self.computed_code = None   # code collected after compute on all connected nodes
		
		self.event_code = {}
		#self.event_code [ 'ParamLabelRenamed' ] = None
		#self.event_code [ 'ParamAdded' ] = None
		#self.event_code [ 'ParamRemoved' ] = None

		self.display = True

		self.computedInputParams = None
		self.computedOutputParams = None
		self.computedLocalParams = None
		self.computedIncludes = None
		self.computedLocals = None
		self.computedCode = None

		#self.previewCode = None

		self.inputParams = []
		self.outputParams = []
		self.internals = []
		self.includes = []

		self.inputLinks = {}
		self.outputLinks = {}

		self.childs = set()

		self.nodenet = nodenet

		# position from GfxNode
		self.offset = ( 0, 0 )

		if xml_node != None :
			self.parseFromXML ( xml_node )
	#
	# __del__
	#
	def __del__ ( self ) :
		#
		if DEBUG_MODE : print ( '>> Node( %s ).__del__' % self.label )
	#
	# build
	#
	@classmethod
	def build ( cls ) :
		# set unique id while building
		node = cls ()
		Node.id += 1
		node.id = Node.id
		return node
	#
	# copy
	#
	def copy ( self ) : assert 0, 'copy needs to be implemented!'
	#
	# updateNode
	#
	def updateNode ( self, emit_signal = False ) : 
		#
		if DEBUG_MODE : print ( '>> Node( %s ).updateNode' % self.label  ), emit_signal
		if emit_signal :
			if DEBUG_MODE : print ( '** emit signal nodeUpdated' )
			if usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'nodeUpdated' ), self )
			else :
				self.nodeUpdated.emit ( self )
	#
	# updateNodeParams
	#
	def updateNodeParams ( self, emit_signal = False ) : 
		#
		if DEBUG_MODE : print ( '>> Node( %s ).updateNodeParams' % self.label ), emit_signal
		if emit_signal :
			if usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'nodeParamsUpdated' ), self )
			else :
				self.nodeParamsUpdated.emit ( self )
	#
	# addChild
	#
	def addChild ( self, node ) : self.childs.add ( node )
	#
	# removeChild
	#
	def removeChild ( self, node ) :
		#
		if node in self.childs :
			self.childs.remove ( node )
			if DEBUG_MODE : print ( '** Node(%s).removeChild %s' % ( self.label, node.label ) )
		else :
			if DEBUG_MODE : print ( '!! Node(%s).removeChild child %s is not in the list' % ( self.label, node.label ) )
	#
	# printInfo
	#
	def printInfo ( self ) :
		#
		print ( ':: Node (id = %d) label = %s' % ( self.id, self.label ) )
		print ( '** Node inputLinks:' )
		for param in self.inputLinks.keys () :
			print ( '\t* param: %s (%s) linked to ' % ( param.name, param.label ) )
			self.inputLinks [ param ].printInfo ()
		print ( '** Node outputLinks:' )
		#print '*****', self.outputLinks
		for param in self.outputLinks.keys () :
			print ( '\t* param: %s (%s) linked to ' % ( param.name, param.label ) )
			linklist = self.outputLinks [ param ]
			for link in linklist :
				link.printInfo ()
		print ( '** Node children:' )
		for child in self.childs :
			print ( '\t* %s' % child.label )
	#
	# addInputParam
	#
	def addInputParam ( self, param ) :
		#
		param.isInput = True
		# to be sure that name and label is unique
		if param.name in self.getParamsNames () : self.renameParamName ( param, param.name )
		if param.label in self.getParamsLabels () : self.renameParamLabel ( param, param.label )
		self.inputParams.append ( param )
		if self.event_code :
			if 'ParamAdded' in self.event_code.keys () :
				exec ( self.event_code [ 'ParamAdded' ], { 'param' : param, 'self' : self } )
	#
	# addOutputParam
	#
	def addOutputParam ( self, param ) :
		#
		param.isInput = False
		# to be sure that name and label is unique
		if param.name in self.getParamsNames () : self.renameParamName ( param, param.name )
		if param.label in self.getParamsLabels () : self.renameParamLabel ( param, param.label )
		self.outputParams.append ( param )
		if self.event_code :
			if 'ParamAdded' in self.event_code.keys () :
				exec ( self.event_code [ 'ParamAdded' ], { 'param' : param, 'self' : self } )
	#
	# addInternal
	#
	def addInternal ( self, newName ) :
		#print '--> add internal: %s' % internal
		internal = newName
		if internal != '' :
			from meCommon import getUniqueName
			internal = getUniqueName ( newName, self.internals )
			self.internals.append ( internal )
		return internal
	#
	# addInclude
	#
	def addInclude ( self, newName ) :
		#print '--> add include: %s' % include
		include = newName
		if include != '' :
			from meCommon import getUniqueName
			include = getUniqueName ( newName, self.includes )
			self.includes.append ( include )
		return include
	#
	# attachInputParamToLink
	#
	def attachInputParamToLink ( self, param, link ) :
		#
		self.inputLinks [ param ] = link
	#
	# attachOutputParamToLink
	#
	def attachOutputParamToLink ( self, param, link ) :
		#
		#if DEBUG_MODE : print ">> Node::attachOutputParamToLink param = %s" % param.name
		if not param in self.outputLinks.keys () :
			self.outputLinks [ param ] = []
		if not link in self.outputLinks [ param ] :
			self.outputLinks [ param ].append ( link )
	#
	# detachInputParam
	#
	def detachInputParam ( self, param ) :
		#
		removedLink = None
		if DEBUG_MODE : print ( ">> Node::detachInputParam param = %s" % param.name )
		if param in self.inputLinks.keys () :
			removedLink = self.inputLinks.pop ( param )
		return removedLink
	#
	# detachOutputParam
	#
	def detachOutputParam ( self, param ) :
		#
		removedLinks = []
		if param in self.outputLinks.keys () :
			outputLinks = self.outputLinks [ param ]
			for link in outputLinks :
				removedLinks.append ( link )
			self.outputLinks.pop ( param )
		return removedLinks
	#
	# detachOutputParamFromLink
	#
	def detachOutputParamFromLink ( self, param, link ) :
		#
		removedLink = None
		if param in self.outputLinks.keys () :
			outputLinks = self.outputLinks [ param ]
			if link in outputLinks :
				removedLink = link
				outputLinks.remove ( link )
		return removedLink
	#
	# isInputParamLinked
	#
	def isInputParamLinked ( self, param ) : return param in self.inputLinks.keys ()
	#
	# isOutputParamLinked
	#
	def isOutputParamLinked ( self, param ) : return param in self.outputLinks.keys ()
	#
	# getLinkedSrcNode
	#
	def getLinkedSrcNode ( self, param ) :
		# returns node linked to input parameter param,
		# skipping all ConnectorNode
		#
		#if DEBUG_MODE : print '* getLinkedSrcNode node = %s param = %s' % ( self.label, param.label )
		srcNode = None
		srcParam = None
		if self.isInputParamLinked ( param ) :
			#if DEBUG_MODE : print '* isInputParamLinked'
			link = self.inputLinks [ param ]
			if link.srcNode.type == 'connector' :
				if len ( link.srcNode.inputParams ) :
					firstParam = link.srcNode.inputParams [0]
					( srcNode, srcParam ) = link.srcNode.getLinkedSrcNode ( firstParam )
				else :
					if DEBUG_MODE : print ( '* no inputParams at connector %s' % ( link.srcNode.label ) )
			else :
				srcNode = link.srcNode
				srcParam = link.srcParam
		return ( srcNode, srcParam )
	#
	# getLinkedDstNodes
	#
	def getLinkedDstNodes ( self, param, dstConnections = [] ) :
		# returns nodes linked to output parameter param,
		# skipping all ConnectorNode
		#
		#if DEBUG_MODE : print '*** getLinkedDstNodese node = %s param = %s' % ( self.label, param.label )
		dstNode = None
		dstParam = None
		# dstConnections = []
		if self.isOutputParamLinked ( param ) :
			#if DEBUG_MODE : print '* isOutputParamLinked'
			dstLinks = self.getOutputLinks ( param )
			for link in dstLinks :
				if link.dstNode.type == 'connector' :
					#if DEBUG_MODE : print '* link.dstNode.type == connector'
					connectorOutputParams = link.dstNode.outputParams
					if len ( connectorOutputParams ) > 0 :
						for connectorOutputParam in connectorOutputParams :
							connectorDstConnections = []
							retList = link.dstNode.getLinkedDstNodes ( connectorOutputParam, connectorDstConnections )
							for ( retNode, retParam ) in retList : 
								dstConnections.append ( ( retNode, retParam ) )
					else :
						if DEBUG_MODE : print ( '* no outputParams at connector %s' % ( link.dstNode.label ) )
				else :
					dstNode = link.dstNode
					dstParam = link.dstParam
					dstConnections.append ( ( dstNode, dstParam ) )
		return dstConnections
	#
	# removeParam
	#
	def removeParam ( self, param ) :
		#
		if self.event_code :
			if 'ParamRemoving' in self.event_code.keys () :
				exec ( self.event_code [ 'ParamRemoving' ], { 'param' : param, 'self' : self } )
		
		removedLinks = []
		if param.isInput :
			link = self.detachInputParam ( param )
			if link is not None : removedLinks.append ( link )
			self.inputParams.remove ( param )
		else :
			removedLinks = self.detachOutputParam ( param )
			self.outputParams.remove ( param )
		if self.event_code :
			if 'ParamRemoved' in self.event_code.keys () :
				exec ( self.event_code [ 'ParamRemoved' ], { 'param' : param, 'self' : self } )
		return removedLinks
	#
	# getInputParamByName
	#
	def getInputParamByName ( self, name ) :
		#
		result = None
		for param in self.inputParams :
			if param.name == name :
				result = param
				break
		return result
	#
	# getOutputParamByName
	#
	def getOutputParamByName ( self, name ) :
		#
		result = None
		for param in self.outputParams :
			if param.name == name :
				result = param
				break
		return result
	#
	# getInputParamValueByName
	#
	def getInputParamValueByName ( self, name, CodeOnly = False ) :
		#
		result = None
		srcNode = srcParam = None
		param = self.getInputParamByName ( name )
		( srcNode, srcParam ) = self.getLinkedSrcNode ( param )
		if srcNode is not None :
			# computation may be skipped if we need only value
			#if compute :
			srcNode.computeNode ( CodeOnly )
			if self.computed_code is not None :
				self.computed_code += srcNode.computed_code
			result = srcNode.parseGlobalVars ( srcParam.getValueToStr () )
		else :
			result = param.getValueToStr ()

		return result
	#
	# return common list for input and output parameters
	#
	def getParamsList ( self ) :
		#
		params = self.inputParams + self.outputParams
		return params
	#
	# getParamsNames
	#
	def getParamsNames ( self ) :
		#
		names = []
		for pm in self.getParamsList () : names.append ( pm.name )
		return names
	#
	# getParamsLabels
	#
	def getParamsLabels ( self ) :
		#
		labels = []
		for pm in self.getParamsList () : labels.append ( pm.label )
		return labels
	#
	# getInputLinks
	#
	def getInputLinks ( self ) :
		#
		inputLinks = []
		for link in self.inputLinks.values () :
			inputLinks.append ( link )
		return inputLinks
	#
	# getOutputLinks
	#
	def getOutputLinks ( self, param = None ) :
		#
		outputLinks = []
		for link_list in self.outputLinks.values () :
			for link in link_list :
				if param is not None :
					if link.srcParam != param :
						continue
				outputLinks.append ( link )
		return outputLinks
	#
	# getInputLinkByID
	#
	def getInputLinkByID ( self, id ) :
		#
		result = None
		for link in self.getInputLinks () :
			if link.id == id :
				result = link
				break
		return result
	#
	# getOutputLinkByID
	#
	def getOutputLinkByID ( self, id ) :
		#
		result = None
		for link in self.getOutputLinks () :
			if link.id == id :
				result = link
				break
		return result
	#
	# renameParamName
	#
	def renameParamName ( self, param, newName ) :
		# assign new unique name to param
		from meCommon import getUniqueName
		param.name = getUniqueName ( newName, self.getParamsNames() )
		return param.name
	#
	# renameParamLabel
	#
	def renameParamLabel ( self, param, newLabel ) :
		#
		oldLabel = param.label
		if DEBUG_MODE : print ( ">> Node( %s ).renameParamLabel  oldLabel = %s newLabel = %s" % ( self.label, oldLabel, newLabel ) )
		if newLabel == '' : newLabel = self.param.name
		# assign new unique label to param
		from meCommon import getUniqueName
		param.label = getUniqueName ( newLabel, self.getParamsLabels () )
		if self.event_code :
			if 'ParamLabelRenamed' in self.event_code.keys () :
				exec ( self.event_code [ 'ParamLabelRenamed' ], { 'param' : param, 'self' : self, 'oldLabel' : oldLabel } )
		
		return param.label
	#
	# onParamChanged
	#
	def onParamChanged ( self, param ) :
		#
		if DEBUG_MODE : print ( ">> Node: onParamChanged node = %s param = %s (pass...)" % ( self.label, param.name ) )
		pass
		#self.emit( QtCore.SIGNAL( 'onNodeParamChanged(QObject,QObject)' ), self, param )
	#
	# getLabel
	#
	def getLabel ( self ) : return self.label
	#
	# getName
	#
	def getName ( self ) : return self.name
	#
	# getNodenetName
	#
	def getNodenetName ( self ) : return self.nodenet.getName ()
	#
	# getInstanceName
	#
	def getInstanceName ( self ) : return  getParsedLabel ( self.label )
	#
	# getParamName
	#
	def getParamName ( self, param ) :
		#
		if param.isRibParam  or param.provider == 'attribute':
			paramName = param.name
		elif param.provider == 'primitive' : 
			paramName = getParsedLabel ( param.label )
		else :
			paramName = self.getInstanceName () + '_' + getParsedLabel ( param.label )
		return paramName
	#
	# getParamDeclaration
	#
	def getParamDeclaration ( self, param ) :
		#
		result = ''
		result += param.typeToStr () + ' '
		result += self.getParamName ( param )
		if param.isArray () and not param.isRibParam :
			arraySize = ''
			if param.arraySize > 0 :
				arraySize = str ( param.arraySize )
			result += '[%s]' % arraySize
		result += ' = ' + param.getValueToStr () + ';\n'
		return result
	#
	# parseFromXML
	#
	def parseFromXML ( self, xml_node ) :
		#
		id_node = xml_node.attributes ().namedItem ( 'id' )
		if not id_node.isNull () :
			self.id = int ( id_node.nodeValue () )
		else :
			if DEBUG_MODE : print ( '>> Node::parseFromXML id is None' )

		self.name = str ( xml_node.attributes ().namedItem ( 'name' ).nodeValue () )
		self.label = str ( xml_node.attributes ().namedItem ( 'label' ).nodeValue () )
		if self.label == '' : self.label = self.name
		#print '-> parsing from XML node name= %s label= %s' % ( self.name, self.label )

		self.version = str ( xml_node.attributes ().namedItem ( 'version' ).nodeValue () )
		self.parent = str ( xml_node.attributes ().namedItem ( 'parent' ).nodeValue () )
		self.format = str ( xml_node.attributes ().namedItem ( 'format' ).nodeValue () )
		
		self.author = str ( xml_node.attributes ().namedItem ( 'author' ).nodeValue () )
		self.type = str ( xml_node.attributes ().namedItem ( 'type' ).nodeValue () )
		#
		# try to convert from old format nodes
		#
		if self.version == '' or self.version is None :
			if self.format == '' or self.format is None :
				( self.type, self.format ) = translateOldType ( self.type )
			
		help_tag = xml_node.namedItem ( 'help' )
		if not help_tag.isNull() :
			self.help = help_tag.toElement ().text ()
		self.icon = str ( xml_node.attributes ().namedItem ( 'icon' ).nodeValue () )

		input_tag = xml_node.namedItem ( 'input' )
		if not input_tag.isNull () :
			xml_paramList = input_tag.toElement ().elementsByTagName ( 'property' )
			for i in range ( 0, xml_paramList.length () ) :
				xml_param = xml_paramList.item ( i )
				#
				# some parameters (String, Color, Point, Vector, Normal, Matrix ...)
				# have different string interpretation in RIB
				#
				isRibParam = ( self.format == 'rib' )
				param = createParamFromXml ( xml_param, isRibParam, True ) # #param.isInput = True
				self.addInputParam ( param )

		output_tag = xml_node.namedItem ( 'output' )
		if not output_tag.isNull () :
			xml_paramList = output_tag.toElement ().elementsByTagName ( 'property' )
			for i in range ( 0, xml_paramList.length () ) :
				xml_param = xml_paramList.item ( i )
				#
				# some parameters (Color, Point, Vector, Normal, Matrix ...)
				# have different string interpretation in RIB
				#
				isRibParam = ( self.format == 'rib' )
				param = createParamFromXml ( xml_param, isRibParam, False ) # #param.isInput = False
				self.addOutputParam ( param )

		internal_tag = xml_node.namedItem ( 'internal' )
		if not internal_tag.isNull () :
			xml_internalList = internal_tag.toElement ().elementsByTagName ( 'variable' )
			for i in range ( 0, xml_internalList.length () ) :
				var_tag = xml_internalList.item ( i )
				var = str ( var_tag.attributes ().namedItem ( 'name' ).nodeValue () )
				self.addInternal ( var )

		include_tag = xml_node.namedItem ( 'include' )
		if not include_tag.isNull () :
			xml_includeList = include_tag.toElement ().elementsByTagName ( 'file' )
			for i in range ( 0, xml_includeList.length () ) :
				inc_tag = xml_includeList.item ( i )
				inc = str ( inc_tag.attributes ().namedItem ( 'name' ).nodeValue () )
				self.addInclude ( inc )

		offset_tag = xml_node.namedItem ( 'offset' )
		if not offset_tag.isNull() :
			x = float ( offset_tag.attributes ().namedItem ( 'x' ).nodeValue () )
			y = float ( offset_tag.attributes ().namedItem ( 'y' ).nodeValue () )
			self.offset = ( x, y )

		control_code_tag = xml_node.namedItem ( 'control_code' )
		if not control_code_tag.isNull () :
			code_str = str ( control_code_tag.toElement ().text () )
			if code_str.lstrip () == '' : code_str = None
			self.control_code = code_str
		else :
			# for temp. backward compatibility
			control_code_tag = xml_node.namedItem ( 'param_code' )
			if not control_code_tag.isNull() :
				code_str = str ( control_code_tag.toElement ().text () )
				if code_str.lstrip () == '' : code_str = None
				self.control_code = code_str
				
		code_tag = xml_node.namedItem ( 'code' )
		if not code_tag.isNull () :
			code_str = str ( code_tag.toElement ().text () )
			if code_str.lstrip () == '' : code_str = None
			self.code = code_str
			
		event_code_tag = xml_node.namedItem ( 'event_code' )
		if not event_code_tag.isNull () :
			xml_handlerList = event_code_tag.toElement ().elementsByTagName ( 'handler' )
			for i in range ( 0, xml_handlerList.length () ) :
				handler_tag = xml_handlerList.item ( i )
				handler_name = str ( handler_tag.attributes ().namedItem ( 'name' ).nodeValue () )
				code_str = str ( handler_tag.toElement ().text () ).lstrip ()
				if code_str == '' : code_str = None
				self.event_code [ handler_name ] = code_str
	#
	# parseToXML
	#
	def parseToXML ( self, dom ) :
		#
		xml_node = dom.createElement ( 'node' )
		if DEBUG_MODE : print ( '>> Node::parseToXML (id = %d)' % ( self.id ) )
		if self.id is None :
			if DEBUG_MODE : print ( '>> Node::parseToXML id is None' )
		xml_node.setAttribute ( 'id', str( self.id ) )
		xml_node.setAttribute ( 'name', self.name )
		if self.label != None : xml_node.setAttribute ( 'label', self.label )
		if self.type != None : xml_node.setAttribute ( 'type', self.type )
		if self.author != None : xml_node.setAttribute ( 'author', self.author )
		if self.icon != None : xml_node.setAttribute ( 'icon', self.icon )
			
		if self.version != None : xml_node.setAttribute ( 'version', self.version )
		if self.parent != None : xml_node.setAttribute ( 'parent', self.parent )
		if self.format != None : xml_node.setAttribute ( 'format', self.format )

		if self.help != None :
			# append node help (short description)
			help_tag = dom.createElement ( 'help' )
			help_text = dom.createTextNode ( self.help )
			help_tag.appendChild ( help_text )
			xml_node.appendChild ( help_tag )

		input_tag = dom.createElement ( 'input' )
		for param in self.inputParams :
			#print '--> parsing param to XML: %s ...' % param.name
			input_tag.appendChild ( param.parseToXML ( dom )  )
		xml_node.appendChild ( input_tag )

		output_tag = dom.createElement ( 'output' )
		for param in self.outputParams :
			#print '--> parsing param to XML: %s ...' % param.name
			output_tag.appendChild ( param.parseToXML ( dom )  )
		xml_node.appendChild ( output_tag )

		internal_tag = dom.createElement ( 'internal' )
		for var in self.internals :
			var_tag = dom.createElement( 'variable' )
			var_tag.setAttribute ( 'name', var )
			internal_tag.appendChild ( var_tag )
		xml_node.appendChild ( internal_tag )

		include_tag = dom.createElement ( 'include' )
		for inc in self.includes :
			inc_tag = dom.createElement( 'file' )
			inc_tag.setAttribute ( 'name', inc )
			include_tag.appendChild ( inc_tag )
		xml_node.appendChild ( include_tag )

		if self.control_code != None :
			control_code_tag = dom.createElement ( 'control_code' )
			control_code_data = dom.createCDATASection ( self.control_code )
			control_code_tag.appendChild ( control_code_data )
			xml_node.appendChild ( control_code_tag )

		if self.code != None :
			code_tag = dom.createElement ( 'code' )
			code_data = dom.createCDATASection ( self.code )
			code_tag.appendChild ( code_data )
			xml_node.appendChild ( code_tag )
			
		if self.event_code :
			event_code_tag = dom.createElement ( 'event_code' )
			print ( '*** write event_code' )
			for key in self.event_code.keys () :
				print ( '*** write handler "%s"' % key )
				handler_tag = dom.createElement( 'handler' )
				handler_tag.setAttribute ( 'name', key )
				event_code_tag.appendChild ( handler_tag )
				handler_data = dom.createCDATASection ( self.event_code [ key ] )
				handler_tag.appendChild ( handler_data )
			xml_node.appendChild ( event_code_tag )

		if self.offset != None :
			( x, y ) = self.offset
			offset_tag = dom.createElement ( 'offset' )
			offset_tag.setAttribute ( 'x', str (x) ) # have to use 'str' because PySide throws 
			offset_tag.setAttribute ( 'y', str (y) ) # Overflow error for negative values here
			xml_node.appendChild ( offset_tag )

		return xml_node
	#
	# getHeader
	#
	def getHeader ( self ) : assert 0, 'getHeader needs to be implemented!'

	#
	# getComputedCode
	#
	def getComputedCode ( self, CodeOnly = False ) : assert 0, 'getComputedCode needs to be implemented!'

	#
	# computeNode
	#
	def computeNode ( self, CodeOnly = False ) : assert 0, 'computeNode needs to be implemented!'
	#
	# collectComputed
	#
	def collectComputed ( self, computedCode, visitedNodes, CodeOnly = False ) :
		#
		print ( '>>> Node.collectComputed (empty)' )
	#
	# parseGlobalVars
	#
	def parseGlobalVars ( self, parsedStr ) :
		#
		print ( '>>> Node.parseGlobalVars (empty)' )
	#
	# execControlCode
	#
	def execControlCode ( self ) :
		#
		if self.control_code != None :
			control_code = self.control_code.lstrip ()
			if control_code != '' :
				exec control_code
	#
	# copySetup
	#
	def copySetup ( self, newNode ) :
		#
		if DEBUG_MODE : print ( '>> Node( %s ).copySetup ' % self.label )

		newNode.id = self.id

		name = self.name
		if name is None : name = str ( self.type )

		newNode.name = name

		label = self.label
		if label is None : label = name

		newNode.label  = label
		newNode.type   = self.type
		newNode.author = self.author
		newNode.help   = self.help
		newNode.icon   = self.icon
		newNode.master = self.master
		newNode.display = self.display
		
		newNode.format = self.format
		newNode.parent = self.parent
		newNode.dirty = self.dirty

		newNode.offset = self.offset

		import copy
		newNode.code         = copy.copy ( self.code )
		newNode.control_code = copy.copy ( self.control_code )
		newNode.event_code   = copy.copy ( self.event_code )
		#self.computed_code = None

		newNode.internals = copy.copy ( self.internals )
		newNode.includes  = copy.copy ( self.includes )

		newNode.inputLinks = {}
		newNode.outputLinks = {}

		#newNode.childs = set ()
		print ( '***newNode.childs: ', newNode.childs )
		#newNode.childs = copy.copy ( self.childs )

		newNode.inputParams = []
		for param in self.inputParams : newNode.inputParams.append ( param.copy () )

		newNode.outputParams = []
		for param in self.outputParams : newNode.outputParams.append ( param.copy () )

		return newNode
	#
	# save Node to .xml document
	#
	def save ( self ) :
		#
		result = False
	
		dom = QtXml.QDomDocument ( self.name )
		xml_code = self.parseToXML ( dom )
		dom.appendChild ( xml_code )
		
		file = QFile ( self.master )
		if file.open ( QtCore.QIODevice.WriteOnly ) :
			if file.write ( dom.toByteArray () ) != -1 :
				result = True
		file.close()
		return result
	#
	# getChildrenSet
	#
	def getChildrenSet ( self, children_set = set () ) :
		#
		for node in self.childs :
			children_set = node.getChildrenSet ( children_set )
			children_set.add ( node )
		return children_set  
	#
	# getChildrenList
	#
	def getChildrenList ( self, children_list = [] ) :
		#
		for node in self.childs :
			children_list = node.getChildrenList ( children_list )
			if node not in children_list :
				children_list.append ( node )
			
		return children_list  
Beispiel #36
0
	def __init__ ( self, xml_node = None, nodenet = None ) :
		#
		QtCore.QObject.__init__ ( self )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.nodeUpdated = Signal () # QtCore.pyqtSignal ( [QtCore.QObject] )
			self.nodeParamsUpdated = Signal () #QtCore.pyqtSignal ( [QtCore.QObject] )
			#
		self.id = None
		self.name = None
		self.label = None
		self.type = None
		
		self.version = None
		self.format = None
		self.parent = None
		self.dirty = False

		self.author = None
		self.help = None
		self.icon = None

		self.master = None

		self.code = None            # Node code (RSL, RIB, ... )
		self.control_code = None    # python code executed before node computation
		self.computed_code = None   # code collected after compute on all connected nodes
		
		self.event_code = {}
		#self.event_code [ 'ParamLabelRenamed' ] = None
		#self.event_code [ 'ParamAdded' ] = None
		#self.event_code [ 'ParamRemoved' ] = None

		self.display = True

		self.computedInputParams = None
		self.computedOutputParams = None
		self.computedLocalParams = None
		self.computedIncludes = None
		self.computedLocals = None
		self.computedCode = None

		#self.previewCode = None

		self.inputParams = []
		self.outputParams = []
		self.internals = []
		self.includes = []

		self.inputLinks = {}
		self.outputLinks = {}

		self.childs = set()

		self.nodenet = nodenet

		# position from GfxNode
		self.offset = ( 0, 0 )

		if xml_node != None :
			self.parseFromXML ( xml_node )
Beispiel #37
0
class NodeList ( QtModule.QWidget ) :
	#
	# __init__
	#
	def __init__ ( self, parent ) :
		#
		QtModule.QWidget.__init__ ( self, parent )
		#
		# Define signals for PyQt5
		#
		if usePySide or usePyQt5 :
			#
			self.setActiveNodeList = Signal ()
			self.addNode = Signal ()
			#
		self.nodesLib = ''
		self.nodesDir = ''
		# This is always the same
		self.ui = Ui_nodeList () 
		self.ui.setupUi ( self )
		self.ui.treeView.setDragEnabled ( True )
		#self.ui.treeView.setRootIsDecorated( True )
		self.connectSignals ()
		self.updateGui ()
	#
	# connectSignals
	#
	def connectSignals ( self ) :
		#
		if  usePyQt4 :
			QtCore.QObject.connect ( self.ui.treeView, QtCore.SIGNAL ( "pressed(QModelIndex)" ), self.clicked )
			QtCore.QObject.connect ( self.ui.treeView, QtCore.SIGNAL ( "doubleClicked(QModelIndex)" ), self.doubleClicked )
		else :
			self.ui.treeView.pressed.connect ( self.clicked )
			self.ui.treeView.doubleClicked.connect ( self.doubleClicked )
	#
	# updateGui
	#
	def updateGui ( self ) :
		#
		if self.nodesLib != '' :
			# self.ui.treeView.setupModel( self.nodesLib.model )
			
			self.ui.treeView.reset ()
			self.ui.treeView.setModel ( self.nodesLib.model ) 
			
			self.ui.infoText.clear ()
			#self.ui.infoText.setText( "<i>Node:</i><br /><i>Author:</i><br />" )
	#
	# setLibrary
	#
	def setLibrary ( self, dirName ) :
		#
		self.nodesDir = dirName
		self.nodesLib = NodeLibrary ( dirName )
		self.updateGui()
	#
	# reloadLibrary
	#
	def reloadLibrary ( self ) :
		#
		print '>> NodeList: reloadLibrary' 
		self.nodesLib = NodeLibrary ( self.nodesDir )
		self.updateGui ()
	#
	# clicked
	#
	def clicked ( self, index ) :
		#
		print ">> NodeList::clicked "
		item = self.nodesLib.model.itemFromIndex ( index ) 
		self.showDescription ( item )
		#
		# send signal to MainWindow to help distinguish which nodeList
		# is active for addNode getNode events
		#
		print ">> NodeList::emit setActiveNodeList"
		if  usePyQt4 :
			self.emit ( QtCore.SIGNAL ( "setActiveNodeList" ), self )
		else :
			self.setActiveNodeList.emit ( self )
	#      
	# doubleClicked
	#
	def doubleClicked ( self, index ) :
		#
		print ">> NodeList::doubleClicked "
		item = self.nodesLib.model.itemFromIndex ( index )
		nodeKind = item.whatsThis ()
		
		if nodeKind != 'folder' :
			if  usePyQt4 :
				nodeFilename = item.data ( QtCore.Qt.UserRole + 4 ).toString ()
			else :
				nodeFilename = item.data ( QtCore.Qt.UserRole + 4 )
			
			print ">> NodeList::emit addNode"
			if  usePyQt4 :
				self.emit ( QtCore.SIGNAL ( 'addNode' ), nodeFilename )
			else :
				self.addNode.emit ( nodeFilename )
	#    
	# showDescription
	#
	def showDescription ( self, item ) :
		#
		print ">> NodeList::showDescription "
		import os
		
		nodeName     = item.text ()
		nodeKind     = item.whatsThis ()
		if  usePyQt4 :
			nodeAuthor   = item.data ( QtCore.Qt.UserRole + 1 ).toString ()
			nodeType     = item.data ( QtCore.Qt.UserRole + 2 ).toString ()
			nodeHelp     = item.data ( QtCore.Qt.UserRole + 3 ).toString ()
			nodeFilename = item.data ( QtCore.Qt.UserRole + 4 ).toString ()
			nodeIcon     = item.data ( QtCore.Qt.UserRole + 5 ).toString ()
		else :
			nodeAuthor   = item.data ( QtCore.Qt.UserRole + 1 )
			nodeType     = item.data ( QtCore.Qt.UserRole + 2 )
			nodeHelp     = item.data ( QtCore.Qt.UserRole + 3 )
			nodeFilename = item.data ( QtCore.Qt.UserRole + 4 )
			nodeIcon     = item.data ( QtCore.Qt.UserRole + 5 )
		
		self.ui.infoText.clear ()
		
		description = ''
		
		if nodeKind != 'folder' :
			if nodeIcon != '' :
				iconFileName = os.path.join ( os.path.dirname ( str ( nodeFilename ) ), str ( nodeIcon ) ) 
				print str ( iconFileName )
				description += '<img src="' + iconFileName + '" />'  # width="128" height="128"

			description += "<table>"
			#description += "<tr>"
			#description += "<td align=right>name:</td>"
			#description += "<td><b>" + nodeName + "</b></td>"
			#description += "</tr>"
			#description += "<tr>"
			#description += "<td align=right>type:</td>"
			#description += "<td><b>" + nodeType +"</b></td>"
			#description += "</tr>"
			#description += "<tr>"
			#description += "<td align=right>filename:</td>"
			#description += "<td>" + nodeFilename +"</td>"
			#description += "</tr>"
			description += "<tr>"
			description += "<td align=left>author:</td>"
			description += "<td><i>" + nodeAuthor +"</i></td>"
			description += "</tr>"
			description += "</table><br />"
			
			description += "<br />" + nodeHelp +"</b><br />"
			
			self.ui.infoText.setText ( description )