def createCompt(self, key): self.new_Compt = ComptItem(self, 0, 0, 0, 0, key) self.qGraCompt[key] = self.new_Compt self.new_Compt.setRect(10, 10, 10, 10) self.sceneContainer.addItem(self.new_Compt)
class KineticsWidget(EditorWidgetBase): def __init__(self, plugin, *args): EditorWidgetBase.__init__(self, *args) self.plugin = plugin self.border = 5 self.comptPen = 6 self.iconScale = 1 self.arrowsize = 2 self.defaultComptsize = 5 self.noPositionInfo = True self.xyCord = {} self.reset() self.qGraCompt = {} self.mooseId_GObj = {} self.srcdesConnection = {} self.editor = None def reset(self): # print "reset " self.createdItem = {} # This are created at drawLine self.lineItem_dict = {} self.object2line = defaultdict(list) self.itemignoreZooming = False if hasattr(self, "sceneContainer"): self.sceneContainer.clear() self.sceneContainer = QtGui.QGraphicsScene(self) sceneDim = self.sceneContainer.itemsBoundingRect() # if (sceneDim.width() == 0 and sceneDim.height() == 0): # self.sceneContainer.setSceneRect(0,0,30,30) # else: # elf.sceneContainer.setSceneRect(self.sceneContainer.itemsBoundingRect()) self.sceneContainer.setBackgroundBrush(QColor(230, 220, 219, 120)) def updateModelView(self): self.getMooseObj() if not self.m: # At the time of model building # when we want an empty GraphicView while creating new model, # then remove all the view and add an empty view if hasattr(self, "view") and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) # self.sceneContainer.setSceneRect(-self.width()/2,-self.height()/2,self.width(),self.height()) self.view = GraphicalView(self.modelRoot, self.sceneContainer, self.border, self, self.createdItem) if isinstance(self, kineticEditorWidget): self.view.setRefWidget("editorView") self.view.setAcceptDrops(True) elif isinstance(self, kineticRunWidget): self.view.setRefWidget("runView") self.connect(self.view, QtCore.SIGNAL("dropped"), self.objectEditSlot) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view, 0, 0) else: # Already created Model # maxmium and minimum coordinates of the objects specified in kkit file. # self.mooseObjOntoscene() # self.drawLine_arrow() if hasattr(self, "view") and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) self.view = GraphicalView(self.modelRoot, self.sceneContainer, self.border, self, self.createdItem) if isinstance(self, kineticEditorWidget): # self.getMooseObj() self.mooseObjOntoscene() self.drawLine_arrow() self.view.setRefWidget("editorView") self.view.setAcceptDrops(True) self.connect(self.view, QtCore.SIGNAL("dropped"), self.objectEditSlot) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) elif isinstance(self, kineticRunWidget): self.view.setRefWidget("runView") hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) self.view.fitInView( self.sceneContainer.itemsBoundingRect().x() - 10, self.sceneContainer.itemsBoundingRect().y() - 10, self.sceneContainer.itemsBoundingRect().width() + 20, self.sceneContainer.itemsBoundingRect().height() + 20, Qt.Qt.IgnoreAspectRatio, ) def getMooseObj(self): # This fun call 2 more function # -- setupMeshObj(self.modelRoot), # ----self.meshEntry has [meshEnt] = function: {}, Pool: {} etc # setupItem self.m = wildcardFind(self.modelRoot + "/##[ISA=ChemCompt]") if self.m: self.xmin = 0.0 self.xmax = 1.0 self.ymin = 0.0 self.ymax = 1.0 self.autoCordinatepos = {} self.srcdesConnection = {} # self.meshEntry.clear= {} # Compartment and its members are setup self.meshEntry, self.xmin, self.xmax, self.ymin, self.ymax, self.noPositionInfo = setupMeshObj( self.modelRoot ) self.autocoordinates = False if self.srcdesConnection: self.srcdesConnection.clear() else: self.srcdesConnection = {} setupItem(self.modelRoot, self.srcdesConnection) if not self.noPositionInfo: self.autocoordinates = True self.xmin, self.xmax, self.ymin, self.ymax, self.autoCordinatepos = autoCoordinates( self.meshEntry, self.srcdesConnection ) # TODO: size will be dummy at this point, but size I need the availiable size from the Gui self.size = QtCore.QSize(1000, 550) if self.xmax - self.xmin != 0: self.xratio = (self.size.width() - 10) / (self.xmax - self.xmin) else: self.xratio = self.size.width() - 10 if self.ymax - self.ymin: self.yratio = (self.size.height() - 10) / (self.ymax - self.ymin) else: self.yratio = self.size.height() - 10 self.xratio = int(self.xratio) self.yratio = int(self.yratio) def sizeHint(self): return QtCore.QSize(800, 400) def updateItemSlot(self, mooseObject): # This is overridden by derived classes to connect appropriate # slot for updating the display item. # In this case if the name is updated from the keyboard both in mooseobj and gui gets updation changedItem = "" for item in self.sceneContainer.items(): if isinstance(item, PoolItem): if mooseObject.getId() == element(item.mobj).getId(): item.updateSlot() # once the text is edited in editor, laydisplay gets updated in turn resize the length, positionChanged signal shd be emitted self.positionChange(mooseObject) def updateColorSlot(self, mooseObject, color): # Color slot for changing background color for PoolItem from objecteditor anninfo = moose.Annotator(mooseObject.path + "/info") textcolor, bgcolor = getColor(anninfo) anninfo.color = str(color.name()) item = self.mooseId_GObj[mooseObject] if isinstance(item, PoolItem) or isinstance(item, EnzItem) or isinstance(item, MMEnzItem): item.updateColor(color) def mooseObjOntoscene(self): # All the compartments are put first on to the scene \ # Need to do: Check With upi if empty compartments exist self.qGraCompt = {} self.mooseId_GObj = {} if self.qGraCompt: self.qGraCompt.clear() else: self.qGraCompt = {} if self.mooseId_GObj: self.mooseId_GObj.clear() else: self.mooseId_GObj = {} for cmpt in sorted(self.meshEntry.iterkeys()): self.createCompt(cmpt) self.qGraCompt[cmpt] # comptRef = self.qGraCompt[cmpt] # Enzymes of all the compartments are placed first, \ # so that when cplx (which is pool object) queries for its parent, it gets its \ # parent enz co-ordinates with respect to QGraphicsscene """ for cmpt, memb in self.meshEntry.items(): for enzObj in find_index(memb, "enzyme"): enzinfo = enzObj.path + "/info" if enzObj.className == "Enz": enzItem = EnzItem(enzObj, self.qGraCompt[cmpt]) else: enzItem = MMEnzItem(enzObj, self.qGraCompt[cmpt]) self.mooseId_GObj[element(enzObj.getId())] = enzItem self.setupDisplay(enzinfo, enzItem, "enzyme") # self.setupSlot(enzObj,enzItem) for cmpt, memb in self.meshEntry.items(): for poolObj in find_index(memb, "pool"): poolinfo = poolObj.path + "/info" # depending on Editor Widget or Run widget pool will be created a PoolItem or PoolItemCircle poolItem = self.makePoolItem(poolObj, self.qGraCompt[cmpt]) self.mooseId_GObj[element(poolObj.getId())] = poolItem self.setupDisplay(poolinfo, poolItem, "pool") for reaObj in find_index(memb, "reaction"): reainfo = reaObj.path + "/info" reaItem = ReacItem(reaObj, self.qGraCompt[cmpt]) self.setupDisplay(reainfo, reaItem, "reaction") self.mooseId_GObj[element(reaObj.getId())] = reaItem for tabObj in find_index(memb, "table"): tabinfo = tabObj.path + "/info" tabItem = TableItem(tabObj, self.qGraCompt[cmpt]) self.setupDisplay(tabinfo, tabItem, "tab") self.mooseId_GObj[element(tabObj.getId())] = tabItem for funcObj in find_index(memb, "function"): funcinfo = moose.element(funcObj.parent).path + "/info" funcParent = self.mooseId_GObj[element(funcObj.parent)] funcItem = FuncItem(funcObj, funcParent) self.mooseId_GObj[element(funcObj.getId())] = funcItem self.setupDisplay(funcinfo, funcItem, "Function") for cplxObj in find_index(memb, "cplx"): cplxinfo = (cplxObj.parent).path + "/info" p = element(cplxObj).parent cplxItem = CplxItem(cplxObj, self.mooseId_GObj[element(cplxObj).parent]) self.mooseId_GObj[element(cplxObj.getId())] = cplxItem self.setupDisplay(cplxinfo, cplxItem, "cplx") # compartment's rectangle size is calculated depending on children self.comptChilrenBoundingRect() def comptChilrenBoundingRect(self): for k, v in self.qGraCompt.items(): # compartment's rectangle size is calculated depending on children rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20)) v.setPen( QtGui.QPen(Qt.QColor(66, 66, 66, 100), self.comptPen, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin) ) def createCompt(self, key): self.new_Compt = ComptItem(self, 0, 0, 0, 0, key) self.qGraCompt[key] = self.new_Compt self.new_Compt.setRect(10, 10, 10, 10) self.sceneContainer.addItem(self.new_Compt) def setupDisplay(self, info, graphicalObj, objClass): Annoinfo = Annotator(info) # For Reaction and Complex object I have skipped the process to get the facecolor and background color as \ # we are not using these colors for displaying the object so just passing dummy color white if objClass == "reaction" or objClass == "cplx" or objClass == "Function" or objClass == "StimulusTable": textcolor, bgcolor = "white", "white" else: textcolor, bgcolor = getColor(info) if bgcolor.name() == "#ffffff" or bgcolor == "white": bgcolor = getRandColor() Annoinfo.color = str(bgcolor.name()) if isinstance(self, kineticEditorWidget): xpos, ypos = self.positioninfo(info) self.xylist = [xpos, ypos] self.xyCord[moose.element(info).parent] = [xpos, ypos] elif isinstance(self, kineticRunWidget): self.editormooseId_GObj = self.editor.getCentralWidget().mooseId_GObj editorItem = self.editormooseId_GObj[moose.element(info).parent] # print "editorItem ",info,editorItem xpos = editorItem.scenePos().x() ypos = editorItem.scenePos().y() Annoinfo.x = xpos Annoinfo.y = -ypos graphicalObj.setDisplayProperties(xpos, ypos, textcolor, bgcolor) def positioninfo(self, iteminfo): Anno = moose.Annotator(self.modelRoot + "/info") if not self.noPositionInfo: try: # kkit does exist item's/info which up querying for parent.path gives the information of item's parent x, y = self.autoCordinatepos[(element(iteminfo).parent).path] except: # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\ # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\ # type of the object (rea,pool,enz,cplx,tab) which I have already done. parent, child = posixpath.split(iteminfo) x, y = self.autoCordinatepos[parent] ypos = (y - self.ymin) * self.yratio else: x = float(element(iteminfo).getField("x")) y = float(element(iteminfo).getField("y")) # Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \ # as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated if Anno.modeltype == "kkit": ypos = 1.0 - (y - self.ymin) * self.yratio else: ypos = (y - self.ymin) * self.yratio xpos = (x - self.xmin) * self.xratio return (xpos, ypos) def drawLine_arrow(self, itemignoreZooming=False): for inn, out in self.srcdesConnection.items(): # print "inn ",inn, " out ",out # self.srcdesConnection is dictionary which contains key,value \ # key is Enzyme or Reaction and value [[list of substrate],[list of product]] (tuple) # key is Function and value is [list of pool] (list) # src = self.mooseId_GObj[inn] if isinstance(out, tuple): src = self.mooseId_GObj[inn] if len(out[0]) == 0: print inn.className + " : " + inn.name + " doesn't output message" else: for items in (items for items in out[0]): des = self.mooseId_GObj[element(items[0])] self.lineCord(src, des, items, itemignoreZooming) if len(out[1]) == 0: print inn.className + " : " + inn.name + " doesn't output message" else: for items in (items for items in out[1]): des = self.mooseId_GObj[element(items[0])] self.lineCord(src, des, items, itemignoreZooming) elif isinstance(out, list): if len(out) == 0: print "Func pool doesn't have sumtotal" else: src = self.mooseId_GObj[inn] for items in (items for items in out): des = self.mooseId_GObj[element(items[0])] self.lineCord(src, des, items, itemignoreZooming) def lineCord(self, src, des, type_no, itemignoreZooming): srcdes_list = [] endtype = type_no[1] line = 0 if (src == "") and (des == ""): print "Source or destination is missing or incorrect" return srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) while type_no[2] > 1 and line <= (type_no[2] - 1): srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) line = line + 1 if type_no[2] > 5: print "Higher order reaction will not be displayed" def drawLine(self, srcdes_list, arrow): src = srcdes_list[0] des = srcdes_list[1] endtype = srcdes_list[2] line = srcdes_list[3] source = element(next((k for k, v in self.mooseId_GObj.items() if v == src), None)) for l, v, et, o in self.object2line[src]: if v == des and o == line: l.setPolygon(arrow) arrowPen = l.pen() arrowPenWidth = self.arrowsize * self.iconScale arrowPen.setColor(l.pen().color()) arrowPen.setWidth(arrowPenWidth) l.setPen(arrowPen) return qgLineitem = self.sceneContainer.addPolygon(arrow) qgLineitem.setParentItem(src.parentItem()) pen = QtGui.QPen(QtCore.Qt.green, 0, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin) pen.setWidth(self.arrowsize) # Green is default color moose.ReacBase and derivatives - already set above if isinstance(source, EnzBase): if (endtype == "s") or (endtype == "p"): pen.setColor(QtCore.Qt.red) elif endtype != "cplx": p1 = next((k for k, v in self.mooseId_GObj.items() if v == src), None) pinfo = p1.path + "/info" color, bgcolor = getColor(pinfo) # color = QColor(color[0],color[1],color[2]) pen.setColor(color) elif isinstance(source, moose.PoolBase) or isinstance(source, moose.Function): pen.setColor(QtCore.Qt.blue) elif isinstance(source, moose.StimulusTable): pen.setColor(QtCore.Qt.yellow) self.lineItem_dict[qgLineitem] = srcdes_list self.object2line[src].append((qgLineitem, des, endtype, line)) self.object2line[des].append((qgLineitem, src, endtype, line)) qgLineitem.setPen(pen) def positionChange(self, mooseObject): # If the item position changes, the corresponding arrow's are calculated if isinstance(element(mooseObject), ChemCompt): for k, v in self.qGraCompt.items(): mesh = mooseObject if k.path == mesh: for rectChilditem in v.childItems(): if isinstance(rectChilditem, KineticsDisplayItem): if isinstance(moose.element(rectChilditem.mobj.path), PoolBase): t = moose.element(rectChilditem.mobj.path) moose.element(t).children for items in moose.element(t).children: if isinstance(moose.element(items), Function): test = moose.element(items.path + "/x") for i in moose.element(test).neighbors["input"]: j = self.mooseId_GObj[moose.element(i)] self.updateArrow(j) self.updateArrow(rectChilditem) else: mobj = self.mooseId_GObj[element(mooseObject)] self.updateArrow(mobj) elePath = moose.element(mooseObject).path pos = elePath.find("/", 1) l = elePath[0:pos] linfo = moose.Annotator(l + "/info") for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() if linfo.modeltype == "new_kkit": # if newly built model then compartment is size is fixed for some size. comptBoundingRect = v.boundingRect() if not comptBoundingRect.contains(rectcompt): self.updateCompartmentSize(v) else: # if already built model then compartment size depends on max and min objects v.setRect( rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20) ) def updateCompartmentSize(self, compartment): compartmentBoundary = compartment.rect() childrenBoundary = compartment.childrenBoundingRect() x = min(compartmentBoundary.x(), childrenBoundary.x()) y = min(compartmentBoundary.y(), childrenBoundary.y()) width = max(compartmentBoundary.width(), childrenBoundary.width()) height = max(compartmentBoundary.height(), childrenBoundary.height()) compartment.setRect(x - 10, y - 10, width + 20, height + 20) def updateArrow(self, qGTextitem): # if there is no arrow to update then return if qGTextitem not in self.object2line: return listItem = self.object2line[qGTextitem] for ql, va, endtype, order in self.object2line[qGTextitem]: srcdes = [] srcdes = self.lineItem_dict[ql] # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz, # if yes then need to check if cplx is connected to any mooseObject, # so that when Enzyme is moved, cplx connected arrow to other mooseObject(poolItem) should also be updated if type(srcdes[0]) == EnzItem: self.cplxUpdatearrow(srcdes[0]) elif type(srcdes[1]) == EnzItem: self.cplxUpdatearrow(srcdes[1]) # For calcArrow(src,des,endtype,itemignoreZooming) is to be provided arrow = calcArrow(srcdes, self.itemignoreZooming, self.iconScale) ql.setPolygon(arrow) def cplxUpdatearrow(self, srcdes): # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz) # And cplxItem is passed for updatearrow for item in srcdes.childItems(): if isinstance(item, CplxItem): self.updateArrow(item) # def deleteSolver(self): # print " delete Solver" # print "### ",moose.wildcardFind(self.modelRoot+'/data/graph#/#') # if moose.wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]'): # compt = moose.wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]') # print " deletSolver ", # # print moose.exists(compt[0].path+'/stoich'), " ksolve ", moose.exists(compt[0].path+'/ksolve') # # print "gsolve ", moose.delete( compt[0].path+'/gsolve' ) # if ( moose.exists( compt[0].path+'/stoich' ) ): # #print "delete" # moose.delete( compt[0].path+'/stoich' ) # if ( moose.exists( compt[0].path+'/ksolve' ) ): # moose.delete( compt[0].path+'/ksolve' ) # if ( moose.exists( compt[0].path+'/gsolve' ) ): # moose.delete( compt[0].path+'/gsolve' ) # for x in moose.wildcardFind( self.modelRoot+'/data/graph#/#' ): # x.tick = -1 def positionChange1(self, mooseObject): # If the item position changes, the corresponding arrow's are calculated if (isinstance(element(mooseObject), CubeMesh)) or (isinstance(element(mooseObject), CylMesh)): v = self.qGraCompt[mooseObject] for rectChilditem in v.childItems(): self.updateArrow(rectChilditem) else: mobj = self.mooseId_GObj[mooseObject.getId()] self.updateArrow(mobj) mooseObjcompt = self.findparent(mooseObject) v = self.qGraCompt[mooseObjcompt] childBoundingRect = v.childrenBoundingRect() comptBoundingRect = v.boundingRect() rectcompt = comptBoundingRect.united(childBoundingRect) comptPen = v.pen() comptWidth = 5 comptPen.setWidth(comptWidth) v.setPen(comptPen) if not comptBoundingRect.contains(childBoundingRect): v.setRect( rectcompt.x() - comptWidth, rectcompt.y() - comptWidth, rectcompt.width() + (comptWidth * 2), rectcompt.height() + (comptWidth * 2), )
class KineticsWidget(EditorWidgetBase): def __init__(self, *args): EditorWidgetBase.__init__(self, *args) self.setAcceptDrops(True) self.border = 10 self.sceneContainer = QtGui.QGraphicsScene(self) self.sceneContainer.setSceneRect(self.sceneContainer.itemsBoundingRect()) self.sceneContainer.setBackgroundBrush(QtGui.QColor(230,220,219,120)) #self.insertMenu = QtGui.QMenu('&Insert') #self._menus.append(self.insertMenu) #self.insertMapper = QtCore.QSignalMapper(self) classlist = ['CubeMesh','CylMesh','Pool','FuncPool','SumFunc','Reac','Enz','MMenz','StimulusTable','Table'] #insertMapper, actions = self.getInsertActions(classlist) #for action in actions: # self.insertMenu.addAction(action) #print "viewType",self.viewType # pickled the color map file """ colormap_file = open(os.path.join(config.settings[config.KEY_COLORMAP_DIR], 'rainbow2.pkl'),'rb') self.colorMap = pickle.load(colormap_file) colormap_file.close() if self.modelRoot == '/': self.m = wildcardFind('/##[ISA=ChemCompt]') else: self.m = wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]') if self.m: self.xmin = 0.0 self.xmax = 1.0 self.ymin = 0.0 self.ymax = 1.0 self.autoCordinatepos = {} # Compartment and its members are setup self.meshEntry,self.xmin,self.xmax,self.ymin,self.ymax,self.noPositionInfo = setupMeshObj(self.modelRoot) self.autocoordinates = False # srcdesConnection dictonary will have connection information between src and des """ self.srcdesConnection = {} setupItem(self.modelRoot,self.srcdesConnection) if self.noPositionInfo: self.autocoordinates = True QtGui.QMessageBox.warning(self, 'No coordinates found for the model', '\n Automatic layouting will be done') #raise Exception('Unsupported kkit version') self.xmin,self.xmax,self.ymin,self.ymax,self.autoCordinatepos = autoCoordinates(self.meshEntry,self.srcdesConnection) # TODO: size will be dummy at this point, but I need the availiable size from the Gui self.size = QtCore.QSize(1024 ,768) #self.size = QtCore.QSize(300,400) # Scale factor to translate the x -y position to fit the Qt graphicalScene, scene width. """ if self.xmax-self.xmin != 0: self.xratio = (self.size.width()-10)/(self.xmax-self.xmin) else: self.xratio = self.size.width()-10 if self.ymax-self.ymin: self.yratio = (self.size.height()-10)/(self.ymax-self.ymin) else: self.yratio = (self.size.height()-10) #A map b/w moose compartment key with QGraphicsObject self.qGraCompt = {} #A map between mooseId of all the mooseObject (except compartment) with QGraphicsObject self.mooseId_GObj = {} self.border = 5 self.arrowsize = 2 self.iconScale = 1 self.defaultComptsize = 5 self.itemignoreZooming = False self.lineItem_dict = {} self.object2line = defaultdict(list) def makePoolItem(self, poolObj, qGraCompt): raise NotImplementedError('method must be reimplemented in subclass') def mooseObjOntoscene(self): # All the compartments are put first on to the scene \ # Need to do: Check With upi if empty compartments exist for cmpt in sorted(self.meshEntry.iterkeys()): self.createCompt(cmpt) self.qGraCompt[cmpt] #comptRef = self.qGraCompt[cmpt] #Enzymes of all the compartments are placed first, \ # so that when cplx (which is pool object) queries for its parent, it gets its \ # parent enz co-ordinates with respect to QGraphicsscene """ for cmpt,memb in self.meshEntry.items(): for enzObj in find_index(memb,'enzyme'): enzinfo = enzObj.path+'/info' if enzObj.className == 'Enz': enzItem = EnzItem(enzObj,self.qGraCompt[cmpt]) else: enzItem = MMEnzItem(enzObj,self.qGraCompt[cmpt]) self.setupDisplay(enzinfo,enzItem,"enzyme") self.setupSlot(enzObj,enzItem) for cmpt,memb in self.meshEntry.items(): for poolObj in find_index(memb,'pool'): poolinfo = poolObj.path+'/info' ''' depending on Editor Widget or Run widget pool will be created a PoolItem or PoolItemCircle ''' poolItem = self.makePoolItem(poolObj,self.qGraCompt[cmpt]) self.setupDisplay(poolinfo,poolItem,"pool") self.setupSlot(poolObj,poolItem) for cplxObj in find_index(memb,'cplx'): cplxinfo = (cplxObj.parent).path+'/info' cplxItem = CplxItem(cplxObj,self.mooseId_GObj[element(cplxObj).parent.getId()]) self.setupDisplay(cplxinfo,cplxItem,"cplx") self.setupSlot(cplxObj,cplxItem) for reaObj in find_index(memb,'reaction'): reainfo = reaObj.path+'/info' reaItem = ReacItem(reaObj,self.qGraCompt[cmpt]) self.setupDisplay(reainfo,reaItem,"reaction") self.setupSlot(reaObj,reaItem) for tabObj in find_index(memb,'table'): tabinfo = tabObj.path+'/info' tabItem = TableItem(tabObj,self.qGraCompt[cmpt]) self.setupDisplay(tabinfo,tabItem,"tab") self.setupSlot(tabObj,tabItem) # compartment's rectangle size is calculated depending on children for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x()-10,rectcompt.y()-10,(rectcompt.width()+20),(rectcompt.height()+20)) v.setPen(QtGui.QPen(Qt.QColor(66,66,66,100), 5, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin)) v.cmptEmitter.connect(v.cmptEmitter,QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"),self.positionChange) v.cmptEmitter.connect(v.cmptEmitter,QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"),self.objectEditSlot) def createCompt(self,key): self.new_Compt = ComptItem(self,0,0,0,0,key) self.qGraCompt[key] = self.new_Compt self.new_Compt.setRect(10,10,10,10) self.sceneContainer.addItem(self.new_Compt) def setupDisplay(self,info,graphicalObj,objClass): xpos,ypos = self.positioninfo(info) # For Reaction and Complex object I have skipped the process to get the facecolor and background color as \ # we are not using these colors for displaying the object so just passing dummy color white if( (objClass == "reaction" ) or (objClass == "cplx")): textcolor,bgcolor = "white","white" elif objClass == "tab": textcolor,bgcolor = getColor(info,self.colorMap) else: textcolor,bgcolor = getColor(info,self.colorMap) graphicalObj.setDisplayProperties(xpos,ypos,textcolor,bgcolor) def positioninfo(self,iteminfo): if self.noPositionInfo: try: # kkit does exist item's/info which up querying for parent.path gives the information of item's parent x,y = self.autoCordinatepos[(element(iteminfo).parent).path] except: # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\ # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\ # type of the object (rea,pool,enz,cplx,tab) which I have already done. parent, child = posixpath.split(iteminfo) x,y = self.autoCordinatepos[parent] ypos = (y-self.ymin)*self.yratio else: x = float(element(iteminfo).getField('x')) y = float(element(iteminfo).getField('y')) #Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \ #as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated ypos = -(y-self.ymin)*self.yratio xpos = (x-self.xmin)*self.xratio return(xpos,ypos) def setupSlot(self,mooseObj,qgraphicItem): self.mooseId_GObj[element(mooseObj).getId()] = qgraphicItem qgraphicItem.connect(qgraphicItem,QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"),self.positionChange) qgraphicItem.connect(qgraphicItem,QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"),self.objectEditSlot) def updateItemSlot(self, mooseObject): #This is overridden by derived classes to connect appropriate #slot for updating the display item. #In this case if the name is updated from the keyboard both in mooseobj and gui gets updation changedItem = '' for item in self.sceneContainer.items(): #print "updateItemSlot",item if isinstance(item,PoolItem): if mooseObject.getId() == element(item.mobj).getId(): print "##",mooseObject.getId(),element(item.mobj).getId() item.updateSlot() #once the text is edited in editor, laydisplay gets updated in turn resize the length, positionChanged signal shd be emitted self.positionChange(mooseObject) def getToolBars(self): raise NotImplementedError('method must be reimplemented in subclass') '''if not hasattr(self, '_insertToolBar'): self._insertToolBar = QtGui.QToolBar('Insert') self._toolBars.append(self._insertToolBar) for action in self.insertMenu.actions(): button = MToolButton() button.setDefaultAction(action) self._insertToolBar.addWidget(button) return self._toolBars ''' def sizeHint(self): return QtCore.QSize(800,400) def updateModelView(self): # if self.modelRoot == '/': # m = wildcardFind('/##[ISA=ChemCompt]') # else: # m = wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]') if not self.m: # when we want an empty GraphicView while creating new model, # then remove all the view and add an empty view if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) createdItem = {} self.sceneContainer.setSceneRect(-self.width()/2,-self.height()/2,self.width(),self.height()) self.view = GraphicalView(self, self.modelRoot,self.sceneContainer,self.border,self,createdItem) self.connect(self.view, QtCore.SIGNAL("dropped"), self.objectEditSlot) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) else: # maxmium and minimum coordinates of the objects specified in kkit file. self.sceneContainer.clear() # Compartment and its members are put on the qgraphicsscene self.mooseObjOntoscene() # All the moose Object are connected for visualization self.drawLine_arrow(itemignoreZooming=False) createdItem = {} if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) self.view = GraphicalView(self,self.modelRoot,self.sceneContainer,self.border,self,createdItem) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) #self.layout().addWidget(self.view) ''' def resetColor(self): for item in self.sceneContainer.items(): if isinstance(item,PoolItem): pinfo = moose.element(item.mobj).path+'/info' color,bg = getColor(pinfo,self.colorMap) item.updateColor(bg) def changeBgSize(self): for item in self.sceneContainer.items(): if isinstance(item,PoolItem): initialConc = moose.element(item.mobj).concInit presentConc = moose.element(item.mobj).conc if initialConc != 0: ratio = presentConc/initialConc else: # multipying by 1000 b'cos moose concentration is in milli in moose ratio = presentConc*1000 item.updateRect(math.sqrt(ratio)) def colorChange(self): #While simulation is running pool color are increased or decreased as per concentration level for item in self.sceneContainer.items(): if isinstance(item,PoolItem): bg = item.returnColor() initialConc = moose.element(item.mobj[0]).concInit presentConc = moose.element(item.mobj[0]).conc if initialConc != 0: ratio = presentConc/initialConc else: # multipying by 1000 b'cos moose concentration is in milli in moose ratio = presentConc*1000 #alpha between0-255 alpha = 128*ratio # Limiting alpha values if int(math.floor(alpha)) > 255: alpha = 255 elif int(math.floor(alpha))< 40: alpha = 40 #only alpha value is changed bg =QtGui.QColor(bg.red(),bg.green(),bg.blue(),alpha) item.updateColor(bg) ''' def positionChange(self,mooseObject): #If the item position changes, the corresponding arrow's are calculated if isinstance(element(mooseObject),CubeMesh): for k, v in self.qGraCompt.items(): #mesh = mooseObject.path+'/mesh[0]' #print " mesh ",mesh,k.path #if k.path == mesh: for rectChilditem in v.childItems(): self.updateArrow(rectChilditem) else: mobj = self.mooseId_GObj[mooseObject.getId()] self.updateArrow(mobj) for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x()-10,rectcompt.y()-10,(rectcompt.width()+20),(rectcompt.height()+20)) def emitItemtoEditor(self,mooseObject): #self.emit(QtCore.SIGNAL("itemPressed(PyQt_PyObject)"),mooseObject) self.editObject.emit(mooseObject.path) def drawLine_arrow(self, itemignoreZooming=False): for inn,out in self.srcdesConnection.items(): # self.srcdesConnection is dictionary which contains key,value \ # key is Enzyme or Reaction and value [[list of substrate],[list of product]] (tuple) # key is FuncBase and value is [list of pool] (list) #src = self.mooseId_GObj[inn] if isinstance(out,tuple): if len(out[0])== 0: print inn.className + ':' +inn.name+ " doesn't output message" else: src = self.mooseId_GObj[inn.getId()] for items in (items for items in out[0] ): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src,des,items,itemignoreZooming) if len(out[1]) == 0: print inn.className + ':' +inn.name+ " doesn't output message" else: for items in (items for items in out[1] ): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src,des,items,itemignoreZooming) elif isinstance(out,list): if len(out) == 0: print "Func pool doesn't have sumtotal" else: src = self.mooseId_GObj[element(inn).getId()] for items in (items for items in out ): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src,des,items,itemignoreZooming) def lineCord(self,src,des,type_no,itemignoreZooming): endtype = type_no[1] line = 0 if (src == "") and (des == ""): print "Source or destination is missing or incorrect" return srcdes_list = [src,des,endtype,line] arrow = calcArrow(srcdes_list,itemignoreZooming,self.iconScale) self.drawLine(srcdes_list,arrow) while(type_no[2] > 1 and line <= (type_no[2]-1)): srcdes_list =[src,des,endtype,line] arrow = calcArrow(srcdes_list,itemignoreZooming,self.iconScale) self.drawLine(srcdes_list,arrow) line = line +1 if type_no[2] > 5: print "Higher order reaction will not be displayed" def drawLine(self,srcdes_list,arrow): src = srcdes_list[0] des = srcdes_list[1] endtype = srcdes_list[2] line = srcdes_list[3] source = element(next((k for k,v in self.mooseId_GObj.items() if v == src), None)) for l,v,o in self.object2line[src]: if v == des and o ==line: l.setPolygon(arrow) arrowPen = l.pen() arrowPenWidth = self.arrowsize*self.iconScale arrowPen.setColor(l.pen().color()) arrowPen.setWidth(arrowPenWidth) l.setPen(arrowPen) return qgLineitem = self.sceneContainer.addPolygon(arrow) pen = QtGui.QPen(QtCore.Qt.green, 0, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin) pen.setWidth(self.arrowsize) #pen.setCosmetic(True) # Green is default color moose.ReacBase and derivatives - already set above if isinstance(source, EnzBase): if ( (endtype == 's') or (endtype == 'p')): pen.setColor(QtCore.Qt.red) elif(endtype != 'cplx'): p1 = (next((k for k,v in self.mooseId_GObj.items() if v == src), None)) pinfo = p1.path+'/info' color,bgcolor = getColor(pinfo,self.colorMap) pen.setColor(color) elif isinstance(source, moose.PoolBase): pen.setColor(QtCore.Qt.blue) elif isinstance(source,moose.StimulusTable): pen.setColor(QtCore.Qt.yellow) self.lineItem_dict[qgLineitem] = srcdes_list self.object2line[ src ].append( ( qgLineitem, des,line) ) self.object2line[ des ].append( ( qgLineitem, src,line ) ) qgLineitem.setPen(pen) def updateArrow(self,qGTextitem): #if there is no arrow to update then return if qGTextitem not in self.object2line: return listItem = self.object2line[qGTextitem] for ql, va,order in self.object2line[qGTextitem]: srcdes = [] srcdes = self.lineItem_dict[ql] # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz, # if yes then need to check if cplx is connected to any mooseObject, # so that when Enzyme is moved, cplx connected arrow to other mooseObject(poolItem) should also be updated if( type(srcdes[0]) == EnzItem): self.cplxUpdatearrow(srcdes[0]) elif( type(srcdes[1]) == EnzItem): self.cplxUpdatearrow(srcdes[1]) # For calcArrow(src,des,endtype,itemignoreZooming) is to be provided arrow = calcArrow(srcdes,self.itemignoreZooming,self.iconScale) ql.setPolygon(arrow) def cplxUpdatearrow(self,srcdes): # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz) #And cplxItem is passed for updatearrow #Note: Here at this point enzItem has just one child which is cplxItem and childItems returns, PyQt4.QtGui.QGraphicsEllipseItem,CplxItem #Assuming CplxItem is always[1], but still check if not[0], if something changes in structure one need to keep an eye. if (srcdes.childItems()[1],CplxItem): self.updateArrow(srcdes.childItems()[1]) else: self.updateArrow(srcdes.childItems()[0]) def keyPressEvent(self,event): # key1 = event.key() # key event does not distinguish between capital and non-capital letters key = event.text().toAscii().toHex() if key == '41': # 'A' fits the view to iconScale factor itemignoreZooming = False self.updateItemTransformationMode(itemignoreZooming) self.view.fitInView(self.sceneContainer.itemsBoundingRect().x()-10,self.sceneContainer.itemsBoundingRect().y()-10,self.sceneContainer.itemsBoundingRect().width()+20,self.sceneContainer.itemsBoundingRect().height()+20,Qt.Qt.IgnoreAspectRatio) self.drawLine_arrow(itemignoreZooming=False) elif (key == '2e'): # '.' key, lower case for '>' zooms in self.view.scale(1.1,1.1) elif (key == '2c'): # ',' key, lower case for '<' zooms in self.view.scale(1/1.1,1/1.1) elif (key == '3c'): # '<' key. zooms-in to iconScale factor self.iconScale *= 0.8 self.updateScale( self.iconScale ) elif (key == '3e'): # '>' key. zooms-out to iconScale factor self.iconScale *= 1.25 self.updateScale( self.iconScale ) elif (key == '61'): # 'a' fits the view to initial value where iconscale=1 self.iconScale = 1 self.updateScale( self.iconScale ) self.view.fitInView(self.sceneContainer.itemsBoundingRect().x()-10,self.sceneContainer.itemsBoundingRect().y()-10,self.sceneContainer.itemsBoundingRect().width()+20,self.sceneContainer.itemsBoundingRect().height()+20,Qt.Qt.IgnoreAspectRatio) def updateItemTransformationMode(self, on): for v in self.sceneContainer.items(): if( not isinstance(v,ComptItem)): #if ( isinstance(v, PoolItem) or isinstance(v, ReacItem) or isinstance(v, EnzItem) or isinstance(v, CplxItem) ): if isinstance(v,KineticsDisplayItem): v.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations, on) def updateScale( self, scale ): for item in self.sceneContainer.items(): if isinstance(item,KineticsDisplayItem): item.refresh(scale) #iteminfo = item.mobj.path+'/info' #xpos,ypos = self.positioninfo(iteminfo) xpos = item.scenePos().x() ypos = item.scenePos().y() if isinstance(item,ReacItem) or isinstance(item,EnzItem) or isinstance(item,MMEnzItem): item.setGeometry(xpos,ypos, item.gobj.boundingRect().width(), item.gobj.boundingRect().height()) elif isinstance(item,CplxItem): item.setGeometry(item.gobj.boundingRect().width()/2,item.gobj.boundingRect().height(), item.gobj.boundingRect().width(), item.gobj.boundingRect().height()) elif isinstance(item,PoolItem): item.setGeometry(xpos, ypos,item.gobj.boundingRect().width() +PoolItem.fontMetrics.width(' '), item.gobj.boundingRect().height()) item.bg.setRect(0, 0, item.gobj.boundingRect().width()+PoolItem.fontMetrics.width(' '), item.gobj.boundingRect().height()) self.drawLine_arrow(itemignoreZooming=False) for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() comptPen = v.pen() comptWidth = self.defaultComptsize*self.iconScale comptPen.setWidth(comptWidth) v.setPen(comptPen) v.setRect(rectcompt.x()-comptWidth,rectcompt.y()-comptWidth,(rectcompt.width()+2*comptWidth),(rectcompt.height()+2*comptWidth))
class KineticsWidget(EditorWidgetBase): def __init__(self, plugin, *args): EditorWidgetBase.__init__(self, *args) self.plugin = plugin self.border = 5 self.comptPen = 6 self.iconScale = 1 self.arrowsize = 2 self.defaultComptsize = 5 self.noPositionInfo = True self.xyCord = {} self.reset() self.qGraCompt = {} self.mooseId_GObj = {} self.srcdesConnection = {} self.editor = None def reset(self): #print "reset " self.createdItem = {} #This are created at drawLine self.lineItem_dict = {} self.object2line = defaultdict(list) self.itemignoreZooming = False if hasattr(self, 'sceneContainer'): self.sceneContainer.clear() self.sceneContainer = QtGui.QGraphicsScene(self) sceneDim = self.sceneContainer.itemsBoundingRect() # if (sceneDim.width() == 0 and sceneDim.height() == 0): # self.sceneContainer.setSceneRect(0,0,30,30) # else: #elf.sceneContainer.setSceneRect(self.sceneContainer.itemsBoundingRect()) self.sceneContainer.setBackgroundBrush(QColor(230, 220, 219, 120)) def updateModelView(self): self.getMooseObj() if not self.m: #At the time of model building # when we want an empty GraphicView while creating new model, # then remove all the view and add an empty view if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) #self.sceneContainer.setSceneRect(-self.width()/2,-self.height()/2,self.width(),self.height()) self.view = GraphicalView(self.modelRoot, self.sceneContainer, self.border, self, self.createdItem) if isinstance(self, kineticEditorWidget): self.view.setRefWidget("editorView") self.view.setAcceptDrops(True) elif isinstance(self, kineticRunWidget): self.view.setRefWidget("runView") self.connect(self.view, QtCore.SIGNAL("dropped"), self.objectEditSlot) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view, 0, 0) else: # Already created Model # maxmium and minimum coordinates of the objects specified in kkit file. #self.mooseObjOntoscene() #self.drawLine_arrow() if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) self.view = GraphicalView(self.modelRoot, self.sceneContainer, self.border, self, self.createdItem) if isinstance(self, kineticEditorWidget): #self.getMooseObj() self.mooseObjOntoscene() self.drawLine_arrow() self.view.setRefWidget("editorView") self.view.setAcceptDrops(True) self.connect(self.view, QtCore.SIGNAL("dropped"), self.objectEditSlot) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) elif isinstance(self, kineticRunWidget): self.view.setRefWidget("runView") hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) self.view.fitInView( self.sceneContainer.itemsBoundingRect().x() - 10, self.sceneContainer.itemsBoundingRect().y() - 10, self.sceneContainer.itemsBoundingRect().width() + 20, self.sceneContainer.itemsBoundingRect().height() + 20, Qt.Qt.IgnoreAspectRatio) def getMooseObj(self): #This fun call 2 more function # -- setupMeshObj(self.modelRoot), # ----self.meshEntry has [meshEnt] = function: {}, Pool: {} etc # setupItem self.m = wildcardFind(self.modelRoot + '/##[ISA=ChemCompt]') if self.m: self.xmin = 0.0 self.xmax = 1.0 self.ymin = 0.0 self.ymax = 1.0 self.autoCordinatepos = {} self.srcdesConnection = {} #self.meshEntry.clear= {} # Compartment and its members are setup self.meshEntry, self.xmin, self.xmax, self.ymin, self.ymax, self.noPositionInfo = setupMeshObj( self.modelRoot) self.autocoordinates = False if self.srcdesConnection: self.srcdesConnection.clear() else: self.srcdesConnection = {} setupItem(self.modelRoot, self.srcdesConnection) if not self.noPositionInfo: self.autocoordinates = True self.xmin, self.xmax, self.ymin, self.ymax, self.autoCordinatepos = autoCoordinates( self.meshEntry, self.srcdesConnection) # TODO: size will be dummy at this point, but size I need the availiable size from the Gui self.size = QtCore.QSize(1000, 550) if self.xmax - self.xmin != 0: self.xratio = (self.size.width() - 10) / (self.xmax - self.xmin) else: self.xratio = self.size.width() - 10 if self.ymax - self.ymin: self.yratio = (self.size.height() - 10) / (self.ymax - self.ymin) else: self.yratio = (self.size.height() - 10) self.xratio = int(self.xratio) self.yratio = int(self.yratio) def sizeHint(self): return QtCore.QSize(800, 400) def updateItemSlot(self, mooseObject): #This is overridden by derived classes to connect appropriate #slot for updating the display item. #In this case if the name is updated from the keyboard both in mooseobj and gui gets updation changedItem = '' for item in self.sceneContainer.items(): if isinstance(item, PoolItem): if mooseObject.getId() == element(item.mobj).getId(): item.updateSlot() #once the text is edited in editor, laydisplay gets updated in turn resize the length, positionChanged signal shd be emitted self.positionChange(mooseObject) def updateColorSlot(self, mooseObject, color): #Color slot for changing background color for PoolItem from objecteditor anninfo = moose.Annotator(mooseObject.path + '/info') textcolor, bgcolor = getColor(anninfo) anninfo.color = str(color.name()) item = self.mooseId_GObj[mooseObject] if (isinstance(item, PoolItem) or isinstance(item, EnzItem) or isinstance(item, MMEnzItem)): item.updateColor(color) def mooseObjOntoscene(self): # All the compartments are put first on to the scene \ # Need to do: Check With upi if empty compartments exist self.qGraCompt = {} self.mooseId_GObj = {} if self.qGraCompt: self.qGraCompt.clear() else: self.qGraCompt = {} if self.mooseId_GObj: self.mooseId_GObj.clear() else: self.mooseId_GObj = {} for cmpt in sorted(self.meshEntry.iterkeys()): self.createCompt(cmpt) self.qGraCompt[cmpt] #comptRef = self.qGraCompt[cmpt] #Enzymes of all the compartments are placed first, \ # so that when cplx (which is pool object) queries for its parent, it gets its \ # parent enz co-ordinates with respect to QGraphicsscene """ for cmpt, memb in self.meshEntry.items(): for enzObj in find_index(memb, 'enzyme'): enzinfo = enzObj.path + '/info' if enzObj.className == 'Enz': enzItem = EnzItem(enzObj, self.qGraCompt[cmpt]) else: enzItem = MMEnzItem(enzObj, self.qGraCompt[cmpt]) self.mooseId_GObj[element(enzObj.getId())] = enzItem self.setupDisplay(enzinfo, enzItem, "enzyme") #self.setupSlot(enzObj,enzItem) for cmpt, memb in self.meshEntry.items(): for poolObj in find_index(memb, 'pool'): poolinfo = poolObj.path + '/info' #depending on Editor Widget or Run widget pool will be created a PoolItem or PoolItemCircle poolItem = self.makePoolItem(poolObj, self.qGraCompt[cmpt]) self.mooseId_GObj[element(poolObj.getId())] = poolItem self.setupDisplay(poolinfo, poolItem, "pool") for reaObj in find_index(memb, 'reaction'): reainfo = reaObj.path + '/info' reaItem = ReacItem(reaObj, self.qGraCompt[cmpt]) self.setupDisplay(reainfo, reaItem, "reaction") self.mooseId_GObj[element(reaObj.getId())] = reaItem for tabObj in find_index(memb, 'table'): tabinfo = tabObj.path + '/info' tabItem = TableItem(tabObj, self.qGraCompt[cmpt]) self.setupDisplay(tabinfo, tabItem, "tab") self.mooseId_GObj[element(tabObj.getId())] = tabItem for funcObj in find_index(memb, 'function'): funcinfo = moose.element(funcObj.parent).path + '/info' funcParent = self.mooseId_GObj[element(funcObj.parent)] funcItem = FuncItem(funcObj, funcParent) self.mooseId_GObj[element(funcObj.getId())] = funcItem self.setupDisplay(funcinfo, funcItem, "Function") for cplxObj in find_index(memb, 'cplx'): cplxinfo = (cplxObj.parent).path + '/info' p = element(cplxObj).parent cplxItem = CplxItem(cplxObj, self.mooseId_GObj[element(cplxObj).parent]) self.mooseId_GObj[element(cplxObj.getId())] = cplxItem self.setupDisplay(cplxinfo, cplxItem, "cplx") # compartment's rectangle size is calculated depending on children self.comptChilrenBoundingRect() def comptChilrenBoundingRect(self): for k, v in self.qGraCompt.items(): # compartment's rectangle size is calculated depending on children rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20)) v.setPen( QtGui.QPen(Qt.QColor(66, 66, 66, 100), self.comptPen, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin)) def createCompt(self, key): self.new_Compt = ComptItem(self, 0, 0, 0, 0, key) self.qGraCompt[key] = self.new_Compt self.new_Compt.setRect(10, 10, 10, 10) self.sceneContainer.addItem(self.new_Compt) def setupDisplay(self, info, graphicalObj, objClass): Annoinfo = Annotator(info) # For Reaction and Complex object I have skipped the process to get the facecolor and background color as \ # we are not using these colors for displaying the object so just passing dummy color white if (objClass == "reaction" or objClass == "cplx" or objClass == "Function" or objClass == "StimulusTable"): textcolor, bgcolor = "white", "white" else: textcolor, bgcolor = getColor(info) if bgcolor.name() == "#ffffff" or bgcolor == "white": bgcolor = getRandColor() Annoinfo.color = str(bgcolor.name()) if isinstance(self, kineticEditorWidget): xpos, ypos = self.positioninfo(info) self.xylist = [xpos, ypos] self.xyCord[moose.element(info).parent] = [xpos, ypos] elif isinstance(self, kineticRunWidget): self.editormooseId_GObj = self.editor.getCentralWidget( ).mooseId_GObj editorItem = self.editormooseId_GObj[moose.element(info).parent] #print "editorItem ",info,editorItem xpos = editorItem.scenePos().x() ypos = editorItem.scenePos().y() Annoinfo.x = xpos Annoinfo.y = -ypos graphicalObj.setDisplayProperties(xpos, ypos, textcolor, bgcolor) def positioninfo(self, iteminfo): Anno = moose.Annotator(self.modelRoot + '/info') if not self.noPositionInfo: try: # kkit does exist item's/info which up querying for parent.path gives the information of item's parent x, y = self.autoCordinatepos[(element(iteminfo).parent).path] except: # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\ # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\ # type of the object (rea,pool,enz,cplx,tab) which I have already done. parent, child = posixpath.split(iteminfo) x, y = self.autoCordinatepos[parent] ypos = (y - self.ymin) * self.yratio else: x = float(element(iteminfo).getField('x')) y = float(element(iteminfo).getField('y')) #Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \ #as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated if Anno.modeltype == "kkit": ypos = 1.0 - (y - self.ymin) * self.yratio else: ypos = (y - self.ymin) * self.yratio xpos = (x - self.xmin) * self.xratio return (xpos, ypos) def drawLine_arrow(self, itemignoreZooming=False): for inn, out in self.srcdesConnection.items(): #print "inn ",inn, " out ",out # self.srcdesConnection is dictionary which contains key,value \ # key is Enzyme or Reaction and value [[list of substrate],[list of product]] (tuple) # key is Function and value is [list of pool] (list) #src = self.mooseId_GObj[inn] if isinstance(out, tuple): src = self.mooseId_GObj[inn] if len(out[0]) == 0: print inn.className + ' : ' + inn.name + " doesn't output message" else: for items in (items for items in out[0]): des = self.mooseId_GObj[element(items[0])] self.lineCord(src, des, items, itemignoreZooming) if len(out[1]) == 0: print inn.className + ' : ' + inn.name + " doesn't output message" else: for items in (items for items in out[1]): des = self.mooseId_GObj[element(items[0])] self.lineCord(src, des, items, itemignoreZooming) elif isinstance(out, list): if len(out) == 0: print "Func pool doesn't have sumtotal" else: src = self.mooseId_GObj[inn] for items in (items for items in out): des = self.mooseId_GObj[element(items[0])] self.lineCord(src, des, items, itemignoreZooming) def lineCord(self, src, des, type_no, itemignoreZooming): srcdes_list = [] endtype = type_no[1] line = 0 if (src == "") and (des == ""): print "Source or destination is missing or incorrect" return srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) while (type_no[2] > 1 and line <= (type_no[2] - 1)): srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) line = line + 1 if type_no[2] > 5: print "Higher order reaction will not be displayed" def drawLine(self, srcdes_list, arrow): src = srcdes_list[0] des = srcdes_list[1] endtype = srcdes_list[2] line = srcdes_list[3] source = element( next((k for k, v in self.mooseId_GObj.items() if v == src), None)) for l, v, et, o in self.object2line[src]: if v == des and o == line: l.setPolygon(arrow) arrowPen = l.pen() arrowPenWidth = self.arrowsize * self.iconScale arrowPen.setColor(l.pen().color()) arrowPen.setWidth(arrowPenWidth) l.setPen(arrowPen) return qgLineitem = self.sceneContainer.addPolygon(arrow) qgLineitem.setParentItem(src.parentItem()) pen = QtGui.QPen(QtCore.Qt.green, 0, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin) pen.setWidth(self.arrowsize) # Green is default color moose.ReacBase and derivatives - already set above if isinstance(source, EnzBase): if ((endtype == 's') or (endtype == 'p')): pen.setColor(QtCore.Qt.red) elif (endtype != 'cplx'): p1 = (next( (k for k, v in self.mooseId_GObj.items() if v == src), None)) pinfo = p1.path + '/info' color, bgcolor = getColor(pinfo) #color = QColor(color[0],color[1],color[2]) pen.setColor(color) elif isinstance(source, moose.PoolBase) or isinstance( source, moose.Function): pen.setColor(QtCore.Qt.blue) elif isinstance(source, moose.StimulusTable): pen.setColor(QtCore.Qt.yellow) self.lineItem_dict[qgLineitem] = srcdes_list self.object2line[src].append((qgLineitem, des, endtype, line)) self.object2line[des].append((qgLineitem, src, endtype, line)) qgLineitem.setPen(pen) def positionChange(self, mooseObject): #If the item position changes, the corresponding arrow's are calculated if isinstance(element(mooseObject), ChemCompt): for k, v in self.qGraCompt.items(): mesh = mooseObject if k.path == mesh: for rectChilditem in v.childItems(): if isinstance(rectChilditem, KineticsDisplayItem): if isinstance( moose.element(rectChilditem.mobj.path), PoolBase): t = moose.element(rectChilditem.mobj.path) moose.element(t).children for items in moose.element(t).children: if isinstance(moose.element(items), Function): test = moose.element(items.path + '/x') for i in moose.element( test).neighbors['input']: j = self.mooseId_GObj[ moose.element(i)] self.updateArrow(j) self.updateArrow(rectChilditem) else: mobj = self.mooseId_GObj[element(mooseObject)] self.updateArrow(mobj) elePath = moose.element(mooseObject).path pos = elePath.find('/', 1) l = elePath[0:pos] linfo = moose.Annotator(l + '/info') for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() if linfo.modeltype == "new_kkit": #if newly built model then compartment is size is fixed for some size. comptBoundingRect = v.boundingRect() if not comptBoundingRect.contains(rectcompt): self.updateCompartmentSize(v) else: #if already built model then compartment size depends on max and min objects v.setRect(rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20)) def updateCompartmentSize(self, compartment): compartmentBoundary = compartment.rect() childrenBoundary = compartment.childrenBoundingRect() x = min(compartmentBoundary.x(), childrenBoundary.x()) y = min(compartmentBoundary.y(), childrenBoundary.y()) width = max(compartmentBoundary.width(), childrenBoundary.width()) height = max(compartmentBoundary.height(), childrenBoundary.height()) compartment.setRect(x - 10, y - 10, width + 20, height + 20) def updateArrow(self, qGTextitem): #if there is no arrow to update then return if qGTextitem not in self.object2line: return listItem = self.object2line[qGTextitem] for ql, va, endtype, order in self.object2line[qGTextitem]: srcdes = [] srcdes = self.lineItem_dict[ql] # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz, # if yes then need to check if cplx is connected to any mooseObject, # so that when Enzyme is moved, cplx connected arrow to other mooseObject(poolItem) should also be updated if (type(srcdes[0]) == EnzItem): self.cplxUpdatearrow(srcdes[0]) elif (type(srcdes[1]) == EnzItem): self.cplxUpdatearrow(srcdes[1]) # For calcArrow(src,des,endtype,itemignoreZooming) is to be provided arrow = calcArrow(srcdes, self.itemignoreZooming, self.iconScale) ql.setPolygon(arrow) def cplxUpdatearrow(self, srcdes): # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz) #And cplxItem is passed for updatearrow for item in srcdes.childItems(): if isinstance(item, CplxItem): self.updateArrow(item) # def deleteSolver(self): # print " delete Solver" # print "### ",moose.wildcardFind(self.modelRoot+'/data/graph#/#') # if moose.wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]'): # compt = moose.wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]') # print " deletSolver ", # # print moose.exists(compt[0].path+'/stoich'), " ksolve ", moose.exists(compt[0].path+'/ksolve') # # print "gsolve ", moose.delete( compt[0].path+'/gsolve' ) # if ( moose.exists( compt[0].path+'/stoich' ) ): # #print "delete" # moose.delete( compt[0].path+'/stoich' ) # if ( moose.exists( compt[0].path+'/ksolve' ) ): # moose.delete( compt[0].path+'/ksolve' ) # if ( moose.exists( compt[0].path+'/gsolve' ) ): # moose.delete( compt[0].path+'/gsolve' ) # for x in moose.wildcardFind( self.modelRoot+'/data/graph#/#' ): # x.tick = -1 def positionChange1(self, mooseObject): #If the item position changes, the corresponding arrow's are calculated if ((isinstance(element(mooseObject), CubeMesh)) or (isinstance(element(mooseObject), CylMesh))): v = self.qGraCompt[mooseObject] for rectChilditem in v.childItems(): self.updateArrow(rectChilditem) else: mobj = self.mooseId_GObj[mooseObject.getId()] self.updateArrow(mobj) mooseObjcompt = self.findparent(mooseObject) v = self.qGraCompt[mooseObjcompt] childBoundingRect = v.childrenBoundingRect() comptBoundingRect = v.boundingRect() rectcompt = comptBoundingRect.united(childBoundingRect) comptPen = v.pen() comptWidth = 5 comptPen.setWidth(comptWidth) v.setPen(comptPen) if not comptBoundingRect.contains(childBoundingRect): v.setRect(rectcompt.x() - comptWidth, rectcompt.y() - comptWidth, rectcompt.width() + (comptWidth * 2), rectcompt.height() + (comptWidth * 2))
class KineticsWidget(EditorWidgetBase): def __init__(self, *args): EditorWidgetBase.__init__(self, *args) self.setAcceptDrops(True) self.border = 10 self.sceneContainer = QtGui.QGraphicsScene(self) self.sceneContainer.setSceneRect( self.sceneContainer.itemsBoundingRect()) self.sceneContainer.setBackgroundBrush(QtGui.QColor( 230, 220, 219, 120)) self.insertMenu = QtGui.QMenu('&Insert') self._menus.append(self.insertMenu) self.insertMapper = QtCore.QSignalMapper(self) classlist = [ 'CubeMesh', 'CylMesh', 'Pool', 'FuncPool', 'SumFunc', 'Reac', 'Enz', 'MMenz', 'StimulusTable', 'Table' ] insertMapper, actions = self.getInsertActions(classlist) for action in actions: self.insertMenu.addAction(action) def getToolBars(self): if not hasattr(self, '_insertToolBar'): self._insertToolBar = QtGui.QToolBar('Insert') self._toolBars.append(self._insertToolBar) for action in self.insertMenu.actions(): button = MToolButton() button.setDefaultAction(action) self._insertToolBar.addWidget(button) return self._toolBars def sizeHint(self): return QtCore.QSize(800, 400) def updateModelView(self): #print "update model view",self.modelRoot if self.modelRoot == '/': m = wildcardFind('/##[ISA=ChemCompt]') else: m = wildcardFind(self.modelRoot + '/##[ISA=ChemCompt]') #print "111",self.modelRoot,m if not m: # when we want an empty GraphicView while creating new model, # then remove all the view and add an empty view if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) self.view = GraphicalView(self.sceneContainer, self.border, self) self.layout().addWidget(self.view) else: # maxmium and minimum coordinates of the objects specified in kkit file. self.xmin = 0.0 self.xmax = 1.0 self.ymin = 0.0 self.ymax = 1.0 self.autoCordinatepos = {} self.sceneContainer.clear() # TODO: size will be dummy at this point, but I need the availiable size from the Gui self.size = QtCore.QSize(1024, 768) #self.size = QtCore.QSize(300,400) self.autocoordinates = False # pickled the color map file """ colormap_file = open( os.path.join(config.settings[config.KEY_COLORMAP_DIR], 'rainbow2.pkl'), 'rb') self.colorMap = pickle.load(colormap_file) colormap_file.close() # Compartment and its members are setup """ self.meshEntry, self.xmin, self.xmax, self.ymin, self.ymax, self.noPositionInfo = setupMeshObj( self.modelRoot) # srcdesConnection dictonary will have connection information between src and des """ self.srcdesConnection = {} setupItem(self.modelRoot, self.srcdesConnection) if self.noPositionInfo: self.autocoordinates = True QtGui.QMessageBox.warning( self, 'No coordinates found for the model', '\n Automatic layouting will be done') #raise Exception('Unsupported kkit version') self.xmin, self.xmax, self.ymin, self.ymax, self.autoCordinatepos = autoCoordinates( self.meshEntry, self.srcdesConnection) # Scale factor to translate the x -y position to fit the Qt graphicalScene, scene width. """ if self.xmax - self.xmin != 0: self.xratio = (self.size.width() - 10) / (self.xmax - self.xmin) else: self.xratio = self.size.width() - 10 if self.ymax - self.ymin: self.yratio = (self.size.height() - 10) / (self.ymax - self.ymin) else: self.yratio = (self.size.height() - 10) #A map b/w moose compartment key with QGraphicsObject self.qGraCompt = {} #A map between mooseId of all the mooseObject (except compartment) with QGraphicsObject self.mooseId_GObj = {} self.border = 5 self.arrowsize = 2 self.iconScale = 1 self.defaultComptsize = 5 self.itemignoreZooming = False self.lineItem_dict = {} self.object2line = defaultdict(list) # Compartment and its members are put on the qgraphicsscene self.mooseObjOntoscene() # All the moose Object are connected for visualization self.drawLine_arrow(itemignoreZooming=False) if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget): self.layout().removeWidget(self.view) self.view = GraphicalView(self.sceneContainer, self.border, self) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) #self.layout().addWidget(self.view) def mooseObjOntoscene(self): # All the compartments are put first on to the scene \ # Need to do: Check With upi if empty compartments exist for cmpt in sorted(self.meshEntry.iterkeys()): self.createCompt(cmpt) self.qGraCompt[cmpt] #comptRef = self.qGraCompt[cmpt] #Enzymes of all the compartments are placed first, \ # so that when cplx (which is pool object) queries for its parent, it gets its \ # parent enz co-ordinates with respect to QGraphicsscene """ for cmpt, memb in self.meshEntry.items(): for enzObj in find_index(memb, 'enzyme'): enzinfo = enzObj.path + '/info' if enzObj.className == 'ZEnz': enzItem = EnzItem(enzObj, self.qGraCompt[cmpt]) else: enzItem = MMEnzItem(enzObj, self.qGraCompt[cmpt]) self.setupDisplay(enzinfo, enzItem, "enzyme") self.setupSlot(enzObj, enzItem) for cmpt, memb in self.meshEntry.items(): for poolObj in find_index(memb, 'pool'): poolinfo = poolObj.path + '/info' poolItem = PoolItem(poolObj, self.qGraCompt[cmpt]) self.setupDisplay(poolinfo, poolItem, "pool") self.setupSlot(poolObj, poolItem) for cplxObj in find_index(memb, 'cplx'): cplxinfo = (cplxObj[0].parent).path + '/info' cplxItem = CplxItem( cplxObj, self.mooseId_GObj[element(cplxObj[0]).parent.getId()]) self.setupDisplay(cplxinfo, cplxItem, "cplx") self.setupSlot(cplxObj, cplxItem) for reaObj in find_index(memb, 'reaction'): reainfo = reaObj.path + '/info' reaItem = ReacItem(reaObj, self.qGraCompt[cmpt]) self.setupDisplay(reainfo, reaItem, "reaction") self.setupSlot(reaObj, reaItem) for tabObj in find_index(memb, 'table'): tabinfo = tabObj.path + '/info' tabItem = PoolItem(tabObj, self.qGraCompt[cmpt]) self.setupDisplay(tabinfo, tabItem, "tab") self.setupSlot(tabObj, tabItem) # compartment's rectangle size is calculated depending on children for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20)) v.setPen( QtGui.QPen(Qt.QColor(66, 66, 66, 100), 5, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin)) v.cmptEmitter.connect( v.cmptEmitter, QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"), self.positionChange) v.cmptEmitter.connect( v.cmptEmitter, QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"), self.objectEditSlot) def createCompt(self, key): self.new_Compt = ComptItem(self, 0, 0, 0, 0, key) self.qGraCompt[key] = self.new_Compt self.new_Compt.setRect(10, 10, 10, 10) self.sceneContainer.addItem(self.new_Compt) def setupDisplay(self, info, graphicalObj, objClass): xpos, ypos = self.positioninfo(info) # For Reaction and Complex object I have skipped the process to get the facecolor and background color as \ # we are not using these colors for displaying the object so just passing dummy color white if ((objClass == "reaction") or (objClass == "cplx")): textcolor, bgcolor = "white", "white" elif objClass == "tab": textcolor, bgcolor = getColor(info, self.colorMap) else: textcolor, bgcolor = getColor(info, self.colorMap) graphicalObj.setDisplayProperties(xpos, ypos, textcolor, bgcolor) def positioninfo(self, iteminfo): if self.noPositionInfo: try: # kkit does exist item's/info which up querying for parent.path gives the information of item's parent x, y = self.autoCordinatepos[(element(iteminfo).parent).path] except: # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\ # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\ # type of the object (rea,pool,enz,cplx,tab) which I have already done. parent, child = posixpath.split(iteminfo) x, y = self.autoCordinatepos[parent] ypos = (y - self.ymin) * self.yratio else: x = float(element(iteminfo).getField('x')) y = float(element(iteminfo).getField('y')) #Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \ #as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated ypos = -(y - self.ymin) * self.yratio xpos = (x - self.xmin) * self.xratio return (xpos, ypos) def setupSlot(self, mooseObj, qgraphicItem): self.mooseId_GObj[element(mooseObj).getId()] = qgraphicItem qgraphicItem.connect( qgraphicItem, QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"), self.positionChange) qgraphicItem.connect( qgraphicItem, QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"), self.objectEditSlot) def updateItemSlot(self, mooseObject): #This is overridden by derived classes to connect appropriate #slot for updating the display item. #In this case if the name is updated from the keyboard both in mooseobj and gui gets updation changedItem = '' for item in self.sceneContainer.items(): if isinstance(item, PoolItem): if mooseObject.getId() == element(item.mobj).getId(): item.updateSlot() #once the text is edited in editor, laydisplay gets updated in turn resize the length, positionChanged signal shd be emitted self.positionChange(mooseObject) def positionChange(self, mooseObject): #If the item position changes, the corresponding arrow's are calculated if isinstance(element(mooseObject), CubeMesh): for k, v in self.qGraCompt.items(): mesh = mooseObject.path + '/mesh[0]' if k.path == mesh: for rectChilditem in v.childItems(): self.updateArrow(rectChilditem) else: mobj = self.mooseId_GObj[mooseObject.getId()] self.updateArrow(mobj) for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20)) def emitItemtoEditor(self, mooseObject): #self.emit(QtCore.SIGNAL("itemPressed(PyQt_PyObject)"),mooseObject) self.editObject.emit(mooseObject.path) def drawLine_arrow(self, itemignoreZooming=False): for inn, out in self.srcdesConnection.items(): # self.srcdesConnection is dictionary which contains key,value \ # key is Enzyme or Reaction and value [[list of substrate],[list of product]] (tuple) # key is FuncBase and value is [list of pool] (list) #src = self.mooseId_GObj[inn] if isinstance(out, tuple): if len(out[0]) == 0: print inn.className + ':' + inn[ 0].name + " doesn't output message" else: src = self.mooseId_GObj[inn] for items in (items for items in out[0]): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src, des, items, itemignoreZooming) if len(out[1]) == 0: print inn.className + ':' + inn[ 0].name + " doesn't output message" else: for items in (items for items in out[1]): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src, des, items, itemignoreZooming) elif isinstance(out, list): if len(out) == 0: print "Func pool doesn't have sumtotal" else: src = self.mooseId_GObj[element(inn).getId()] for items in (items for items in out): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src, des, items, itemignoreZooming) def lineCord(self, src, des, type_no, itemignoreZooming): endtype = type_no[1] line = 0 if (src == "") and (des == ""): print "Source or destination is missing or incorrect" return srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) while (type_no[2] > 1 and line <= (type_no[2] - 1)): srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) line = line + 1 if type_no[2] > 5: print "Higher order reaction will not be displayed" def drawLine(self, srcdes_list, arrow): src = srcdes_list[0] des = srcdes_list[1] endtype = srcdes_list[2] line = srcdes_list[3] source = element( next((k for k, v in self.mooseId_GObj.items() if v == src), None)) for l, v, o in self.object2line[src]: if v == des and o == line: l.setPolygon(arrow) arrowPen = l.pen() arrowPenWidth = self.arrowsize * self.iconScale arrowPen.setColor(l.pen().color()) arrowPen.setWidth(arrowPenWidth) l.setPen(arrowPen) return qgLineitem = self.sceneContainer.addPolygon(arrow) pen = QtGui.QPen(QtCore.Qt.green, 0, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin) pen.setWidth(self.arrowsize) #pen.setCosmetic(True) # Green is default color moose.ReacBase and derivatives - already set above if isinstance(source, EnzBase): if ((endtype == 's') or (endtype == 'p')): pen.setColor(QtCore.Qt.red) elif (endtype != 'cplx'): p1 = (next( (k for k, v in self.mooseId_GObj.items() if v == src), None)) pinfo = p1.path + '/info' color, bgcolor = getColor(pinfo, self.colorMap) pen.setColor(color) elif isinstance(source, moose.PoolBase): pen.setColor(QtCore.Qt.blue) elif isinstance(source, moose.StimulusTable): pen.setColor(QtCore.Qt.yellow) self.lineItem_dict[qgLineitem] = srcdes_list self.object2line[src].append((qgLineitem, des, line)) self.object2line[des].append((qgLineitem, src, line)) qgLineitem.setPen(pen) def updateArrow(self, qGTextitem): #if there is no arrow to update then return if qGTextitem not in self.object2line: return listItem = self.object2line[qGTextitem] for ql, va, order in self.object2line[qGTextitem]: srcdes = [] srcdes = self.lineItem_dict[ql] # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz, # if yes then need to check if cplx is connected to any mooseObject, # so that when Enzyme is moved, cplx connected arrow to other mooseObject(poolItem) should also be updated if (type(srcdes[0]) == EnzItem): self.cplxUpdatearrow(srcdes[0]) elif (type(srcdes[1]) == EnzItem): self.cplxUpdatearrow(srcdes[1]) # For calcArrow(src,des,endtype,itemignoreZooming) is to be provided arrow = calcArrow(srcdes, self.itemignoreZooming, self.iconScale) ql.setPolygon(arrow) def cplxUpdatearrow(self, srcdes): # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz) #And cplxItem is passed for updatearrow #Note: Here at this point enzItem has just one child which is cplxItem and childItems returns, PyQt5.QtGui.QGraphicsEllipseItem,CplxItem #Assuming CplxItem is always[1], but still check if not[0], if something changes in structure one need to keep an eye. if (srcdes.childItems()[1], CplxItem): self.updateArrow(srcdes.childItems()[1]) else: self.updateArrow(srcdes.childItems()[0]) def keyPressEvent(self, event): # key1 = event.key() # key event does not distinguish between capital and non-capital letters key = event.text().toAscii().toHex() if key == '41': # 'A' fits the view to iconScale factor itemignoreZooming = False self.updateItemTransformationMode(itemignoreZooming) self.view.fitInView( self.sceneContainer.itemsBoundingRect().x() - 10, self.sceneContainer.itemsBoundingRect().y() - 10, self.sceneContainer.itemsBoundingRect().width() + 20, self.sceneContainer.itemsBoundingRect().height() + 20, Qt.Qt.IgnoreAspectRatio) self.drawLine_arrow(itemignoreZooming=False) elif (key == '2e'): # '.' key, lower case for '>' zooms in self.view.scale(1.1, 1.1) elif (key == '2c'): # ',' key, lower case for '<' zooms in self.view.scale(1 / 1.1, 1 / 1.1) elif (key == '3c'): # '<' key. zooms-in to iconScale factor self.iconScale *= 0.8 self.updateScale(self.iconScale) elif (key == '3e'): # '>' key. zooms-out to iconScale factor self.iconScale *= 1.25 self.updateScale(self.iconScale) elif (key == '61' ): # 'a' fits the view to initial value where iconscale=1 self.iconScale = 1 self.updateScale(self.iconScale) self.view.fitInView( self.sceneContainer.itemsBoundingRect().x() - 10, self.sceneContainer.itemsBoundingRect().y() - 10, self.sceneContainer.itemsBoundingRect().width() + 20, self.sceneContainer.itemsBoundingRect().height() + 20, Qt.Qt.IgnoreAspectRatio) def updateItemTransformationMode(self, on): for v in self.sceneContainer.items(): if (not isinstance(v, ComptItem)): #if ( isinstance(v, PoolItem) or isinstance(v, ReacItem) or isinstance(v, EnzItem) or isinstance(v, CplxItem) ): if isinstance(v, KineticsDisplayItem): v.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations, on) def updateScale(self, scale): for item in self.sceneContainer.items(): if isinstance(item, KineticsDisplayItem): item.refresh(scale) #iteminfo = item.mobj.path+'/info' #xpos,ypos = self.positioninfo(iteminfo) xpos = item.scenePos().x() ypos = item.scenePos().y() if isinstance(item, ReacItem) or isinstance( item, EnzItem) or isinstance(item, MMEnzItem): item.setGeometry(xpos, ypos, item.gobj.boundingRect().width(), item.gobj.boundingRect().height()) elif isinstance(item, CplxItem): item.setGeometry(item.gobj.boundingRect().width() / 2, item.gobj.boundingRect().height(), item.gobj.boundingRect().width(), item.gobj.boundingRect().height()) elif isinstance(item, PoolItem): item.setGeometry( xpos, ypos, item.gobj.boundingRect().width() + PoolItem.fontMetrics.width(' '), item.gobj.boundingRect().height()) item.bg.setRect( 0, 0, item.gobj.boundingRect().width() + PoolItem.fontMetrics.width(' '), item.gobj.boundingRect().height()) self.drawLine_arrow(itemignoreZooming=False) for k, v in self.qGraCompt.items(): rectcompt = v.childrenBoundingRect() comptPen = v.pen() comptWidth = self.defaultComptsize * self.iconScale comptPen.setWidth(comptWidth) v.setPen(comptPen) v.setRect(rectcompt.x() - comptWidth, rectcompt.y() - comptWidth, (rectcompt.width() + 2 * comptWidth), (rectcompt.height() + 2 * comptWidth))