6221aa07d8f1f6363737fd2e8357e42fa8e1047a
[profile/ivi/qtbase.git] / src / plugins / platforms / windows / qwindowstheme.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwindowstheme.h"
43 #include "qwindowsdialoghelpers.h"
44 #include "qwindowscontext.h"
45 #include "qwindowsintegration.h"
46 #include "qt_windows.h"
47 #include "qwindowsfontdatabase.h"
48 #ifdef Q_OS_WINCE
49 #  include "qplatformfunctions_wince.h"
50 #  include "winuser.h"
51 #endif
52
53 #include <QtCore/QVariant>
54 #include <QtCore/QCoreApplication>
55 #include <QtCore/QDebug>
56 #include <QtCore/QTextStream>
57 #include <QtCore/QSysInfo>
58 #include <QtGui/QPalette>
59 #include <QtGui/QGuiApplication>
60 #include <QtGui/qwindowsysteminterface.h>
61
62 QT_BEGIN_NAMESPACE
63
64 static inline QTextStream& operator<<(QTextStream &str, const QColor &c)
65 {
66     str.setIntegerBase(16);
67     str.setFieldWidth(2);
68     str.setPadChar(QLatin1Char('0'));
69     str << " rgb: #" << c.red()  << c.green() << c.blue();
70     str.setIntegerBase(10);
71     str.setFieldWidth(0);
72     return str;
73 }
74
75 static inline void paletteRoleToString(const QPalette &palette,
76                                        const QPalette::ColorRole role,
77                                        QTextStream &str)
78 {
79     str << "Role: ";
80     str.setFieldWidth(2);
81     str.setPadChar(QLatin1Char('0'));
82     str << role;
83     str.setFieldWidth(0);
84     str << " Active: "  << palette.color(QPalette::Active, role)
85         << " Disabled: "  << palette.color(QPalette::Disabled, role)
86         << " Inactive: " << palette.color(QPalette::Inactive, role)
87         << '\n';
88 }
89
90 static inline QString paletteToString(const QPalette &palette)
91 {
92     QString result;
93     QTextStream str(&result);
94     for (int r = 0; r < QPalette::NColorRoles; ++r)
95         paletteRoleToString(palette, static_cast<QPalette::ColorRole>(r), str);
96     return result;
97 }
98
99 static inline bool booleanSystemParametersInfo(UINT what, bool defaultValue)
100 {
101     BOOL result;
102     if (SystemParametersInfo(what, 0, &result, 0))
103         return result ? true : false;
104     return defaultValue;
105 }
106
107 static inline bool dWordSystemParametersInfo(UINT what, DWORD defaultValue)
108 {
109     DWORD result;
110     if (SystemParametersInfo(what, 0, &result, 0))
111         return result;
112     return defaultValue;
113 }
114
115 static inline QColor mixColors(const QColor &c1, const QColor &c2)
116 {
117     return QColor ((c1.red() + c2.red()) / 2,
118                    (c1.green() + c2.green()) / 2,
119                    (c1.blue() + c2.blue()) / 2);
120 }
121
122 static inline QColor getSysColor(int index)
123 {
124     return qColorToCOLORREF(GetSysColor(index));
125 }
126
127 // from QStyle::standardPalette
128 static inline QPalette standardPalette()
129 {
130     QColor backgroundColor(0xd4, 0xd0, 0xc8); // win 2000 grey
131     QColor lightColor(backgroundColor.lighter());
132     QColor darkColor(backgroundColor.darker());
133     const QBrush darkBrush(darkColor);
134     QColor midColor(Qt::gray);
135     QPalette palette(Qt::black, backgroundColor, lightColor, darkColor,
136                      midColor, Qt::black, Qt::white);
137     palette.setBrush(QPalette::Disabled, QPalette::WindowText, darkBrush);
138     palette.setBrush(QPalette::Disabled, QPalette::Text, darkBrush);
139     palette.setBrush(QPalette::Disabled, QPalette::ButtonText, darkBrush);
140     palette.setBrush(QPalette::Disabled, QPalette::Base, QBrush(backgroundColor));
141     return palette;
142 }
143
144 static inline QPalette systemPalette()
145 {
146     QPalette result = standardPalette();
147     result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
148     result.setColor(QPalette::Button, getSysColor(COLOR_BTNFACE));
149     result.setColor(QPalette::Light, getSysColor(COLOR_BTNHIGHLIGHT));
150     result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW));
151     result.setColor(QPalette::Mid, result.button().color().darker(150));
152     result.setColor(QPalette::Text, getSysColor(COLOR_WINDOWTEXT));
153     result.setColor(QPalette::BrightText, getSysColor(COLOR_BTNHIGHLIGHT));
154     result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW));
155     result.setColor(QPalette::Window, getSysColor(COLOR_BTNFACE));
156     result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT));
157     result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
158     result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
159     result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT));
160     result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT));
161     result.setColor(QPalette::Link, Qt::blue);
162     result.setColor(QPalette::LinkVisited, Qt::magenta);
163     result.setColor(QPalette::Inactive, QPalette::Button, result.button().color());
164     result.setColor(QPalette::Inactive, QPalette::Window, result.background().color());
165     result.setColor(QPalette::Inactive, QPalette::Light, result.light().color());
166     result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color());
167
168     if (result.midlight() == result.button())
169         result.setColor(QPalette::Midlight, result.button().color().lighter(110));
170     if (result.background() != result.base()) {
171         result.setColor(QPalette::Inactive, QPalette::Highlight, result.color(QPalette::Inactive, QPalette::Window));
172         result.setColor(QPalette::Inactive, QPalette::HighlightedText, result.color(QPalette::Inactive, QPalette::Text));
173     }
174
175     const QColor disabled =
176         mixColors(result.foreground().color(), result.button().color());
177
178     result.setColorGroup(QPalette::Disabled, result.foreground(), result.button(),
179                          result.light(), result.dark(), result.mid(),
180                          result.text(), result.brightText(), result.base(),
181                          result.background());
182     result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
183     result.setColor(QPalette::Disabled, QPalette::Text, disabled);
184     result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
185     result.setColor(QPalette::Disabled, QPalette::Highlight,
186                     getSysColor(COLOR_HIGHLIGHT));
187     result.setColor(QPalette::Disabled, QPalette::HighlightedText,
188                     getSysColor(COLOR_HIGHLIGHTTEXT));
189     result.setColor(QPalette::Disabled, QPalette::Base,
190                     result.background().color());
191     return result;
192 }
193
194 static inline QPalette toolTipPalette(const QPalette &systemPalette)
195 {
196     QPalette result(systemPalette);
197     const QColor tipBgColor(getSysColor(COLOR_INFOBK));
198     const QColor tipTextColor(getSysColor(COLOR_INFOTEXT));
199
200     result.setColor(QPalette::All, QPalette::Button, tipBgColor);
201     result.setColor(QPalette::All, QPalette::Window, tipBgColor);
202     result.setColor(QPalette::All, QPalette::Text, tipTextColor);
203     result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
204     result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
205     result.setColor(QPalette::All, QPalette::Button, tipBgColor);
206     result.setColor(QPalette::All, QPalette::Window, tipBgColor);
207     result.setColor(QPalette::All, QPalette::Text, tipTextColor);
208     result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
209     result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
210     const QColor disabled =
211         mixColors(result.foreground().color(), result.button().color());
212     result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
213     result.setColor(QPalette::Disabled, QPalette::Text, disabled);
214     result.setColor(QPalette::Disabled, QPalette::Base, Qt::white);
215     result.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white);
216     return result;
217 }
218
219 static inline QPalette menuPalette(const QPalette &systemPalette)
220 {
221     QPalette result(systemPalette);
222     const QColor menuColor(getSysColor(COLOR_MENU));
223     const QColor menuTextColor(getSysColor(COLOR_MENUTEXT));
224     const QColor disabled(getSysColor(COLOR_GRAYTEXT));
225     const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false);
226     // we might need a special color group for the result.
227     result.setColor(QPalette::Active, QPalette::Button, menuColor);
228     result.setColor(QPalette::Active, QPalette::Text, menuTextColor);
229     result.setColor(QPalette::Active, QPalette::WindowText, menuTextColor);
230     result.setColor(QPalette::Active, QPalette::ButtonText, menuTextColor);
231     result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
232     result.setColor(QPalette::Disabled, QPalette::Text, disabled);
233 #ifndef Q_OS_WINCE
234     result.setColor(QPalette::Disabled, QPalette::Highlight,
235                     getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT));
236 #else
237     result.setColor(QPalette::Disabled, QPalette::Highlight,
238                     getSysColor(COLOR_HIGHLIGHT));
239 #endif
240     result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
241     result.setColor(QPalette::Disabled, QPalette::Button,
242                     result.color(QPalette::Active, QPalette::Button));
243     result.setColor(QPalette::Inactive, QPalette::Button,
244                     result.color(QPalette::Active, QPalette::Button));
245     result.setColor(QPalette::Inactive, QPalette::Text,
246                     result.color(QPalette::Active, QPalette::Text));
247     result.setColor(QPalette::Inactive, QPalette::WindowText,
248                     result.color(QPalette::Active, QPalette::WindowText));
249     result.setColor(QPalette::Inactive, QPalette::ButtonText,
250                     result.color(QPalette::Active, QPalette::ButtonText));
251     result.setColor(QPalette::Inactive, QPalette::Highlight,
252                     result.color(QPalette::Active, QPalette::Highlight));
253     result.setColor(QPalette::Inactive, QPalette::HighlightedText,
254                     result.color(QPalette::Active, QPalette::HighlightedText));
255     result.setColor(QPalette::Inactive, QPalette::ButtonText,
256                     systemPalette.color(QPalette::Inactive, QPalette::Dark));
257     return result;
258 }
259
260 static inline QPalette *menuBarPalette(const QPalette &menuPalette)
261 {
262     QPalette *result = 0;
263     if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) {
264         result = new QPalette(menuPalette);
265 #ifndef Q_OS_WINCE
266         const QColor menubar(getSysColor(COLOR_MENUBAR));
267 #else
268         const QColor menubar(getSysColor(COLOR_MENU));
269 #endif
270         result->setColor(QPalette::Active, QPalette::Button, menubar);
271         result->setColor(QPalette::Disabled, QPalette::Button, menubar);
272         result->setColor(QPalette::Inactive, QPalette::Button, menubar);
273     }
274     return result;
275 }
276
277 const char *QWindowsTheme::name = "windows";
278 QWindowsTheme *QWindowsTheme::m_instance = 0;
279
280 QWindowsTheme::QWindowsTheme()
281 {
282     m_instance = this;
283     qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0));
284     qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0));
285     refresh();
286 }
287
288 QWindowsTheme::~QWindowsTheme()
289 {
290     clearPalettes();
291     clearFonts();
292     m_instance = 0;
293 }
294
295 static inline QStringList iconThemeSearchPaths()
296 {
297     const QFileInfo appDir(QCoreApplication::applicationDirPath() + QStringLiteral("/icons"));
298     return appDir.isDir() ? QStringList(appDir.absoluteFilePath()) : QStringList();
299 }
300
301 static inline QStringList styleNames()
302 {
303     QStringList result;
304     if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
305         result.append(QStringLiteral("WindowsVista"));
306     if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP)
307         result.append(QStringLiteral("WindowsXP"));
308     result.append(QStringLiteral("Windows"));
309     return result;
310 }
311
312 static inline int uiEffects()
313 {
314     int result = 0;
315     if (booleanSystemParametersInfo(SPI_GETUIEFFECTS, false))
316         result |= QPlatformTheme::GeneralUiEffect;
317     if (booleanSystemParametersInfo(SPI_GETMENUANIMATION, false))
318         result |= QPlatformTheme::AnimateMenuUiEffect;
319     if (booleanSystemParametersInfo(SPI_GETMENUFADE, false))
320         result |= QPlatformTheme::FadeMenuUiEffect;
321     if (booleanSystemParametersInfo(SPI_GETCOMBOBOXANIMATION, false))
322         result |= QPlatformTheme::AnimateComboUiEffect;
323     if (booleanSystemParametersInfo(SPI_GETTOOLTIPANIMATION, false))
324         result |= QPlatformTheme::AnimateTooltipUiEffect;
325     return result;
326 }
327
328 QVariant QWindowsTheme::themeHint(ThemeHint hint) const
329 {
330     switch (hint) {
331     case UseFullScreenForPopupMenu:
332         return QVariant(true);
333     case DialogButtonBoxLayout:
334         return QVariant(int(0)); // QDialogButtonBox::WinLayout
335     case IconThemeSearchPaths:
336         return QVariant(iconThemeSearchPaths());
337     case StyleNames:
338         return QVariant(styleNames());
339 #ifndef Q_OS_WINCE
340     case TextCursorWidth:
341         return QVariant(int(dWordSystemParametersInfo(SPI_GETCARETWIDTH, 1u)));
342     case DropShadow:
343         return QVariant(booleanSystemParametersInfo(SPI_GETDROPSHADOW, false));
344 #endif // !Q_OS_WINCE
345     case MaximumScrollBarDragDistance:
346         return QVariant(qRound(qreal(QWindowsContext::instance()->defaultDPI()) * 1.375));
347     case KeyboardScheme:
348         return QVariant(int(WindowsKeyboardScheme));
349     case UiEffects:
350         return QVariant(uiEffects());
351     default:
352         break;
353     }
354     return QPlatformTheme::themeHint(hint);
355 }
356
357 void QWindowsTheme::clearPalettes()
358 {
359     qDeleteAll(m_palettes, m_palettes + NPalettes);
360     qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0));
361 }
362
363 void QWindowsTheme::refreshPalettes()
364 {
365
366     if (!QGuiApplication::desktopSettingsAware())
367         return;
368     m_palettes[SystemPalette] = new QPalette(systemPalette());
369     m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette]));
370     m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette]));
371     m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette]);
372     if (QWindowsContext::verboseTheming)
373         qDebug() << __FUNCTION__ << '\n'
374                  << "  system=" << paletteToString(*m_palettes[SystemPalette])
375                  << "  tooltip=" << paletteToString(*m_palettes[ToolTipPalette]);
376 }
377
378 void QWindowsTheme::clearFonts()
379 {
380     qDeleteAll(m_fonts, m_fonts + NFonts);
381     qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0));
382 }
383
384 void QWindowsTheme::refreshFonts()
385 {
386 #ifndef Q_OS_WINCE // ALL THIS FUNCTIONALITY IS MISSING ON WINCE
387     clearFonts();
388     if (!QGuiApplication::desktopSettingsAware())
389         return;
390     NONCLIENTMETRICS ncm;
391     ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
392     SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
393
394     const QFont menuFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMenuFont);
395     const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
396     const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont);
397     const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont);
398
399     LOGFONT lfIconTitleFont;
400     SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0);
401     const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont);
402
403     m_fonts[SystemFont] = new QFont(QWindowsFontDatabase::systemDefaultFont());
404     m_fonts[MenuFont] = new QFont(menuFont);
405     m_fonts[MenuBarFont] = new QFont(menuFont);
406     m_fonts[MessageBoxFont] = new QFont(messageBoxFont);
407     m_fonts[TipLabelFont] = new QFont(statusFont);
408     m_fonts[StatusBarFont] = new QFont(statusFont);
409     m_fonts[MdiSubWindowTitleFont] = new QFont(titleFont);
410     m_fonts[DockWidgetTitleFont] = new QFont(titleFont);
411     m_fonts[ItemViewFont] = new QFont(iconTitleFont);
412
413     if (QWindowsContext::verboseTheming)
414         qDebug() << __FUNCTION__ << '\n'
415                  << "  menuFont=" << menuFont
416                  << "  messageBox=" << MessageBoxFont;
417 #endif // !Q_OS_WINCE
418 }
419
420 bool QWindowsTheme::usePlatformNativeDialog(DialogType type) const
421 {
422     return QWindowsDialogs::useHelper(type);
423 }
424
425 QPlatformDialogHelper *QWindowsTheme::createPlatformDialogHelper(DialogType type) const
426 {
427     return QWindowsDialogs::createHelper(type);
428 }
429
430 void QWindowsTheme::windowsThemeChanged(QWindow * window)
431 {
432     refresh();
433     QWindowSystemInterface::handleThemeChange(window);
434 }
435
436 QT_END_NAMESPACE