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

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