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

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