# -*- coding: utf-8 -*-"""The Tk graphical representation of an edge in the graph, i.e. anarrow connecting nodes.The information is stored in the graph object as attributes of theedge so that the graphical representation can be restored as needed."""importloggingimportmathimportseammfromtkinterimportfontimporttkinterastkimportweakreflogger=logging.getLogger(__name__)
[docs]classTkEdge(seamm.Edge):str_to_object=weakref.WeakValueDictionary()def__init__(self,graph,node1,node2,edge_type="execution",edge_subtype="next",canvas=None,anchor1="s",anchor2="n",coords=None,**kwargs):"""Initialize the edge, ensuring that it is in the graph. Keyword arguments: """self._data=[]logger.debug("Creating TkEdge {}".format(self))logger.debug("\tnode1 = {}".format(node1))logger.debug("\tnode2 = {}".format(node2))# Initialize the parent classsuper().__init__(graph,node1,node2,edge_type,edge_subtype,**kwargs)self._data["canvas"]=canvasself.anchor1=anchor1self.anchor2=anchor2ifcoordsisNone:x0,y0=self.node1.anchor_point(self.anchor1)x1,y1=self.node2.anchor_point(self.anchor2)self.coords=[x0,y0,x1,y1]else:self.coords=coords# Remember the object so can get from tags on the canvasTkEdge.str_to_object[str(id(self))]=self# Arrange that the graphics are deleted when we areself._finalizer=weakref.finalize(self,self.canvas.delete,self.tag())self._finalizer.atexit=Falsedef__eq__(self,other):"""Return a boolean if this object is equal to another"""returnsuper().__eq__(other)@propertydefcanvas(self):returnself._data["canvas"]@propertydefanchor1(self):returnself._data["anchor1"]@anchor1.setterdefanchor1(self,value):self._data["anchor1"]=value@propertydefanchor2(self):returnself._data["anchor2"]@anchor2.setterdefanchor2(self,value):self._data["anchor2"]=value@propertydefcoords(self):returnself._data["coords"]@coords.setterdefcoords(self,value):self._data["coords"]=value@propertydefhas_label(self):return"label_id"inself._data@propertydeflabel_id(self):returnself._data["label_id"]@propertydeflabel_bg_id(self):returnself._data["label_bg_id"]
[docs]deftag(self):"""Return a string tag for self"""return"edge="+str(id(self))
[docs]defdraw(self):"""Draw the arrow for this edge"""self.move()
[docs]defmove(self):"""Redraw the arrow when the nodes have moved"""x0,y0=self.node1.anchor_point(self.anchor1)x1,y1=self.node2.anchor_point(self.anchor2)self.coords[0]=x0self.coords[1]=y0self.coords[-2]=x1self.coords[-1]=y1# the arrowself.canvas.delete(self.tag()+"&& type=arrow")arrow_id=self.canvas.create_line(self.coords,arrow=tk.LAST,tags=[self.tag(),"type=arrow"])self._data["arrow_id"]=arrow_id# and the labelifself.edge_subtype!="next":self.canvas.delete(self.tag()+"&& type=label")text=self.canvas.create_text(self.label_position(x0,y0,x1,y1),text=self.edge_subtype,font=font.Font(family="Helvetica",size=8),tags=[self.tag(),"type=label"],)self._data["label_id"]=textself.canvas.delete(self.tag()+"&& type=label_bg")bg=self.canvas.create_rectangle(self.canvas.bbox(text),outline="white",fill="white",tags=[self.tag(),"type=label_bg"],)self._data["label_bg_id"]=bgself.canvas.tag_lower(bg,text)
[docs]deflabel_position(self,x0,y0,x1,y1,offset=15):"""Work out the position for the label on an edge"""dx=x1-x0dy=y1-y0length=math.sqrt(dx*dx+dy*dy)iflength<2*offset:offset=int(length/2)xy=[x0ifdx==0.0elsex0+dx/length*offset,y0ifdy==0.0elsey0+dy/length*offset,]returnxy
[docs]defundraw(self):"""Remove any graphics"""self.canvas.delete(self.tag())if"arrow_id"inself._data:delself._data["arrow_id"]if"label_id"inself._data:delself._data["label_id"]if"label_bg_id"inself._data:delself._data["label_bg_id"]