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 "callout.h"
31#include <QtGui/QPainter>
32#include <QtGui/QFontMetrics>
33#include <QtWidgets/QGraphicsSceneMouseEvent>
34#include <QtGui/QMouseEvent>
35#include <QtCharts/QChart>
36
37Callout::Callout(QChart *chart):
38 QGraphicsItem(chart),
39 m_chart(chart)
40{
41}
42
43QRectF Callout::boundingRect() const
44{
45 QPointF anchor = mapFromParent(point: m_chart->mapToPosition(value: m_anchor));
46 QRectF rect;
47 rect.setLeft(qMin(a: m_rect.left(), b: anchor.x()));
48 rect.setRight(qMax(a: m_rect.right(), b: anchor.x()));
49 rect.setTop(qMin(a: m_rect.top(), b: anchor.y()));
50 rect.setBottom(qMax(a: m_rect.bottom(), b: anchor.y()));
51 return rect;
52}
53
54void Callout::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
55{
56 Q_UNUSED(option)
57 Q_UNUSED(widget)
58 QPainterPath path;
59 path.addRoundedRect(rect: m_rect, xRadius: 5, yRadius: 5);
60
61 QPointF anchor = mapFromParent(point: m_chart->mapToPosition(value: m_anchor));
62 if (!m_rect.contains(p: anchor)) {
63 QPointF point1, point2;
64
65 // establish the position of the anchor point in relation to m_rect
66 bool above = anchor.y() <= m_rect.top();
67 bool aboveCenter = anchor.y() > m_rect.top() && anchor.y() <= m_rect.center().y();
68 bool belowCenter = anchor.y() > m_rect.center().y() && anchor.y() <= m_rect.bottom();
69 bool below = anchor.y() > m_rect.bottom();
70
71 bool onLeft = anchor.x() <= m_rect.left();
72 bool leftOfCenter = anchor.x() > m_rect.left() && anchor.x() <= m_rect.center().x();
73 bool rightOfCenter = anchor.x() > m_rect.center().x() && anchor.x() <= m_rect.right();
74 bool onRight = anchor.x() > m_rect.right();
75
76 // get the nearest m_rect corner.
77 qreal x = (onRight + rightOfCenter) * m_rect.width();
78 qreal y = (below + belowCenter) * m_rect.height();
79 bool cornerCase = (above && onLeft) || (above && onRight) || (below && onLeft) || (below && onRight);
80 bool vertical = qAbs(t: anchor.x() - x) > qAbs(t: anchor.y() - y);
81
82 qreal x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * !vertical * (onLeft * 10 - onRight * 20);
83 qreal y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20);;
84 point1.setX(x1);
85 point1.setY(y1);
86
87 qreal x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * !vertical * (onLeft * 20 - onRight * 10);;
88 qreal y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10);;
89 point2.setX(x2);
90 point2.setY(y2);
91
92 path.moveTo(p: point1);
93 path.lineTo(p: anchor);
94 path.lineTo(p: point2);
95 path = path.simplified();
96 }
97 painter->setBrush(QColor(255, 255, 255));
98 painter->drawPath(path);
99 painter->drawText(r: m_textRect, text: m_text);
100}
101
102void Callout::mousePressEvent(QGraphicsSceneMouseEvent *event)
103{
104 event->setAccepted(true);
105}
106
107void Callout::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
108{
109 if (event->buttons() & Qt::LeftButton){
110 setPos(mapToParent(point: event->pos() - event->buttonDownPos(button: Qt::LeftButton)));
111 event->setAccepted(true);
112 } else {
113 event->setAccepted(false);
114 }
115}
116
117void Callout::setText(const QString &text)
118{
119 m_text = text;
120 QFontMetrics metrics(m_font);
121 m_textRect = metrics.boundingRect(r: QRect(0, 0, 150, 150), flags: Qt::AlignLeft, text: m_text);
122 m_textRect.translate(dx: 5, dy: 5);
123 prepareGeometryChange();
124 m_rect = m_textRect.adjusted(xp1: -5, yp1: -5, xp2: 5, yp2: 5);
125}
126
127void Callout::setAnchor(QPointF point)
128{
129 m_anchor = point;
130}
131
132void Callout::updateGeometry()
133{
134 prepareGeometryChange();
135 setPos(m_chart->mapToPosition(value: m_anchor) + QPoint(10, -50));
136}
137

source code of qtcharts/examples/charts/callout/callout.cpp