src/eric7/EricGraphics/EricArrowItem.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2007 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a graphics item subclass for an arrow.
8 """
9
10 import enum
11 import math
12
13 from PyQt6.QtCore import QPointF, QRectF, QSizeF, QLineF, Qt
14 from PyQt6.QtGui import QPen, QPolygonF, QColor
15 from PyQt6.QtWidgets import QAbstractGraphicsShapeItem, QGraphicsItem, QStyle
16
17 ArrowheadAngleFactor = 0.26179938779914941
18 # That is: 0.5 * math.atan(math.sqrt(3.0) / 3.0)
19
20
21 class EricArrowType(enum.Enum):
22 """
23 Class defining the arrow types.
24 """
25 NORMAL = 1
26 WIDE = 2
27
28
29 class EricArrowItem(QAbstractGraphicsShapeItem):
30 """
31 Class implementing an arrow graphics item subclass.
32 """
33 def __init__(self, origin=None, end=None,
34 filled=False, arrowType=EricArrowType.NORMAL, colors=None,
35 parent=None):
36 """
37 Constructor
38
39 @param origin origin of the arrow
40 @type QPointF
41 @param end end point of the arrow
42 @type QPointF
43 @param filled flag indicating a filled arrow head
44 @type bool
45 @param arrowType arrow type
46 @type EricArrowType
47 @param colors tuple containing the foreground and background colors
48 @type tuple of (QColor, QColor)
49 @param parent reference to the parent object
50 @type QGraphicsItem
51 """
52 super().__init__(parent)
53
54 self._origin = QPointF() if origin is None else QPointF(origin)
55 self._end = QPointF() if end is None else QPointF(end)
56 self._filled = filled
57 self.__type = arrowType
58
59 if colors is None:
60 self._colors = (QColor(Qt.GlobalColor.black),
61 QColor(Qt.GlobalColor.white))
62 else:
63 self._colors = colors
64
65 self._halfLength = 13.0
66
67 self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, True)
68 self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, True)
69
70 def setPoints(self, xa, ya, xb, yb):
71 """
72 Public method to set the start and end points of the line.
73
74 <b>Note:</b> This method does not redraw the item.
75
76 @param xa x-coordinate of the start point (float)
77 @param ya y-coordinate of the start point (float)
78 @param xb x-coordinate of the end point (float)
79 @param yb y-coordinate of the end point (float)
80 """
81 self._origin = QPointF(xa, ya)
82 self._end = QPointF(xb, yb)
83
84 def setStartPoint(self, x, y):
85 """
86 Public method to set the start point.
87
88 <b>Note:</b> This method does not redraw the item.
89
90 @param x x-coordinate of the start point (float)
91 @param y y-coordinate of the start point (float)
92 """
93 self._origin = QPointF(x, y)
94
95 def setEndPoint(self, x, y):
96 """
97 Public method to set the end point.
98
99 <b>Note:</b> This method does not redraw the item.
100
101 @param x x-coordinate of the end point (float)
102 @param y y-coordinate of the end point (float)
103 """
104 self._end = QPointF(x, y)
105
106 def boundingRect(self):
107 """
108 Public method to return the bounding rectangle.
109
110 @return bounding rectangle (QRectF)
111 """
112 extra = self._halfLength / 2.0
113 return QRectF(self._origin, QSizeF(self._end.x() - self._origin.x(),
114 self._end.y() - self._origin.y())
115 ).normalized().adjusted(-extra, -extra, extra, extra)
116
117 def paint(self, painter, option, widget=None):
118 """
119 Public method to paint the item in local coordinates.
120
121 @param painter reference to the painter object (QPainter)
122 @param option style options (QStyleOptionGraphicsItem)
123 @param widget optional reference to the widget painted on (QWidget)
124 """
125 width = 2 if (
126 (option.state & QStyle.StateFlag.State_Selected) ==
127 QStyle.StateFlag.State_Selected
128 ) else 1
129
130 # draw the line first
131 line = QLineF(self._origin, self._end)
132 painter.setPen(
133 QPen(self._colors[0], width, Qt.PenStyle.SolidLine,
134 Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
135 painter.drawLine(line)
136
137 # draw the arrow head
138 arrowAngle = (
139 ArrowheadAngleFactor
140 if self.__type == EricArrowType.NORMAL else
141 2 * ArrowheadAngleFactor
142 )
143 slope = math.atan2(line.dy(), line.dx())
144
145 # Calculate left arrow point
146 arrowSlope = slope + arrowAngle
147 a1 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope),
148 self._end.y() - self._halfLength * math.sin(arrowSlope))
149
150 # Calculate right arrow point
151 arrowSlope = slope - arrowAngle
152 a2 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope),
153 self._end.y() - self._halfLength * math.sin(arrowSlope))
154
155 if self._filled:
156 painter.setBrush(self._colors[0])
157 else:
158 painter.setBrush(self._colors[1])
159 polygon = QPolygonF()
160 polygon.append(line.p2())
161 polygon.append(a1)
162 polygon.append(a2)
163 painter.drawPolygon(polygon)

eric ide

mercurial