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