1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <private/boxwhiskers_p.h>
31#include <QtGui/QPainter>
32#include <QtWidgets/QWidget>
33#include <QtWidgets/QGraphicsSceneMouseEvent>
34
35QT_CHARTS_BEGIN_NAMESPACE
36
37BoxWhiskers::BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent) :
38 QGraphicsObject(parent),
39 m_boxSet(set),
40 m_domain(domain),
41 m_mousePressed(false)
42{
43 setAcceptHoverEvents(true);
44 setAcceptedMouseButtons(Qt::MouseButtonMask);
45 setFlag(flag: QGraphicsObject::ItemIsSelectable);
46}
47
48BoxWhiskers::~BoxWhiskers()
49{
50}
51
52void BoxWhiskers::mousePressEvent(QGraphicsSceneMouseEvent *event)
53{
54 Q_UNUSED(event)
55 emit pressed(boxset: m_boxSet);
56 m_mousePressed = true;
57}
58
59void BoxWhiskers::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
60{
61 Q_UNUSED(event)
62 emit hovered(status: true, boxset: m_boxSet);
63}
64
65void BoxWhiskers::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
66{
67 Q_UNUSED(event)
68 emit hovered(status: false, boxset: m_boxSet);
69}
70
71void BoxWhiskers::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
72{
73 Q_UNUSED(event)
74 emit released(boxset: m_boxSet);
75 if (m_mousePressed)
76 emit clicked(boxset: m_boxSet);
77}
78
79void BoxWhiskers::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
80{
81 Q_UNUSED(event)
82 // For Box a press signal needs to be explicitly fired for mouseDoubleClickEvent
83 emit pressed(boxset: m_boxSet);
84 emit doubleClicked(boxset: m_boxSet);
85}
86
87void BoxWhiskers::setBrush(const QBrush &brush)
88{
89 m_brush = brush;
90 m_outlinePen.setColor(m_brush.color());
91 update();
92}
93
94void BoxWhiskers::setPen(const QPen &pen)
95{
96 qreal widthDiff = pen.widthF() - m_pen.widthF();
97 m_boundingRect.adjust(xp1: -widthDiff, yp1: -widthDiff, xp2: widthDiff, yp2: widthDiff);
98
99 m_pen = pen;
100 m_medianPen = pen;
101 m_medianPen.setCapStyle(Qt::FlatCap);
102 m_outlinePen = pen;
103 m_outlinePen.setStyle(Qt::SolidLine);
104 m_outlinePen.setColor(m_brush.color());
105
106 update();
107}
108
109void BoxWhiskers::setBoxWidth(const qreal width)
110{
111 m_boxWidth = width;
112}
113
114void BoxWhiskers::setLayout(const BoxWhiskersData &data)
115{
116 m_data = data;
117
118 updateGeometry(domain: m_domain);
119 update();
120}
121
122QSizeF BoxWhiskers::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
123{
124 Q_UNUSED(which)
125 Q_UNUSED(constraint)
126
127 return QSizeF();
128}
129
130void BoxWhiskers::setGeometry(const QRectF &rect)
131{
132 Q_UNUSED(rect)
133}
134
135QRectF BoxWhiskers::boundingRect() const
136{
137 return m_boundingRect;
138}
139
140void BoxWhiskers::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
141{
142 Q_UNUSED(option)
143 Q_UNUSED(widget)
144
145 painter->save();
146 painter->setBrush(m_brush);
147 painter->setClipRect(parentItem()->boundingRect());
148 painter->setPen(m_pen);
149 painter->drawPath(path: m_boxPath);
150 if (!m_boxOutlined)
151 painter->setPen(m_outlinePen);
152 painter->drawRect(rect: m_middleBox);
153 painter->setPen(m_medianPen);
154 qreal halfLine = m_pen.widthF() / 2.0;
155 painter->drawLine(l: QLineF(m_geometryLeft - halfLine, m_geometryMedian,
156 m_geometryRight + halfLine, m_geometryMedian));
157 painter->restore();
158}
159
160void BoxWhiskers::updateGeometry(AbstractDomain *domain)
161{
162 m_domain = domain;
163
164 prepareGeometryChange();
165
166 QPainterPath path;
167 m_boxPath = path;
168 m_boundingRect = m_boxPath.boundingRect();
169
170 qreal columnWidth = 1.0 / m_data.m_seriesCount;
171 qreal left = ((1.0 - m_boxWidth) / 2.0) * columnWidth + columnWidth * m_data.m_seriesIndex + m_data.m_index - 0.5;
172 qreal barWidth = m_boxWidth * columnWidth;
173
174 QPointF geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_upperExtreme), ok&: m_validData);
175 if (!m_validData)
176 return;
177 m_geometryLeft = geometryPoint.x();
178 qreal geometryUpperExtreme = geometryPoint.y();
179 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left + barWidth, m_data.m_upperQuartile), ok&: m_validData);
180 if (!m_validData)
181 return;
182 m_geometryRight = geometryPoint.x();
183 qreal geometryUpperQuartile = geometryPoint.y();
184 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_lowerQuartile), ok&: m_validData);
185 if (!m_validData)
186 return;
187 qreal geometryLowerQuartile = geometryPoint.y();
188 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_lowerExtreme), ok&: m_validData);
189 if (!m_validData)
190 return;
191 qreal geometryLowerExtreme = geometryPoint.y();
192 geometryPoint = m_domain->calculateGeometryPoint(point: QPointF(left, m_data.m_median), ok&: m_validData);
193 if (!m_validData)
194 return;
195 m_geometryMedian = geometryPoint.y();
196
197 // Upper whisker
198 path.moveTo(x: m_geometryLeft, y: geometryUpperExtreme);
199 path.lineTo(x: m_geometryRight, y: geometryUpperExtreme);
200 path.moveTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryUpperExtreme);
201 path.lineTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryUpperQuartile);
202
203 // Middle Box
204 m_middleBox.setCoords(xp1: m_geometryLeft, yp1: geometryUpperQuartile, xp2: m_geometryRight, yp2: geometryLowerQuartile);
205
206 // Lower whisker
207 path.moveTo(x: m_geometryLeft, y: geometryLowerExtreme);
208 path.lineTo(x: m_geometryRight, y: geometryLowerExtreme);
209 path.moveTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryLowerQuartile);
210 path.lineTo(x: (m_geometryLeft + m_geometryRight) / 2.0, y: geometryLowerExtreme);
211
212 path.closeSubpath();
213
214 m_boxPath = path;
215 m_boundingRect = m_boxPath.boundingRect();
216
217 qreal extra = m_pen.widthF();
218 m_boundingRect.adjust(xp1: -extra, yp1: -extra, xp2: extra, yp2: extra);
219}
220
221QT_CHARTS_END_NAMESPACE
222
223#include "moc_boxwhiskers_p.cpp"
224

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