Source code for seamm.tk_edge

# -*- coding: utf-8 -*-

"""The Tk graphical representation of an edge in the graph, i.e. an
arrow connecting nodes.

The information is stored in the graph object as attributes of the
edge so that the graphical representation can be restored as needed.
"""

import logging
import math
import seamm
from tkinter import font
import tkinter as tk
import weakref

logger = logging.getLogger(__name__)


[docs] class TkEdge(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 class super().__init__(graph, node1, node2, edge_type, edge_subtype, **kwargs) self._data["canvas"] = canvas self.anchor1 = anchor1 self.anchor2 = anchor2 if coords is None: 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 canvas TkEdge.str_to_object[str(id(self))] = self # Arrange that the graphics are deleted when we are self._finalizer = weakref.finalize(self, self.canvas.delete, self.tag()) self._finalizer.atexit = False def __eq__(self, other): """Return a boolean if this object is equal to another""" return super().__eq__(other) @property def canvas(self): return self._data["canvas"] @property def anchor1(self): return self._data["anchor1"] @anchor1.setter def anchor1(self, value): self._data["anchor1"] = value @property def anchor2(self): return self._data["anchor2"] @anchor2.setter def anchor2(self, value): self._data["anchor2"] = value @property def coords(self): return self._data["coords"] @coords.setter def coords(self, value): self._data["coords"] = value @property def has_label(self): return "label_id" in self._data @property def label_id(self): return self._data["label_id"] @property def label_bg_id(self): return self._data["label_bg_id"]
[docs] def tag(self): """Return a string tag for self""" return "edge=" + str(id(self))
[docs] def draw(self): """Draw the arrow for this edge""" self.move()
[docs] def move(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] = x0 self.coords[1] = y0 self.coords[-2] = x1 self.coords[-1] = y1 # the arrow self.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 label if self.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"] = text self.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"] = bg self.canvas.tag_lower(bg, text)
[docs] def label_position(self, x0, y0, x1, y1, offset=15): """Work out the position for the label on an edge""" dx = x1 - x0 dy = y1 - y0 length = math.sqrt(dx * dx + dy * dy) if length < 2 * offset: offset = int(length / 2) xy = [ x0 if dx == 0.0 else x0 + dx / length * offset, y0 if dy == 0.0 else y0 + dy / length * offset, ] return xy
[docs] def undraw(self): """Remove any graphics""" self.canvas.delete(self.tag()) if "arrow_id" in self._data: del self._data["arrow_id"] if "label_id" in self._data: del self._data["label_id"] if "label_bg_id" in self._data: del self._data["label_bg_id"]