Skip to content
Snippets Groups Projects
arrow.py 7.27 KiB
Newer Older
  • Learn to ignore specific revisions
  • from qtpy.QtCore import QPointF
    
    from qtpy.QtGui import QPen, QPainterPath
    from qtpy.QtWidgets import QGraphicsPathItem, QMenu
    
    from b_asic.GUI._preferences import GRID, LINECOLOR, PORTHEIGHT, PORTWIDTH
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
    
    
    class Arrow(QGraphicsPathItem):
    
        """Arrow/connection in signal flow graph GUI."""
    
    
        def __init__(self, source, destination, window, signal=None, parent=None):
    
            """
            Parameters
            ==========
    
            source :
                Source operation.
            destination :
                Destination operation.
            window :
                Window containing signal flow graph.
            signal : Signal, optional
                Let arrow represent *signal*.
            parent : optional
                Parent.
            """
    
            super().__init__(parent)
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
            if signal is None:
                signal = Signal(source.port, destination.port)
            self.signal = signal
    
            self.destination = destination
            self._window = window
            self.moveLine()
            self.source.moved.connect(self.moveLine)
            self.destination.moved.connect(self.moveLine)
    
        def contextMenuEvent(self, event):
    
            """Open right-click menu."""
    
            menu = QMenu()
            menu.addAction("Delete", self.remove)
            menu.exec_(self.cursor().pos())
    
        def remove(self):
    
            """Remove line and connections to signals etc."""
    
            self.signal.remove_destination()
            self.signal.remove_source()
            self._window.scene.removeItem(self)
            if self in self._window.signalList:
                self._window.signalList.remove(self)
    
            if self in self._window.signalPortDict:
                for port1, port2 in self._window.signalPortDict[self]:
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
                    for (
                        operation,
                        operation_ports,
                    ) in self._window.portDict.items():
                        if (
                            port1 in operation_ports or port2 in operation_ports
                        ) and operation in self._window.opToSFG:
                            self._window.logger.info(
                                "Operation detected in existing SFG, removing SFG"
                                " with name:"
                                f" {self._window.opToSFG[operation].name}."
                            )
                            del self._window.sfg_dict[
                                self._window.opToSFG[operation].name
                            ]
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
                            self._window.opToSFG = {
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
                                op: self._window.opToSFG[op]
                                for op in self._window.opToSFG
                                if self._window.opToSFG[op]
                                is not self._window.opToSFG[operation]
                            }
    
    
            del self._window.signalPortDict[self]
    
        def moveLine(self):
    
            """
            Draw a line connecting self.source with self.destination. Used as callback when moving operations.
            """
    
            ORTHOGONAL = True
            OFFSET = 2 * PORTWIDTH
    
            self.setPen(QPen(LINECOLOR, 3))
    
            source_flipped = self.source.operation.is_flipped()
            destination_flipped = self.destination.operation.is_flipped()
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
            x0 = (
                self.source.operation.x()
                + self.source.x()
                + (PORTWIDTH if not source_flipped else 0)
            )
    
            y0 = self.source.operation.y() + self.source.y() + PORTHEIGHT / 2
    
    Oscar Gustafsson's avatar
    Oscar Gustafsson committed
            x1 = (
                self.destination.operation.x()
                + self.destination.x()
                + (0 if not destination_flipped else PORTWIDTH)
            )
    
            y1 = (
                self.destination.operation.y()
                + self.destination.y()
                + PORTHEIGHT / 2
            )
            xmid = (x0 + x1) / 2
            ymid = (y0 + y1) / 2
    
            both_flipped = source_flipped and destination_flipped
            any_flipped = source_flipped or destination_flipped
    
            p = QPainterPath(QPointF(x0, y0))
    
            # TODO: Simplify or create a better router
            if not ORTHOGONAL:
    
            elif y0 == y1:
                if not any_flipped:
                    if x0 <= x1:
                        pass
                    else:
                        p.lineTo(QPointF(x0 + OFFSET, y0))
                        p.lineTo(QPointF(x0 + OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(x1 - OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(x1 - OFFSET, y0))
                elif both_flipped:
                    if x1 <= x0:
                        pass
                    else:
                        p.lineTo(QPointF(x0 + OFFSET, y0))
                        p.lineTo(QPointF(x0 + OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(x1 - OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(x1 - OFFSET, y0))
                elif source_flipped:
                    if x0 <= x1:
                        p.lineTo(QPointF(x0 - OFFSET, y0))
                        p.lineTo(QPointF(x0 - OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(xmid, y0 + OFFSET))
                        p.lineTo(QPointF(xmid, y0))
                    else:
                        p.lineTo(QPointF(x0 + OFFSET, y0))
                        p.lineTo(QPointF(x0 + OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(xmid, y0 + OFFSET))
                        p.lineTo(QPointF(xmid, y0))
                else:
                    if x1 <= x0:
                        p.lineTo(QPointF(x0 + OFFSET, y0))
                        p.lineTo(QPointF(x0 + OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(xmid, y0 + OFFSET))
                        p.lineTo(QPointF(xmid, y0))
                    else:
                        p.lineTo(QPointF(xmid, y0))
                        p.lineTo(QPointF(xmid, y0 + OFFSET))
                        p.lineTo(QPointF(x1 + OFFSET, y0 + OFFSET))
                        p.lineTo(QPointF(x1 + OFFSET, y0))
    
            elif abs(x0 - x1) <= GRID:
                if both_flipped or not any_flipped:
                    offset = -OFFSET if both_flipped else OFFSET
                    p.lineTo(QPointF(x0 + offset, y0))
                    p.lineTo(QPointF(x0 + offset, ymid))
                    p.lineTo(QPointF(x0 - offset, ymid))
                    p.lineTo(QPointF(x0 - offset, y1))
                else:
                    offset = -OFFSET if source_flipped else -OFFSET
                    p.lineTo(QPointF(x0 + offset, y0))
                    p.lineTo(QPointF(x0 + offset, y1))
    
                if not any_flipped:
                    if x0 <= x1:
                        p.lineTo(QPointF(xmid, y0))
                        p.lineTo(QPointF(xmid, y1))
                    else:
                        p.lineTo(x0 + OFFSET, y0)
                        p.lineTo(x0 + OFFSET, ymid)
                        p.lineTo(x1 - OFFSET, ymid)
                        p.lineTo(x1 - OFFSET, y1)
                elif both_flipped:
                    if x0 >= x1:
                        p.lineTo(QPointF(xmid, y0))
                        p.lineTo(QPointF(xmid, y1))
                    else:
                        p.lineTo(x0 - OFFSET, y0)
                        p.lineTo(x0 - OFFSET, ymid)
                        p.lineTo(x1 + OFFSET, ymid)
                        p.lineTo(x1 + OFFSET, y1)
                elif source_flipped:
                    xmin = min(x0, x1) - OFFSET
                    p.lineTo(QPointF(xmin, y0))
                    p.lineTo(QPointF(xmin, y1))
                else:
                    xmax = max(x0, x1) + OFFSET
                    p.lineTo(QPointF(xmax, y0))
                    p.lineTo(QPointF(xmax, y1))
    
    
            p.lineTo(QPointF(x1, y1))
            self.setPath(p)