eric7/E5Graphics/E5ArrowItem.py

branch
eric7
changeset 8312
800c432b34c8
parent 8268
6b8128e0c9d1
child 8318
962bce857696
diff -r 4e8b98454baa -r 800c432b34c8 eric7/E5Graphics/E5ArrowItem.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/E5Graphics/E5ArrowItem.py	Sat May 15 18:45:04 2021 +0200
@@ -0,0 +1,163 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a graphics item subclass for an arrow.
+"""
+
+import enum
+import math
+
+from PyQt5.QtCore import QPointF, QRectF, QSizeF, QLineF, Qt
+from PyQt5.QtGui import QPen, QPolygonF, QColor
+from PyQt5.QtWidgets import QAbstractGraphicsShapeItem, QGraphicsItem, QStyle
+
+ArrowheadAngleFactor = 0.26179938779914941
+# That is: 0.5 * math.atan(math.sqrt(3.0) / 3.0)
+
+
+class E5ArrowType(enum.Enum):
+    """
+    Class defining the arrow types.
+    """
+    NORMAL = 1
+    WIDE = 2
+
+
+class E5ArrowItem(QAbstractGraphicsShapeItem):
+    """
+    Class implementing an arrow graphics item subclass.
+    """
+    def __init__(self, origin=None, end=None,
+                 filled=False, arrowType=E5ArrowType.NORMAL, colors=None,
+                 parent=None):
+        """
+        Constructor
+        
+        @param origin origin of the arrow
+        @type QPointF
+        @param end end point of the arrow
+        @type QPointF
+        @param filled flag indicating a filled arrow head
+        @type bool
+        @param arrowType arrow type
+        @type E5ArrowType
+        @param colors tuple containing the foreground and background colors
+        @type tuple of (QColor, QColor)
+        @param parent reference to the parent object
+        @type QGraphicsItem
+        """
+        super().__init__(parent)
+        
+        self._origin = QPointF() if origin is None else QPointF(origin)
+        self._end = QPointF() if end is None else QPointF(end)
+        self._filled = filled
+        self.__type = arrowType
+        
+        if colors is None:
+            self._colors = (QColor(Qt.GlobalColor.black),
+                            QColor(Qt.GlobalColor.white))
+        else:
+            self._colors = colors
+        
+        self._halfLength = 13.0
+        
+        self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, True)
+        self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, True)
+        
+    def setPoints(self, xa, ya, xb, yb):
+        """
+        Public method to set the start and end points of the line.
+        
+        <b>Note:</b> This method does not redraw the item.
+        
+        @param xa x-coordinate of the start point (float)
+        @param ya y-coordinate of the start point (float)
+        @param xb x-coordinate of the end point (float)
+        @param yb y-coordinate of the end point (float)
+        """
+        self._origin = QPointF(xa, ya)
+        self._end = QPointF(xb, yb)
+        
+    def setStartPoint(self, x, y):
+        """
+        Public method to set the start point.
+        
+        <b>Note:</b> This method does not redraw the item.
+        
+        @param x x-coordinate of the start point (float)
+        @param y y-coordinate of the start point (float)
+        """
+        self._origin = QPointF(x, y)
+        
+    def setEndPoint(self, x, y):
+        """
+        Public method to set the end point.
+        
+        <b>Note:</b> This method does not redraw the item.
+        
+        @param x x-coordinate of the end point (float)
+        @param y y-coordinate of the end point (float)
+        """
+        self._end = QPointF(x, y)
+        
+    def boundingRect(self):
+        """
+        Public method to return the bounding rectangle.
+        
+        @return bounding rectangle (QRectF)
+        """
+        extra = self._halfLength / 2.0
+        return QRectF(self._origin, QSizeF(self._end.x() - self._origin.x(),
+                                           self._end.y() - self._origin.y())
+                      ).normalized().adjusted(-extra, -extra, extra, extra)
+        
+    def paint(self, painter, option, widget=None):
+        """
+        Public method to paint the item in local coordinates.
+        
+        @param painter reference to the painter object (QPainter)
+        @param option style options (QStyleOptionGraphicsItem)
+        @param widget optional reference to the widget painted on (QWidget)
+        """
+        width = 2 if (
+            (option.state & QStyle.StateFlag.State_Selected) ==
+            QStyle.State(QStyle.StateFlag.State_Selected)
+        ) else 1
+        
+        # draw the line first
+        line = QLineF(self._origin, self._end)
+        painter.setPen(
+            QPen(self._colors[0], width, Qt.PenStyle.SolidLine,
+                 Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
+        painter.drawLine(line)
+        
+        # draw the arrow head
+        arrowAngle = (
+            ArrowheadAngleFactor
+            if self.__type == E5ArrowType.NORMAL else
+            2 * ArrowheadAngleFactor
+        )
+        slope = math.atan2(line.dy(), line.dx())
+        
+        # Calculate left arrow point
+        arrowSlope = slope + arrowAngle
+        a1 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope),
+                     self._end.y() - self._halfLength * math.sin(arrowSlope))
+        
+        # Calculate right arrow point
+        arrowSlope = slope - arrowAngle
+        a2 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope),
+                     self._end.y() - self._halfLength * math.sin(arrowSlope))
+        
+        if self._filled:
+            painter.setBrush(self._colors[0])
+        else:
+            painter.setBrush(self._colors[1])
+        polygon = QPolygonF()
+        polygon.append(line.p2())
+        polygon.append(a1)
+        polygon.append(a2)
+        painter.drawPolygon(polygon)

eric ide

mercurial