1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <private/boxwhiskers_p.h>
5#include <QtGui/QPainter>
6#include <QtWidgets/QWidget>
7#include <QtWidgets/QGraphicsSceneMouseEvent>
8
9QT_BEGIN_NAMESPACE
10
11BoxWhiskers::BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent) :
12 QGraphicsObject(parent),
13 m_boxSet(set),
14 m_domain(domain),
15 m_mousePressed(false)
16{
17 setAcceptHoverEvents(true);
18 setAcceptedMouseButtons(Qt::MouseButtonMask);
19 setFlag(flag: QGraphicsObject::ItemIsSelectable);
20}
21
22BoxWhiskers::~BoxWhiskers()
23{
24}
25
26void BoxWhiskers::mousePressEvent(QGraphicsSceneMouseEvent *event)
27{
28 Q_UNUSED(event);
29 emit pressed(boxset: m_boxSet);
30 m_mousePressed = true;
31}
32
33void BoxWhiskers::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
34{
35 Q_UNUSED(event);
36 emit hovered(status: true, boxset: m_boxSet);
37}
38
39void BoxWhiskers::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
40{
41 Q_UNUSED(event);
42 emit hovered(status: false, boxset: m_boxSet);
43}
44
45void BoxWhiskers::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
46{
47 Q_UNUSED(event);
48 emit released(boxset: m_boxSet);
49 if (m_mousePressed)
50 emit clicked(boxset: m_boxSet);
51}
52
53void BoxWhiskers::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
54{
55 Q_UNUSED(event);
56 // For Box a press signal needs to be explicitly fired for mouseDoubleClickEvent
57 emit pressed(boxset: m_boxSet);
58 emit doubleClicked(boxset: m_boxSet);
59}
60
61void BoxWhiskers::setBrush(const QBrush &brush)
62{
63 m_brush = brush;
64 m_outlinePen.setColor(m_brush.color());
65 update();
66}
67
68void BoxWhiskers::setPen(const QPen &pen)
69{
70 qreal widthDiff = pen.widthF() - m_pen.widthF();
71 m_boundingRect.adjust(xp1: -widthDiff, yp1: -widthDiff, xp2: widthDiff, yp2: widthDiff);
72
73 m_pen = pen;
74 m_medianPen = pen;
75 m_medianPen.setCapStyle(Qt::FlatCap);
76 m_outlinePen = pen;
77 m_outlinePen.setStyle(Qt::SolidLine);
78 m_outlinePen.setColor(m_brush.color());
79
80 update();
81}
82
83void BoxWhiskers::setBoxWidth(const qreal width)
84{
85 m_boxWidth = width;
86}
87
88void BoxWhiskers::setLayout(const BoxWhiskersData &data)
89{
90 m_data = data;
91
92 updateGeometry(domain: m_domain);
93 update();
94}
95
96QSizeF BoxWhiskers::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
97{
98 Q_UNUSED(which);
99 Q_UNUSED(constraint);
100
101 return QSizeF();
102}
103
104void BoxWhiskers::setGeometry(const QRectF &rect)
105{
106 Q_UNUSED(rect);
107}
108
109QRectF BoxWhiskers::boundingRect() const
110{
111 return m_boundingRect;
112}
113
114void BoxWhiskers::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
115{
116 Q_UNUSED(option);
117 Q_UNUSED(widget);
118
119 painter->save();
120 painter->setBrush(m_brush);
121 painter->setClipRect(parentItem()->boundingRect());
122 painter->setPen(m_pen);
123 painter->drawPath(path: m_boxPath);
124 if (!m_boxOutlined)
125 painter->setPen(m_outlinePen);
126 painter->drawRect(rect: m_middleBox);
127 painter->setPen(m_medianPen);
128 qreal halfLine = m_pen.widthF() / 2.0;
129 painter->drawLine(l: QLineF(m_geometryLeft - halfLine, m_geometryMedian,
130 m_geometryRight + halfLine, m_geometryMedian));
131 painter->restore();
132}
133
134void BoxWhiskers::updateGeometry(AbstractDomain *domain)
135{
136 m_domain = domain;
137
138 prepareGeometryChange();
139
140 QPainterPath path;
141 m_boxPath = path;
142 m_boundingRect = m_boxPath.boundingRect();
143
144 qreal columnWidth = 1.0 / m_data.m_seriesCount;
145 qreal left = ((1.0 - m_boxWidth) / 2.0) * columnWidth + columnWidth * m_data.m_seriesIndex + m_data.m_index - 0.5;
146 qreal barWidth = m_boxWidth * columnWidth;
147
148 QPointF geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_upperExtreme), ok&: m_validData);
149 if (!m_validData)
150 return;
151 m_geometryLeft = geometryPoint.x();
152 qreal geometryUpperExtreme = geometryPoint.y();
153 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left + barWidth, m_data.m_upperQuartile), ok&: m_validData);
154 if (!m_validData)
155 return;
156 m_geometryRight = geometryPoint.x();
157 qreal geometryUpperQuartile = geometryPoint.y();
158 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_lowerQuartile), ok&: m_validData);
159 if (!m_validData)
160 return;
161 qreal geometryLowerQuartile = geometryPoint.y();
162 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_lowerExtreme), ok&: m_validData);
163 if (!m_validData)
164 return;
165 qreal geometryLowerExtreme = geometryPoint.y();
166 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_median), ok&: m_validData);
167 if (!m_validData)
168 return;
169 m_geometryMedian = geometryPoint.y();
170
171 // Upper whisker
172 path.moveTo(x: m_geometryLeft, y: geometryUpperExtreme);
173 path.lineTo(x: m_geometryRight, y: geometryUpperExtreme);
174 path.moveTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryUpperExtreme);
175 path.lineTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryUpperQuartile);
176
177 // Middle Box
178 m_middleBox.setCoords(xp1: m_geometryLeft, yp1: geometryUpperQuartile, xp2: m_geometryRight, yp2: geometryLowerQuartile);
179
180 // Lower whisker
181 path.moveTo(x: m_geometryLeft, y: geometryLowerExtreme);
182 path.lineTo(x: m_geometryRight, y: geometryLowerExtreme);
183 path.moveTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryLowerQuartile);
184 path.lineTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryLowerExtreme);
185
186 path.closeSubpath();
187
188 m_boxPath = path;
189 m_boundingRect = m_boxPath.boundingRect();
190
191 qreal extra = m_pen.widthF();
192 m_boundingRect.adjust(xp1: -extra, yp1: -extra, xp2: extra, yp2: extra);
193}
194
195QT_END_NAMESPACE
196
197#include "moc_boxwhiskers_p.cpp"
198

source code of qtcharts/src/charts/boxplotchart/boxwhiskers.cpp