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 examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
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** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "sortingbox.h"
52
53#include <QMouseEvent>
54#include <QIcon>
55#include <QPainter>
56#include <QRandomGenerator>
57#include <QStyle>
58#include <QToolButton>
59#include <QToolTip>
60
61//! [0]
62SortingBox::SortingBox(QWidget *parent)
63 : QWidget(parent)
64{
65//! [0] //! [1]
66 setMouseTracking(true);
67//! [1] //! [2]
68 setBackgroundRole(QPalette::Base);
69//! [2]
70
71 itemInMotion = nullptr;
72
73//! [3]
74 newCircleButton = createToolButton(toolTip: tr(s: "New Circle"),
75 icon: QIcon(":/images/circle.png"),
76 SLOT(createNewCircle()));
77
78 newSquareButton = createToolButton(toolTip: tr(s: "New Square"),
79 icon: QIcon(":/images/square.png"),
80 SLOT(createNewSquare()));
81
82 newTriangleButton = createToolButton(toolTip: tr(s: "New Triangle"),
83 icon: QIcon(":/images/triangle.png"),
84 SLOT(createNewTriangle()));
85
86 circlePath.addEllipse(rect: QRect(0, 0, 100, 100));
87 squarePath.addRect(rect: QRect(0, 0, 100, 100));
88
89 qreal x = trianglePath.currentPosition().x();
90 qreal y = trianglePath.currentPosition().y();
91 trianglePath.moveTo(x: x + 120 / 2, y);
92 trianglePath.lineTo(x: 0, y: 100);
93 trianglePath.lineTo(x: 120, y: 100);
94 trianglePath.lineTo(x: x + 120 / 2, y);
95
96//! [3] //! [4]
97 setWindowTitle(tr(s: "Tool Tips"));
98 resize(w: 500, h: 300);
99
100 createShapeItem(path: circlePath, toolTip: tr(s: "Circle"), pos: initialItemPosition(path: circlePath),
101 color: initialItemColor());
102 createShapeItem(path: squarePath, toolTip: tr(s: "Square"), pos: initialItemPosition(path: squarePath),
103 color: initialItemColor());
104 createShapeItem(path: trianglePath, toolTip: tr(s: "Triangle"),
105 pos: initialItemPosition(path: trianglePath), color: initialItemColor());
106}
107//! [4]
108
109//! [5]
110bool SortingBox::event(QEvent *event)
111{
112//! [5] //! [6]
113 if (event->type() == QEvent::ToolTip) {
114 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
115 int index = itemAt(pos: helpEvent->pos());
116 if (index != -1) {
117 QToolTip::showText(pos: helpEvent->globalPos(), text: shapeItems[index].toolTip());
118 } else {
119 QToolTip::hideText();
120 event->ignore();
121 }
122
123 return true;
124 }
125 return QWidget::event(event);
126}
127//! [6]
128
129//! [7]
130void SortingBox::resizeEvent(QResizeEvent * /* event */)
131{
132 int margin = style()->pixelMetric(metric: QStyle::PM_DefaultTopLevelMargin);
133 int x = width() - margin;
134 int y = height() - margin;
135
136 y = updateButtonGeometry(button: newCircleButton, x, y);
137 y = updateButtonGeometry(button: newSquareButton, x, y);
138 updateButtonGeometry(button: newTriangleButton, x, y);
139}
140//! [7]
141
142//! [8]
143void SortingBox::paintEvent(QPaintEvent * /* event */)
144{
145 QPainter painter(this);
146 painter.setRenderHint(hint: QPainter::Antialiasing);
147 for (const ShapeItem &shapeItem : qAsConst(t&: shapeItems)) {
148//! [8] //! [9]
149 painter.translate(offset: shapeItem.position());
150//! [9] //! [10]
151 painter.setBrush(shapeItem.color());
152 painter.drawPath(path: shapeItem.path());
153 painter.translate(offset: -shapeItem.position());
154 }
155}
156//! [10]
157
158//! [11]
159void SortingBox::mousePressEvent(QMouseEvent *event)
160{
161 if (event->button() == Qt::LeftButton) {
162 int index = itemAt(pos: event->pos());
163 if (index != -1) {
164 itemInMotion = &shapeItems[index];
165 previousPosition = event->pos();
166 shapeItems.move(from: index, to: shapeItems.size() - 1);
167 update();
168 }
169 }
170}
171//! [11]
172
173//! [12]
174void SortingBox::mouseMoveEvent(QMouseEvent *event)
175{
176 if ((event->buttons() & Qt::LeftButton) && itemInMotion)
177 moveItemTo(pos: event->pos());
178}
179//! [12]
180
181//! [13]
182void SortingBox::mouseReleaseEvent(QMouseEvent *event)
183{
184 if (event->button() == Qt::LeftButton && itemInMotion) {
185 moveItemTo(pos: event->pos());
186 itemInMotion = nullptr;
187 }
188}
189//! [13]
190
191//! [14]
192void SortingBox::createNewCircle()
193{
194 static int count = 1;
195 createShapeItem(path: circlePath, toolTip: tr(s: "Circle <%1>").arg(a: ++count),
196 pos: randomItemPosition(), color: randomItemColor());
197}
198//! [14]
199
200//! [15]
201void SortingBox::createNewSquare()
202{
203 static int count = 1;
204 createShapeItem(path: squarePath, toolTip: tr(s: "Square <%1>").arg(a: ++count),
205 pos: randomItemPosition(), color: randomItemColor());
206}
207//! [15]
208
209//! [16]
210void SortingBox::createNewTriangle()
211{
212 static int count = 1;
213 createShapeItem(path: trianglePath, toolTip: tr(s: "Triangle <%1>").arg(a: ++count),
214 pos: randomItemPosition(), color: randomItemColor());
215}
216//! [16]
217
218//! [17]
219int SortingBox::itemAt(const QPoint &pos)
220{
221 for (int i = shapeItems.size() - 1; i >= 0; --i) {
222 const ShapeItem &item = shapeItems[i];
223 if (item.path().contains(pt: pos - item.position()))
224 return i;
225 }
226 return -1;
227}
228//! [17]
229
230//! [18]
231void SortingBox::moveItemTo(const QPoint &pos)
232{
233 QPoint offset = pos - previousPosition;
234 itemInMotion->setPosition(itemInMotion->position() + offset);
235//! [18] //! [19]
236 previousPosition = pos;
237 update();
238}
239//! [19]
240
241//! [20]
242int SortingBox::updateButtonGeometry(QToolButton *button, int x, int y)
243{
244 QSize size = button->sizeHint();
245 button->setGeometry(ax: x - size.rwidth(), ay: y - size.rheight(),
246 aw: size.rwidth(), ah: size.rheight());
247
248 return y - size.rheight()
249 - style()->pixelMetric(metric: QStyle::PM_DefaultLayoutSpacing);
250}
251//! [20]
252
253//! [21]
254void SortingBox::createShapeItem(const QPainterPath &path,
255 const QString &toolTip, const QPoint &pos,
256 const QColor &color)
257{
258 ShapeItem shapeItem;
259 shapeItem.setPath(path);
260 shapeItem.setToolTip(toolTip);
261 shapeItem.setPosition(pos);
262 shapeItem.setColor(color);
263 shapeItems.append(t: shapeItem);
264 update();
265}
266//! [21]
267
268//! [22]
269QToolButton *SortingBox::createToolButton(const QString &toolTip,
270 const QIcon &icon, const char *member)
271{
272 QToolButton *button = new QToolButton(this);
273 button->setToolTip(toolTip);
274 button->setIcon(icon);
275 button->setIconSize(QSize(32, 32));
276 connect(sender: button, SIGNAL(clicked()), receiver: this, member);
277
278 return button;
279}
280//! [22]
281
282//! [23]
283QPoint SortingBox::initialItemPosition(const QPainterPath &path)
284{
285 int x;
286 int y = (height() - qRound(d: path.controlPointRect().height()) / 2);
287 if (shapeItems.size() == 0)
288 x = ((3 * width()) / 2 - qRound(d: path.controlPointRect().width())) / 2;
289 else
290 x = (width() / shapeItems.size()
291 - qRound(d: path.controlPointRect().width())) / 2;
292
293 return QPoint(x, y);
294}
295//! [23]
296
297//! [24]
298QPoint SortingBox::randomItemPosition()
299{
300 return QPoint(QRandomGenerator::global()->bounded(highest: width() - 120), QRandomGenerator::global()->bounded(highest: height() - 120));
301}
302//! [24]
303
304//! [25]
305QColor SortingBox::initialItemColor()
306{
307 return QColor::fromHsv(h: ((shapeItems.size() + 1) * 85) % 256, s: 255, v: 190);
308}
309//! [25]
310
311//! [26]
312QColor SortingBox::randomItemColor()
313{
314 return QColor::fromHsv(h: QRandomGenerator::global()->bounded(highest: 256), s: 255, v: 190);
315}
316//! [26]
317

source code of qtbase/examples/widgets/widgets/tooltips/sortingbox.cpp