1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qbitmap.h"
5#include "qevent.h"
6#include "qstylepainter.h"
7#include "qrubberband.h"
8#include "qtimer.h"
9
10#include "qstyle.h"
11#include "qstyleoption.h"
12
13#include <qdebug.h>
14
15#include <private/qwidget_p.h>
16
17QT_BEGIN_NAMESPACE
18
19//### a rubberband window type would be a more elegant solution
20#define RUBBERBAND_WINDOW_TYPE Qt::ToolTip
21
22class QRubberBandPrivate : public QWidgetPrivate
23{
24 Q_DECLARE_PUBLIC(QRubberBand)
25public:
26 QRect rect;
27 QRubberBand::Shape shape;
28 QRegion clipping;
29 void updateMask();
30};
31
32/*!
33 Initialize \a option with the values from this QRubberBand. This method
34 is useful for subclasses when they need a QStyleOptionRubberBand, but don't want
35 to fill in all the information themselves.
36
37 \sa QStyleOption::initFrom()
38*/
39void QRubberBand::initStyleOption(QStyleOptionRubberBand *option) const
40{
41 if (!option)
42 return;
43 option->initFrom(w: this);
44 option->shape = d_func()->shape;
45#ifndef Q_OS_MAC
46 option->opaque = true;
47#else
48 option->opaque = windowFlags() & RUBBERBAND_WINDOW_TYPE;
49#endif
50}
51
52/*!
53 \class QRubberBand
54 \brief The QRubberBand class provides a rectangle or line that can
55 indicate a selection or a boundary.
56
57 \inmodule QtWidgets
58
59 A rubber band is often used to show a new bounding area (as in a
60 QSplitter or a QDockWidget that is undocking). Historically this has
61 been implemented using a QPainter and XOR, but this approach
62 doesn't always work properly since rendering can happen in the
63 window below the rubber band, but before the rubber band has been
64 "erased".
65
66 You can create a QRubberBand whenever you need to render a rubber band
67 around a given area (or to represent a single line), then call
68 setGeometry(), move() or resize() to position and size it. A common
69 pattern is to do this in conjunction with mouse events. For example:
70
71 \snippet code/src_gui_widgets_qrubberband.cpp 0
72
73 If you pass a parent to QRubberBand's constructor, the rubber band will
74 display only inside its parent, but stays on top of other child widgets.
75 If no parent is passed, QRubberBand will act as a top-level widget.
76
77 Call show() to make the rubber band visible; also when the
78 rubber band is not a top-level. Hiding or destroying
79 the widget will make the rubber band disappear. The rubber band
80 can be a \l Rectangle or a \l Line (vertical or horizontal),
81 depending on the shape() it was given when constructed.
82*/
83
84// ### DOC: How about some nice convenience constructors?
85//QRubberBand::QRubberBand(QRubberBand::Type t, const QRect &rect, QWidget *p)
86//QRubberBand::QRubberBand(QRubberBand::Type t, int x, int y, int w, int h, QWidget *p)
87
88/*!
89 Constructs a rubber band of shape \a s, with parent \a p.
90
91 By default a rectangular rubber band (\a s is \c Rectangle) will
92 use a mask, so that a small border of the rectangle is all
93 that is visible. Some styles (e.g., native \macos) will
94 change this and call QWidget::setWindowOpacity() to make a
95 semi-transparent filled selection rectangle.
96*/
97QRubberBand::QRubberBand(Shape s, QWidget *p)
98 : QWidget(*new QRubberBandPrivate, p, (p && p->windowType() != Qt::Desktop) ? Qt::Widget : RUBBERBAND_WINDOW_TYPE)
99{
100 Q_D(QRubberBand);
101 d->shape = s;
102 setAttribute(Qt::WA_TransparentForMouseEvents);
103 setAttribute(Qt::WA_NoSystemBackground);
104 setAttribute(Qt::WA_WState_ExplicitShowHide);
105 setVisible(false);
106}
107
108/*!
109 Destructor.
110*/
111QRubberBand::~QRubberBand()
112{
113}
114
115/*!
116 \enum QRubberBand::Shape
117
118 This enum specifies what shape a QRubberBand should have. This is
119 a drawing hint that is passed down to the style system, and can be
120 interpreted by each QStyle.
121
122 \value Line A QRubberBand can represent a vertical or horizontal
123 line. Geometry is still given in rect() and the line
124 will fill the given geometry on most styles.
125
126 \value Rectangle A QRubberBand can represent a rectangle. Some
127 styles will interpret this as a filled (often
128 semi-transparent) rectangle, or a rectangular
129 outline.
130*/
131
132/*!
133 Returns the shape of this rubber band. The shape can only be set
134 upon construction.
135*/
136QRubberBand::Shape QRubberBand::shape() const
137{
138 Q_D(const QRubberBand);
139 return d->shape;
140}
141
142/*!
143 \internal
144*/
145void QRubberBandPrivate::updateMask()
146{
147 Q_Q(QRubberBand);
148 QStyleHintReturnMask mask;
149 QStyleOptionRubberBand opt;
150 q->initStyleOption(option: &opt);
151 if (q->style()->styleHint(stylehint: QStyle::SH_RubberBand_Mask, opt: &opt, widget: q, returnData: &mask)) {
152 q->setMask(mask.region);
153 } else {
154 q->clearMask();
155 }
156}
157
158/*!
159 \reimp
160*/
161void QRubberBand::paintEvent(QPaintEvent *)
162{
163 QStylePainter painter(this);
164 QStyleOptionRubberBand option;
165 initStyleOption(option: &option);
166 painter.drawControl(ce: QStyle::CE_RubberBand, opt: option);
167}
168
169/*!
170 \reimp
171*/
172void QRubberBand::changeEvent(QEvent *e)
173{
174 QWidget::changeEvent(e);
175 switch (e->type()) {
176 case QEvent::ParentChange:
177 if (parent()) {
178 setWindowFlags(windowFlags() & ~RUBBERBAND_WINDOW_TYPE);
179 } else {
180 setWindowFlags(windowFlags() | RUBBERBAND_WINDOW_TYPE);
181 }
182 break;
183 default:
184 break;
185 }
186
187 if (e->type() == QEvent::ZOrderChange)
188 raise();
189}
190
191/*!
192 \reimp
193*/
194void QRubberBand::showEvent(QShowEvent *e)
195{
196 raise();
197 e->ignore();
198}
199
200/*!
201 \reimp
202*/
203void QRubberBand::resizeEvent(QResizeEvent *)
204{
205 Q_D(QRubberBand);
206 d->updateMask();
207}
208
209/*!
210 \reimp
211*/
212void QRubberBand::moveEvent(QMoveEvent *)
213{
214 Q_D(QRubberBand);
215 d->updateMask();
216}
217
218/*!
219 \fn void QRubberBand::move(const QPoint &p);
220
221 \overload
222
223 Moves the rubberband to point \a p.
224
225 \sa resize()
226*/
227
228/*!
229 \fn void QRubberBand::move(int x, int y);
230
231 Moves the rubberband to point (\a x, \a y).
232
233 \sa resize()
234*/
235
236/*!
237 \fn void QRubberBand::resize(const QSize &size);
238
239 \overload
240
241 Resizes the rubberband so that its new size is \a size.
242
243 \sa move()
244*/
245
246/*!
247 \fn void QRubberBand::resize(int width, int height);
248
249 Resizes the rubberband so that its width is \a width, and its
250 height is \a height.
251
252 \sa move()
253*/
254
255/*!
256 \fn void QRubberBand::setGeometry(const QRect &rect)
257
258 Sets the geometry of the rubber band to \a rect, specified in the coordinate system
259 of its parent widget.
260
261 \sa QWidget::geometry
262*/
263void QRubberBand::setGeometry(const QRect &geom)
264{
265 QWidget::setGeometry(geom);
266}
267
268/*!
269 \fn void QRubberBand::setGeometry(int x, int y, int width, int height)
270 \overload
271
272 Sets the geometry of the rubberband to the rectangle whose top-left corner lies at
273 the point (\a x, \a y), and with dimensions specified by \a width and \a height.
274 The geometry is specified in the parent widget's coordinate system.
275*/
276
277/*! \reimp */
278bool QRubberBand::event(QEvent *e)
279{
280 return QWidget::event(event: e);
281}
282
283QT_END_NAMESPACE
284
285#include "moc_qrubberband.cpp"
286

source code of qtbase/src/widgets/widgets/qrubberband.cpp