comparison foosdk/wtl/Include/atltheme.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 // Windows Template Library - WTL version 10.0
2 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Public License (http://opensource.org/licenses/MS-PL)
7 // which can be found in the file MS-PL.txt at the root folder.
8
9 #ifndef __ATLTHEME_H__
10 #define __ATLTHEME_H__
11
12 #pragma once
13
14 #ifndef __ATLAPP_H__
15 #error atltheme.h requires atlapp.h to be included first
16 #endif
17
18 #ifndef __ATLWIN_H__
19 #error atltheme.h requires atlwin.h to be included first
20 #endif
21
22 #include <vssym32.h>
23
24 // Note: To create an application that also runs on older versions of Windows,
25 // use delay load of uxtheme.dll and ensure that no calls to the Theme API are
26 // made if theming is not supported. It is enough to check if m_hTheme is NULL.
27 // Example:
28 // if(m_hTheme != NULL)
29 // {
30 // DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL);
31 // DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect);
32 // }
33 // else
34 // {
35 // dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH);
36 // dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
37 // }
38 //
39 // Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib,
40 // and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the
41 // project properties.
42
43
44 ///////////////////////////////////////////////////////////////////////////////
45 // Classes in this file:
46 //
47 // CTheme
48 // CThemeImpl<T, TBase>
49 //
50 // CBufferedPaint
51 // CBufferedPaintImpl<T>
52 // CBufferedPaintWindowImpl<T, TBase, TWinTraits>
53 // CBufferedAnimation
54 // CBufferedAnimationImpl<T, TState>
55 // CBufferedAnimationWindowImpl<T, TState, TBase, TWinTraits>
56 //
57 // Global functions:
58 // AtlDrawThemeClientEdge()
59
60
61 namespace WTL
62 {
63
64 ///////////////////////////////////////////////////////////////////////////////
65 // CTheme - wrapper for theme handle
66
67 class CTheme
68 {
69 public:
70 // Data members
71 HTHEME m_hTheme;
72 static int m_nIsThemingSupported;
73
74 // Constructor
75 CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme)
76 {
77 IsThemingSupported();
78 }
79
80 // Operators and helpers
81 bool IsThemeNull() const
82 {
83 return (m_hTheme == NULL);
84 }
85
86 CTheme& operator =(HTHEME hTheme)
87 {
88 m_hTheme = hTheme;
89 return *this;
90 }
91
92 operator HTHEME() const
93 {
94 return m_hTheme;
95 }
96
97 void Attach(HTHEME hTheme)
98 {
99 m_hTheme = hTheme;
100 }
101
102 HTHEME Detach()
103 {
104 HTHEME hTheme = m_hTheme;
105 m_hTheme = NULL;
106 return hTheme;
107 }
108
109 // Theme support helper
110 static bool IsThemingSupported()
111 {
112 if(m_nIsThemingSupported == -1)
113 {
114 CStaticDataInitCriticalSectionLock lock;
115 if(FAILED(lock.Lock()))
116 {
117 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n"));
118 ATLASSERT(FALSE);
119 return false;
120 }
121
122 if(m_nIsThemingSupported == -1)
123 {
124 HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
125 m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0;
126 if(hThemeDLL != NULL)
127 ::FreeLibrary(hThemeDLL);
128 }
129
130 lock.Unlock();
131 }
132
133 ATLASSERT(m_nIsThemingSupported != -1);
134 return (m_nIsThemingSupported == 1);
135 }
136
137 // Operations and theme properties
138 HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList)
139 {
140 if(!IsThemingSupported())
141 return NULL;
142
143 ATLASSERT(m_hTheme == NULL);
144 m_hTheme = ::OpenThemeData(hWnd, pszClassList);
145 return m_hTheme;
146 }
147
148 HRESULT CloseThemeData()
149 {
150 HRESULT hRet = S_FALSE;
151 if(m_hTheme != NULL)
152 {
153 hRet = ::CloseThemeData(m_hTheme);
154 if(SUCCEEDED(hRet))
155 m_hTheme = NULL;
156 }
157 return hRet;
158 }
159
160 HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL)
161 {
162 ATLASSERT(m_hTheme != NULL);
163 return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect);
164 }
165
166 // Missing in original uxtheme.h
167 #ifdef DTBG_CLIPRECT
168 HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL)
169 {
170 ATLASSERT(m_hTheme != NULL);
171 return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions);
172 }
173 #endif // DTBG_CLIPRECT
174
175 HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect)
176 {
177 ATLASSERT(m_hTheme != NULL);
178 return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect);
179 }
180
181 HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID, LPCRECT pBoundingRect, LPRECT pContentRect) const
182 {
183 ATLASSERT(m_hTheme != NULL);
184 return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID, pBoundingRect, pContentRect);
185 }
186
187 HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const
188 {
189 ATLASSERT(m_hTheme != NULL);
190 return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect);
191 }
192
193 HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const
194 {
195 ATLASSERT(m_hTheme != NULL);
196 return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize);
197 }
198
199 HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT pBoundingRect, LPRECT pExtentRect) const
200 {
201 ATLASSERT(m_hTheme != NULL);
202 return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect);
203 }
204
205 HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const
206 {
207 ATLASSERT(m_hTheme != NULL);
208 return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric);
209 }
210
211 HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const
212 {
213 ATLASSERT(m_hTheme != NULL);
214 return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion);
215 }
216
217 HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const
218 {
219 ATLASSERT(m_hTheme != NULL);
220 return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode);
221 }
222
223 HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL)
224 {
225 ATLASSERT(m_hTheme != NULL);
226 return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect);
227 }
228
229 HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex)
230 {
231 ATLASSERT(m_hTheme != NULL);
232 return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex);
233 }
234
235 BOOL IsThemePartDefined(int nPartID, int nStateID) const
236 {
237 ATLASSERT(m_hTheme != NULL);
238 return ::IsThemePartDefined(m_hTheme, nPartID, nStateID);
239 }
240
241 BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const
242 {
243 ATLASSERT(m_hTheme != NULL);
244 return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID);
245 }
246
247 HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const
248 {
249 ATLASSERT(m_hTheme != NULL);
250 return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor);
251 }
252
253 HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const
254 {
255 ATLASSERT(m_hTheme != NULL);
256 return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal);
257 }
258
259 HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const
260 {
261 ATLASSERT(m_hTheme != NULL);
262 return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars);
263 }
264
265 HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const
266 {
267 ATLASSERT(m_hTheme != NULL);
268 return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal);
269 }
270
271 HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const
272 {
273 ATLASSERT(m_hTheme != NULL);
274 return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal);
275 }
276
277 HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const
278 {
279 ATLASSERT(m_hTheme != NULL);
280 return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal);
281 }
282
283 HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const
284 {
285 ATLASSERT(m_hTheme != NULL);
286 return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint);
287 }
288
289 // deprecated
290 HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const
291 {
292 ATLASSERT(m_hTheme != NULL);
293 return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);
294 }
295
296 HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const
297 {
298 ATLASSERT(m_hTheme != NULL);
299 return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);
300 }
301
302 HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const
303 {
304 ATLASSERT(m_hTheme != NULL);
305 return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect);
306 }
307
308 HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const
309 {
310 ATLASSERT(m_hTheme != NULL);
311 return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins);
312 }
313
314 HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const
315 {
316 ATLASSERT(m_hTheme != NULL);
317 return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList);
318 }
319
320 HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const
321 {
322 ATLASSERT(m_hTheme != NULL);
323 return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin);
324 }
325
326 HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const
327 {
328 ATLASSERT(m_hTheme != NULL);
329 return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars);
330 }
331
332 COLORREF GetThemeSysColor(int nColorID) const
333 {
334 ATLASSERT(m_hTheme != NULL);
335 return ::GetThemeSysColor(m_hTheme, nColorID);
336 }
337
338 HBRUSH GetThemeSysColorBrush(int nColorID) const
339 {
340 ATLASSERT(m_hTheme != NULL);
341 return ::GetThemeSysColorBrush(m_hTheme, nColorID);
342 }
343
344 int GetThemeSysSize(int nSizeID) const
345 {
346 ATLASSERT(m_hTheme != NULL);
347 return ::GetThemeSysSize(m_hTheme, nSizeID);
348 }
349
350 BOOL GetThemeSysBool(int nBoolID) const
351 {
352 ATLASSERT(m_hTheme != NULL);
353 return ::GetThemeSysBool(m_hTheme, nBoolID);
354 }
355
356 HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const
357 {
358 ATLASSERT(m_hTheme != NULL);
359 return ::GetThemeSysFont(m_hTheme, nFontID, plf);
360 }
361
362 HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const
363 {
364 ATLASSERT(m_hTheme != NULL);
365 return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars);
366 }
367
368 HRESULT GetThemeSysInt(int nIntID, int* pnValue) const
369 {
370 ATLASSERT(m_hTheme != NULL);
371 return ::GetThemeSysInt(m_hTheme, nIntID, pnValue);
372 }
373
374 HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags)
375 {
376 if(!IsThemingSupported())
377 return NULL;
378
379 ATLASSERT(m_hTheme == NULL);
380 m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags);
381 return m_hTheme;
382 }
383
384 #if (_WIN32_WINNT >= 0x0600)
385 HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions)
386 {
387 ATLASSERT(m_hTheme != NULL);
388 return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions);
389 }
390
391 HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration)
392 {
393 ATLASSERT(m_hTheme != NULL);
394 return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration);
395 }
396 #endif // (_WIN32_WINNT >= 0x0600)
397
398 #if (_WIN32_WINNT >= 0x0600)
399 HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap)
400 {
401 ATLASSERT(m_hTheme != NULL);
402 return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap);
403 }
404
405 HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance)
406 {
407 ATLASSERT(m_hTheme != NULL);
408 return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance);
409 }
410 #endif // (_WIN32_WINNT >= 0x0600)
411
412 #if (_WIN32_WINNT >= 0x0602)
413 HRESULT GetThemeAnimationProperty(int iStoryboardId, int iTargetId, TA_PROPERTY eProperty, VOID* pvProperty, DWORD cbSize, DWORD* pcbSizeOut)
414 {
415 ATLASSERT(m_hTheme != NULL);
416 return ::GetThemeAnimationProperty(m_hTheme, iStoryboardId, iTargetId, eProperty, pvProperty, cbSize, pcbSizeOut);
417 }
418
419 HRESULT GetThemeAnimationTransform(int iStoryboardId, int iTargetId, DWORD dwTransformIndex, TA_TRANSFORM* pTransform, DWORD cbSize, DWORD* pcbSizeOut)
420 {
421 ATLASSERT(m_hTheme != NULL);
422 return ::GetThemeAnimationTransform(m_hTheme, iStoryboardId, iTargetId, dwTransformIndex, pTransform, cbSize, pcbSizeOut);
423 }
424
425 HRESULT GetThemeTimingFunction(int iTimingFunctionId, TA_TIMINGFUNCTION* pTimingFunction, DWORD cbSize, DWORD* pcbSizeOut)
426 {
427 ATLASSERT(m_hTheme != NULL);
428 return ::GetThemeTimingFunction(m_hTheme, iTimingFunctionId, pTimingFunction, cbSize, pcbSizeOut);
429 }
430 #endif // (_WIN32_WINNT >= 0x0602)
431 };
432
433 __declspec(selectany) int CTheme::m_nIsThemingSupported = -1;
434
435
436 ///////////////////////////////////////////////////////////////////////////////
437 // CThemeImpl - theme support implementation
438
439 // Derive from this class to implement window with theme support.
440 // Example:
441 // class CMyThemeWindow : public CWindowImpl<CMyThemeWindow>, public CThemeImpl<CMyThemeWindow>
442 // {
443 // ...
444 // BEGIN_MSG_MAP(CMyThemeWindow)
445 // CHAIN_MSG_MAP(CThemeImpl<CMyThemeWindow>)
446 // ...
447 // END_MSG_MAP()
448 // ...
449 // };
450 //
451 // If you set theme class list, the class will automaticaly open/close/reopen theme data.
452
453
454 // Helper for drawing theme client edge
455 inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0)
456 {
457 ATLASSERT(hTheme != NULL);
458 ATLASSERT(::IsWindow(hWnd));
459
460 CWindowDC dc(hWnd);
461 if(dc.IsNull())
462 return false;
463
464 // Get border size
465 int cxBorder = ::GetSystemMetrics(SM_CXBORDER);
466 int cyBorder = ::GetSystemMetrics(SM_CYBORDER);
467 if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder)))
468 cyBorder = cxBorder;
469
470 RECT rect = {};
471 ::GetWindowRect(hWnd, &rect);
472
473 // Remove the client edge from the update region
474 int cxEdge = ::GetSystemMetrics(SM_CXEDGE);
475 int cyEdge = ::GetSystemMetrics(SM_CYEDGE);
476 ::InflateRect(&rect, -cxEdge, -cyEdge);
477 CRgn rgn;
478 rgn.CreateRectRgnIndirect(&rect);
479 if(rgn.IsNull())
480 return false;
481
482 if(hRgnUpdate != NULL)
483 rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND);
484
485 ::OffsetRect(&rect, -rect.left, -rect.top);
486
487 ::OffsetRect(&rect, cxEdge, cyEdge);
488 dc.ExcludeClipRect(&rect);
489 ::InflateRect(&rect, cxEdge, cyEdge);
490
491 ::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL);
492
493 // Use background brush too, since theme border might not cover everything
494 if((cxBorder < cxEdge) && (cyBorder < cyEdge))
495 {
496 if(hBrush == NULL)
497 hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND);
498
499 ::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge);
500 dc.FillRect(&rect, hBrush);
501 }
502
503 ::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L);
504
505 return true;
506 }
507
508
509 // Theme extended styles
510 #define THEME_EX_3DCLIENTEDGE 0x00000001
511 #define THEME_EX_THEMECLIENTEDGE 0x00000002
512
513 template <class T, class TBase = CTheme>
514 class CThemeImpl : public TBase
515 {
516 public:
517 // Data members
518 LPWSTR m_lpstrThemeClassList;
519 DWORD m_dwExtendedStyle; // theme specific extended styles
520
521 // Constructor & destructor
522 CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0)
523 { }
524
525 ~CThemeImpl()
526 {
527 delete [] m_lpstrThemeClassList;
528 }
529
530 // Attributes
531 bool SetThemeClassList(LPCWSTR lpstrThemeClassList)
532 {
533 if(m_lpstrThemeClassList != NULL)
534 {
535 delete [] m_lpstrThemeClassList;
536 m_lpstrThemeClassList = NULL;
537 }
538
539 if(lpstrThemeClassList == NULL)
540 return true;
541
542 int cchLen = lstrlenW(lpstrThemeClassList) + 1;
543 ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]);
544 if(m_lpstrThemeClassList == NULL)
545 return false;
546
547 ATL::Checked::wcscpy_s(m_lpstrThemeClassList, cchLen, lpstrThemeClassList);
548
549 return true;
550 }
551
552 bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const
553 {
554 int cchLen = lstrlenW(m_lpstrThemeClassList) + 1;
555 if(cchListBuffer < cchLen)
556 return false;
557
558 ATL::Checked::wcscpy_s(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList);
559
560 return true;
561 }
562
563 LPCWSTR GetThemeClassList() const
564 {
565 return m_lpstrThemeClassList;
566 }
567
568 DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
569 {
570 DWORD dwPrevStyle = m_dwExtendedStyle;
571 if(dwMask == 0)
572 m_dwExtendedStyle = dwExtendedStyle;
573 else
574 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
575
576 return dwPrevStyle;
577 }
578
579 DWORD GetThemeExtendedStyle() const
580 {
581 return m_dwExtendedStyle;
582 }
583
584 // Operations
585 HTHEME OpenThemeData()
586 {
587 T* pT = static_cast<T*>(this);
588 ATLASSERT(::IsWindow(pT->m_hWnd));
589 ATLASSERT(m_lpstrThemeClassList != NULL);
590 if(m_lpstrThemeClassList == NULL)
591 return NULL;
592 this->CloseThemeData();
593
594 return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList);
595 }
596
597 HTHEME OpenThemeData(LPCWSTR pszClassList)
598 {
599 if(!SetThemeClassList(pszClassList))
600 return NULL;
601
602 return OpenThemeData();
603 }
604
605 HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList)
606 {
607 if(!this->IsThemingSupported())
608 return S_FALSE;
609
610 T* pT = static_cast<T*>(this);
611 ATLASSERT(::IsWindow(pT->m_hWnd));
612 return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList);
613 }
614
615 HTHEME GetWindowTheme() const
616 {
617 if(!this->IsThemingSupported())
618 return NULL;
619
620 const T* pT = static_cast<const T*>(this);
621 ATLASSERT(::IsWindow(pT->m_hWnd));
622 return ::GetWindowTheme(pT->m_hWnd);
623 }
624
625 HRESULT EnableThemeDialogTexture(DWORD dwFlags)
626 {
627 if(!this->IsThemingSupported())
628 return S_FALSE;
629
630 T* pT = static_cast<T*>(this);
631 ATLASSERT(::IsWindow(pT->m_hWnd));
632 return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags);
633 }
634
635 BOOL IsThemeDialogTextureEnabled() const
636 {
637 if(!this->IsThemingSupported())
638 return FALSE;
639
640 const T* pT = static_cast<const T*>(this);
641 ATLASSERT(::IsWindow(pT->m_hWnd));
642 return ::IsThemeDialogTextureEnabled(pT->m_hWnd);
643 }
644
645 HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL)
646 {
647 if(!this->IsThemingSupported())
648 return S_FALSE;
649
650 T* pT = static_cast<T*>(this);
651 ATLASSERT(::IsWindow(pT->m_hWnd));
652 return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect);
653 }
654
655 #if (_WIN32_WINNT >= 0x0600)
656 HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute)
657 {
658 if(!this->IsThemingSupported())
659 return S_FALSE;
660
661 T* pT = static_cast<T*>(this);
662 ATLASSERT(::IsWindow(pT->m_hWnd));
663 return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute);
664 }
665
666 HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask)
667 {
668 if(!this->IsThemingSupported())
669 return S_FALSE;
670
671 T* pT = static_cast<T*>(this);
672 ATLASSERT(::IsWindow(pT->m_hWnd));
673 WTA_OPTIONS opt = { dwAttributes, dwMask };
674 return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt));
675 }
676
677 HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL)
678 {
679 if(!this->IsThemingSupported())
680 return S_FALSE;
681
682 T* pT = static_cast<T*>(this);
683 ATLASSERT(::IsWindow(pT->m_hWnd));
684 return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect);
685 }
686 #endif // (_WIN32_WINNT >= 0x0600)
687
688 // Message map and handlers
689 // Note: If you handle any of these messages in your derived class,
690 // it is better to put CHAIN_MSG_MAP at the start of your message map.
691 BEGIN_MSG_MAP(CThemeImpl)
692 MESSAGE_HANDLER(WM_CREATE, OnCreate)
693 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
694 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
695 MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
696 END_MSG_MAP()
697
698 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
699 {
700 if(m_lpstrThemeClassList != NULL)
701 OpenThemeData();
702
703 bHandled = FALSE;
704 return 1;
705 }
706
707 LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
708 {
709 this->CloseThemeData();
710
711 bHandled = FALSE;
712 return 1;
713 }
714
715 LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
716 {
717 this->CloseThemeData();
718 if(m_lpstrThemeClassList != NULL)
719 this->OpenThemeData();
720
721 bHandled = FALSE;
722 return 1;
723 }
724
725 LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
726 {
727 T* pT = static_cast<T*>(this);
728 ATLASSERT(::IsWindow(pT->m_hWnd));
729 LRESULT lRet = 0;
730 bHandled = FALSE;
731 if(this->IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0))
732 {
733 if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0)
734 {
735 lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam);
736 bHandled = TRUE;
737 }
738 else if((this->m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0))
739 {
740 HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL;
741 if(pT->DrawThemeClientEdge(hRgn))
742 bHandled = TRUE;
743 }
744 }
745
746 return lRet;
747 }
748
749 // Drawing helper
750 bool DrawThemeClientEdge(HRGN hRgnUpdate)
751 {
752 T* pT = static_cast<T*>(this);
753 return AtlDrawThemeClientEdge(this->m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0);
754 }
755 };
756
757 ///////////////////////////////////////////////////////////////////////////////
758 // Buffered Paint and Animation
759
760 #if (_WIN32_WINNT >= 0x0600)
761
762 ///////////////////////////////////////////////////////////////////////////////
763 // CBufferedPaintBase - Buffered Paint support for othe classes
764
765 class CBufferedPaintBase
766 {
767 public:
768 static int m_nIsBufferedPaintSupported;
769
770 CBufferedPaintBase()
771 {
772 if(IsBufferedPaintSupported())
773 ATLVERIFY(SUCCEEDED(::BufferedPaintInit()));
774 }
775
776 ~CBufferedPaintBase()
777 {
778 if(IsBufferedPaintSupported())
779 ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit()));
780 }
781
782 static bool IsBufferedPaintSupported()
783 {
784 if(m_nIsBufferedPaintSupported == -1)
785 {
786 CStaticDataInitCriticalSectionLock lock;
787 if(FAILED(lock.Lock()))
788 {
789 ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n"));
790 ATLASSERT(FALSE);
791 return false;
792 }
793
794 if(m_nIsBufferedPaintSupported == -1)
795 m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0;
796
797 lock.Unlock();
798 }
799
800 ATLASSERT(m_nIsBufferedPaintSupported != -1);
801 return (m_nIsBufferedPaintSupported == 1);
802 }
803 };
804
805 __declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1;
806
807
808 ///////////////////////////////////////////////////////////////////////////////
809 // CBufferedPaint - support for buffered paint functions
810
811 class CBufferedPaint
812 {
813 public:
814 HPAINTBUFFER m_hPaintBuffer;
815
816 CBufferedPaint() : m_hPaintBuffer(NULL)
817 { }
818
819 ~CBufferedPaint()
820 {
821 ATLVERIFY(SUCCEEDED(End()));
822 }
823
824 bool IsNull() const
825 {
826 return (m_hPaintBuffer == NULL);
827 }
828
829 HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint)
830 {
831 ATLASSERT(m_hPaintBuffer == NULL);
832 m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint);
833 return m_hPaintBuffer;
834 }
835
836 HRESULT End(BOOL bUpdate = TRUE)
837 {
838 HRESULT hRet = S_FALSE;
839 if(m_hPaintBuffer != NULL)
840 {
841 hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate);
842 m_hPaintBuffer = NULL;
843 }
844 return hRet;
845 }
846
847 HRESULT GetTargetRect(LPRECT pRect) const
848 {
849 ATLASSERT(m_hPaintBuffer != NULL);
850 return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect);
851 }
852
853 HDC GetTargetDC() const
854 {
855 ATLASSERT(m_hPaintBuffer != NULL);
856 return ::GetBufferedPaintTargetDC(m_hPaintBuffer);
857 }
858
859 HDC GetPaintDC() const
860 {
861 ATLASSERT(m_hPaintBuffer != NULL);
862 return ::GetBufferedPaintDC(m_hPaintBuffer);
863 }
864
865 HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const
866 {
867 ATLASSERT(m_hPaintBuffer != NULL);
868 return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow);
869 }
870
871 HRESULT Clear(const RECT* pRect = NULL)
872 {
873 ATLASSERT(m_hPaintBuffer != NULL);
874 return ::BufferedPaintClear(m_hPaintBuffer, pRect);
875 }
876
877 HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL)
878 {
879 ATLASSERT(m_hPaintBuffer != NULL);
880 return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha);
881 }
882
883 HRESULT MakeOpaque(const RECT* pRect = NULL)
884 {
885 ATLASSERT(m_hPaintBuffer != NULL);
886 return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255);
887 }
888 };
889
890
891 ///////////////////////////////////////////////////////////////////////////////
892 // CBufferedPaintImpl - provides buffered paint for any window
893
894 template <class T>
895 class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase
896 {
897 public:
898 CBufferedPaint m_BufferedPaint;
899 BP_BUFFERFORMAT m_dwFormat;
900 BP_PAINTPARAMS m_PaintParams;
901
902 CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB)
903 {
904 memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));
905 m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);
906 }
907
908 // Message map and handlers
909 BEGIN_MSG_MAP(CBufferedPaintImpl)
910 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
911 MESSAGE_HANDLER(WM_PAINT, OnPaint)
912 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
913 END_MSG_MAP()
914
915 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
916 {
917 return 1; // no background needed
918 }
919
920 LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
921 {
922 T* pT = static_cast<T*>(this);
923 if(wParam != NULL)
924 {
925 RECT rect = {};
926 pT->GetClientRect(&rect);
927 pT->DoPaint((HDC)wParam, rect);
928 }
929 else
930 {
931 CPaintDC dc(pT->m_hWnd);
932 pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint);
933 }
934
935 return 0;
936 }
937
938 // Overrideables
939 void DoBufferedPaint(CDCHandle dc, RECT& rect)
940 {
941 HDC hDCPaint = NULL;
942 if(IsBufferedPaintSupported())
943 m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint);
944
945 T* pT = static_cast<T*>(this);
946 if(hDCPaint != NULL)
947 pT->DoPaint(hDCPaint, rect);
948 else
949 pT->DoPaint(dc.m_hDC, rect);
950
951 if(IsBufferedPaintSupported())
952 m_BufferedPaint.End();
953 }
954
955 void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/)
956 {
957 // must be implemented in a derived class
958 ATLASSERT(FALSE);
959 }
960 };
961
962
963 ///////////////////////////////////////////////////////////////////////////////
964 // CBufferedPaintWindowImpl - implements a window that uses buffered paint
965
966 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
967 class ATL_NO_VTABLE CBufferedPaintWindowImpl :
968 public ATL::CWindowImpl<T, TBase, TWinTraits>,
969 public CBufferedPaintImpl< T >
970 {
971 public:
972 BEGIN_MSG_MAP(CBufferedPaintWindowImpl)
973 CHAIN_MSG_MAP(CBufferedPaintImpl< T >)
974 END_MSG_MAP()
975 };
976
977
978 ///////////////////////////////////////////////////////////////////////////////
979 // CBufferedAnimation - support for buffered animation
980
981 class CBufferedAnimation
982 {
983 public:
984 HANIMATIONBUFFER m_hAnimationBuffer;
985
986 CBufferedAnimation() : m_hAnimationBuffer(NULL)
987 { }
988
989 ~CBufferedAnimation()
990 {
991 ATLVERIFY(SUCCEEDED(End()));
992 }
993
994 bool IsNull() const
995 {
996 return (m_hAnimationBuffer == NULL);
997 }
998
999 HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo)
1000 {
1001 ATLASSERT(m_hAnimationBuffer == NULL);
1002 m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo);
1003 return m_hAnimationBuffer;
1004 }
1005
1006 HRESULT End(BOOL bUpdate = TRUE)
1007 {
1008 HRESULT hRet = S_FALSE;
1009 if(m_hAnimationBuffer != NULL)
1010 {
1011 hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate);
1012 m_hAnimationBuffer = NULL;
1013 }
1014 return hRet;
1015 }
1016
1017 static bool IsRendering(HWND hWnd, HDC hDC)
1018 {
1019 return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE);
1020 }
1021
1022 static HRESULT StopAllAnimations(HWND hWnd)
1023 {
1024 return ::BufferedPaintStopAllAnimations(hWnd);
1025 }
1026 };
1027
1028
1029 ///////////////////////////////////////////////////////////////////////////////
1030 // CBufferedAnimationImpl - provides buffered animation support for any window
1031
1032 // Note: You can either use m_State and m_NewState to store the state information
1033 // for the animation change, or map your state to those data members. DoPaint()
1034 // should only rely on the state information that is passed to it.
1035
1036 template <class T, class TState = DWORD_PTR>
1037 class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase
1038 {
1039 public:
1040 BP_BUFFERFORMAT m_dwFormat;
1041 BP_PAINTPARAMS m_PaintParams;
1042 BP_ANIMATIONPARAMS m_AnimationParams;
1043
1044 TState m_State;
1045 TState m_NewState;
1046
1047 CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB)
1048 {
1049 memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));
1050 m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);
1051
1052 memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS));
1053 m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS);
1054 m_AnimationParams.style = BPAS_LINEAR;
1055 m_AnimationParams.dwDuration = 500;
1056
1057 T* pT = static_cast<T*>(this);
1058 pT->SetState(InitialState);
1059 pT->SetNewState(InitialState);
1060 }
1061
1062 DWORD GetDuration() const
1063 {
1064 return m_AnimationParams.dwDuration;
1065 }
1066
1067 void SetDuration(DWORD dwDuration)
1068 {
1069 m_AnimationParams.dwDuration = dwDuration;
1070 }
1071
1072 void DoAnimation(TState NewState, const RECT* pRect = NULL)
1073 {
1074 T* pT = static_cast<T*>(this);
1075 pT->SetNewState(NewState);
1076
1077 pT->InvalidateRect(pRect, FALSE);
1078 pT->UpdateWindow();
1079
1080 pT->SetState(NewState);
1081 }
1082
1083 // Message map and handlers
1084 BEGIN_MSG_MAP(CBufferedAnimationImpl)
1085 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
1086 MESSAGE_HANDLER(WM_PAINT, OnPaint)
1087 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
1088 END_MSG_MAP()
1089
1090 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1091 {
1092 return 1; // no background needed
1093 }
1094
1095 LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1096 {
1097 T* pT = static_cast<T*>(this);
1098 if(wParam != NULL)
1099 {
1100 RECT rect = {};
1101 pT->GetClientRect(&rect);
1102 pT->DoPaint((HDC)wParam, rect, m_NewState);
1103 }
1104 else
1105 {
1106 CPaintDC dc(pT->m_hWnd);
1107 pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint);
1108 }
1109
1110 return 0;
1111 }
1112
1113 // Overrideables
1114 void SetState(TState State)
1115 {
1116 m_State = State;
1117 }
1118
1119 void SetNewState(TState State)
1120 {
1121 m_NewState = State;
1122 }
1123
1124 bool AreStatesEqual() const
1125 {
1126 return (m_State == m_NewState);
1127 }
1128
1129 void DoAnimationPaint(CDCHandle dc, RECT& rect)
1130 {
1131 T* pT = static_cast<T*>(this);
1132 if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc))
1133 return;
1134
1135 DWORD dwDurationSave = m_AnimationParams.dwDuration;
1136 if(pT->AreStatesEqual())
1137 m_AnimationParams.dwDuration = 0;
1138
1139 HDC hdcFrom = NULL, hdcTo = NULL;
1140 CBufferedAnimation ba;
1141 if(IsBufferedPaintSupported())
1142 ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo);
1143
1144 if(!ba.IsNull())
1145 {
1146 if(hdcFrom != NULL)
1147 pT->DoPaint(hdcFrom, rect, m_State);
1148
1149 if (hdcTo != NULL)
1150 pT->DoPaint(hdcTo, rect, m_NewState);
1151 }
1152 else
1153 {
1154 pT->DoPaint(dc.m_hDC, rect, m_NewState);
1155 }
1156
1157 m_AnimationParams.dwDuration = dwDurationSave;
1158 }
1159
1160 void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/)
1161 {
1162 // must be implemented in a derived class
1163 ATLASSERT(FALSE);
1164 }
1165 };
1166
1167
1168 ///////////////////////////////////////////////////////////////////////////////
1169 // CBufferedAnimationWindowImpl - implements a window that uses buffered animation
1170
1171 template <class T, class TState = DWORD_PTR, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
1172 class ATL_NO_VTABLE CBufferedAnimationWindowImpl :
1173 public ATL::CWindowImpl<T, TBase, TWinTraits>,
1174 public CBufferedAnimationImpl< T, TState >
1175 {
1176 public:
1177 CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState)
1178 { }
1179
1180 typedef CBufferedAnimationImpl< T, TState > _baseBufferedAnimation;
1181 BEGIN_MSG_MAP(CBufferedAnimationWindowImpl)
1182 CHAIN_MSG_MAP(_baseBufferedAnimation)
1183 END_MSG_MAP()
1184 };
1185
1186 #endif // (_WIN32_WINNT >= 0x0600)
1187
1188 } // namespace WTL
1189
1190 #endif // __ATLTHEME_H__