/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc ** All rights reserved. ** For any questions to Digia, please use contact form at http://qt.io ** ** This file is part of the Qt Charts module. ** ** Licensees holding valid commercial license for Qt may use this file in ** accordance with the Qt License Agreement provided with the Software ** or, alternatively, in accordance with the terms contained in a written ** agreement between you and Digia. ** ** If you have questions regarding the use of this file, please use ** contact form at http://qt.io ** ****************************************************************************/ #include #include #include #include QT_CHARTS_BEGIN_NAMESPACE BoxWhiskers::BoxWhiskers(QBoxSet *set, AbstractDomain *domain, QGraphicsObject *parent) : QGraphicsObject(parent), m_boxSet(set), m_domain(domain), m_mousePressed(false) { setAcceptHoverEvents(true); setAcceptedMouseButtons(Qt::MouseButtonMask); setFlag(QGraphicsObject::ItemIsSelectable); } BoxWhiskers::~BoxWhiskers() { } void BoxWhiskers::mousePressEvent(QGraphicsSceneMouseEvent *event) { emit pressed(m_boxSet); m_lastMousePos = event->pos(); m_mousePressed = true; } 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); } void BoxWhiskers::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { emit released(m_boxSet); if (m_lastMousePos == event->pos() && m_mousePressed) 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); } void BoxWhiskers::setBrush(const QBrush &brush) { m_brush = brush; m_outlinePen.setColor(m_brush.color()); update(); } void BoxWhiskers::setPen(const QPen &pen) { qreal widthDiff = pen.widthF() - m_pen.widthF(); m_boundingRect.adjust(-widthDiff, -widthDiff, widthDiff, widthDiff); m_pen = pen; m_medianPen = pen; m_medianPen.setCapStyle(Qt::FlatCap); m_outlinePen = pen; m_outlinePen.setStyle(Qt::SolidLine); m_outlinePen.setColor(m_brush.color()); update(); } void BoxWhiskers::setBoxWidth(const qreal width) { m_boxWidth = width; } void BoxWhiskers::setLayout(const BoxWhiskersData &data) { m_data = data; updateGeometry(m_domain); 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) painter->save(); painter->setBrush(m_brush); painter->setClipRect(parentItem()->boundingRect()); painter->setPen(m_pen); painter->drawPath(m_boxPath); 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)); painter->restore(); } void BoxWhiskers::updateGeometry(AbstractDomain *domain) { m_domain = domain; prepareGeometryChange(); QPainterPath path; m_boxPath = path; m_boundingRect = m_boxPath.boundingRect(); qreal columnWidth = 1.0 / m_data.m_seriesCount; 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; QPointF geometryPoint = m_domain->calculateGeometryPoint(QPointF(left, m_data.m_upperExtreme), m_validData); if (!m_validData) return; m_geometryLeft = geometryPoint.x(); qreal geometryUpperExtreme = geometryPoint.y(); geometryPoint = m_domain->calculateGeometryPoint(QPointF(left + barWidth, m_data.m_upperQuartile), m_validData); if (!m_validData) return; m_geometryRight = geometryPoint.x(); 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; m_geometryMedian = geometryPoint.y(); // Upper whisker 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); // Middle Box m_middleBox.setCoords(m_geometryLeft, geometryUpperQuartile, m_geometryRight, geometryLowerQuartile); // Lower whisker 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); path.closeSubpath(); m_boxPath = path; m_boundingRect = m_boxPath.boundingRect(); qreal extra = m_pen.widthF(); m_boundingRect.adjust(-extra, -extra, extra, extra); } #include "moc_boxwhiskers_p.cpp" QT_CHARTS_END_NAMESPACE