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 "qframe.h"
41#include "qbitmap.h"
42#include "qdrawutil.h"
43#include "qevent.h"
44#include "qpainter.h"
45#include "qstyle.h"
46#include "qstyleoption.h"
47#include "qapplication.h"
48
49#include "qframe_p.h"
50
51QT_BEGIN_NAMESPACE
52
53QFramePrivate::QFramePrivate()
54 : frect(0, 0, 0, 0),
55 frameStyle(QFrame::NoFrame | QFrame::Plain),
56 lineWidth(1),
57 midLineWidth(0),
58 frameWidth(0),
59 leftFrameWidth(0), rightFrameWidth(0),
60 topFrameWidth(0), bottomFrameWidth(0)
61{
62}
63
64QFramePrivate::~QFramePrivate()
65{
66}
67
68inline void QFramePrivate::init()
69{
70 setLayoutItemMargins(QStyle::SE_FrameLayoutItem);
71}
72
73/*!
74 \class QFrame
75 \brief The QFrame class is the base class of widgets that can have a frame.
76
77 \ingroup abstractwidgets
78 \inmodule QtWidgets
79
80 QMenu uses this to "raise" the menu above the surrounding
81 screen. QProgressBar has a "sunken" look. QLabel has a flat look.
82 The frames of widgets like these can be changed.
83
84 \snippet code/src_gui_widgets_qframe.cpp 0
85
86 The QFrame class can also be used directly for creating simple
87 placeholder frames without any contents.
88
89 The frame style is specified by a \l{QFrame::Shape}{frame shape} and
90 a \l{QFrame::Shadow}{shadow style} that is used to visually separate
91 the frame from surrounding widgets. These properties can be set
92 together using the setFrameStyle() function and read with frameStyle().
93
94 The frame shapes are \l NoFrame, \l Box, \l Panel, \l StyledPanel,
95 HLine and \l VLine; the shadow styles are \l Plain, \l Raised and
96 \l Sunken.
97
98 A frame widget has three attributes that describe the thickness of the
99 border: \l lineWidth, \l midLineWidth, and \l frameWidth.
100
101 \list
102 \li The line width is the width of the frame border. It can be modified
103 to customize the frame's appearance.
104
105 \li The mid-line width specifies the width of an extra line in the
106 middle of the frame, which uses a third color to obtain a special
107 3D effect. Notice that a mid-line is only drawn for \l Box, \l
108 HLine and \l VLine frames that are raised or sunken.
109
110 \li The frame width is determined by the frame style, and the frameWidth()
111 function is used to obtain the value defined for the style used.
112 \endlist
113
114 The margin between the frame and the contents of the frame can be
115 customized with the QWidget::setContentsMargins() function.
116
117 \target picture
118 This table shows some of the combinations of styles and line widths:
119
120 \image frames.png Table of frame styles
121*/
122
123
124/*!
125 \enum QFrame::Shape
126
127 This enum type defines the shapes of frame available.
128
129 \value NoFrame QFrame draws nothing
130 \value Box QFrame draws a box around its contents
131 \value Panel QFrame draws a panel to make the contents appear
132 raised or sunken
133 \value StyledPanel draws a rectangular panel with a look that
134 depends on the current GUI style. It can be raised or sunken.
135 \value HLine QFrame draws a horizontal line that frames nothing
136 (useful as separator)
137 \value VLine QFrame draws a vertical line that frames nothing
138 (useful as separator)
139 \value WinPanel draws a rectangular panel that can be raised or
140 sunken like those in Windows 2000. Specifying this shape sets
141 the line width to 2 pixels. WinPanel is provided for compatibility.
142 For GUI style independence we recommend using StyledPanel instead.
143
144 When it does not call QStyle, Shape interacts with QFrame::Shadow,
145 the lineWidth() and the midLineWidth() to create the total result.
146 See the picture of the frames in the main class documentation.
147
148 \sa QFrame::Shadow, QFrame::style(), QStyle::drawPrimitive()
149*/
150
151
152/*!
153 \enum QFrame::Shadow
154
155 This enum type defines the types of shadow that are used to give
156 a 3D effect to frames.
157
158 \value Plain the frame and contents appear level with the
159 surroundings; draws using the palette QPalette::WindowText color
160 (without any 3D effect)
161
162 \value Raised the frame and contents appear raised; draws a 3D
163 raised line using the light and dark colors of the current color
164 group
165 \value Sunken the frame and contents appear sunken; draws a 3D
166 sunken line using the light and dark colors of the current color
167 group
168
169 Shadow interacts with QFrame::Shape, the lineWidth() and the
170 midLineWidth(). See the picture of the frames in the main class
171 documentation.
172
173 \sa QFrame::Shape, lineWidth(), midLineWidth()
174*/
175
176/*!
177 \enum QFrame::StyleMask
178
179 This enum defines two constants that can be used to extract the
180 two components of frameStyle():
181
182 \value Shadow_Mask The \l Shadow part of frameStyle()
183 \value Shape_Mask The \l Shape part of frameStyle()
184
185 Normally, you don't need to use these, since frameShadow() and
186 frameShape() already extract the \l Shadow and the \l Shape parts
187 of frameStyle().
188
189 \sa frameStyle(), setFrameStyle()
190*/
191
192/*!
193 Constructs a frame widget with frame style \l NoFrame and a
194 1-pixel frame width.
195
196 The \a parent and \a f arguments are passed to the QWidget
197 constructor.
198*/
199
200QFrame::QFrame(QWidget* parent, Qt::WindowFlags f)
201 : QWidget(*new QFramePrivate, parent, f)
202{
203 Q_D(QFrame);
204 d->init();
205}
206
207/*! \internal */
208QFrame::QFrame(QFramePrivate &dd, QWidget* parent, Qt::WindowFlags f)
209 : QWidget(dd, parent, f)
210{
211 Q_D(QFrame);
212 d->init();
213}
214
215/*!
216 \since 5.5
217
218 Initializes \a option with the values from this QFrame. This method is
219 useful for subclasses when they need a QStyleOptionFrame but don't want to
220 fill in all the information themselves.
221
222 \sa QStyleOption::initFrom()
223*/
224void QFrame::initStyleOption(QStyleOptionFrame *option) const
225{
226 if (!option)
227 return;
228
229 Q_D(const QFrame);
230 option->initFrom(this);
231
232 int frameShape = d->frameStyle & QFrame::Shape_Mask;
233 int frameShadow = d->frameStyle & QFrame::Shadow_Mask;
234 option->frameShape = Shape(int(option->frameShape) | frameShape);
235 option->rect = frameRect();
236 switch (frameShape) {
237 case QFrame::Box:
238 case QFrame::HLine:
239 case QFrame::VLine:
240 case QFrame::StyledPanel:
241 case QFrame::Panel:
242 option->lineWidth = d->lineWidth;
243 option->midLineWidth = d->midLineWidth;
244 break;
245 default:
246 // most frame styles do not handle customized line and midline widths
247 // (see updateFrameWidth()).
248 option->lineWidth = d->frameWidth;
249 break;
250 }
251
252 if (frameShadow == Sunken)
253 option->state |= QStyle::State_Sunken;
254 else if (frameShadow == Raised)
255 option->state |= QStyle::State_Raised;
256}
257
258
259/*!
260 Destroys the frame.
261 */
262QFrame::~QFrame()
263{
264}
265
266/*!
267 Returns the frame style.
268
269 The default value is QFrame::Plain.
270
271 \sa setFrameStyle(), frameShape(), frameShadow()
272*/
273int QFrame::frameStyle() const
274{
275 Q_D(const QFrame);
276 return d->frameStyle;
277}
278
279/*!
280 \property QFrame::frameShape
281 \brief the frame shape value from the frame style
282
283 \sa frameStyle(), frameShadow()
284*/
285
286QFrame::Shape QFrame::frameShape() const
287{
288 Q_D(const QFrame);
289 return (Shape) (d->frameStyle & Shape_Mask);
290}
291
292void QFrame::setFrameShape(QFrame::Shape s)
293{
294 Q_D(QFrame);
295 setFrameStyle((d->frameStyle & Shadow_Mask) | s);
296}
297
298
299/*!
300 \property QFrame::frameShadow
301 \brief the frame shadow value from the frame style
302
303 \sa frameStyle(), frameShape()
304*/
305QFrame::Shadow QFrame::frameShadow() const
306{
307 Q_D(const QFrame);
308 return (Shadow) (d->frameStyle & Shadow_Mask);
309}
310
311void QFrame::setFrameShadow(QFrame::Shadow s)
312{
313 Q_D(QFrame);
314 setFrameStyle((d->frameStyle & Shape_Mask) | s);
315}
316
317/*!
318 Sets the frame style to \a style.
319
320 The \a style is the bitwise OR between a frame shape and a frame
321 shadow style. See the picture of the frames in the main class
322 documentation.
323
324 The frame shapes are given in \l{QFrame::Shape} and the shadow
325 styles in \l{QFrame::Shadow}.
326
327 If a mid-line width greater than 0 is specified, an additional
328 line is drawn for \l Raised or \l Sunken \l Box, \l HLine, and \l
329 VLine frames. The mid-color of the current color group is used for
330 drawing middle lines.
331
332 \sa frameStyle()
333*/
334
335void QFrame::setFrameStyle(int style)
336{
337 Q_D(QFrame);
338 if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
339 QSizePolicy sp;
340
341 switch (style & Shape_Mask) {
342 case HLine:
343 sp = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, QSizePolicy::Line);
344 break;
345 case VLine:
346 sp = QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum, QSizePolicy::Line);
347 break;
348 default:
349 sp = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::Frame);
350 }
351 setSizePolicy(sp);
352 setAttribute(Qt::WA_WState_OwnSizePolicy, false);
353 }
354 d->frameStyle = (short)style;
355 update();
356 d->updateFrameWidth();
357}
358
359/*!
360 \property QFrame::lineWidth
361 \brief the line width
362
363 Note that the \e total line width for frames used as separators
364 (\l HLine and \l VLine) is specified by \l frameWidth.
365
366 The default value is 1.
367
368 \sa midLineWidth, frameWidth
369*/
370
371void QFrame::setLineWidth(int w)
372{
373 Q_D(QFrame);
374 if (short(w) == d->lineWidth)
375 return;
376 d->lineWidth = short(w);
377 d->updateFrameWidth();
378}
379
380int QFrame::lineWidth() const
381{
382 Q_D(const QFrame);
383 return d->lineWidth;
384}
385
386/*!
387 \property QFrame::midLineWidth
388 \brief the width of the mid-line
389
390 The default value is 0.
391
392 \sa lineWidth, frameWidth
393*/
394
395void QFrame::setMidLineWidth(int w)
396{
397 Q_D(QFrame);
398 if (short(w) == d->midLineWidth)
399 return;
400 d->midLineWidth = short(w);
401 d->updateFrameWidth();
402}
403
404int QFrame::midLineWidth() const
405{
406 Q_D(const QFrame);
407 return d->midLineWidth;
408}
409
410/*!
411 \internal
412 Updates the frame widths from the style.
413*/
414void QFramePrivate::updateStyledFrameWidths()
415{
416 Q_Q(const QFrame);
417 QStyleOptionFrame opt;
418 q->initStyleOption(&opt);
419
420 QRect cr = q->style()->subElementRect(QStyle::SE_ShapedFrameContents, &opt, q);
421 leftFrameWidth = cr.left() - opt.rect.left();
422 topFrameWidth = cr.top() - opt.rect.top();
423 rightFrameWidth = opt.rect.right() - cr.right(),
424 bottomFrameWidth = opt.rect.bottom() - cr.bottom();
425 frameWidth = qMax(qMax(leftFrameWidth, rightFrameWidth),
426 qMax(topFrameWidth, bottomFrameWidth));
427}
428
429/*!
430 \internal
431 Updated the frameWidth parameter.
432*/
433
434void QFramePrivate::updateFrameWidth()
435{
436 Q_Q(QFrame);
437 QRect fr = q->frameRect();
438 updateStyledFrameWidths();
439 q->setFrameRect(fr);
440 setLayoutItemMargins(QStyle::SE_FrameLayoutItem);
441}
442
443/*!
444 \property QFrame::frameWidth
445 \brief the width of the frame that is drawn.
446
447 Note that the frame width depends on the \l{QFrame::setFrameStyle()}{frame style},
448 not only the line width and the mid-line width. For example, the style specified
449 by \l NoFrame always has a frame width of 0, whereas the style \l Panel has a
450 frame width equivalent to the line width.
451
452 \sa lineWidth(), midLineWidth(), frameStyle()
453*/
454int QFrame::frameWidth() const
455{
456 Q_D(const QFrame);
457 return d->frameWidth;
458}
459
460
461/*!
462 \property QFrame::frameRect
463 \brief the frame's rectangle
464
465 The frame's rectangle is the rectangle the frame is drawn in. By
466 default, this is the entire widget. Setting the rectangle does
467 does \e not cause a widget update. The frame rectangle is
468 automatically adjusted when the widget changes size.
469
470 If you set the rectangle to a null rectangle (for example,
471 QRect(0, 0, 0, 0)), then the resulting frame rectangle is
472 equivalent to the \l{QWidget::rect()}{widget rectangle}.
473*/
474
475QRect QFrame::frameRect() const
476{
477 Q_D(const QFrame);
478 QRect fr = contentsRect();
479 fr.adjust(-d->leftFrameWidth, -d->topFrameWidth, d->rightFrameWidth, d->bottomFrameWidth);
480 return fr;
481}
482
483void QFrame::setFrameRect(const QRect &r)
484{
485 Q_D(QFrame);
486 QRect cr = r.isValid() ? r : rect();
487 cr.adjust(d->leftFrameWidth, d->topFrameWidth, -d->rightFrameWidth, -d->bottomFrameWidth);
488 setContentsMargins(cr.left(), cr.top(), rect().right() - cr.right(), rect().bottom() - cr.bottom());
489}
490
491/*!\reimp
492*/
493QSize QFrame::sizeHint() const
494{
495 Q_D(const QFrame);
496 // Returns a size hint for the frame - for HLine and VLine
497 // shapes, this is stretchable one way and 3 pixels wide the
498 // other. For other shapes, QWidget::sizeHint() is used.
499 switch (d->frameStyle & Shape_Mask) {
500 case HLine:
501 return QSize(-1,3);
502 case VLine:
503 return QSize(3,-1);
504 default:
505 return QWidget::sizeHint();
506 }
507}
508
509/*!\reimp
510*/
511
512void QFrame::paintEvent(QPaintEvent *)
513{
514 QPainter paint(this);
515 drawFrame(&paint);
516}
517
518/*!
519 \internal
520
521 Used by QLabel and QLCDNumber
522 */
523void QFrame::drawFrame(QPainter *p)
524{
525 QStyleOptionFrame opt;
526 initStyleOption(&opt);
527 style()->drawControl(QStyle::CE_ShapedFrame, &opt, p, this);
528}
529
530
531/*!\reimp
532 */
533void QFrame::changeEvent(QEvent *ev)
534{
535 Q_D(QFrame);
536 if (ev->type() == QEvent::StyleChange
537#ifdef Q_OS_MAC
538 || ev->type() == QEvent::MacSizeChange
539#endif
540 )
541 d->updateFrameWidth();
542 QWidget::changeEvent(ev);
543}
544
545/*! \reimp */
546bool QFrame::event(QEvent *e)
547{
548 if (e->type() == QEvent::ParentChange)
549 d_func()->updateFrameWidth();
550 bool result = QWidget::event(e);
551 //this has to be done after the widget has been polished
552 if (e->type() == QEvent::Polish)
553 d_func()->updateFrameWidth();
554 return result;
555}
556
557QT_END_NAMESPACE
558
559#include "moc_qframe.cpp"
560