1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #ifndef QWINDOWSXPSTYLE_P_P_H
41 #define QWINDOWSXPSTYLE_P_P_H
42
43 //
44 // W A R N I N G
45 // -------------
46 //
47 // This file is not part of the Qt API. It exists for the convenience
48 // of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
49 // file may change from version to version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53
54 #include <QtWidgets/private/qtwidgetsglobal_p.h>
55 #include "qwindowsxpstyle_p.h"
56 #include <QtWidgets/private/qwindowsstyle_p_p.h>
57 #include <qmap.h>
58 #include <qt_windows.h>
59
60 #include <uxtheme.h>
61 #include <vssym32.h>
62
63 #include <limits.h>
64
65 QT_BEGIN_NAMESPACE
66
67 class QDebug;
68
69 // TMT_TEXTSHADOWCOLOR is wrongly defined in mingw
70 #if TMT_TEXTSHADOWCOLOR != 3818
71 #undef TMT_TEXTSHADOWCOLOR
72 #define TMT_TEXTSHADOWCOLOR 3818
73 #endif
74 #ifndef TST_NONE
75 # define TST_NONE 0
76 #endif
77
78 // These defines are missing from the tmschema, but still exist as
79 // states for their parts
80 #ifndef MINBS_INACTIVE
81 #define MINBS_INACTIVE 5
82 #endif
83 #ifndef MAXBS_INACTIVE
84 #define MAXBS_INACTIVE 5
85 #endif
86 #ifndef RBS_INACTIVE
87 #define RBS_INACTIVE 5
88 #endif
89 #ifndef HBS_INACTIVE
90 #define HBS_INACTIVE 5
91 #endif
92 #ifndef CBS_INACTIVE
93 #define CBS_INACTIVE 5
94 #endif
95
96 // Uncomment define below to build debug assisting code, and output
97 // #define DEBUG_XP_STYLE
98
99 // Declarations -----------------------------------------------------------------------------------
100 class XPThemeData
101 {
102 public:
103 explicit XPThemeData(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
104 int part = 0, int state = 0, const QRect &r = QRect())
widget(w)105 : widget(w), painter(p), theme(themeIn), partId(part), stateId(state),
106 mirrorHorizontally(false), mirrorVertically(false), noBorder(false),
107 noContent(false), rect(r)
108 {}
109
110 HRGN mask(QWidget *widget);
111 HTHEME handle();
112
113 static RECT toRECT(const QRect &qr);
114 bool isValid();
115
116 QSizeF size();
117 QMarginsF margins(const QRect &rect, int propId = TMT_CONTENTMARGINS);
118 QMarginsF margins(int propId = TMT_CONTENTMARGINS);
119
120 static QSizeF themeSize(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1, int part = 0, int state = 0);
121 static QMarginsF themeMargins(const QRect &rect, const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
122 int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
123 static QMarginsF themeMargins(const QWidget *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
124 int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
125
126 const QWidget *widget;
127 QPainter *painter;
128
129 int theme;
130 HTHEME htheme = nullptr;
131 int partId;
132 int stateId;
133
134 uint mirrorHorizontally : 1;
135 uint mirrorVertically : 1;
136 uint noBorder : 1;
137 uint noContent : 1;
138 uint rotate = 0;
139 QRect rect;
140 };
141
142 struct ThemeMapKey {
143 int theme = 0;
144 int partId = -1;
145 int stateId = -1;
146 bool noBorder = false;
147 bool noContent = false;
148
149 ThemeMapKey() = default;
ThemeMapKeyThemeMapKey150 ThemeMapKey(const XPThemeData &data)
151 : theme(data.theme), partId(data.partId), stateId(data.stateId),
152 noBorder(data.noBorder), noContent(data.noContent) {}
153
154 };
155
qHash(const ThemeMapKey & key)156 inline uint qHash(const ThemeMapKey &key)
157 { return key.theme ^ key.partId ^ key.stateId; }
158
159 inline bool operator==(const ThemeMapKey &k1, const ThemeMapKey &k2)
160 {
161 return k1.theme == k2.theme
162 && k1.partId == k2.partId
163 && k1.stateId == k2.stateId;
164 }
165
166 enum AlphaChannelType {
167 UnknownAlpha = -1, // Alpha of part & state not yet known
168 NoAlpha, // Totally opaque, no need to touch alpha (RGB)
169 MaskAlpha, // Alpha channel must be fixed (ARGB)
170 RealAlpha // Proper alpha values from Windows (ARGB_Premultiplied)
171 };
172
173 struct ThemeMapData {
174 AlphaChannelType alphaType = UnknownAlpha; // Which type of alpha on part & state
175
176 bool dataValid : 1; // Only used to detect if hash value is ok
177 bool partIsTransparent : 1;
178 bool hasAlphaChannel : 1; // True = part & state has real Alpha
179 bool wasAlphaSwapped : 1; // True = alpha channel needs to be swapped
180 bool hadInvalidAlpha : 1; // True = alpha channel contained invalid alpha values
181
ThemeMapDataThemeMapData182 ThemeMapData() : dataValid(false), partIsTransparent(false),
183 hasAlphaChannel(false), wasAlphaSwapped(false), hadInvalidAlpha(false) {}
184 };
185
186 #ifndef QT_NO_DEBUG_STREAM
187 QDebug operator<<(QDebug d, const XPThemeData &t);
188 QDebug operator<<(QDebug d, const ThemeMapKey &k);
189 QDebug operator<<(QDebug d, const ThemeMapData &td);
190 #endif
191
192 class QWindowsXPStylePrivate : public QWindowsStylePrivate
193 {
194 Q_DECLARE_PUBLIC(QWindowsXPStyle)
195 public:
196 enum Theme {
197 ButtonTheme,
198 ComboboxTheme,
199 EditTheme,
200 HeaderTheme,
201 ListViewTheme,
202 MenuTheme,
203 ProgressTheme,
204 RebarTheme,
205 ScrollBarTheme,
206 SpinTheme,
207 TabTheme,
208 TaskDialogTheme,
209 ToolBarTheme,
210 ToolTipTheme,
211 TrackBarTheme,
212 XpTreeViewTheme, // '+'/'-' shape treeview indicators (XP)
213 WindowTheme,
214 StatusTheme,
215 VistaTreeViewTheme, // arrow shape treeview indicators (Vista) obtained from "explorer" theme.
216 NThemes
217 };
218
QWindowsXPStylePrivate()219 QWindowsXPStylePrivate()
220 { init(); }
221
~QWindowsXPStylePrivate()222 ~QWindowsXPStylePrivate()
223 { cleanup(); }
224
225 static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
226 static int fixedPixelMetric(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
227
228 static HWND winId(const QWidget *widget);
229
230 void init(bool force = false);
231 void cleanup(bool force = false);
232 void cleanupHandleMap();
233
234 HBITMAP buffer(int w = 0, int h = 0);
bufferHDC()235 HDC bufferHDC()
236 { return bufferDC;}
237
238 static bool useXP(bool update = false);
239 static QRect scrollBarGripperBounds(QStyle::State flags, const QWidget *widget, XPThemeData *theme);
240
241 bool isTransparent(XPThemeData &themeData);
242 QRegion region(XPThemeData &themeData);
243
244 bool drawBackground(XPThemeData &themeData, qreal correctionFactor = 1);
245 bool drawBackgroundThruNativeBuffer(XPThemeData &themeData, qreal aditionalDevicePixelRatio, qreal correctionFactor);
246 bool drawBackgroundDirectly(HDC dc, XPThemeData &themeData, qreal aditionalDevicePixelRatio);
247
248 bool hasAlphaChannel(const QRect &rect);
249 bool fixAlphaChannel(const QRect &rect);
250 bool swapAlphaChannel(const QRect &rect, bool allPixels = false);
251
252 QRgb groupBoxTextColor = 0;
253 QRgb groupBoxTextColorDisabled = 0;
254 QRgb sliderTickColor = 0;
255 bool hasInitColors = false;
256
257 static HTHEME createTheme(int theme, HWND hwnd);
258 static QString themeName(int theme);
hasTheme(int theme)259 static inline bool hasTheme(int theme) { return theme >= 0 && theme < NThemes && m_themes[theme]; }
260 static bool isItemViewDelegateLineEdit(const QWidget *widget);
261 static bool isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget);
262
263 QIcon dockFloat, dockClose;
264
265 private:
266 #ifdef DEBUG_XP_STYLE
267 void dumpNativeDIB(int w, int h);
268 void showProperties(XPThemeData &themeData);
269 #endif
270
271 static bool initVistaTreeViewTheming();
272 static void cleanupVistaTreeViewTheming();
273
274 static QBasicAtomicInt ref;
275 static bool use_xp;
276
277 QHash<ThemeMapKey, ThemeMapData> alphaCache;
278 HDC bufferDC = nullptr;
279 HBITMAP bufferBitmap = nullptr;
280 HBITMAP nullBitmap = nullptr;
281 uchar *bufferPixels = nullptr;
282 int bufferW = 0;
283 int bufferH = 0;
284
285 static HWND m_vistaTreeViewHelper;
286 static HTHEME m_themes[NThemes];
287 };
288
size()289 inline QSizeF XPThemeData::size()
290 {
291 QSizeF result(0, 0);
292 if (isValid()) {
293 SIZE size;
294 if (SUCCEEDED(GetThemePartSize(handle(), nullptr, partId, stateId, nullptr, TS_TRUE, &size)))
295 result = QSize(size.cx, size.cy);
296 }
297 return result;
298 }
299
margins(const QRect & qRect,int propId)300 inline QMarginsF XPThemeData::margins(const QRect &qRect, int propId)
301 {
302 QMarginsF result(0, 0, 0 ,0);
303 if (isValid()) {
304 MARGINS margins;
305 RECT rect = XPThemeData::toRECT(qRect);
306 if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, &rect, &margins)))
307 result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
308 }
309 return result;
310 }
311
margins(int propId)312 inline QMarginsF XPThemeData::margins(int propId)
313 {
314 QMarginsF result(0, 0, 0 ,0);
315 if (isValid()) {
316 MARGINS margins;
317 if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, nullptr, &margins)))
318 result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
319 }
320 return result;
321 }
322
themeSize(const QWidget * w,QPainter * p,int themeIn,int part,int state)323 inline QSizeF XPThemeData::themeSize(const QWidget *w, QPainter *p, int themeIn, int part, int state)
324 {
325 XPThemeData theme(w, p, themeIn, part, state);
326 return theme.size();
327 }
328
themeMargins(const QRect & rect,const QWidget * w,QPainter * p,int themeIn,int part,int state,int propId)329 inline QMarginsF XPThemeData::themeMargins(const QRect &rect, const QWidget *w, QPainter *p, int themeIn,
330 int part, int state, int propId)
331 {
332 XPThemeData theme(w, p, themeIn, part, state);
333 return theme.margins(rect, propId);
334 }
335
themeMargins(const QWidget * w,QPainter * p,int themeIn,int part,int state,int propId)336 inline QMarginsF XPThemeData::themeMargins(const QWidget *w, QPainter *p, int themeIn,
337 int part, int state, int propId)
338 {
339 XPThemeData theme(w, p, themeIn, part, state);
340 return theme.margins(propId);
341 }
342
343 QT_END_NAMESPACE
344
345 #endif //QWINDOWSXPSTYLE_P_P_H
346