boxwhiskers.cpp
223 lines
| 6.7 KiB
| text/x-c
|
CppLexer
Miikka Heikkinen
|
r2854 | /**************************************************************************** | ||
Titta Heikkala
|
r2845 | ** | ||
Miikka Heikkinen
|
r2854 | ** Copyright (C) 2016 The Qt Company Ltd. | ||
** Contact: https://www.qt.io/licensing/ | ||||
Titta Heikkala
|
r2845 | ** | ||
Miikka Heikkinen
|
r2854 | ** This file is part of the Qt Charts module of the Qt Toolkit. | ||
Titta Heikkala
|
r2845 | ** | ||
Miikka Heikkinen
|
r2854 | ** $QT_BEGIN_LICENSE:GPL$ | ||
Titta Heikkala
|
r2845 | ** Commercial License Usage | ||
** Licensees holding valid commercial Qt licenses may use this file in | ||||
** accordance with the commercial license agreement provided with the | ||||
** Software or, alternatively, in accordance with the terms contained in | ||||
** a written agreement between you and The Qt Company. For licensing terms | ||||
Miikka Heikkinen
|
r2854 | ** and conditions see https://www.qt.io/terms-conditions. For further | ||
** information use the contact form at https://www.qt.io/contact-us. | ||||
** | ||||
** GNU General Public License Usage | ||||
** Alternatively, this file may be used under the terms of the GNU | ||||
** General Public License version 3 or (at your option) any later version | ||||
** approved by the KDE Free Qt Foundation. The licenses are as published by | ||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3 | ||||
** included in the packaging of this file. Please review the following | ||||
** information to ensure the GNU General Public License requirements will | ||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html. | ||||
Titta Heikkala
|
r2845 | ** | ||
** $QT_END_LICENSE$ | ||||
** | ||||
Miikka Heikkinen
|
r2854 | ****************************************************************************/ | ||
Mika Salmela
|
r2548 | |||
Titta Heikkala
|
r2714 | #include <private/boxwhiskers_p.h> | ||
#include <QtGui/QPainter> | ||||
#include <QtWidgets/QWidget> | ||||
Titta Heikkala
|
r2739 | #include <QtWidgets/QGraphicsSceneMouseEvent> | ||
Mika Salmela
|
r2548 | |||
Titta Heikkala
|
r2712 | QT_CHARTS_BEGIN_NAMESPACE | ||
Mika Salmela
|
r2548 | |||
BoxWhiskers::BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent) : | ||||
QGraphicsObject(parent), | ||||
m_boxSet(set), | ||||
Titta Heikkala
|
r2739 | m_domain(domain), | ||
m_mousePressed(false) | ||||
Mika Salmela
|
r2548 | { | ||
setAcceptHoverEvents(true); | ||||
setAcceptedMouseButtons(Qt::MouseButtonMask); | ||||
Titta Heikkala
|
r2739 | setFlag(QGraphicsObject::ItemIsSelectable); | ||
Mika Salmela
|
r2548 | } | ||
BoxWhiskers::~BoxWhiskers() | ||||
{ | ||||
} | ||||
void BoxWhiskers::mousePressEvent(QGraphicsSceneMouseEvent *event) | ||||
{ | ||||
Titta Heikkala
|
r2746 | Q_UNUSED(event) | ||
Titta Heikkala
|
r2739 | emit pressed(m_boxSet); | ||
m_mousePressed = true; | ||||
Mika Salmela
|
r2548 | } | ||
void BoxWhiskers::hoverEnterEvent(QGraphicsSceneHoverEvent *event) | ||||
{ | ||||
Q_UNUSED(event) | ||||
emit hovered(true, m_boxSet); | ||||
} | ||||
void BoxWhiskers::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) | ||||
{ | ||||
Q_UNUSED(event) | ||||
emit hovered(false, m_boxSet); | ||||
} | ||||
Titta Heikkala
|
r2739 | void BoxWhiskers::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) | ||
{ | ||||
Titta Heikkala
|
r2746 | Q_UNUSED(event) | ||
Titta Heikkala
|
r2739 | emit released(m_boxSet); | ||
Titta Heikkala
|
r2746 | if (m_mousePressed) | ||
Titta Heikkala
|
r2739 | emit clicked(m_boxSet); | ||
} | ||||
void BoxWhiskers::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) | ||||
{ | ||||
Q_UNUSED(event) | ||||
// For Box a press signal needs to be explicitly fired for mouseDoubleClickEvent | ||||
emit pressed(m_boxSet); | ||||
emit doubleClicked(m_boxSet); | ||||
} | ||||
Mika Salmela
|
r2548 | void BoxWhiskers::setBrush(const QBrush &brush) | ||
{ | ||||
m_brush = brush; | ||||
Mika Salmela
|
r2573 | m_outlinePen.setColor(m_brush.color()); | ||
Mika Salmela
|
r2548 | update(); | ||
} | ||||
void BoxWhiskers::setPen(const QPen &pen) | ||||
{ | ||||
Mika Salmela
|
r2573 | qreal widthDiff = pen.widthF() - m_pen.widthF(); | ||
m_boundingRect.adjust(-widthDiff, -widthDiff, widthDiff, widthDiff); | ||||
Mika Salmela
|
r2548 | m_pen = pen; | ||
Mika Salmela
|
r2573 | m_medianPen = pen; | ||
m_medianPen.setCapStyle(Qt::FlatCap); | ||||
m_outlinePen = pen; | ||||
m_outlinePen.setStyle(Qt::SolidLine); | ||||
m_outlinePen.setColor(m_brush.color()); | ||||
Mika Salmela
|
r2548 | update(); | ||
} | ||||
Mika Salmela
|
r2584 | void BoxWhiskers::setBoxWidth(const qreal width) | ||
{ | ||||
m_boxWidth = width; | ||||
} | ||||
Mika Salmela
|
r2548 | void BoxWhiskers::setLayout(const BoxWhiskersData &data) | ||
{ | ||||
m_data = data; | ||||
Mika Salmela
|
r2554 | updateGeometry(m_domain); | ||
Mika Salmela
|
r2548 | update(); | ||
} | ||||
QSizeF BoxWhiskers::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const | ||||
{ | ||||
Q_UNUSED(which) | ||||
Q_UNUSED(constraint) | ||||
return QSizeF(); | ||||
} | ||||
void BoxWhiskers::setGeometry(const QRectF &rect) | ||||
{ | ||||
Q_UNUSED(rect) | ||||
} | ||||
QRectF BoxWhiskers::boundingRect() const | ||||
{ | ||||
return m_boundingRect; | ||||
} | ||||
void BoxWhiskers::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) | ||||
{ | ||||
Q_UNUSED(option) | ||||
Q_UNUSED(widget) | ||||
Miikka Heikkinen
|
r2586 | painter->save(); | ||
Mika Salmela
|
r2548 | painter->setBrush(m_brush); | ||
painter->setClipRect(parentItem()->boundingRect()); | ||||
Mika Salmela
|
r2573 | painter->setPen(m_pen); | ||
Mika Salmela
|
r2548 | painter->drawPath(m_boxPath); | ||
Mika Salmela
|
r2573 | if (!m_boxOutlined) | ||
painter->setPen(m_outlinePen); | ||||
painter->drawRect(m_middleBox); | ||||
painter->setPen(m_medianPen); | ||||
qreal halfLine = m_pen.widthF() / 2.0; | ||||
painter->drawLine(QLineF(m_geometryLeft - halfLine, m_geometryMedian, | ||||
m_geometryRight + halfLine, m_geometryMedian)); | ||||
Miikka Heikkinen
|
r2586 | painter->restore(); | ||
Mika Salmela
|
r2548 | } | ||
Mika Salmela
|
r2554 | void BoxWhiskers::updateGeometry(AbstractDomain *domain) | ||
Mika Salmela
|
r2548 | { | ||
Mika Salmela
|
r2554 | m_domain = domain; | ||
Mika Salmela
|
r2548 | prepareGeometryChange(); | ||
QPainterPath path; | ||||
Mika Salmela
|
r2554 | m_boxPath = path; | ||
m_boundingRect = m_boxPath.boundingRect(); | ||||
Mika Salmela
|
r2548 | |||
qreal columnWidth = 1.0 / m_data.m_seriesCount; | ||||
Mika Salmela
|
r2584 | qreal left = ((1.0 - m_boxWidth) / 2.0) * columnWidth + columnWidth * m_data.m_seriesIndex + m_data.m_index - 0.5; | ||
qreal barWidth = m_boxWidth * columnWidth; | ||||
Mika Salmela
|
r2554 | |||
QPointF geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_upperExtreme), m_validData); | ||||
if (!m_validData) | ||||
return; | ||||
Mika Salmela
|
r2573 | m_geometryLeft = geometryPoint.x(); | ||
Mika Salmela
|
r2554 | qreal geometryUpperExtreme = geometryPoint.y(); | ||
geometryPoint = m_domain->calculateGeometryPoint(QPointF(left + barWidth, m_data.m_upperQuartile), m_validData); | ||||
if (!m_validData) | ||||
return; | ||||
Mika Salmela
|
r2573 | m_geometryRight = geometryPoint.x(); | ||
Mika Salmela
|
r2554 | qreal geometryUpperQuartile = geometryPoint.y(); | ||
geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerQuartile), m_validData); | ||||
if (!m_validData) | ||||
return; | ||||
qreal geometryLowerQuartile = geometryPoint.y(); | ||||
geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_lowerExtreme), m_validData); | ||||
if (!m_validData) | ||||
return; | ||||
qreal geometryLowerExtreme = geometryPoint.y(); | ||||
geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_median), m_validData); | ||||
if (!m_validData) | ||||
return; | ||||
Mika Salmela
|
r2573 | m_geometryMedian = geometryPoint.y(); | ||
Mika Salmela
|
r2548 | |||
// Upper whisker | ||||
Mika Salmela
|
r2573 | path.moveTo(m_geometryLeft, geometryUpperExtreme); | ||
path.lineTo(m_geometryRight, geometryUpperExtreme); | ||||
path.moveTo((m_geometryLeft + m_geometryRight) / 2.0, geometryUpperExtreme); | ||||
path.lineTo((m_geometryLeft + m_geometryRight) / 2.0, geometryUpperQuartile); | ||||
Mika Salmela
|
r2548 | |||
// Middle Box | ||||
Mika Salmela
|
r2573 | m_middleBox.setCoords(m_geometryLeft, geometryUpperQuartile, m_geometryRight, geometryLowerQuartile); | ||
Mika Salmela
|
r2548 | |||
// Lower whisker | ||||
Mika Salmela
|
r2573 | path.moveTo(m_geometryLeft, geometryLowerExtreme); | ||
path.lineTo(m_geometryRight, geometryLowerExtreme); | ||||
path.moveTo((m_geometryLeft + m_geometryRight) / 2.0, geometryLowerQuartile); | ||||
path.lineTo((m_geometryLeft + m_geometryRight) / 2.0, geometryLowerExtreme); | ||||
Mika Salmela
|
r2548 | |||
path.closeSubpath(); | ||||
m_boxPath = path; | ||||
Mika Salmela
|
r2554 | m_boundingRect = m_boxPath.boundingRect(); | ||
Miikka Heikkinen
|
r2565 | |||
Mika Salmela
|
r2584 | qreal extra = m_pen.widthF(); | ||
Miikka Heikkinen
|
r2565 | m_boundingRect.adjust(-extra, -extra, extra, extra); | ||
Mika Salmela
|
r2548 | } | ||
#include "moc_boxwhiskers_p.cpp" | ||||
Titta Heikkala
|
r2712 | QT_CHARTS_END_NAMESPACE | ||