Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qstylekitstyle.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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// Qt-Security score:significant reason:default
4
7#include <QtWidgets/qstyleoption.h>
8#include <QtWidgets/qstyle.h>
9#include <QtWidgets/qapplication.h>
10#if QT_CONFIG(scrollarea)
11#include <QtWidgets/qabstractscrollarea.h>
12#endif
13#if QT_CONFIG(itemviews)
14#include <QtWidgets/qabstractitemview.h>
15#endif
16#if QT_CONFIG(lineedit)
17#include <QtWidgets/qlineedit.h>
18#endif
19#if QT_CONFIG(pushbutton)
20#include <QtWidgets/qpushbutton.h>
21#endif
22#if QT_CONFIG(checkbox)
23#include <QtWidgets/qcheckbox.h>
24#endif
25#if QT_CONFIG(radiobutton)
26#include <QtWidgets/qradiobutton.h>
27#endif
28#if QT_CONFIG(combobox)
29#include <QtWidgets/qcombobox.h>
30#endif
31#if QT_CONFIG(slider)
32#include <QtWidgets/qslider.h>
33#endif
34#if QT_CONFIG(scrollbar)
35#include <QtWidgets/qscrollbar.h>
36#endif
37#if QT_CONFIG(spinbox)
38#include <QtWidgets/qspinbox.h>
39#endif
40#if QT_CONFIG(progressbar)
41#include <QtWidgets/qprogressbar.h>
42#endif
43#if QT_CONFIG(textedit)
44#include <QtWidgets/qtextedit.h>
45#include <QtWidgets/qplaintextedit.h>
46#endif
47#if QT_CONFIG(tabbar)
48#include <QtWidgets/qtabbar.h>
49#endif
50#if QT_CONFIG(toolbar)
51#include <QtWidgets/qtoolbar.h>
52#endif
53#if QT_CONFIG(groupbox)
54#include <QtWidgets/qgroupbox.h>
55#endif
56#if QT_CONFIG(menu)
57#include <QtWidgets/qmenu.h>
58#endif
59#if QT_CONFIG(label)
60#include <QtWidgets/qlabel.h>
61#endif
62#include <QtWidgets/private/qwidget_p.h>
63#include <QtGui/qpainter.h>
64#include <QtGui/qpainterpath.h>
65#include <QtGui/qpainterstateguard.h>
66#include <QtGui/qstylehints.h>
67#include <QtQml/private/qqmlcomponent_p.h>
68#include <QtLabsStyleKit/private/qqstylekit_p.h>
69#include <QtLabsStyleKit/private/qqstylekitcontrolproperties_p.h>
70#include <QtLabsStyleKit/private/qqstylekitstyle_p.h>
71
73
74/*!
75 \class QStyleKitStyle
76 \inmodule QtLabsStyleKit
77 \ingroup appearance
78 \since 6.12
79
80 \brief The QStyleKitStyle class applies a \l {Qt Labs StyleKit} style
81 to Qt Widgets.
82
83 QStyleKitStyle is a QStyle implementation that uses a \l StyleKit \l Style
84 to style Qt Widgets. It loads the Style at the local path specified by
85 \l stylePath, and uses it to resolve style properties such as colors,
86 fonts, and sizes for widgets in various states, in order to paint them
87 according to the style's design. This allows the same StyleKit style to be
88 shared between Qt Quick Controls and Qt Widgets.
89
90 \note StyleKit is a Qt Labs module, and its API may change between
91 Qt releases.
92
93 \section1 Loading a Style
94
95 A style is a QML file whose root object is a \l Style. To load it,
96 pass the file path to the constructor or to \l setStylePath():
97
98 \code
99 auto *style = new QStyleKitStyle(QStringLiteral("qrc:/styles/MyStyle.qml"));
100 QApplication::setStyle(style);
101 \endcode
102
103 QStyleKitStyle is also registered as a QStyleFactory plugin under the
104 key \c StyleKit, which can be selected via the \c -style command line
105 argument or QApplication::setStyle(). When created through the
106 factory, set \l stylePath after construction to load a style file.
107
108 \code
109 auto *style = QStyleFactory::create("StyleKit");
110 style->setProperty("stylePath", QStringLiteral("qrc:/styles/MyStyle.qml"));
111 QApplication::setStyle(style);
112 \endcode
113
114 The Style is loaded with an internal QQmlEngine owned by the
115 QStyleKitStyle instance. If the URL is invalid or the root object is
116 not a \l Style, a warning is emitted and the style behaves like
117 QCommonStyle until a valid \l stylePath is set.
118
119 \section1 Themes
120
121 A Style may define one or more named \l {Theme}{themes}. The active
122 theme is selected with \l setThemeName(); the list of available
123 themes is exposed through \l themeNames. The special theme name
124 \c System makes the style follow the platform color scheme: when the
125 OS color scheme changes, the active theme is recreated automatically
126 and all widgets are repolished.
127
128 \sa QStyle, QCommonStyle, QStyleFactory, {Qt Labs StyleKit}, Style, Theme
129*/
130
131/*!
132 \property QStyleKitStyle::stylePath
133 \brief the URL of the QML \l Style file driving this style.
134
135 The URL must resolve to a QML component whose root object is a
136 \l Style. Setting this property reloads the style; if the new file
137 cannot be loaded, the previously loaded style is kept and a warning
138 is emitted.
139
140 \note The file specified by \l stylePath must be a local file. Remote files
141 (e.g., HTTP URLs) are not supported.
142*/
143
144/*!
145 \property QStyleKitStyle::themeName
146 \brief the name of the active theme.
147
148 The value must be one of the entries in \l themeNames, or the
149 special name \c System to follow the platform color scheme.
150 Setting this property updates all widgets to repaint with the
151 new theme.
152*/
153
154/*!
155 \property QStyleKitStyle::themeNames
156 \brief the list of theme names exposed by the loaded \l Style.
157
158 This list includes the built-in \c Light and \c Dark themes as well
159 as any custom themes defined by the style.
160*/
161
163{
164 if (!widget)
165 return QQStyleKitReader::Control;
166
167#if QT_CONFIG(pushbutton)
168 if (qobject_cast<const QPushButton *>(widget))
169 return QQStyleKitReader::Button;
170#endif
171#if QT_CONFIG(checkbox)
172 if (qobject_cast<const QCheckBox *>(widget))
173 return QQStyleKitReader::CheckBox;
174#endif
175#if QT_CONFIG(radiobutton)
176 if (qobject_cast<const QRadioButton *>(widget))
177 return QQStyleKitReader::RadioButton;
178#endif
179#if QT_CONFIG(combobox)
180 if (qobject_cast<const QComboBox *>(widget))
181 return QQStyleKitReader::ComboBox;
182#endif
183#if QT_CONFIG(slider)
184 if (qobject_cast<const QSlider *>(widget))
185 return QQStyleKitReader::Slider;
186#endif
187#if QT_CONFIG(scrollbar)
188 if (qobject_cast<const QScrollBar *>(widget))
189 return QQStyleKitReader::ScrollBar;
190#endif
191#if QT_CONFIG(spinbox)
192 if (qobject_cast<const QSpinBox *>(widget) || qobject_cast<const QDoubleSpinBox *>(widget))
193 return QQStyleKitReader::SpinBox;
194#endif
195#if QT_CONFIG(itemviews)
196 if (qobject_cast<const QAbstractItemView *>(widget))
197 return QQStyleKitReader::ItemDelegate;
198#endif
199#if QT_CONFIG(progressbar)
200 if (qobject_cast<const QProgressBar *>(widget))
201 return QQStyleKitReader::ProgressBar;
202#endif
203#if QT_CONFIG(lineedit)
204 if (qobject_cast<const QLineEdit *>(widget))
205 return QQStyleKitReader::TextField;
206#endif
207#if QT_CONFIG(textedit)
208 if (qobject_cast<const QTextEdit *>(widget) || qobject_cast<const QPlainTextEdit *>(widget))
209 return QQStyleKitReader::TextArea;
210#endif
211#if QT_CONFIG(tabbar)
212 if (qobject_cast<const QTabBar *>(widget))
213 return QQStyleKitReader::TabBar;
214#endif
215#if QT_CONFIG(toolbar)
216 if (qobject_cast<const QToolBar *>(widget))
217 return QQStyleKitReader::ToolBar;
218#endif
219#if QT_CONFIG(groupbox)
220 if (qobject_cast<const QGroupBox *>(widget))
221 return QQStyleKitReader::GroupBox;
222#endif
223 if (widget->windowType() & Qt::Popup)
224 return QQStyleKitReader::Popup;
225 if (widget->windowType() & Qt::Dialog)
226 return QQStyleKitReader::Dialog;
227 if (widget->windowType() & Qt::Window)
228 return QQStyleKitReader::ApplicationWindow;
229#ifndef QT_NO_FRAME
230 if (qobject_cast<const QFrame *>(widget))
231 return QQStyleKitReader::Frame;
232#endif
233
234 return QQStyleKitReader::Control;
235}
236
237static uint resolvedAlignment(uint raw, Qt::Alignment hDefault, Qt::Alignment vDefault)
238{
239 uint result = 0;
240 const uint h = raw & Qt::AlignHorizontal_Mask;
241 const uint v = raw & Qt::AlignVertical_Mask;
242 result |= h ? h : uint(hDefault);
243 result |= v ? v : uint(vDefault);
244 return result;
245}
246
247// Copied from qstylesheetstyle.cpp
248static const QWidget *containerWidget(const QWidget *w)
249{
250#if QT_CONFIG(lineedit)
251 if (qobject_cast<const QLineEdit *>(w)) {
252 //if the QLineEdit is an embeddedWidget, we need the real widget
253 QWidget *parent = w->parentWidget();
254 if (false
255#if QT_CONFIG(combobox)
256 || qobject_cast<const QComboBox *>(parent)
257#endif
258#if QT_CONFIG(spinbox)
259 || qobject_cast<const QAbstractSpinBox *>(parent)
260#endif
261 ) {
262 return parent;
263 }
264 }
265#endif
266
267#if QT_CONFIG(scrollarea)
268 if (const QAbstractScrollArea *sa = qobject_cast<const QAbstractScrollArea *>(w->parentWidget())) {
269 if (sa->viewport() == w)
270 return w->parentWidget();
271 }
272#endif
273
274 return w;
275}
276
277QStyleKitStylePrivate::QStyleKitStylePrivate()
278 : QCommonStylePrivate()
279{
280}
281
282bool QStyleKitStylePrivate::loadStyle()
283{
284 Q_Q(QStyleKitStyle);
285 if (!qmlEngine)
286 qmlEngine = new QQmlEngine(q);
287
288 if (!qmlEngine) {
289 qWarning("QStyleKitStyle: No QML engine available to load style.");
290 return false;
291 }
292 const QUrl url(stylePath);
293 if (stylePath.isEmpty() || !url.isValid()) {
294 qWarning("QStyleKitStyle: No valid style path provided: %s", qPrintable(stylePath));
295 return false;
296 }
297 // TODO: Support async loading
298 // For now warn and fail if the URL is not a local file or qrc resource, as
299 // QQmlComponent loads them asynchronously but loadStyle() expects the style to be loaded synchronously
300 if (!url.isLocalFile() && url.scheme() != QLatin1String("qrc")) {
301 qWarning("QStyleKitStyle: only local files and qrc resources are supported as stylePath, got: %s",
302 qPrintable(stylePath));
303 return false;
304 }
305 QQmlComponent component(qmlEngine, url);
306 // Avoid creating anything other than StyleKit Style objects
307 // by checking the metaobject of the root type before creating the object
308 QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(&component);
309 const auto compilationUnit = componentPrivate->compilationUnit();
310 const auto propertyCache = compilationUnit ? compilationUnit->rootPropertyCache() : nullptr;
311 const auto firstMetaObject = propertyCache ? propertyCache->firstCppMetaObject() : nullptr;
312 if (!firstMetaObject || !firstMetaObject->inherits(&QQStyleKitStyle::staticMetaObject)) {
313 qWarning("QStyleKitStyle: Failed to load style from %s: component is not a StyleKit Style.",
314 qPrintable(stylePath));
315 return false;
316 }
317 if (component.isError()) {
318 qWarning("QStyleKitStyle: Failed to load style from %s: %s",
319 qPrintable(stylePath), qPrintable(component.errorString()));
320 return false;
321 }
322 QQStyleKitStyle *styleObject = qobject_cast<QQStyleKitStyle *>(component.create());
323 if (!styleObject) {
324 qWarning("QStyleKitStyle: Failed to create style object from %s: component is not a StyleKit style.",
325 qPrintable(stylePath));
326 return false;
327 }
328 const bool isReload = style != nullptr;
329 delete style;
330 style = styleObject;
331 style->setParent(q);
332
333 if (!isReload) {
334 QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, q, [this]() {
335 if (style && style->themeName() == QLatin1String("System")) {
336 style->recreateTheme();
337 updateStyle();
338 }
339 });
340 }
341
342 if (style->loaded())
343 QQStyleKitReader::resetReadersForStyle(style);
344
345 return true;
346}
347
348void QStyleKitStylePrivate::updateStyle()
349{
350 clearMetricsCache();
351
352 if (sharedReader && sharedReader->style() != style)
353 sharedReader->setExplicitStyle(style);
354
355 for (const auto &byItem : std::as_const(itemViewItemReaders)) {
356 for (auto *reader : std::as_const(byItem)) {
357 if (reader && reader->style() != style)
358 reader->setExplicitStyle(style);
359 }
360 }
361
362 for (auto *wr : std::as_const(widgetReaders)) {
363 if (wr->style() != style)
364 wr->setExplicitStyle(style);
365 }
366
367 if (!QWidgetPrivate::allWidgets)
368 return;
369
370 for (auto *widget : std::as_const(*QWidgetPrivate::allWidgets)) {
371 if (customFontWidgets.contains(widget))
372 unsetStyleFont(widget);
373 setStyleFont(widget);
374 if (customPaletteWidgets.contains(widget))
375 unsetStylePalette(widget);
376 refreshStylePalette(widget);
377 }
378
379 QEvent styleChange(QEvent::StyleChange);
380 for (auto *widget : std::as_const(*QWidgetPrivate::allWidgets)) {
381 QApplication::sendEvent(widget, &styleChange);
382 widget->update();
383 }
384}
385
386// Follow the approach in qstylesheetstyle.cpp
387void QStyleKitStylePrivate::unsetStyleFont(QWidget *widget)
388{
389 auto it = customFontWidgets.find(widget);
390 if (it == customFontWidgets.end())
391 return;
392
393 auto customFont = std::move(*it);
394 customFontWidgets.erase(it);
395 widget->setFont(std::move(customFont).reverted(widget->font()));
396}
397
398void QStyleKitStylePrivate::setStyleFont(QWidget *widget)
399{
400 if (!style || !widget)
401 return;
402
403 const QWidget *targetWidget = containerWidget(widget);
404 QQStyleKitReader::ControlType controlType = controlTypeForWidget(targetWidget);
405
406 const QFont styleFont = style->fontForControlType(controlType);
407
408 if (styleFont.resolveMask() == 0)
409 return;
410
411 if (!customFontWidgets.contains(widget)) {
412 customFontWidgets.insert(widget, { widget->font(), 0 });
413 QObject::connect(widget, &QObject::destroyed, widget, [this, widget]() {
414 customFontWidgets.remove(widget);
415 });
416 }
417
418 const quint64 styleMask = styleFont.resolveMask();
419 customFontWidgets[widget].resolveMask |= styleMask;
420
421 QFont merged = styleFont.resolve(widget->font());
422 merged.setResolveMask(widget->font().resolveMask() | styleMask);
423 widget->setFont(merged);
424}
425
426void QStyleKitStylePrivate::unsetStylePalette(QWidget *widget)
427{
428 auto it = customPaletteWidgets.find(widget);
429 if (it == customPaletteWidgets.end())
430 return;
431
432 Q_Q(QStyleKitStyle);
433 widget->removeEventFilter(q);
434
435 auto customPalette = std::move(*it);
436 customPaletteWidgets.erase(it);
437 widget->setPalette(std::move(customPalette).reverted(widget->palette()));
438}
439
440void QStyleKitStylePrivate::setStylePalette(QWidget *widget, const QPalette &stylePalette) const
441{
442 if (!style || !widget)
443 return;
444
445 const quint64 styleMask = stylePalette.resolveMask();
446 if (styleMask == 0)
447 return;
448
449 if (!customPaletteWidgets.contains(widget)) {
450 customPaletteWidgets.insert(widget, { widget->palette(), 0 });
451 QObject::connect(widget, &QObject::destroyed, widget, [this, widget]() {
452 customPaletteWidgets.remove(widget);
453 });
454 }
455
456 customPaletteWidgets[widget].resolveMask |= styleMask;
457 QPalette merged = stylePalette.resolve(widget->palette());
458 merged.setResolveMask(widget->palette().resolveMask() | styleMask);
459 widget->setPalette(merged);
460}
461
462// For widgets that partially or fully draw themselves (instead of delegating to the style),
463// using palette roles, we need to push the style colors to those roles
464void QStyleKitStylePrivate::refreshStylePalette(QWidget *widget)
465{
466 if (!style || !widget)
467 return;
468
469 const bool isWindow = widget->windowType() & (Qt::Popup | Qt::Window | Qt::Dialog);
470 const bool isPaletteManaged = false
471#if QT_CONFIG(label)
472 || qobject_cast<const QLabel *>(widget)
473#endif
474#if QT_CONFIG(textedit)
475 || qobject_cast<const QTextEdit *>(widget)
476 || qobject_cast<const QPlainTextEdit *>(widget)
477#endif
478 || isWindow;
479 if (!isPaletteManaged)
480 return;
481
482 const QWidget *targetWidget = containerWidget(widget);
483 QQStyleKitReader::ControlType controlType = controlTypeForWidget(targetWidget);
484
485 auto *shared = ensureSharedReader();
486 if (!shared)
487 return;
488
489 QStyleOption opt;
490 opt.initFrom(targetWidget);
491 const QQSK::State currentState = resolvedStateFor(controlType, opt.state);
492
493 QPalette stylePalette;
494 if (isWindow) {
495 // Windows draw their own background using the QPalette::Window role
496 shared->setControlTypeAndState(controlType, currentState);
497 if (const auto *bg = shared->global()->background(); bg && bg->isDefined(QQSK::Property::Color))
498 stylePalette.setColor(QPalette::Window, bg->color());
499 shared->setControlTypeAndState(controlType, QQSK::StateFlag::Disabled);
500 if (const auto *dbg = shared->global()->background(); dbg && dbg->isDefined(QQSK::Property::Color))
501 stylePalette.setColor(QPalette::Disabled, QPalette::Window, dbg->color());
502 } else {
503 // The remaining text-based widgets use the QPalette::Text/WindowText roles for their foreground color
504 shared->setControlTypeAndState(controlType, currentState);
505 if (const auto *text = shared->global()->text(); text && text->isDefined(QQSK::Property::Color)) {
506 stylePalette.setColor(QPalette::Text, text->color());
507 stylePalette.setColor(QPalette::WindowText, text->color());
508 }
509 shared->setControlTypeAndState(controlType, QQSK::StateFlag::Disabled);
510 if (const auto *dt = shared->global()->text(); dt && dt->isDefined(QQSK::Property::Color)) {
511 stylePalette.setColor(QPalette::Disabled, QPalette::Text, dt->color());
512 stylePalette.setColor(QPalette::Disabled, QPalette::WindowText, dt->color());
513 }
514
515 // Track state changes to update the text color if it changes btw states (e.g. hover/pressed)
516 if (!customPaletteWidgets.contains(widget)) {
517 Q_Q(QStyleKitStyle);
518 widget->installEventFilter(q);
519 }
520 }
521
522 setStylePalette(widget, stylePalette);
523}
524
525/*! \internal
526 Returns a reader for the given widget, creating and caching it if needed.
527*/
528QQStyleKitReader *QStyleKitStylePrivate::readerForWidget(const QWidget *widget) const
529{
530 Q_Q(const QStyleKitStyle);
531 if (!style || !widget)
532 return nullptr;
533
534 if (auto it = widgetReaders.find(widget); it != widgetReaders.end())
535 return *it;
536
537 auto *widgetReader = new QQStyleKitReader(const_cast<QStyleKitStyle *>(q));
538 widgetReader->setExplicitStyle(style);
539 widgetReader->setTarget(const_cast<QWidget *>(widget));
540 widgetReaders.insert(widget, widgetReader);
541 QObject::connect(widget, &QObject::destroyed, q, [this, widget]() {
542 cleanupWidgetReader(widget);
543 });
544 return widgetReader;
545}
546
547void QStyleKitStylePrivate::cleanupWidgetReader(const QWidget *widget) const
548{
549 if (auto *reader = widgetReaders.take(widget))
550 reader->deleteLater();
551 cleanupItemViewItemReaders(widget);
552}
553
554/*! \internal
555 Returns a unique key for the given item view item, or 0 if the option is not an item view item.
556 The key is used to cache a reader for the item.
557*/
558quint64 QStyleKitStylePrivate::itemViewItemKeyForOption(const QStyleOption *opt)
559{
560 if (const auto *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
561 const auto &idx = viewOpt->index;
562 if (!idx.isValid())
563 return 0;
564
565 // Generate a unique key for the item using its row, column, and internalId
566 return qHashMulti(0, idx.row(), idx.column(), quint64(idx.internalId()));
567 }
568 return 0;
569}
570
571/*! \internal
572 Returns a reader for the given item view item, creating and caching it if needed.
573 Each item gets its own reader so that transitions for different items animate independently.
574*/
575QQStyleKitReader *QStyleKitStylePrivate::readerForItemViewItem(
576 const QWidget *widget, quint64 itemKey) const
577{
578 Q_Q(const QStyleKitStyle);
579 if (!style)
580 return nullptr;
581
582 auto &byItem = itemViewItemReaders[widget];
583 if (auto it = byItem.find(itemKey); it != byItem.end())
584 return *it;
585
586 auto *reader = new QQStyleKitReader(const_cast<QStyleKitStyle *>(q));
587 reader->setExplicitStyle(style);
588 reader->setTarget(const_cast<QWidget *>(widget));
589 byItem.insert(itemKey, reader);
590 return reader;
591}
592
593void QStyleKitStylePrivate::cleanupItemViewItemReaders(const QWidget *widget) const
594{
595 const auto readers = itemViewItemReaders.take(widget);
596 for (auto *reader : readers)
597 reader->deleteLater();
598}
599
600/*! \internal
601 Resolves the given QStyle::State into a QQSK::State based on the mapping of
602 state flags for the given control type.
603*/
604QQSK::State QStyleKitStylePrivate::resolvedStateFor(
605 QQStyleKitReader::ControlType type, QStyle::State state) const
606{
607 QQSK::State flags;
608 flags.setFlag(QQSK::StateFlag::Disabled, !(state & QStyle::State_Enabled));
609 flags.setFlag(QQSK::StateFlag::Hovered, (state & QStyle::State_MouseOver));
610 flags.setFlag(QQSK::StateFlag::Pressed, state & QStyle::State_Sunken);
611 flags.setFlag(QQSK::StateFlag::Checked, state & QStyle::State_On);
612 flags.setFlag(QQSK::StateFlag::Focused, state & QStyle::State_HasFocus);
613 flags.setFlag(QQSK::StateFlag::Highlighted, state & QStyle::State_Selected);
614 flags.setFlag(QQSK::StateFlag::Vertical, !(state & QStyle::State_Horizontal));
615
616 // ComboBox uses QStyle::State_On to indicate the popup is open, which is
617 // not a "checked" semantic.
618 if (type == QQStyleKitReader::ControlType::ComboBox)
619 flags.setFlag(QQSK::StateFlag::Checked, false);
620
621 // Popup has no hover state in the Controls style
622 if (type == QQStyleKitReader::ControlType::Popup)
623 flags.setFlag(QQSK::StateFlag::Hovered, false);
624
625 return flags;
626}
627
628/*! \internal
629 Returns the ControlMetrics for the given control type and state,
630 reading from the style if needed and caching the result.
631*/
632const QStyleKitStylePrivate::ControlMetrics &QStyleKitStylePrivate::metricsFor(
633 QQStyleKitReader::ControlType type, QQSK::State state) const
634{
635 if (auto it = metricsCache.find({type, state}); it != metricsCache.end())
636 return *it;
637
638 auto *reader = ensureSharedReader();
639 Q_ASSERT(reader);
640 reader->setControlTypeAndState(type, state);
641 return *metricsCache.insert({type, state}, metricsForReader(reader));
642}
643
644/*! \internal
645 Resolves the properties for the given widget, control type and state,
646 and returns them as a QQStyleKitResolved.
647*/
648QStyleKitStylePrivate::QQStyleKitResolved QStyleKitStylePrivate::resolve(
649 const QWidget *w, QQStyleKitReader::ControlType type, QStyle::State state) const
650{
651 QQStyleKitResolved out;
652 out.widget = w;
653
654 auto *reader = readerForWidget(w);
655 if (!reader)
656 return out;
657
658 const QQSK::State resolvedState = resolvedStateFor(type, state);
659 reader->setControlTypeAndState(type, resolvedState);
660
661 out.reader = reader;
662 out.metrics = &metricsFor(type, resolvedState);
663 return out;
664}
665
666/*! \internal
667 Resolves the properties for the given item view item, control type and state,
668 and returns them as a QQStyleKitResolved.
669 Falls back to resolve() if the option is not an item view item.
670*/
671QStyleKitStylePrivate::QQStyleKitResolved QStyleKitStylePrivate::resolveItemViewItem(
672 const QWidget *w, const QStyleOption *opt,
673 QQStyleKitReader::ControlType type, QStyle::State state) const
674{
675 // Same machinery as resolve(), but for sub-elements that have their own state
676 // (item view rows/cells). Each (widget, itemKey) gets its own reader
677 // so transitions for different items animate independently.
678 // Falls back to the widget reader
679 const quint64 itemKey = itemViewItemKeyForOption(opt);
680 if (itemKey == 0)
681 return resolve(w, type, state);
682
683 auto *reader = readerForItemViewItem(w, itemKey);
684 if (!reader)
685 return resolve(w, type, state);
686
687 const QQSK::State resolvedState = resolvedStateFor(type, state);
688 reader->setControlTypeAndState(type, resolvedState);
689
690 QQStyleKitResolved out;
691 out.widget = w;
692 out.reader = reader;
693 out.metrics = &metricsFor(type, resolvedState);
694 return out;
695}
696
697const QQStyleKitTextProperties *QStyleKitStylePrivate::QQStyleKitResolved::text() const
698{
699 return reader ? reader->text() : nullptr;
700}
701
702const QQStyleKitDelegateProperties *QStyleKitStylePrivate::QQStyleKitResolved::background() const
703{
704 return reader ? reader->background() : nullptr;
705}
706
707const QQStyleKitHandleProperties *QStyleKitStylePrivate::QQStyleKitResolved::handle() const
708{
709 return reader ? reader->handle() : nullptr;
710}
711
712const QQStyleKitIndicatorWithSubTypes *QStyleKitStylePrivate::QQStyleKitResolved::indicator() const
713{
714 return reader ? reader->indicator() : nullptr;
715}
716
717QFont QStyleKitStylePrivate::QQStyleKitResolved::font() const
718{
719 return reader ? reader->font() : QFont();
720}
721
722QQStyleKitReader *QStyleKitStylePrivate::ensureSharedReader() const
723{
724 if (sharedReader)
725 return sharedReader;
726
727 Q_Q(const QStyleKitStyle);
728 if (!style)
729 return nullptr;
730 sharedReader = new QQStyleKitReader(const_cast<QStyleKitStyle *>(q));
731 // Disable transitions since this reader is used for one-off metric reads in layout queries
732 sharedReader->setTransitionsEnabled(false);
733 sharedReader->setExplicitStyle(style);
734 return sharedReader;
735}
736
737/*! \internal
738 Resolves the properties for the given control type and state using the shared reader,
739 which disables transitions and is used for layout queries, so that layout never depends
740 on animation state.
741*/
742QStyleKitStylePrivate::QQStyleKitLayoutResolved QStyleKitStylePrivate::resolveLayout(
743 QQStyleKitReader::ControlType type, QStyle::State state) const
744{
745 QQStyleKitLayoutResolved out;
746 auto *reader = ensureSharedReader();
747 if (!reader)
748 return out;
749
750 const QQSK::State resolvedState = resolvedStateFor(type, state);
751 out.metrics = &metricsFor(type, resolvedState);
752 // metricsFor() sets the sharedReader to (type, resolvedState) on cache miss.
753 // On hit it didn't, so make sure staticProps / staticFont reflect the state
754 // and type of the caller
755 reader->setControlTypeAndState(type, resolvedState);
756 out.staticProps = reader->global();
757 out.staticFont = reader->font();
758 return out;
759}
760
761const QQStyleKitTextProperties *QStyleKitStylePrivate::QQStyleKitLayoutResolved::text() const
762{
763 return staticProps ? staticProps->text() : nullptr;
764}
765
766const QQStyleKitDelegateProperties *QStyleKitStylePrivate::QQStyleKitLayoutResolved::background() const
767{
768 return staticProps ? staticProps->background() : nullptr;
769}
770
771const QQStyleKitHandleProperties *QStyleKitStylePrivate::QQStyleKitLayoutResolved::handle() const
772{
773 return staticProps ? staticProps->handle() : nullptr;
774}
775
776const QQStyleKitIndicatorWithSubTypes *QStyleKitStylePrivate::QQStyleKitLayoutResolved::indicator() const
777{
778 return staticProps ? staticProps->indicator() : nullptr;
779}
780
781void QStyleKitStylePrivate::clearMetricsCache()
782{
783 metricsCache.clear();
784}
785
786void QStyleKitStylePrivate::drawControlIndicator(const QQStyleKitDelegateProperties *indicator, const QRectF &rect, QPainter *painter) const
787{
788 if (!indicator || !rect.isValid())
789 return;
790
791 // indicator (background)
792 QRectF indicatorRect = rect;
793 if (indicator->visible() && indicator->opacity() > 0)
794 drawStyledItemRect(indicator, indicatorRect, painter);
795
796 const QQStyleKitDelegateProperties *foreground = nullptr;
797 if (auto *indicatorWithSubTypes = qobject_cast<const QQStyleKitIndicatorWithSubTypes *>(indicator)) {
798 foreground = indicatorWithSubTypes->foreground();
799 } else if (auto *indicatorProps = qobject_cast<const QQStyleKitIndicatorProperties *>(indicator)) {
800 foreground = indicatorProps->foreground();
801 } else {
802 return;
803 }
804 if (!foreground || !foreground->visible() || foreground->opacity() <= 0)
805 return;
806
807 // foreground
808 QRectF foregroundRect;
809 const uint foregroundAlign = resolvedAlignment(foreground->alignment(), Qt::AlignHCenter, Qt::AlignVCenter);
810 const auto foregroundW = foreground->implicitWidth() >= 0 ? foreground->implicitWidth() : indicatorRect.width() - foreground->leftMargin() - foreground->rightMargin();
811 const auto foregroundH = foreground->implicitHeight() >= 0 ? foreground->implicitHeight() : indicatorRect.height() - foreground->topMargin() - foreground->bottomMargin();
812 foregroundRect.setSize(QSizeF(foregroundW, foregroundH));
813 if (foregroundAlign & Qt::AlignLeft)
814 foregroundRect.moveLeft(indicatorRect.left() + foreground->leftMargin());
815 else if (foregroundAlign & Qt::AlignHCenter)
816 foregroundRect.moveLeft(indicatorRect.left() + (indicatorRect.width() - foregroundW) / 2.0);
817 else if (foregroundAlign & Qt::AlignRight)
818 foregroundRect.moveLeft(indicatorRect.right() - foreground->rightMargin() - foregroundW);
819 if (foregroundAlign & Qt::AlignTop)
820 foregroundRect.moveTop(indicatorRect.top() + foreground->topMargin());
821 else if (foregroundAlign & Qt::AlignVCenter)
822 foregroundRect.moveTop(indicatorRect.top() + (indicatorRect.height() - foregroundH) / 2.0);
823 else if (foregroundAlign & Qt::AlignBottom)
824 foregroundRect.moveTop(indicatorRect.bottom() - foreground->bottomMargin() - foregroundH);
825 drawStyledItemRect(foreground, foregroundRect, painter);
826}
827
828void QStyleKitStylePrivate::drawControlText(const QQStyleKitTextProperties *textProps,
829 const QFont &font, const QRect &rect,
830 const QString &text, uint textFlags, QPainter *p) const
831{
832 uint flags = textFlags;
833 flags |= textProps
834 ? resolvedAlignment(textProps->alignment(), Qt::AlignHCenter, Qt::AlignVCenter)
835 : uint(Qt::AlignHCenter | Qt::AlignVCenter);
836
837 const QFont oldFont = p->font();
838 p->setFont(font.resolve(oldFont));
839 p->setBrush(Qt::NoBrush);
840 p->setPen(textProps ? textProps->color() : QColor());
841 p->drawText(rect, flags, text, nullptr);
842}
843
844void QStyleKitStylePrivate::drawStyledItemRect(const QQStyleKitDelegateProperties *props, const QRectF &rect, QPainter *painter) const
845{
846 if (!props || !props->visible() || props->opacity() <= 0 || !rect.isValid())
847 return;
848
849 QPainterStateGuard stateGuard(painter);
850 painter->setRenderHint(QPainter::Antialiasing, true);
851 painter->setClipping(props->clip());
852
853 // opacity
854 const auto opacity = props->opacity();
855
856 // border
857 const auto *border = props->border();
858 auto borderWidth = 0;
859 auto inset = 0.0;
860 QColor borderColor;
861 if (border) {
862 borderWidth = border->width();
863 borderColor = border->color();
864 inset = borderWidth / 2.0;
865 }
866 if (borderWidth > 0 && borderColor.isValid() && borderColor.alpha() > 0) {
867 QPen pen(borderColor, borderWidth);
868 painter->setPen(pen);
869 } else {
870 painter->setPen(Qt::NoPen);
871 }
872
873 // radius
874 // TODO: support different radius for each corner
875 const qreal minDimension = qMin(rect.width(), rect.height());
876 const qreal xRadius = qMax(0.0, qMin(props->topLeftRadius() - inset, minDimension / 2.0));
877 const qreal yRadius = qMax(0.0, qMin(props->bottomLeftRadius() - inset, minDimension / 2.0));
878
879 QRectF adjustedRect = rect.adjusted(inset, inset, -inset, -inset);
880
881 // rotation
882 if (props->rotation() != 0) {
883 const auto center = rect.center();
884 painter->translate(center);
885 painter->rotate(props->rotation());
886 painter->translate(-center);
887 }
888
889 // gradients/color
890 // TODO: support palette roles for colors and gradients
891 QColor color = props->color();
892 QBrush colorBrush(color);
893 painter->setBrush(colorBrush);
894 if (color.isValid()) {
895 painter->setOpacity(opacity);
896 painter->drawRoundedRect(adjustedRect, xRadius, yRadius, Qt::AbsoluteSize);
897 }
898 if (QQuickGradient *gradient = props->gradient()) {
899 QLinearGradient linearGradient(rect.topLeft(), rect.bottomLeft());
900 QQmlListProperty<QQuickGradientStop> stops = gradient->stops();
901 const int stopCount = stops.count(&stops);
902 for (int i = 0; i < stopCount; i++) {
903 QQuickGradientStop *stop = static_cast<QQuickGradientStop*>(stops.at(&stops, i));
904 linearGradient.setColorAt(stop->position(), stop->color());
905 }
906 QBrush gradientBrush(linearGradient);
907 painter->setBrush(gradientBrush);
908 painter->setOpacity(opacity);
909 painter->drawRoundedRect(adjustedRect, xRadius, yRadius, Qt::AbsoluteSize);
910 }
911
912 // image
913 drawStyledItemImage(props->image(), adjustedRect, opacity, painter);
914}
915
916void QStyleKitStylePrivate::drawStyledItemImage(const QQStyleKitImageProperties *image, const QRectF &rect,
917 qreal opacity, QPainter *painter) const
918{
919 if (!image || image->source().isEmpty() || image->color().alpha() <= 0)
920 return;
921
922 QString imageSource = image->source().toString();
923 if (imageSource.startsWith(QLatin1String("qrc:/")))
924 imageSource = imageSource.mid(3);
925 QUrl imageUrl(imageSource);
926 QString imagePath = imageUrl.isLocalFile() ? imageUrl.toLocalFile() : imageSource;
927 QPixmap pixmap(imagePath);
928 if (pixmap.isNull())
929 return;
930
931 if (image->color().isValid()) {
932 QImage coloredImage = pixmap.toImage();
933 QPainter imagePainter(&coloredImage);
934 imagePainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
935 imagePainter.fillRect(coloredImage.rect(), image->color());
936 imagePainter.end();
937 pixmap = QPixmap::fromImage(coloredImage);
938 }
939 painter->setOpacity(opacity);
940 const QSizeF pixmapSize = pixmap.deviceIndependentSize();
941
942 switch (image->fillMode()) {
943 case QQuickImage::PreserveAspectFit: {
944 const QSize scaled = pixmapSize.scaled(rect.size(), Qt::KeepAspectRatio).toSize();
945 const QPointF topLeft(
946 rect.x() + (rect.width() - scaled.width()) / 2.0,
947 rect.y() + (rect.height() - scaled.height()) / 2.0
948 );
949 painter->drawPixmap(QRectF(topLeft, scaled), pixmap, QRectF(QPointF(0, 0), pixmapSize));
950 break;
951 }
952 case QQuickImage::PreserveAspectCrop: {
953 const QSize scaled = pixmapSize.scaled(rect.size(), Qt::KeepAspectRatioByExpanding).toSize();
954 const QPointF topLeft(
955 rect.x() + (rect.width() - scaled.width()) / 2.0,
956 rect.y() + (rect.height() - scaled.height()) / 2.0
957 );
958 QPainterStateGuard stateGuard(painter);
959 painter->setClipRect(rect);
960 painter->drawPixmap(QRectF(topLeft, scaled), pixmap, QRectF(QPointF(0, 0), pixmapSize));
961 break;
962 }
963 // TODO: Support remaining fill modes
964 case QQuickImage::Stretch:
965 default:
966 painter->drawPixmap(rect, pixmap, QRectF(QPointF(0, 0), pixmapSize));
967 break;
968 }
969}
970
971QRect QStyleKitStylePrivate::getAlignedRectInContainer(const QRect &container, const QSize &size,
972 uint alignment, const QMargins &padding,
973 const QMargins &margins) const
974{
975 QRect r(QPoint(0, 0), size);
976
977 if (alignment & Qt::AlignLeft)
978 r.moveLeft(container.x() + padding.left() + margins.left());
979 else if (alignment & Qt::AlignHCenter)
980 r.moveLeft(container.x() + (container.width() - size.width()) / 2);
981 else // AlignRight
982 r.moveLeft(container.x() + container.width() - padding.right() - margins.right() - size.width());
983
984 if (alignment & Qt::AlignTop)
985 r.moveTop(container.y() + padding.top() + margins.top());
986 else if (alignment & Qt::AlignVCenter)
987 r.moveTop(container.y() + (container.height() - size.height()) / 2);
988 else // AlignBottom
989 r.moveTop(container.y() + container.height() - padding.bottom() - margins.bottom() - size.height());
990
991 return r;
992}
993
994QStyleKitStylePrivate::ControlMetrics QStyleKitStylePrivate::metricsForReader(QQStyleKitReader *reader) const
995{
996 Q_ASSERT(reader);
997 const QQStyleKitControlProperties *props = reader->global();
998 ControlMetrics metrics;
999 metrics.bgImplicitSize = QSize(0, 0);
1000 metrics.textPadding = QMargins(0, 0, 0, 0);
1001 metrics.padding = QMargins(props->leftPadding(), props->topPadding(),
1002 props->rightPadding(), props->bottomPadding());
1003 metrics.spacing = props->spacing();
1004 metrics.margins = QMargins(0, 0, 0, 0);
1005 metrics.indicatorImplicitSize = QSize(0, 0);
1006 metrics.indicatorMargins = QMargins(0, 0, 0, 0);
1007 metrics.foregroundImplicitSize = QSize(0, 0);
1008 metrics.foregroundMargins = QMargins(0, 0, 0, 0);
1009 const auto *background = props->background();
1010 if (background) {
1011 auto scale = background->scale();
1012 if (scale == 0)
1013 scale = 1.0;
1014 metrics.bgImplicitSize = QSize(static_cast<int>(background->implicitWidth()), static_cast<int>(background->implicitHeight())) * scale;
1015 metrics.margins = QMargins(background->leftMargin(), background->topMargin(), background->rightMargin(), background->bottomMargin());
1016 }
1017 const auto *textProps = props->text();
1018 if (textProps)
1019 metrics.textPadding = QMargins(textProps->leftPadding(), textProps->topPadding(),textProps->rightPadding(), textProps->bottomPadding());
1020 const auto *indicator = props->indicator();
1021 if (indicator) {
1022 auto scale = indicator->scale();
1023 if (scale == 0)
1024 scale = 1.0;
1025 metrics.indicatorMargins = QMargins(indicator->leftMargin(), indicator->topMargin(), indicator->rightMargin(), indicator->bottomMargin());
1026 metrics.indicatorImplicitSize = QSize(std::max(.0, indicator->implicitWidth()),
1027 std::max(.0, indicator->implicitHeight())) * scale;
1028
1029 const auto *foreground = indicator->foreground();
1030 if (foreground) {
1031 auto scale = foreground->scale();
1032 if (scale == 0)
1033 scale = 1.0;
1034 metrics.foregroundMargins = QMargins(foreground->leftMargin(), foreground->topMargin(), foreground->rightMargin(), foreground->bottomMargin());
1035 const auto foregroundW = foreground->implicitWidth() >= 0
1036 ? foreground->implicitWidth()
1037 : std::max(0, metrics.indicatorImplicitSize.width() - metrics.foregroundMargins.left() - metrics.foregroundMargins.right());
1038 const auto foregroundH = foreground->implicitHeight() >= 0
1039 ? foreground->implicitHeight()
1040 : std::max(0, metrics.indicatorImplicitSize.height() - metrics.foregroundMargins.top() - metrics.foregroundMargins.bottom());
1041 metrics.foregroundImplicitSize = QSize(foregroundW, foregroundH) * scale;
1042 }
1043 }
1044 const auto *handle = props->handle();
1045 if (handle) {
1046 auto scale = handle->scale();
1047 if (scale == 0)
1048 scale = 1.0;
1049 metrics.handleImplicitSize = QSize(handle->implicitWidth(), handle->implicitHeight()) * scale;
1050 metrics.handleMargins = QMargins(handle->leftMargin(), handle->topMargin(), handle->rightMargin(), handle->bottomMargin());
1051 }
1052 return metrics;
1053}
1054
1055/*!
1056 Constructs a QStyleKitStyle with no style loaded.
1057
1058 Use \l setStylePath() to load a QML \l Style after construction.
1059 Until a style is loaded, painting and metrics behave as in
1060 QCommonStyle.
1061*/
1062QStyleKitStyle::QStyleKitStyle()
1063 : QCommonStyle(*new QStyleKitStylePrivate())
1064{
1065}
1066
1067/*!
1068 Constructs a QStyleKitStyle and loads the QML \l Style at \a fileName.
1069
1070 \a fileName is interpreted as a URL, and may use any scheme supported
1071 by QQmlEngine, including \c qrc, \c file, and \c http. If the URL is
1072 invalid or the root object of the loaded component is not a \l Style,
1073 a warning is emitted and the constructed style behaves as
1074 QCommonStyle until a valid \l stylePath is set.
1075*/
1076QStyleKitStyle::QStyleKitStyle(const QString &fileName)
1077 : QCommonStyle(*new QStyleKitStylePrivate())
1078{
1079 Q_D(QStyleKitStyle);
1080 d->stylePath = fileName;
1081 if (!d->loadStyle()) {
1082 qWarning("QStyleKitStyle: Failed to load style from %s", qPrintable(fileName));
1083 }
1084}
1085
1086/*!
1087 Destroys the QStyleKitStyle.
1088*/
1089QStyleKitStyle::~QStyleKitStyle()
1090{
1091}
1092
1093/*!
1094 Returns the URL of the currently loaded \l Style file.
1095
1096 \sa setStylePath()
1097*/
1098QString QStyleKitStyle::stylePath() const
1099{
1100 Q_D(const QStyleKitStyle);
1101 return d->stylePath;
1102}
1103
1104/*!
1105 Loads the QML \l Style at \a fileName and applies it to all widgets.
1106
1107 \a fileName is interpreted as a URL. If the URL is the same as the
1108 currently loaded style, this function does nothing. If the new style
1109 cannot be loaded, the previously loaded style remains active and a
1110 warning is emitted; \l stylePathChanged() is still emitted to reflect
1111 the changed property value.
1112
1113 \sa stylePath()
1114*/
1115void QStyleKitStyle::setStylePath(const QString &fileName)
1116{
1117 Q_D(QStyleKitStyle);
1118 if (d->stylePath == fileName)
1119 return;
1120 d->stylePath = fileName;
1121 if (d->loadStyle())
1122 d->updateStyle();
1123 emit stylePathChanged();
1124}
1125
1126/*!
1127 Returns the name of the currently active theme, or an empty string
1128 if no \l Style has been loaded.
1129
1130 \sa setThemeName(), themeNames()
1131*/
1132QString QStyleKitStyle::themeName() const
1133{
1134 Q_D(const QStyleKitStyle);
1135 return d->style ? d->style->themeName() : QString();
1136}
1137
1138/*!
1139 Activates the theme named \a themeName.
1140
1141 \a themeName must be one of the entries in \l themeNames(), or the
1142 special name \c System to follow the platform color scheme. If no
1143 \l Style has been loaded, this function emits a warning and returns
1144 without changing the active theme.
1145
1146 \sa themeName(), themeNames()
1147*/
1148void QStyleKitStyle::setThemeName(const QString &themeName)
1149{
1150 Q_D(QStyleKitStyle);
1151 if (!d->style) {
1152 qWarning("QStyleKitStyle: No style loaded, cannot set theme name.");
1153 return;
1154 }
1155 if (d->style->themeName() == themeName)
1156 return;
1157 d->style->setThemeName(themeName);
1158 d->updateStyle();
1159 emit themeNameChanged();
1160}
1161
1162/*!
1163 Returns the names of all themes exposed by the loaded \l Style,
1164 including the built-in \c Light and \c Dark themes and any custom
1165 themes defined by the style. Returns an empty list when no style
1166 is loaded.
1167
1168 \sa customThemeNames(), themeName()
1169*/
1170QStringList QStyleKitStyle::themeNames() const
1171{
1172 Q_D(const QStyleKitStyle);
1173 return d->style ? d->style->themeNames() : QStringList();
1174}
1175
1176/*!
1177 Returns the names of the custom themes defined by the loaded
1178 \l Style, excluding the built-in \c Light and \c Dark themes.
1179 Returns an empty list when no style is loaded.
1180
1181 \sa themeNames()
1182*/
1183QStringList QStyleKitStyle::customThemeNames() const
1184{
1185 Q_D(const QStyleKitStyle);
1186 return d->style ? d->style->customThemeNames() : QStringList();
1187}
1188
1189/*! \reimp */
1190void QStyleKitStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
1191 const QWidget *w) const
1192{
1193 Q_D(const QStyleKitStyle);
1194 if (!d->style) {
1195 qWarning("QStyleKitStyle: No StyleKit style loaded, drawing primitive with QCommonStyle: %d", int(pe));
1196 QCommonStyle::drawPrimitive(pe, opt, p, w);
1197 return;
1198 }
1199
1200 switch (pe) {
1201 case PE_FrameButtonBevel:
1202 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1203 const auto controlType = btn->features & QStyleOptionButton::Flat
1204 ? QQStyleKitReader::ControlType::FlatButton
1205 : QQStyleKitReader::ControlType::Button;
1206 const auto r = d->resolve(w, controlType, btn->state);
1207 if (!r.isValid())
1208 break;
1209 d->drawStyledItemRect(r.background(), opt->rect, p);
1210 return;
1211 }
1212 break;
1213 case PE_Frame: {
1214 QQStyleKitReader::ControlType controlType;
1215 const bool isPopup = w && (false
1216#if QT_CONFIG(menu)
1217 || qobject_cast<const QMenu *>(w)
1218#endif
1219#if QT_CONFIG(combobox)
1220 || (w && w->inherits("QComboBoxPrivateContainer"))
1221#endif
1222 );
1223 if (isPopup)
1224 controlType = QQStyleKitReader::ControlType::Popup;
1225#if QT_CONFIG(lineedit)
1226 else if (qobject_cast<const QLineEdit *>(w))
1227 controlType = QQStyleKitReader::ControlType::TextField;
1228#endif
1229 else
1230 controlType = QQStyleKitReader::ControlType::Frame;
1231 const auto r = d->resolve(w, controlType, opt->state);
1232 if (!r.isValid())
1233 break;
1234 d->drawStyledItemRect(r.background(), opt->rect, p);
1235 return;
1236 }
1237#if QT_CONFIG(lineedit)
1238 case PE_PanelLineEdit:
1239 if (const auto *lineEdit = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
1240 const QObject *parent = w ? w->parent() : nullptr;
1241#if QT_CONFIG(spinbox)
1242 const bool isInSpinBox = qobject_cast<const QAbstractSpinBox *>(parent);
1243#else
1244 const bool isInSpinBox = false;
1245#endif
1246#if QT_CONFIG(combobox)
1247 const bool isInComboBox = qobject_cast<const QComboBox *>(parent);
1248#else
1249 const bool isInComboBox = false;
1250#endif
1251 // For spinbox and combobox, the line edit doesn't have its own background in the Controls style
1252 if (isInSpinBox || isInComboBox)
1253 return;
1254
1255 // LineEdit sets Sunken flag to indicate Sunken frame,
1256 // but the style uses it to indicate pressed state, so ignore it
1257 QStyleOption lineEditOpt(*lineEdit);
1258 lineEditOpt.state &= ~QStyle::State_Sunken;
1259 const auto r = d->resolve(w, QQStyleKitReader::ControlType::TextField, lineEditOpt.state);
1260 if (!r.isValid())
1261 break;
1262
1263 // LineEdit draws its own text using the Text role so update that role in the palette
1264 if (auto *le = qobject_cast<const QLineEdit *>(w)) {
1265 if (const auto *txt = r.text(); txt && txt->isDefined(QQSK::Property::Color)) {
1266 QPalette stylePalette;
1267 stylePalette.setColor(QPalette::Text, txt->color());
1268 d->setStylePalette(const_cast<QLineEdit *>(le), stylePalette);
1269 }
1270 }
1271
1272 d->drawStyledItemRect(r.background(), opt->rect, p);
1273 return;
1274 }
1275 break;
1276#endif // QT_CONFIG(lineedit)
1277#if QT_CONFIG(itemviews)
1278 case PE_PanelItemViewItem: {
1279 const auto r = d->resolveItemViewItem(w, opt, QQStyleKitReader::ControlType::ItemDelegate, opt->state);
1280 if (!r.isValid())
1281 break;
1282 d->drawStyledItemRect(r.background(), opt->rect, p);
1283 return;
1284 }
1285#endif // QT_CONFIG(itemviews)
1286 case PE_IndicatorCheckBox:
1287 case PE_IndicatorRadioButton: {
1288 const auto controlType = pe == PE_IndicatorCheckBox
1289 ? QQStyleKitReader::ControlType::CheckBox
1290 : QQStyleKitReader::ControlType::RadioButton;
1291 const auto r = d->resolve(w, controlType, opt->state);
1292 if (!r.isValid())
1293 break;
1294 d->drawControlIndicator(r.indicator(), opt->rect, p);
1295 return;
1296 }
1297 case PE_IndicatorArrowDown: {
1298 const auto r = d->resolve(w, QQStyleKitReader::ControlType::ComboBox, opt->state);
1299 if (!r.isValid())
1300 break;
1301 d->drawControlIndicator(r.indicator(), opt->rect, p);
1302 return;
1303 }
1304 case PE_IndicatorItemViewItemCheck: {
1305 const auto r = d->resolveItemViewItem(w, opt, QQStyleKitReader::ControlType::ItemDelegate, opt->state);
1306 if (!r.isValid())
1307 break;
1308 d->drawControlIndicator(r.indicator(), opt->rect, p);
1309 return;
1310 }
1311#if QT_CONFIG(spinbox)
1312 case PE_IndicatorSpinUp:
1313 case PE_IndicatorSpinDown: {
1314 const auto r = d->resolve(w, QQStyleKitReader::ControlType::SpinBox, opt->state);
1315 if (!r.isValid())
1316 break;
1317 const auto *indicator = r.indicator();
1318 const auto *upDownIndicator = indicator ? (pe == PE_IndicatorSpinUp ? indicator->first() : indicator->second()) : nullptr;
1319 d->drawControlIndicator(upDownIndicator, opt->rect, p);
1320 return;
1321 }
1322#endif // QT_CONFIG(spinbox)
1323 default:
1324 break;
1325 }
1326 QCommonStyle::drawPrimitive(pe, opt, p, w);
1327}
1328
1329/*! \reimp */
1330void QStyleKitStyle::drawControl(ControlElement element, const QStyleOption *opt, QPainter *p,
1331 const QWidget *w) const
1332{
1333 Q_D(const QStyleKitStyle);
1334 if (!d->style) {
1335 qWarning("QStyleKitStyle: No StyleKit style loaded, drawing control with QCommonStyle: %d", int(element));
1336 QCommonStyle::drawControl(element, opt, p, w);
1337 return;
1338 }
1339
1340 switch (element) {
1341 case CE_PushButton:
1342 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1343 proxy()->drawControl(CE_PushButtonBevel, btn, p, w);
1344 QStyleOptionButton btnContent(*btn);
1345 btnContent.rect = subElementRect(SE_PushButtonContents, btn, w);
1346 proxy()->drawControl(CE_PushButtonLabel, &btnContent, p, w);
1347 }
1348 return;
1349 case CE_PushButtonBevel:
1350 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1351 QStyleOptionButton btnBg(*btn);
1352 btnBg.rect = subElementRect(SE_PushButtonBevel, btn, w);
1353 proxy()->drawPrimitive(PE_FrameButtonBevel, &btnBg, p, w);
1354 }
1355 return;
1356 case CE_PushButtonLabel:
1357 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1358 const auto controlType = btn->features & QStyleOptionButton::Flat ? QQStyleKitReader::ControlType::FlatButton : QQStyleKitReader::ControlType::Button;
1359 const auto r = d->resolve(w, controlType, btn->state);
1360 if (!r.isValid())
1361 break;
1362 const auto metrics = r.metrics;
1363
1364 QRect textRect = opt->rect;
1365 uint textFlags = Qt::TextShowMnemonic;
1366 if (!styleHint(SH_UnderlineShortcut, opt, w))
1367 textFlags |= Qt::TextHideMnemonic;
1368
1369 // icon
1370 const QIcon icon = btn->icon;
1371 if (!icon.isNull()) {
1372 const auto *textProps = r.text();
1373 uint iconTextFlags = textFlags;
1374 iconTextFlags |= textProps
1375 ? resolvedAlignment(textProps->alignment(), Qt::AlignHCenter, Qt::AlignVCenter)
1376 : uint(Qt::AlignHCenter | Qt::AlignVCenter);
1377 QIcon::Mode mode = btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
1378 if (mode == QIcon::Normal && btn->state & State_HasFocus)
1379 mode = QIcon::Active;
1380 QIcon::State iconState = btn->state & State_On ? QIcon::On : QIcon::Off;
1381 const auto paintDeviceDpr = p->device()->devicePixelRatio();
1382 QPixmap pixmap = icon.pixmap(btn->iconSize, paintDeviceDpr, mode, iconState);
1383 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
1384 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
1385 int labelWidth = pixmapWidth;
1386 int iconSpacing = metrics->spacing;
1387 int textWidth = btn->fontMetrics.boundingRect(opt->rect, iconTextFlags, btn->text).width();
1388 if (!btn->text.isEmpty())
1389 labelWidth += (textWidth + iconSpacing + textProps->leftPadding() + textProps->rightPadding());
1390
1391 QRect iconRect;
1392 if (iconTextFlags & Qt::AlignLeft) {
1393 iconRect = QRect(textRect.x(), textRect.y() + (textRect.height() - pixmapHeight) / 2,
1394 pixmapWidth, pixmapHeight);
1395 } else if (iconTextFlags & Qt::AlignHCenter) {
1396 iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
1397 textRect.y() + (textRect.height() - pixmapHeight) / 2,
1398 pixmapWidth, pixmapHeight);
1399 } else {
1400 iconRect = QRect(textRect.x() + textRect.width() - labelWidth,
1401 textRect.y() + (textRect.height() - pixmapHeight) / 2,
1402 pixmapWidth, pixmapHeight);
1403 }
1404 iconRect = visualRect(btn->direction, textRect, iconRect);
1405
1406 // After placing the icon, left-align the text relative to it
1407 textFlags &= ~Qt::AlignHorizontal_Mask;
1408 textFlags |= Qt::AlignLeft;
1409 if (btn->direction == Qt::RightToLeft)
1410 textRect.setRight(iconRect.left() - iconSpacing);
1411 else
1412 textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing);
1413
1414 p->drawPixmap(iconRect, pixmap);
1415 }
1416
1417 if (btn->features & QStyleOptionButton::HasMenu) {
1418 int indicatorSize = pixelMetric(PM_MenuButtonIndicator, btn, w);
1419 if (btn->direction == Qt::LeftToRight)
1420 textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
1421 else
1422 textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
1423 }
1424 d->drawControlText(r.text(), r.font(), textRect, btn->text, textFlags, p);
1425 return;
1426 }
1427 break;
1428 case CE_CheckBox:
1429 case CE_RadioButton:
1430 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1431 const auto controlType = element == CE_CheckBox ? QQStyleKitReader::ControlType::CheckBox
1432 : QQStyleKitReader::ControlType::RadioButton;
1433 const auto r = d->resolve(w, controlType, btn->state);
1434 if (!r.isValid())
1435 break;
1436 QRect backgroundRect = btn->rect.marginsRemoved(r.metrics->margins);
1437 // background
1438 d->drawStyledItemRect(r.background(), backgroundRect, p);
1439 // label
1440 QStyleOptionButton btnContent(*btn);
1441 const auto contentElement = element == CE_CheckBox ? SE_CheckBoxContents : SE_RadioButtonContents;
1442 btnContent.rect = subElementRect(contentElement, btn, w);
1443 const auto labelElement = element == CE_CheckBox ? CE_CheckBoxLabel : CE_RadioButtonLabel;
1444 proxy()->drawControl(labelElement, &btnContent, p, w);
1445 // indicator
1446 QStyleOptionButton indicator(*btn);
1447 const auto indicatorElement = element == CE_CheckBox ? SE_CheckBoxIndicator : SE_RadioButtonIndicator;
1448 indicator.rect = subElementRect(indicatorElement, btn, w);
1449 const auto primitiveElement = element == CE_CheckBox ? PE_IndicatorCheckBox : PE_IndicatorRadioButton;
1450 proxy()->drawPrimitive(primitiveElement, &indicator, p, w);
1451 return;
1452 }
1453 break;
1454 case CE_CheckBoxLabel:
1455 case CE_RadioButtonLabel:
1456 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1457 const auto controlType = element == CE_CheckBoxLabel ? QQStyleKitReader::ControlType::CheckBox
1458 : QQStyleKitReader::ControlType::RadioButton;
1459 const auto r = d->resolve(w, controlType, btn->state);
1460 if (!r.isValid())
1461 break;
1462 uint textFlags = Qt::TextShowMnemonic;
1463 if (!styleHint(SH_UnderlineShortcut, opt, w))
1464 textFlags |= Qt::TextHideMnemonic;
1465 d->drawControlText(r.text(), r.font(), opt->rect, btn->text, textFlags, p);
1466 return;
1467 }
1468 break;
1469#if QT_CONFIG(combobox)
1470 case CE_ComboBoxLabel:
1471 if (const auto *comboBox = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
1472 if (comboBox->editable)
1473 return;
1474 const auto r = d->resolve(w, QQStyleKitReader::ControlType::ComboBox, comboBox->state);
1475 if (!r.isValid())
1476 break;
1477 const QRect textRect = subControlRect(CC_ComboBox, comboBox, SC_ComboBoxEditField, w)
1478 .marginsRemoved(r.metrics->textPadding);
1479 uint textFlags = Qt::TextShowMnemonic;
1480 if (!styleHint(SH_UnderlineShortcut, opt, w))
1481 textFlags |= Qt::TextHideMnemonic;
1482 d->drawControlText(r.text(), r.font(), textRect, comboBox->currentText, textFlags, p);
1483 return;
1484 }
1485 break;
1486#endif // QT_CONFIG(combobox)
1487#if QT_CONFIG(progressbar)
1488 case CE_ProgressBar:
1489 if (const QStyleOptionProgressBar *progressBar = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1490 const auto r = d->resolve(w, QQStyleKitReader::ControlType::ProgressBar, progressBar->state);
1491 if (!r.isValid())
1492 break;
1493 QRect backgroundRect = progressBar->rect.marginsRemoved(r.metrics->margins);
1494 // background
1495 d->drawStyledItemRect(r.background(), backgroundRect, p);
1496 // groove
1497 QStyleOptionProgressBar contents(*progressBar);
1498 contents.rect = subElementRect(SE_ProgressBarGroove, progressBar, w);
1499 proxy()->drawControl(CE_ProgressBarGroove, &contents, p, w);
1500 // track
1501 contents.rect = subElementRect(SE_ProgressBarContents, progressBar, w);
1502 proxy()->drawControl(CE_ProgressBarContents, &contents, p, w);
1503 // We intentionally don't draw the label as it is not drawn on the Controls Style
1504 return;
1505 }
1506 break;
1507 case CE_ProgressBarGroove: {
1508 // groove = indicator background
1509 const auto r = d->resolve(w, QQStyleKitReader::ControlType::ProgressBar, opt->state);
1510 if (!r.isValid())
1511 break;
1512 const auto *indicator = r.indicator();
1513 if (indicator && indicator->visible() && indicator->opacity() > 0)
1514 d->drawStyledItemRect(indicator, opt->rect, p);
1515 return;
1516 }
1517 case CE_ProgressBarContents:
1518 // contents = indicator foreground
1519 if (const auto *progressBar = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1520 const auto r = d->resolve(w, QQStyleKitReader::ControlType::ProgressBar, progressBar->state);
1521 if (!r.isValid())
1522 break;
1523 const auto progress = progressBar->progress;
1524 const auto ratio = progressBar->maximum > progressBar->minimum ? (progress - progressBar->minimum) / static_cast<qreal>(progressBar->maximum - progressBar->minimum) : 0;
1525 const auto width = static_cast<int>(progressBar->rect.width() * ratio);
1526 const auto x = progressBar->invertedAppearance ? progressBar->rect.right() - width : progressBar->rect.left();
1527 const auto contentsRect = QRect(x, progressBar->rect.y(), width, progressBar->rect.height());
1528 const auto *foreground = r.indicator() ? r.indicator()->foreground() : nullptr;
1529 if (foreground && foreground->visible() && foreground->opacity() > 0)
1530 d->drawStyledItemRect(foreground, contentsRect, p);
1531 return;
1532 }
1533 break;
1534#endif // QT_CONFIG(progressbar)
1535#if QT_CONFIG(itemviews)
1536 case CE_ItemViewItem:
1537 if (const auto *itemViewOption = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
1538 const auto r = d->resolveItemViewItem(w, opt, QQStyleKitReader::ControlType::ItemDelegate, opt->state);
1539 if (!r.isValid())
1540 break;
1541 QStyleOptionViewItem optBg(*itemViewOption);
1542 optBg.rect = optBg.rect.marginsRemoved(r.metrics->margins);
1543 QRect indicatorRect = subElementRect(SE_ItemViewItemCheckIndicator, itemViewOption, w);
1544 QRect iconRect = subElementRect(SE_ItemViewItemDecoration, itemViewOption, w);
1545 QRect textRect = subElementRect(SE_ItemViewItemText, itemViewOption, w);
1546 // Capture text properties + font now, before the indicator
1547 // drawPrimitive below potentially mutates the reader's state
1548 const auto *itemTextProps = r.text();
1549 const QFont itemFont = r.font();
1550
1551 // background
1552 proxy()->drawPrimitive(PE_PanelItemViewItem, &optBg, p, w);
1553
1554 // indicator
1555 if (itemViewOption->features & QStyleOptionViewItem::HasCheckIndicator) {
1556 QStyleOptionViewItem option(*itemViewOption);
1557 option.rect = indicatorRect;
1558 option.state = option.state & ~QStyle::State_HasFocus;
1559
1560 switch (itemViewOption->checkState) {
1561 case Qt::Unchecked:
1562 option.state |= QStyle::State_Off;
1563 break;
1564 case Qt::PartiallyChecked:
1565 option.state |= QStyle::State_NoChange;
1566 break;
1567 case Qt::Checked:
1568 option.state |= QStyle::State_On;
1569 break;
1570 }
1571 proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, p, w);
1572 }
1573
1574 // icon
1575 QIcon::Mode mode = QIcon::Normal;
1576 if (!(itemViewOption->state & QStyle::State_Enabled))
1577 mode = QIcon::Disabled;
1578 else if (itemViewOption->state & QStyle::State_Selected)
1579 mode = QIcon::Selected;
1580 QIcon::State state = itemViewOption->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
1581 itemViewOption->icon.paint(p, iconRect, itemViewOption->decorationAlignment, mode, state);
1582
1583 // draw text
1584 uint textFlags = Qt::TextShowMnemonic;
1585 if (!styleHint(SH_UnderlineShortcut, opt, w))
1586 textFlags |= Qt::TextHideMnemonic;
1587 d->drawControlText(itemTextProps, itemFont, textRect, itemViewOption->text, textFlags, p);
1588 return;
1589 }
1590 break;
1591#endif // QT_CONFIG(itemviews)
1592#ifndef QT_NO_FRAME
1593 case CE_ShapedFrame:
1594#if QT_CONFIG(combobox)
1595 if (w && w->inherits("QComboBoxPrivateContainer")) {
1596 const auto r = d->resolve(w, QQStyleKitReader::ControlType::Popup, opt->state);
1597 if (!r.isValid())
1598 break;
1599 QRect backgroundRect = opt->rect.marginsRemoved(r.metrics->margins);
1600 d->drawStyledItemRect(r.background(), backgroundRect, p);
1601 return;
1602 }
1603#endif // QT_CONFIG(combobox)
1604 break;
1605#endif // QT_NO_FRAME
1606 default:
1607 break;
1608 }
1609 QCommonStyle::drawControl(element, opt, p, w);
1610}
1611
1612/*! \reimp */
1613QRect QStyleKitStyle::subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget) const
1614{
1615 Q_D(const QStyleKitStyle);
1616 if (!d->style) {
1617 qWarning("QStyleKitStyle: No StyleKit style loaded, calculating subElementRect with QCommonStyle: %d", int(r));
1618 return QCommonStyle::subElementRect(r, opt, widget);
1619 }
1620
1621 switch (r) {
1622 case SE_PushButtonLayoutItem:
1623 case SE_PushButtonBevel:
1624 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1625 const auto controlType = btn->features & QStyleOptionButton::Flat
1626 ? QQStyleKitReader::ControlType::FlatButton
1627 : QQStyleKitReader::ControlType::Button;
1628 const auto resolved = d->resolveLayout(controlType, opt->state);
1629 if (!resolved.isValid())
1630 break;
1631 const auto &metrics = *resolved.metrics;
1632 QRect rect = opt->rect.marginsRemoved(metrics.margins);
1633 return visualRect(opt->direction, opt->rect, rect);
1634 }
1635 break;
1636 case SE_PushButtonContents:
1637 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1638 const auto controlType = btn->features & QStyleOptionButton::Flat
1639 ? QQStyleKitReader::ControlType::FlatButton
1640 : QQStyleKitReader::ControlType::Button;
1641 const auto resolved = d->resolveLayout(controlType, opt->state);
1642 if (!resolved.isValid())
1643 break;
1644 const auto &metrics = *resolved.metrics;
1645 QRect rect = opt->rect.marginsRemoved(metrics.margins + metrics.padding + metrics.textPadding);
1646 return visualRect(opt->direction, opt->rect, rect);
1647 }
1648 break;
1649 case SE_CheckBoxContents:
1650 case SE_RadioButtonContents: {
1651 const auto controlType = r == SE_CheckBoxContents ? QQStyleKitReader::ControlType::CheckBox
1652 : QQStyleKitReader::ControlType::RadioButton;
1653 const auto resolved = d->resolveLayout(controlType, opt->state);
1654 if (!resolved.isValid())
1655 break;
1656 const auto &metrics = *resolved.metrics;
1657 QRect contentsRect = opt->rect.marginsRemoved(metrics.margins + metrics.padding);
1658 const auto subElement = r == SE_CheckBoxContents ? SE_CheckBoxIndicator : SE_RadioButtonIndicator;
1659 QRect indicatorRect = visualRect(opt->direction, opt->rect, subElementRect(subElement, opt, widget));
1660 const int spacing = metrics.spacing;
1661 const auto *indicator = resolved.indicator();
1662 const uint alignment = indicator
1663 ? resolvedAlignment(indicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter)
1664 : uint(Qt::AlignLeft | Qt::AlignVCenter);
1665 if (alignment & Qt::AlignLeft) {
1666 contentsRect.setLeft(indicatorRect.right() + spacing + metrics.textPadding.left());
1667 } else if (alignment & Qt::AlignHCenter) {
1668 contentsRect.setLeft(indicatorRect.right() + spacing + metrics.textPadding.left());
1669 contentsRect.setRight(indicatorRect.left() - spacing - metrics.textPadding.right());
1670 } else {
1671 contentsRect.setRight(indicatorRect.left() - spacing - metrics.textPadding.right());
1672 }
1673 return visualRect(opt->direction, opt->rect, contentsRect);
1674 }
1675 case SE_CheckBoxIndicator:
1676 case SE_RadioButtonIndicator: {
1677 const auto controlType = r == SE_CheckBoxIndicator
1678 ? QQStyleKitReader::ControlType::CheckBox
1679 : QQStyleKitReader::ControlType::RadioButton;
1680 const auto resolved = d->resolveLayout(controlType, opt->state);
1681 if (!resolved.isValid())
1682 break;
1683 const auto &metrics = *resolved.metrics;
1684 QRect rect = opt->rect.marginsRemoved(metrics.margins);
1685 const auto *indicator = resolved.indicator();
1686 if (!indicator || !indicator->visible() || indicator->opacity() == 0)
1687 return rect;
1688
1689 const int w = indicator->implicitWidth() >= 0
1690 ? indicator->implicitWidth()
1691 : rect.width() - metrics.padding.left() - metrics.padding.right()
1692 - metrics.indicatorMargins.left() - metrics.indicatorMargins.right();
1693 const int h = indicator->implicitHeight() >= 0
1694 ? indicator->implicitHeight()
1695 : rect.height() - metrics.padding.top() - metrics.padding.bottom()
1696 - metrics.indicatorMargins.top() - metrics.indicatorMargins.bottom();
1697 const uint alignment = resolvedAlignment(indicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
1698 const QRect indicatorRect = d->getAlignedRectInContainer(
1699 rect, QSize(w, h), alignment, metrics.padding, metrics.indicatorMargins);
1700 return visualRect(opt->direction, rect, indicatorRect);
1701 }
1702#if QT_CONFIG(itemviews)
1703 case SE_ItemViewItemCheckIndicator: {
1704 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::ItemDelegate, opt->state);
1705 if (!resolved.isValid())
1706 break;
1707 const auto &metrics = *resolved.metrics;
1708 QRect rect = opt->rect.marginsRemoved(metrics.margins);
1709 const auto *indicator = resolved.indicator();
1710 if (!indicator || !indicator->visible() || indicator->opacity() == 0)
1711 return rect;
1712
1713 const int w = indicator->implicitWidth() >= 0
1714 ? indicator->implicitWidth()
1715 : rect.width() - metrics.padding.left() - metrics.padding.right()
1716 - metrics.indicatorMargins.left() - metrics.indicatorMargins.right();
1717 const int h = indicator->implicitHeight() >= 0
1718 ? indicator->implicitHeight()
1719 : rect.height() - metrics.padding.top() - metrics.padding.bottom()
1720 - metrics.indicatorMargins.top() - metrics.indicatorMargins.bottom();
1721 const uint alignment = resolvedAlignment(indicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
1722 const QRect indicatorRect = d->getAlignedRectInContainer(
1723 rect, QSize(w, h), alignment, metrics.padding, metrics.indicatorMargins);
1724 return visualRect(opt->direction, rect, indicatorRect);
1725 }
1726 case SE_ItemViewItemText:
1727 if (const auto *itemViewOption = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
1728 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::ItemDelegate, opt->state);
1729 if (!resolved.isValid())
1730 break;
1731 const auto &metrics = *resolved.metrics;
1732 QRect contentsRect = opt->rect.marginsRemoved(metrics.margins + metrics.padding);
1733 QRect indicatorRect;
1734 if (itemViewOption->features & QStyleOptionViewItem::HasCheckIndicator)
1735 indicatorRect = subElementRect(SE_ItemViewItemCheckIndicator, opt, widget);
1736 const int spacing = metrics.spacing;
1737 QRect textRect = contentsRect;
1738 const auto *textProps = resolved.text();
1739 uint textAlign;
1740 if (textProps)
1741 textAlign = resolvedAlignment(textProps->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
1742 else
1743 textAlign = Qt::AlignLeft | Qt::AlignVCenter;
1744 if (indicatorRect.isValid()) {
1745 if (textAlign & Qt::AlignLeft) {
1746 textRect.setLeft(indicatorRect.right() + spacing + metrics.textPadding.left());
1747 } else if (textAlign & Qt::AlignHCenter) {
1748 textRect.setLeft(indicatorRect.right() + spacing + metrics.textPadding.left());
1749 textRect.setRight(indicatorRect.left() - spacing - metrics.textPadding.right());
1750 } else {
1751 textRect.setRight(indicatorRect.left() - spacing - metrics.textPadding.right());
1752 }
1753 } else {
1754 if (textAlign & Qt::AlignLeft) {
1755 textRect.setLeft(textRect.left() + metrics.textPadding.left());
1756 } else if (textAlign & Qt::AlignHCenter) {
1757 textRect.setLeft(textRect.left() + metrics.textPadding.left() / 2);
1758 textRect.setRight(textRect.right() - metrics.textPadding.right() / 2);
1759 } else {
1760 textRect.setRight(textRect.right() - metrics.textPadding.right());
1761 }
1762 }
1763 if (textAlign & Qt::AlignTop) {
1764 textRect.setTop(textRect.top() + metrics.textPadding.top());
1765 } else if (textAlign & Qt::AlignVCenter) {
1766 textRect.setTop(textRect.top() + metrics.textPadding.top() / 2);
1767 textRect.setBottom(textRect.bottom() - metrics.textPadding.bottom() / 2);
1768 } else {
1769 textRect.setBottom(textRect.bottom() - metrics.textPadding.bottom());
1770 }
1771 return visualRect(opt->direction, opt->rect, textRect);
1772 }
1773 break;
1774#endif // QT_CONFIG(itemviews)
1775 case SE_PushButtonFocusRect:
1776 case SE_CheckBoxClickRect:
1777 case SE_RadioButtonClickRect:
1778 return opt->rect;
1779#if QT_CONFIG(progressbar)
1780 case SE_ProgressBarGroove: {
1781 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::ProgressBar, opt->state);
1782 if (!resolved.isValid())
1783 break;
1784 const auto &metrics = *resolved.metrics;
1785 QRect rect = opt->rect.marginsRemoved(metrics.margins);
1786 const auto *indicator = resolved.indicator();
1787 if (!indicator || !indicator->visible() || indicator->opacity() == 0)
1788 return rect;
1789
1790 const int w = indicator->implicitWidth() >= 0
1791 ? indicator->implicitWidth()
1792 : rect.width() - metrics.padding.left() - metrics.padding.right()
1793 - metrics.indicatorMargins.left() - metrics.indicatorMargins.right();
1794 const int h = indicator->implicitHeight() >= 0
1795 ? indicator->implicitHeight()
1796 : rect.height() - metrics.padding.top() - metrics.padding.bottom()
1797 - metrics.indicatorMargins.top() - metrics.indicatorMargins.bottom();
1798 const uint alignment = resolvedAlignment(indicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
1799 const QRect indicatorRect = d->getAlignedRectInContainer(
1800 rect, QSize(w, h), alignment, metrics.padding, metrics.indicatorMargins);
1801 return visualRect(opt->direction, rect, indicatorRect);
1802 }
1803 case SE_ProgressBarContents: {
1804 if (qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
1805 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::ProgressBar, opt->state);
1806 if (!resolved.isValid())
1807 break;
1808 const auto *foreground = resolved.indicator() ? resolved.indicator()->foreground() : nullptr;
1809 if (!foreground || !foreground->visible() || foreground->opacity() == 0)
1810 return opt->rect;
1811
1812 QRect indicatorRect = visualRect(opt->direction, opt->rect, subElementRect(SE_ProgressBarGroove, opt, widget));
1813 const auto foregroundW = foreground->implicitWidth() >= 0 ? foreground->implicitWidth() : indicatorRect.width() - foreground->leftMargin() - foreground->rightMargin();
1814 const auto foregroundH = foreground->implicitHeight() >= 0 ? foreground->implicitHeight() : indicatorRect.height() - foreground->topMargin() - foreground->bottomMargin();
1815 const uint foregroundAlign = resolvedAlignment(foreground->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
1816 const QMargins foregroundMargins = QMargins(foreground->leftMargin(), foreground->topMargin(), foreground->rightMargin(), foreground->bottomMargin());
1817 const QRect foregroundRect = d->getAlignedRectInContainer(
1818 indicatorRect, QSize(foregroundW, foregroundH), foregroundAlign, QMargins(0, 0, 0, 0), foregroundMargins);
1819 return visualRect(opt->direction, opt->rect, foregroundRect);
1820 }
1821 break;
1822 }
1823#endif // QT_CONFIG(progressbar)
1824 case SE_LineEditContents:
1825 if (qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
1826#if QT_CONFIG(spinbox)
1827 const bool isInSpinBox = widget && qobject_cast<const QSpinBox *>(widget->parentWidget());
1828#else
1829 const bool isInSpinBox = false;
1830#endif
1831 const auto controlType = isInSpinBox ? QQStyleKitReader::ControlType::SpinBox : QQStyleKitReader::ControlType::TextField;
1832 const auto resolved = d->resolveLayout(controlType, opt->state);
1833 if (!resolved.isValid())
1834 break;
1835 const auto &metrics = *resolved.metrics;
1836 QRect contentsRect = opt->rect.marginsRemoved(metrics.padding);
1837 const auto *textProps = resolved.text();
1838 const uint textAlign = resolvedAlignment(
1839 textProps ? textProps->alignment() : 0u, Qt::AlignLeft, Qt::AlignVCenter);
1840 if (textAlign & Qt::AlignLeft)
1841 contentsRect.setLeft(contentsRect.left() + metrics.textPadding.left());
1842 else if (textAlign & Qt::AlignHCenter) {
1843 contentsRect.setLeft(contentsRect.left() + metrics.textPadding.left() / 2);
1844 contentsRect.setRight(contentsRect.right() - metrics.textPadding.right() / 2);
1845 } else {
1846 contentsRect.setRight(contentsRect.right() - metrics.textPadding.right());
1847 }
1848 if (textAlign & Qt::AlignTop)
1849 contentsRect.setTop(contentsRect.top() + metrics.textPadding.top());
1850 else if (textAlign & Qt::AlignVCenter) {
1851 contentsRect.setTop(contentsRect.top() + metrics.textPadding.top() / 2);
1852 contentsRect.setBottom(contentsRect.bottom() - metrics.textPadding.bottom() / 2);
1853 } else {
1854 contentsRect.setBottom(contentsRect.bottom() - metrics.textPadding.bottom());
1855 }
1856 return visualRect(opt->direction, opt->rect, contentsRect);
1857 }
1858 break;
1859 case SE_ShapedFrameContents:
1860#if QT_CONFIG(combobox)
1861 if (widget && widget->inherits("QComboBoxPrivateContainer")) {
1862 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::Popup, opt->state);
1863 if (!resolved.isValid())
1864 break;
1865 const auto &metrics = *resolved.metrics;
1866 QRect contentsRect = opt->rect.marginsRemoved(metrics.margins + metrics.padding);
1867 return visualRect(opt->direction, opt->rect, contentsRect);
1868 }
1869#endif
1870 break;
1871 default:
1872 break;
1873 }
1874 return QCommonStyle::subElementRect(r, opt, widget);
1875}
1876
1877/*! \reimp */
1878void QStyleKitStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
1879 const QWidget *w) const
1880{
1881 Q_D(const QStyleKitStyle);
1882 if (!d->style) {
1883 qWarning("QStyleKitStyle: No StyleKit style loaded, drawing complex control with QCommonStyle: %d", int(cc));
1884 QCommonStyle::drawComplexControl(cc, opt, p, w);
1885 return;
1886 }
1887
1888 switch (cc) {
1889#if QT_CONFIG(slider)
1890 case CC_Slider:
1891 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
1892 const auto r = d->resolve(w, QQStyleKitReader::ControlType::Slider, slider->state);
1893 if (!r.isValid())
1894 break;
1895 const auto &metrics = *r.metrics;
1896 QRect backgroundRect = opt->rect.marginsRemoved(metrics.margins);
1897
1898 // background
1899 d->drawStyledItemRect(r.background(), backgroundRect, p);
1900
1901 // groove
1902 const auto grooveRect = subControlRect(CC_Slider, opt, SC_SliderGroove, w);
1903 if (slider->subControls & SC_SliderGroove) {
1904 // groove
1905 const auto *indicator = r.indicator();
1906 if (indicator && indicator->visible() && indicator->opacity() > 0)
1907 d->drawStyledItemRect(indicator, grooveRect, p);
1908
1909 // track
1910 const auto *foreground = indicator ? indicator->foreground() : nullptr;
1911 if (foreground && foreground->visible() && foreground->opacity() > 0) {
1912 const bool isHorizontal = slider->orientation == Qt::Horizontal;
1913 const auto availableW = isHorizontal
1914 ? grooveRect.width() - foreground->leftMargin() - foreground->rightMargin()
1915 : grooveRect.width() - foreground->topMargin() - foreground->bottomMargin();
1916 const auto availableH = isHorizontal
1917 ? grooveRect.height() - foreground->topMargin() - foreground->bottomMargin()
1918 : grooveRect.height() - foreground->leftMargin() - foreground->rightMargin();
1919
1920 const qreal range = slider->maximum - slider->minimum;
1921 const qreal ratio = range > 0 ? (slider->sliderPosition - slider->minimum) / range : 0;
1922
1923 qreal trackW, trackH;
1924 if (isHorizontal) {
1925 trackW = ratio * availableW;
1926 trackH = foreground->implicitHeight() >= 0 ? foreground->implicitHeight() : availableH;
1927 } else {
1928 trackW = foreground->implicitWidth() >= 0 ? foreground->implicitWidth() : availableW;
1929 trackH = ratio * availableH;
1930 }
1931 QRect trackRect(0, 0, trackW, trackH);
1932 // alignment
1933 const uint rawHAlign = foreground->alignment() & Qt::AlignHorizontal_Mask;
1934 const uint rawVAlign = foreground->alignment() & Qt::AlignVertical_Mask;
1935 // For vertical orientation, swap alignment
1936 uint hAlign, vAlign;
1937 if (isHorizontal) {
1938 hAlign = rawHAlign;
1939 vAlign = rawVAlign;
1940 } else {
1941 if (rawVAlign == Qt::AlignTop)
1942 hAlign = Qt::AlignLeft;
1943 else if (rawVAlign == Qt::AlignVCenter)
1944 hAlign = Qt::AlignHCenter;
1945 else if (rawVAlign == Qt::AlignBottom)
1946 hAlign = Qt::AlignRight;
1947 else
1948 hAlign = 0;
1949
1950 if (rawHAlign == Qt::AlignLeft)
1951 vAlign = Qt::AlignTop;
1952 else if (rawHAlign == Qt::AlignHCenter)
1953 vAlign = Qt::AlignVCenter;
1954 else if (rawHAlign == Qt::AlignRight)
1955 vAlign = Qt::AlignBottom;
1956 else
1957 vAlign = 0;
1958 }
1959 if (hAlign & Qt::AlignLeft)
1960 trackRect.moveLeft(grooveRect.left() + foreground->leftMargin());
1961 else if (hAlign & Qt::AlignHCenter)
1962 trackRect.moveLeft(grooveRect.left() + foreground->leftMargin()
1963 + (availableW - trackRect.width()) / 2);
1964 else if (hAlign & Qt::AlignRight)
1965 trackRect.moveLeft(grooveRect.right() - foreground->rightMargin() - trackRect.width());
1966 if (vAlign & Qt::AlignTop) {
1967 if (!isHorizontal)
1968 trackRect.moveTop(grooveRect.bottom() - foreground->bottomMargin() - trackRect.height());
1969 else
1970 trackRect.moveTop(grooveRect.top() + foreground->topMargin());
1971 } else if (vAlign & Qt::AlignVCenter) {
1972 trackRect.moveTop(grooveRect.top() + (grooveRect.height() - trackRect.height()) / 2);
1973 } else if (vAlign & Qt::AlignBottom) {
1974 if (!isHorizontal)
1975 trackRect.moveTop(grooveRect.top() + foreground->topMargin());
1976 else
1977 trackRect.moveTop(grooveRect.bottom() - foreground->bottomMargin() - trackRect.height());
1978 }
1979 d->drawStyledItemRect(foreground, visualRect(opt->direction, grooveRect, trackRect), p);
1980 }
1981 }
1982
1983 // handle
1984 if (slider->subControls & SC_SliderHandle) {
1985 QStyleOptionSlider handleOpt(*slider);
1986 handleOpt.rect = subControlRect(CC_Slider, opt, SC_SliderHandle, w);
1987 const auto *handle = r.handle();
1988 if (handle && handle->visible() && handle->opacity() > 0)
1989 d->drawStyledItemRect(handle, handleOpt.rect, p);
1990 }
1991 return;
1992 }
1993 break;
1994#endif // QT_CONFIG(slider)
1995#if QT_CONFIG(combobox)
1996 case CC_ComboBox:
1997 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
1998 // background
1999 const auto r = d->resolve(w, QQStyleKitReader::ControlType::ComboBox, combo->state);
2000 if (!r.isValid())
2001 break;
2002 QRect frameRect = subControlRect(CC_ComboBox, opt, SC_ComboBoxFrame, w);
2003 d->drawStyledItemRect(r.background(), frameRect, p);
2004
2005 // indicator
2006 if (combo->subControls & SC_ComboBoxArrow) {
2007 QStyleOptionComboBox indicatorOpt(*combo);
2008 indicatorOpt.rect = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow, w);
2009 proxy()->drawPrimitive(PE_IndicatorArrowDown, &indicatorOpt, p, w);
2010 }
2011
2012 // The editable combobox paints its own line edit using the QPalette::Text role
2013 // for the text color, so update that color in the palette
2014 if (auto *cb = qobject_cast<const QComboBox *>(w); cb && cb->isEditable()) {
2015 if (const auto *txt = r.text(); txt && txt->isDefined(QQSK::Property::Color)) {
2016 QPalette stylePalette;
2017 stylePalette.setColor(QPalette::Text, txt->color());
2018 d->setStylePalette(cb->lineEdit(), stylePalette);
2019 }
2020 }
2021 return;
2022 }
2023 break;
2024#endif // QT_CONFIG(combobox)
2025#if QT_CONFIG(spinbox)
2026 case CC_SpinBox:
2027 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
2028 const auto r = d->resolve(w, QQStyleKitReader::ControlType::SpinBox, spin->state);
2029 if (!r.isValid())
2030 break;
2031 QRect frameRect = opt->rect.marginsRemoved(r.metrics->margins);
2032 // background
2033 d->drawStyledItemRect(r.background(), frameRect, p);
2034 // up/down buttons
2035 if (spin->subControls & SC_SpinBoxUp) {
2036 QStyleOptionSpinBox upOpt(*spin);
2037 upOpt.rect = subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w);
2038 proxy()->drawPrimitive(PE_IndicatorSpinUp, &upOpt, p, w);
2039 }
2040 if (spin->subControls & SC_SpinBoxDown) {
2041 QStyleOptionSpinBox downOpt(*spin);
2042 downOpt.rect = subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w);
2043 proxy()->drawPrimitive(PE_IndicatorSpinDown, &downOpt, p, w);
2044 }
2045 // The spinbox line edit paints its text using the QPalette::Text role,
2046 // so update that color in the palette
2047 if (auto *sb = qobject_cast<const QSpinBox *>(w)) {
2048 if (const auto *txt = r.text(); txt && txt->isDefined(QQSK::Property::Color)) {
2049 QLineEdit *lineEdit = sb->findChild<QLineEdit *>();
2050 if (lineEdit) {
2051 QPalette p = lineEdit->palette();
2052 if (p.color(QPalette::Text) != txt->color()) {
2053 p.setColor(QPalette::Text, txt->color());
2054 lineEdit->setPalette(p);
2055 }
2056 }
2057 }
2058 }
2059 return;
2060 }
2061 break;
2062#endif // QT_CONFIG(spinbox)
2063 default:
2064 break;
2065 }
2066 QCommonStyle::drawComplexControl(cc, opt, p, w);
2067}
2068
2069/*! \reimp */
2070QStyle::SubControl QStyleKitStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
2071 const QPoint &pt, const QWidget *w) const
2072{
2073 return QCommonStyle::hitTestComplexControl(cc, opt, pt, w);
2074}
2075
2076/*! \reimp */
2077QRect QStyleKitStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
2078 const QWidget *w) const
2079{
2080 Q_D(const QStyleKitStyle);
2081 if (!d->style) {
2082 qWarning("QStyleKitStyle: No StyleKit style loaded, calculating subControlRect with QCommonStyle: %d %d",
2083 int(cc), int(sc));
2084 return QCommonStyle::subControlRect(cc, opt, sc, w);
2085 }
2086
2087 switch (cc) {
2088#if QT_CONFIG(slider)
2089 case CC_Slider:
2090 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
2091 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::Slider, opt->state);
2092 if (!resolved.isValid())
2093 break;
2094 const auto &metrics = *resolved.metrics;
2095 QRect contentsRect = opt->rect.marginsRemoved(
2096 slider->orientation == Qt::Horizontal
2097 ? QMargins(metrics.margins.left(), metrics.margins.top(), metrics.margins.right(), metrics.margins.bottom())
2098 : QMargins(metrics.margins.top(), metrics.margins.left(), metrics.margins.bottom(), metrics.margins.right())
2099 ).marginsRemoved(
2100 slider->orientation == Qt::Horizontal
2101 ? QMargins(metrics.padding.left(), metrics.padding.top(), metrics.padding.right(), metrics.padding.bottom())
2102 : QMargins(metrics.padding.top(), metrics.padding.left(), metrics.padding.bottom(), metrics.padding.right())
2103 );
2104
2105 const auto *indicator = resolved.indicator();
2106 if (!indicator)
2107 return contentsRect;
2108 switch (sc) {
2109 case SC_SliderGroove: {
2110 const bool isHorizontal = slider->orientation == Qt::Horizontal;
2111 const auto availableW = isHorizontal
2112 ? contentsRect.width() - indicator->leftMargin() - indicator->rightMargin()
2113 : contentsRect.width() - indicator->topMargin() - indicator->bottomMargin();
2114 const auto availableH = isHorizontal
2115 ? contentsRect.height() - indicator->topMargin() - indicator->bottomMargin()
2116 : contentsRect.height() - indicator->leftMargin() - indicator->rightMargin();
2117
2118 qreal grooveW, grooveH;
2119 if (isHorizontal) {
2120 grooveW = indicator->implicitWidth() >= 0
2121 ? indicator->implicitWidth()
2122 : availableW;
2123 grooveH = indicator->implicitHeight() >= 0
2124 ? indicator->implicitHeight()
2125 : availableH;
2126 } else {
2127 grooveW = indicator->implicitHeight() >= 0
2128 ? indicator->implicitHeight()
2129 : availableW;
2130 grooveH = indicator->implicitWidth() >= 0
2131 ? indicator->implicitWidth()
2132 : availableH;
2133 }
2134
2135 QRectF grooveRect(0, 0, grooveW, grooveH);
2136 // alignment
2137 const uint rawHAlign = indicator->alignment() & Qt::AlignHorizontal_Mask;
2138 const uint rawVAlign = indicator->alignment() & Qt::AlignVertical_Mask;
2139 // For vertical orientation, swap alignment axes
2140 uint hAlign, vAlign;
2141 if (isHorizontal) {
2142 hAlign = rawHAlign ? static_cast<Qt::Alignment>(rawHAlign) : Qt::AlignLeft;
2143 vAlign = rawVAlign ? static_cast<Qt::Alignment>(rawVAlign) : Qt::AlignVCenter;
2144 } else {
2145 if (rawVAlign & Qt::AlignTop)
2146 hAlign = Qt::AlignLeft;
2147 else if (rawVAlign & Qt::AlignBottom)
2148 hAlign = Qt::AlignRight;
2149 else if (rawVAlign & Qt::AlignVCenter)
2150 hAlign = Qt::AlignHCenter;
2151 else
2152 hAlign = Qt::AlignLeft;
2153
2154 if (rawHAlign & Qt::AlignLeft)
2155 vAlign = Qt::AlignTop;
2156 else if (rawHAlign & Qt::AlignRight)
2157 vAlign = Qt::AlignBottom;
2158 else if (rawHAlign & Qt::AlignHCenter)
2159 vAlign = Qt::AlignVCenter;
2160 else
2161 vAlign = Qt::AlignVCenter;
2162 }
2163
2164 if (hAlign & Qt::AlignLeft) {
2165 grooveRect.moveLeft(contentsRect.x() + indicator->leftMargin());
2166 } else if (hAlign & Qt::AlignHCenter) {
2167 const int availableWidth = contentsRect.width()
2168 - indicator->leftMargin()
2169 - indicator->rightMargin();
2170 grooveRect.moveLeft(contentsRect.x() + indicator->leftMargin()
2171 + (availableWidth - grooveW) / 2.0);
2172 } else {
2173 grooveRect.moveLeft(contentsRect.x() + contentsRect.width()
2174 - indicator->rightMargin() - grooveW);
2175 }
2176
2177 if (vAlign & Qt::AlignTop) {
2178 grooveRect.moveTop(contentsRect.y() + indicator->topMargin());
2179 } else if (vAlign & Qt::AlignVCenter) {
2180 const int availableHeight = contentsRect.height()
2181 - indicator->topMargin()
2182 - indicator->bottomMargin();
2183 grooveRect.moveTop(contentsRect.y() + indicator->topMargin()
2184 + (availableHeight - grooveH) / 2.0);
2185 } else {
2186 grooveRect.moveTop(contentsRect.y() + contentsRect.height()
2187 - indicator->bottomMargin() - grooveH);
2188 }
2189 return visualRect(opt->direction, opt->rect, grooveRect.toAlignedRect());
2190 }
2191 case SC_SliderHandle: {
2192 const auto *handle = resolved.handle();
2193 if (!handle || !handle->visible() || handle->opacity() == 0)
2194 return contentsRect;
2195
2196 QRect handleRect;
2197 const bool horizontal = slider->orientation == Qt::Horizontal;
2198 const auto handleW = handle->implicitWidth() >= 0 ? handle->implicitWidth() : contentsRect.width() - handle->leftMargin() - handle->rightMargin();
2199 const auto handleH = handle->implicitHeight() >= 0 ? handle->implicitHeight() : contentsRect.height() - handle->topMargin() - handle->bottomMargin();
2200 const int range = horizontal ? contentsRect.width() - handleW : contentsRect.height() - handleH;
2201 const int sliderPos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
2202 slider->sliderPosition, range, !horizontal);
2203 if (horizontal)
2204 handleRect = QRect(contentsRect.x() + sliderPos, contentsRect.y() + handle->topMargin() + (contentsRect.height() - handleH) / 2, handleW, handleH);
2205 else
2206 handleRect = QRect(contentsRect.x() + handle->leftMargin() + (contentsRect.width() - handleW) / 2, contentsRect.y() + sliderPos, handleW, handleH);
2207 return visualRect(opt->direction, opt->rect, handleRect);
2208 }
2209 default:
2210 break;
2211 }
2212 }
2213 break;
2214#endif // QT_CONFIG(slider)
2215#if QT_CONFIG(combobox)
2216 case CC_ComboBox:
2217 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
2218 QRect frameRect = combo->rect;
2219 const auto r = d->resolveLayout(QQStyleKitReader::ControlType::ComboBox, combo->state);
2220 if (!r.isValid())
2221 break;
2222 const auto &metrics = *r.metrics;
2223 frameRect = frameRect.marginsRemoved(metrics.margins);
2224 switch (sc) {
2225 case SC_ComboBoxFrame:
2226 return visualRect(opt->direction, opt->rect, frameRect);
2227 case SC_ComboBoxEditField: {
2228 QRect contentsRect = frameRect.marginsRemoved(metrics.padding);
2229 QRect indicatorRect = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow, w);
2230 const int spacing = metrics.spacing;
2231 const auto *indicator = r.indicator();
2232 const uint indicatorAlign = indicator
2233 ? resolvedAlignment(indicator->alignment(), Qt::AlignRight, Qt::AlignVCenter)
2234 : uint(Qt::AlignRight | Qt::AlignVCenter);
2235 if (indicatorAlign & Qt::AlignLeft) {
2236 contentsRect.setLeft(indicatorRect.right() + spacing);
2237 } else if (indicatorAlign & Qt::AlignRight) {
2238 contentsRect.setRight(indicatorRect.left() - spacing);
2239 }
2240 return visualRect(opt->direction, opt->rect, contentsRect);
2241 }
2242 case SC_ComboBoxArrow: {
2243 QRect contentsRect = frameRect.marginsRemoved(metrics.padding);
2244 const auto *indicator = r.indicator();
2245 if (!indicator || !indicator->visible() || indicator->opacity() == 0)
2246 return contentsRect;
2247
2248 const int w = indicator->implicitWidth() >= 0
2249 ? indicator->implicitWidth()
2250 : contentsRect.width() - indicator->leftMargin() - indicator->rightMargin();
2251 const int h = indicator->implicitHeight() >= 0
2252 ? indicator->implicitHeight()
2253 : contentsRect.height() - indicator->topMargin() - indicator->bottomMargin();
2254 const uint indicatorAlign = resolvedAlignment(indicator->alignment(), Qt::AlignRight, Qt::AlignVCenter);
2255 const QMargins indicatorMargins(indicator->leftMargin(), indicator->topMargin(),
2256 indicator->rightMargin(), indicator->bottomMargin());
2257 return visualRect(opt->direction, opt->rect,
2258 d->getAlignedRectInContainer(contentsRect, QSize(w, h), indicatorAlign, QMargins(), indicatorMargins));
2259 }
2260 case SC_ComboBoxListBoxPopup: {
2261 QRect popupRect = opt->rect;
2262 popupRect.setTop(opt->rect.bottom());
2263 return visualRect(opt->direction, opt->rect, popupRect);
2264 }
2265 default:
2266 break;
2267 }
2268 }
2269 break;
2270#endif // QT_CONFIG(combobox)
2271#if QT_CONFIG(spinbox)
2272 case CC_SpinBox:
2273 if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
2274 const auto r = d->resolveLayout(QQStyleKitReader::ControlType::SpinBox, spinBox->state);
2275 if (!r.isValid())
2276 break;
2277 const auto &metrics = *r.metrics;
2278 QRect frameRect = opt->rect.marginsRemoved(metrics.margins);
2279 QRect contentsRect = frameRect.marginsRemoved(metrics.padding);
2280 switch (sc) {
2281 case SC_SpinBoxFrame:
2282 return visualRect(opt->direction, opt->rect, frameRect);
2283 case SC_SpinBoxEditField: {
2284 QRect upIndicatorRect = subControlRect(CC_SpinBox, opt, SC_SpinBoxUp, w);
2285 QRect downIndicatorRect = subControlRect(CC_SpinBox, opt, SC_SpinBoxDown, w);
2286 const int spacing = metrics.spacing;
2287 const auto *upIndicator = r.indicator() ? r.indicator()->first() : nullptr;
2288 const auto *downIndicator = r.indicator() ? r.indicator()->second() : nullptr;
2289 const bool hasUpIndicator = upIndicator && upIndicator->visible() && upIndicator->opacity() > 0;
2290 const bool hasDownIndicator = downIndicator && downIndicator->visible() && downIndicator->opacity() > 0;
2291 const uint upAlign = hasUpIndicator
2292 ? resolvedAlignment(upIndicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter)
2293 : uint(Qt::AlignLeft | Qt::AlignVCenter);
2294 const uint downAlign = hasDownIndicator
2295 ? resolvedAlignment(downIndicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter)
2296 : uint(Qt::AlignLeft | Qt::AlignVCenter);
2297 if (hasUpIndicator && hasDownIndicator) {
2298 if ((upAlign & Qt::AlignLeft) && (downAlign & Qt::AlignRight)) {
2299 contentsRect.setLeft(upIndicatorRect.right() + spacing);
2300 contentsRect.setRight(downIndicatorRect.left() - spacing);
2301 } else if ((upAlign & Qt::AlignRight) && (downAlign & Qt::AlignLeft)) {
2302 contentsRect.setRight(upIndicatorRect.left() - spacing);
2303 contentsRect.setLeft(downIndicatorRect.right() + spacing);
2304 }
2305 } else if (hasUpIndicator) {
2306 if (upAlign & Qt::AlignLeft) {
2307 contentsRect.setLeft(upIndicatorRect.right() + spacing);
2308 } else if (upAlign & Qt::AlignRight) {
2309 contentsRect.setRight(upIndicatorRect.left() - spacing);
2310 }
2311 } else if (hasDownIndicator) {
2312 if (downAlign & Qt::AlignLeft) {
2313 contentsRect.setLeft(downIndicatorRect.right() + spacing);
2314 } else if (downAlign & Qt::AlignRight) {
2315 contentsRect.setRight(downIndicatorRect.left() - spacing);
2316 }
2317 }
2318 return visualRect(opt->direction, opt->rect, contentsRect);
2319 }
2320 case SC_SpinBoxUp: {
2321 const auto *upIndicator = r.indicator() ? r.indicator()->first() : nullptr;
2322 if (!upIndicator || !upIndicator->visible() || upIndicator->opacity() == 0)
2323 return contentsRect;
2324
2325 const int w = upIndicator->implicitWidth() >= 0 ? upIndicator->implicitWidth() : contentsRect.width() - upIndicator->leftMargin() - upIndicator->rightMargin();
2326 const int h = upIndicator->implicitHeight() >= 0 ? upIndicator->implicitHeight() : contentsRect.height() - upIndicator->topMargin() - upIndicator->bottomMargin();
2327 const uint upAlign = resolvedAlignment(upIndicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
2328 const QMargins upMargins(upIndicator->leftMargin(), upIndicator->topMargin(),
2329 upIndicator->rightMargin(), upIndicator->bottomMargin());
2330 return visualRect(opt->direction, opt->rect,
2331 d->getAlignedRectInContainer(contentsRect, QSize(w, h), upAlign, QMargins(), upMargins));
2332 }
2333 case SC_SpinBoxDown: {
2334 const auto *downIndicator = r.indicator() ? r.indicator()->second() : nullptr;
2335 if (!downIndicator || !downIndicator->visible() || downIndicator->opacity() == 0)
2336 return frameRect;
2337
2338 const int w = downIndicator->implicitWidth() >= 0 ? downIndicator->implicitWidth() : contentsRect.width() - downIndicator->leftMargin() - downIndicator->rightMargin();
2339 const int h = downIndicator->implicitHeight() >= 0 ? downIndicator->implicitHeight() : contentsRect.height() - downIndicator->topMargin() - downIndicator->bottomMargin();
2340 const uint downAlign = resolvedAlignment(downIndicator->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
2341 const QMargins downMargins(downIndicator->leftMargin(), downIndicator->topMargin(),
2342 downIndicator->rightMargin(), downIndicator->bottomMargin());
2343 return visualRect(opt->direction, opt->rect,
2344 d->getAlignedRectInContainer(contentsRect, QSize(w, h), downAlign, QMargins(), downMargins));
2345 }
2346 default:
2347 break;
2348 }
2349 }
2350 break;
2351#endif // QT_CONFIG(spinbox)
2352 default:
2353 break;
2354 }
2355 return QCommonStyle::subControlRect(cc, opt, sc, w);
2356}
2357
2358/*! \reimp */
2359QSize QStyleKitStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
2360 const QSize &contentsSize, const QWidget *widget) const
2361{
2362 Q_D(const QStyleKitStyle);
2363 if (!d->style) {
2364 qWarning("QStyleKitStyle: No StyleKit style loaded, calculating sizeFromContents with QCommonStyle: %d", int(ct));
2365 return QCommonStyle::sizeFromContents(ct, opt, contentsSize, widget);
2366 }
2367
2368 switch (ct) {
2369 case CT_PushButton:
2370 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2371 const auto controlType = btn->features & QStyleOptionButton::Flat
2372 ? QQStyleKitReader::ControlType::FlatButton
2373 : QQStyleKitReader::ControlType::Button;
2374 const auto resolved = d->resolveLayout(controlType, opt->state);
2375 if (!resolved.isValid())
2376 break;
2377 const auto &metrics = *resolved.metrics;
2378 const QSize textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, btn->text);
2379 const QSize contentSizeWithPadding = textSize.expandedTo(contentsSize)
2380 + QSize(metrics.padding.left() + metrics.padding.right(),
2381 metrics.padding.top() + metrics.padding.bottom())
2382 + QSize(metrics.textPadding.left() + metrics.textPadding.right(),
2383 metrics.textPadding.top() + metrics.textPadding.bottom());
2384 const QSize bgSizeWithMargins = metrics.bgImplicitSize + QSize(metrics.margins.left() + metrics.margins.right(),
2385 metrics.margins.top() + metrics.margins.bottom());
2386 return contentSizeWithPadding.expandedTo(bgSizeWithMargins);
2387 }
2388 break;
2389 case CT_CheckBox:
2390 case CT_RadioButton:
2391 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
2392 const auto controlType = ct == CT_CheckBox ? QQStyleKitReader::ControlType::CheckBox
2393 : QQStyleKitReader::ControlType::RadioButton;
2394 const auto resolved = d->resolveLayout(controlType, opt->state);
2395 if (!resolved.isValid())
2396 break;
2397 const auto &metrics = *resolved.metrics;
2398 const QSize textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, btn->text);
2399 const int bgWidth = metrics.bgImplicitSize.width() + metrics.margins.left() + metrics.margins.right();
2400 const int bgHeight = metrics.bgImplicitSize.height() + metrics.margins.top() + metrics.margins.bottom();
2401 const int contentWidth = std::max(textSize.width(), contentsSize.width()) + metrics.padding.left() + metrics.padding.right()
2402 + metrics.textPadding.left() + metrics.textPadding.right();
2403 const int contentHeight = std::max(textSize.height(), contentsSize.height()) + metrics.padding.top() + metrics.padding.bottom()
2404 + metrics.textPadding.top() + metrics.textPadding.bottom();
2405 const int indicatorWidth = metrics.indicatorImplicitSize.width() + metrics.indicatorMargins.left()
2406 + metrics.indicatorMargins.right();
2407 const int indicatorHeight = metrics.indicatorImplicitSize.height() + metrics.indicatorMargins.top()
2408 + metrics.indicatorMargins.bottom();
2409 return QSize(std::max({contentWidth + indicatorWidth + metrics.spacing, bgWidth}),
2410 std::max({contentHeight, indicatorHeight, bgHeight}));
2411 }
2412 break;
2413#if QT_CONFIG(itemviews)
2414 case CT_ItemViewItem:
2415 if (const auto *item = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
2416 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::ItemDelegate, opt->state);
2417 if (!resolved.isValid())
2418 break;
2419 const auto &metrics = *resolved.metrics;
2420 const QSize textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, item->text);
2421 const int bgWidth = metrics.bgImplicitSize.width() + metrics.margins.left() + metrics.margins.right();
2422 const int bgHeight = metrics.bgImplicitSize.height() + metrics.margins.top() + metrics.margins.bottom();
2423 const int contentWidth = std::max(textSize.width(), contentsSize.width()) + metrics.padding.left() + metrics.padding.right()
2424 + metrics.textPadding.left() + metrics.textPadding.right();
2425 const int contentHeight = std::max(textSize.height(), contentsSize.height()) + metrics.padding.top() + metrics.padding.bottom()
2426 + metrics.textPadding.top() + metrics.textPadding.bottom();
2427 const int indicatorWidth = metrics.indicatorImplicitSize.width() + metrics.indicatorMargins.left()
2428 + metrics.indicatorMargins.right();
2429 const int indicatorHeight = metrics.indicatorImplicitSize.height() + metrics.indicatorMargins.top()
2430 + metrics.indicatorMargins.bottom();
2431 return QSize(std::max({contentWidth + indicatorWidth + metrics.spacing, bgWidth}),
2432 std::max({contentHeight, indicatorHeight, bgHeight}));
2433 }
2434 break;
2435#endif // QT_CONFIG(itemviews)
2436 case CT_ProgressBar:
2437 if (qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
2438 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::ProgressBar, opt->state);
2439 if (!resolved.isValid())
2440 break;
2441 const auto &metrics = *resolved.metrics;
2442 const auto indicatorW = std::max(metrics.indicatorImplicitSize.width()
2443 + metrics.indicatorMargins.left()
2444 + metrics.indicatorMargins.right(),
2445 metrics.foregroundImplicitSize.width()
2446 + metrics.foregroundMargins.left()
2447 + metrics.foregroundMargins.right());
2448 const auto indicatorH = std::max(metrics.indicatorImplicitSize.height()
2449 + metrics.indicatorMargins.top()
2450 + metrics.indicatorMargins.bottom(),
2451 metrics.foregroundImplicitSize.height()
2452 + metrics.foregroundMargins.top()
2453 + metrics.foregroundMargins.bottom());
2454 const int bgW = metrics.bgImplicitSize.width() + metrics.margins.left() + metrics.margins.right();
2455 const int bgH = metrics.bgImplicitSize.height() + metrics.margins.top() + metrics.margins.bottom();
2456 // For progress bar in Controls, the content size is based on the indicator size
2457 const int contentW = indicatorW + metrics.padding.left() + metrics.padding.right();
2458 const int contentH = indicatorH + metrics.padding.top() + metrics.padding.bottom();
2459 return QSize(std::max(contentW, bgW), std::max(contentH, bgH));
2460 }
2461 break;
2462 case CT_Slider:
2463 if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
2464 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::Slider, opt->state);
2465 if (!resolved.isValid())
2466 break;
2467 const auto &metrics = *resolved.metrics;
2468 // background in Controls = indicator = groove + track
2469 const int bgW = std::max(metrics.indicatorImplicitSize.width() + metrics.indicatorMargins.left() + metrics.indicatorMargins.right(),
2470 metrics.bgImplicitSize.width() + metrics.margins.left() + metrics.margins.right());
2471 const int bgH = std::max(metrics.indicatorImplicitSize.height() + metrics.indicatorMargins.top() + metrics.indicatorMargins.bottom(),
2472 metrics.bgImplicitSize.height() + metrics.margins.top() + metrics.margins.bottom());
2473 const int handleW = metrics.handleImplicitSize.width() + metrics.padding.left() + metrics.padding.right();
2474 const int handleH = metrics.handleImplicitSize.height() + metrics.padding.top() + metrics.padding.bottom();
2475 return slider->orientation == Qt::Horizontal
2476 ? QSize(std::max(handleW, bgW), std::max(handleH, bgH))
2477 : QSize(std::max(handleH, bgH), std::max(handleW, bgW));
2478 }
2479 break;
2480#if QT_CONFIG(lineedit)
2481 case CT_LineEdit:
2482 if (const auto *lineEdit = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2483 QStyleOption lineEditOpt(*lineEdit);
2484 lineEditOpt.state &= ~QStyle::State_Sunken;
2485#if QT_CONFIG(spinbox)
2486 const bool isInSpinBox = widget && qobject_cast<const QSpinBox *>(widget->parent());
2487#else
2488 const bool isInSpinBox = false;
2489#endif
2490 auto controlType = isInSpinBox ? QQStyleKitReader::ControlType::SpinBox : QQStyleKitReader::ControlType::TextField;
2491 const auto resolved = d->resolveLayout(controlType, lineEditOpt.state);
2492 if (!resolved.isValid())
2493 break;
2494 const auto &metrics = *resolved.metrics;
2495 QSize bgSize(0, 0);
2496 // For spinbox, the line edit doesn't have its own background in the Controls style
2497 if (!isInSpinBox)
2498 bgSize = metrics.bgImplicitSize.grownBy(metrics.margins);
2499 const QSize contentSizeWithPadding = contentsSize.grownBy(metrics.textPadding).grownBy(metrics.padding);
2500 return contentSizeWithPadding.expandedTo(bgSize);
2501 }
2502 break;
2503#endif // QT_CONFIG(lineedit)
2504#if QT_CONFIG(combobox)
2505 case CT_ComboBox:
2506 if (const auto *comboBox = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
2507 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::ComboBox, opt->state);
2508 if (!resolved.isValid())
2509 break;
2510 const auto &metrics = *resolved.metrics;
2511 const QSize textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, comboBox->currentText);
2512 const int bgW = metrics.bgImplicitSize.width() + metrics.margins.left() + metrics.margins.right();
2513 const int bgH = metrics.bgImplicitSize.height() + metrics.margins.top() + metrics.margins.bottom();
2514 const int contentW = textSize.width() + metrics.padding.left() + metrics.padding.right()
2515 + metrics.textPadding.left() + metrics.textPadding.right();
2516 const int contentH = textSize.height() + metrics.padding.top() + metrics.padding.bottom()
2517 + metrics.textPadding.top() + metrics.textPadding.bottom();
2518 const int indicatorW = metrics.indicatorImplicitSize.width() + metrics.indicatorMargins.left()
2519 + metrics.indicatorMargins.right();
2520 const int indicatorH = metrics.indicatorImplicitSize.height() + metrics.indicatorMargins.top()
2521 + metrics.indicatorMargins.bottom();
2522 return QSize(std::max({contentW + indicatorW + metrics.spacing, bgW}),
2523 std::max({contentH, indicatorH, bgH}));
2524 }
2525 break;
2526#endif // QT_CONFIG(combobox)
2527#if QT_CONFIG(spinbox)
2528 case CT_SpinBox: {
2529 const auto resolved = d->resolveLayout(QQStyleKitReader::ControlType::SpinBox, opt->state);
2530 if (!resolved.isValid())
2531 break;
2532 const auto &metrics = *resolved.metrics;
2533 const int bgW = metrics.bgImplicitSize.width() + metrics.margins.left() + metrics.margins.right();
2534 const int bgH = metrics.bgImplicitSize.height() + metrics.margins.top() + metrics.margins.bottom();
2535 const int contentW = contentsSize.width() + metrics.padding.left() + metrics.padding.right()
2536 + metrics.textPadding.left() + metrics.textPadding.right();
2537 const int contentH = contentsSize.height() + metrics.padding.top() + metrics.padding.bottom()
2538 + metrics.textPadding.top() + metrics.textPadding.bottom();
2539 // TODO: Support vertical layout for spinbox, currently we assume horizontal layout
2540 // TODO: Calculate each indicator (up/down) size separately if they have different sizes in the style
2541 const int indicatorW = (metrics.indicatorImplicitSize.width() + metrics.indicatorMargins.left()
2542 + metrics.indicatorMargins.right()) * 2;
2543 const int indicatorH = metrics.indicatorImplicitSize.height() + metrics.indicatorMargins.top()
2544 + metrics.indicatorMargins.bottom();
2545 return QSize(std::max({contentW + indicatorW + metrics.spacing, bgW}),
2546 std::max({contentH, indicatorH, bgH}));
2547 }
2548#endif // QT_CONFIG(spinbox)
2549 default:
2550 break;
2551 }
2552 return QCommonStyle::sizeFromContents(ct, opt, contentsSize, widget);
2553}
2554
2555/*! \reimp */
2556int QStyleKitStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *widget) const
2557{
2558 // case PM_LayoutBottomMargin:
2559 // case PM_LayoutTopMargin:
2560 // case PM_LayoutLeftMargin:
2561 // case PM_LayoutRightMargin:
2562 // return -100.0;
2563 return QCommonStyle::pixelMetric(m, opt, widget);
2564}
2565
2566/*! \reimp */
2567int QStyleKitStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
2568 QStyleHintReturn *shret) const
2569{
2570 switch (sh) {
2571 case SH_SpinBox_SelectOnStep:
2572 return 0;
2573 default:
2574 break;
2575 }
2576 return QCommonStyle::styleHint(sh, opt, w, shret);
2577}
2578
2579/*! \reimp */
2580QPalette QStyleKitStyle::standardPalette() const
2581{
2582 return QCommonStyle::standardPalette();
2583}
2584
2585/*! \reimp */
2586void QStyleKitStyle::polish(QWidget *widget)
2587{
2588 if (!widget)
2589 return;
2590
2591 Q_D(QStyleKitStyle);
2592 widget->setAttribute(Qt::WA_Hover);
2593
2594 // Create per-widget reader for interactive controls (transitions)
2595 const bool isInteractiveControl = false
2596#if QT_CONFIG(pushbutton)
2597 || qobject_cast<const QPushButton *>(widget)
2598#endif
2599#if QT_CONFIG(checkbox)
2600 || qobject_cast<const QCheckBox *>(widget)
2601#endif
2602#if QT_CONFIG(radiobutton)
2603 || qobject_cast<const QRadioButton *>(widget)
2604#endif
2605#if QT_CONFIG(combobox)
2606 || qobject_cast<const QComboBox *>(widget)
2607 || (widget && widget->inherits("QComboBoxPrivateContainer"))
2608#endif
2609#if QT_CONFIG(lineedit)
2610 || qobject_cast<const QLineEdit *>(widget)
2611#endif
2612#if QT_CONFIG(textedit)
2613 || qobject_cast<const QTextEdit *>(widget)
2614 || qobject_cast<const QPlainTextEdit *>(widget)
2615#endif
2616#if QT_CONFIG(label)
2617 || qobject_cast<const QLabel *>(widget)
2618#endif
2619#if QT_CONFIG(progressbar)
2620 || qobject_cast<const QProgressBar *>(widget)
2621#endif
2622#if QT_CONFIG(slider)
2623 || qobject_cast<const QSlider *>(widget)
2624#endif
2625#if QT_CONFIG(scrollbar)
2626 || qobject_cast<const QScrollBar *>(widget)
2627#endif
2628#if QT_CONFIG(spinbox)
2629 || qobject_cast<const QSpinBox *>(widget)
2630#endif
2631#if QT_CONFIG(tabbar)
2632 || qobject_cast<const QTabBar *>(widget)
2633#endif
2634 ;
2635 if (isInteractiveControl)
2636 d->readerForWidget(widget);
2637
2638#if QT_CONFIG(itemviews)
2639 if (auto *view = qobject_cast<QAbstractItemView *>(widget)) {
2640#if QT_CONFIG(combobox)
2641 if (auto *p = view->parentWidget(); p && p->inherits("QComboBoxPrivateContainer"))
2642 view->viewport()->setAutoFillBackground(false);
2643#endif
2644 }
2645#endif
2646
2647#if QT_CONFIG(lineedit)
2648 if (auto *lineEdit = qobject_cast<QLineEdit *>(widget)) {
2649 if (!lineEdit->property("_q_stylekit_alignment_set").toBool()) {
2650 QQStyleKitReader *r = d->readerForWidget(widget);
2651 if (r) {
2652 const QWidget *target = containerWidget(widget);
2653 QQStyleKitReader::ControlType ct = controlTypeForWidget(target);
2654 r->setControlType(ct);
2655 const auto *textProps = r->global()->text();
2656 if (textProps) {
2657 const uint align = resolvedAlignment(
2658 textProps->alignment(), Qt::AlignLeft, Qt::AlignVCenter);
2659 lineEdit->setAlignment(Qt::Alignment(align));
2660 }
2661 }
2662 }
2663 }
2664#endif
2665
2666 d->setStyleFont(widget);
2667 d->refreshStylePalette(widget);
2668
2669 QCommonStyle::polish(widget);
2670}
2671
2672/*! \reimp */
2673void QStyleKitStyle::polish(QApplication *app)
2674{
2675 QCommonStyle::polish(app);
2676}
2677
2678/*! \reimp */
2679void QStyleKitStyle::polish(QPalette &palette)
2680{
2681 QCommonStyle::polish(palette);
2682}
2683
2684/*! \reimp */
2685void QStyleKitStyle::unpolish(QWidget *widget)
2686{
2687 Q_D(QStyleKitStyle);
2688 d->unsetStylePalette(widget);
2689 d->unsetStyleFont(widget);
2690 d->cleanupWidgetReader(widget);
2691 QCommonStyle::unpolish(widget);
2692}
2693
2694/*! \reimp */
2695void QStyleKitStyle::unpolish(QApplication *app)
2696{
2697 Q_D(QStyleKitStyle);
2698 d->clearMetricsCache();
2699 QCommonStyle::unpolish(app);
2700}
2701
2702/*! \reimp */
2703bool QStyleKitStyle::eventFilter(QObject *obj, QEvent *event)
2704{
2705 Q_D(QStyleKitStyle);
2706 switch (event->type()) {
2707 case QEvent::HoverEnter:
2708 case QEvent::HoverLeave:
2709 case QEvent::FocusIn:
2710 case QEvent::FocusOut:
2711 if (auto *w = qobject_cast<QWidget *>(obj)) {
2712 if (d->customPaletteWidgets.contains(w))
2713 d->refreshStylePalette(w);
2714 }
2715 break;
2716 default:
2717 break;
2718 }
2719 return QCommonStyle::eventFilter(obj, event);
2720}
2721
2722QT_END_NAMESPACE
2723
2724#include "moc_qstylekitstyle.cpp"
Combined button and popup list for selecting options.
static uint resolvedAlignment(uint raw, Qt::Alignment hDefault, Qt::Alignment vDefault)
static QQStyleKitReader::ControlType controlTypeForWidget(const QWidget *widget)
static const QWidget * containerWidget(const QWidget *w)