annotate style/AppEventFilter.cpp @ 668:dac3781826da thorn-cpp

Experimental branch based on Thorn C++ code from RG
author Chris Cannam
date Tue, 30 Apr 2019 11:36:38 +0100
parents
children
rev   line source
Chris@668 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@668 2
Chris@668 3 /*
Chris@668 4 Vect
Chris@668 5 An experimental audio player for plural recordings of a work
Chris@668 6 Centre for Digital Music, Queen Mary, University of London.
Chris@668 7
Chris@668 8 This file is taken from Rosegarden, a MIDI and audio sequencer and
Chris@668 9 musical notation editor. Copyright 2000-2018 the Rosegarden
Chris@668 10 development team. Thorn style developed in stylesheet form by
Chris@668 11 D. Michael McIntyre and reimplemented as a class by David Faure.
Chris@668 12
Chris@668 13 This program is free software; you can redistribute it and/or
Chris@668 14 modify it under the terms of the GNU General Public License as
Chris@668 15 published by the Free Software Foundation; either version 2 of the
Chris@668 16 License, or (at your option) any later version. See the file
Chris@668 17 COPYING included with this distribution for more information.
Chris@668 18 */
Chris@668 19
Chris@668 20 #include "ThornStyle.h"
Chris@668 21 #include "AppEventFilter.h"
Chris@668 22
Chris@668 23 #include <QApplication>
Chris@668 24 #include <QFileDialog>
Chris@668 25 #include <QAbstractItemView>
Chris@668 26 #include <QCheckBox>
Chris@668 27 #include <QLabel>
Chris@668 28 #include <QRadioButton>
Chris@668 29 #include <QToolBar>
Chris@668 30 #include <QWidget>
Chris@668 31 #include <QDialogButtonBox>
Chris@668 32 #include <QPushButton>
Chris@668 33 #include <QComboBox>
Chris@668 34 #include <QSpinBox>
Chris@668 35
Chris@668 36 // Apply the style to widget and its children, recursively
Chris@668 37 // Even though every widget goes through the event filter, this is needed
Chris@668 38 // for the case where a whole widget hierarchy is suddenly reparented into the file dialog.
Chris@668 39 // Then we need to apply the app style again. Testcase: scrollbars in file dialog.
Chris@668 40 static void applyStyleRecursive(QWidget* widget, QStyle *style)
Chris@668 41 {
Chris@668 42 if (widget->style() != style) {
Chris@668 43 widget->setStyle(style);
Chris@668 44 }
Chris@668 45 foreach (QObject* obj, widget->children()) {
Chris@668 46 if (obj->isWidgetType()) {
Chris@668 47 QWidget *w = static_cast<QWidget *>(obj);
Chris@668 48 applyStyleRecursive(w, style);
Chris@668 49 }
Chris@668 50 }
Chris@668 51 }
Chris@668 52
Chris@668 53 AppEventFilter::AppEventFilter() :
Chris@668 54 m_systemPalette(qApp->palette()),
Chris@668 55 m_systemStyle(qApp->style()) {
Chris@668 56 }
Chris@668 57
Chris@668 58 bool
Chris@668 59 AppEventFilter::shouldIgnoreThornStyle(QWidget *widget) const {
Chris@668 60 return qobject_cast<QFileDialog *>(widget)
Chris@668 61 || widget->inherits("KDEPlatformFileDialog")
Chris@668 62 || widget->inherits("KDirSelectDialog");
Chris@668 63 }
Chris@668 64
Chris@668 65 // when we ditch Qt4, we can switch to qCDebug...
Chris@668 66 //#define DEBUG_EVENTFILTER
Chris@668 67
Chris@668 68 bool AppEventFilter::eventFilter(QObject *watched, QEvent *event)
Chris@668 69 {
Chris@668 70 static bool s_insidePolish = false; // setStyle calls polish again, so skip doing the work twice
Chris@668 71 if (!s_insidePolish && watched->isWidgetType() && event->type() == QEvent::Polish) {
Chris@668 72 s_insidePolish = true;
Chris@668 73 // This is called after every widget is created and just before being shown
Chris@668 74 // (we use this so that it has a proper parent widget already)
Chris@668 75 QWidget *widget = static_cast<QWidget *>(watched);
Chris@668 76 if (shouldIgnoreThornStyle(widget)) {
Chris@668 77 // The palette from the mainwindow propagated to the dialog, restore it.
Chris@668 78 widget->setPalette(m_systemPalette);
Chris@668 79 #ifdef DEBUG_EVENTFILTER
Chris@668 80 qDebug() << widget << "now using app style (recursive)";
Chris@668 81 #endif
Chris@668 82 applyStyleRecursive(widget, qApp->style());
Chris@668 83 s_insidePolish = false;
Chris@668 84 return false;
Chris@668 85 }
Chris@668 86 QWidget *toplevel = widget->window();
Chris@668 87 #ifdef DEBUG_EVENTFILTER
Chris@668 88 qDebug() << widget << "current widget style=" << widget->style() << "shouldignore=" << shouldIgnoreThornStyle(toplevel);
Chris@668 89 #endif
Chris@668 90 if (shouldIgnoreThornStyle(toplevel)) {
Chris@668 91 // Here we should apply qApp->style() recursively on widget and its children, in case one was reparented
Chris@668 92 #ifdef DEBUG_EVENTFILTER
Chris@668 93 qDebug() << widget << widget->objectName() << "in" << toplevel << "now using app style (recursive)";
Chris@668 94 #endif
Chris@668 95 applyStyleRecursive(widget, qApp->style());
Chris@668 96 } else if (widget->style() != &m_style) {
Chris@668 97 #ifdef DEBUG_EVENTFILTER
Chris@668 98 //qDebug() << " ToolTipBase=" << widget->palette().color(QPalette::ToolTipBase).name();
Chris@668 99 #endif
Chris@668 100 // Apply style recursively because some child widgets (e.g. QHeaderView in QTreeWidget, in DeviceManagerDialog) don't seem to get here.
Chris@668 101 if (qobject_cast<QAbstractItemView *>(widget)) {
Chris@668 102 applyStyleRecursive(widget, &m_style);
Chris@668 103 } else {
Chris@668 104 widget->setStyle(&m_style);
Chris@668 105 }
Chris@668 106 #ifdef DEBUG_EVENTFILTER
Chris@668 107 qDebug() << " now using style" << widget->style();
Chris@668 108 #endif
Chris@668 109 if (widget->windowType() != Qt::Widget) { // window, tooltip, ...
Chris@668 110 widget->setPalette(m_style.standardPalette());
Chris@668 111 #ifdef DEBUG_EVENTFILTER
Chris@668 112 qDebug() << " after setPalette: ToolTipBase=" << widget->palette().color(QPalette::ToolTipBase).name();
Chris@668 113 #endif
Chris@668 114 } else {
Chris@668 115 #ifdef DEBUG_EVENTFILTER
Chris@668 116 //qDebug() << " not a toplevel. ToolTipBase=" << widget->palette().color(QPalette::ToolTipBase).name();
Chris@668 117 #endif
Chris@668 118 }
Chris@668 119 polishWidget(widget);
Chris@668 120 }
Chris@668 121 s_insidePolish = false;
Chris@668 122 }
Chris@668 123 return false; // don't eat the event
Chris@668 124 }
Chris@668 125
Chris@668 126 void AppEventFilter::polishWidget(QWidget *widget)
Chris@668 127 {
Chris@668 128 if (QLabel *label = qobject_cast<QLabel *>(widget)) {
Chris@668 129 if (qobject_cast<QToolBar *>(widget->parentWidget())) {
Chris@668 130 /* Toolbars must be light enough for black icons, therefore black text on their
Chris@668 131 QLabels, rather than white, is more appropriate.
Chris@668 132 QToolBar QLabel { color: #000000; } */
Chris@668 133 QPalette pal = label->palette();
Chris@668 134 pal.setColor(label->foregroundRole(), Qt::black);
Chris@668 135 label->setPalette(pal);
Chris@668 136 //qDebug() << "made label black:" << label << label->text();
Chris@668 137 }
Chris@668 138 if (widget->objectName() == "SPECIAL_LABEL") {
Chris@668 139 widget->setAutoFillBackground(true);
Chris@668 140 // QWidget#SPECIAL_LABEL { color: #000000; background-color: #999999; }
Chris@668 141 QPalette palette = widget->palette();
Chris@668 142 palette.setColor(QPalette::WindowText, Qt::black);
Chris@668 143 palette.setColor(QPalette::Window, QColor(0x99, 0x99, 0x99));
Chris@668 144 widget->setPalette(palette);
Chris@668 145 }
Chris@668 146 } else if (widget->objectName() == "Rosegarden Transport") {
Chris@668 147 // Give the non-LED parts of the dialog the groupbox "lighter black"
Chris@668 148 // background for improved contrast.
Chris@668 149 QPalette transportPalette = widget->palette();
Chris@668 150 transportPalette.setColor(widget->backgroundRole(), QColor(0x40, 0x40, 0x40));
Chris@668 151 widget->setPalette(transportPalette);
Chris@668 152 widget->setAutoFillBackground(true);
Chris@668 153 } else if (QCheckBox *cb = qobject_cast<QCheckBox *>(widget)) {
Chris@668 154 cb->setAttribute(Qt::WA_Hover);
Chris@668 155 } else if (QRadioButton *rb = qobject_cast<QRadioButton *>(widget)) {
Chris@668 156 rb->setAttribute(Qt::WA_Hover);
Chris@668 157 } else if (QPushButton *pb = qobject_cast<QPushButton *>(widget)) {
Chris@668 158 pb->setAttribute(Qt::WA_Hover);
Chris@668 159 if (qobject_cast<QDialogButtonBox *>(widget->parentWidget())) {
Chris@668 160 // Bug in QDialogButtonBox: if the app style sets QStyle::SH_DialogButtonBox_ButtonsHaveIcons
Chris@668 161 // a later call to setStyle() doesn't remove the button icon again.
Chris@668 162 // Fix submitted at https://codereview.qt-project.org/183788
Chris@668 163 pb->setIcon(QIcon());
Chris@668 164 }
Chris@668 165 } else if (QComboBox *cb = qobject_cast<QComboBox *>(widget)) {
Chris@668 166 cb->setAttribute(Qt::WA_Hover);
Chris@668 167 } else if (QAbstractSpinBox *sb = qobject_cast<QAbstractSpinBox *>(widget)) {
Chris@668 168 sb->setAttribute(Qt::WA_Hover);
Chris@668 169 }
Chris@668 170 }