xref: /reactos/sdk/lib/cicero/cicuif.cpp (revision a55345be)
1 /*
2  * PROJECT:     ReactOS Cicero
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Cicero UIF Library
5  * COPYRIGHT:   Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include "precomp.h"
9 #include "cicuif.h"
10 
11 /////////////////////////////////////////////////////////////////////////////
12 // static members
13 
14 HINSTANCE CUIFTheme::s_hUXTHEME = NULL;
15 FN_OpenThemeData CUIFTheme::s_fnOpenThemeData = NULL;
16 FN_CloseThemeData CUIFTheme::s_fnCloseThemeData = NULL;
17 FN_DrawThemeBackground CUIFTheme::s_fnDrawThemeBackground = NULL;
18 FN_DrawThemeParentBackground CUIFTheme::s_fnDrawThemeParentBackground = NULL;
19 FN_DrawThemeText CUIFTheme::s_fnDrawThemeText = NULL;
20 FN_DrawThemeIcon CUIFTheme::s_fnDrawThemeIcon = NULL;
21 FN_GetThemeBackgroundExtent CUIFTheme::s_fnGetThemeBackgroundExtent = NULL;
22 FN_GetThemeBackgroundContentRect CUIFTheme::s_fnGetThemeBackgroundContentRect = NULL;
23 FN_GetThemeTextExtent CUIFTheme::s_fnGetThemeTextExtent = NULL;
24 FN_GetThemePartSize CUIFTheme::s_fnGetThemePartSize = NULL;
25 FN_DrawThemeEdge CUIFTheme::s_fnDrawThemeEdge = NULL;
26 FN_GetThemeColor CUIFTheme::s_fnGetThemeColor = NULL;
27 FN_GetThemeMargins CUIFTheme::s_fnGetThemeMargins = NULL;
28 FN_GetThemeFont CUIFTheme::s_fnGetThemeFont = NULL;
29 FN_GetThemeSysColor CUIFTheme::s_fnGetThemeSysColor = NULL;
30 FN_GetThemeSysSize CUIFTheme::s_fnGetThemeSysSize = NULL;
31 
32 CUIFSystemInfo *CUIFSystemInfo::s_pSystemInfo = NULL;
33 
34 CUIFColorTableSys *CUIFScheme::s_pColorTableSys = NULL;
35 CUIFColorTableOff10 *CUIFScheme::s_pColorTableOff10 = NULL;
36 
37 /////////////////////////////////////////////////////////////////////////////
38 
GetSystemMetrics()39 void CUIFSystemInfo::GetSystemMetrics()
40 {
41     HDC hDC = ::GetDC(NULL);
42     m_cBitsPixels = ::GetDeviceCaps(hDC, BITSPIXEL);
43     ::ReleaseDC(NULL, hDC);
44 
45     HIGHCONTRAST HighContrast = { sizeof(HighContrast) };
46     ::SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(HighContrast), &HighContrast, 0);
47     m_bHighContrast1 = !!(HighContrast.dwFlags & HCF_HIGHCONTRASTON);
48     COLORREF rgbBtnText = ::GetSysColor(COLOR_BTNTEXT);
49     COLORREF rgbBtnFace = ::GetSysColor(COLOR_BTNFACE);
50     const COLORREF black = RGB(0, 0, 0), white = RGB(255, 255, 255);
51     m_bHighContrast2 = (m_bHighContrast1 ||
52                         (rgbBtnText == black && rgbBtnFace == white) ||
53                         (rgbBtnText == white && rgbBtnFace == black));
54 }
55 
Initialize()56 void CUIFSystemInfo::Initialize()
57 {
58     dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
59     ::GetVersionEx(this);
60     GetSystemMetrics();
61 }
62 
63 /////////////////////////////////////////////////////////////////////////////
64 // CUIFTheme
65 
InternalOpenThemeData(HWND hWnd)66 HRESULT CUIFTheme::InternalOpenThemeData(HWND hWnd)
67 {
68     if (!hWnd || !m_pszClassList)
69         return E_FAIL;
70 
71     if (!cicGetFN(s_hUXTHEME, s_fnOpenThemeData, TEXT("uxtheme.dll"), "OpenThemeData"))
72         return E_FAIL;
73     m_hTheme = s_fnOpenThemeData(hWnd, m_pszClassList);
74     return (m_hTheme ? S_OK : E_FAIL);
75 }
76 
EnsureThemeData(HWND hWnd)77 HRESULT CUIFTheme::EnsureThemeData(HWND hWnd)
78 {
79     if (m_hTheme)
80         return S_OK;
81     return InternalOpenThemeData(hWnd);
82 }
83 
CloseThemeData()84 HRESULT CUIFTheme::CloseThemeData()
85 {
86     if (!m_hTheme)
87         return S_OK;
88 
89     if (!cicGetFN(s_hUXTHEME, s_fnCloseThemeData, TEXT("uxtheme.dll"), "CloseThemeData"))
90         return E_FAIL;
91 
92     HRESULT hr = s_fnCloseThemeData(m_hTheme);
93     m_hTheme = NULL;
94     return hr;
95 }
96 
97 STDMETHODIMP
DrawThemeBackground(HDC hDC,int iStateId,LPCRECT pRect,LPCRECT pClipRect)98 CUIFTheme::DrawThemeBackground(HDC hDC, int iStateId, LPCRECT pRect, LPCRECT pClipRect)
99 {
100     if (!cicGetFN(s_hUXTHEME, s_fnDrawThemeBackground, TEXT("uxtheme.dll"), "DrawThemeBackground"))
101         return E_FAIL;
102     return s_fnDrawThemeBackground(m_hTheme, hDC, m_iPartId, iStateId, pRect, pClipRect);
103 }
104 
105 STDMETHODIMP
DrawThemeParentBackground(HWND hwnd,HDC hDC,LPRECT prc)106 CUIFTheme::DrawThemeParentBackground(HWND hwnd, HDC hDC, LPRECT prc)
107 {
108     if (!cicGetFN(s_hUXTHEME, s_fnDrawThemeParentBackground, TEXT("uxtheme.dll"), "DrawThemeParentBackground"))
109         return E_FAIL;
110     return s_fnDrawThemeParentBackground(hwnd, hDC, prc);
111 }
112 
113 STDMETHODIMP
DrawThemeText(HDC hDC,int iStateId,LPCWSTR pszText,int cchText,DWORD dwTextFlags,DWORD dwTextFlags2,LPCRECT pRect)114 CUIFTheme::DrawThemeText(HDC hDC, int iStateId, LPCWSTR pszText, int cchText, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect)
115 {
116     if (!cicGetFN(s_hUXTHEME, s_fnDrawThemeText, TEXT("uxtheme.dll"), "DrawThemeText"))
117         return E_FAIL;
118     return s_fnDrawThemeText(m_hTheme, hDC, m_iPartId, iStateId, pszText, cchText, dwTextFlags, dwTextFlags2, pRect);
119 }
120 
121 STDMETHODIMP
DrawThemeIcon(HDC hDC,int iStateId,LPCRECT pRect,HIMAGELIST himl,int iImageIndex)122 CUIFTheme::DrawThemeIcon(HDC hDC, int iStateId, LPCRECT pRect, HIMAGELIST himl, int iImageIndex)
123 {
124     if (!cicGetFN(s_hUXTHEME, s_fnDrawThemeIcon, TEXT("uxtheme.dll"), "DrawThemeIcon"))
125         return E_FAIL;
126     return s_fnDrawThemeIcon(m_hTheme, hDC, m_iPartId, iStateId, pRect, himl, iImageIndex);
127 }
128 
129 STDMETHODIMP
GetThemeBackgroundExtent(HDC hDC,int iStateId,LPCRECT pContentRect,LPRECT pExtentRect)130 CUIFTheme::GetThemeBackgroundExtent(HDC hDC, int iStateId, LPCRECT pContentRect, LPRECT pExtentRect)
131 {
132     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeBackgroundExtent, TEXT("uxtheme.dll"), "GetThemeBackgroundExtent"))
133         return E_FAIL;
134     return s_fnGetThemeBackgroundExtent(m_hTheme, hDC, m_iPartId, iStateId, pContentRect, pExtentRect);
135 }
136 
137 STDMETHODIMP
GetThemeBackgroundContentRect(HDC hDC,int iStateId,LPCRECT pBoundingRect,LPRECT pContentRect)138 CUIFTheme::GetThemeBackgroundContentRect(HDC hDC, int iStateId, LPCRECT pBoundingRect, LPRECT pContentRect)
139 {
140     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeBackgroundContentRect, TEXT("uxtheme.dll"), "GetThemeBackgroundContentRect"))
141         return E_FAIL;
142     return s_fnGetThemeBackgroundContentRect(m_hTheme, hDC, m_iPartId, iStateId, pBoundingRect, pContentRect);
143 }
144 
145 STDMETHODIMP
GetThemeTextExtent(HDC hDC,int iStateId,LPCWSTR pszText,int cchCharCount,DWORD dwTextFlags,LPCRECT pBoundingRect,LPRECT pExtentRect)146 CUIFTheme::GetThemeTextExtent(HDC hDC, int iStateId, LPCWSTR pszText, int cchCharCount, DWORD dwTextFlags, LPCRECT pBoundingRect, LPRECT pExtentRect)
147 {
148     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeTextExtent, TEXT("uxtheme.dll"), "GetThemeTextExtent"))
149         return E_FAIL;
150     return s_fnGetThemeTextExtent(m_hTheme, hDC, m_iPartId, iStateId, pszText, cchCharCount, dwTextFlags, pBoundingRect, pExtentRect);
151 }
152 
153 STDMETHODIMP
GetThemePartSize(HDC hDC,int iStateId,LPRECT prc,THEMESIZE eSize,SIZE * psz)154 CUIFTheme::GetThemePartSize(HDC hDC, int iStateId, LPRECT prc, THEMESIZE eSize, SIZE *psz)
155 {
156     if (!cicGetFN(s_hUXTHEME, s_fnGetThemePartSize, TEXT("uxtheme.dll"), "GetThemePartSize"))
157         return E_FAIL;
158     return s_fnGetThemePartSize(m_hTheme, hDC, m_iPartId, iStateId, prc, eSize, psz);
159 }
160 
161 STDMETHODIMP
DrawThemeEdge(HDC hDC,int iStateId,LPCRECT pDestRect,UINT uEdge,UINT uFlags,LPRECT pContentRect)162 CUIFTheme::DrawThemeEdge(HDC hDC, int iStateId, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect)
163 {
164     if (!cicGetFN(s_hUXTHEME, s_fnDrawThemeEdge, TEXT("uxtheme.dll"), "DrawThemeEdge"))
165         return E_FAIL;
166     return s_fnDrawThemeEdge(m_hTheme, hDC, m_iPartId, iStateId, pDestRect, uEdge, uFlags, pContentRect);
167 }
168 
169 STDMETHODIMP
GetThemeColor(int iStateId,int iPropId,COLORREF * pColor)170 CUIFTheme::GetThemeColor(int iStateId, int iPropId, COLORREF *pColor)
171 {
172     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeColor, TEXT("uxtheme.dll"), "GetThemeColor"))
173         return E_FAIL;
174     return s_fnGetThemeColor(m_hTheme, m_iPartId, iStateId, iPropId, pColor);
175 }
176 
177 STDMETHODIMP
GetThemeMargins(HDC hDC,int iStateId,int iPropId,LPRECT prc,MARGINS * pMargins)178 CUIFTheme::GetThemeMargins(HDC hDC, int iStateId, int iPropId, LPRECT prc, MARGINS *pMargins)
179 {
180     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeMargins, TEXT("uxtheme.dll"), "GetThemeMargins"))
181         return E_FAIL;
182     return s_fnGetThemeMargins(m_hTheme, hDC, m_iPartId, iStateId, iPropId, prc, pMargins);
183 }
184 
185 STDMETHODIMP
GetThemeFont(HDC hDC,int iStateId,int iPropId,LOGFONTW * pFont)186 CUIFTheme::GetThemeFont(HDC hDC, int iStateId, int iPropId, LOGFONTW *pFont)
187 {
188     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeFont, TEXT("uxtheme.dll"), "GetThemeFont"))
189         return E_FAIL;
190     return s_fnGetThemeFont(m_hTheme, hDC, m_iPartId, iStateId, iPropId, pFont);
191 }
192 
STDMETHODIMP_(COLORREF)193 STDMETHODIMP_(COLORREF)
194 CUIFTheme::GetThemeSysColor(INT iColorId)
195 {
196     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeSysColor, TEXT("uxtheme.dll"), "GetThemeSysColor"))
197         return RGB(0, 0, 0);
198     return s_fnGetThemeSysColor(m_hTheme, iColorId);
199 }
200 
STDMETHODIMP_(int)201 STDMETHODIMP_(int)
202 CUIFTheme::GetThemeSysSize(int iSizeId)
203 {
204     if (!cicGetFN(s_hUXTHEME, s_fnGetThemeSysSize, TEXT("uxtheme.dll"), "GetThemeSysSize"))
205         return 0;
206     return s_fnGetThemeSysSize(m_hTheme, iSizeId);
207 }
208 
STDMETHODIMP_(void)209 STDMETHODIMP_(void)
210 CUIFTheme::SetActiveTheme(LPCWSTR pszClassList, INT iPartId, INT iStateId)
211 {
212     m_iPartId = iPartId;
213     m_iStateId = iStateId;
214     m_pszClassList = pszClassList;
215 }
216 
217 /////////////////////////////////////////////////////////////////////////////
218 // CUIFObject
219 
220 /// @unimplemented
CUIFObject(CUIFObject * pParent,DWORD nObjectID,LPCRECT prc,DWORD style)221 CUIFObject::CUIFObject(CUIFObject *pParent, DWORD nObjectID, LPCRECT prc, DWORD style)
222 {
223     m_pszClassList = NULL;
224     m_hTheme = NULL;
225     m_pParent = pParent;
226     m_nObjectID = nObjectID;
227     m_style = style;
228 
229     if (prc)
230         m_rc = *prc;
231     else
232         m_rc = { 0, 0, 0, 0 };
233 
234     if (m_pParent)
235     {
236         m_pWindow = m_pParent->m_pWindow;
237         m_pScheme = m_pParent->m_pScheme;
238     }
239     else
240     {
241         m_pWindow = NULL;
242         m_pScheme = NULL;
243     }
244 
245     m_bEnable = m_bVisible = TRUE;
246 
247     m_hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
248     m_bHasCustomFont = FALSE;
249 
250     m_pszToolTip = NULL;
251 
252     m_dwUnknown4[0] = -1; //FIXME: name
253     m_dwUnknown4[1] = -1; //FIXME: name
254 }
255 
~CUIFObject()256 CUIFObject::~CUIFObject()
257 {
258     if (m_pWindow)
259     {
260         CUIFToolTip *pToolTip = m_pWindow->m_pToolTip;
261         if (pToolTip && pToolTip->m_pToolTipTarget == this)
262             pToolTip->m_pToolTipTarget = NULL;
263     }
264 
265     if (m_pszToolTip)
266     {
267         delete[] m_pszToolTip;
268         m_pszToolTip = NULL;
269     }
270 
271     for (size_t iObj = m_ObjectArray.size(); iObj > 0; )
272     {
273         --iObj;
274         delete m_ObjectArray[iObj];
275     }
276     m_ObjectArray.clear();
277 
278     if (m_pWindow)
279         m_pWindow->RemoveUIObj(this);
280 
281     CloseThemeData();
282 }
283 
STDMETHODIMP_(void)284 STDMETHODIMP_(void) CUIFObject::OnPaint(HDC hDC)
285 {
286     if (!(m_pWindow->m_style & UIF_WINDOW_ENABLETHEMED) || !OnPaintTheme(hDC))
287         OnPaintNoTheme(hDC);
288 }
289 
STDMETHODIMP_(BOOL)290 STDMETHODIMP_(BOOL) CUIFObject::OnSetCursor(UINT uMsg, LONG x, LONG y)
291 {
292     return FALSE;
293 }
294 
STDMETHODIMP_(void)295 STDMETHODIMP_(void) CUIFObject::GetRect(LPRECT prc)
296 {
297     *prc = m_rc;
298 }
299 
STDMETHODIMP_(BOOL)300 STDMETHODIMP_(BOOL) CUIFObject::PtInObject(POINT pt)
301 {
302     return m_bVisible && ::PtInRect(&m_rc, pt);
303 }
304 
STDMETHODIMP_(void)305 STDMETHODIMP_(void) CUIFObject::PaintObject(HDC hDC, LPCRECT prc)
306 {
307     if (!m_bVisible)
308         return;
309 
310     if (!prc)
311         prc = &m_rc;
312 
313     OnPaint(hDC);
314 
315     for (size_t iItem = 0; iItem < m_ObjectArray.size(); ++iItem)
316     {
317         CUIFObject *pObject = m_ObjectArray[iItem];
318         RECT rc;
319         if (::IntersectRect(&rc, prc, &pObject->m_rc))
320             pObject->PaintObject(hDC, &rc);
321     }
322 }
323 
STDMETHODIMP_(void)324 STDMETHODIMP_(void) CUIFObject::CallOnPaint()
325 {
326     if (m_pWindow)
327         m_pWindow->UpdateUI(&m_rc);
328 }
329 
STDMETHODIMP_(void)330 STDMETHODIMP_(void) CUIFObject::Enable(BOOL bEnable)
331 {
332     if (m_bEnable == bEnable)
333         return;
334 
335     m_bEnable = bEnable;
336     for (size_t iItem = 0; iItem < m_ObjectArray.size(); ++iItem)
337         m_ObjectArray[iItem]->Enable(bEnable);
338 
339     CallOnPaint();
340 }
341 
STDMETHODIMP_(void)342 STDMETHODIMP_(void) CUIFObject::Show(BOOL bVisible)
343 {
344     if (m_bVisible == bVisible)
345         return;
346 
347     m_bVisible = bVisible;
348     for (size_t iItem = 0; iItem < m_ObjectArray.size(); ++iItem)
349         m_ObjectArray[iItem]->Show(bVisible);
350 
351     if (m_bVisible || m_pParent)
352         m_pParent->CallOnPaint();
353 }
354 
STDMETHODIMP_(void)355 STDMETHODIMP_(void) CUIFObject::SetFontToThis(HFONT hFont)
356 {
357     m_bHasCustomFont = !!hFont;
358     if (!hFont)
359         hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
360     m_hFont = hFont;
361 }
362 
STDMETHODIMP_(void)363 STDMETHODIMP_(void) CUIFObject::SetFont(HFONT hFont)
364 {
365     SetFontToThis(hFont);
366 
367     for (size_t iItem = 0; iItem < m_ObjectArray.size(); ++iItem)
368         m_ObjectArray[iItem]->SetFont(hFont);
369 
370     CallOnPaint();
371 }
372 
STDMETHODIMP_(void)373 STDMETHODIMP_(void) CUIFObject::SetStyle(DWORD style)
374 {
375     m_style = style;
376 }
377 
STDMETHODIMP_(void)378 STDMETHODIMP_(void) CUIFObject::AddUIObj(CUIFObject *pObject)
379 {
380     m_ObjectArray.Add(pObject);
381     CallOnPaint();
382 }
383 
STDMETHODIMP_(void)384 STDMETHODIMP_(void) CUIFObject::RemoveUIObj(CUIFObject *pObject)
385 {
386     if (m_ObjectArray.Remove(pObject))
387         CallOnPaint();
388 }
389 
STDMETHODIMP_(LRESULT)390 STDMETHODIMP_(LRESULT) CUIFObject::OnObjectNotify(CUIFObject *pObject, WPARAM wParam, LPARAM lParam)
391 {
392     if (m_pParent)
393         return m_pParent->OnObjectNotify(pObject, wParam, lParam);
394     return 0;
395 }
396 
STDMETHODIMP_(void)397 STDMETHODIMP_(void) CUIFObject::SetToolTip(LPCWSTR pszToolTip)
398 {
399     if (m_pszToolTip)
400     {
401         delete[] m_pszToolTip;
402         m_pszToolTip = NULL;
403     }
404 
405     if (pszToolTip)
406     {
407         size_t cch = wcslen(pszToolTip);
408         m_pszToolTip = new(cicNoThrow) WCHAR[cch + 1];
409         if (m_pszToolTip)
410             lstrcpynW(m_pszToolTip, pszToolTip, cch + 1);
411     }
412 }
413 
STDMETHODIMP_(void)414 STDMETHODIMP_(void) CUIFObject::ClearWndObj()
415 {
416     m_pWindow = NULL;
417     for (size_t iItem = 0; iItem < m_ObjectArray.size(); ++iItem)
418         m_ObjectArray[iItem]->ClearWndObj();
419 }
420 
STDMETHODIMP_(void)421 STDMETHODIMP_(void) CUIFObject::ClearTheme()
422 {
423     CloseThemeData();
424     for (size_t iItem = 0; iItem < m_ObjectArray.size(); ++iItem)
425         m_ObjectArray[iItem]->ClearTheme();
426 }
427 
StartCapture()428 void CUIFObject::StartCapture()
429 {
430     if (m_pWindow)
431         m_pWindow->SetCaptureObject(this);
432 }
433 
EndCapture()434 void CUIFObject::EndCapture()
435 {
436     if (m_pWindow)
437         m_pWindow->SetCaptureObject(NULL);
438 }
439 
IsCapture()440 BOOL CUIFObject::IsCapture()
441 {
442     return m_pWindow && (m_pWindow->m_pCaptured == this);
443 }
444 
SetRect(LPCRECT prc)445 void CUIFObject::SetRect(LPCRECT prc)
446 {
447     m_rc = *prc;
448     if (m_pWindow)
449         m_pWindow->OnObjectMoved(this);
450     CallOnPaint();
451 }
452 
NotifyCommand(WPARAM wParam,LPARAM lParam)453 LRESULT CUIFObject::NotifyCommand(WPARAM wParam, LPARAM lParam)
454 {
455     if (m_pParent)
456         return m_pParent->OnObjectNotify(this, wParam, lParam);
457     return 0;
458 }
459 
DetachWndObj()460 void CUIFObject::DetachWndObj()
461 {
462     if (m_pWindow)
463     {
464         CUIFToolTip *pToolTip = m_pWindow->m_pToolTip;
465         if (pToolTip && pToolTip->m_pToolTipTarget == this)
466             pToolTip->m_pToolTipTarget = NULL;
467 
468         m_pWindow->RemoveUIObj(this);
469         m_pWindow = NULL;
470     }
471 }
472 
IsRTL()473 BOOL CUIFObject::IsRTL()
474 {
475     if (!m_pWindow)
476         return FALSE;
477     return !!(m_pWindow->m_style & UIF_WINDOW_LAYOUTRTL);
478 }
479 
ObjectFromPoint(POINT pt)480 CUIFObject* CUIFObject::ObjectFromPoint(POINT pt)
481 {
482     if (!PtInObject(pt))
483         return NULL;
484 
485     CUIFObject *pFound = this;
486     for (size_t i = 0; i < m_ObjectArray.size(); ++i)
487     {
488         CUIFObject *pObject = m_ObjectArray[i]->ObjectFromPoint(pt);
489         if (pObject)
490             pFound = pObject;
491     }
492     return pFound;
493 }
494 
SetScheme(CUIFScheme * scheme)495 void CUIFObject::SetScheme(CUIFScheme *scheme)
496 {
497     m_pScheme = scheme;
498     for (size_t i = 0; i < m_ObjectArray.size(); ++i)
499     {
500         m_ObjectArray[i]->SetScheme(scheme);
501     }
502 }
503 
StartTimer(WPARAM wParam)504 void CUIFObject::StartTimer(WPARAM wParam)
505 {
506     if (m_pWindow)
507         m_pWindow->SetTimerObject(this, wParam);
508 }
509 
EndTimer()510 void CUIFObject::EndTimer()
511 {
512     if (m_pWindow)
513         m_pWindow->SetTimerObject(NULL, 0);
514 }
515 
516 /////////////////////////////////////////////////////////////////////////////
517 // CUIFColorTable...
518 
STDMETHODIMP_(void)519 STDMETHODIMP_(void) CUIFColorTableSys::InitColor()
520 {
521     m_rgbColors[0] = ::GetSysColor(COLOR_BTNFACE);
522     m_rgbColors[1] = ::GetSysColor(COLOR_BTNSHADOW);
523     m_rgbColors[2] = ::GetSysColor(COLOR_ACTIVEBORDER);
524     m_rgbColors[3] = ::GetSysColor(COLOR_ACTIVECAPTION);
525     m_rgbColors[4] = ::GetSysColor(COLOR_BTNFACE);
526     m_rgbColors[5] = ::GetSysColor(COLOR_BTNSHADOW);
527     m_rgbColors[6] = ::GetSysColor(COLOR_BTNTEXT);
528     m_rgbColors[7] = ::GetSysColor(COLOR_CAPTIONTEXT);
529     m_rgbColors[8] = ::GetSysColor(COLOR_GRAYTEXT);
530     m_rgbColors[9] = ::GetSysColor(COLOR_HIGHLIGHT);
531     m_rgbColors[10] = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
532     m_rgbColors[11] = ::GetSysColor(COLOR_INACTIVECAPTION);
533     m_rgbColors[12] = ::GetSysColor(COLOR_INACTIVECAPTIONTEXT);
534     m_rgbColors[13] = ::GetSysColor(COLOR_MENUTEXT);
535     m_rgbColors[14] = ::GetSysColor(COLOR_WINDOW);
536     m_rgbColors[15] = ::GetSysColor(COLOR_WINDOWTEXT);
537 }
538 
STDMETHODIMP_(void)539 STDMETHODIMP_(void) CUIFColorTableSys::InitBrush()
540 {
541     ZeroMemory(m_hBrushes, sizeof(m_hBrushes));
542 }
543 
STDMETHODIMP_(void)544 STDMETHODIMP_(void) CUIFColorTableSys::DoneBrush()
545 {
546     for (size_t i = 0; i < _countof(m_hBrushes); ++i)
547     {
548         if (m_hBrushes[i])
549         {
550             ::DeleteObject(m_hBrushes[i]);
551             m_hBrushes[i] = NULL;
552         }
553     }
554 }
555 
GetBrush(INT iColor)556 HBRUSH CUIFColorTableSys::GetBrush(INT iColor)
557 {
558     if (!m_hBrushes[iColor])
559         m_hBrushes[iColor] = ::CreateSolidBrush(m_rgbColors[iColor]);
560     return m_hBrushes[iColor];
561 }
562 
GetBrush(INT iColor)563 HBRUSH CUIFColorTableOff10::GetBrush(INT iColor)
564 {
565     if (!m_hBrushes[iColor])
566         m_hBrushes[iColor] = ::CreateSolidBrush(m_rgbColors[iColor]);
567     return m_hBrushes[iColor];
568 }
569 
570 /// @unimplemented
STDMETHODIMP_(void)571 STDMETHODIMP_(void) CUIFColorTableOff10::InitColor()
572 {
573     m_rgbColors[0] = ::GetSysColor(COLOR_BTNFACE);
574     m_rgbColors[1] = ::GetSysColor(COLOR_WINDOW);
575     m_rgbColors[2] = ::GetSysColor(COLOR_WINDOW);
576     m_rgbColors[3] = ::GetSysColor(COLOR_BTNFACE);
577     m_rgbColors[4] = ::GetSysColor(COLOR_BTNSHADOW);
578     m_rgbColors[5] = ::GetSysColor(COLOR_WINDOW);
579     m_rgbColors[6] = ::GetSysColor(COLOR_HIGHLIGHT);
580     m_rgbColors[7] = ::GetSysColor(COLOR_WINDOWTEXT);
581     m_rgbColors[8] = ::GetSysColor(COLOR_HIGHLIGHT);
582     m_rgbColors[9] = ::GetSysColor(COLOR_HIGHLIGHT);
583     m_rgbColors[10] = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
584     m_rgbColors[11] = ::GetSysColor(COLOR_BTNFACE);
585     m_rgbColors[12] = ::GetSysColor(COLOR_BTNTEXT);
586     m_rgbColors[13] = ::GetSysColor(COLOR_BTNSHADOW);
587     m_rgbColors[14] = ::GetSysColor(COLOR_BTNFACE);
588     m_rgbColors[15] = ::GetSysColor(COLOR_WINDOW);
589     m_rgbColors[16] = ::GetSysColor(COLOR_HIGHLIGHT);
590     m_rgbColors[17] = ::GetSysColor(COLOR_BTNTEXT);
591     m_rgbColors[18] = ::GetSysColor(COLOR_WINDOW);
592     m_rgbColors[19] = ::GetSysColor(COLOR_BTNSHADOW);
593     m_rgbColors[20] = ::GetSysColor(COLOR_BTNFACE);
594     m_rgbColors[21] = ::GetSysColor(COLOR_BTNSHADOW);
595     m_rgbColors[22] = ::GetSysColor(COLOR_BTNFACE);
596     m_rgbColors[23] = ::GetSysColor(COLOR_BTNSHADOW);
597     m_rgbColors[24] = ::GetSysColor(COLOR_CAPTIONTEXT);
598     m_rgbColors[25] = ::GetSysColor(COLOR_HIGHLIGHT);
599     m_rgbColors[26] = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
600     m_rgbColors[27] = ::GetSysColor(COLOR_BTNFACE);
601     m_rgbColors[28] = ::GetSysColor(COLOR_BTNTEXT);
602     m_rgbColors[29] = ::GetSysColor(COLOR_BTNSHADOW);
603     m_rgbColors[30] = ::GetSysColor(COLOR_BTNTEXT);
604     m_rgbColors[31] = ::GetSysColor(COLOR_WINDOWTEXT);
605 }
606 
STDMETHODIMP_(void)607 STDMETHODIMP_(void) CUIFColorTableOff10::InitBrush()
608 {
609     ZeroMemory(m_hBrushes, sizeof(m_hBrushes));
610 }
611 
STDMETHODIMP_(void)612 STDMETHODIMP_(void) CUIFColorTableOff10::DoneBrush()
613 {
614     for (size_t i = 0; i < _countof(m_hBrushes); ++i)
615     {
616         if (m_hBrushes[i])
617         {
618             ::DeleteObject(m_hBrushes[i]);
619             m_hBrushes[i] = NULL;
620         }
621     }
622 }
623 
624 /////////////////////////////////////////////////////////////////////////////
625 // CUIFScheme
626 
627 /// @unimplemented
cicCreateUIFScheme(DWORD type)628 CUIFScheme *cicCreateUIFScheme(DWORD type)
629 {
630 #if 1
631     return new(cicNoThrow) CUIFSchemeDef(type);
632 #else
633     switch (type)
634     {
635         case 1:  return new(cicNoThrow) CUIFSchemeOff10(1);
636         case 2:  return new(cicNoThrow) CUIFSchemeOff10(2);
637         case 3:  return new(cicNoThrow) CUIFSchemeOff10(3);
638         default: return new(cicNoThrow) CUIFSchemeDef(type);
639     }
640 #endif
641 }
642 
STDMETHODIMP_(DWORD)643 STDMETHODIMP_(DWORD) CUIFSchemeDef::GetType()
644 {
645     return m_dwType;
646 }
647 
STDMETHODIMP_(COLORREF)648 STDMETHODIMP_(COLORREF) CUIFSchemeDef::GetColor(INT iColor)
649 {
650     return s_pColorTableSys->GetColor(iColor);
651 }
652 
STDMETHODIMP_(HBRUSH)653 STDMETHODIMP_(HBRUSH) CUIFSchemeDef::GetBrush(INT iColor)
654 {
655     return s_pColorTableSys->GetBrush(iColor);
656 }
657 
STDMETHODIMP_(INT)658 STDMETHODIMP_(INT) CUIFSchemeDef::CyMenuItem(INT cyText)
659 {
660     return cyText + 2;
661 }
662 
STDMETHODIMP_(INT)663 STDMETHODIMP_(INT) CUIFSchemeDef::CxSizeFrame()
664 {
665     return ::GetSystemMetrics(SM_CXSIZEFRAME);
666 }
667 
STDMETHODIMP_(INT)668 STDMETHODIMP_(INT) CUIFSchemeDef::CySizeFrame()
669 {
670     return ::GetSystemMetrics(SM_CYSIZEFRAME);
671 }
672 
STDMETHODIMP_(void)673 STDMETHODIMP_(void) CUIFScheme::FillRect(HDC hDC, LPCRECT prc, INT iColor)
674 {
675     ::FillRect(hDC, prc, GetBrush(iColor));
676 }
677 
STDMETHODIMP_(void)678 STDMETHODIMP_(void) CUIFScheme::FrameRect(HDC hDC, LPCRECT prc, INT iColor)
679 {
680     ::FrameRect(hDC, prc, GetBrush(iColor));
681 }
682 
STDMETHODIMP_(void)683 STDMETHODIMP_(void) CUIFSchemeDef::DrawSelectionRect(HDC hDC, LPCRECT prc, int)
684 {
685     ::FillRect(hDC, prc, GetBrush(6));
686 }
687 
STDMETHODIMP_(void)688 STDMETHODIMP_(void)
689 CUIFSchemeDef::GetCtrlFaceOffset(DWORD dwUnknownFlags, DWORD dwDrawFlags, LPSIZE pSize)
690 {
691     if (!(dwDrawFlags & UIF_DRAW_PRESSED))
692     {
693         if (dwDrawFlags & 0x2)
694         {
695             if (dwUnknownFlags & 0x10)
696             {
697                 pSize->cx = pSize->cy = -1;
698                 return;
699             }
700             pSize->cx = pSize->cy = !!(dwUnknownFlags & 0x20);
701         }
702         else
703         {
704             if (!(dwDrawFlags & 0x1))
705             {
706                 pSize->cx = pSize->cy = -((dwUnknownFlags & 1) != 0);
707                 return;
708             }
709             if (dwUnknownFlags & 0x4)
710             {
711                 pSize->cx = pSize->cy = -1;
712                 return;
713             }
714             pSize->cx = pSize->cy = !!(dwUnknownFlags & 0x8);
715         }
716         return;
717     }
718 
719     if (!(dwUnknownFlags & 0x40))
720     {
721         pSize->cx = pSize->cy = !!(dwUnknownFlags & 0x80);
722         return;
723     }
724 
725     pSize->cx = pSize->cy = -1;
726 }
727 
STDMETHODIMP_(void)728 STDMETHODIMP_(void)
729 CUIFSchemeDef::DrawCtrlBkgd(HDC hDC, LPCRECT prc, DWORD dwUnknownFlags, DWORD dwDrawFlags)
730 {
731     ::FillRect(hDC, prc, GetBrush(9));
732 
733     if (!(dwDrawFlags & UIF_DRAW_PRESSED) && (dwDrawFlags & 0x2))
734         return;
735 
736     HBRUSH hbrDither = cicCreateDitherBrush();
737     if (!hbrDither)
738         return;
739 
740     COLORREF rgbOldText = ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNFACE));
741     COLORREF rgbOldBack = ::SetBkColor(hDC, ::GetSysColor(COLOR_BTNHIGHLIGHT));
742 
743     RECT rc = *prc;
744     ::InflateRect(&rc, -2, -2);
745     ::FillRect(hDC, &rc, hbrDither);
746     ::SetTextColor(hDC, rgbOldText);
747     ::SetBkColor(hDC, rgbOldBack);
748     ::DeleteObject(hbrDither);
749 }
750 
STDMETHODIMP_(void)751 STDMETHODIMP_(void)
752 CUIFSchemeDef::DrawCtrlEdge(
753     HDC hDC,
754     LPCRECT prc,
755     DWORD dwUnknownFlags,
756     DWORD dwDrawFlags)
757 {
758     UINT uEdge = BDR_RAISEDINNER;
759 
760     if (dwDrawFlags & 0x10)
761     {
762         if (!(dwUnknownFlags & 0x40))
763         {
764             if (dwUnknownFlags & 0x80)
765                 uEdge = BDR_SUNKENOUTER;
766             else
767                 return;
768         }
769     }
770     else if (dwDrawFlags & 0x2)
771     {
772         if (!(dwUnknownFlags & 0x10))
773         {
774             if (dwUnknownFlags & 0x20)
775                 uEdge = BDR_SUNKENOUTER;
776             else
777                 return;
778         }
779     }
780     else if (dwDrawFlags & 0x1)
781     {
782         if (!(dwUnknownFlags & 0x4))
783         {
784             if (dwUnknownFlags & 0x8)
785                 uEdge = BDR_SUNKENOUTER;
786             else
787                 return;
788         }
789     }
790     else if (!(dwUnknownFlags & 0x1))
791     {
792         return;
793     }
794 
795     RECT rc = *prc;
796     ::DrawEdge(hDC, &rc, uEdge, BF_RECT);
797 }
798 
STDMETHODIMP_(void)799 STDMETHODIMP_(void)
800 CUIFSchemeDef::DrawCtrlText(
801     HDC hDC,
802     LPCRECT prc,
803     LPCWSTR pszText,
804     INT cchText,
805     DWORD dwDrawFlags,
806     BOOL bRight)
807 {
808     COLORREF rgbOldText = ::GetTextColor(hDC);
809     INT OldBkMode = ::SetBkMode(hDC, TRANSPARENT);
810 
811     if (cchText == -1)
812         cchText = lstrlenW(pszText);
813 
814     RECT rc = *prc;
815     if (dwDrawFlags & UIF_DRAW_DISABLED)
816     {
817         ::OffsetRect(&rc, 1, 1);
818         ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNHIGHLIGHT));
819         ::ExtTextOutW(hDC, (bRight ? rc.right : rc.left), rc.top, ETO_CLIPPED, &rc,
820                       pszText, cchText, NULL);
821         ::OffsetRect(&rc, -1, -1);
822     }
823 
824     ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNTEXT));
825     ::ExtTextOutW(hDC, (bRight ? rc.right : rc.left), rc.top, ETO_CLIPPED, &rc,
826                   pszText, cchText, NULL);
827 
828     ::SetTextColor(hDC, rgbOldText);
829     ::SetBkMode(hDC, OldBkMode);
830 }
831 
STDMETHODIMP_(void)832 STDMETHODIMP_(void)
833 CUIFSchemeDef::DrawCtrlIcon(HDC hDC, LPCRECT prc, HICON hIcon, DWORD dwDrawFlags, LPSIZE pSize)
834 {
835     if (m_bMirroring)
836     {
837         HBITMAP hbm1, hbm2;
838         if (cicGetIconBitmaps(hIcon, &hbm1, &hbm2, pSize))
839         {
840             DrawCtrlBitmap(hDC, prc, hbm1, hbm2, dwDrawFlags);
841             ::DeleteObject(hbm1);
842             ::DeleteObject(hbm2);
843         }
844     }
845     else
846     {
847         UINT uFlags = DST_PREFIXTEXT | DST_TEXT;
848         if (dwDrawFlags & UIF_DRAW_DISABLED)
849             uFlags |= (DSS_MONO | DSS_DISABLED);
850         ::DrawState(hDC, 0, 0, (LPARAM)hIcon, 0, prc->left, prc->top, 0, 0, uFlags);
851     }
852 }
853 
STDMETHODIMP_(void)854 STDMETHODIMP_(void)
855 CUIFSchemeDef::DrawCtrlBitmap(HDC hDC, LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2, DWORD dwDrawFlags)
856 {
857     if (m_bMirroring)
858     {
859         hbm1 = cicMirrorBitmap(hbm1, GetBrush(9));
860         hbm2 = cicMirrorBitmap(hbm2, (HBRUSH)GetStockObject(BLACK_BRUSH));
861     }
862 
863     HBRUSH hBrush = (HBRUSH)UlongToHandle(COLOR_BTNFACE + 1);
864     BOOL bBrushCreated = FALSE;
865     if (hbm2)
866     {
867         HBITMAP hBitmap = NULL;
868         if (dwDrawFlags & UIF_DRAW_DISABLED)
869         {
870             hBitmap = cicCreateDisabledBitmap(prc, hbm2, GetBrush(9), GetBrush(11), TRUE);
871         }
872         else
873         {
874             if ((dwDrawFlags & UIF_DRAW_PRESSED) && !(dwDrawFlags & 0x2))
875             {
876                 hBrush = cicCreateDitherBrush();
877                 bBrushCreated = TRUE;
878             }
879 
880             COLORREF rgbFace = ::GetSysColor(COLOR_BTNFACE);
881             COLORREF rgbHighlight = ::GetSysColor(COLOR_BTNHIGHLIGHT);
882             hBitmap = cicCreateMaskBmp(prc, hbm1, hbm2, hBrush, rgbFace, rgbHighlight);
883         }
884 
885         if (hBitmap)
886         {
887             ::DrawState(hDC, NULL, NULL, (LPARAM)hBitmap, 0,
888                         prc->left, prc->top,
889                         prc->right - prc->left, prc->bottom - prc->top,
890                         DST_BITMAP);
891             ::DeleteObject(hBitmap);
892         }
893     }
894     else
895     {
896         UINT uFlags = DST_BITMAP;
897         if (dwDrawFlags & UIF_DRAW_DISABLED)
898             uFlags |= (DSS_MONO | DSS_DISABLED);
899 
900         ::DrawState(hDC, NULL, NULL, (LPARAM)hbm1, 0,
901                     prc->left, prc->top,
902                     prc->right - prc->left, prc->bottom - prc->top,
903                     uFlags);
904     }
905 
906     if (bBrushCreated)
907         ::DeleteObject(hBrush);
908 
909     if (m_bMirroring)
910     {
911         ::DeleteObject(hbm1);
912         ::DeleteObject(hbm2);
913     }
914 }
915 
STDMETHODIMP_(void)916 STDMETHODIMP_(void)
917 CUIFSchemeDef::DrawMenuBitmap(HDC hDC, LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2, DWORD dwDrawFlags)
918 {
919     DrawCtrlBitmap(hDC, prc, hbm1, hbm2, dwDrawFlags);
920 }
921 
STDMETHODIMP_(void)922 STDMETHODIMP_(void)
923 CUIFSchemeDef::DrawMenuSeparator(HDC hDC, LPCRECT prc)
924 {
925     RECT rc = *prc;
926     rc.bottom = rc.top + (rc.bottom - rc.top) / 2;
927     ::FillRect(hDC, &rc, (HBRUSH)UlongToHandle(COLOR_BTNSHADOW + 1));
928 
929     rc = *prc;
930     rc.top += (rc.bottom - rc.top) / 2;
931     ::FillRect(hDC, &rc, (HBRUSH)UlongToHandle(COLOR_BTNHIGHLIGHT + 1));
932 }
933 
STDMETHODIMP_(void)934 STDMETHODIMP_(void)
935 CUIFSchemeDef::DrawFrameCtrlBkgd(HDC hDC, LPCRECT prc, DWORD dwUnknownFlags, DWORD dwDrawFlags)
936 {
937     DrawCtrlBkgd(hDC, prc, dwUnknownFlags, dwDrawFlags);
938 }
939 
STDMETHODIMP_(void)940 STDMETHODIMP_(void)
941 CUIFSchemeDef::DrawFrameCtrlEdge(HDC hDC, LPCRECT prc, DWORD dwUnknownFlags, DWORD dwDrawFlags)
942 {
943     DrawCtrlEdge(hDC, prc, dwUnknownFlags, dwDrawFlags);
944 }
945 
STDMETHODIMP_(void)946 STDMETHODIMP_(void)
947 CUIFSchemeDef::DrawFrameCtrlIcon(HDC hDC, LPCRECT prc, HICON hIcon, DWORD dwDrawFlags, LPSIZE pSize)
948 {
949     DrawCtrlIcon(hDC, prc, hIcon, dwDrawFlags, pSize);
950 }
951 
STDMETHODIMP_(void)952 STDMETHODIMP_(void)
953 CUIFSchemeDef::DrawFrameCtrlBitmap(HDC hDC, LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2, DWORD dwDrawFlags)
954 {
955     DrawCtrlBitmap(hDC, prc, hbm1, hbm2, dwDrawFlags);
956 }
957 
STDMETHODIMP_(void)958 STDMETHODIMP_(void)
959 CUIFSchemeDef::DrawWndFrame(HDC hDC, LPCRECT prc, DWORD type, DWORD unused1, DWORD unused2)
960 {
961     RECT rc = *prc;
962     if (type && type <= 2)
963         ::DrawEdge(hDC, &rc, BDR_RAISED, BF_RECT);
964     else
965         FrameRect(hDC, &rc, 14);
966 }
967 
STDMETHODIMP_(void)968 STDMETHODIMP_(void)
969 CUIFSchemeDef::DrawDragHandle(HDC hDC, LPCRECT prc, BOOL bVertical)
970 {
971     RECT rc;
972     if (bVertical)
973         rc = { prc->left, prc->top + 1, prc->right, prc->top + 4 };
974     else
975         rc = { prc->left + 1, prc->top, prc->left + 4, prc->bottom };
976     ::DrawEdge(hDC, &rc, BDR_RAISEDINNER, BF_RECT);
977 }
978 
STDMETHODIMP_(void)979 STDMETHODIMP_(void)
980 CUIFSchemeDef::DrawSeparator(HDC hDC, LPCRECT prc, BOOL bVertical)
981 {
982     HPEN hLightPen = ::CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNHIGHLIGHT));
983     if (!hLightPen)
984         return;
985 
986     HPEN hShadowPen = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));
987     if (!hShadowPen)
988     {
989         ::DeleteObject(hLightPen);
990         return;
991     }
992 
993     HGDIOBJ hPenOld = ::SelectObject(hDC, hShadowPen);
994     if (bVertical)
995     {
996         ::MoveToEx(hDC, prc->left, prc->top + 1, NULL);
997         ::LineTo(hDC, prc->right, prc->top + 1);
998         ::SelectObject(hDC, hLightPen);
999         ::MoveToEx(hDC, prc->left, prc->top + 2, NULL);
1000         ::LineTo(hDC, prc->right, prc->top + 2);
1001     }
1002     else
1003     {
1004         ::MoveToEx(hDC, prc->left + 1, prc->top, NULL);
1005         ::LineTo(hDC, prc->left + 1, prc->bottom);
1006         ::SelectObject(hDC, hLightPen);
1007         ::MoveToEx(hDC, prc->left + 2, prc->top, NULL);
1008         ::LineTo(hDC, prc->left + 2, prc->bottom);
1009     }
1010     ::SelectObject(hDC, hPenOld);
1011 
1012     ::DeleteObject(hShadowPen);
1013     ::DeleteObject(hLightPen);
1014 }
1015 
1016 /////////////////////////////////////////////////////////////////////////////
1017 // CUIFIcon
1018 
GetImageList(BOOL bMirror)1019 HIMAGELIST CUIFIcon::GetImageList(BOOL bMirror)
1020 {
1021     if (!m_hImageList)
1022         return NULL;
1023 
1024     if (m_hIcon)
1025     {
1026         SIZE iconSize;
1027         cicGetIconSize(m_hIcon, &iconSize);
1028 
1029         UINT uFlags = ILC_COLOR32 | ILC_MASK;
1030         if (bMirror)
1031             uFlags |= ILC_MIRROR;
1032 
1033         m_hImageList = ImageList_Create(iconSize.cx, iconSize.cy, uFlags, 1, 0);
1034         if (m_hImageList)
1035             ImageList_ReplaceIcon(m_hImageList, -1, m_hIcon);
1036 
1037         return m_hImageList;
1038     }
1039 
1040     return NULL;
1041 }
1042 
1043 /////////////////////////////////////////////////////////////////////////////
1044 // CUIFBitmapDC
1045 
CUIFBitmapDC(BOOL bMemory)1046 CUIFBitmapDC::CUIFBitmapDC(BOOL bMemory)
1047 {
1048     m_hBitmap = NULL;
1049     m_hOldBitmap = NULL;
1050     m_hOldObject = NULL;
1051     if (bMemory)
1052         m_hDC = ::CreateCompatibleDC(NULL);
1053     else
1054         m_hDC = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
1055 }
1056 
~CUIFBitmapDC()1057 CUIFBitmapDC::~CUIFBitmapDC()
1058 {
1059     Uninit();
1060     ::DeleteDC(m_hDC);
1061 }
1062 
Uninit(BOOL bKeep)1063 void CUIFBitmapDC::Uninit(BOOL bKeep)
1064 {
1065     if (m_hOldBitmap)
1066     {
1067         ::SelectObject(m_hDC, m_hOldBitmap);
1068         m_hOldBitmap = NULL;
1069     }
1070 
1071     if (m_hOldObject)
1072     {
1073         ::SelectObject(m_hDC, m_hOldObject);
1074         m_hOldObject = NULL;
1075     }
1076 
1077     if (!bKeep)
1078     {
1079         if (m_hBitmap)
1080         {
1081             ::DeleteObject(m_hBitmap);
1082             m_hBitmap = NULL;
1083         }
1084     }
1085 }
1086 
SetBitmap(HBITMAP hBitmap)1087 BOOL CUIFBitmapDC::SetBitmap(HBITMAP hBitmap)
1088 {
1089     if (m_hDC)
1090         m_hOldBitmap = ::SelectObject(m_hDC, hBitmap);
1091     return TRUE;
1092 }
1093 
SetBitmap(LONG cx,LONG cy,WORD cPlanes,WORD cBitCount)1094 BOOL CUIFBitmapDC::SetBitmap(LONG cx, LONG cy, WORD cPlanes, WORD cBitCount)
1095 {
1096     m_hBitmap = ::CreateBitmap(cx, cy, cPlanes, cBitCount, 0);
1097     m_hOldBitmap = ::SelectObject(m_hDC, m_hBitmap);
1098     return TRUE;
1099 }
1100 
SetDIB(LONG cx,LONG cy,WORD cPlanes,WORD cBitCount)1101 BOOL CUIFBitmapDC::SetDIB(LONG cx, LONG cy, WORD cPlanes, WORD cBitCount)
1102 {
1103     BITMAPINFO bmi;
1104     ZeroMemory(&bmi, sizeof(bmi));
1105     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1106     bmi.bmiHeader.biWidth = cx;
1107     bmi.bmiHeader.biHeight = cy;
1108     bmi.bmiHeader.biPlanes = cPlanes;
1109     bmi.bmiHeader.biBitCount = cBitCount;
1110     bmi.bmiHeader.biCompression = BI_RGB;
1111     m_hBitmap = ::CreateDIBSection(m_hDC, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
1112     m_hOldBitmap = ::SelectObject(m_hDC, m_hBitmap);
1113     return TRUE;
1114 }
1115 
cicInitUIFUtil(void)1116 void cicInitUIFUtil(void)
1117 {
1118     if (!CUIFBitmapDC::s_phdcSrc)
1119         CUIFBitmapDC::s_phdcSrc = new(cicNoThrow) CUIFBitmapDC(TRUE);
1120 
1121     if (!CUIFBitmapDC::s_phdcMask)
1122         CUIFBitmapDC::s_phdcMask = new(cicNoThrow) CUIFBitmapDC(TRUE);
1123 
1124     if (!CUIFBitmapDC::s_phdcDst)
1125         CUIFBitmapDC::s_phdcDst = new(cicNoThrow) CUIFBitmapDC(TRUE);
1126 
1127     if (CUIFBitmapDC::s_phdcSrc && CUIFBitmapDC::s_phdcMask && CUIFBitmapDC::s_phdcDst)
1128         CUIFBitmapDC::s_fInitBitmapDCs = TRUE;
1129 }
1130 
cicDoneUIFUtil(void)1131 void cicDoneUIFUtil(void)
1132 {
1133     if (CUIFBitmapDC::s_phdcSrc)
1134     {
1135         delete CUIFBitmapDC::s_phdcSrc;
1136         CUIFBitmapDC::s_phdcSrc = NULL;
1137     }
1138 
1139     if (CUIFBitmapDC::s_phdcMask)
1140     {
1141         delete CUIFBitmapDC::s_phdcMask;
1142         CUIFBitmapDC::s_phdcMask = NULL;
1143     }
1144 
1145     if (CUIFBitmapDC::s_phdcDst)
1146     {
1147         delete CUIFBitmapDC::s_phdcDst;
1148         CUIFBitmapDC::s_phdcDst = NULL;
1149     }
1150 
1151     CUIFBitmapDC::s_fInitBitmapDCs = FALSE;
1152 }
1153 
cicMirrorBitmap(HBITMAP hBitmap,HBRUSH hbrBack)1154 HBITMAP cicMirrorBitmap(HBITMAP hBitmap, HBRUSH hbrBack)
1155 {
1156     BITMAP bm;
1157     if (!CUIFBitmapDC::s_fInitBitmapDCs || !::GetObject(hBitmap, sizeof(bm), &bm))
1158         return NULL;
1159 
1160     CUIFBitmapDC::s_phdcSrc->SetBitmap(hBitmap);
1161     CUIFBitmapDC::s_phdcDst->SetDIB(bm.bmWidth, bm.bmHeight, 1, 32);
1162     CUIFBitmapDC::s_phdcMask->SetDIB(bm.bmWidth, bm.bmHeight, 1, 32);
1163 
1164     RECT rc = { 0, 0, bm.bmWidth, bm.bmHeight };
1165     FillRect(*CUIFBitmapDC::s_phdcDst, &rc, hbrBack);
1166 
1167     ::SetLayout(*CUIFBitmapDC::s_phdcMask, LAYOUT_RTL);
1168 
1169     ::BitBlt(*CUIFBitmapDC::s_phdcMask, 0, 0, bm.bmWidth, bm.bmHeight, *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCCOPY);
1170 
1171     ::SetLayout(*CUIFBitmapDC::s_phdcMask, 0);
1172 
1173     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, bm.bmWidth, bm.bmHeight, *CUIFBitmapDC::s_phdcMask, 1, 0, SRCCOPY);
1174 
1175     CUIFBitmapDC::s_phdcSrc->Uninit();
1176     CUIFBitmapDC::s_phdcMask->Uninit();
1177     CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
1178     return CUIFBitmapDC::s_phdcDst->DetachBitmap();
1179 }
1180 
cicCreateDitherBrush(VOID)1181 HBRUSH cicCreateDitherBrush(VOID)
1182 {
1183     BYTE bytes[16];
1184     ZeroMemory(&bytes, sizeof(bytes));
1185     bytes[0] = bytes[4] = bytes[8] = bytes[12] = 0x55;
1186     bytes[2] = bytes[6] = bytes[10] = bytes[14] = 0xAA;
1187     HBITMAP hBitmap = ::CreateBitmap(8, 8, 1, 1, bytes);
1188     if (!hBitmap)
1189         return NULL;
1190 
1191     LOGBRUSH lb;
1192     lb.lbHatch = (ULONG_PTR)hBitmap;
1193     lb.lbStyle = BS_PATTERN;
1194     HBRUSH hbr = ::CreateBrushIndirect(&lb);
1195     ::DeleteObject(hBitmap);
1196     return hbr;
1197 }
1198 
1199 HBITMAP
cicCreateDisabledBitmap(LPCRECT prc,HBITMAP hbmMask,HBRUSH hbr1,HBRUSH hbr2,BOOL bPressed)1200 cicCreateDisabledBitmap(LPCRECT prc, HBITMAP hbmMask, HBRUSH hbr1, HBRUSH hbr2, BOOL bPressed)
1201 {
1202     if (!CUIFBitmapDC::s_fInitBitmapDCs)
1203         return NULL;
1204 
1205     LONG width = prc->right - prc->left, height = prc->bottom - prc->top;
1206 
1207     CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
1208     CUIFBitmapDC::s_phdcMask->SetBitmap(hbmMask);
1209     CUIFBitmapDC::s_phdcSrc->SetDIB(width, height, 1, 32);
1210 
1211     RECT rc = { 0, 0, width, height };
1212     ::FillRect(*CUIFBitmapDC::s_phdcDst, &rc, hbr1);
1213 
1214     HBRUSH hbrWhite = (HBRUSH)GetStockObject(WHITE_BRUSH);
1215     ::FillRect(*CUIFBitmapDC::s_phdcSrc, &rc, hbrWhite);
1216 
1217     ::BitBlt(*CUIFBitmapDC::s_phdcSrc, 0, 0, width, height, *CUIFBitmapDC::s_phdcMask, 0, 0, SRCINVERT);
1218     if (bPressed)
1219         ::BitBlt(*CUIFBitmapDC::s_phdcDst, 1, 1, width, height,
1220                  *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCPAINT);
1221     else
1222         ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height,
1223                  *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCPAINT);
1224 
1225     ::FillRect(*CUIFBitmapDC::s_phdcSrc, &rc, hbr2);
1226 
1227     ::BitBlt(*CUIFBitmapDC::s_phdcSrc, 0, 0, width, height, *CUIFBitmapDC::s_phdcMask, 0, 0, SRCPAINT);
1228     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCAND);
1229 
1230     CUIFBitmapDC::s_phdcSrc->Uninit();
1231     CUIFBitmapDC::s_phdcMask->Uninit();
1232     CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
1233     return CUIFBitmapDC::s_phdcDst->DetachBitmap();
1234 }
1235 
1236 HBITMAP
cicCreateShadowMaskBmp(LPRECT prc,HBITMAP hbm1,HBITMAP hbm2,HBRUSH hbr1,HBRUSH hbr2)1237 cicCreateShadowMaskBmp(LPRECT prc, HBITMAP hbm1, HBITMAP hbm2, HBRUSH hbr1, HBRUSH hbr2)
1238 {
1239     if (!CUIFBitmapDC::s_fInitBitmapDCs)
1240         return NULL;
1241 
1242     --prc->left;
1243     --prc->top;
1244 
1245     LONG width = prc->right - prc->left;
1246     LONG height = prc->bottom - prc->top;
1247 
1248     CUIFBitmapDC bitmapDC(TRUE);
1249 
1250     CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
1251     CUIFBitmapDC::s_phdcSrc->SetBitmap(hbm1);
1252     CUIFBitmapDC::s_phdcMask->SetBitmap(hbm2);
1253     bitmapDC.SetDIB(width, height, 1, 32);
1254 
1255     RECT rc = { 0, 0, width, height };
1256 
1257     ::FillRect(*CUIFBitmapDC::s_phdcDst, &rc, hbr1);
1258     ::FillRect(bitmapDC, &rc, hbr2);
1259 
1260     ::BitBlt(bitmapDC, 0, 0, width, height, *CUIFBitmapDC::s_phdcMask, 0, 0, SRCPAINT);
1261     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 2, 2, width, height, bitmapDC, 0, 0, SRCAND);
1262     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcMask, 0, 0, SRCAND);
1263     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCINVERT);
1264 
1265     CUIFBitmapDC::s_phdcSrc->Uninit();
1266     CUIFBitmapDC::s_phdcMask->Uninit();
1267     CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
1268     return CUIFBitmapDC::s_phdcDst->DetachBitmap();
1269 }
1270 
1271 HBITMAP
cicChangeBitmapColor(LPCRECT prc,HBITMAP hbm,COLORREF rgbBack,COLORREF rgbFore)1272 cicChangeBitmapColor(LPCRECT prc, HBITMAP hbm, COLORREF rgbBack, COLORREF rgbFore)
1273 {
1274     if (!CUIFBitmapDC::s_fInitBitmapDCs)
1275         return NULL;
1276 
1277     INT width = prc->right - prc->left;
1278     INT height = prc->bottom - prc->top;
1279 
1280     CUIFSolidBrush brush(rgbFore);
1281 
1282     CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
1283     CUIFBitmapDC::s_phdcSrc->SetBitmap(hbm);
1284     CUIFBitmapDC::s_phdcMask->SetBitmap(width, height, 1, 1);
1285 
1286     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCCOPY);
1287     ::SelectObject(*CUIFBitmapDC::s_phdcDst, (HBRUSH)brush);
1288     ::SetBkColor(*CUIFBitmapDC::s_phdcDst, rgbBack);
1289 
1290     ::BitBlt(*CUIFBitmapDC::s_phdcMask, 0, 0, width, height, *CUIFBitmapDC::s_phdcDst, 0, 0, MERGECOPY);
1291     ::SetBkColor(*CUIFBitmapDC::s_phdcDst, RGB(255, 255, 255));
1292     ::SetTextColor(*CUIFBitmapDC::s_phdcDst, RGB(0, 0, 0));
1293     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcMask, 0, 0, 0xE20746u);
1294 
1295     CUIFBitmapDC::s_phdcSrc->Uninit();
1296     CUIFBitmapDC::s_phdcMask->Uninit();
1297     CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
1298     return CUIFBitmapDC::s_phdcDst->DetachBitmap();
1299 }
1300 
1301 HBITMAP
cicConvertBlackBKGBitmap(LPCRECT prc,HBITMAP hbm1,HBITMAP hbm2,HBRUSH hBrush)1302 cicConvertBlackBKGBitmap(LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2, HBRUSH hBrush)
1303 {
1304     if (!CUIFBitmapDC::s_fInitBitmapDCs)
1305         return NULL;
1306 
1307     if (IS_INTRESOURCE(hBrush))
1308         hBrush = ::GetSysColorBrush(HandleToLong(hBrush) - 1);
1309 
1310     LOGBRUSH lb;
1311     ::GetObject(hBrush, sizeof(lb), &lb);
1312     if (lb.lbStyle || lb.lbColor)
1313         return NULL;
1314 
1315     INT width = prc->right - prc->left;
1316     INT height = prc->bottom - prc->top;
1317 
1318     HBITMAP hBitmap = cicChangeBitmapColor(prc, hbm1, 0, RGB(255, 255, 255));
1319     if ( !hBitmap )
1320         return NULL;
1321 
1322     CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
1323     CUIFBitmapDC::s_phdcSrc->SetBitmap(hBitmap);
1324     CUIFBitmapDC::s_phdcMask->SetBitmap(hbm2);
1325 
1326     RECT rc = { 0, 0, width, height };
1327 
1328     HBRUSH hbrWhite = (HBRUSH)GetStockObject(WHITE_BRUSH);
1329     ::FillRect(*CUIFBitmapDC::s_phdcDst, &rc, hbrWhite);
1330 
1331     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcMask, 0, 0, 0x660046u);
1332     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcSrc, 0, 0, 0x8800C6u);
1333 
1334     CUIFBitmapDC::s_phdcSrc->Uninit();
1335     CUIFBitmapDC::s_phdcMask->Uninit();
1336     CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
1337     ::DeleteObject(hBitmap);
1338     return CUIFBitmapDC::s_phdcDst->DetachBitmap();
1339 }
1340 
1341 HBITMAP
cicCreateMaskBmp(LPCRECT prc,HBITMAP hbm1,HBITMAP hbm2,HBRUSH hbr,COLORREF rgbColor,COLORREF rgbBack)1342 cicCreateMaskBmp(LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2,
1343                  HBRUSH hbr, COLORREF rgbColor, COLORREF rgbBack)
1344 {
1345     if (!CUIFBitmapDC::s_fInitBitmapDCs)
1346         return NULL;
1347 
1348     INT width = prc->right - prc->left;
1349     INT height = prc->bottom - prc->top;
1350     HBITMAP hBitmap = cicConvertBlackBKGBitmap(prc, hbm1, hbm2, hbr);
1351     if (hBitmap)
1352         return hBitmap;
1353 
1354     CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
1355     CUIFBitmapDC::s_phdcSrc->SetBitmap(hbm1);
1356     CUIFBitmapDC::s_phdcMask->SetBitmap(hbm2);
1357 
1358     RECT rc = { 0, 0, width, height };
1359 
1360     COLORREF OldTextColor = ::SetTextColor(*CUIFBitmapDC::s_phdcDst, rgbColor);
1361     COLORREF OldBkColor = ::SetBkColor(*CUIFBitmapDC::s_phdcDst, rgbBack);
1362     ::FillRect(*CUIFBitmapDC::s_phdcDst, &rc, hbr);
1363     ::SetTextColor(*CUIFBitmapDC::s_phdcDst, OldTextColor);
1364     ::SetBkColor(*CUIFBitmapDC::s_phdcDst, OldBkColor);
1365 
1366     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcMask, 0, 0, SRCAND);
1367     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCINVERT);
1368     CUIFBitmapDC::s_phdcSrc->Uninit();
1369     CUIFBitmapDC::s_phdcMask->Uninit();
1370     CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
1371 
1372     return CUIFBitmapDC::s_phdcDst->DetachBitmap();
1373 }
1374 
cicGetIconBitmaps(HICON hIcon,HBITMAP * hbm1,HBITMAP * hbm2,const SIZE * pSize)1375 BOOL cicGetIconBitmaps(HICON hIcon, HBITMAP *hbm1, HBITMAP *hbm2, const SIZE *pSize)
1376 {
1377     if (!CUIFBitmapDC::s_fInitBitmapDCs)
1378         return FALSE;
1379 
1380     SIZE size;
1381     if (pSize)
1382     {
1383         size = *pSize;
1384     }
1385     else
1386     {
1387         if (!cicGetIconSize(hIcon, &size))
1388             return FALSE;
1389     }
1390 
1391     CUIFBitmapDC::s_phdcSrc->SetDIB(size.cx, size.cy, 1, 32);
1392     CUIFBitmapDC::s_phdcMask->SetBitmap(size.cx, size.cy, 1, 1);
1393 
1394     RECT rc = { 0, 0, size.cx, size.cy };
1395     ::FillRect(*CUIFBitmapDC::s_phdcSrc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
1396 
1397     ::DrawIconEx(*CUIFBitmapDC::s_phdcSrc, 0, 0, hIcon, size.cx, size.cy, 0, 0, DI_NORMAL);
1398     ::DrawIconEx(*CUIFBitmapDC::s_phdcMask, 0, 0, hIcon, size.cx, size.cy, 0, 0, DI_MASK);
1399 
1400     CUIFBitmapDC::s_phdcSrc->Uninit(TRUE);
1401     CUIFBitmapDC::s_phdcMask->Uninit(TRUE);
1402     *hbm1 = CUIFBitmapDC::s_phdcSrc->DetachBitmap();
1403     *hbm2 = CUIFBitmapDC::s_phdcMask->DetachBitmap();
1404     return TRUE;
1405 }
1406 
cicDrawMaskBmpOnDC(HDC hDC,LPCRECT prc,HBITMAP hbmp,HBITMAP hbmpMask)1407 void cicDrawMaskBmpOnDC(HDC hDC, LPCRECT prc, HBITMAP hbmp, HBITMAP hbmpMask)
1408 {
1409     if (!CUIFBitmapDC::s_fInitBitmapDCs)
1410         return;
1411 
1412     LONG cx = prc->right - prc->left, cy = prc->bottom - prc->top;
1413     CUIFBitmapDC::s_phdcDst->SetDIB(cx, cy, 1, 32);
1414     CUIFBitmapDC::s_phdcSrc->SetBitmap(hbmp);
1415     CUIFBitmapDC::s_phdcMask->SetBitmap(hbmpMask);
1416     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, cx, cy, hDC, prc->left, prc->top, SRCCOPY);
1417     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, cx, cy, *CUIFBitmapDC::s_phdcMask, 0, 0, SRCAND);
1418     ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, cx, cy, *CUIFBitmapDC::s_phdcSrc, 0, 0, SRCINVERT);
1419     ::BitBlt(hDC, prc->left, prc->top, cx, cy, *CUIFBitmapDC::s_phdcDst, 0, 0, SRCCOPY);
1420     CUIFBitmapDC::s_phdcSrc->Uninit(FALSE);
1421     CUIFBitmapDC::s_phdcMask->Uninit(FALSE);
1422     CUIFBitmapDC::s_phdcDst->Uninit(FALSE);
1423 }
1424 
1425 /////////////////////////////////////////////////////////////////////////////
1426 // CUIFWindow
1427 
CUIFWindow(HINSTANCE hInst,DWORD style)1428 CUIFWindow::CUIFWindow(HINSTANCE hInst, DWORD style)
1429     : CUIFObject(NULL, 0, NULL, style)
1430 {
1431     m_hInst = hInst;
1432     m_nLeft = 200;
1433     m_nTop = 200;
1434     m_nWidth = 200;
1435     m_nHeight = 200;
1436     m_hWnd = 0;
1437     m_pWindow = this;
1438     m_pCaptured = NULL;
1439     m_pTimerObject = NULL;
1440     m_pPointed = NULL;
1441     m_bPointing = FALSE;
1442     m_pToolTip = NULL;
1443     m_pShadow = NULL;
1444     m_bShowShadow = TRUE;
1445     m_pBehindModal = NULL;
1446     CUIFWindow::CreateScheme();
1447 }
1448 
~CUIFWindow()1449 CUIFWindow::~CUIFWindow()
1450 {
1451     if (m_pToolTip)
1452     {
1453         delete m_pToolTip;
1454         m_pToolTip = NULL;
1455     }
1456     if (m_pShadow)
1457     {
1458         delete m_pShadow;
1459         m_pShadow = NULL;
1460     }
1461     for (size_t i = m_ObjectArray.size(); i > 0; )
1462     {
1463         --i;
1464         CUIFObject *pObject = m_ObjectArray[i];
1465         m_ObjectArray[i] = NULL;
1466         m_ObjectArray.Remove(pObject);
1467         delete pObject;
1468     }
1469     if (m_pScheme)
1470     {
1471         delete m_pScheme;
1472         m_pScheme = NULL;
1473     }
1474 }
1475 
STDMETHODIMP_(BOOL)1476 STDMETHODIMP_(BOOL)
1477 CUIFWindow::Initialize()
1478 {
1479     LPCTSTR pszClass = GetClassName();
1480 
1481     WNDCLASSEX wcx;
1482     ZeroMemory(&wcx, sizeof(wcx));
1483     wcx.cbSize = sizeof(WNDCLASSEXW);
1484     if (!::GetClassInfoEx(m_hInst, pszClass, &wcx))
1485     {
1486         ZeroMemory(&wcx, sizeof(wcx));
1487         wcx.cbSize = sizeof(wcx);
1488         wcx.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
1489         wcx.lpfnWndProc = CUIFWindow::WindowProcedure;
1490         wcx.cbClsExtra = 0;
1491         wcx.cbWndExtra = sizeof(LONG_PTR) * 2;
1492         wcx.hInstance = m_hInst;
1493         wcx.hIcon = NULL;
1494         wcx.hCursor = ::LoadCursor(NULL, IDC_ARROW);
1495         wcx.lpszClassName = pszClass;
1496         wcx.hbrBackground = NULL;
1497         wcx.lpszMenuName = NULL;
1498         wcx.hIconSm = NULL;
1499         ::RegisterClassEx(&wcx);
1500     }
1501 
1502     cicUpdateUIFSys();
1503     cicUpdateUIFScheme();
1504 
1505     if (m_style & UIF_WINDOW_TOOLTIP)
1506     {
1507         DWORD style = (m_style & UIF_WINDOW_LAYOUTRTL) | UIF_WINDOW_TOPMOST | 0x10;
1508         m_pToolTip = new(cicNoThrow) CUIFToolTip(m_hInst, style, this);
1509         if (m_pToolTip)
1510             m_pToolTip->Initialize();
1511     }
1512 
1513     if (m_style & UIF_WINDOW_SHADOW)
1514     {
1515         m_pShadow = new(cicNoThrow) CUIFShadow(m_hInst, UIF_WINDOW_TOPMOST, this);
1516         if (m_pShadow)
1517             m_pShadow->Initialize();
1518     }
1519 
1520     return CUIFObject::Initialize();
1521 }
1522 
STDMETHODIMP_(LRESULT)1523 STDMETHODIMP_(LRESULT)
1524 CUIFWindow::OnSettingChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1525 {
1526     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
1527 }
1528 
UpdateUI(LPCRECT prc)1529 void CUIFWindow::UpdateUI(LPCRECT prc)
1530 {
1531     if (::IsWindow(m_hWnd))
1532         ::InvalidateRect(m_hWnd, prc, FALSE);
1533 }
1534 
1535 CUIFWindow*
GetThis(HWND hWnd)1536 CUIFWindow::GetThis(HWND hWnd)
1537 {
1538     return (CUIFWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
1539 }
1540 
1541 void
SetThis(HWND hWnd,LONG_PTR dwNewLong)1542 CUIFWindow::SetThis(HWND hWnd, LONG_PTR dwNewLong)
1543 {
1544     ::SetWindowLongPtr(hWnd, GWLP_USERDATA, dwNewLong);
1545 }
1546 
CreateScheme()1547 void CUIFWindow::CreateScheme()
1548 {
1549     if (m_pScheme)
1550     {
1551         delete m_pScheme;
1552         m_pScheme = NULL;
1553     }
1554 
1555     INT iScheme = 0;
1556     if (m_style & UIF_WINDOW_USESCHEME1)
1557         iScheme = 1;
1558     else if (m_style & UIF_WINDOW_USESCHEME2)
1559         iScheme = 2;
1560     else if (m_style & UIF_WINDOW_USESCHEME3)
1561         iScheme = 3;
1562 
1563     m_pScheme = cicCreateUIFScheme(iScheme);
1564     SetScheme(m_pScheme);
1565 }
1566 
STDMETHODIMP_(DWORD)1567 STDMETHODIMP_(DWORD)
1568 CUIFWindow::GetWndStyle()
1569 {
1570     DWORD ret;
1571 
1572     if (m_style & UIF_WINDOW_CHILD)
1573         ret = WS_CHILD | WS_CLIPSIBLINGS;
1574     else
1575         ret = WS_POPUP | WS_DISABLED;
1576 
1577     if (m_style & UIF_WINDOW_USESCHEME1)
1578         ret |= WS_BORDER;
1579     else if (m_style & UIF_WINDOW_DLGFRAME)
1580         ret |= WS_DLGFRAME;
1581     else if ((m_style & UIF_WINDOW_USESCHEME2) || (m_style & 0x10))
1582         ret |= WS_BORDER;
1583 
1584     return ret;
1585 }
1586 
STDMETHODIMP_(DWORD)1587 STDMETHODIMP_(DWORD)
1588 CUIFWindow::GetWndStyleEx()
1589 {
1590     DWORD ret = 0;
1591     if (m_style & UIF_WINDOW_TOPMOST)
1592         ret |= WS_EX_TOPMOST;
1593     if (m_style & UIF_WINDOW_TOOLWINDOW)
1594         ret |= WS_EX_TOOLWINDOW;
1595     if (m_style & UIF_WINDOW_LAYOUTRTL)
1596         ret |= WS_EX_LAYOUTRTL;
1597     return ret;
1598 }
1599 
STDMETHODIMP_(HWND)1600 STDMETHODIMP_(HWND)
1601 CUIFWindow::CreateWnd(HWND hwndParent)
1602 {
1603     HWND hWnd = CreateWindowEx(GetWndStyleEx(), GetClassName(), GetWndTitle(), GetWndStyle(),
1604                                m_nLeft, m_nTop, m_nWidth, m_nHeight,
1605                                hwndParent, NULL, m_hInst, this);
1606     if (m_pToolTip)
1607         m_pToolTip->CreateWnd(hWnd);
1608     if (m_pShadow)
1609         m_pShadow->CreateWnd(hWnd);
1610     return hWnd;
1611 }
1612 
Show(BOOL bVisible)1613 void CUIFWindow::Show(BOOL bVisible)
1614 {
1615     if (!IsWindow(m_hWnd))
1616         return;
1617 
1618     if (bVisible && (m_style & UIF_WINDOW_TOPMOST))
1619         ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1620 
1621     m_bVisible = bVisible;
1622     ::ShowWindow(m_hWnd, (bVisible ? SW_SHOWNOACTIVATE : 0));
1623 }
1624 
STDMETHODIMP_(BOOL)1625 STDMETHODIMP_(BOOL)
1626 CUIFWindow::AnimateWnd(DWORD dwTime, DWORD dwFlags)
1627 {
1628     if (!::IsWindow(m_hWnd))
1629         return FALSE;
1630 
1631     BOOL bVisible = !(dwFlags & 0x10000);
1632     OnAnimationStart();
1633     BOOL ret = ::AnimateWindow(m_hWnd, dwTime, dwFlags);
1634     if (!ret)
1635         m_bVisible = bVisible;
1636     OnAnimationEnd();
1637     return ret;
1638 }
1639 
SetCaptureObject(CUIFObject * pCaptured)1640 void CUIFWindow::SetCaptureObject(CUIFObject *pCaptured)
1641 {
1642     if (pCaptured)
1643     {
1644         m_pCaptured = pCaptured;
1645         SetCapture(TRUE);
1646     }
1647     else
1648     {
1649         m_pCaptured = NULL;
1650         SetCapture(FALSE);
1651     }
1652 }
1653 
STDMETHODIMP_(void)1654 STDMETHODIMP_(void)
1655 CUIFWindow::SetCapture(BOOL bSet)
1656 {
1657     if (bSet)
1658         ::SetCapture(m_hWnd);
1659     else
1660         ::ReleaseCapture();
1661 }
1662 
SetObjectPointed(CUIFObject * pPointed,POINT pt)1663 void CUIFWindow::SetObjectPointed(CUIFObject *pPointed, POINT pt)
1664 {
1665     if (pPointed == m_pPointed)
1666         return;
1667 
1668     if (m_pCaptured)
1669     {
1670         if (m_pCaptured == m_pPointed && m_pPointed->m_bEnable)
1671             m_pPointed->OnMouseOut(pt.x, pt.y);
1672     }
1673     else if (m_pPointed && m_pPointed->m_bEnable)
1674     {
1675         m_pPointed->OnMouseOut(pt.x, pt.y);
1676     }
1677 
1678     m_pPointed = pPointed;
1679 
1680     if (m_pCaptured)
1681     {
1682         if (m_pCaptured == m_pPointed && m_pPointed->m_bEnable)
1683             m_pPointed->OnMouseIn(pt.x, pt.y);
1684     }
1685     else if (m_pPointed && m_pPointed->m_bEnable)
1686     {
1687         m_pPointed->OnMouseIn(pt.x, pt.y);
1688     }
1689 }
1690 
STDMETHODIMP_(void)1691 STDMETHODIMP_(void)
1692 CUIFWindow::OnObjectMoved(CUIFObject *pObject)
1693 {
1694     if (!::IsWindow(m_hWnd))
1695         return;
1696 
1697     POINT pt;
1698     ::GetCursorPos(&pt);
1699     ::ScreenToClient(m_hWnd, &pt);
1700     POINT pt2 = pt;
1701     CUIFObject *pFound = ObjectFromPoint(pt);
1702     SetObjectPointed(pFound, pt2);
1703 }
1704 
STDMETHODIMP_(void)1705 STDMETHODIMP_(void)
1706 CUIFWindow::SetRect(LPCRECT prc)
1707 {
1708     RECT Rect = { 0, 0, 0, 0 };
1709 
1710     if (::IsWindow(m_hWnd))
1711         ::GetClientRect(m_hWnd, &Rect);
1712 
1713     CUIFObject::SetRect(&Rect);
1714 }
1715 
STDMETHODIMP_(void)1716 STDMETHODIMP_(void)
1717 CUIFWindow::ClientRectToWindowRect(LPRECT lpRect)
1718 {
1719     DWORD style, exstyle;
1720     if (::IsWindow(m_hWnd))
1721     {
1722         style = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
1723         exstyle = ::GetWindowLongPtr(m_hWnd, GWL_EXSTYLE);
1724     }
1725     else
1726     {
1727         style = GetWndStyle();
1728         exstyle = GetWndStyleEx();
1729     }
1730     ::AdjustWindowRectEx(lpRect, style, FALSE, exstyle);
1731 }
1732 
STDMETHODIMP_(void)1733 STDMETHODIMP_(void)
1734 CUIFWindow::GetWindowFrameSize(LPSIZE pSize)
1735 {
1736     RECT rc = { 0, 0, 0, 0 };
1737 
1738     ClientRectToWindowRect(&rc);
1739     pSize->cx = (rc.right - rc.left) / 2;
1740     pSize->cy = (rc.bottom - rc.top) / 2;
1741 }
1742 
STDMETHODIMP_(void)1743 STDMETHODIMP_(void)
1744 CUIFWindow::OnAnimationEnd()
1745 {
1746     if (m_pShadow && m_bShowShadow)
1747         m_pShadow->Show(m_bVisible);
1748 }
1749 
STDMETHODIMP_(void)1750 STDMETHODIMP_(void)
1751 CUIFWindow::OnThemeChanged(HWND hWnd, WPARAM wParam, LPARAM lParam)
1752 {
1753     ClearTheme();
1754 }
1755 
1756 LRESULT
WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1757 CUIFWindow::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1758 {
1759     switch (uMsg)
1760     {
1761         case WM_GETOBJECT:
1762             return OnGetObject(hWnd, WM_GETOBJECT, wParam, lParam);
1763 
1764         case WM_SYSCOLORCHANGE:
1765             cicUpdateUIFScheme();
1766             OnSysColorChange();
1767             return 0;
1768 
1769         case WM_ENDSESSION:
1770             OnEndSession(hWnd, wParam, lParam);
1771             return 0;
1772 
1773         case WM_SHOWWINDOW:
1774             if (m_pShadow && m_bShowShadow)
1775                 m_pShadow->Show(wParam);
1776             return OnShowWindow(hWnd, WM_SHOWWINDOW, wParam, lParam);
1777 
1778         case WM_SETTINGCHANGE:
1779             cicUpdateUIFSys();
1780             cicUpdateUIFScheme();
1781             return OnSettingChange(hWnd, WM_SETTINGCHANGE, wParam, lParam);
1782         case WM_SETCURSOR:
1783         {
1784             POINT Point;
1785             ::GetCursorPos(&Point);
1786             ::ScreenToClient(m_hWnd, &Point);
1787 
1788             if (m_pBehindModal)
1789             {
1790                 m_pBehindModal->ModalMouseNotify(HIWORD(lParam), Point.x, Point.y);
1791                 return TRUE;
1792             }
1793 
1794             if (!m_bPointing)
1795             {
1796                 ::SetTimer(m_hWnd, POINTING_TIMER_ID, 1000, NULL);
1797                 m_bPointing = TRUE;
1798             }
1799 
1800             if (m_pToolTip)
1801             {
1802                 MSG msg = { m_hWnd, HIWORD(lParam), 0, MAKELPARAM(Point.x, Point.y) };
1803                 m_pToolTip->RelayEvent(&msg);
1804             }
1805 
1806             if (!(m_style & UIF_WINDOW_NOMOUSEMSG))
1807                 HandleMouseMsg(HIWORD(lParam), Point.x, Point.y);
1808 
1809             return TRUE;
1810         }
1811         case WM_MOUSEACTIVATE:
1812             return MA_NOACTIVATE;
1813         case WM_ERASEBKGND:
1814             return OnEraseBkGnd(hWnd, WM_ERASEBKGND, wParam, lParam);
1815         case WM_CREATE:
1816             SetRect(NULL);
1817             OnCreate(hWnd);
1818             return 0;
1819         case WM_DESTROY:
1820             if (m_pToolTip && ::IsWindow(*m_pToolTip))
1821                 ::DestroyWindow(*m_pToolTip);
1822             if (m_pShadow && ::IsWindow(*m_pShadow))
1823                 ::DestroyWindow(*m_pShadow);
1824             OnDestroy(hWnd);
1825             return 0;
1826         case WM_SIZE:
1827             SetRect(NULL);
1828             return 0;
1829         case WM_ACTIVATE:
1830             return OnActivate(hWnd, WM_ACTIVATE, wParam, lParam);
1831         case WM_SETFOCUS:
1832             OnSetFocus(hWnd);
1833             return 0;
1834         case WM_KILLFOCUS:
1835             OnKillFocus(hWnd);
1836             return 0;
1837         case WM_PAINT:
1838         {
1839             PAINTSTRUCT Paint;
1840             HDC hDC = ::BeginPaint(hWnd, &Paint);
1841             PaintObject(hDC, &Paint.rcPaint);
1842             ::EndPaint(hWnd, &Paint);
1843             return 0;
1844         }
1845         case WM_PRINTCLIENT:
1846         {
1847             PaintObject((HDC)wParam, NULL);
1848             return 0;
1849         }
1850         case WM_THEMECHANGED:
1851         {
1852             OnThemeChanged(hWnd, wParam, lParam);
1853             return 0;
1854         }
1855         case WM_COMMAND:
1856         {
1857             return 0;
1858         }
1859         case WM_TIMER:
1860         {
1861             switch (wParam)
1862             {
1863                 case USER_TIMER_ID:
1864                 {
1865                     if (m_pTimerObject)
1866                         m_pTimerObject->OnTimer();
1867                     break;
1868                 }
1869                 case POINTING_TIMER_ID:
1870                 {
1871                     POINT pt;
1872                     ::GetCursorPos(&pt);
1873 
1874                     POINT pt2 = pt;
1875                     ::ScreenToClient(m_hWnd, &pt2);
1876 
1877                     RECT rc;
1878                     ::GetWindowRect(m_hWnd, &rc);
1879 
1880                     if (::PtInRect(&rc, pt) && ::WindowFromPoint(pt) == m_hWnd)
1881                     {
1882                         m_pBehindModal->ModalMouseNotify(WM_MOUSEMOVE, pt2.x, pt2.y);
1883                     }
1884                     else
1885                     {
1886                         ::KillTimer(m_hWnd, POINTING_TIMER_ID);
1887                         m_bPointing = FALSE;
1888                         SetObjectPointed(NULL, pt2);
1889                         OnMouseOutFromWindow(pt2.x, pt2.y);
1890                     }
1891 
1892                     if (m_pToolTip)
1893                     {
1894                         MSG msg = { m_hWnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt2.x, pt2.y) };
1895                         m_pToolTip->RelayEvent(&msg);
1896                     }
1897                     break;
1898                 }
1899                 default:
1900                 {
1901                     OnTimer(wParam);
1902                     break;
1903                 }
1904             }
1905             break;
1906         }
1907         case WM_MOUSEMOVE:
1908         case WM_LBUTTONDOWN:
1909         case WM_LBUTTONDBLCLK:
1910         case WM_LBUTTONUP:
1911         case WM_MBUTTONDOWN:
1912         case WM_MBUTTONDBLCLK:
1913         case WM_MBUTTONUP:
1914         case WM_RBUTTONDOWN:
1915         case WM_RBUTTONDBLCLK:
1916         case WM_RBUTTONUP:
1917         {
1918             if (m_pBehindModal)
1919                 m_pBehindModal->ModalMouseNotify(uMsg, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
1920             else
1921                 HandleMouseMsg(uMsg, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
1922             break;
1923         }
1924         case WM_KEYUP:
1925         {
1926             OnKeyUp(hWnd, wParam, lParam);
1927             break;
1928         }
1929         case WM_WINDOWPOSCHANGING:
1930         {
1931             WINDOWPOS *pwp = (WINDOWPOS *)lParam;
1932             if (m_pShadow && (pwp->flags & SWP_HIDEWINDOW))
1933                 m_pShadow->Show(FALSE);
1934             if (!(pwp->flags & SWP_NOZORDER) && pwp->hwndInsertAfter == m_pShadow->m_hWnd)
1935                 pwp->flags |= SWP_NOZORDER;
1936             m_pShadow->OnOwnerWndMoved(!(pwp->flags & SWP_NOSIZE));
1937             return OnWindowPosChanging(hWnd, WM_WINDOWPOSCHANGING, wParam, lParam);
1938         }
1939         case WM_WINDOWPOSCHANGED:
1940         {
1941             WINDOWPOS *pwp = (WINDOWPOS *)lParam;
1942             if (m_pShadow)
1943                 m_pShadow->OnOwnerWndMoved(!(pwp->flags & SWP_NOSIZE));
1944             return OnWindowPosChanged(hWnd, WM_WINDOWPOSCHANGED, wParam, lParam);
1945         }
1946         case WM_NOTIFY:
1947             OnNotify(hWnd, wParam, lParam);
1948             return 0;
1949         case WM_NOTIFYFORMAT:
1950             return OnNotifyFormat(hWnd, wParam, lParam);
1951         case WM_DISPLAYCHANGE:
1952             cicUpdateUIFSys();
1953             cicUpdateUIFScheme();
1954             return OnDisplayChange(hWnd, WM_DISPLAYCHANGE, wParam, lParam);
1955         case WM_NCDESTROY:
1956             OnNCDestroy(hWnd);
1957             return 0;
1958         case WM_KEYDOWN:
1959             OnKeyDown(hWnd, wParam, lParam);
1960             return 0;
1961         default:
1962         {
1963             if (uMsg >= WM_USER)
1964             {
1965                 CUIFWindow *pThis = CUIFWindow::GetThis(hWnd);
1966                 pThis->OnUser(hWnd, uMsg, wParam, lParam);
1967                 break;
1968             }
1969             return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
1970         }
1971     }
1972 
1973     return 0;
1974 }
1975 
1976 LRESULT CALLBACK
WindowProcedure(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1977 CUIFWindow::WindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1978 {
1979     CUIFWindow *This;
1980 
1981     if (uMsg == WM_NCCREATE)
1982     {
1983         This = (CUIFWindow*)((CREATESTRUCT*)lParam)->lpCreateParams;
1984         CUIFWindow::SetThis(hWnd, (LONG_PTR)This);
1985         This->m_hWnd = hWnd;
1986     }
1987     else
1988     {
1989         This = CUIFWindow::GetThis(hWnd);
1990     }
1991 
1992     if (uMsg == WM_GETMINMAXINFO)
1993     {
1994         if (This)
1995             return This->WindowProc(hWnd, uMsg, wParam, lParam);
1996         else
1997             return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
1998     }
1999 
2000     if (!This)
2001         return 0;
2002 
2003     if (uMsg == WM_NCDESTROY)
2004     {
2005         This->m_hWnd = NULL;
2006         ::SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
2007     }
2008 
2009     return This->WindowProc(hWnd, uMsg, wParam, lParam);
2010 }
2011 
2012 BOOL
GetWorkArea(LPCRECT prcWnd,LPRECT prcWorkArea)2013 CUIFWindow::GetWorkArea(LPCRECT prcWnd, LPRECT prcWorkArea)
2014 {
2015     if (!(m_style & (UIF_WINDOW_WORKAREA | UIF_WINDOW_MONITOR)))
2016         return FALSE;
2017 
2018     HMONITOR hMon = ::MonitorFromRect(prcWnd, MONITOR_DEFAULTTONEAREST);
2019     MONITORINFO mi;
2020     mi.cbSize = sizeof(MONITORINFO);
2021     if (!hMon || !::GetMonitorInfo(hMon, &mi))
2022     {
2023         if (m_style & UIF_WINDOW_WORKAREA)
2024             return ::SystemParametersInfo(SPI_GETWORKAREA, 0, prcWorkArea, 0);
2025 
2026         prcWorkArea->left = prcWorkArea->top = 0;
2027         prcWorkArea->right = ::GetSystemMetrics(SM_CXSCREEN);
2028         prcWorkArea->bottom = ::GetSystemMetrics(SM_CYSCREEN);
2029         return TRUE;
2030     }
2031 
2032     if (m_style & UIF_WINDOW_WORKAREA)
2033     {
2034         *prcWorkArea = mi.rcWork;
2035         return TRUE;
2036     }
2037 
2038     *prcWorkArea = mi.rcMonitor;
2039     return TRUE;
2040 }
2041 
2042 void
AdjustWindowPosition()2043 CUIFWindow::AdjustWindowPosition()
2044 {
2045     RECT rc;
2046     rc.left = m_nLeft;
2047     rc.right = m_nLeft + m_nWidth;
2048     rc.top = m_nTop;
2049     rc.bottom = m_nTop + m_nHeight;
2050 
2051     RECT rcWorkArea;
2052     if (!GetWorkArea(&rc, &rcWorkArea))
2053         return;
2054 
2055     if (m_nLeft < rcWorkArea.left)
2056         m_nLeft = rcWorkArea.left;
2057     if (m_nTop < rcWorkArea.top)
2058         m_nTop = rcWorkArea.top;
2059     if (m_nLeft + m_nWidth >= rcWorkArea.right)
2060         m_nLeft = rcWorkArea.right - m_nWidth;
2061     if (m_nTop + m_nHeight >= rcWorkArea.bottom)
2062         m_nTop = rcWorkArea.bottom - m_nHeight;
2063 }
2064 
SetBehindModal(CUIFWindow * pBehindModal)2065 void CUIFWindow::SetBehindModal(CUIFWindow *pBehindModal)
2066 {
2067     m_pBehindModal = pBehindModal;
2068 }
2069 
SetTimerObject(CUIFObject * pTimerObject,UINT uElapse)2070 void CUIFWindow::SetTimerObject(CUIFObject *pTimerObject, UINT uElapse)
2071 {
2072     if (pTimerObject)
2073     {
2074         m_pTimerObject = pTimerObject;
2075         ::SetTimer(m_hWnd, USER_TIMER_ID, uElapse, NULL);
2076     }
2077     else
2078     {
2079         m_pTimerObject = NULL;
2080         ::KillTimer(m_hWnd, USER_TIMER_ID);
2081     }
2082 }
2083 
STDMETHODIMP_(void)2084 STDMETHODIMP_(void)
2085 CUIFWindow::PaintObject(HDC hDC, LPCRECT prc)
2086 {
2087     BOOL bGotDC = FALSE;
2088     if (!hDC)
2089     {
2090         hDC = ::GetDC(m_hWnd);
2091         bGotDC = TRUE;
2092     }
2093 
2094     if (!prc)
2095         prc = &m_rc;
2096 
2097     HDC hMemDC = ::CreateCompatibleDC(hDC);
2098     HBITMAP hbmMem = ::CreateCompatibleBitmap(hDC, prc->right - prc->left, prc->bottom - prc->top);
2099 
2100     HGDIOBJ hbmOld = ::SelectObject(hMemDC, hbmMem);
2101     ::SetViewportOrgEx(hMemDC, -prc->left, -prc->top, NULL);
2102     if (FAILED(EnsureThemeData(m_hWnd)) ||
2103         ((!(m_style & UIF_WINDOW_CHILD) || FAILED(DrawThemeParentBackground(m_hWnd, hMemDC, &m_rc))) &&
2104          FAILED(DrawThemeBackground(hMemDC, m_iStateId, &m_rc, NULL))))
2105     {
2106         if (m_pScheme)
2107             m_pScheme->FillRect(hMemDC, prc, 22);
2108     }
2109 
2110     CUIFObject::PaintObject(hMemDC, prc);
2111     ::BitBlt(hDC, prc->left, prc->top,
2112                   prc->right - prc->left, prc->bottom - prc->top,
2113              hMemDC, prc->left, prc->top, SRCCOPY);
2114     ::SelectObject(hMemDC, hbmOld);
2115     ::DeleteObject(hbmMem);
2116     ::DeleteDC(hMemDC);
2117 
2118     if (bGotDC)
2119         ::ReleaseDC(m_hWnd, hDC);
2120 }
2121 
STDMETHODIMP_(void)2122 STDMETHODIMP_(void)
2123 CUIFWindow::Move(INT x, INT y, INT nWidth, INT nHeight)
2124 {
2125     m_nLeft = x;
2126     m_nTop = y;
2127     if (nWidth >= 0)
2128         m_nWidth = nWidth;
2129     if (nHeight >= 0)
2130         m_nHeight = nHeight;
2131     if (::IsWindow(m_hWnd))
2132     {
2133         AdjustWindowPosition();
2134         ::MoveWindow(m_hWnd, m_nLeft, m_nTop, m_nWidth, m_nHeight, TRUE);
2135     }
2136 }
2137 
STDMETHODIMP_(void)2138 STDMETHODIMP_(void)
2139 CUIFWindow::RemoveUIObj(CUIFObject *pRemove)
2140 {
2141     if (pRemove == m_pCaptured)
2142         SetCaptureObject(NULL);
2143 
2144     if (pRemove == m_pTimerObject)
2145     {
2146         m_pTimerObject = NULL;
2147         ::KillTimer(m_hWnd, USER_TIMER_ID);
2148     }
2149 
2150     if (pRemove == m_pPointed)
2151         m_pPointed = NULL;
2152 
2153     CUIFObject::RemoveUIObj(pRemove);
2154 }
2155 
STDMETHODIMP_(void)2156 STDMETHODIMP_(void)
2157 CUIFWindow::HandleMouseMsg(UINT uMsg, LONG x, LONG y)
2158 {
2159     POINT pt = { x, y };
2160 
2161     CUIFObject *pFound = (CUIFWindow *)ObjectFromPoint(pt);
2162 
2163     SetObjectPointed(pFound, pt);
2164 
2165     if (m_pCaptured)
2166         pFound = m_pCaptured;
2167 
2168     if (!pFound || OnSetCursor(uMsg, pt.x, pt.y))
2169     {
2170         HCURSOR hCursor = ::LoadCursor(NULL, IDC_ARROW);
2171         ::SetCursor(hCursor);
2172     }
2173 
2174     if (pFound && pFound->m_bEnable)
2175     {
2176         switch (uMsg)
2177         {
2178             case WM_MOUSEMOVE:
2179                 pFound->OnMouseMove(pt.x, pt.y);
2180                 break;
2181             case WM_LBUTTONDOWN:
2182                 pFound->OnLButtonDown(pt.x, pt.y);
2183                 break;
2184             case WM_LBUTTONUP:
2185                 pFound->OnLButtonUp(pt.x, pt.y);
2186                 break;
2187             case WM_RBUTTONDOWN:
2188                 pFound->OnRButtonDown(pt.x, pt.y);
2189                 break;
2190             case WM_RBUTTONUP:
2191                 pFound->OnRButtonUp(pt.x, pt.y);
2192                 break;
2193             case WM_MBUTTONDOWN:
2194                 pFound->OnMButtonDown(pt.x, pt.y);
2195                 break;
2196             case WM_MBUTTONUP:
2197                 pFound->OnMButtonUp(pt.x, pt.y);
2198                 break;
2199         }
2200     }
2201 }
2202 
2203 /////////////////////////////////////////////////////////////////////////////
2204 // CUIFShadow
2205 
2206 /// @unimplemented
CUIFShadow(HINSTANCE hInst,DWORD style,CUIFWindow * pShadowOwner)2207 CUIFShadow::CUIFShadow(HINSTANCE hInst, DWORD style, CUIFWindow *pShadowOwner)
2208     : CUIFWindow(hInst, (style | UIF_WINDOW_TOOLWINDOW))
2209 {
2210     m_pShadowOwner = pShadowOwner;
2211     m_rgbShadowColor = RGB(0, 0, 0);
2212     m_dwUnknown11[0] = 0;
2213     m_dwUnknown11[1] = 0;
2214     m_xShadowDelta = m_yShadowDelta = 0;
2215     m_bLayerAvailable = FALSE;
2216 }
2217 
~CUIFShadow()2218 CUIFShadow::~CUIFShadow()
2219 {
2220     if (m_pShadowOwner)
2221         m_pShadowOwner->m_pShadow = NULL;
2222 }
2223 
2224 /// @unimplemented
InitSettings()2225 void CUIFShadow::InitSettings()
2226 {
2227     m_bLayerAvailable = FALSE;
2228     m_rgbShadowColor = RGB(128, 128, 128);
2229     m_xShadowDelta = m_yShadowDelta = 2;
2230 }
2231 
2232 /// @unimplemented
InitShadow()2233 void CUIFShadow::InitShadow()
2234 {
2235     if (m_bLayerAvailable)
2236     {
2237         //FIXME
2238     }
2239 }
2240 
AdjustWindowPos()2241 void CUIFShadow::AdjustWindowPos()
2242 {
2243     HWND hwndOwner = *m_pShadowOwner;
2244     if (!::IsWindow(m_hWnd))
2245         return;
2246 
2247     RECT rc;
2248     ::GetWindowRect(hwndOwner, &rc);
2249     ::SetWindowPos(m_hWnd, hwndOwner,
2250                    rc.left + m_xShadowDelta,
2251                    rc.top + m_yShadowDelta,
2252                    rc.right - rc.left,
2253                    rc.bottom - rc.top,
2254                    SWP_NOOWNERZORDER | SWP_NOACTIVATE);
2255 }
2256 
OnOwnerWndMoved(BOOL bDoSize)2257 void CUIFShadow::OnOwnerWndMoved(BOOL bDoSize)
2258 {
2259     if (::IsWindow(m_hWnd) && ::IsWindowVisible(m_hWnd))
2260     {
2261         AdjustWindowPos();
2262         if (bDoSize)
2263             InitShadow();
2264     }
2265 }
2266 
STDMETHODIMP_(BOOL)2267 STDMETHODIMP_(BOOL)
2268 CUIFShadow::Initialize()
2269 {
2270     InitSettings();
2271     return CUIFWindow::Initialize();
2272 }
2273 
STDMETHODIMP_(DWORD)2274 STDMETHODIMP_(DWORD)
2275 CUIFShadow::GetWndStyleEx()
2276 {
2277     DWORD exstyle = CUIFWindow::GetWndStyleEx();
2278     if (m_bLayerAvailable)
2279         exstyle |= WS_EX_LAYERED;
2280     return exstyle;
2281 }
2282 
STDMETHODIMP_(void)2283 STDMETHODIMP_(void)
2284 CUIFShadow::OnPaint(HDC hDC)
2285 {
2286     RECT rc = m_rc;
2287     HBRUSH hBrush = ::CreateSolidBrush(m_rgbShadowColor);
2288     ::FillRect(hDC, &rc, hBrush);
2289     ::DeleteObject(hBrush);
2290 }
2291 
STDMETHODIMP_(LRESULT)2292 STDMETHODIMP_(LRESULT)
2293 CUIFShadow::OnWindowPosChanging(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
2294 {
2295     WINDOWPOS *wp = (WINDOWPOS *)lParam;
2296     wp->hwndInsertAfter = *m_pShadowOwner;
2297     return ::DefWindowProc(hWnd, Msg, wParam, lParam);
2298 }
2299 
STDMETHODIMP_(LRESULT)2300 STDMETHODIMP_(LRESULT)
2301 CUIFShadow::OnSettingChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2302 {
2303     InitSettings();
2304 
2305     DWORD exstyle;
2306     if (m_bLayerAvailable)
2307         exstyle = ::GetWindowLongPtr(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED;
2308     else
2309         exstyle = ::GetWindowLongPtr(m_hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED;
2310 
2311     ::SetWindowLongPtr(m_hWnd, GWL_EXSTYLE, exstyle);
2312 
2313     AdjustWindowPos();
2314     InitShadow();
2315 
2316     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
2317 }
2318 
STDMETHODIMP_(void)2319 STDMETHODIMP_(void)
2320 CUIFShadow::Show(BOOL bVisible)
2321 {
2322     if (bVisible && ::IsWindow(m_hWnd) && !::IsWindowVisible(m_hWnd))
2323     {
2324         AdjustWindowPos();
2325         InitShadow();
2326     }
2327 
2328     if (::IsWindow(m_hWnd))
2329     {
2330         m_bVisible = bVisible;
2331         ::ShowWindow(m_hWnd, (bVisible ? SW_SHOWNOACTIVATE : SW_HIDE));
2332     }
2333 }
2334 
2335 /////////////////////////////////////////////////////////////////////////////
2336 // CUIFToolTip
2337 
CUIFToolTip(HINSTANCE hInst,DWORD style,CUIFWindow * pToolTipOwner)2338 CUIFToolTip::CUIFToolTip(HINSTANCE hInst, DWORD style, CUIFWindow *pToolTipOwner)
2339     : CUIFWindow(hInst, style)
2340 {
2341     m_pToolTipOwner = pToolTipOwner;
2342     m_rcToolTipMargin.left = 2;
2343     m_rcToolTipMargin.top = 2;
2344     m_rcToolTipMargin.right = 2;
2345     m_rcToolTipMargin.bottom = 2;
2346     m_pToolTipTarget = NULL;
2347     m_pszToolTipText = NULL;
2348     m_dwUnknown10 = 0; //FIXME: name and type
2349     m_nDelayTimeType2 = -1;
2350     m_nDelayTimeType3 = -1;
2351     m_nDelayTimeType1 = -1;
2352     m_cxToolTipWidth = -1;
2353     m_bToolTipHasBkColor = 0;
2354     m_bToolTipHasTextColor = 0;
2355     m_rgbToolTipBkColor = 0;
2356     m_rgbToolTipTextColor = 0;
2357 }
2358 
~CUIFToolTip()2359 CUIFToolTip::~CUIFToolTip()
2360 {
2361     if (m_pToolTipOwner)
2362         m_pToolTipOwner->m_pToolTip = NULL;
2363     if (m_pszToolTipText)
2364         delete[] m_pszToolTipText;
2365 }
2366 
2367 LONG
GetDelayTime(UINT uType)2368 CUIFToolTip::GetDelayTime(UINT uType)
2369 {
2370     LONG nDelayTime;
2371     switch (uType)
2372     {
2373         case 1:
2374         {
2375             nDelayTime = m_nDelayTimeType1;
2376             if (nDelayTime == -1)
2377                 return ::GetDoubleClickTime() / 5;
2378             return nDelayTime;
2379         }
2380         case 2:
2381         {
2382             nDelayTime = m_nDelayTimeType2;
2383             if (nDelayTime == -1)
2384                 return 10 * ::GetDoubleClickTime();
2385             return nDelayTime;
2386         }
2387         case 3:
2388         {
2389             nDelayTime = m_nDelayTimeType3;
2390             if (nDelayTime == -1)
2391                 return ::GetDoubleClickTime();
2392             return nDelayTime;
2393         }
2394         default:
2395         {
2396             return 0;
2397         }
2398     }
2399 }
2400 
GetMargin(LPRECT prc)2401 void CUIFToolTip::GetMargin(LPRECT prc)
2402 {
2403     if (prc)
2404         *prc = m_rcToolTipMargin;
2405 }
2406 
2407 COLORREF
GetTipBkColor()2408 CUIFToolTip::GetTipBkColor()
2409 {
2410     if (m_bToolTipHasBkColor)
2411         return m_rgbToolTipBkColor;
2412     return ::GetSysColor(COLOR_INFOBK);
2413 }
2414 
2415 COLORREF
GetTipTextColor()2416 CUIFToolTip::GetTipTextColor()
2417 {
2418     if (m_bToolTipHasTextColor)
2419         return m_rgbToolTipTextColor;
2420     return ::GetSysColor(COLOR_INFOTEXT);
2421 }
2422 
2423 CUIFObject*
FindObject(HWND hWnd,POINT pt)2424 CUIFToolTip::FindObject(HWND hWnd, POINT pt)
2425 {
2426     if (hWnd == *m_pToolTipOwner)
2427         return m_pToolTipOwner->ObjectFromPoint(pt);
2428     return NULL;
2429 }
2430 
2431 void
ShowTip()2432 CUIFToolTip::ShowTip()
2433 {
2434     ::KillTimer(m_hWnd, TOOLTIP_TIMER_ID);
2435 
2436     if (!m_pToolTipTarget)
2437         return;
2438 
2439     LPCWSTR pszText = m_pToolTipTarget->GetToolTip();
2440     if (!pszText)
2441         return;
2442 
2443     if (!m_pToolTipTarget || m_pToolTipTarget->OnShowToolTip())
2444         return;
2445 
2446     POINT Point;
2447     ::GetCursorPos(&Point);
2448     ::ScreenToClient(*m_pToolTipTarget->m_pWindow, &Point);
2449 
2450     RECT rc;
2451     m_pToolTipTarget->GetRect(&rc);
2452     if (!::PtInRect(&rc, Point))
2453         return;
2454 
2455     size_t cchText = wcslen(pszText);
2456     m_pszToolTipText = new(cicNoThrow) WCHAR[cchText + 1];
2457     if (!m_pszToolTipText)
2458         return;
2459 
2460     lstrcpynW(m_pszToolTipText, pszText, cchText + 1);
2461 
2462     SIZE size;
2463     GetTipWindowSize(&size);
2464 
2465     RECT rc2 = rc;
2466     ::ClientToScreen(*m_pToolTipTarget->m_pWindow, (LPPOINT)&rc);
2467     ::ClientToScreen(*m_pToolTipTarget->m_pWindow, (LPPOINT)&rc.right);
2468     GetTipWindowRect(&rc2, size, &rc);
2469 
2470     m_bShowToolTip = TRUE;
2471     Move(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
2472     Show(TRUE);
2473 }
2474 
2475 void
HideTip()2476 CUIFToolTip::HideTip()
2477 {
2478     ::KillTimer(m_hWnd, TOOLTIP_TIMER_ID);
2479     m_bShowToolTip = FALSE;
2480 
2481     if (m_pToolTipTarget)
2482         m_pToolTipTarget->OnHideToolTip();
2483 
2484     if (m_bVisible)
2485     {
2486         if (m_pszToolTipText)
2487         {
2488             delete[] m_pszToolTipText;
2489             m_pszToolTipText = NULL;
2490         }
2491         Show(FALSE);
2492     }
2493 }
2494 
2495 void
GetTipWindowSize(LPSIZE pSize)2496 CUIFToolTip::GetTipWindowSize(LPSIZE pSize)
2497 {
2498     if (!m_pszToolTipText)
2499         return;
2500 
2501     HDC hDC = ::GetDC(m_hWnd);
2502     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
2503 
2504     RECT rcText = { 0, 0, 0, 0 };
2505     INT cyText;
2506     if (m_cxToolTipWidth <= 0)
2507     {
2508         cyText = ::DrawTextW(hDC, m_pszToolTipText, -1, &rcText, DT_CALCRECT | DT_SINGLELINE);
2509     }
2510     else
2511     {
2512         rcText.right = m_cxToolTipWidth;
2513         cyText = ::DrawTextW(hDC, m_pszToolTipText, -1, &rcText, DT_CALCRECT | DT_WORDBREAK);
2514     }
2515 
2516     RECT rcMargin;
2517     GetMargin(&rcMargin);
2518 
2519     RECT rc;
2520     rc.left     = rcText.left - rcMargin.left;
2521     rc.top      = rcText.top - rcMargin.top;
2522     rc.right    = rcText.right + rcMargin.right;
2523     rc.bottom   = rcText.top + cyText + rcMargin.bottom;
2524     ClientRectToWindowRect(&rc);
2525 
2526     pSize->cx = rc.right - rc.left;
2527     pSize->cy = rc.bottom - rc.top;
2528 
2529     ::SelectObject(hDC, hFontOld);
2530     ::ReleaseDC(m_hWnd, hDC);
2531 }
2532 
2533 void
GetTipWindowRect(LPRECT pRect,SIZE toolTipSize,LPCRECT prc)2534 CUIFToolTip::GetTipWindowRect(LPRECT pRect, SIZE toolTipSize, LPCRECT prc)
2535 {
2536     POINT Point;
2537     GetCursorPos(&Point);
2538 
2539     HCURSOR hCursor = ::GetCursor();
2540     ICONINFO IconInfo;
2541     INT yHotspot = 0;
2542     INT cyCursor = ::GetSystemMetrics(SM_CYCURSOR);
2543     if (hCursor && ::GetIconInfo(hCursor, &IconInfo))
2544     {
2545         BITMAP bm;
2546         ::GetObject(IconInfo.hbmMask, sizeof(bm), &bm);
2547         if (!IconInfo.fIcon)
2548         {
2549             cyCursor = bm.bmHeight;
2550             yHotspot = IconInfo.yHotspot;
2551             if (!IconInfo.hbmColor)
2552                 cyCursor = bm.bmHeight / 2;
2553         }
2554         if (IconInfo.hbmColor)
2555             ::DeleteObject(IconInfo.hbmColor);
2556         if (IconInfo.hbmMask)
2557             ::DeleteObject(IconInfo.hbmMask);
2558     }
2559 
2560     RECT rcMonitor;
2561     rcMonitor.left = 0;
2562     rcMonitor.top = 0;
2563     rcMonitor.right = GetSystemMetrics(SM_CXSCREEN);
2564     rcMonitor.bottom = GetSystemMetrics(SM_CYSCREEN);
2565 
2566     HMONITOR hMon = ::MonitorFromPoint(Point, MONITOR_DEFAULTTONEAREST);
2567     MONITORINFO mi;
2568     if (hMon)
2569     {
2570         mi.cbSize = sizeof(MONITORINFO);
2571         if (::GetMonitorInfo(hMon, &mi))
2572             rcMonitor = mi.rcMonitor;
2573     }
2574 
2575     pRect->left   = Point.x;
2576     pRect->right  = pRect->left + toolTipSize.cx;
2577     pRect->top    = Point.y + cyCursor - yHotspot;
2578     pRect->bottom = pRect->top + toolTipSize.cy;
2579 
2580     if (rcMonitor.right < pRect->right)
2581     {
2582         pRect->left = rcMonitor.right - toolTipSize.cx;
2583         pRect->right = rcMonitor.right;
2584     }
2585     if (pRect->left < rcMonitor.left)
2586     {
2587         pRect->left = rcMonitor.left;
2588         pRect->right = rcMonitor.left + toolTipSize.cx;
2589     }
2590     if (rcMonitor.bottom < pRect->bottom)
2591     {
2592         pRect->top = rcMonitor.bottom - toolTipSize.cy;
2593         pRect->bottom = rcMonitor.bottom;
2594     }
2595     if (pRect->top < rcMonitor.top)
2596     {
2597         pRect->top = rcMonitor.top;
2598         pRect->bottom = rcMonitor.top + toolTipSize.cy;
2599     }
2600 }
2601 
2602 void
RelayEvent(LPMSG pMsg)2603 CUIFToolTip::RelayEvent(LPMSG pMsg)
2604 {
2605     if (!pMsg)
2606         return;
2607 
2608     switch (pMsg->message)
2609     {
2610         case WM_MOUSEMOVE:
2611         {
2612             if (m_bEnable &&
2613                 ::GetKeyState(VK_LBUTTON) >= 0 &&
2614                 ::GetKeyState(VK_MBUTTON) >= 0 &&
2615                 ::GetKeyState(VK_RBUTTON) >= 0)
2616             {
2617                 POINT pt = { (SHORT)LOWORD(pMsg->lParam), (SHORT)HIWORD(pMsg->lParam) };
2618                 CUIFObject *pFound = CUIFToolTip::FindObject(pMsg->hwnd, pt);
2619                 if (pFound)
2620                 {
2621                     if (m_pToolTipTarget != pFound)
2622                     {
2623                         HideTip();
2624 
2625                         LONG DelayTime;
2626                         if (!m_bVisible)
2627                             DelayTime = GetDelayTime(3);
2628                         else
2629                             DelayTime = GetDelayTime(1);
2630                         ::SetTimer(m_hWnd, TOOLTIP_TIMER_ID, DelayTime, NULL);
2631                     }
2632                 }
2633                 else
2634                 {
2635                     HideTip();
2636                 }
2637                 m_pToolTipTarget = pFound;
2638             }
2639             break;
2640         }
2641         case WM_LBUTTONDOWN:
2642         case WM_RBUTTONDOWN:
2643         case WM_MBUTTONDOWN:
2644         {
2645             HideTip();
2646             break;
2647         }
2648     }
2649 }
2650 
STDMETHODIMP_(void)2651 STDMETHODIMP_(void) CUIFToolTip::OnPaint(HDC hDC)
2652 {
2653     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
2654     INT iBkModeOld = ::SetBkMode(hDC, TRANSPARENT);
2655 
2656     COLORREF rgbTextColor = GetTipTextColor();
2657     COLORREF rgbOldTextColor = ::SetTextColor(hDC, rgbTextColor);
2658 
2659     COLORREF rgbBkColor = GetTipBkColor();
2660     HBRUSH hbrBack = ::CreateSolidBrush(rgbBkColor);
2661     RECT rc = m_rc;
2662     if (hbrBack)
2663     {
2664         ::FillRect(hDC, &rc, hbrBack);
2665         ::DeleteObject(hbrBack);
2666     }
2667 
2668     RECT rcMargin;
2669     GetMargin(&rcMargin);
2670 
2671     rc.left += rcMargin.left;
2672     rc.top += rcMargin.top;
2673     rc.right -= rcMargin.right;
2674     rc.bottom -= rcMargin.bottom;
2675 
2676     if (m_cxToolTipWidth <= 0)
2677         ::DrawTextW(hDC, m_pszToolTipText, -1, &rc, DT_SINGLELINE);
2678     else
2679         ::DrawTextW(hDC, m_pszToolTipText, -1, &rc, DT_WORDBREAK);
2680 
2681     ::SetTextColor(hDC, rgbOldTextColor);
2682     ::SetBkMode(hDC, iBkModeOld);
2683     ::SelectObject(hDC, hFontOld);
2684 }
2685 
STDMETHODIMP_(void)2686 STDMETHODIMP_(void) CUIFToolTip::Enable(BOOL bEnable)
2687 {
2688     if (!bEnable)
2689         HideTip();
2690     CUIFObject::Enable(bEnable);
2691 }
2692 
STDMETHODIMP_(void)2693 STDMETHODIMP_(void) CUIFToolTip::OnTimer(WPARAM wParam)
2694 {
2695     if (wParam == TOOLTIP_TIMER_ID)
2696         ShowTip();
2697 }
2698 
2699 /////////////////////////////////////////////////////////////////////////////
2700 // CUIFButton
2701 
CUIFButton(CUIFObject * pParent,DWORD nObjectID,LPCRECT prc,DWORD style)2702 CUIFButton::CUIFButton(
2703     CUIFObject *pParent,
2704     DWORD nObjectID,
2705     LPCRECT prc,
2706     DWORD style) : CUIFObject(pParent, nObjectID, prc, style)
2707 {
2708     m_ButtonIcon.m_hIcon = NULL;
2709     m_ButtonIcon.m_hImageList = NULL;
2710     m_dwUnknown9 = 0;
2711     m_uButtonStatus = 0;
2712     m_bPressed = FALSE;
2713     m_hbmButton1 = NULL;
2714     m_hbmButton2 = NULL;
2715     m_pszButtonText = NULL;
2716 }
2717 
~CUIFButton()2718 CUIFButton::~CUIFButton()
2719 {
2720     if (m_pszButtonText)
2721     {
2722         delete[] m_pszButtonText;
2723         m_pszButtonText = NULL;
2724     }
2725 
2726     if (m_ButtonIcon.m_hImageList)
2727         ImageList_Destroy(m_ButtonIcon.m_hImageList);
2728 }
2729 
2730 void
DrawBitmapProc(HDC hDC,LPCRECT prc,BOOL bPressed)2731 CUIFButton::DrawBitmapProc(HDC hDC, LPCRECT prc, BOOL bPressed)
2732 {
2733     INT width = m_rc.right - m_rc.left;
2734     INT height = m_rc.bottom - m_rc.top;
2735     if (m_hbmButton2)
2736     {
2737         HBITMAP hbmMask = cicCreateMaskBmp(&m_rc, m_hbmButton1, m_hbmButton2,
2738                                            (HBRUSH)UlongToHandle(COLOR_BTNFACE + 1), 0, 0);
2739         ::DrawState(hDC, NULL, NULL, (LPARAM)hbmMask, 0,
2740                     prc->left + bPressed, prc->top + bPressed,
2741                     width - bPressed, height - bPressed,
2742                     DST_BITMAP | (m_bEnable ? 0 : (DSS_MONO | DSS_DISABLED)));
2743         ::DeleteObject(hbmMask);
2744     }
2745     else
2746     {
2747         ::DrawState(hDC, NULL, NULL, (LPARAM)m_hbmButton1, 0,
2748                     prc->left + bPressed, prc->top + bPressed,
2749                     width - bPressed, height - bPressed,
2750                     DST_BITMAP | (m_bEnable ? 0 : (DSS_MONO | DSS_DISABLED)));
2751     }
2752 }
2753 
2754 void
DrawEdgeProc(HDC hDC,LPCRECT prc,BOOL bPressed)2755 CUIFButton::DrawEdgeProc(HDC hDC, LPCRECT prc, BOOL bPressed)
2756 {
2757     RECT rc = *prc;
2758     if (bPressed)
2759         ::DrawEdge(hDC, &rc, BDR_SUNKENOUTER, BF_RECT);
2760     else
2761         ::DrawEdge(hDC, &rc, BDR_RAISEDINNER, BF_RECT);
2762 }
2763 
DrawIconProc(HDC hDC,LPRECT prc,BOOL bPressed)2764 void CUIFButton::DrawIconProc(HDC hDC, LPRECT prc, BOOL bPressed)
2765 {
2766     INT width = prc->right - prc->left;
2767     INT height = prc->bottom - prc->top;
2768     RECT rc = { 0, 0, width, height };
2769 
2770     HDC hMemDC = ::CreateCompatibleDC(hDC);
2771     if (!hMemDC)
2772         return;
2773 
2774     HBITMAP hbmMem = ::CreateCompatibleBitmap(hDC, width, height);
2775     if (!hbmMem)
2776     {
2777         ::DeleteDC(hMemDC);
2778         return;
2779     }
2780 
2781     HGDIOBJ hbmOld = ::SelectObject(hMemDC, hbmMem);
2782     if (m_bEnable)
2783     {
2784         ::BitBlt(hMemDC, rc.left, rc.top, width, height, hDC, prc->left, prc->top, SRCCOPY);
2785     }
2786     else
2787     {
2788         HBRUSH hbrWhite = (HBRUSH)::GetStockObject(WHITE_BRUSH);
2789         ::FillRect(hMemDC, &rc, hbrWhite);
2790     }
2791 
2792     if (m_style & UIF_BUTTON_LARGE_ICON)
2793     {
2794         ::DrawIconEx(hMemDC,
2795                      2 + bPressed, 2 + bPressed,
2796                      m_ButtonIcon.m_hIcon,
2797                      width - 4, height - 4,
2798                      0, NULL, DI_NORMAL);
2799     }
2800     else
2801     {
2802         ::DrawIconEx(hMemDC,
2803                      (width - 16) / 2 + bPressed,
2804                      (height - 16) / 2 + bPressed,
2805                      m_ButtonIcon.m_hIcon,
2806                      16, 16,
2807                      0, NULL, DI_NORMAL);
2808     }
2809 
2810     ::SelectObject(hMemDC, hbmOld);
2811     ::DrawState(hDC, NULL, NULL, (LPARAM)hbmMem, 0,
2812                 prc->left, prc->top, width, height,
2813                 DST_BITMAP | (m_bEnable ? 0 : (DSS_MONO | DSS_DISABLED)));
2814     ::DeleteObject(hbmMem);
2815     ::DeleteDC(hMemDC);
2816 }
2817 
2818 void
DrawTextProc(HDC hDC,LPCRECT prc,BOOL bPressed)2819 CUIFButton::DrawTextProc(HDC hDC, LPCRECT prc, BOOL bPressed)
2820 {
2821     if (!m_pszButtonText)
2822         return;
2823 
2824     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
2825     INT cchText = lstrlenW(m_pszButtonText);
2826     SIZE textSize;
2827     ::GetTextExtentPoint32W(hDC, m_pszButtonText, cchText, &textSize);
2828 
2829     INT xText, yText;
2830     if ((m_style & UIF_BUTTON_H_ALIGN_MASK) == UIF_BUTTON_H_ALIGN_CENTER)
2831         xText = (m_rc.right - m_rc.left - textSize.cx) / 2;
2832     else if ((m_style & UIF_BUTTON_H_ALIGN_MASK) == UIF_BUTTON_H_ALIGN_RIGHT)
2833         xText = m_rc.right - m_rc.left - textSize.cx;
2834     else
2835         xText = 0;
2836 
2837     if ((m_style & UIF_BUTTON_V_ALIGN_MASK) == UIF_BUTTON_V_ALIGN_MIDDLE)
2838         yText = (m_rc.bottom - m_rc.top - textSize.cy) / 2;
2839     else if ((m_style & UIF_BUTTON_V_ALIGN_MASK) == UIF_BUTTON_V_ALIGN_BOTTOM)
2840         yText = m_rc.bottom - m_rc.top - textSize.cy;
2841     else
2842         yText = 0;
2843 
2844     ::SetBkMode(hDC, TRANSPARENT);
2845 
2846     if (m_bEnable)
2847     {
2848         ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNTEXT));
2849         ::ExtTextOutW(hDC,
2850                       xText + prc->left + bPressed, yText + prc->top + bPressed,
2851                       ETO_CLIPPED, prc,
2852                       m_pszButtonText, cchText, NULL);
2853     }
2854     else
2855     {
2856         ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNHILIGHT));
2857         ::ExtTextOutW(hDC,
2858                       xText + prc->left + bPressed + 1, yText + prc->top + bPressed + 1,
2859                       ETO_CLIPPED, prc,
2860                       m_pszButtonText, cchText, NULL);
2861 
2862         ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNSHADOW));
2863         ::ExtTextOutW(hDC,
2864                       xText + prc->left + bPressed, yText + prc->top + bPressed,
2865                       ETO_CLIPPED, prc,
2866                       m_pszButtonText, cchText, NULL);
2867     }
2868 
2869     ::SelectObject(hDC, hFontOld);
2870 }
2871 
STDMETHODIMP_(void)2872 STDMETHODIMP_(void)
2873 CUIFButton::Enable(BOOL bEnable)
2874 {
2875     CUIFObject::Enable(bEnable);
2876     if (!m_bEnable)
2877     {
2878         SetStatus(0);
2879         if (IsCapture())
2880             CUIFObject::EndCapture();
2881     }
2882 }
2883 
2884 void
GetIconSize(HICON hIcon,LPSIZE pSize)2885 CUIFButton::GetIconSize(HICON hIcon, LPSIZE pSize)
2886 {
2887     ICONINFO IconInfo;
2888     if (::GetIconInfo(hIcon, &IconInfo))
2889     {
2890         BITMAP bm;
2891         ::GetObject(IconInfo.hbmColor, sizeof(bm), &bm);
2892         ::DeleteObject(IconInfo.hbmColor);
2893         ::DeleteObject(IconInfo.hbmMask);
2894         pSize->cx = bm.bmWidth;
2895         pSize->cy = bm.bmHeight;
2896     }
2897     else
2898     {
2899         pSize->cx = ::GetSystemMetrics(SM_CXSMICON);
2900         pSize->cy = ::GetSystemMetrics(SM_CYSMICON);
2901     }
2902 }
2903 
2904 void
GetTextSize(LPCWSTR pszText,LPSIZE pSize)2905 CUIFButton::GetTextSize(LPCWSTR pszText, LPSIZE pSize)
2906 {
2907     HDC hDC = ::GetDC(NULL);
2908     INT cchText = lstrlenW(pszText);
2909     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
2910 
2911     if (!m_bHasCustomFont && SUCCEEDED(EnsureThemeData(*m_pWindow)))
2912     {
2913         RECT rc;
2914         GetThemeTextExtent(hDC, 0, pszText, cchText, 0, NULL, &rc);
2915         pSize->cx = rc.right;
2916         pSize->cy = rc.bottom;
2917     }
2918     else
2919     {
2920         ::GetTextExtentPoint32W(hDC, pszText, cchText, pSize);
2921     }
2922 
2923     if (m_style & UIF_BUTTON_VERTICAL)
2924     {
2925         INT tmp = pSize->cx;
2926         pSize->cx = pSize->cy;
2927         pSize->cy = tmp;
2928     }
2929 
2930     ::SelectObject(hDC, hFontOld);
2931     ::ReleaseDC(NULL, hDC);
2932 }
2933 
STDMETHODIMP_(void)2934 STDMETHODIMP_(void)
2935 CUIFButton::OnLButtonDown(LONG x, LONG y)
2936 {
2937     SetStatus(1);
2938     StartCapture();
2939     if ((m_style & 0x30) == 0x20)
2940         NotifyCommand(1, 0);
2941 }
2942 
2943 /// @unimplemented
STDMETHODIMP_(void)2944 STDMETHODIMP_(void)
2945 CUIFButton::OnLButtonUp(LONG x, LONG y)
2946 {
2947     POINT pt = { x, y };
2948     BOOL bCapture = IsCapture();
2949     if (bCapture)
2950         EndCapture();
2951 
2952     BOOL bNotInObject = (m_style & 0x30) == 0x20;
2953     if ((m_style & 0x30) != 0x10)
2954     {
2955         bNotInObject = !PtInObject(pt);
2956         if (bNotInObject)
2957         {
2958             SetStatus(0);
2959             return;
2960         }
2961     }
2962     else
2963     {
2964         if (!bNotInObject)
2965         {
2966             bNotInObject = !PtInObject(pt);
2967             if (!bNotInObject)
2968             {
2969                 SetStatus(2);
2970                 NotifyCommand(1, 0);
2971                 return;
2972             }
2973         }
2974         SetStatus(0);
2975         return;
2976     }
2977 
2978     SetStatus(2);
2979 
2980     if (bCapture)
2981     {
2982         m_bPressed = !m_bPressed;
2983         NotifyCommand(1, 0);
2984     }
2985 }
2986 
OnMouseIn(LONG x,LONG y)2987 void CUIFButton::OnMouseIn(LONG x, LONG y)
2988 {
2989     if ((m_style & 0x30) == 0x20)
2990     {
2991         if (IsCapture())
2992             SetStatus(0);
2993         else
2994             SetStatus(2);
2995     }
2996     else
2997     {
2998         if (IsCapture())
2999             SetStatus(1);
3000         else
3001             SetStatus(2);
3002     }
3003 }
3004 
OnMouseOut(LONG x,LONG y)3005 void CUIFButton::OnMouseOut(LONG x, LONG y)
3006 {
3007     if ((m_style & 0x30) == 0x20)
3008         SetStatus(0);
3009     else if (IsCapture())
3010         SetStatus(3);
3011     else
3012         SetStatus(0);
3013 }
3014 
STDMETHODIMP_(void)3015 STDMETHODIMP_(void)
3016 CUIFButton::OnPaintNoTheme(HDC hDC)
3017 {
3018     ::FillRect(hDC, &m_rc, (HBRUSH)UlongToHandle(COLOR_BTNFACE + 1));
3019 
3020     if (m_bPressed && ((m_uButtonStatus == 0) || (m_uButtonStatus == 3)))
3021     {
3022         HBRUSH hbr = cicCreateDitherBrush();
3023         if (hbr)
3024         {
3025             COLORREF OldTextColor = ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNFACE));
3026             COLORREF OldBkColor = ::SetBkColor(hDC, ::GetSysColor(COLOR_BTNHIGHLIGHT));
3027             RECT rc = m_rc;
3028             ::InflateRect(&rc, -2, -2);
3029             ::FillRect(hDC, &rc, hbr);
3030             ::SetTextColor(hDC, OldTextColor);
3031             ::SetBkColor(hDC, OldBkColor);
3032             ::DeleteObject(hbr);
3033         }
3034     }
3035 
3036     BOOL bPressed = (m_bPressed || (m_uButtonStatus == 1));
3037     if (m_hbmButton1)
3038         DrawBitmapProc(hDC, &m_rc, bPressed);
3039     else if (m_ButtonIcon.m_hIcon)
3040         DrawIconProc(hDC, &m_rc, bPressed);
3041     else
3042         DrawTextProc(hDC, &m_rc, bPressed);
3043 
3044     if (m_bPressed || (m_uButtonStatus == 1))
3045         DrawEdgeProc(hDC, &m_rc, TRUE);
3046     else if (2 <= m_uButtonStatus && m_uButtonStatus <= 3)
3047         DrawEdgeProc(hDC, &m_rc, FALSE);
3048 }
3049 
SetIcon(HICON hIcon)3050 void CUIFButton::SetIcon(HICON hIcon)
3051 {
3052     m_ButtonIcon = hIcon;
3053 
3054     if (m_ButtonIcon.m_hIcon)
3055         GetIconSize(m_ButtonIcon.m_hIcon, &m_IconSize);
3056     else
3057         m_IconSize.cx = m_IconSize.cy = 0;
3058 
3059     CallOnPaint();
3060 }
3061 
SetStatus(UINT uStatus)3062 void CUIFButton::SetStatus(UINT uStatus)
3063 {
3064     if (uStatus != m_uButtonStatus)
3065     {
3066         m_uButtonStatus = uStatus;
3067         CallOnPaint();
3068     }
3069 }
3070 
SetText(LPCWSTR pszText)3071 void CUIFButton::SetText(LPCWSTR pszText)
3072 {
3073     if (m_pszButtonText)
3074     {
3075         delete[] m_pszButtonText;
3076         m_pszButtonText = NULL;
3077     }
3078 
3079     m_TextSize.cx = m_TextSize.cy = 0;
3080 
3081     if (pszText)
3082     {
3083         INT cch = lstrlenW(pszText);
3084         m_pszButtonText = new(cicNoThrow) WCHAR[cch + 1];
3085         if (!m_pszButtonText)
3086             return;
3087 
3088         lstrcpynW(m_pszButtonText, pszText, cch + 1);
3089         GetTextSize(m_pszButtonText, &m_TextSize);
3090     }
3091 
3092     CallOnPaint();
3093 }
3094 
3095 /////////////////////////////////////////////////////////////////////////////
3096 // CUIFButton2
3097 
CUIFButton2(CUIFObject * pParent,DWORD nObjectID,LPCRECT prc,DWORD style)3098 CUIFButton2::CUIFButton2(
3099     CUIFObject *pParent,
3100     DWORD nObjectID,
3101     LPCRECT prc,
3102     DWORD style) : CUIFButton(pParent, nObjectID, prc, style)
3103 {
3104     m_iStateId = 0;
3105     m_iPartId = BP_PUSHBUTTON;
3106     m_pszClassList = L"TOOLBAR";
3107 }
3108 
~CUIFButton2()3109 CUIFButton2::~CUIFButton2()
3110 {
3111     CloseThemeData();
3112 }
3113 
MakeDrawFlag()3114 DWORD CUIFButton2::MakeDrawFlag()
3115 {
3116     DWORD dwDrawFlags = 0;
3117     if (m_bPressed)
3118         dwDrawFlags |= UIF_DRAW_PRESSED;
3119     if (m_uButtonStatus == 1)
3120         dwDrawFlags |= 0x2;
3121     else if (2 <= m_uButtonStatus && m_uButtonStatus <= 3)
3122         dwDrawFlags |= 0x1;
3123     if (!m_bEnable)
3124         dwDrawFlags |= UIF_DRAW_DISABLED;
3125     return dwDrawFlags;
3126 }
3127 
3128 /// @unimplemented
STDMETHODIMP_(BOOL)3129 STDMETHODIMP_(BOOL)
3130 CUIFButton2::OnPaintTheme(HDC hDC)
3131 {
3132     //FIXME
3133     return FALSE;
3134 }
3135 
STDMETHODIMP_(void)3136 STDMETHODIMP_(void)
3137 CUIFButton2::OnPaintNoTheme(HDC hDC)
3138 {
3139     if (!m_pScheme)
3140        return;
3141 
3142     INT width = m_rc.right - m_rc.left;
3143     INT height = m_rc.bottom - m_rc.top;
3144     HDC hdcMem = ::CreateCompatibleDC(hDC);
3145     if (!hdcMem)
3146         return;
3147 
3148     HBITMAP hbmMem = ::CreateCompatibleBitmap(hDC, width, height);
3149     if ( !hbmMem )
3150     {
3151         ::DeleteDC(hdcMem);
3152         return;
3153     }
3154 
3155     HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbmMem);
3156     HGDIOBJ hFontOld = ::SelectObject(hdcMem, m_hFont);
3157     RECT rcBack = { 0, 0, width, height };
3158 
3159     INT cxText = 0, cyText = 0, cxContent = 0, cyContent = 0;
3160     INT cxyBorders, cxButton, cyButton;
3161     if (m_pszButtonText)
3162     {
3163         cxText = m_TextSize.cx;
3164         cyText = m_TextSize.cy;
3165     }
3166 
3167     if (m_ButtonIcon.m_hIcon)
3168     {
3169         cxContent = m_IconSize.cx;
3170         cyContent = m_IconSize.cy;
3171     }
3172     else if (m_hbmButton1)
3173     {
3174         cxContent = m_BitmapSize.cx;
3175         cyContent = m_BitmapSize.cy;
3176     }
3177 
3178     if (m_style & UIF_BUTTON_VERTICAL)
3179     {
3180         cxyBorders = ((cyText && cyContent) ? 2 : 0);
3181 
3182         cxButton = cxContent;
3183         cyButton = cyText + cyContent + cxyBorders;
3184         if (cxText > cxContent)
3185             cxButton = cxText;
3186     }
3187     else
3188     {
3189         cxyBorders = ((cxText && cxContent) ? 2 : 0);
3190 
3191         cxButton = cxText + cxContent + cxyBorders;
3192         cyButton = cyContent;
3193         if (cyText > cyButton)
3194             cyButton = cyText;
3195     }
3196 
3197     INT xOffset, yOffset;
3198     if ((m_style & UIF_BUTTON_H_ALIGN_MASK) == UIF_BUTTON_H_ALIGN_CENTER)
3199         xOffset = (rcBack.left + rcBack.right - cxButton) / 2;
3200     else if ((m_style & UIF_BUTTON_H_ALIGN_MASK) == UIF_BUTTON_H_ALIGN_RIGHT)
3201         xOffset = rcBack.right - cxText - 2;
3202     else
3203         xOffset = rcBack.left + 2;
3204 
3205 
3206     if ((m_style & UIF_BUTTON_V_ALIGN_MASK) == UIF_BUTTON_V_ALIGN_MIDDLE)
3207         yOffset = (rcBack.top + rcBack.bottom - cyButton) / 2;
3208     else if ((m_style & UIF_BUTTON_V_ALIGN_MASK) == UIF_BUTTON_V_ALIGN_BOTTOM)
3209         yOffset = rcBack.bottom - cyButton - 2;
3210     else
3211         yOffset = rcBack.top + 2;
3212 
3213     RECT rc = { xOffset, yOffset, xOffset + cxButton, cyButton + yOffset };
3214     SIZE offsetSize = { 0, 0 };
3215     DWORD dwDrawFlags = MakeDrawFlag();
3216     m_pScheme->GetCtrlFaceOffset(((m_style & 0x200) ? 0xA5 : 0x54),
3217                                  dwDrawFlags,
3218                                  &offsetSize);
3219     ::OffsetRect(&rc, offsetSize.cx, offsetSize.cy);
3220 
3221     RECT rcImage, rcText;
3222     if (m_style & UIF_BUTTON_VERTICAL)
3223     {
3224         rcImage.left    = (rc.left + rc.right - cxContent) / 2;
3225         rcImage.top     = rc.top;
3226         rcImage.right   = rcImage.left + cxContent;
3227         rcImage.bottom  = rc.top + cyContent;
3228         rcText.left     = (rc.left + rc.right - cxText) / 2;
3229         rcText.top      = rc.bottom - cyText;
3230         rcText.right    = rcText.left + cxText;
3231         rcText.bottom   = rc.bottom;
3232     }
3233     else
3234     {
3235         rcImage.left    = rc.left;
3236         rcImage.top     = (rc.top + rc.bottom - cyContent) / 2;
3237         rcImage.bottom  = rcImage.top + cyContent;
3238         rcImage.right   = rc.left + cxContent;
3239         rcText.left     = rc.right - cxText;
3240         rcText.top      = (rc.top + rc.bottom - cyText) / 2;
3241         rcText.right    = rc.right;
3242         rcText.bottom   = rcText.top + cyText;
3243     }
3244 
3245     if (IsRTL())
3246         m_pScheme->m_bMirroring = TRUE;
3247 
3248     m_pScheme->DrawCtrlBkgd(hdcMem,
3249                             &rcBack,
3250                             ((m_style & 0x200) ? 0xA5 : 0x54),
3251                             dwDrawFlags);
3252     if (m_pszButtonText)
3253     {
3254         m_pScheme->DrawCtrlText(hdcMem, &rcText, m_pszButtonText, -1, dwDrawFlags,
3255                                 !!(m_style & UIF_BUTTON_VERTICAL));
3256     }
3257 
3258     if (m_ButtonIcon.m_hIcon)
3259         m_pScheme->DrawCtrlIcon(hdcMem, &rcImage, m_ButtonIcon.m_hIcon, dwDrawFlags, &m_IconSize);
3260     else if (m_hbmButton1)
3261         m_pScheme->DrawCtrlBitmap(hdcMem, &rcImage, m_hbmButton1, m_hbmButton2, dwDrawFlags);
3262 
3263     if (IsRTL())
3264         m_pScheme->m_bMirroring = FALSE;
3265 
3266     m_pScheme->DrawCtrlEdge(hdcMem,
3267                             &rcBack,
3268                             ((m_style & 0x200) ? 0xA5 : 0x54),
3269                             dwDrawFlags);
3270 
3271     ::BitBlt(hDC, m_rc.left, m_rc.top, width, height, hdcMem, 0, 0, SRCCOPY);
3272     ::SelectObject(hdcMem, hFontOld);
3273     ::SelectObject(hdcMem, hbmOld);
3274     ::DeleteObject(hbmMem);
3275 }
3276 
3277 /////////////////////////////////////////////////////////////////////////////
3278 // CUIFGripper
3279 
CUIFGripper(CUIFObject * pParent,LPCRECT prc,DWORD style)3280 CUIFGripper::CUIFGripper(CUIFObject *pParent, LPCRECT prc, DWORD style)
3281     : CUIFObject(pParent, 0, prc, style)
3282 {
3283     m_iStateId = 0;
3284     m_pszClassList = L"REBAR";
3285     if (m_style & UIF_GRIPPER_VERTICAL)
3286         m_iPartId = RP_GRIPPERVERT;
3287     else
3288         m_iPartId = RP_GRIPPER;
3289 }
3290 
~CUIFGripper()3291 CUIFGripper::~CUIFGripper()
3292 {
3293 }
3294 
STDMETHODIMP_(void)3295 STDMETHODIMP_(void)
3296 CUIFGripper::OnMouseMove(LONG x, LONG y)
3297 {
3298     if (IsCapture())
3299     {
3300         POINT pt;
3301         ::GetCursorPos(&pt);
3302         m_pWindow->Move(pt.x - m_ptGripper.x, pt.y - m_ptGripper.y, -1, -1);
3303     }
3304 }
3305 
STDMETHODIMP_(void)3306 STDMETHODIMP_(void)
3307 CUIFGripper::OnLButtonDown(LONG x, LONG y)
3308 {
3309     StartCapture();
3310     m_ptGripper.x = x;
3311     m_ptGripper.y = y;
3312     ::ScreenToClient(*m_pWindow, &m_ptGripper);
3313     RECT rc;
3314     ::GetWindowRect(*m_pWindow, &rc);
3315     m_ptGripper.x -= rc.left;
3316     m_ptGripper.y -= rc.top;
3317 }
3318 
STDMETHODIMP_(void)3319 STDMETHODIMP_(void)
3320 CUIFGripper::OnLButtonUp(LONG x, LONG y)
3321 {
3322     if (IsCapture())
3323         EndCapture();
3324 }
3325 
STDMETHODIMP_(BOOL)3326 STDMETHODIMP_(BOOL)
3327 CUIFGripper::OnPaintTheme(HDC hDC)
3328 {
3329     if (FAILED(EnsureThemeData(*m_pWindow)))
3330         return FALSE;
3331 
3332     if (m_style & UIF_GRIPPER_VERTICAL)
3333     {
3334         m_rc.top += 2;
3335         m_rc.bottom -= 2;
3336     }
3337     else
3338     {
3339         m_rc.left += 2;
3340         m_rc.right -= 2;
3341     }
3342 
3343     if (FAILED(DrawThemeBackground(hDC, 1, &m_rc, 0)))
3344         return FALSE;
3345 
3346     return TRUE;
3347 }
3348 
STDMETHODIMP_(void)3349 STDMETHODIMP_(void)
3350 CUIFGripper::OnPaintNoTheme(HDC hDC)
3351 {
3352     if (m_pScheme)
3353     {
3354         m_pScheme->DrawDragHandle(hDC, &m_rc, !!(m_style & UIF_GRIPPER_VERTICAL));
3355         return;
3356     }
3357 
3358     RECT rc;
3359     if (m_style & UIF_GRIPPER_VERTICAL)
3360         rc = { m_rc.left, m_rc.top + 1, m_rc.right, m_rc.top + 4 };
3361     else
3362         rc = { m_rc.left + 1, m_rc.top, m_rc.left + 4, m_rc.bottom };
3363 
3364     ::DrawEdge(hDC, &rc, BDR_RAISEDINNER, BF_RECT);
3365 }
3366 
STDMETHODIMP_(BOOL)3367 STDMETHODIMP_(BOOL)
3368 CUIFGripper::OnSetCursor(UINT uMsg, LONG x, LONG y)
3369 {
3370     HCURSOR hCursor = ::LoadCursor(NULL, IDC_SIZEALL);
3371     ::SetCursor(hCursor);
3372     return TRUE;
3373 }
3374 
STDMETHODIMP_(void)3375 STDMETHODIMP_(void)
3376 CUIFGripper::SetStyle(DWORD style)
3377 {
3378     m_style = style;
3379     if (m_style & UIF_GRIPPER_VERTICAL)
3380         SetActiveTheme(L"REBAR", RP_GRIPPERVERT, 0);
3381     else
3382         SetActiveTheme(L"REBAR", RP_GRIPPER, 0);
3383 }
3384 
3385 /////////////////////////////////////////////////////////////////////////////
3386 // CUIFToolbarMenuButton
3387 
CUIFToolbarMenuButton(CUIFToolbarButton * pParent,DWORD nObjectID,LPCRECT prc,DWORD style)3388 CUIFToolbarMenuButton::CUIFToolbarMenuButton(
3389     CUIFToolbarButton *pParent,
3390     DWORD nObjectID,
3391     LPCRECT prc,
3392     DWORD style) : CUIFButton2(pParent, nObjectID, prc, style)
3393 {
3394     m_pToolbarButton = pParent;
3395 
3396     HFONT hFont = ::CreateFontW(8, 8, 0, 0, FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET,
3397                                 0, 0, 0, 0, L"Marlett");
3398     SetFont(hFont);
3399     SetText(L"u"); // downward triangle
3400 }
3401 
~CUIFToolbarMenuButton()3402 CUIFToolbarMenuButton::~CUIFToolbarMenuButton()
3403 {
3404     ::DeleteObject(m_hFont);
3405     SetFont(NULL);
3406 }
3407 
STDMETHODIMP_(void)3408 STDMETHODIMP_(void)
3409 CUIFToolbarMenuButton::OnLButtonUp(LONG x, LONG y)
3410 {
3411     CUIFButton::OnLButtonUp(x, y);
3412     m_pToolbarButton->OnUnknownMouse0();
3413 }
3414 
STDMETHODIMP_(BOOL)3415 STDMETHODIMP_(BOOL)
3416 CUIFToolbarMenuButton::OnSetCursor(UINT uMsg, LONG x, LONG y)
3417 {
3418     m_pToolbarButton->OnSetCursor(uMsg, x, y);
3419     return FALSE;
3420 }
3421 
3422 /////////////////////////////////////////////////////////////////////////////
3423 // CUIFToolbarButtonElement
3424 
CUIFToolbarButtonElement(CUIFToolbarButton * pParent,DWORD nObjectID,LPCRECT prc,DWORD style)3425 CUIFToolbarButtonElement::CUIFToolbarButtonElement(
3426     CUIFToolbarButton *pParent,
3427     DWORD nObjectID,
3428     LPCRECT prc,
3429     DWORD style) : CUIFButton2(pParent, nObjectID, prc, style)
3430 {
3431     m_pToolbarButton = pParent;
3432 }
3433 
STDMETHODIMP_(LPCWSTR)3434 STDMETHODIMP_(LPCWSTR)
3435 CUIFToolbarButtonElement::GetToolTip()
3436 {
3437     if (m_pToolbarButton)
3438         return m_pToolbarButton->GetToolTip();
3439     return NULL;
3440 }
3441 
STDMETHODIMP_(void)3442 STDMETHODIMP_(void)
3443 CUIFToolbarButtonElement::OnLButtonUp(LONG x, LONG y)
3444 {
3445     CUIFButton::OnLButtonUp(x, y);
3446     if ((m_pToolbarButton->m_dwToolbarButtonFlags & 0x30000) == 0x20000)
3447         m_pToolbarButton->OnUnknownMouse0();
3448     else
3449         m_pToolbarButton->OnLeftClick();
3450 }
3451 
STDMETHODIMP_(void)3452 STDMETHODIMP_(void)
3453 CUIFToolbarButtonElement::OnRButtonUp(LONG x, LONG y)
3454 {
3455     if ((m_pToolbarButton->m_dwToolbarButtonFlags & 0x30000) != 0x20000)
3456         m_pToolbarButton->OnRightClick();
3457 }
3458 
3459 /////////////////////////////////////////////////////////////////////////////
3460 // CUIFToolbarButton
3461 
CUIFToolbarButton(CUIFObject * pParent,DWORD nObjectID,LPCRECT prc,DWORD style,DWORD dwToolbarButtonFlags,LPCWSTR pszUnknownText)3462 CUIFToolbarButton::CUIFToolbarButton(
3463     CUIFObject *pParent,
3464     DWORD nObjectID,
3465     LPCRECT prc,
3466     DWORD style,
3467     DWORD dwToolbarButtonFlags,
3468     LPCWSTR pszUnknownText) : CUIFObject(pParent, nObjectID, prc, style)
3469 {
3470     m_dwToolbarButtonFlags = dwToolbarButtonFlags;
3471     m_pszUnknownText = pszUnknownText;
3472 }
3473 
Init()3474 BOOL CUIFToolbarButton::Init()
3475 {
3476     RECT rc1, rc2;
3477     rc1 = rc2 = m_rc;
3478 
3479     if ((m_dwToolbarButtonFlags & 0x30000) == 0x30000)
3480     {
3481         rc1.right -= 12;
3482         rc2.left = rc1.right + 1;
3483     }
3484 
3485     DWORD style = UIF_BUTTON_LARGE_ICON | UIF_BUTTON_V_ALIGN_MIDDLE | UIF_BUTTON_H_ALIGN_CENTER;
3486     if (m_dwToolbarButtonFlags & 0x2000)
3487         style |= 0x10;
3488     if (m_dwToolbarButtonFlags & 0x80000)
3489         style |= UIF_BUTTON_VERTICAL;
3490     m_pToolbarButtonElement = new(cicNoThrow) CUIFToolbarButtonElement(this, m_nObjectID, &rc1, style);
3491     if (!m_pToolbarButtonElement)
3492         return FALSE;
3493 
3494     m_pToolbarButtonElement->Initialize();
3495     AddUIObj(m_pToolbarButtonElement);
3496 
3497     if (!m_bEnable)
3498         m_pToolbarButtonElement->Enable(FALSE);
3499 
3500     if ((m_dwToolbarButtonFlags & 0x30000) == 0x30000)
3501     {
3502         style = UIF_BUTTON_LARGE_ICON | UIF_BUTTON_H_ALIGN_CENTER;
3503         if (m_dwToolbarButtonFlags & 0x80000)
3504             style |= UIF_BUTTON_VERTICAL;
3505 
3506         m_pToolbarMenuButton = new(cicNoThrow) CUIFToolbarMenuButton(this, 0, &rc2, style);
3507         if (!m_pToolbarMenuButton)
3508             return FALSE;
3509 
3510         m_pToolbarMenuButton->Initialize();
3511         AddUIObj(m_pToolbarMenuButton);
3512 
3513         if (!m_bEnable)
3514             m_pToolbarMenuButton->Enable(FALSE);
3515     }
3516 
3517     return TRUE;
3518 }
3519 
GetIcon()3520 HICON CUIFToolbarButton::GetIcon()
3521 {
3522     return m_pToolbarButtonElement->m_ButtonIcon.m_hIcon;
3523 }
3524 
SetIcon(HICON hIcon)3525 void CUIFToolbarButton::SetIcon(HICON hIcon)
3526 {
3527     m_pToolbarButtonElement->SetIcon(hIcon);
3528 }
3529 
STDMETHODIMP_(void)3530 STDMETHODIMP_(void)
3531 CUIFToolbarButton::ClearWndObj()
3532 {
3533     if (m_pToolbarButtonElement)
3534         m_pToolbarButtonElement->ClearWndObj();
3535     if (m_pToolbarMenuButton)
3536         m_pToolbarMenuButton->ClearWndObj();
3537 
3538     CUIFObject::ClearWndObj();
3539 }
3540 
STDMETHODIMP_(void)3541 STDMETHODIMP_(void)
3542 CUIFToolbarButton::DetachWndObj()
3543 {
3544     if (m_pToolbarButtonElement)
3545         m_pToolbarButtonElement->DetachWndObj();
3546     if (m_pToolbarMenuButton)
3547         m_pToolbarMenuButton->DetachWndObj();
3548 
3549     CUIFObject::DetachWndObj();
3550 }
3551 
STDMETHODIMP_(void)3552 STDMETHODIMP_(void)
3553 CUIFToolbarButton::Enable(BOOL bEnable)
3554 {
3555     CUIFObject::Enable(bEnable);
3556     if (m_pToolbarButtonElement)
3557         m_pToolbarButtonElement->Enable(bEnable);
3558     if (m_pToolbarMenuButton)
3559         m_pToolbarMenuButton->Enable(bEnable);
3560 }
3561 
STDMETHODIMP_(LPCWSTR)3562 STDMETHODIMP_(LPCWSTR)
3563 CUIFToolbarButton::GetToolTip()
3564 {
3565     return CUIFObject::GetToolTip();
3566 }
3567 
STDMETHODIMP_(void)3568 STDMETHODIMP_(void)
3569 CUIFToolbarButton::SetActiveTheme(LPCWSTR pszClassList, INT iPartId, INT iStateId)
3570 {
3571     if (m_pToolbarButtonElement)
3572         m_pToolbarButtonElement->SetActiveTheme(pszClassList, iPartId, iStateId);
3573     if (m_pToolbarMenuButton)
3574         m_pToolbarMenuButton->SetActiveTheme(pszClassList, iPartId, iStateId);
3575 
3576     m_pszClassList = pszClassList;
3577     m_iPartId = iPartId;
3578     m_iStateId = iStateId;
3579 }
3580 
STDMETHODIMP_(void)3581 STDMETHODIMP_(void)
3582 CUIFToolbarButton::SetFont(HFONT hFont)
3583 {
3584     m_pToolbarButtonElement->SetFont(hFont);
3585 }
3586 
STDMETHODIMP_(void)3587 STDMETHODIMP_(void)
3588 CUIFToolbarButton::SetRect(LPCRECT prc)
3589 {
3590     CUIFObject::SetRect(prc);
3591 
3592     RECT rc1, rc2;
3593     rc1 = rc2 = m_rc;
3594 
3595     if ((m_dwToolbarButtonFlags & 0x30000) == 0x30000)
3596     {
3597         rc1.right -= 12;
3598         rc2.left = rc1.right + 1;
3599     }
3600 
3601     if (m_pToolbarButtonElement)
3602         m_pToolbarButtonElement->SetRect(&rc1);
3603     if (m_pToolbarMenuButton)
3604         m_pToolbarMenuButton->SetRect(&rc2);
3605 }
3606 
STDMETHODIMP_(void)3607 STDMETHODIMP_(void)
3608 CUIFToolbarButton::SetToolTip(LPCWSTR pszToolTip)
3609 {
3610     CUIFObject::SetToolTip(pszToolTip);
3611     if (m_pToolbarButtonElement)
3612         m_pToolbarButtonElement->SetToolTip(pszToolTip);
3613     if (m_pToolbarMenuButton)
3614         m_pToolbarMenuButton->SetToolTip(pszToolTip);
3615 }
3616 
3617 /////////////////////////////////////////////////////////////////////////////
3618 // CUIFWndFrame
3619 
CUIFWndFrame(CUIFObject * pParent,LPCRECT prc,DWORD style)3620 CUIFWndFrame::CUIFWndFrame(
3621     CUIFObject *pParent,
3622     LPCRECT prc,
3623     DWORD style) : CUIFObject(pParent, 0, prc, style)
3624 {
3625     m_iPartId = 7;
3626     m_iStateId = 0;
3627     m_pszClassList = L"WINDOW";
3628     m_dwHitTest = 0;
3629     m_cxFrame = m_cyFrame = 0;
3630 
3631     if (m_pScheme)
3632     {
3633         if ((m_style & 0xF) && (m_style & 0xF) <= 2)
3634         {
3635             m_cxFrame = m_pScheme->CxSizeFrame();
3636             m_cyFrame = m_pScheme->CySizeFrame();
3637         }
3638         else
3639         {
3640             m_cxFrame = m_pScheme->CxWndBorder();
3641             m_cyFrame = m_pScheme->CyWndBorder();
3642         }
3643     }
3644 
3645     m_cxMin = GetSystemMetrics(SM_CXMIN);
3646     m_cyMin = GetSystemMetrics(SM_CYMIN);
3647 }
3648 
GetFrameSize(LPSIZE pSize)3649 void CUIFWndFrame::GetFrameSize(LPSIZE pSize)
3650 {
3651     pSize->cx = m_cxFrame;
3652     pSize->cy = m_cyFrame;
3653 }
3654 
HitTest(LONG x,LONG y)3655 DWORD CUIFWndFrame::HitTest(LONG x, LONG y)
3656 {
3657     DWORD dwFlags = 0;
3658     if ( m_rc.left <= x && x < m_rc.left + m_cxFrame)
3659         dwFlags |= 0x10;
3660     if (m_rc.top <= y && y < m_rc.top + m_cyFrame )
3661         dwFlags |= 0x20;
3662     if (m_rc.right - m_cxFrame <= x && x < m_rc.right)
3663         dwFlags |= 0x40;
3664     if (m_rc.bottom - m_cyFrame <= y && y < m_rc.bottom)
3665         dwFlags |= 0x80;
3666     return dwFlags;
3667 }
3668 
STDMETHODIMP_(void)3669 STDMETHODIMP_(void)
3670 CUIFWndFrame::OnMouseMove(LONG x, LONG y)
3671 {
3672     if (!IsCapture())
3673         return;
3674 
3675     POINT Point;
3676     ::ClientToScreen(*m_pWindow, &Point);
3677 
3678     RECT rc = m_rcWnd;
3679 
3680     if (m_dwHitTest & 0x10)
3681         rc.left = Point.x + m_rcWnd.left - m_ptHit.x;
3682 
3683     if (m_dwHitTest & 0x20)
3684         rc.top = Point.y + m_rcWnd.top - m_ptHit.y;
3685 
3686     if (m_dwHitTest & 0x40)
3687     {
3688         rc.right = Point.x + m_rcWnd.right - m_ptHit.x;
3689         if (rc.right <= rc.left + m_cxMin)
3690             rc.right = rc.left + m_cxMin;
3691     }
3692 
3693     if (m_dwHitTest & 0x80)
3694     {
3695         rc.bottom = Point.y + m_rcWnd.bottom - m_ptHit.y;
3696         if (rc.bottom <= rc.top + m_cyMin)
3697             rc.bottom = rc.top + m_cyMin;
3698     }
3699 
3700     m_pWindow->Move(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
3701 }
3702 
STDMETHODIMP_(void)3703 STDMETHODIMP_(void)
3704 CUIFWndFrame::OnLButtonDown(LONG x, LONG y)
3705 {
3706     POINT Point = { x, y };
3707     DWORD hitTest = m_style & HitTest(x, y);
3708     if (!hitTest)
3709         return;
3710 
3711     ::ClientToScreen(*m_pWindow, &Point);
3712     m_ptHit = Point;
3713     m_pWindow = m_pWindow;
3714     m_dwHitTest = hitTest;
3715     ::GetWindowRect(*m_pWindow, &m_rcWnd);
3716     StartCapture();
3717 }
3718 
STDMETHODIMP_(void)3719 STDMETHODIMP_(void)
3720 CUIFWndFrame::OnLButtonUp(LONG x, LONG y)
3721 {
3722     if (IsCapture())
3723         EndCapture();
3724 }
3725 
STDMETHODIMP_(BOOL)3726 STDMETHODIMP_(BOOL)
3727 CUIFWndFrame::OnPaintTheme(HDC hDC)
3728 {
3729     if (FAILED(EnsureThemeData(*m_pWindow)))
3730         return FALSE;
3731 
3732     RECT rc = m_rc;
3733     rc.right = m_cxFrame;
3734     if (FAILED(DrawThemeEdge(hDC, 0, &rc, 5, 1, NULL)))
3735         return FALSE;
3736 
3737     rc = m_rc;
3738     rc.left = rc.right - m_cxFrame;
3739     if (FAILED(DrawThemeEdge(hDC, 0, &rc, 10, 4, NULL)))
3740         return FALSE;
3741 
3742     rc = m_rc;
3743     rc.bottom = m_cyFrame;
3744     if (FAILED(DrawThemeEdge(hDC, 0, &rc, 5, 2, NULL)))
3745         return FALSE;
3746 
3747     rc = m_rc;
3748     rc.top = rc.bottom - m_cyFrame;
3749     if (FAILED(DrawThemeEdge(hDC, 0, &rc, 10, 8, NULL)))
3750         return FALSE;
3751 
3752     return TRUE;
3753 }
3754 
STDMETHODIMP_(void)3755 STDMETHODIMP_(void)
3756 CUIFWndFrame::OnPaintNoTheme(HDC hDC)
3757 {
3758     if (!m_pScheme)
3759         return;
3760 
3761     DWORD type = 0;
3762     if ((m_style & 0xF) == 1)
3763         type = 1;
3764     else if ( (m_style & 0xF) == 2 )
3765         type = 2;
3766 
3767     m_pScheme->DrawWndFrame(hDC, &m_rc, type, m_cxFrame, m_cyFrame);
3768 }
3769 
STDMETHODIMP_(BOOL)3770 STDMETHODIMP_(BOOL)
3771 CUIFWndFrame::OnSetCursor(UINT uMsg, LONG x, LONG y)
3772 {
3773     DWORD dwHitTest = m_dwHitTest;
3774     if (!IsCapture())
3775         dwHitTest = m_style & HitTest(x, y);
3776 
3777     LPTSTR pszCursor = NULL;
3778     switch (dwHitTest)
3779     {
3780         case 0x30:
3781         case 0xC0:
3782             pszCursor = IDC_SIZENWSE;
3783             break;
3784         case 0x90:
3785         case 0x60:
3786             pszCursor = IDC_SIZENESW;
3787             break;
3788         case 0x10:
3789         case 0x40:
3790             pszCursor = IDC_SIZEWE;
3791             break;
3792         case 0x20:
3793         case 0x80:
3794             pszCursor = IDC_SIZENS;
3795             break;
3796         default:
3797             return FALSE;
3798     }
3799 
3800     HCURSOR hCursor = ::LoadCursor(NULL, pszCursor);
3801     ::SetCursor(hCursor);
3802     return TRUE;
3803 }
3804 
3805 /////////////////////////////////////////////////////////////////////////////
3806 // CUIFBalloonButton
3807 
CUIFBalloonButton(CUIFObject * pParent,DWORD nObjectID,LPCRECT prc,DWORD style)3808 CUIFBalloonButton::CUIFBalloonButton(
3809     CUIFObject *pParent,
3810     DWORD nObjectID,
3811     LPCRECT prc,
3812     DWORD style) : CUIFButton(pParent, nObjectID, prc, style)
3813 {
3814     m_nCommandID = 0;
3815 }
3816 
STDMETHODIMP_(void)3817 STDMETHODIMP_(void)
3818 CUIFBalloonButton::OnPaint(HDC hDC)
3819 {
3820     RECT rc = m_rc;
3821     ::OffsetRect(&rc, -rc.left, -rc.top);
3822 
3823     HDC hMemDC = ::CreateCompatibleDC(hDC);
3824     HBITMAP hbmMem = ::CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
3825     HGDIOBJ hbmOld = ::SelectObject(hMemDC, hbmMem);
3826 
3827     BOOL bPressed;
3828     COLORREF rgbShadow, rgbBorder;
3829     if (m_uButtonStatus == 1)
3830     {
3831         bPressed = TRUE;
3832         rgbShadow = ::GetSysColor(COLOR_BTNSHADOW);
3833         rgbBorder = ::GetSysColor(COLOR_BTNHIGHLIGHT);
3834     }
3835     else
3836     {
3837         bPressed = FALSE;
3838         if (m_uButtonStatus < 4)
3839         {
3840             rgbShadow = ::GetSysColor(COLOR_BTNHIGHLIGHT);
3841             rgbBorder = ::GetSysColor(COLOR_BTNSHADOW);
3842         }
3843         else
3844         {
3845             rgbShadow = ::GetSysColor(COLOR_INFOBK);
3846             rgbBorder = ::GetSysColor(COLOR_INFOBK);
3847         }
3848     }
3849 
3850     COLORREF rgbInfoBk = ::GetSysColor(COLOR_INFOBK);
3851     HBRUSH hbrBack = ::CreateSolidBrush(rgbInfoBk);
3852     ::FillRect(hMemDC, &rc, hbrBack);
3853     ::DeleteObject(hbrBack);
3854 
3855     DrawTextProc(hMemDC, &rc, bPressed);
3856 
3857     HBRUSH hNullBrush = (HBRUSH)::GetStockObject(NULL_BRUSH);
3858     HGDIOBJ hbrOld = ::SelectObject(hMemDC, hNullBrush);
3859 
3860     HPEN hPen = ::CreatePen(PS_SOLID, 0, rgbShadow);
3861     HGDIOBJ hPenOld = ::SelectObject(hMemDC, hPen);
3862     ::RoundRect(hMemDC, rc.left, rc.top, rc.right - 1, rc.bottom - 1, 6, 6);
3863     ::SelectObject(hMemDC, hPenOld);
3864     ::DeleteObject(hPen);
3865 
3866     hPen = ::CreatePen(PS_SOLID, 0, rgbBorder);
3867     hPenOld = ::SelectObject(hMemDC, hPen);
3868     ::RoundRect(hMemDC, rc.left + 1, rc.top + 1, rc.right, rc.bottom, 6, 6);
3869     ::SelectObject(hMemDC, hPenOld);
3870     ::DeleteObject(hPen);
3871 
3872     hPen = ::CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNFACE));
3873     hPenOld = ::SelectObject(hMemDC, hPen);
3874     ::RoundRect(hMemDC, rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1, 6, 6);
3875     ::SelectObject(hMemDC, hPenOld);
3876     ::DeleteObject(hPen);
3877 
3878     ::SelectObject(hMemDC, hbrOld);
3879     ::BitBlt(hDC, m_rc.left, m_rc.top, m_rc.right - m_rc.left, m_rc.bottom - m_rc.top,
3880              hMemDC, rc.left, rc.top, SRCCOPY);
3881     ::SelectObject(hMemDC, hbmOld);
3882     ::DeleteObject(hbmMem);
3883     ::DeleteDC(hMemDC);
3884 }
3885 
3886 void
DrawTextProc(HDC hDC,LPCRECT prc,BOOL bPressed)3887 CUIFBalloonButton::DrawTextProc(HDC hDC, LPCRECT prc, BOOL bPressed)
3888 {
3889     if (!m_pszButtonText)
3890         return;
3891 
3892     UINT uFlags = DT_SINGLELINE;
3893 
3894     if ((m_style & UIF_BUTTON_H_ALIGN_MASK) == UIF_BUTTON_H_ALIGN_CENTER)
3895         uFlags |= DT_CENTER;
3896     else if ((m_style & UIF_BUTTON_H_ALIGN_MASK) == UIF_BUTTON_H_ALIGN_RIGHT)
3897         uFlags |= DT_RIGHT;
3898 
3899     if ((m_style & UIF_BUTTON_V_ALIGN_MASK) == UIF_BUTTON_V_ALIGN_MIDDLE)
3900         uFlags |= DT_VCENTER;
3901     else if ((m_style & UIF_BUTTON_V_ALIGN_MASK) == UIF_BUTTON_V_ALIGN_BOTTOM)
3902         uFlags |= DT_BOTTOM;
3903 
3904     COLORREF rgbOldColor = ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNTEXT));
3905     INT nOldBkMode = ::SetBkMode(hDC, TRANSPARENT);
3906 
3907     RECT rc = *prc;
3908     if (bPressed)
3909         ::OffsetRect(&rc, 1, 1);
3910 
3911     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
3912     ::DrawTextW(hDC, m_pszButtonText, -1, &rc, uFlags);
3913     ::SelectObject(hDC, hFontOld);
3914 
3915     ::SetBkMode(hDC, nOldBkMode);
3916     ::SetTextColor(hDC, rgbOldColor);
3917 }
3918 
3919 /////////////////////////////////////////////////////////////////////////////
3920 // CUIFBalloonWindow
3921 
CUIFBalloonWindow(HINSTANCE hInst,DWORD style)3922 CUIFBalloonWindow::CUIFBalloonWindow(HINSTANCE hInst, DWORD style) : CUIFWindow(hInst, style)
3923 {
3924     m_dwUnknown6 = -1;
3925     m_nActionID = -1;
3926     m_hRgn = NULL;
3927     m_pszBalloonText = NULL;
3928     m_bHasBkColor = m_bHasTextColor = FALSE;
3929     m_rgbBkColor = 0;
3930     m_rgbTextColor = 0;
3931     m_ptTarget.x = m_ptTarget.y = 0;
3932     ZeroMemory(&m_rcExclude, sizeof(m_rcExclude));
3933     m_dwUnknown7 = 0;
3934     m_nBalloonType = 0;
3935     m_dwUnknown8[0] = 0;
3936     m_dwUnknown8[1] = 0;
3937     m_ptBalloon.x = m_ptBalloon.y = 0;
3938     m_cButtons = 0;
3939     m_hwndNotif = NULL;
3940     m_uNotifMsg = 0;
3941     m_rcMargin.left = 8;
3942     m_rcMargin.top = 8;
3943     m_rcMargin.right = 8;
3944     m_rcMargin.bottom = 8;
3945 }
3946 
~CUIFBalloonWindow()3947 CUIFBalloonWindow::~CUIFBalloonWindow()
3948 {
3949     if (m_pszBalloonText)
3950     {
3951         delete[] m_pszBalloonText;
3952         m_pszBalloonText = NULL;
3953     }
3954 }
3955 
STDMETHODIMP_(BOOL)3956 STDMETHODIMP_(BOOL)
3957 CUIFBalloonWindow::Initialize()
3958 {
3959     CUIFWindow::Initialize();
3960 
3961     if ((m_style & UIF_BALLOON_WINDOW_TYPE_MASK) == UIF_BALLOON_WINDOW_OK)
3962     {
3963         AddButton(IDOK);
3964     }
3965     else if ((m_style & UIF_BALLOON_WINDOW_TYPE_MASK) == UIF_BALLOON_WINDOW_YESNO)
3966     {
3967         AddButton(IDYES);
3968         AddButton(IDNO);
3969     }
3970 
3971     return TRUE;
3972 }
3973 
STDMETHODIMP_(void)3974 STDMETHODIMP_(void)
3975 CUIFBalloonWindow::OnCreate(HWND hWnd)
3976 {
3977     m_nActionID = -1;
3978     AdjustPos();
3979 }
3980 
STDMETHODIMP_(void)3981 STDMETHODIMP_(void)
3982 CUIFBalloonWindow::OnDestroy(HWND hWnd)
3983 {
3984     SendNotification(m_nActionID);
3985     DoneWindowRegion();
3986 }
3987 
STDMETHODIMP_(void)3988 STDMETHODIMP_(void)
3989 CUIFBalloonWindow::OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
3990 {
3991     CUIFBalloonButton *pButton = NULL;
3992 
3993     switch (wParam)
3994     {
3995         case VK_RETURN:
3996             pButton = (CUIFBalloonButton *)FindUIObject(0);
3997             break;
3998         case VK_ESCAPE:
3999             m_nActionID = -1;
4000             ::DestroyWindow(m_hWnd);
4001             return;
4002         case TEXT('Y'):
4003             pButton = FindButton(IDYES);
4004             break;
4005         case TEXT('N'):
4006             pButton = FindButton(IDNO);
4007             break;
4008     }
4009 
4010     if (!pButton)
4011         return;
4012 
4013     m_nActionID = pButton->m_nCommandID;
4014     ::DestroyWindow(m_hWnd);
4015 }
4016 
STDMETHODIMP_(LRESULT)4017 STDMETHODIMP_(LRESULT)
4018 CUIFBalloonWindow::OnObjectNotify(CUIFObject *pObject, WPARAM wParam, LPARAM lParam)
4019 {
4020     CUIFBalloonButton *pButton = (CUIFBalloonButton *)pObject;
4021     m_nActionID = pButton->m_nCommandID;
4022     ::DestroyWindow(m_hWnd);
4023     return 0;
4024 }
4025 
STDMETHODIMP_(void)4026 STDMETHODIMP_(void)
4027 CUIFBalloonWindow::OnPaint(HDC hDC)
4028 {
4029     RECT rc;
4030     GetRect(&rc);
4031     PaintFrameProc(hDC, &rc);
4032 
4033     switch (m_nBalloonType)
4034     {
4035         case 1:
4036             rc.top += 16;
4037             break;
4038         case 2:
4039             rc.right -= 16;
4040             break;
4041         case 3:
4042             rc.left += 16;
4043             break;
4044         default:
4045             rc.bottom -= 16;
4046             break;
4047     }
4048 
4049     RECT rcMargin;
4050     GetMargin(&rcMargin);
4051 
4052     rc.left += rcMargin.left;
4053     rc.top += rcMargin.top;
4054     rc.right -= rcMargin.right;
4055     rc.bottom -= rcMargin.bottom;
4056 
4057     PaintMessageProc(hDC, &rc, m_pszBalloonText);
4058 }
4059 
4060 void
AddButton(UINT nCommandId)4061 CUIFBalloonWindow::AddButton(UINT nCommandId)
4062 {
4063     RECT rc = { 0, 0, 0, 0 };
4064     if (!((IDOK <= nCommandId) && (nCommandId <= IDNO)))
4065         return;
4066 
4067     CUIFBalloonButton *pButton = new(cicNoThrow) CUIFBalloonButton(this, m_cButtons, &rc, 5);
4068     if (!pButton)
4069         return;
4070 
4071     pButton->Initialize();
4072     pButton->m_nCommandID = nCommandId;
4073 
4074     LPCWSTR pszText;
4075 #ifdef IDS_OK
4076     extern HINSTANCE g_hInst;
4077     WCHAR szText[64];
4078     ::LoadStringW(g_hInst, IDS_OK + (nCommandId - IDOK), szText, _countof(szText));
4079     pszText = szText;
4080 #else
4081     switch (nCommandId)
4082     {
4083         case IDOK:      pszText = L"OK";      break;
4084         case IDCANCEL:  pszText = L"Cancel";  break;
4085         case IDABORT:   pszText = L"&Abort";  break;
4086         case IDRETRY:   pszText = L"&Retry";  break;
4087         case IDIGNORE:  pszText = L"&Ignore"; break;
4088         case IDYES:     pszText = L"&Yes";    break;
4089         default:        pszText = L"&No";     break;
4090     }
4091 #endif
4092 
4093     pButton->SetText(pszText);
4094 
4095     AddUIObj(pButton);
4096     ++m_cButtons;
4097 }
4098 
4099 /// @unimplemented
4100 void
AdjustPos()4101 CUIFBalloonWindow::AdjustPos()
4102 {
4103     //FIXME
4104 }
4105 
4106 HRGN
CreateRegion(LPCRECT prc)4107 CUIFBalloonWindow::CreateRegion(LPCRECT prc)
4108 {
4109     POINT Points[4];
4110     HRGN hRgn;
4111     BOOL bFlag = FALSE;
4112     LONG x, y;
4113 
4114     switch (m_nBalloonType)
4115     {
4116         case 1:
4117             hRgn = ::CreateRoundRectRgn(prc->left, prc->top + 16, prc->right, prc->bottom, 16, 16);
4118             y = prc->top + 16;
4119             bFlag = TRUE;
4120             break;
4121 
4122         case 2:
4123             hRgn = ::CreateRoundRectRgn(prc->left, prc->top, prc->right - 16, prc->bottom, 16, 16);
4124             x = prc->right - 17;
4125             break;
4126 
4127         case 3:
4128             hRgn = ::CreateRoundRectRgn(prc->left + 16, prc->top, prc->right, prc->bottom, 16, 16);
4129             x = prc->left + 16;
4130             break;
4131 
4132         default:
4133             hRgn = ::CreateRoundRectRgn(prc->left, prc->top, prc->right, prc->bottom - 16, 16, 16);
4134             y = prc->bottom - 17;
4135             bFlag = TRUE;
4136             break;
4137     }
4138 
4139     if (bFlag)
4140     {
4141         x = Points[1].x = m_ptBalloon.x;
4142         Points[1].y = m_ptBalloon.y;
4143         Points[0].y = Points[2].y = Points[3].y = y;
4144         Points[2].x = x + 10 * (2 * (m_dwUnknown8[0] == 0) - 1);
4145     }
4146     else
4147     {
4148         Points[2].x = x;
4149         y = Points[0].y = Points[1].y = Points[3].y = m_ptBalloon.y;
4150         Points[1].x = m_ptBalloon.x;
4151         Points[2].y = y + 10 * (2 * (m_dwUnknown8[0] == 2) - 1);
4152     }
4153 
4154     Points[0].x = Points[3].x = x;
4155 
4156     HRGN hPolygonRgn = ::CreatePolygonRgn(Points, _countof(Points), WINDING);
4157     ::CombineRgn(hRgn, hRgn, hPolygonRgn, RGN_OR);
4158     ::DeleteObject(hPolygonRgn);
4159     return hRgn;
4160 }
4161 
4162 void
DoneWindowRegion()4163 CUIFBalloonWindow::DoneWindowRegion()
4164 {
4165     if (m_hRgn)
4166     {
4167         ::SetWindowRgn(m_hWnd, NULL, TRUE);
4168         ::DeleteObject(m_hRgn);
4169         m_hRgn = NULL;
4170     }
4171 }
4172 
4173 CUIFBalloonButton *
FindButton(UINT nCommandID)4174 CUIFBalloonWindow::FindButton(UINT nCommandID)
4175 {
4176     for (UINT iButton = 0; iButton < m_cButtons; ++iButton)
4177     {
4178         CUIFBalloonButton *pButton = (CUIFBalloonButton *)FindUIObject(iButton);
4179         if (pButton && (pButton->m_nCommandID == nCommandID))
4180             return pButton;
4181     }
4182     return NULL;
4183 }
4184 
4185 CUIFObject *
FindUIObject(UINT nObjectID)4186 CUIFBalloonWindow::FindUIObject(UINT nObjectID)
4187 {
4188     for (size_t iItem = 0; iItem < m_ObjectArray.size(); ++iItem)
4189     {
4190         CUIFObject *pObject = m_ObjectArray[iItem];
4191         if (pObject->m_nObjectID == nObjectID)
4192             return pObject;
4193     }
4194     return NULL;
4195 }
4196 
4197 COLORREF
GetBalloonBkColor()4198 CUIFBalloonWindow::GetBalloonBkColor()
4199 {
4200     if (m_bHasBkColor)
4201         return m_rgbBkColor;
4202     else
4203         return ::GetSysColor(COLOR_INFOBK);
4204 }
4205 
4206 COLORREF
GetBalloonTextColor()4207 CUIFBalloonWindow::GetBalloonTextColor()
4208 {
4209     if (m_bHasTextColor)
4210         return m_rgbTextColor;
4211     else
4212         return ::GetSysColor(COLOR_INFOTEXT);
4213 }
4214 
4215 void
GetButtonSize(LPSIZE pSize)4216 CUIFBalloonWindow::GetButtonSize(LPSIZE pSize)
4217 {
4218     HDC hDisplayDC = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
4219 
4220     TEXTMETRIC tm;
4221     HGDIOBJ hFontOld = ::SelectObject(hDisplayDC, m_hFont);
4222     ::GetTextMetrics(hDisplayDC, &tm);
4223     ::SelectObject(hDisplayDC, hFontOld);
4224     ::DeleteDC(hDisplayDC);
4225 
4226     pSize->cx = 16 * tm.tmAveCharWidth;
4227     pSize->cy = tm.tmHeight + 10;
4228 }
4229 
4230 void
GetMargin(LPRECT prcMargin)4231 CUIFBalloonWindow::GetMargin(LPRECT prcMargin)
4232 {
4233     if (prcMargin)
4234         *prcMargin = m_rcMargin;
4235 }
4236 
4237 void
SetExcludeRect(LPCRECT prcExclude)4238 CUIFBalloonWindow::SetExcludeRect(LPCRECT prcExclude)
4239 {
4240     m_rcExclude = *prcExclude;
4241     AdjustPos();
4242 }
4243 
4244 void
SetTargetPos(POINT ptTarget)4245 CUIFBalloonWindow::SetTargetPos(POINT ptTarget)
4246 {
4247     m_ptTarget = ptTarget;
4248     AdjustPos();
4249 }
4250 
4251 void
SetText(LPCWSTR pszText)4252 CUIFBalloonWindow::SetText(LPCWSTR pszText)
4253 {
4254     if (m_pszBalloonText)
4255     {
4256         delete[] m_pszBalloonText;
4257         m_pszBalloonText = NULL;
4258     }
4259 
4260     if (pszText == NULL)
4261         pszText = L"";
4262 
4263     size_t cch = wcslen(pszText);
4264     m_pszBalloonText = new(cicNoThrow) WCHAR[cch + 1];
4265     if (m_pszBalloonText)
4266         lstrcpynW(m_pszBalloonText, pszText, cch + 1);
4267 
4268     AdjustPos();
4269 }
4270 
4271 void
InitWindowRegion()4272 CUIFBalloonWindow::InitWindowRegion()
4273 {
4274     RECT rc;
4275     GetRect(&rc);
4276     m_hRgn = CreateRegion(&rc);
4277     if (m_hRgn)
4278         ::SetWindowRgn(m_hWnd, m_hRgn, TRUE);
4279 }
4280 
4281 void
LayoutObject()4282 CUIFBalloonWindow::LayoutObject()
4283 {
4284     SIZE size;
4285     GetButtonSize(&size);
4286 
4287     RECT rc;
4288     GetRect(&rc);
4289 
4290     switch (m_nBalloonType)
4291     {
4292         case 1:
4293             rc.top += 16;
4294             break;
4295         case 2:
4296             rc.right -= 16;
4297             break;
4298         case 3:
4299             rc.left += 16;
4300             break;
4301         default:
4302             rc.bottom -= 16;
4303             break;
4304     }
4305 
4306     RECT rcMargin;
4307     GetMargin(&rcMargin);
4308     rc.left += rcMargin.left;
4309     rc.top += rcMargin.top;
4310     rc.right -= rcMargin.right;
4311     rc.bottom -= rcMargin.bottom;
4312 
4313     LONG xLeft = (rc.left + rc.right - size.cx * (((m_cButtons - 1) / 2) - m_cButtons)) / 2;
4314     for (UINT iButton = 0; iButton < m_cButtons; ++iButton)
4315     {
4316         CUIFObject *UIObject = FindUIObject(iButton);
4317         if (!UIObject)
4318             continue;
4319 
4320         rcMargin.left = xLeft + iButton * (size.cx * 3 / 2);
4321         rcMargin.top = rc.bottom - size.cy;
4322         rcMargin.right = rcMargin.left + size.cx;
4323         rcMargin.bottom = rc.bottom;
4324 
4325         UIObject->SetRect(&rcMargin);
4326         UIObject->Show(TRUE);
4327     }
4328 }
4329 
4330 void
PaintFrameProc(HDC hDC,LPCRECT prc)4331 CUIFBalloonWindow::PaintFrameProc(HDC hDC, LPCRECT prc)
4332 {
4333     HRGN hRgn = CreateRegion(prc);
4334     HBRUSH hbrBack = ::CreateSolidBrush(GetBalloonBkColor());
4335     HBRUSH hbrFrame = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOWFRAME));
4336     ::FillRgn(hDC, hRgn, hbrBack);
4337     ::FrameRgn(hDC, hRgn, hbrFrame, 1, 1);
4338     ::DeleteObject(hbrBack);
4339     ::DeleteObject(hbrFrame);
4340     ::DeleteObject(hRgn);
4341 }
4342 
4343 void
PaintMessageProc(HDC hDC,LPRECT prc,LPCWSTR pszText)4344 CUIFBalloonWindow::PaintMessageProc(HDC hDC, LPRECT prc, LPCWSTR pszText)
4345 {
4346     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
4347     COLORREF rgbOldColor = ::SetTextColor(hDC, GetBalloonTextColor());
4348     INT nOldBkMode = ::SetBkMode(hDC, TRANSPARENT);
4349     ::DrawTextW(hDC, pszText, -1, prc, DT_WORDBREAK);
4350     ::SelectObject(hDC, hFontOld);
4351     ::SetTextColor(hDC, rgbOldColor);
4352     ::SetBkMode(hDC, nOldBkMode);
4353 }
4354 
4355 void
SendNotification(WPARAM wParam)4356 CUIFBalloonWindow::SendNotification(WPARAM wParam)
4357 {
4358     if (m_hwndNotif)
4359         ::PostMessage(m_hwndNotif, m_uNotifMsg, wParam, 0);
4360 }
4361 
4362 /////////////////////////////////////////////////////////////////////////////
4363 // CUIFMenu
4364 
CUIFMenu(HINSTANCE hInst,DWORD style,DWORD dwUnknown14)4365 CUIFMenu::CUIFMenu(
4366     HINSTANCE hInst,
4367     DWORD style,
4368     DWORD dwUnknown14) : CUIFWindow(hInst, style)
4369 {
4370     m_nSelectedID = -1;
4371     m_dwUnknown14 = dwUnknown14;
4372     SetMenuFont();
4373 }
4374 
~CUIFMenu()4375 CUIFMenu::~CUIFMenu()
4376 {
4377     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
4378         delete m_MenuItems[iItem];
4379 
4380     ::DeleteObject(m_hMenuFont);
4381     ClearMenuFont();
4382 }
4383 
CancelMenu()4384 void CUIFMenu::CancelMenu()
4385 {
4386     if (m_pVisibleSubMenu)
4387     {
4388         UninitShow();
4389     }
4390     else if (m_bModal)
4391     {
4392         SetSelectedId(0xFFFFFFFF);
4393         ::PostMessage(m_hWnd, WM_NULL, 0, 0);
4394     }
4395 }
4396 
ClearMenuFont()4397 void CUIFMenu::ClearMenuFont()
4398 {
4399     SetFont(NULL);
4400     ::DeleteObject(m_hFont);
4401 }
4402 
4403 CUIFMenuItem*
GetNextItem(CUIFMenuItem * pItem)4404 CUIFMenu::GetNextItem(CUIFMenuItem *pItem)
4405 {
4406     size_t iItem, cItems = m_MenuItems.size();
4407 
4408     if (cItems == 0)
4409         return NULL;
4410 
4411     if (!m_pSelectedItem)
4412         return m_MenuItems[0];
4413 
4414     for (iItem = 0; iItem < cItems; )
4415     {
4416         if (m_MenuItems[iItem++] == pItem)
4417             break;
4418     }
4419 
4420     for (;;)
4421     {
4422         if (iItem == cItems)
4423             iItem = 0;
4424         if (!m_MenuItems[iItem] || !m_MenuItems[iItem]->m_bMenuItemDisabled)
4425             break;
4426         ++iItem;
4427     }
4428 
4429     return m_MenuItems[iItem];
4430 }
4431 
4432 CUIFMenuItem*
GetPrevItem(CUIFMenuItem * pItem)4433 CUIFMenu::GetPrevItem(CUIFMenuItem *pItem)
4434 {
4435     ptrdiff_t iItem, cItems = m_MenuItems.size();
4436 
4437     if (cItems == 0)
4438         return NULL;
4439 
4440     if (!m_pSelectedItem)
4441         return m_MenuItems[cItems - 1];
4442 
4443     for (iItem = cItems - 1; iItem >= 0; )
4444     {
4445         if (m_MenuItems[iItem--] == pItem)
4446             break;
4447     }
4448 
4449     for (;;)
4450     {
4451         if (iItem < 0)
4452             iItem = cItems - 1;
4453         if (!m_MenuItems[iItem] || !m_MenuItems[iItem]->m_bMenuItemDisabled)
4454             break;
4455         --iItem;
4456     }
4457 
4458     return m_MenuItems[iItem];
4459 }
4460 
4461 CUIFMenu*
GetTopSubMenu()4462 CUIFMenu::GetTopSubMenu()
4463 {
4464     CUIFMenu *pMenu;
4465     for (pMenu = this; pMenu->m_pParentMenu; pMenu = pMenu->m_pParentMenu)
4466         ;
4467     return pMenu;
4468 }
4469 
HandleMouseMsg(UINT uMsg,LONG x,LONG y)4470 void CUIFMenu::HandleMouseMsg(UINT uMsg, LONG x, LONG y)
4471 {
4472     POINT pt = { x, y };
4473     if (!::PtInRect(&m_rc, pt) &&
4474         (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_RBUTTONUP))
4475     {
4476         SetSelectedId(-1);
4477         PostMessage(m_hWnd, WM_NULL, 0, 0);
4478     }
4479     CUIFWindow::HandleMouseMsg(uMsg, x, y);
4480 }
4481 
STDMETHODIMP_(BOOL)4482 STDMETHODIMP_(BOOL)
4483 CUIFMenu::InitShow(CUIFWindow *pWindow, LPCRECT prc, BOOL bFlag, BOOL bDoAnimation)
4484 {
4485     HWND hWnd = NULL;
4486     if (pWindow)
4487         hWnd = *pWindow;
4488 
4489     CreateWnd(hWnd);
4490 
4491     m_bHasMargin = FALSE;
4492 
4493     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
4494     {
4495         if (m_MenuItems[iItem])
4496             m_MenuItems[iItem]->InitMenuExtent();
4497     }
4498 
4499     INT cxMax = 0;
4500 
4501     m_cxMenuExtent = 0;
4502     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
4503     {
4504         CUIFMenuItem *pItem = m_MenuItems[iItem];
4505         if (!pItem)
4506             continue;
4507 
4508         INT cxItem = m_cxyMargin + pItem->m_MenuLeftExtent.cx;
4509         if (cxMax < cxItem)
4510             cxMax = cxItem;
4511         m_cxMenuExtent = max(m_cxMenuExtent, pItem->m_MenuRightExtent.cx);
4512         if (!m_bHasMargin && pItem->m_hbmColor && pItem->IsCheck())
4513             m_bHasMargin = TRUE;
4514     }
4515 
4516     RECT rcItem = { 0, 0, 0, 0 };
4517     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
4518     {
4519         CUIFMenuItem *pItem = m_MenuItems[iItem];
4520         if (!pItem)
4521             continue;
4522 
4523         INT cyItem = pItem->m_MenuLeftExtent.cy;
4524         rcItem.right = rcItem.left + cxMax + m_cxMenuExtent;
4525         rcItem.bottom = rcItem.top + cyItem;
4526         pItem->SetRect(&rcItem);
4527         rcItem.top += cyItem;
4528         AddUIObj(pItem);
4529     }
4530 
4531     rcItem.top = 0;
4532     DWORD style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
4533     cxMax = rcItem.right;
4534     INT cyMax = rcItem.bottom;
4535     if (style & WS_DLGFRAME)
4536     {
4537         cxMax = rcItem.right + 2 * ::GetSystemMetrics(SM_CXDLGFRAME);
4538         cyMax += 2 * ::GetSystemMetrics(SM_CYDLGFRAME);
4539     }
4540     else if (style & WS_BORDER)
4541     {
4542         cxMax = rcItem.right + 2 * ::GetSystemMetrics(SM_CXBORDER);
4543         cyMax += 2 * ::GetSystemMetrics(SM_CYBORDER);
4544     }
4545 
4546     RECT rc = { 0, 0, ::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN) };
4547 
4548     RECT rc3 = *prc;
4549     HMONITOR hMon = ::MonitorFromRect(&rc3, MONITOR_DEFAULTTONEAREST);
4550     if (hMon)
4551     {
4552         MONITORINFO mi = { sizeof(mi) };
4553         if (::GetMonitorInfo(hMon, &mi))
4554             rc = mi.rcMonitor;
4555     }
4556 
4557     if (m_style & 0x200)
4558         rcItem.left -= cxMax;
4559 
4560     INT x, y;
4561     DWORD dwFlags2 = 0;
4562 
4563     if (bFlag)
4564     {
4565         INT bottom = prc->bottom;
4566         x = rcItem.left + prc->left;
4567         if (rcItem.top + bottom + cyMax > rc.bottom)
4568         {
4569             bottom = prc->top - cyMax;
4570             dwFlags2 = 8;
4571         }
4572         else
4573         {
4574             dwFlags2 = 4;
4575         }
4576 
4577         y = rcItem.top + bottom;
4578 
4579         if (rcItem.left + cxMax + prc->right > rc.right)
4580             x = rc.right - cxMax;
4581     }
4582     else
4583     {
4584         y = rcItem.top + prc->top;
4585         if (rcItem.left + prc->right + cxMax > rc.right)
4586         {
4587             x = rcItem.left + prc->left - cxMax;
4588             dwFlags2 = 2;
4589         }
4590         else
4591         {
4592             x = rcItem.left + prc->right;
4593             dwFlags2 = 1;
4594         }
4595         if (rcItem.top + cyMax + prc->bottom > rc.bottom)
4596             y = rc.bottom - cyMax;
4597     }
4598 
4599     if (x > rc.right - cxMax)
4600         x = rc.right - cxMax;
4601     if (x < rc.left)
4602         x = rc.left;
4603     if (y > rc.bottom - cyMax)
4604         y = rc.bottom - cyMax;
4605     if (y < rc.top)
4606         y = rc.top;
4607 
4608     Move(x, y, cxMax, -1);
4609 
4610     SetRect(NULL);
4611 
4612     BOOL bAnimation = FALSE;
4613     if (bDoAnimation &&
4614         ::SystemParametersInfo(SPI_GETMENUANIMATION, 0, &bAnimation, 0) && bAnimation)
4615     {
4616         BOOL bMenuFade = FALSE;
4617         if (!::SystemParametersInfoA(SPI_GETMENUFADE, 0, &bMenuFade, 0))
4618             bMenuFade = FALSE;
4619 
4620         DWORD dwFlags = (bMenuFade ? 0x80000 : dwFlags2) | 0x40000;
4621         if (!AnimateWnd(200, dwFlags))
4622             Show(TRUE);
4623     }
4624     else
4625     {
4626         Show(TRUE);
4627     }
4628 
4629     if (m_pVisibleSubMenu)
4630         m_pVisibleSubMenu->m_pParentMenu = this;
4631 
4632     return TRUE;
4633 }
4634 
InsertItem(CUIFMenuItem * pItem)4635 BOOL CUIFMenu::InsertItem(CUIFMenuItem *pItem)
4636 {
4637     if (!m_MenuItems.Add(pItem))
4638         return FALSE;
4639 
4640     pItem->SetFont(m_hFont);
4641     return TRUE;
4642 }
4643 
InsertSeparator()4644 BOOL CUIFMenu::InsertSeparator()
4645 {
4646     CUIFMenuItemSeparator *pSep = new(cicNoThrow) CUIFMenuItemSeparator(this);
4647     if (!pSep)
4648         return FALSE;
4649 
4650     if (!m_MenuItems.Add(pSep))
4651     {
4652         delete pSep;
4653         return FALSE;
4654     }
4655 
4656     pSep->Initialize();
4657     return TRUE;
4658 }
4659 
STDMETHODIMP_(void)4660 STDMETHODIMP_(void)
4661 CUIFMenu::ModalMessageLoop()
4662 {
4663     MSG msg;
4664 
4665     while (::GetMessage(&msg, 0, 0, 0) && msg.message != WM_NULL &&
4666            (msg.hwnd == m_hWnd || msg.message <= WM_MOUSEFIRST || WM_MOUSELAST <= msg.message))
4667     {
4668         if (!msg.hwnd && WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST)
4669             msg.hwnd = GetTopSubMenu()->m_hWnd;
4670         ::TranslateMessage(&msg);
4671         ::DispatchMessage(&msg);
4672     }
4673 }
4674 
STDMETHODIMP_(void)4675 STDMETHODIMP_(void)
4676 CUIFMenu::ModalMouseNotify(UINT uMsg, LONG x, LONG y)
4677 {
4678     if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN)
4679         CancelMenu();
4680 }
4681 
STDMETHODIMP_(void)4682 STDMETHODIMP_(void)
4683 CUIFMenu::OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
4684 {
4685     CUIFMenuItem *pTargetItem;
4686 
4687     BYTE vKey = (BYTE)wParam;
4688 
4689     switch (vKey)
4690     {
4691         case VK_ESCAPE:
4692             CancelMenu();
4693             return;
4694 
4695         case VK_LEFT:
4696             if (!m_pVisibleSubMenu)
4697                 return;
4698 
4699             CancelMenu();
4700             return;
4701 
4702         case VK_RIGHT:
4703             if (m_pSelectedItem && m_pSelectedItem->m_pSubMenu)
4704             {
4705                 m_pSelectedItem->ShowSubPopup();
4706                 CUIFMenu *pSubMenu = m_pSelectedItem->m_pSubMenu;
4707                 pTargetItem = pSubMenu->GetNextItem(NULL);
4708                 pSubMenu->SetSelectedItem(pTargetItem);
4709             }
4710             return;
4711 
4712         case VK_UP:
4713             pTargetItem = GetPrevItem(m_pSelectedItem);
4714             SetSelectedItem(pTargetItem);
4715             return;
4716 
4717         case VK_DOWN:
4718             pTargetItem = GetNextItem(m_pSelectedItem);
4719             SetSelectedItem(pTargetItem);
4720             return;
4721 
4722         case VK_RETURN:
4723             break;
4724 
4725         default:
4726         {
4727             if (!(('A' <= vKey && vKey <= 'Z') || ('0' <= vKey && vKey <= '9')))
4728                 return;
4729 
4730             size_t iItem;
4731             for (iItem = 0; iItem < m_MenuItems.size(); ++iItem)
4732             {
4733                 CUIFMenuItem *pItem = m_MenuItems[iItem];
4734                 if (pItem->m_nMenuItemVKey == vKey)
4735                 {
4736                     SetSelectedItem(pItem);
4737                     break;
4738                 }
4739             }
4740 
4741             if (iItem == m_MenuItems.size())
4742                 return;
4743         }
4744     }
4745 
4746     if (m_pSelectedItem && !m_pSelectedItem->m_bMenuItemGrayed)
4747     {
4748         CUIFMenu *pSubMenu = m_pSelectedItem->m_pSubMenu;
4749         if (pSubMenu)
4750         {
4751             m_pSelectedItem->ShowSubPopup();
4752             pTargetItem = pSubMenu->GetNextItem(NULL);
4753             pSubMenu->SetSelectedItem(pTargetItem);
4754         }
4755         else
4756         {
4757             SetSelectedId(m_pSelectedItem->m_nMenuItemID);
4758             ::PostMessage(m_hWnd, WM_NULL, 0, 0);
4759         }
4760     }
4761 }
4762 
PostKey(BOOL bUp,WPARAM wParam,LPARAM lParam)4763 void CUIFMenu::PostKey(BOOL bUp, WPARAM wParam, LPARAM lParam)
4764 {
4765     if (m_bModal)
4766     {
4767         // NOTE: hWnd parameter will be populated in CUIFMenu::ModalMessageLoop.
4768         if (bUp)
4769             ::PostMessage(NULL, WM_KEYUP, wParam, lParam);
4770         else
4771             ::PostMessage(NULL, WM_KEYDOWN, wParam, lParam);
4772     }
4773 }
4774 
SetMenuFont()4775 void CUIFMenu::SetMenuFont()
4776 {
4777     LONG height = 14;
4778 
4779     NONCLIENTMETRICS ncm = { sizeof(ncm) };
4780     if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
4781     {
4782         HFONT hFont = ::CreateFontIndirect(&ncm.lfMenuFont);
4783         SetFont(hFont);
4784 
4785         LONG lfHeight = ncm.lfMenuFont.lfHeight;
4786         if (lfHeight < 0)
4787             lfHeight = -lfHeight;
4788         height = (ncm.iMenuHeight + lfHeight) / 2;
4789     }
4790 
4791     m_hMenuFont = ::CreateFontW(height, 0, 0, 0, FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET,
4792                                 0, 0, 0, 0, L"Marlett");
4793     INT cxSmallIcon = ::GetSystemMetrics(SM_CXSMICON);
4794     m_cxyMargin = max(height, cxSmallIcon) + 2;
4795 }
4796 
SetSelectedId(UINT nSelectID)4797 void CUIFMenu::SetSelectedId(UINT nSelectID)
4798 {
4799     CUIFMenu *pMenu = this;
4800 
4801     while (pMenu->m_pVisibleSubMenu)
4802         pMenu = pMenu->m_pVisibleSubMenu;
4803 
4804     pMenu->m_nSelectedID = nSelectID;
4805 }
4806 
SetSelectedItem(CUIFMenuItem * pItem)4807 void CUIFMenu::SetSelectedItem(CUIFMenuItem *pItem)
4808 {
4809     CUIFMenuItem *pOldItem = m_pSelectedItem;
4810     if (pOldItem == pItem)
4811         return;
4812 
4813     m_pSelectedItem = pItem;
4814     if (pOldItem)
4815         pOldItem->CallOnPaint();
4816     if (m_pSelectedItem)
4817         m_pSelectedItem->CallOnPaint();
4818 }
4819 
ShowModalPopup(CUIFWindow * pWindow,LPCRECT prc,BOOL bFlag)4820 UINT CUIFMenu::ShowModalPopup(CUIFWindow *pWindow, LPCRECT prc, BOOL bFlag)
4821 {
4822     CUIFObject *pCaptured = NULL;
4823     if (pWindow)
4824     {
4825         pCaptured = pWindow->m_pCaptured;
4826         CUIFWindow::SetCaptureObject(NULL);
4827     }
4828 
4829     UINT nSelectedID = -1;
4830     if (InitShow(pWindow, prc, bFlag, TRUE))
4831     {
4832         m_bModal = TRUE;
4833         pWindow->SetBehindModal(this);
4834         ModalMessageLoop();
4835         nSelectedID = m_nSelectedID;
4836         pWindow->SetBehindModal(NULL);
4837         m_bModal = FALSE;
4838     }
4839 
4840     UninitShow();
4841 
4842     if (pWindow)
4843         pWindow->SetCaptureObject(pCaptured);
4844 
4845     return nSelectedID;
4846 }
4847 
ShowSubPopup(CUIFMenu * pSubMenu,LPCRECT prc,BOOL bFlag)4848 void CUIFMenu::ShowSubPopup(CUIFMenu *pSubMenu, LPCRECT prc, BOOL bFlag)
4849 {
4850     m_pVisibleSubMenu = pSubMenu;
4851     InitShow(pSubMenu, prc, bFlag, TRUE);
4852 }
4853 
STDMETHODIMP_(BOOL)4854 STDMETHODIMP_(BOOL)
4855 CUIFMenu::UninitShow()
4856 {
4857     if (m_pParentMenu)
4858         m_pParentMenu->UninitShow();
4859 
4860     Show(FALSE);
4861 
4862     if (m_pVisibleSubMenu)
4863         m_pVisibleSubMenu->m_pParentMenu = NULL;
4864 
4865     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
4866         RemoveUIObj(m_MenuItems[iItem]);
4867 
4868     ::DestroyWindow(m_hWnd);
4869     return TRUE;
4870 }
4871 
4872 /////////////////////////////////////////////////////////////////////////////
4873 // CUIFMenuItem
4874 
CUIFMenuItem(CUIFMenu * pMenu,BOOL bDisabled)4875 CUIFMenuItem::CUIFMenuItem(
4876     CUIFMenu *pMenu,
4877     BOOL bDisabled) : CUIFObject(pMenu, 0, NULL, 0)
4878 {
4879     m_ichMenuItemPrefix = -1;
4880     m_nMenuItemID = 0;
4881     m_pszMenuItemLeft = m_pszMenuItemRight = NULL;
4882     m_cchMenuItemLeft = m_cchMenuItemRight = 0;
4883     m_nMenuItemVKey = 0;
4884     m_hbmColor = m_hbmMask = NULL;
4885     m_bMenuItemChecked = m_bMenuItemGrayed = FALSE;
4886     m_bMenuItemDisabled = bDisabled;
4887     m_pMenu = pMenu;
4888 }
4889 
~CUIFMenuItem()4890 CUIFMenuItem::~CUIFMenuItem()
4891 {
4892     if (m_pszMenuItemLeft)
4893     {
4894         delete[] m_pszMenuItemLeft;
4895         m_pszMenuItemLeft = NULL;
4896     }
4897 
4898     if (m_pszMenuItemRight)
4899     {
4900         delete[] m_pszMenuItemRight;
4901         m_pszMenuItemRight = NULL;
4902     }
4903 
4904     if (m_pSubMenu)
4905     {
4906         delete m_pSubMenu;
4907         m_pSubMenu = NULL;
4908     }
4909 }
4910 
Init(UINT nMenuItemID,LPCWSTR pszText)4911 BOOL CUIFMenuItem::Init(UINT nMenuItemID, LPCWSTR pszText)
4912 {
4913     m_nMenuItemID = nMenuItemID;
4914 
4915     if (!pszText)
4916     {
4917         m_pszMenuItemLeft = NULL;
4918         m_cchMenuItemLeft = 0;
4919         return TRUE;
4920     }
4921 
4922     INT cch = lstrlenW(pszText);
4923     m_pszMenuItemLeft = new(cicNoThrow) WCHAR[cch + 1];
4924     if (!m_pszMenuItemLeft)
4925         return FALSE;
4926 
4927     const WCHAR *pch0 = pszText;
4928     INT ich1, ich2;
4929     for (ich1 = 0; *pch0 && *pch0 != L'\t'; ++ich1, ++pch0)
4930     {
4931         if (*pch0 == L'&' && *++pch0 != L'&')
4932         {
4933             m_nMenuItemVKey = ::VkKeyScanW(*pch0);
4934             if (!m_nMenuItemVKey)
4935                 m_nMenuItemVKey = (BYTE)VkKeyScanA(*(BYTE*)pch0);
4936             m_ichMenuItemPrefix = ich1;
4937         }
4938         m_pszMenuItemLeft[ich1] = *pch0;
4939     }
4940     m_pszMenuItemLeft[ich1] = 0;
4941     m_cchMenuItemLeft = lstrlenW(m_pszMenuItemLeft);
4942 
4943     if (*pch0 == L'\t')
4944     {
4945         m_cchMenuItemRight = 0;
4946         m_pszMenuItemRight = new(cicNoThrow) WCHAR[cch + 1];
4947         if (m_pszMenuItemRight)
4948         {
4949             ++pch0;
4950             WCHAR wch = *pch0;
4951             for (ich2 = 0; *pch0; ++ich2)
4952             {
4953                 m_pszMenuItemRight[ich2] = wch;
4954                 wch = *++pch0;
4955             }
4956             m_pszMenuItemRight[ich2] = 0;
4957             m_cchMenuItemRight = lstrlenW(m_pszMenuItemRight);
4958         }
4959     }
4960 
4961     return TRUE;
4962 }
4963 
STDMETHODIMP_(void)4964 STDMETHODIMP_(void)
4965 CUIFMenuItem::InitMenuExtent()
4966 {
4967     if (!m_pszMenuItemLeft)
4968     {
4969         if (m_hbmColor)
4970         {
4971             BITMAP bm;
4972             ::GetObject(m_hbmColor, sizeof(bm), &bm);
4973             m_MenuLeftExtent.cx = bm.bmWidth + 2;
4974             m_MenuLeftExtent.cy = bm.bmHeight + 4;
4975         }
4976         else
4977         {
4978             m_MenuLeftExtent.cx = m_MenuLeftExtent.cy = 0;
4979         }
4980         return;
4981     }
4982 
4983     HDC hDC = ::GetDC(*m_pWindow);
4984 
4985     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
4986     ::GetTextExtentPoint32W(hDC, m_pszMenuItemLeft, m_cchMenuItemLeft, &m_MenuLeftExtent);
4987     m_MenuLeftExtent.cx += 16;
4988     m_MenuLeftExtent.cy += 8;
4989     if (m_pszMenuItemRight)
4990     {
4991         ::GetTextExtentPoint32W(hDC, m_pszMenuItemRight, m_cchMenuItemRight, &m_MenuRightExtent);
4992         m_MenuRightExtent.cy += 8;
4993     }
4994     ::SelectObject(hDC, hFontOld);
4995 
4996     if (m_pSubMenu)
4997         m_MenuLeftExtent.cx += m_MenuLeftExtent.cy + 2;
4998     if (m_pMenu->m_style & UIF_MENU_USE_OFF10)
4999         m_MenuLeftExtent.cx += 24;
5000 
5001     ::ReleaseDC(*m_pWindow, hDC);
5002 }
5003 
IsCheck()5004 BOOL CUIFMenuItem::IsCheck()
5005 {
5006     return m_bMenuItemChecked || m_bMenuItemForceChecked;
5007 }
5008 
DrawArrow(HDC hDC,INT xLeft,INT yTop)5009 void CUIFMenuItem::DrawArrow(HDC hDC, INT xLeft, INT yTop)
5010 {
5011     if (!m_pSubMenu)
5012         return;
5013 
5014     HGDIOBJ hFontOld = ::SelectObject(hDC, m_pMenu->m_hMenuFont);
5015     ::TextOutW(hDC, xLeft, yTop, L"4", 1); // rightward triangle
5016     ::SelectObject(hDC, hFontOld);
5017 }
5018 
DrawBitmapProc(HDC hDC,INT xLeft,INT yTop)5019 void CUIFMenuItem::DrawBitmapProc(HDC hDC, INT xLeft, INT yTop)
5020 {
5021     if (!m_pScheme || !m_hbmColor)
5022         return;
5023 
5024     BITMAP bm;
5025     ::GetObject(m_hbmColor, sizeof(bm), &bm);
5026 
5027     INT width = m_pMenu->m_cxyMargin, height = m_rc.bottom - m_rc.top;
5028     if (width > bm.bmWidth)
5029     {
5030         width = bm.bmWidth;
5031         xLeft += (width - bm.bmWidth) / 2;
5032     }
5033     if (height > bm.bmHeight)
5034     {
5035         height = bm.bmHeight;
5036         yTop += (height - bm.bmHeight) / 2;
5037     }
5038 
5039     RECT rc = { xLeft, yTop, xLeft + width, yTop + height };
5040 
5041     if (IsRTL())
5042         m_pScheme->m_bMirroring = TRUE;
5043 
5044     if (m_pMenu->m_pSelectedItem != this || m_bMenuItemDisabled)
5045         m_pScheme->DrawFrameCtrlBitmap(hDC, &rc, m_hbmColor, m_hbmMask, 0);
5046     else
5047         m_pScheme->DrawFrameCtrlBitmap(hDC, &rc, m_hbmColor, m_hbmMask, UIF_DRAW_PRESSED);
5048 
5049     if (IsRTL())
5050         m_pScheme->m_bMirroring = FALSE;
5051 }
5052 
DrawCheck(HDC hDC,INT xLeft,INT yTop)5053 void CUIFMenuItem::DrawCheck(HDC hDC, INT xLeft, INT yTop)
5054 {
5055     if (!IsCheck())
5056         return;
5057 
5058     HGDIOBJ hFontOld = ::SelectObject(hDC, m_pMenu->m_hMenuFont);
5059     WCHAR wch = (m_bMenuItemChecked ? L'a' : L'h'); // checkmark or bullet
5060     ::TextOutW(hDC, xLeft, yTop, &wch, 1);
5061     ::SelectObject(hDC, hFontOld);
5062 }
5063 
5064 void
DrawUnderline(HDC hDC,INT xText,INT yText,HBRUSH hbr)5065 CUIFMenuItem::DrawUnderline(HDC hDC, INT xText, INT yText, HBRUSH hbr)
5066 {
5067     if (m_ichMenuItemPrefix > m_cchMenuItemLeft)
5068         return;
5069 
5070     SIZE PrePrefixSize, PostPrefixSize;
5071     ::GetTextExtentPoint32W(hDC, m_pszMenuItemLeft, m_ichMenuItemPrefix, &PrePrefixSize);
5072     ::GetTextExtentPoint32W(hDC, m_pszMenuItemLeft, m_ichMenuItemPrefix + 1, &PostPrefixSize);
5073 
5074     BOOL bHeadPrefix = (m_ichMenuItemPrefix == 0);
5075 
5076     RECT rc;
5077     rc.left   = xText + PrePrefixSize.cx + !bHeadPrefix;
5078     rc.right  = xText + PostPrefixSize.cx;
5079     rc.top    = (yText + PostPrefixSize.cy) - 1;
5080     rc.bottom = yText + PostPrefixSize.cy;
5081     ::FillRect(hDC, &rc, hbr);
5082 }
5083 
STDMETHODIMP_(void)5084 STDMETHODIMP_(void)
5085 CUIFMenuItem::OnLButtonUp(LONG x, LONG y)
5086 {
5087     if (!m_bMenuItemGrayed && !m_bMenuItemDisabled && !m_pSubMenu)
5088     {
5089         m_pMenu->SetSelectedId(m_nMenuItemID);
5090         ::PostMessage(*m_pWindow, WM_NULL, 0, 0);
5091     }
5092 }
5093 
STDMETHODIMP_(void)5094 STDMETHODIMP_(void)
5095 CUIFMenuItem::OnMouseIn(LONG x, LONG y)
5096 {
5097     if (m_pMenu->m_pParentMenu)
5098         m_pMenu->m_pParentMenu->CancelMenu();
5099 
5100     if (m_pSubMenu)
5101     {
5102         DWORD Delay;
5103         if (!::SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &Delay, 0))
5104             Delay = 300;
5105 
5106         CUIFObject::StartTimer(Delay);
5107     }
5108 
5109     m_pMenu->SetSelectedItem(this);
5110 }
5111 
STDMETHODIMP_(void)5112 STDMETHODIMP_(void)
5113 CUIFMenuItem::OnPaint(HDC hDC)
5114 {
5115     if (m_pMenu->m_style & UIF_MENU_USE_OFF10)
5116         OnPaintO10(hDC);
5117     else
5118         OnPaintDef(hDC);
5119 }
5120 
STDMETHODIMP_(void)5121 STDMETHODIMP_(void)
5122 CUIFMenuItem::OnPaintO10(HDC hDC)
5123 {
5124     if (!m_pScheme)
5125         return;
5126 
5127     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
5128 
5129     SIZE textSize;
5130     ::GetTextExtentPoint32W(hDC, m_pszMenuItemLeft, m_cchMenuItemLeft, &textSize);
5131 
5132     LONG cySpace = m_rc.bottom - m_rc.top - textSize.cy;
5133     LONG xCheck = m_rc.left, yCheck = m_rc.top + cySpace / 2;
5134     LONG cxyMargin = (m_pMenu->m_bHasMargin ? m_pMenu->m_cxyMargin : 0);
5135 
5136     LONG xBitmap = m_rc.left + cxyMargin, yBitmap = m_rc.top;
5137     LONG xText = m_rc.left + m_pMenu->m_cxyMargin + cxyMargin + 8;
5138     LONG yText = m_rc.top + cySpace / 2;
5139     LONG xArrow = m_rc.left - textSize.cy + m_rc.right - 2;
5140     LONG xRightText = m_rc.right - m_pMenu->m_cxMenuExtent - 8;
5141 
5142     RECT rc;
5143     GetRect(&rc);
5144 
5145     if (m_bMenuItemDisabled || m_pMenu->m_pSelectedItem != this)
5146     {
5147         rc.right = m_pMenu->m_cxyMargin + rc.left + 2;
5148         if (m_pMenu->m_bHasMargin)
5149             rc.right += m_pMenu->m_cxyMargin;
5150 
5151         ::FillRect(hDC, &rc, m_pScheme->GetBrush(9));
5152     }
5153     else
5154     {
5155         m_pScheme->DrawCtrlBkgd(hDC, &rc, 0, UIF_DRAW_PRESSED);
5156         m_pScheme->DrawCtrlEdge(hDC, &rc, 0, UIF_DRAW_PRESSED);
5157     }
5158 
5159     ::SetBkMode(hDC, TRANSPARENT);
5160 
5161     if (m_bMenuItemGrayed)
5162     {
5163         ::SetTextColor(hDC, m_pScheme->GetColor(11));
5164         ::ExtTextOutW(hDC, xText, yText, ETO_CLIPPED, &m_rc, m_pszMenuItemLeft,
5165                       m_cchMenuItemLeft, NULL);
5166     }
5167     else if (m_bMenuItemDisabled || m_pMenu->m_pSelectedItem != this)
5168     {
5169         ::SetTextColor(hDC, m_pScheme->GetColor(10));
5170         ::ExtTextOutW(hDC, xText, yText, ETO_CLIPPED, &m_rc, m_pszMenuItemLeft,
5171                       m_cchMenuItemLeft, NULL);
5172     }
5173     else
5174     {
5175         ::SetTextColor(hDC, m_pScheme->GetColor(5));
5176         ::ExtTextOutW(hDC, xText, yText, ETO_CLIPPED, &m_rc, m_pszMenuItemLeft,
5177                       m_cchMenuItemLeft, NULL);
5178     }
5179 
5180     DrawUnderline(hDC, xText, yText, m_pScheme->GetBrush(5));
5181 
5182     if (m_pszMenuItemRight)
5183     {
5184         ::ExtTextOutW(hDC, xRightText, yText, ETO_CLIPPED, &m_rc, m_pszMenuItemRight,
5185                       m_cchMenuItemRight, NULL);
5186     }
5187 
5188     DrawCheck(hDC, xCheck, yCheck);
5189     DrawBitmapProc(hDC, xBitmap, yBitmap);
5190     DrawArrow(hDC, xArrow, yText);
5191 
5192     ::SelectObject(hDC, hFontOld);
5193 }
5194 
STDMETHODIMP_(void)5195 STDMETHODIMP_(void)
5196 CUIFMenuItem::OnPaintDef(HDC hDC)
5197 {
5198     HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
5199 
5200     SIZE textSize;
5201     ::GetTextExtentPoint32W(hDC, m_pszMenuItemLeft, m_cchMenuItemLeft, &textSize);
5202 
5203     LONG cxyMargin = (m_pMenu->m_bHasMargin ? m_pMenu->m_cxyMargin : 0);
5204 
5205     LONG cySpace = m_rc.bottom - m_rc.top - textSize.cy;
5206     LONG xCheck = m_rc.left, yCheck = m_rc.top + cySpace / 2;
5207     LONG xBitmap = m_rc.left + cxyMargin, yBitmap = m_rc.top;
5208     LONG xText = m_rc.left + cxyMargin + m_pMenu->m_cxyMargin + 2;
5209     LONG yText = m_rc.top + cySpace / 2;
5210 
5211     LONG xArrow = m_rc.right + m_rc.left - 10;
5212 
5213     ::SetBkMode(hDC, TRANSPARENT);
5214 
5215     if (m_bMenuItemGrayed)
5216     {
5217         UINT uOptions = ETO_CLIPPED;
5218         if (m_bMenuItemDisabled || m_pMenu->m_pSelectedItem != this)
5219         {
5220             ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNHIGHLIGHT));
5221             ::ExtTextOutW(hDC, xText + 1, yText + 1, ETO_CLIPPED, &m_rc, m_pszMenuItemLeft,
5222                           m_cchMenuItemLeft, NULL);
5223             DrawCheck(hDC, xCheck + 1, yCheck + 1);
5224             DrawBitmapProc(hDC, xBitmap + 1, yBitmap + 1);
5225             DrawArrow(hDC, xArrow + 1, yText + 1);
5226         }
5227         else
5228         {
5229             ::SetBkColor(hDC, ::GetSysColor(COLOR_HIGHLIGHT));
5230             uOptions = ETO_CLIPPED | ETO_OPAQUE;
5231         }
5232         ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNSHADOW));
5233         ::ExtTextOutW(hDC, xText, yText, uOptions, &m_rc, m_pszMenuItemLeft,
5234                       m_cchMenuItemLeft, NULL);
5235         DrawUnderline(hDC, xText, yText, (HBRUSH)UlongToHandle(COLOR_BTNSHADOW + 1));
5236     }
5237     else if (m_bMenuItemDisabled || m_pMenu->m_pSelectedItem != this)
5238     {
5239         ::SetTextColor(hDC, ::GetSysColor(COLOR_MENUTEXT));
5240         ::ExtTextOutW(hDC, xText, yText, ETO_CLIPPED, &m_rc, m_pszMenuItemLeft,
5241                       m_cchMenuItemLeft, NULL);
5242         DrawUnderline(hDC, xText, yText, (HBRUSH)UlongToHandle(COLOR_MENUTEXT + 1));
5243     }
5244     else
5245     {
5246         ::SetTextColor(hDC, ::GetSysColor(COLOR_HIGHLIGHTTEXT));
5247         ::SetBkColor(hDC, ::GetSysColor(COLOR_HIGHLIGHT));
5248         ::ExtTextOutW(hDC, xText, yText, ETO_CLIPPED | ETO_OPAQUE, &m_rc,
5249                       m_pszMenuItemLeft, m_cchMenuItemLeft, NULL);
5250         DrawUnderline(hDC, xText, yText, (HBRUSH)UlongToHandle(COLOR_HIGHLIGHTTEXT + 1));
5251     }
5252 
5253     DrawCheck(hDC, xCheck, yCheck);
5254     DrawBitmapProc(hDC, xBitmap, yBitmap);
5255     DrawArrow(hDC, xArrow, yText);
5256 
5257     ::SelectObject(hDC, hFontOld);
5258 }
5259 
STDMETHODIMP_(void)5260 STDMETHODIMP_(void)
5261 CUIFMenuItem::OnTimer()
5262 {
5263     CUIFObject::EndTimer();
5264     if (m_pMenu->m_pPointed == this)
5265         ShowSubPopup();
5266 }
5267 
SetBitmapMask(HBITMAP hbmMask)5268 void CUIFMenuItem::SetBitmapMask(HBITMAP hbmMask)
5269 {
5270     m_hbmMask = hbmMask;
5271     CallOnPaint();
5272 }
5273 
ShowSubPopup()5274 void CUIFMenuItem::ShowSubPopup()
5275 {
5276     RECT rc = m_rc;
5277     ::ClientToScreen(*m_pWindow, (LPPOINT)&rc);
5278     ::ClientToScreen(*m_pWindow, (LPPOINT)&rc.right);
5279     m_pSubMenu->ShowSubPopup(m_pMenu, &rc, FALSE);
5280 }
5281 
5282 /////////////////////////////////////////////////////////////////////////////
5283 // CUIFMenuItemSeparator
5284 
CUIFMenuItemSeparator(CUIFMenu * pMenu)5285 CUIFMenuItemSeparator::CUIFMenuItemSeparator(CUIFMenu *pMenu) : CUIFMenuItem(pMenu, TRUE)
5286 {
5287     m_nMenuItemID = -1;
5288 }
5289 
STDMETHODIMP_(void)5290 STDMETHODIMP_(void)
5291 CUIFMenuItemSeparator::InitMenuExtent()
5292 {
5293     m_MenuLeftExtent.cx = 0;
5294     m_MenuLeftExtent.cy = 6;
5295 }
5296 
STDMETHODIMP_(void)5297 STDMETHODIMP_(void)
5298 CUIFMenuItemSeparator::OnPaintDef(HDC hDC)
5299 {
5300     if (!m_pScheme)
5301         return;
5302 
5303     RECT rc;
5304     rc.left   = m_rc.left + 2;
5305     rc.top    = m_rc.top + (m_rc.bottom - m_rc.top - 2) / 2;
5306     rc.right  = m_rc.right - 2;
5307     rc.bottom = rc.top + 2;
5308     m_pScheme->DrawMenuSeparator(hDC, &rc);
5309 }
5310 
STDMETHODIMP_(void)5311 STDMETHODIMP_(void)
5312 CUIFMenuItemSeparator::OnPaintO10(HDC hDC)
5313 {
5314     if (!m_pScheme)
5315         return;
5316 
5317     LONG cx = m_rc.right - m_rc.left - 4;
5318     LONG cy = (m_rc.bottom - m_rc.top - 2) / 2;
5319 
5320     RECT rc;
5321     GetRect(&rc);
5322 
5323     rc.right = rc.left + m_pMenu->m_cxyMargin + 2;
5324     if (m_pMenu->m_bHasMargin)
5325         rc.right += m_pMenu->m_cxyMargin;
5326 
5327     HBRUSH hBrush = m_pScheme->GetBrush(9);
5328     ::FillRect(hDC, &rc, hBrush);
5329     rc = {
5330         m_rc.left + m_pMenu->m_cxyMargin + 4,
5331         m_rc.top + cy,
5332         m_rc.left + cx + 2,
5333         m_rc.top + cy + 1
5334     };
5335     m_pScheme->DrawMenuSeparator(hDC, &rc);
5336 }
5337 
5338 /////////////////////////////////////////////////////////////////////////////
5339 
cicGetWorkAreaRect(POINT pt,LPRECT prc)5340 void cicGetWorkAreaRect(POINT pt, LPRECT prc)
5341 {
5342     ::SystemParametersInfo(SPI_GETWORKAREA, 0, prc, 0);
5343 
5344     HMONITOR hMon = ::MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
5345     if (hMon)
5346     {
5347         MONITORINFO mi = { sizeof(mi) };
5348         if (::GetMonitorInfo(hMon, &mi))
5349             *prc = mi.rcWork;
5350     }
5351 }
5352 
cicGetScreenRect(POINT pt,LPRECT prc)5353 void cicGetScreenRect(POINT pt, LPRECT prc)
5354 {
5355     *prc = { 0, 0, ::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN) };
5356     HMONITOR hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
5357     if (hMon)
5358     {
5359         MONITORINFO mi = { sizeof(mi) };
5360         GetMonitorInfo(hMon, &mi);
5361             *prc = mi.rcMonitor;
5362     }
5363 }
5364 
cicIsFullScreenSize(HWND hWnd)5365 BOOL cicIsFullScreenSize(HWND hWnd)
5366 {
5367     RECT rc;
5368 
5369     ::GetWindowRect(hWnd, &rc);
5370     return (rc.left <= 0) && (rc.top <= 0) &&
5371            (rc.right >= GetSystemMetrics(SM_CXFULLSCREEN)) &&
5372            (rc.bottom >= GetSystemMetrics(SM_CYFULLSCREEN));
5373 }
5374 
cicGetIconSize(HICON hIcon,LPSIZE pSize)5375 BOOL cicGetIconSize(HICON hIcon, LPSIZE pSize)
5376 {
5377     ICONINFO IconInfo;
5378     if (!GetIconInfo(hIcon, &IconInfo))
5379         return FALSE;
5380 
5381     BITMAP bm;
5382     ::GetObject(IconInfo.hbmColor, sizeof(bm), &bm);
5383     ::DeleteObject(IconInfo.hbmColor);
5384     ::DeleteObject(IconInfo.hbmMask);
5385     pSize->cx = bm.bmWidth;
5386     pSize->cy = bm.bmHeight;
5387     return TRUE;
5388 }
5389 
5390 /////////////////////////////////////////////////////////////////////////////
5391 
cicInitUIFSys(void)5392 void cicInitUIFSys(void)
5393 {
5394     CUIFSystemInfo::s_pSystemInfo = new(cicNoThrow) CUIFSystemInfo();
5395     if (CUIFSystemInfo::s_pSystemInfo)
5396         CUIFSystemInfo::s_pSystemInfo->Initialize();
5397 }
5398 
cicDoneUIFSys(void)5399 void cicDoneUIFSys(void)
5400 {
5401     if (CUIFSystemInfo::s_pSystemInfo)
5402     {
5403         delete CUIFSystemInfo::s_pSystemInfo;
5404         CUIFSystemInfo::s_pSystemInfo = NULL;
5405     }
5406 }
5407 
cicUpdateUIFSys(void)5408 void cicUpdateUIFSys(void)
5409 {
5410     if (CUIFSystemInfo::s_pSystemInfo)
5411         CUIFSystemInfo::s_pSystemInfo->GetSystemMetrics();
5412 }
5413 
5414 /////////////////////////////////////////////////////////////////////////////
5415 
cicInitUIFScheme(void)5416 void cicInitUIFScheme(void)
5417 {
5418     CUIFColorTable *pColorTable;
5419 
5420     pColorTable = CUIFScheme::s_pColorTableSys = new(cicNoThrow) CUIFColorTableSys();
5421     if (pColorTable)
5422     {
5423         pColorTable->InitColor();
5424         pColorTable->InitBrush();
5425     }
5426 
5427     pColorTable = CUIFScheme::s_pColorTableOff10 = new(cicNoThrow) CUIFColorTableOff10();
5428     if (pColorTable)
5429     {
5430         pColorTable->InitColor();
5431         pColorTable->InitBrush();
5432     }
5433 }
5434 
cicUpdateUIFScheme(void)5435 void cicUpdateUIFScheme(void)
5436 {
5437     if (CUIFScheme::s_pColorTableSys)
5438         CUIFScheme::s_pColorTableSys->Update();
5439     if (CUIFScheme::s_pColorTableOff10)
5440         CUIFScheme::s_pColorTableOff10->Update();
5441 }
5442 
cicDoneUIFScheme(void)5443 void cicDoneUIFScheme(void)
5444 {
5445     if (CUIFScheme::s_pColorTableSys)
5446     {
5447         delete CUIFScheme::s_pColorTableSys;
5448         CUIFScheme::s_pColorTableSys = NULL;
5449     }
5450     if (CUIFScheme::s_pColorTableOff10)
5451     {
5452         delete CUIFScheme::s_pColorTableOff10;
5453         CUIFScheme::s_pColorTableOff10 = NULL;
5454     }
5455 }
5456 
5457 /////////////////////////////////////////////////////////////////////////////
5458 
cicInitUIFLib(void)5459 void cicInitUIFLib(void)
5460 {
5461     cicInitUIFSys();
5462     cicInitUIFScheme();
5463     cicInitUIFUtil();
5464 }
5465 
cicDoneUIFLib(void)5466 void cicDoneUIFLib(void)
5467 {
5468     cicDoneUIFScheme();
5469     cicDoneUIFSys();
5470     cicDoneUIFUtil();
5471 }
5472 
5473 /////////////////////////////////////////////////////////////////////////////
5474