From 7293200ace12f4870b87bb6a1f5a22ef53bf52cd Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Sun, 28 Jun 2015 21:31:30 +1000 Subject: Add attribute to enable font and palette propagation in QSS. By default when using Qt Style Sheets, a widget does not inherit its font and palette from its parent widget. With the Qt::AA_UseStyleSheetPropagationInWidgetStyles application attribute set, propagation when using Qt Style Sheets behaves like it does with regular QWidget::setPalette() and QWidget::setFont() calls. [ChangeLog][QtWidgets] Added the Qt::AA_UseStyleSheetPropagationInWidgetStyles attribute which enables font and palette propagation for Qt Style Sheets. Task-number: QTBUG-37580 Change-Id: I3038c13d61e32625a1a05291c5394eaefd376a68 Reviewed-by: Samuel Nevala Reviewed-by: Lars Knoll --- .../doc/snippets/code/doc_src_stylesheet.cpp | 4 + .../doc/src/widgets-and-layouts/stylesheet.qdoc | 22 +++- src/widgets/kernel/qwidget.cpp | 33 ++++-- src/widgets/styles/qstylesheetstyle.cpp | 121 +++++++++++++++++---- src/widgets/styles/qstylesheetstyle_p.h | 6 +- 5 files changed, 151 insertions(+), 35 deletions(-) (limited to 'src/widgets') diff --git a/src/widgets/doc/snippets/code/doc_src_stylesheet.cpp b/src/widgets/doc/snippets/code/doc_src_stylesheet.cpp index a937498fe5..01f4c528a2 100644 --- a/src/widgets/doc/snippets/code/doc_src_stylesheet.cpp +++ b/src/widgets/doc/snippets/code/doc_src_stylesheet.cpp @@ -138,3 +138,7 @@ emailEdit->setProperty("mandatoryField", true); QSpinBox *ageSpinBox = new QSpinBox(this); ageSpinBox->setProperty("mandatoryField", true); //! [95] + +//! [96] +qApp->setAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles, true); +//! [97] diff --git a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc index fc3ac345a8..bea1a6e657 100644 --- a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc +++ b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc @@ -492,9 +492,9 @@ \section1 Inheritance In classic CSS, when font and color of an item is not explicitly set, - it gets automatically inherited from the parent. When using Qt Style Sheets, - a widget does \b{not} automatically inherit its font and color setting - from its parent widget. + it gets automatically inherited from the parent. By default, when using + Qt Style Sheets, a widget does \b{not} automatically inherit its font + and color setting from its parent widget. For example, consider a QPushButton inside a QGroupBox: @@ -507,9 +507,23 @@ \snippet code/doc_src_stylesheet.cpp 25 - In contrast, setting a font and propagate using QWidget::setFont() and + In contrast, setting a font and palette using QWidget::setFont() and QWidget::setPalette() propagates to child widgets. + If you would prefer that the font and palette propagate to child widgets, + you can set the Qt::AA_UseStyleSheetPropagationInWidgetStyles flag, like + this: + + Usage: + \snippet code/doc_src_stylesheet.cpp 96 + + When the widget-style font and palette propagation is enabled, font and + palette changes made through Qt Style Sheets will behave as though the + user had manually called the corresponding QWidget::setPalette() and + QWidget::setFont() methods on all of the QWidgets targeted by the style + sheet. If this would have caused propagation in C++, it will cause + propagation in style sheets and visa versa. + \section1 Widgets Inside C++ Namespaces The Type Selector can be used to style widgets of a particular type. For diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 1ebf782edf..66ded4cb5f 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1954,11 +1954,14 @@ void QWidgetPrivate::propagatePaletteChange() } int mask = data.pal.resolve() | inheritedPaletteResolveMask; + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); + QEvent pc(QEvent::PaletteChange); QApplication::sendEvent(q, &pc); for (int i = 0; i < children.size(); ++i) { QWidget *w = qobject_cast(children.at(i)); - if (w && !w->testAttribute(Qt::WA_StyleSheet) + if (w && (!w->testAttribute(Qt::WA_StyleSheet) || useStyleSheetPropagationInWidgetStyles) && (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))) { QWidgetPrivate *wd = w->d_func(); wd->inheritedPaletteResolveMask = mask; @@ -4543,15 +4546,19 @@ void QWidget::setPalette(const QPalette &palette) QPalette QWidgetPrivate::naturalWidgetPalette(uint inheritedMask) const { Q_Q(const QWidget); + + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); + QPalette naturalPalette = QApplication::palette(q); - if (!q->testAttribute(Qt::WA_StyleSheet) + if ((!q->testAttribute(Qt::WA_StyleSheet) || useStyleSheetPropagationInWidgetStyles) && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) #ifndef QT_NO_GRAPHICSVIEW || (extra && extra->proxyWidget) #endif //QT_NO_GRAPHICSVIEW )) { if (QWidget *p = q->parentWidget()) { - if (!p->testAttribute(Qt::WA_StyleSheet)) { + if (!p->testAttribute(Qt::WA_StyleSheet) || useStyleSheetPropagationInWidgetStyles) { if (!naturalPalette.isCopyOf(QApplication::palette())) { QPalette inheritedPalette = p->palette(); inheritedPalette.resolve(inheritedMask); @@ -4687,15 +4694,19 @@ void QWidget::setFont(const QFont &font) QFont QWidgetPrivate::naturalWidgetFont(uint inheritedMask) const { Q_Q(const QWidget); + + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); + QFont naturalFont = QApplication::font(q); - if (!q->testAttribute(Qt::WA_StyleSheet) + if ((!q->testAttribute(Qt::WA_StyleSheet) || useStyleSheetPropagationInWidgetStyles) && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) #ifndef QT_NO_GRAPHICSVIEW || (extra && extra->proxyWidget) #endif //QT_NO_GRAPHICSVIEW )) { if (QWidget *p = q->parentWidget()) { - if (!p->testAttribute(Qt::WA_StyleSheet)) { + if (!p->testAttribute(Qt::WA_StyleSheet) || useStyleSheetPropagationInWidgetStyles) { if (!naturalFont.isCopyOf(QApplication::font())) { QFont inheritedFont = p->font(); inheritedFont.resolve(inheritedMask); @@ -4747,6 +4758,8 @@ void QWidgetPrivate::updateFont(const QFont &font) #ifndef QT_NO_STYLE_STYLESHEET const QStyleSheetStyle* cssStyle; cssStyle = extra ? qobject_cast(extra->style) : 0; + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); #endif data.fnt = QFont(font, q); @@ -4771,7 +4784,7 @@ void QWidgetPrivate::updateFont(const QFont &font) if (w) { if (0) { #ifndef QT_NO_STYLE_STYLESHEET - } else if (w->testAttribute(Qt::WA_StyleSheet)) { + } else if (!useStyleSheetPropagationInWidgetStyles && w->testAttribute(Qt::WA_StyleSheet)) { // Style sheets follow a different font propagation scheme. if (cssStyle) cssStyle->updateStyleSheetFont(w); @@ -4786,7 +4799,7 @@ void QWidgetPrivate::updateFont(const QFont &font) } #ifndef QT_NO_STYLE_STYLESHEET - if (cssStyle) { + if (!useStyleSheetPropagationInWidgetStyles && cssStyle) { cssStyle->updateStyleSheetFont(q); } #endif @@ -10442,7 +10455,11 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) d->reparentFocusWidgets(oldtlw); setAttribute(Qt::WA_Resized, resized); - if (!testAttribute(Qt::WA_StyleSheet) + + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); + + if (!useStyleSheetPropagationInWidgetStyles && !testAttribute(Qt::WA_StyleSheet) && (!parent || !parent->testAttribute(Qt::WA_StyleSheet))) { d->resolveFont(); d->resolvePalette(); diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 380b2b3939..c9440efc8c 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -2556,7 +2556,13 @@ void QStyleSheetStyle::setPalette(QWidget *w) { PseudoClass_Enabled, QPalette::Inactive } }; - QPalette p = w->palette(); + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); + + QPalette p; + if (!useStyleSheetPropagationInWidgetStyles) + p = w->palette(); + QWidget *ew = embeddedWidget(w); for (int i = 0; i < 3; i++) { @@ -2573,32 +2579,84 @@ void QStyleSheetStyle::setPalette(QWidget *w) rule.configurePalette(&p, map[i].group, ew, ew != w); } - styleSheetCaches->customPaletteWidgets.insert(w, w->palette()); - w->setPalette(p); - if (ew != w) - ew->setPalette(p); + if (!useStyleSheetPropagationInWidgetStyles || p.resolve() != 0) { + QPalette wp = w->palette(); + styleSheetCaches->customPaletteWidgets.insert(w, qMakePair(wp, p.resolve())); + + if (useStyleSheetPropagationInWidgetStyles) { + p = p.resolve(wp); + p.resolve(p.resolve() | wp.resolve()); + } + + w->setPalette(p); + if (ew != w) + ew->setPalette(p); + } } void QStyleSheetStyle::unsetPalette(QWidget *w) { + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); + if (styleSheetCaches->customPaletteWidgets.contains(w)) { - QPalette p = styleSheetCaches->customPaletteWidgets.value(w); - w->setPalette(p); + QPair p = styleSheetCaches->customPaletteWidgets.value(w); + styleSheetCaches->customPaletteWidgets.remove(w); + + QPalette original = p.first; + + if (useStyleSheetPropagationInWidgetStyles) { + original.resolve(original.resolve() & p.second); + + QPalette wp = w->palette(); + wp.resolve(wp.resolve() & ~p.second); + wp.resolve(original); + wp.resolve(wp.resolve() | original.resolve()); + original = wp; + } + + w->setPalette(original); QWidget *ew = embeddedWidget(w); if (ew != w) - ew->setPalette(p); - styleSheetCaches->customPaletteWidgets.remove(w); + ew->setPalette(original); } - QVariant oldFont = w->property("_q_styleSheetWidgetFont"); - if (oldFont.isValid()) { - w->setFont(qvariant_cast(oldFont)); + + if (useStyleSheetPropagationInWidgetStyles) { + unsetStyleSheetFont(w); + QWidget *ew = embeddedWidget(w); + if (ew != w) + unsetStyleSheetFont(ew); + } else { + QVariant oldFont = w->property("_q_styleSheetWidgetFont"); + if (oldFont.isValid()) { + w->setFont(qvariant_cast(oldFont)); + } } + if (styleSheetCaches->autoFillDisabledWidgets.contains(w)) { embeddedWidget(w)->setAutoFillBackground(true); styleSheetCaches->autoFillDisabledWidgets.remove(w); } } +void QStyleSheetStyle::unsetStyleSheetFont(QWidget *w) const +{ + if (styleSheetCaches->customFontWidgets.contains(w)) { + QPair f = styleSheetCaches->customFontWidgets.value(w); + styleSheetCaches->customFontWidgets.remove(w); + + QFont original = f.first; + original.resolve(original.resolve() & f.second); + + QFont font = w->font(); + font.resolve(font.resolve() & ~f.second); + font.resolve(original); + font.resolve(font.resolve() | original.resolve()); + + w->setFont(font); + } +} + static void updateObjects(const QList& objects) { if (!styleSheetCaches->styleRulesCache.isEmpty() || !styleSheetCaches->hasStyleRuleCache.isEmpty() || !styleSheetCaches->renderRulesCache.isEmpty()) { @@ -2658,6 +2716,7 @@ void QStyleSheetStyleCaches::objectDestroyed(QObject *o) hasStyleRuleCache.remove(o); renderRulesCache.remove(o); customPaletteWidgets.remove((const QWidget *)o); + customFontWidgets.remove(static_cast(o)); styleSheetCache.remove(o); autoFillDisabledWidgets.remove((const QWidget *)o); } @@ -5846,24 +5905,42 @@ void QStyleSheetStyle::updateStyleSheetFont(QWidget* w) const // we should never override it. if (w->objectName() == QLatin1String("qt_fontDialog_sampleEdit")) return; + QWidget *container = containerWidget(w); QRenderRule rule = renderRule(container, PseudoElement_None, PseudoClass_Active | PseudoClass_Enabled | extendedPseudoClass(container)); - QFont font = rule.font.resolve(w->font()); - if ((!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation)) - && isNaturalChild(w) && qobject_cast(w->parent())) { + const bool useStyleSheetPropagationInWidgetStyles = + QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles); - font = font.resolve(static_cast(w->parent())->font()); - } + if (useStyleSheetPropagationInWidgetStyles) { + unsetStyleSheetFont(w); - if (w->data->fnt == font) - return; + if (rule.font.resolve()) { + QFont wf = w->font(); + styleSheetCaches->customFontWidgets.insert(w, qMakePair(wf, rule.font.resolve())); + + QFont font = rule.font.resolve(wf); + font.resolve(wf.resolve() | rule.font.resolve()); + w->setFont(font); + } + } else { + QFont font = rule.font.resolve(w->font()); - w->data->fnt = font; + if ((!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation)) + && isNaturalChild(w) && qobject_cast(w->parent())) { - QEvent e(QEvent::FontChange); - QApplication::sendEvent(w, &e); + font = font.resolve(static_cast(w->parent())->font()); + } + + if (w->data->fnt == font) + return; + + w->data->fnt = font; + + QEvent e(QEvent::FontChange); + QApplication::sendEvent(w, &e); + } } void QStyleSheetStyle::saveWidgetFont(QWidget* w, const QFont& font) const diff --git a/src/widgets/styles/qstylesheetstyle_p.h b/src/widgets/styles/qstylesheetstyle_p.h index 9cd8cb889d..f622f7f419 100644 --- a/src/widgets/styles/qstylesheetstyle_p.h +++ b/src/widgets/styles/qstylesheetstyle_p.h @@ -149,6 +149,7 @@ private: void unsetPalette(QWidget *); void setProperties(QWidget *); void setGeometry(QWidget *); + void unsetStyleSheetFont(QWidget *) const; QVector styleRules(const QObject *obj) const; bool hasStyleRule(const QObject *obj, int part) const; @@ -178,9 +179,12 @@ public: QHash > hasStyleRuleCache; typedef QHash > QRenderRules; QHash renderRulesCache; - QHash customPaletteWidgets; // widgets whose palette we tampered QHash styleSheetCache; // parsed style sheets QSet autoFillDisabledWidgets; + // widgets whose palettes and fonts we have tampered. stored value pair is + // QPair + QHash > customPaletteWidgets; + QHash > customFontWidgets; }; -- cgit v1.2.3