eric7/EricGraphics/EricArrowItem.py

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

eric ide

mercurial