https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0b3756044f1b0bc40115e40133dca7f7430bbfb2

commit 0b3756044f1b0bc40115e40133dca7f7430bbfb2
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Tue Jan 9 16:57:30 2024 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Tue Jan 9 16:57:30 2024 +0900

    [MSCTFIME][MSUTB][SDK] cicuif.h: Add CUIFButton (#6320)
    
    Supporing TIPs...
    JIRA issue: CORE-19268
    - Add CUIFButton, CUIFSolidBrush, and CUIFIcon classes.
---
 dll/ime/msctfime/CMakeLists.txt     |   2 +-
 dll/win32/msutb/CMakeLists.txt      |   4 +-
 sdk/include/reactos/cicero/cicuif.h | 685 +++++++++++++++++++++++++++++++++++-
 3 files changed, 677 insertions(+), 14 deletions(-)

diff --git a/dll/ime/msctfime/CMakeLists.txt b/dll/ime/msctfime/CMakeLists.txt
index b2ec562e673..a3955cea141 100644
--- a/dll/ime/msctfime/CMakeLists.txt
+++ b/dll/ime/msctfime/CMakeLists.txt
@@ -18,5 +18,5 @@ set_module_type(msctfime win32dll UNICODE)
 set_target_properties(msctfime PROPERTIES SUFFIX ".ime")
 target_link_libraries(msctfime wine uuid)
 add_importlibs(msctfime user32 gdi32 advapi32 msvcrt kernel32 ntdll)
-add_delay_importlibs(msctfime msctf oleaut32 imm32)
+add_delay_importlibs(msctfime comctl32 msctf oleaut32 imm32)
 add_cd_file(TARGET msctfime DESTINATION reactos/system32 FOR all)
diff --git a/dll/win32/msutb/CMakeLists.txt b/dll/win32/msutb/CMakeLists.txt
index 3e48eb33311..d4259dc7cda 100644
--- a/dll/win32/msutb/CMakeLists.txt
+++ b/dll/win32/msutb/CMakeLists.txt
@@ -14,6 +14,6 @@ add_library(msutb MODULE
 set_module_type(msutb win32dll)
 add_dependencies(msutb msctf psdk)
 target_link_libraries(msutb wine uuid atl_classes)
-add_importlibs(msutb user32 gdi32 advapi32 comctl32 msvcrt kernel32 ntdll)
-add_delay_importlibs(msutb msctf ole32 oleaut32)
+add_importlibs(msutb user32 gdi32 advapi32 msvcrt kernel32 ntdll)
+add_delay_importlibs(msutb comctl32 msctf ole32 oleaut32)
 add_cd_file(TARGET msutb DESTINATION reactos/system32 FOR all)
diff --git a/sdk/include/reactos/cicero/cicuif.h 
b/sdk/include/reactos/cicero/cicuif.h
index 637f699325e..e9c12852bbe 100644
--- a/sdk/include/reactos/cicero/cicuif.h
+++ b/sdk/include/reactos/cicero/cicuif.h
@@ -1,7 +1,7 @@
 /*
  * PROJECT:     ReactOS Cicero
  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
- * PURPOSE:     Cicero UI interface
+ * PURPOSE:     Cicero UIF Library
  * COPYRIGHT:   Copyright 2023 Katayama Hirofumi MZ 
<katayama.hirofumi...@gmail.com>
  */
 
@@ -9,17 +9,28 @@
 
 #include "cicarray.h"
 
+// This is Cicero UIF Library to support the IME UI interface.
+// Cicero UIF Library implements some GUI parts for IMEs and Language Bar.
+// The GUI parts of UIF Library requires special handling because:
+//
+// 1. To avoid interfering with IME input, the GUI part should not receive 
focus.
+// 2. The IME popup window has WS_DISABLED style, so it cannot receive mouse 
messages
+//    directly.
+
 class CUIFSystemInfo;
-struct CUIFTheme;
+class CUIFTheme;
     class CUIFObject;
         class CUIFWindow;
             class CUIFToolTip;
             class CUIFShadow;
+        class CUIFButton;
 class CUIFObjectArray;
 class CUIFColorTable;
     class CUIFColorTableSys;
     class CUIFColorTableOff10;
 class CUIFBitmapDC;
+class CUIFIcon;
+class CUIFSolidBrush;
 class CUIFScheme;
 
 /////////////////////////////////////////////////////////////////////////////
@@ -67,8 +78,9 @@ using FN_GetThemeSysSize = decltype(&GetThemeSysSize);
 
 /////////////////////////////////////////////////////////////////////////////
 
-struct CUIFTheme
+class CUIFTheme
 {
+public:
     LPCWSTR m_pszClassList;
     INT m_iPartId;
     INT m_iStateId;
@@ -187,6 +199,8 @@ enum
     UIF_STYLE_TOOLTIP = 0x20,
     UIF_STYLE_SHADOW = 0x40,
     UIF_STYLE_RTL = 0x200,
+    UIF_STYLE_VERTICAL = 0x400,
+    UIF_STYLE_THEMED = 0x80000000,
 };
 
 class CUIFObject : public CUIFTheme
@@ -209,7 +223,7 @@ protected:
     friend class CUIFToolTip;
 
 public:
-    CUIFObject(CUIFObject *pParent, DWORD dwUnknown3, LPRECT prc, DWORD style);
+    CUIFObject(CUIFObject *pParent, DWORD dwUnknown3, LPCRECT prc, DWORD 
style);
     virtual ~CUIFObject();
 
     void StartCapture();
@@ -253,7 +267,7 @@ public:
     STDMETHOD_(void, DetachWndObj)();
     STDMETHOD_(void, ClearWndObj)();
     STDMETHOD_(LRESULT, OnPaintTheme)(HDC hDC);
-    STDMETHOD_(void, DoPaint)(HDC hDC);
+    STDMETHOD_(void, OnPaintNoTheme)(HDC hDC);
     STDMETHOD_(void, ClearTheme)();
 };
 
@@ -313,6 +327,53 @@ public:
 
 /////////////////////////////////////////////////////////////////////////////
 
+class CUIFSolidBrush
+{
+public:
+    HBRUSH m_hBrush;
+
+    operator HBRUSH() const { return m_hBrush; }
+
+    CUIFSolidBrush(COLORREF rgbColor)
+    {
+        m_hBrush = ::CreateSolidBrush(rgbColor);
+    }
+    ~CUIFSolidBrush()
+    {
+        if (m_hBrush)
+        {
+            ::DeleteObject(m_hBrush);
+            m_hBrush = NULL;
+        }
+    }
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+class CUIFIcon
+{
+public:
+    HICON m_hIcon;
+    HIMAGELIST m_hImageList;
+
+    CUIFIcon& operator=(HICON hIcon)
+    {
+        m_hIcon = hIcon;
+        if (m_hImageList)
+        {
+            ImageList_Destroy(m_hImageList);
+            m_hImageList = NULL;
+        }
+        return *this;
+    }
+
+    HIMAGELIST GetImageList(BOOL bMirror);
+};
+
+BOOL cicGetIconSize(HICON hIcon, LPSIZE pSize);
+
+/////////////////////////////////////////////////////////////////////////////
+
 class CUIFBitmapDC
 {
 protected:
@@ -359,6 +420,10 @@ HBRUSH cicCreateDitherBrush(VOID);
 HBITMAP cicCreateDisabledBitmap(LPCRECT prc, HBITMAP hbmMask, HBRUSH hbr1, 
HBRUSH hbr2,
                                 BOOL bPressed);
 HBITMAP cicCreateShadowMaskBmp(LPRECT prc, HBITMAP hbm1, HBITMAP hbm2, HBRUSH 
hbr1, HBRUSH hbr2);
+HBITMAP cicChangeBitmapColor(LPCRECT prc, HBITMAP hbm, COLORREF rgbBack, 
COLORREF rgbFore);
+HBITMAP cicConvertBlackBKGBitmap(LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2, 
HBRUSH hBrush);
+HBITMAP cicCreateMaskBmp(LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2, HBRUSH hbr,
+                         COLORREF rgbColor, COLORREF rgbBack);
 
 /////////////////////////////////////////////////////////////////////////////
 
@@ -402,6 +467,7 @@ protected:
     friend class CUIFObject;
     friend class CUIFShadow;
     friend class CUIFToolTip;
+    friend class CUIFButton;
 
 public:
     CUIFWindow(HINSTANCE hInst, DWORD style);
@@ -538,6 +604,45 @@ public:
 
 /////////////////////////////////////////////////////////////////////////////
 
+class CUIFButton : public CUIFObject
+{
+protected:
+    UINT m_uButtonStatus;
+    LPWSTR m_pszButtonText;
+    CUIFIcon m_ButtonIcon;
+    DWORD m_dwUnknown9;
+    HBITMAP m_hbmButton1;
+    HBITMAP m_hbmButton2;
+    DWORD m_dwUnknown10;
+    SIZE m_IconSize;
+    SIZE m_TextSize;
+
+    void DrawBitmapProc(HDC hDC, LPCRECT prc, BOOL bPressed);
+    void DrawEdgeProc(HDC hDC, LPCRECT prc, BOOL bPressed);
+    void DrawIconProc(HDC hDC, LPRECT prc, BOOL bPressed);
+    void DrawTextProc(HDC hDC, LPCRECT prc, BOOL bPressed);
+
+public:
+    CUIFButton(CUIFObject *pParent, DWORD dwUnknown3, LPCRECT prc, DWORD 
style);
+    ~CUIFButton() override;
+
+    void SetIcon(HICON hIcon);
+    void SetText(LPCWSTR pszText);
+
+    void GetIconSize(HICON hIcon, LPSIZE pSize);
+    void GetTextSize(LPCWSTR pszText, LPSIZE pSize);
+    void OnMouseIn(POINT pt);
+    void OnMouseOut(POINT pt);
+
+    STDMETHOD_(void, Enable)(BOOL bEnable) override;
+    STDMETHOD_(void, OnLButtonDown)(LONG x, LONG y) override;
+    STDMETHOD_(void, OnLButtonUp)(LONG x, LONG y) override;
+    STDMETHOD_(void, OnPaintNoTheme)(HDC hDC) override;
+    STDMETHOD_(void, SetStatus)(UINT uStatus);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
 inline void cicInitUIFLib(void)
 {
     cicInitUIFSys();
@@ -768,7 +873,7 @@ CUIFTheme::SetActiveTheme(LPCWSTR pszClassList, INT 
iPartId, INT iStateId)
 
 /// @unimplemented
 inline
-CUIFObject::CUIFObject(CUIFObject *pParent, DWORD dwUnknown3, LPRECT prc, 
DWORD style)
+CUIFObject::CUIFObject(CUIFObject *pParent, DWORD dwUnknown3, LPCRECT prc, 
DWORD style)
 {
     m_pszClassList = NULL;
     m_hTheme = NULL;
@@ -842,8 +947,8 @@ inline STDMETHODIMP_(void) CUIFObject::Initialize()
 
 inline STDMETHODIMP_(void) CUIFObject::OnPaint(HDC hDC)
 {
-    if (!(m_pWindow->m_style & 0x80000000) || !OnPaintTheme(hDC))
-        DoPaint(hDC);
+    if (!(m_pWindow->m_style & UIF_STYLE_THEMED) || !OnPaintTheme(hDC))
+        OnPaintNoTheme(hDC);
 }
 
 inline STDMETHODIMP_(BOOL) CUIFObject::OnSetCursor(UINT uMsg, LONG x, LONG y)
@@ -992,7 +1097,7 @@ inline STDMETHODIMP_(LRESULT) CUIFObject::OnPaintTheme(HDC 
hDC)
     return 0;
 }
 
-inline STDMETHODIMP_(void) CUIFObject::DoPaint(HDC hDC)
+inline STDMETHODIMP_(void) CUIFObject::OnPaintNoTheme(HDC hDC)
 {
 }
 
@@ -1242,6 +1347,47 @@ inline CUIFScheme::CUIFScheme(DWORD type)
 
 /////////////////////////////////////////////////////////////////////////////
 
+inline BOOL cicGetIconSize(HICON hIcon, LPSIZE pSize)
+{
+    ICONINFO IconInfo;
+    if (!GetIconInfo(hIcon, &IconInfo))
+        return FALSE;
+
+    BITMAP bm;
+    ::GetObject(IconInfo.hbmColor, sizeof(bm), &bm);
+    ::DeleteObject(IconInfo.hbmColor);
+    ::DeleteObject(IconInfo.hbmMask);
+    pSize->cx = bm.bmWidth;
+    pSize->cy = bm.bmHeight;
+    return TRUE;
+}
+
+inline HIMAGELIST CUIFIcon::GetImageList(BOOL bMirror)
+{
+    if (!m_hImageList)
+        return NULL;
+
+    if (m_hIcon)
+    {
+        SIZE iconSize;
+        cicGetIconSize(m_hIcon, &iconSize);
+
+        UINT flags = ILC_COLOR32 | ILC_MASK;
+        if (bMirror)
+            flags |= ILC_MIRROR;
+
+        m_hImageList = ImageList_Create(iconSize.cx, iconSize.cy, flags, 1, 0);
+        if (m_hImageList)
+            ImageList_ReplaceIcon(m_hImageList, -1, m_hIcon);
+
+        return m_hImageList;
+    }
+
+    return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 inline CUIFBitmapDC::CUIFBitmapDC(BOOL bMemory)
 {
     m_hBitmap = NULL;
@@ -1476,6 +1622,112 @@ cicCreateShadowMaskBmp(LPRECT prc, HBITMAP hbm1, 
HBITMAP hbm2, HBRUSH hbr1, HBRU
     return CUIFBitmapDC::s_phdcDst->DetachBitmap();
 }
 
+inline HBITMAP
+cicChangeBitmapColor(LPCRECT prc, HBITMAP hbm, COLORREF rgbBack, COLORREF 
rgbFore)
+{
+    if (!CUIFBitmapDC::s_fInitBitmapDCs)
+        return NULL;
+
+    INT width = prc->right - prc->left;
+    INT height = prc->bottom - prc->top;
+
+    CUIFSolidBrush brush(rgbFore);
+
+    CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
+    CUIFBitmapDC::s_phdcSrc->SetBitmap(hbm);
+    CUIFBitmapDC::s_phdcMask->SetBitmap(width, height, 1, 1);
+
+    ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, 
*CUIFBitmapDC::s_phdcSrc, 0, 0, SRCCOPY);
+    ::SelectObject(*CUIFBitmapDC::s_phdcDst, (HBRUSH)brush);
+    ::SetBkColor(*CUIFBitmapDC::s_phdcDst, rgbBack);
+
+    ::BitBlt(*CUIFBitmapDC::s_phdcMask, 0, 0, width, height, 
*CUIFBitmapDC::s_phdcDst, 0, 0, MERGECOPY);
+    ::SetBkColor(*CUIFBitmapDC::s_phdcDst, RGB(255, 255, 255));
+    ::SetTextColor(*CUIFBitmapDC::s_phdcDst, RGB(0, 0, 0));
+    ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, 
*CUIFBitmapDC::s_phdcMask, 0, 0, 0xE20746u);
+
+    CUIFBitmapDC::s_phdcSrc->Uninit(FALSE);
+    CUIFBitmapDC::s_phdcMask->Uninit(FALSE);
+    CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
+    return CUIFBitmapDC::s_phdcDst->DetachBitmap();
+}
+
+inline HBITMAP
+cicConvertBlackBKGBitmap(LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2, HBRUSH 
hBrush)
+{
+    if (!CUIFBitmapDC::s_fInitBitmapDCs)
+        return NULL;
+
+    if (IS_INTRESOURCE(hBrush))
+        hBrush = ::GetSysColorBrush(HandleToLong(hBrush) - 1);
+
+    LOGBRUSH lb;
+    ::GetObject(hBrush, sizeof(lb), &lb);
+    if (lb.lbStyle || lb.lbColor)
+        return NULL;
+
+    INT width = prc->right - prc->left;
+    INT height = prc->bottom - prc->top;
+
+    HBITMAP hBitmap = cicChangeBitmapColor(prc, hbm1, 0, RGB(255, 255, 255));
+    if ( !hBitmap )
+        return NULL;
+
+    CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
+    CUIFBitmapDC::s_phdcSrc->SetBitmap(hBitmap);
+    CUIFBitmapDC::s_phdcMask->SetBitmap(hbm2);
+
+    RECT rc;
+    ::SetRect(&rc, 0, 0, width, height);
+
+    HBRUSH hbrWhite = (HBRUSH)GetStockObject(WHITE_BRUSH);
+    ::FillRect(*CUIFBitmapDC::s_phdcDst, &rc, hbrWhite);
+
+    ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, 
*CUIFBitmapDC::s_phdcMask, 0, 0, 0x660046u);
+    ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, 
*CUIFBitmapDC::s_phdcSrc, 0, 0, 0x8800C6u);
+
+    CUIFBitmapDC::s_phdcSrc->Uninit(FALSE);
+    CUIFBitmapDC::s_phdcMask->Uninit(FALSE);
+    CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
+    ::DeleteObject(hBitmap);
+    return CUIFBitmapDC::s_phdcDst->DetachBitmap();
+}
+
+inline HBITMAP
+cicCreateMaskBmp(LPCRECT prc, HBITMAP hbm1, HBITMAP hbm2,
+                 HBRUSH hbr, COLORREF rgbColor, COLORREF rgbBack)
+{
+    if (!CUIFBitmapDC::s_fInitBitmapDCs)
+        return NULL;
+
+    INT width = prc->right - prc->left;
+    INT height = prc->bottom - prc->top;
+    HBITMAP hBitmap = cicConvertBlackBKGBitmap(prc, hbm1, hbm2, hbr);
+    if (hBitmap)
+        return hBitmap;
+
+    CUIFBitmapDC::s_phdcDst->SetDIB(width, height, 1, 32);
+    CUIFBitmapDC::s_phdcSrc->SetBitmap(hbm1);
+    CUIFBitmapDC::s_phdcMask->SetBitmap(hbm2);
+
+    RECT rc;
+    ::SetRect(&rc, 0, 0, width, height);
+
+    COLORREF OldTextColor = ::SetTextColor(*CUIFBitmapDC::s_phdcDst, rgbColor);
+    COLORREF OldBkColor = ::SetBkColor(*CUIFBitmapDC::s_phdcDst, rgbBack);
+    ::FillRect(*CUIFBitmapDC::s_phdcDst, &rc, hbr);
+    ::SetTextColor(*CUIFBitmapDC::s_phdcDst, OldTextColor);
+    ::SetBkColor(*CUIFBitmapDC::s_phdcDst, OldBkColor);
+
+    ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, 
*CUIFBitmapDC::s_phdcMask, 0, 0, SRCAND);
+    ::BitBlt(*CUIFBitmapDC::s_phdcDst, 0, 0, width, height, 
*CUIFBitmapDC::s_phdcSrc, 0, 0, SRCINVERT);
+    CUIFBitmapDC::s_phdcSrc->Uninit(FALSE);
+    CUIFBitmapDC::s_phdcMask->Uninit(FALSE);
+    CUIFBitmapDC::s_phdcDst->Uninit(TRUE);
+
+    return CUIFBitmapDC::s_phdcDst->DetachBitmap();
+}
+
 /////////////////////////////////////////////////////////////////////////////
 
 inline CUIFWindow::CUIFWindow(HINSTANCE hInst, DWORD style)
@@ -1668,7 +1920,7 @@ CUIFWindow::GetWndStyle()
 
     if (m_style & 0x10000000)
         ret |= WS_BORDER;
-    else if (m_style & 8)
+    else if (m_style & 0x8)
         ret |= WS_DLGFRAME;
     else if ((m_style & 0x20000000) || (m_style & 0x10))
         ret |= WS_BORDER;
@@ -1720,7 +1972,7 @@ inline void CUIFWindow::Show(BOOL bVisible)
     if (!IsWindow(m_hWnd))
         return;
 
-    if (bVisible && (m_style & 2))
+    if (bVisible && (m_style & UIF_STYLE_TOPMOST))
         ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | 
SWP_NOSIZE);
 
     m_bVisible = bVisible;
@@ -2843,3 +3095,414 @@ inline STDMETHODIMP_(void) CUIFToolTip::OnTimer(WPARAM 
wParam)
     if (wParam == TOOLTIP_TIMER_ID)
         ShowTip();
 }
+
+/////////////////////////////////////////////////////////////////////////////
+
+inline
+CUIFButton::CUIFButton(
+    CUIFObject *pParent,
+    DWORD dwUnknown3,
+    LPCRECT prc,
+    DWORD style) : CUIFObject(pParent, dwUnknown3, prc, style)
+{
+    m_ButtonIcon.m_hIcon = NULL;
+    m_ButtonIcon.m_hImageList = NULL;
+    m_dwUnknown9 = 0;
+    m_uButtonStatus = 0;
+    m_dwUnknown10 = 0;
+    m_hbmButton1 = NULL;
+    m_hbmButton2 = NULL;
+    m_pszButtonText = NULL;
+}
+
+inline CUIFButton::~CUIFButton()
+{
+    if (m_pszButtonText)
+    {
+        delete[] m_pszButtonText;
+        m_pszButtonText = NULL;
+    }
+
+    if (m_ButtonIcon.m_hImageList)
+        ImageList_Destroy(m_ButtonIcon.m_hImageList);
+}
+
+inline void
+CUIFButton::DrawBitmapProc(HDC hDC, LPCRECT prc, BOOL bPressed)
+{
+    INT width = m_rc.right - m_rc.left;
+    INT height = m_rc.bottom - m_rc.top;
+    if (m_hbmButton2)
+    {
+        HBITMAP hbmMask = cicCreateMaskBmp(&m_rc, m_hbmButton1, m_hbmButton2,
+                                           (HBRUSH)UlongToHandle(COLOR_BTNFACE 
+ 1), 0, 0);
+        ::DrawState(hDC, NULL, NULL, (LPARAM)hbmMask, 0,
+                    prc->left + bPressed, prc->top + bPressed,
+                    width - bPressed, height - bPressed,
+                    (m_bEnable ? 0 : (DSS_MONO | DSS_DISABLED)) | DST_BITMAP);
+        ::DeleteObject(hbmMask);
+    }
+    else
+    {
+        ::DrawState(hDC, NULL, NULL, (LPARAM)m_hbmButton1, 0,
+                    prc->left + bPressed, prc->top + bPressed,
+                    width - bPressed, height - bPressed,
+                    (m_bEnable ? 0 : (DSS_MONO | DSS_DISABLED)) | DST_BITMAP);
+    }
+}
+
+inline void
+CUIFButton::DrawEdgeProc(HDC hDC, LPCRECT prc, BOOL bPressed)
+{
+    RECT rc = *prc;
+    if (bPressed)
+        ::DrawEdge(hDC, &rc, BDR_SUNKENOUTER, BF_RECT);
+    else
+        ::DrawEdge(hDC, &rc, BDR_RAISEDINNER, BF_RECT);
+}
+
+inline void CUIFButton::DrawIconProc(HDC hDC, LPRECT prc, BOOL bPressed)
+{
+    INT width = prc->right - prc->left;
+    INT height = prc->bottom - prc->top;
+    RECT rc = { 0, 0, width, height };
+
+    HDC hMemDC = ::CreateCompatibleDC(hDC);
+    if (!hMemDC)
+        return;
+
+    HBITMAP hbmMem = ::CreateCompatibleBitmap(hDC, width, height);
+    if (!hbmMem)
+    {
+        ::DeleteDC(hMemDC);
+        return;
+    }
+
+    HGDIOBJ hbmOld = ::SelectObject(hMemDC, hbmMem);
+    if (m_bEnable)
+    {
+        ::BitBlt(hMemDC, rc.left, rc.top, width, height, hDC, prc->left, 
prc->top, SRCCOPY);
+    }
+    else
+    {
+        HBRUSH hbrWhite = (HBRUSH)::GetStockObject(WHITE_BRUSH);
+        ::FillRect(hMemDC, &rc, hbrWhite);
+    }
+
+    if (m_style & 0x100)
+    {
+        ::DrawIconEx(hMemDC,
+                     2 + bPressed, 2 + bPressed,
+                     m_ButtonIcon.m_hIcon,
+                     width - 4, height - 4,
+                     0, NULL, DI_NORMAL);
+    }
+    else
+    {
+        ::DrawIconEx(hMemDC,
+                     (width - 16) / 2 + bPressed,
+                     (height - 16) / 2 + bPressed,
+                     m_ButtonIcon.m_hIcon,
+                     16, 16,
+                     0, NULL, DI_NORMAL);
+    }
+
+    ::SelectObject(hMemDC, hbmOld);
+    ::DrawState(hDC, NULL, NULL, (LPARAM)hbmMem, 0,
+                prc->left, prc->top, width, height,
+                (m_bEnable ? 0 : (DSS_MONO | DSS_DISABLED)) | DST_BITMAP);
+    ::DeleteObject(hbmMem);
+    ::DeleteDC(hMemDC);
+}
+
+inline void
+CUIFButton::DrawTextProc(HDC hDC, LPCRECT prc, BOOL bPressed)
+{
+    if (!m_pszButtonText)
+        return;
+
+    HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
+    INT cchText = lstrlenW(m_pszButtonText);
+    SIZE textSize;
+    ::GetTextExtentPoint32W(hDC, m_pszButtonText, cchText, &textSize);
+
+    INT xText, yText;
+    if ((m_style & (UIF_STYLE_CHILD | UIF_STYLE_TOPMOST)) == UIF_STYLE_CHILD)
+        xText = (m_rc.right - m_rc.left - textSize.cx) / 2;
+    else if ((m_style & (UIF_STYLE_CHILD | UIF_STYLE_TOPMOST)) == 
UIF_STYLE_TOPMOST)
+        xText = m_rc.right - m_rc.left - textSize.cx;
+    else
+        xText = 0;
+
+    if ((m_style & 0xC) == UIF_STYLE_TOOLWINDOW)
+        yText = (m_rc.bottom - m_rc.top - textSize.cy) / 2;
+    else if ((m_style & 0xC) == 0x8)
+        yText = m_rc.bottom - m_rc.top - textSize.cy;
+    else
+        yText = 0;
+
+    ::SetBkMode(hDC, TRANSPARENT);
+
+    if (m_bEnable)
+    {
+        ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNTEXT));
+        ::ExtTextOutW(hDC,
+                      xText + prc->left + bPressed, yText + prc->top + 
bPressed,
+                      ETO_CLIPPED, prc,
+                      m_pszButtonText, cchText, NULL);
+    }
+    else
+    {
+        ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNHILIGHT));
+        ::ExtTextOutW(hDC,
+                      xText + prc->left + bPressed + 1, yText + prc->top + 
bPressed + 1,
+                      ETO_CLIPPED, prc,
+                      m_pszButtonText, cchText, NULL);
+
+        ::SetTextColor(hDC, ::GetSysColor(COLOR_BTNSHADOW));
+        ::ExtTextOutW(hDC,
+                      xText + prc->left + bPressed, yText + prc->top + 
bPressed,
+                      ETO_CLIPPED, prc,
+                      m_pszButtonText, cchText, NULL);
+    }
+
+    ::SelectObject(hDC, hFontOld);
+}
+
+inline STDMETHODIMP_(void)
+CUIFButton::Enable(BOOL bEnable)
+{
+    CUIFObject::Enable(bEnable);
+    if (!m_bEnable)
+    {
+        SetStatus(0);
+        if (IsCapture())
+            CUIFObject::EndCapture();
+    }
+}
+
+inline void
+CUIFButton::GetIconSize(HICON hIcon, LPSIZE pSize)
+{
+    ICONINFO IconInfo;
+    if (::GetIconInfo(hIcon, &IconInfo))
+    {
+        BITMAP bm;
+        ::GetObject(IconInfo.hbmColor, sizeof(bm), &bm);
+        ::DeleteObject(IconInfo.hbmColor);
+        ::DeleteObject(IconInfo.hbmMask);
+        pSize->cx = bm.bmWidth;
+        pSize->cy = bm.bmHeight;
+    }
+    else
+    {
+        pSize->cx = ::GetSystemMetrics(SM_CXSMICON);
+        pSize->cy = ::GetSystemMetrics(SM_CYSMICON);
+    }
+}
+
+inline void
+CUIFButton::GetTextSize(LPCWSTR pszText, LPSIZE pSize)
+{
+    HDC hDC = ::GetDC(NULL);
+    INT cchText = lstrlenW(pszText);
+    HGDIOBJ hFontOld = ::SelectObject(hDC, m_hFont);
+
+    if (!m_bHasCustomFont && SUCCEEDED(EnsureThemeData(m_pWindow->m_hWnd)))
+    {
+        RECT rc;
+        GetThemeTextExtent(hDC, 0, pszText, cchText, 0, NULL, &rc);
+        pSize->cx = rc.right;
+        pSize->cy = rc.bottom;
+    }
+    else
+    {
+        ::GetTextExtentPoint32W(hDC, pszText, cchText, pSize);
+    }
+
+    if (m_style & UIF_STYLE_VERTICAL)
+    {
+        INT tmp = pSize->cx;
+        pSize->cx = pSize->cy;
+        pSize->cy = tmp;
+    }
+
+    ::SelectObject(hDC, hFontOld);
+    ::ReleaseDC(NULL, hDC);
+}
+
+inline STDMETHODIMP_(void)
+CUIFButton::OnLButtonDown(LONG x, LONG y)
+{
+    SetStatus(1);
+    StartCapture();
+    if ((m_style & 0x30) == UIF_STYLE_TOOLTIP)
+        NotifyCommand(1, 0);
+}
+
+/// @unimplemented
+inline STDMETHODIMP_(void)
+CUIFButton::OnLButtonUp(LONG x, LONG y)
+{
+    POINT pt = { x, y };
+    BOOL bCapture = IsCapture();
+    if (bCapture)
+        EndCapture();
+
+    BOOL bNotInObject = (m_style & 0x30) == UIF_STYLE_TOOLTIP;
+    if ((m_style & 0x30) != 0x10)
+    {
+        bNotInObject = !PtInObject(pt);
+        if (bNotInObject)
+        {
+            SetStatus(0);
+            return;
+        }
+    }
+    else
+    {
+        if (!bNotInObject)
+        {
+            bNotInObject = !PtInObject(pt);
+            if (!bNotInObject)
+            {
+                SetStatus(2);
+                NotifyCommand(1, 0);
+                return;
+            }
+        }
+        SetStatus(0);
+        return;
+    }
+
+    SetStatus(2);
+
+    if (bCapture)
+    {
+        m_dwUnknown10 = !m_dwUnknown10;
+        NotifyCommand(1, 0);
+    }
+}
+
+inline void CUIFButton::OnMouseIn(POINT pt)
+{
+    if ((m_style & 0x30) == UIF_STYLE_TOOLTIP)
+    {
+        if (IsCapture())
+            SetStatus(0);
+        else
+            SetStatus(2);
+    }
+    else
+    {
+        if (IsCapture())
+            SetStatus(1);
+        else
+            SetStatus(2);
+    }
+}
+
+inline void CUIFButton::OnMouseOut(POINT pt)
+{
+    if ((m_style & 0x30) == UIF_STYLE_TOOLTIP)
+    {
+        SetStatus(0);
+    }
+    else
+    {
+        if (IsCapture())
+            SetStatus(3);
+        else
+            SetStatus(0);
+    }
+}
+
+inline STDMETHODIMP_(void)
+CUIFButton::OnPaintNoTheme(HDC hDC)
+{
+    ::FillRect(hDC, &m_rc, (HBRUSH)UlongToHandle(COLOR_BTNFACE + 1));
+
+    if (m_dwUnknown10 && ((m_uButtonStatus == 0) || (m_uButtonStatus == 3)))
+    {
+        HBRUSH hbr = cicCreateDitherBrush();
+        if (hbr)
+        {
+            COLORREF OldTextColor = ::SetTextColor(hDC, 
::GetSysColor(COLOR_BTNFACE));
+            COLORREF OldBkColor = ::SetBkColor(hDC, 
::GetSysColor(COLOR_BTNHIGHLIGHT));
+            RECT rc = m_rc;
+            ::InflateRect(&rc, -2, -2);
+            ::FillRect(hDC, &rc, hbr);
+            ::SetTextColor(hDC, OldTextColor);
+            ::SetBkColor(hDC, OldBkColor);
+            ::DeleteObject(hbr);
+        }
+    }
+
+    BOOL bPressed = (m_dwUnknown10 || (m_uButtonStatus == 1));
+    if (m_hbmButton1)
+    {
+        DrawBitmapProc(hDC, &m_rc, bPressed);
+    }
+    else if (m_ButtonIcon.m_hIcon)
+    {
+        DrawIconProc(hDC, &m_rc, bPressed);
+    }
+    else
+    {
+        DrawTextProc(hDC, &m_rc, bPressed);
+    }
+
+    if (m_dwUnknown10 || (m_uButtonStatus == 1))
+    {
+        DrawEdgeProc(hDC, &m_rc, TRUE);
+    }
+    else if (2 <= m_uButtonStatus && m_uButtonStatus <= 3)
+    {
+        DrawEdgeProc(hDC, &m_rc, FALSE);
+    }
+}
+
+inline void CUIFButton::SetIcon(HICON hIcon)
+{
+    m_ButtonIcon = hIcon;
+
+    if (m_ButtonIcon.m_hIcon)
+        GetIconSize(m_ButtonIcon.m_hIcon, &m_IconSize);
+    else
+        m_IconSize.cx = m_IconSize.cy = 0;
+
+    CallOnPaint();
+}
+
+inline void CUIFButton::SetStatus(UINT uStatus)
+{
+    if (uStatus != m_uButtonStatus)
+    {
+        m_uButtonStatus = uStatus;
+        CallOnPaint();
+    }
+}
+
+inline void CUIFButton::SetText(LPCWSTR pszText)
+{
+    if (m_pszButtonText)
+    {
+        delete[] m_pszButtonText;
+        m_pszButtonText = NULL;
+    }
+
+    m_TextSize.cx = m_TextSize.cy = 0;
+
+    if (pszText)
+    {
+        INT cch = lstrlenW(pszText);
+        m_pszButtonText = new(cicNoThrow) WCHAR[cch + 1];
+        if (!m_pszButtonText)
+            return;
+
+        lstrcpynW(m_pszButtonText, pszText, cch + 1);
+        GetTextSize(m_pszButtonText, &m_TextSize);
+    }
+
+    CallOnPaint();
+}

Reply via email to