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 <qstyle.h>
5#include <private/qproxystyle_p.h>
6#include <private/qapplication_p.h>
7#include "qproxystyle.h"
8#include "qstylefactory.h"
9#include <private/qstyle_p.h>
10
11#if !defined(QT_NO_STYLE_PROXY) || defined(QT_PLUGIN)
12
13QT_BEGIN_NAMESPACE
14
15using namespace Qt::StringLiterals;
16
17/*!
18 \class QProxyStyle
19
20 \brief The QProxyStyle class is a convenience class that simplifies
21 dynamically overriding QStyle elements.
22
23 \since 4.6
24
25 \inmodule QtWidgets
26
27 A QProxyStyle wraps a QStyle (usually the default system style) for the
28 purpose of dynamically overriding painting or other specific style behavior.
29
30 The following example shows how to override the shortcut underline
31 behavior on any platform:
32
33 \snippet code/src_gui_qproxystyle.cpp 1
34
35 Warning: The \l {QCommonStyle} {common styles} provided by Qt will
36 respect this hint, because they call QStyle::proxy(), but there is
37 no guarantee that QStyle::proxy() will be called for user defined
38 or system controlled styles. It would not work on a Mac, for
39 example, where menus are handled by the operating system.
40
41 When a proxy style should be set on a specific widget only, you have
42 to make sure to not set the proxy on the global application style which
43 is returned by QWidget::style(). You have to create a separate custom style
44 for the widget similar to:
45
46 \snippet code/src_gui_qproxystyle.cpp 2
47
48 \sa QStyle
49*/
50
51void QProxyStylePrivate::ensureBaseStyle() const
52{
53 Q_Q(const QProxyStyle);
54
55 if (baseStyle)
56 return;
57
58 if (!baseStyle && !QApplicationPrivate::styleOverride.isEmpty()) {
59 baseStyle = QStyleFactory::create(QApplicationPrivate::styleOverride);
60 if (baseStyle) {
61 // If baseStyle is an instance of the same proxyStyle
62 // we destroy it and fall back to the desktop style
63 if (qstrcmp(str1: baseStyle->metaObject()->className(),
64 str2: q->metaObject()->className()) == 0) {
65 delete baseStyle;
66 baseStyle = nullptr;
67 }
68 }
69 }
70
71 if (!baseStyle) // Use application desktop style
72 baseStyle = QStyleFactory::create(QApplicationPrivate::desktopStyleKey());
73
74 if (!baseStyle) // Fallback to windows style
75 baseStyle = QStyleFactory::create("windows"_L1);
76
77 baseStyle->setProxy(const_cast<QProxyStyle*>(q));
78 baseStyle->setParent(const_cast<QProxyStyle*>(q)); // Take ownership
79}
80
81/*!
82 Constructs a QProxyStyle object for overriding behavior in the
83 specified \a style, or in the default native \l{QApplication::style()}
84 {style} if \a style is not specified.
85
86 Ownership of \a style is transferred to QProxyStyle.
87*/
88QProxyStyle::QProxyStyle(QStyle *style) :
89 QCommonStyle(*new QProxyStylePrivate())
90{
91 Q_D(QProxyStyle);
92 if (style) {
93 d->baseStyle = style;
94 style->setProxy(this);
95 style->setParent(this); // Take ownership
96 }
97}
98
99/*!
100 Constructs a QProxyStyle object for overriding behavior in
101 the base style specified by style \a key, or in the current
102 \l{QApplication::style()}{application style} if the specified
103 style \a key is unrecognized.
104
105 \sa QStyleFactory::create()
106*/
107QProxyStyle::QProxyStyle(const QString &key)
108 : QProxyStyle(QStyleFactory::create(key))
109{
110}
111
112/*!
113 Destroys the QProxyStyle object.
114*/
115QProxyStyle::~QProxyStyle()
116{
117}
118
119/*!
120 Returns the proxy base style object. If no base style
121 is set on the proxy style, QProxyStyle will create
122 an instance of the application style instead.
123
124 \sa setBaseStyle(), QStyle
125*/
126QStyle *QProxyStyle::baseStyle() const
127{
128 Q_D (const QProxyStyle);
129 d->ensureBaseStyle();
130 return d->baseStyle;
131}
132
133/*!
134 Sets the base style that should be proxied.
135
136 Ownership of \a style is transferred to QProxyStyle.
137
138 If style is \nullptr, a desktop-dependent style will be
139 assigned automatically.
140*/
141void QProxyStyle::setBaseStyle(QStyle *style)
142{
143 Q_D (QProxyStyle);
144
145 if (d->baseStyle && d->baseStyle->parent() == this)
146 d->baseStyle->deleteLater();
147
148 d->baseStyle = style;
149
150 if (d->baseStyle) {
151 d->baseStyle->setProxy(this);
152 d->baseStyle->setParent(this);
153 }
154}
155
156/*! \reimp
157 */
158void QProxyStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
159{
160 Q_D (const QProxyStyle);
161 d->ensureBaseStyle();
162 d->baseStyle->drawPrimitive(pe: element, opt: option, p: painter, w: widget);
163}
164
165/*!
166 \reimp
167 */
168void QProxyStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
169{
170 Q_D (const QProxyStyle);
171 d->ensureBaseStyle();
172 d->baseStyle->drawControl(element, opt: option, p: painter, w: widget);
173}
174
175/*! \reimp
176 */
177void QProxyStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
178{
179 Q_D (const QProxyStyle);
180 d->ensureBaseStyle();
181 d->baseStyle->drawComplexControl(cc: control, opt: option, p: painter, widget);
182}
183
184/*! \reimp
185 */
186void QProxyStyle::drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal, bool enabled,
187 const QString &text, QPalette::ColorRole textRole) const
188{
189 Q_D (const QProxyStyle);
190 d->ensureBaseStyle();
191 d->baseStyle->drawItemText(painter, rect, flags, pal, enabled, text, textRole);
192}
193
194/*! \reimp
195 */
196void QProxyStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, const QPixmap &pixmap) const
197{
198 Q_D (const QProxyStyle);
199 d->ensureBaseStyle();
200 d->baseStyle->drawItemPixmap(painter, rect, alignment, pixmap);
201}
202
203/*! \reimp
204 */
205QSize QProxyStyle::sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const
206{
207 Q_D (const QProxyStyle);
208 d->ensureBaseStyle();
209 return d->baseStyle->sizeFromContents(ct: type, opt: option, contentsSize: size, w: widget);
210}
211
212/*! \reimp
213 */
214QRect QProxyStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
215{
216 Q_D (const QProxyStyle);
217 d->ensureBaseStyle();
218 return d->baseStyle->subElementRect(subElement: element, option, widget);
219}
220
221/*! \reimp
222 */
223QRect QProxyStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *option, SubControl sc, const QWidget *widget) const
224{
225 Q_D (const QProxyStyle);
226 d->ensureBaseStyle();
227 return d->baseStyle->subControlRect(cc, opt: option, sc, widget);
228}
229
230/*! \reimp
231 */
232QRect QProxyStyle::itemTextRect(const QFontMetrics &fm, const QRect &r, int flags, bool enabled, const QString &text) const
233{
234 Q_D (const QProxyStyle);
235 d->ensureBaseStyle();
236 return d->baseStyle->itemTextRect(fm, r, flags, enabled, text);
237}
238
239/*! \reimp
240 */
241QRect QProxyStyle::itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const
242{
243 Q_D (const QProxyStyle);
244 d->ensureBaseStyle();
245 return d->baseStyle->itemPixmapRect(r, flags, pixmap);
246}
247
248/*! \reimp
249 */
250QStyle::SubControl QProxyStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget) const
251{
252 Q_D (const QProxyStyle);
253 d->ensureBaseStyle();
254 return d->baseStyle->hitTestComplexControl(cc: control, opt: option, pt: pos, widget);
255}
256
257/*! \reimp
258 */
259int QProxyStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
260{
261 Q_D (const QProxyStyle);
262 d->ensureBaseStyle();
263 return d->baseStyle->styleHint(stylehint: hint, opt: option, widget, returnData);
264}
265
266/*! \reimp
267 */
268int QProxyStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
269{
270 Q_D (const QProxyStyle);
271 d->ensureBaseStyle();
272 return d->baseStyle->pixelMetric(metric, option, widget);
273}
274
275/*! \reimp
276 */
277QPixmap QProxyStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget) const
278{
279 Q_D (const QProxyStyle);
280 d->ensureBaseStyle();
281 return d->baseStyle->standardPixmap(standardPixmap, opt, widget);
282}
283
284/*! \reimp
285 */
286QPixmap QProxyStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const
287{
288 Q_D (const QProxyStyle);
289 d->ensureBaseStyle();
290 return d->baseStyle->generatedIconPixmap(iconMode, pixmap, opt);
291}
292
293/*! \reimp
294 */
295QPalette QProxyStyle::standardPalette() const
296{
297 Q_D (const QProxyStyle);
298 d->ensureBaseStyle();
299 return d->baseStyle->standardPalette();
300}
301
302/*! \reimp
303 */
304void QProxyStyle::polish(QWidget *widget)
305{
306 Q_D (QProxyStyle);
307 d->ensureBaseStyle();
308 d->baseStyle->polish(widget);
309}
310
311/*! \reimp
312 */
313void QProxyStyle::polish(QPalette &pal)
314{
315 Q_D (QProxyStyle);
316 d->ensureBaseStyle();
317 d->baseStyle->polish(palette&: pal);
318}
319
320/*! \reimp
321 */
322void QProxyStyle::polish(QApplication *app)
323{
324 Q_D (QProxyStyle);
325 d->ensureBaseStyle();
326 d->baseStyle->polish(application: app);
327}
328
329/*! \reimp
330 */
331void QProxyStyle::unpolish(QWidget *widget)
332{
333 Q_D (QProxyStyle);
334 d->ensureBaseStyle();
335 d->baseStyle->unpolish(widget);
336}
337
338/*! \reimp
339 */
340void QProxyStyle::unpolish(QApplication *app)
341{
342 Q_D (QProxyStyle);
343 d->ensureBaseStyle();
344 d->baseStyle->unpolish(application: app);
345}
346
347/*! \reimp
348 */
349bool QProxyStyle::event(QEvent *e)
350{
351 Q_D (QProxyStyle);
352
353 switch (e->type()) {
354 // The Mac style relies on these events in order to set the focus frame
355 case QEvent::FocusIn:
356 case QEvent::FocusOut:
357 d->ensureBaseStyle();
358 return QApplication::sendEvent(receiver: d->baseStyle, event: e);
359 default:
360 break;
361 }
362
363 return QCommonStyle::event(event: e);
364}
365
366/*!
367 Returns an icon for the given \a standardIcon.
368
369 Reimplement this slot to provide your own icons in a QStyle
370 subclass. The \a option argument can be used to pass extra
371 information required to find the appropriate icon. The \a widget
372 argument is optional and can also be used to help find the icon.
373 */
374QIcon QProxyStyle::standardIcon(StandardPixmap standardIcon,
375 const QStyleOption *option,
376 const QWidget *widget) const
377{
378 Q_D (const QProxyStyle);
379 d->ensureBaseStyle();
380 return d->baseStyle->standardIcon(standardIcon, option, widget);
381}
382
383/*!
384 This slot is called by layoutSpacing() to determine the spacing that
385 should be used between \a control1 and \a control2 in a layout. \a
386 orientation specifies whether the controls are laid out side by side
387 or stacked vertically. The \a option parameter can be used to pass
388 extra information about the parent widget. The \a widget parameter
389 is optional and can also be used if \a option is \nullptr.
390
391 The default implementation returns -1.
392
393 \sa combinedLayoutSpacing()
394 */
395int QProxyStyle::layoutSpacing(QSizePolicy::ControlType control1,
396 QSizePolicy::ControlType control2,
397 Qt::Orientation orientation,
398 const QStyleOption *option,
399 const QWidget *widget) const
400{
401 Q_D (const QProxyStyle);
402 d->ensureBaseStyle();
403 return d->baseStyle->layoutSpacing(control1, control2, orientation, option, widget);
404}
405
406QT_END_NAMESPACE
407
408#include "moc_qproxystyle.cpp"
409
410#endif // QT_NO_STYLE_PROXY
411

source code of qtbase/src/widgets/styles/qproxystyle.cpp