From a73ea93f5fc27e6102130f8865767a734d940447 Mon Sep 17 00:00:00 2001 From: hatelamers <97636078+hatelamers@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:45:16 +0100 Subject: [PATCH] WTLx library updated --- src/app/ShellBrowseMenu.cpp | 99 ++----- src/app/ShellBrowseMenu.h | 13 +- src/wtlx/wtlx.vcxproj | 1 + src/wtlx/wtlx.vcxproj.filters | 39 +++ src/wtlx/wtlx/UxModePopupMenu.h | 300 +++++++++++++++++++++ src/wtlx/wtlx/uxthemehelper.h | 455 +++++++++++++++++++++++++++----- 6 files changed, 765 insertions(+), 142 deletions(-) create mode 100644 src/wtlx/wtlx/UxModePopupMenu.h diff --git a/src/app/ShellBrowseMenu.cpp b/src/app/ShellBrowseMenu.cpp index e062ee0..2c33724 100644 --- a/src/app/ShellBrowseMenu.cpp +++ b/src/app/ShellBrowseMenu.cpp @@ -8,7 +8,7 @@ CShellBrowseMenu::CShellBrowseMenu(const ShellMenuController* controller) : m_controller(controller), m_isRendered(false), m_isCtxMenuShowing(false) { - LoadIconImages(); + LoadMenuImages(); } HRESULT CShellBrowseMenu::Rebuild() @@ -57,7 +57,7 @@ BOOL CShellBrowseMenu::InvokeWithSelection(LPCTSTR strVerb) const void CShellBrowseMenu::UxModeUpdateColorSettings() { - CUxModeMenuHelper::UxModeUpdateColorSettings(); + CUxModeMenuBase::UxModeUpdateColorSettings(); if (!uxTheme.IsInDarkMode()) { m_menuColors.crHighlightBg = UXCOLOR_LIGHTER(m_menuColors.crHighlightBg, 0.3); @@ -279,7 +279,7 @@ LRESULT CShellBrowseMenu::OnDrawItem(UINT, WPARAM /*wParam*/, LPARAM lParam, BOO } bHandled = TRUE; - return CustomDrawMenuItem(lpDis); + return CustomDrawPopupMenuItem(lpDis); } LRESULT CShellBrowseMenu::OnMeasureItem(UINT, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) @@ -292,57 +292,31 @@ LRESULT CShellBrowseMenu::OnMeasureItem(UINT, WPARAM /*wParam*/, LPARAM lParam, } bHandled = TRUE; - return MeasureMenuItem(lpMis); + auto pData = reinterpret_cast(lpMis->itemData); + return MeasurePopupMenuItem(lpMis, pData ? (LPCTSTR)pData->caption : NULL); } -BOOL CShellBrowseMenu::CustomDrawMenuItem(LPDRAWITEMSTRUCT lpDis) +BOOL CShellBrowseMenu::CustomDrawPopupMenuItem(LPDRAWITEMSTRUCT lpDis) { + CustomDrawPopupMenuBackground(lpDis); + auto itemState = CustomDrawPopupMenuItemBackground(lpDis); - auto pData = (LPSHELLMENUITEMDATA)lpDis->itemData; - - CDCHandle dc = lpDis->hDC; - RECT& rcItem = lpDis->rcItem; - - CRect rcOverpaint(rcItem); - rcOverpaint.top -= 1; - rcOverpaint.bottom += 1; - m_menuTheme.DrawThemeBackground(dc, MENU_POPUPBACKGROUND, 0, rcOverpaint, NULL); - - auto isDisabled = ODS_GRAYED == (lpDis->itemState & ODS_GRAYED); - auto isSelected = ODS_SELECTED == (lpDis->itemState & ODS_SELECTED); - auto isSeparator = 0 == pData->caption.GetLength(); - - auto itemState = isDisabled ? MPIF_DISABLED : MPI_NORMAL; - if (isSelected) - itemState = isDisabled ? MPI_DISABLEDHOT : MPI_HOT; - m_menuTheme.DrawThemeBackground(dc, MENU_POPUPITEM, itemState, &rcItem, NULL); - - if (isSelected && !isDisabled) - { - CPen pen; - pen.CreatePen(PS_SOLID, 1, m_menuColors.crHihghlight); - auto oldPen = dc.SelectPen(pen); - auto oldBrush = dc.SelectBrush((HBRUSH)::GetStockObject(HOLLOW_BRUSH)); - dc.Rectangle(&rcItem); - if (oldBrush) - dc.SelectBrush(oldBrush); - if (oldPen) - dc.SelectPen(oldPen); - } - - CRect rc(rcItem); + CRect rc(lpDis->rcItem); if (m_menuMetrics.sizeIcon.cx) { rc.left += m_menuMetrics.sizeIcon.cx + (m_menuMetrics.paddingIcon.cx * 2); } - if (isSeparator) + auto pData = (LPSHELLMENUITEMDATA)lpDis->itemData; + CDCHandle dc = lpDis->hDC; + + if (NULL == pData || 0 == pData->caption.GetLength()) { m_menuTheme.DrawThemeBackground(dc, MENU_POPUPSEPARATOR, 0, rc, NULL); } else { - auto isSubmenu = ::IsMenu((HMENU)(UINT_PTR)lpDis->itemID); + auto isDisabled = ODS_GRAYED == (lpDis->itemState & ODS_GRAYED); if (-1 < pData->iconIndex && m_pImageList) { @@ -370,51 +344,30 @@ BOOL CShellBrowseMenu::CustomDrawMenuItem(LPDRAWITEMSTRUCT lpDis) } m_menuTheme.DrawThemeText(dc, MENU_POPUPITEM, itemState, pData->caption, -1, dwFlags, 0, rc); - if (isSubmenu) + if (::IsMenu((HMENU)(UINT_PTR)lpDis->itemID)) { - CustomDrawMenuArrow(dc, &rcItem, isDisabled); + CustomDrawMenuArrow(dc, &lpDis->rcItem, isDisabled); } - dc.ExcludeClipRect(&rcItem); + dc.ExcludeClipRect(&lpDis->rcItem); } return TRUE; } -BOOL CShellBrowseMenu::MeasureMenuItem(LPMEASUREITEMSTRUCT lpMis) +HRESULT CShellBrowseMenu::LoadMenuImages() { - auto pData = (LPSHELLMENUITEMDATA)lpMis->itemData; - - auto isSeparator = 0 == pData->caption.GetLength(); - if (isSeparator) - { - lpMis->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2; - lpMis->itemWidth = 0; - } - else + auto result = S_FALSE; + if (!m_pImageList) { - CWindowDC dc(GetOwnerHWND()); - CRect rcText; - m_menuTheme.GetThemeTextExtent(dc, MENU_POPUPITEM, MPI_NORMAL, pData->caption, -1, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT, NULL, rcText); - - lpMis->itemHeight = m_menuMetrics.itemHeight; - lpMis->itemWidth = rcText.Width() + m_menuMetrics.paddingIcon.cx + m_menuMetrics.sizeMnuArrow.cx; - if (m_menuMetrics.sizeIcon.cx) + result = ::SHGetImageList(SHIL_SMALL, IID_IImageList, (void**)&m_pImageList); + if (SUCCEEDED(result) && m_pImageList) { - lpMis->itemWidth += (m_menuMetrics.paddingText.cx * 2) + m_menuMetrics.sizeIcon.cx; + m_pImageList->GetIconSize((int*)&m_menuMetrics.sizeIcon.cx, (int*)&m_menuMetrics.sizeIcon.cy); + m_pImageList->GetIconSize((int*)&m_menuMetrics.sizeIcon.cx, (int*)&m_menuMetrics.sizeIcon.cy); } } - - return TRUE; -} - -HRESULT CShellBrowseMenu::LoadIconImages() -{ - auto result = ::SHGetImageList(SHIL_SMALL, IID_IImageList, (void**) &m_pImageList); - if (SUCCEEDED(result) && m_pImageList) - { - m_pImageList->GetIconSize((int*)&m_menuMetrics.sizeIcon.cx, (int*)&m_menuMetrics.sizeIcon.cy); - m_pImageList->GetIconSize((int*)&m_menuMetrics.sizeIcon.cx, (int*)&m_menuMetrics.sizeIcon.cy); - } + if (S_FALSE == result) + m_menuMetrics.sizeIcon.cx = m_menuMetrics.sizeIcon.cy = 16; return result; } diff --git a/src/app/ShellBrowseMenu.h b/src/app/ShellBrowseMenu.h index aab9d78..213503d 100644 --- a/src/app/ShellBrowseMenu.h +++ b/src/app/ShellBrowseMenu.h @@ -7,7 +7,7 @@ #endif class CShellBrowseMenu - : public CUxModeMenuHelper + : public CUxModeMenuBase { public: enum MessageID @@ -60,7 +60,7 @@ class CShellBrowseMenu virtual ~CShellBrowseMenu() = default; BEGIN_MSG_MAP(CShellBrowseMenu) - CHAIN_MSG_MAP(CUxModeMenuHelper) + CHAIN_MSG_MAP(CUxModeMenuBase) MESSAGE_HANDLER(WM_MENURBUTTONUP, OnMenuRButtonUp) MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUp) MESSAGE_HANDLER(WM_MENUCOMMAND, OnMenuCommand) @@ -89,9 +89,10 @@ class CShellBrowseMenu void Bind(const ShellMenuController* controller) { ATLASSERT(controller); + auto init = NULL == m_controller; m_controller = controller; m_mnuTop.Attach(m_controller ? m_controller->GetTopHMenu() : NULL); - UxModeSetup(); + UxModeSetup(init); SetupMenuInfo(m_mnuTop); if (!m_rootIDL.IsNull()) { @@ -116,6 +117,8 @@ class CShellBrowseMenu { return m_controller ? m_controller->GetHWnd() : NULL; } + HRESULT LoadMenuImages(); + private: LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); LRESULT OnUninitMenuPopup(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); @@ -126,10 +129,8 @@ class CShellBrowseMenu LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled); - BOOL CustomDrawMenuItem(LPDRAWITEMSTRUCT lpDis); - BOOL MeasureMenuItem(LPMEASUREITEMSTRUCT lpMis); + BOOL CustomDrawPopupMenuItem(LPDRAWITEMSTRUCT lpDis); - HRESULT LoadIconImages(); BOOL SetupMenuInfo(CMenuHandle& menu); HRESULT BuildFolderMenu(LPSHELLFOLDER pFolder, HMENU hMenu); void CleanUpMenuData(HMENU hMenu); diff --git a/src/wtlx/wtlx.vcxproj b/src/wtlx/wtlx.vcxproj index 71bd46d..46111b0 100644 --- a/src/wtlx/wtlx.vcxproj +++ b/src/wtlx/wtlx.vcxproj @@ -252,6 +252,7 @@ + diff --git a/src/wtlx/wtlx.vcxproj.filters b/src/wtlx/wtlx.vcxproj.filters index 6c04d59..6d6deef 100644 --- a/src/wtlx/wtlx.vcxproj.filters +++ b/src/wtlx/wtlx.vcxproj.filters @@ -24,6 +24,45 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + diff --git a/src/wtlx/wtlx/UxModePopupMenu.h b/src/wtlx/wtlx/UxModePopupMenu.h new file mode 100644 index 0000000..6a241f5 --- /dev/null +++ b/src/wtlx/wtlx/UxModePopupMenu.h @@ -0,0 +1,300 @@ +#pragma once + +struct UxModeMenuItemData +{ + int iconIndex{ -1 }; + bool isSubmenu{ false }; + CString caption; +}; + +template +class CUxModePopupMenu + : public CUxModeMenuBase +{ +public: + + BEGIN_MSG_MAP(CUxModePopupMenu) + CHAIN_MSG_MAP(CUxModeMenuBase) + MESSAGE_HANDLER(WM_INITMENUPOPUP, UxModeOnInitMenuPopup) + MESSAGE_HANDLER(WM_MENUSELECT, UxModeOnMenuSelect) + MESSAGE_HANDLER(WM_UNINITMENUPOPUP, UxModeOnUninitMenuPopup) + MESSAGE_HANDLER(WM_DRAWITEM, UxModeMenuOnDrawItem) + MESSAGE_HANDLER(WM_MEASUREITEM, UxModeMenuOnMeasureItem) + END_MSG_MAP() + +protected: + BOOL HandleMenuItemSelected(HMENU /*hMenu*/, WORD /*item*/, WORD /*flags*/) + { + return FALSE; + } + + int UpdateMenuItemData(TData* /*pData*/, UINT /*itemID*/, UINT /*itemPos*/, UINT /*itemType*/) + { + return -1; + } + + HRESULT LoadMenuImages() + { + if (!m_menuItemImages.IsNull()) + { + m_menuItemImages.GetIconSize(m_menuMetrics.sizeIcon); + return S_OK; + } + m_menuMetrics.sizeIcon.cx = m_menuMetrics.sizeIcon.cy = 16; + return S_FALSE; + } + + virtual void UxModeSetup(bool init = true) override + { + ATLTRACE(_T(__FUNCTION__) _T("\n")); + CUxModeMenuBase::UxModeSetup(init); + if (init) + { + GetThis()->LoadMenuImages(); + } + } + + BOOL CustomDrawPopupMenuItem(LPDRAWITEMSTRUCT lpDis) + { + CustomDrawPopupMenuBackground(lpDis); + auto itemState = CustomDrawPopupMenuItemBackground(lpDis); + + CRect rc(lpDis->rcItem); + if (m_menuMetrics.sizeIcon.cx) + { + rc.left += m_menuMetrics.sizeIcon.cx + (m_menuMetrics.paddingIcon.cx * 2); + } + + auto pData = reinterpret_cast(lpDis->itemData); + //ATLTRACE(_T(__FUNCTION__) _T(" id=%d, caption=%s, itemState=%d, themeItemState=%d\n") + // , lpDis->itemID, pData ? (LPCTSTR)pData->caption : _T("null"), lpDis->itemState, itemState); + CDCHandle dc = lpDis->hDC; + if (NULL == pData || 0 == pData->caption.GetLength()) + { + m_menuTheme.DrawThemeBackground(dc, MENU_POPUPSEPARATOR, 0, rc, NULL); + } + else + { + auto isDisabled = ODS_GRAYED == (lpDis->itemState & ODS_GRAYED); + if (S_FALSE == CustomDrawPopupMenuCheck(lpDis) && !m_menuItemImages.IsNull() && -1 < pData->iconIndex) + { + CRect rcIcon(lpDis->rcItem); + rcIcon.left += m_menuMetrics.paddingIcon.cx; + rcIcon.top += m_menuMetrics.paddingIcon.cy; + rcIcon.right = rcIcon.left + m_menuMetrics.sizeIcon.cx; + rcIcon.bottom = rcIcon.top + m_menuMetrics.sizeIcon.cy + m_menuMetrics.paddingIcon.cy; + + if (isDisabled) + { + CIcon ico = m_menuItemImages.ExtractIcon(pData->iconIndex); + dc.DrawState(rcIcon.TopLeft(), rcIcon.Size(), ico, DST_ICON | DSS_DISABLED, m_menuColors.brushBg); + } + else + { + m_menuTheme.DrawThemeIcon(dc, MENU_POPUPITEM, itemState, rcIcon, m_menuItemImages, pData->iconIndex); + } + } + + int nTab = pData->caption.Find('\t'); + + dc.SetBkMode(TRANSPARENT); + + rc.left += m_menuMetrics.paddingText.cx; + rc.right -= m_menuMetrics.sizeMnuArrow.cx + m_menuMetrics.paddingText.cx; + + DWORD dwFlags = DT_SINGLELINE | DT_VCENTER | DT_LEFT; + if (ODS_NOACCEL == (ODS_NOACCEL & lpDis->itemState)) { + dwFlags |= DT_HIDEPREFIX; + } + m_menuTheme.DrawThemeText(dc, MENU_POPUPITEM, itemState, pData->caption, nTab, dwFlags, 0, rc); + if (-1 < nTab) + { + dwFlags &= ~DT_LEFT; + dwFlags |= DT_RIGHT; + m_menuTheme.DrawThemeText(dc, MENU_POPUPITEM, itemState, pData->caption.GetBuffer() + nTab + 1, -1, dwFlags, 0, rc); + pData->caption.ReleaseBuffer(); + } + + if (pData->isSubmenu) + { + CustomDrawMenuArrow(dc, &lpDis->rcItem, isDisabled); + } + + dc.ExcludeClipRect(&lpDis->rcItem); + } + return TRUE; + } + + BOOL InitMenuPopup(HMENU hMenu, WORD /*submenuPos*/) + { + CMenuHandle menuPopup = hMenu; + ATLASSERT(menuPopup.IsMenu()); + + MENUINFO mi; + ::ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + if (m_menuMetrics.sizeIcon.cx) + { + mi.fMask = MIM_STYLE; + mi.dwStyle = MNS_CHECKORBMP; + } + UxModeUpdateMenuInfo(mi); + if (mi.fMask) + menuPopup.SetMenuInfo(&mi); + + TCHAR szCaption[MAX_PATH]; + szCaption[0] = _T('\0'); + for (UINT i = 0; i < (UINT)menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; + mii.dwTypeData = szCaption; + mii.cch = MAX_PATH; + if (menuPopup.GetMenuItemInfo(i, TRUE, &mii) && MFT_OWNERDRAW != (MFT_OWNERDRAW & mii.fType)) + { + mii.fMask = MIIM_TYPE; + if (MFT_SEPARATOR != mii.fType) + { + auto pData = new TData; + mii.dwItemData = reinterpret_cast(pData); + pData->caption = szCaption; + pData->isSubmenu = ::IsMenu(mii.hSubMenu); + GetThis()->UpdateMenuItemData(pData, mii.wID, i, mii.fType); + mii.fMask |= MIIM_DATA; + } + mii.fType |= MFT_OWNERDRAW; + + if (!menuPopup.SetMenuItemInfo(i, TRUE, &mii)) + { + ATLTRACE(_T("SetMenuItemInfo() failed with error: 0x%0lX, fType=0x%0lX, fState=0x%0lX\n") + , ATL::AtlHresultFromLastError(), mii.fType, mii.fState); + } + } + } + m_openMenus.Push(hMenu); + return TRUE; + } + + BOOL UnInitMenuPopup(HMENU hMenu) + { + CleanUpMenuData(hMenu); + auto cMenus = m_openMenus.GetSize(); + if (cMenus && m_openMenus[cMenus - 1] == hMenu) + m_openMenus.Pop(); + return TRUE; + } + + void ClearAllMenus() + { + ATLTRACE(_T(__FUNCTION__) _T("\n")); + HMENU hMenu = NULL; + while (NULL != (hMenu = m_openMenus.Pop())) + { + CleanUpMenuData(hMenu); + } + } + + void CleanUpMenuData(HMENU hMenu) + { + ATLTRACE(_T(__FUNCTION__) _T("(%p)\n"), hMenu); + CMenuHandle menuPopup = hMenu; + ATLASSERT(menuPopup.IsMenu()); + + BOOL bRet = FALSE; + for (int i = 0; i < menuPopup.GetMenuItemCount(); i++) + { + CMenuItemInfo mii; + mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + auto pData = reinterpret_cast(mii.dwItemData); + if (pData) + { + //mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE; + mii.fType &= ~MFT_OWNERDRAW; + mii.dwItemData = NULL; + mii.cch = pData->caption.GetLength(); + mii.dwTypeData = pData->caption.GetBuffer(); + + bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); + ATLASSERT(bRet); + + pData->caption.ReleaseBuffer(); + delete pData; + } + } + } + +private: + + LRESULT UxModeOnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + ATLTRACE(_T(__FUNCTION__) _T("\n")); + bHandled = FALSE; + // System menu, do nothing + if ((BOOL)HIWORD(lParam)) + { + return 1; + } + InitMenuPopup(reinterpret_cast(wParam), LOWORD(lParam)); + return 1L; + } + + LRESULT UxModeOnUninitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) + { + bHandled = FALSE; + ATLTRACE(_T(__FUNCTION__) _T("\n")); + UnInitMenuPopup(reinterpret_cast(wParam)); + return 1L; + } + + LRESULT UxModeOnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + //ATLTRaCE(_T(__FUNCTION__) _T("\n")); + bHandled = FALSE; + auto flags = HIWORD(wParam); + if (flags == 0xFFFF && lParam == NULL) // Menu closing + { + ClearAllMenus(); + } + else if (MF_HILITE == (MF_HILITE & flags)) + { + bHandled = HandleMenuItemSelected(reinterpret_cast(lParam), LOWORD(wParam), flags); + } + return 1L; + } + + LRESULT UxModeMenuOnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + //ATLTRACE(_T(__FUNCTION__) _T("\n")); + bHandled = FALSE; + auto lpDis = reinterpret_cast(lParam); + if (NULL == lpDis || ODT_MENU != lpDis->CtlType) + { + return FALSE; + } + + bHandled = TRUE; + return CustomDrawPopupMenuItem(lpDis); + } + + LRESULT UxModeMenuOnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + //ATLTRACE(_T(__FUNCTION__) _T("\n")); + bHandled = FALSE; + auto lpMis = reinterpret_cast(lParam); + if (NULL == lpMis || ODT_MENU != lpMis->CtlType) + { + return FALSE; + } + + bHandled = TRUE; + auto pData = reinterpret_cast(lpMis->itemData); + return MeasurePopupMenuItem(lpMis, pData ? (LPCTSTR)pData->caption : NULL); + } + +protected: + CSimpleStack m_openMenus; + CImageList m_menuItemImages; +}; \ No newline at end of file diff --git a/src/wtlx/wtlx/uxthemehelper.h b/src/wtlx/wtlx/uxthemehelper.h index b6d15b4..275cb01 100644 --- a/src/wtlx/wtlx/uxthemehelper.h +++ b/src/wtlx/wtlx/uxthemehelper.h @@ -355,13 +355,19 @@ struct UxModeMenuMetrics NONCLIENTMETRICS metricsNC{ 0 }; }; -template class CUxModeBase { +public: + BEGIN_MSG_MAP(CUxModeBase) + MESSAGE_HANDLER(WM_THEMECHANGED, UxModeOnThemeChange) + MESSAGE_HANDLER(WM_DESTROY, UxModeOnDestroy) + END_MSG_MAP() + protected: - virtual void UxModeSetup() + virtual void UxModeSetup(bool init = true) { + ATLTRACE(_T(__FUNCTION__) _T(" init=%d\n"), init); if (!m_menuTheme.IsThemeNull()) m_menuTheme.CloseThemeData(); auto hwnd = GetOwnerHWND(); @@ -375,14 +381,16 @@ class CUxModeBase { } - virtual HWND GetOwnerHWND() + virtual void UxModeCleanup() { - return NULL; + ATLTRACE(_T(__FUNCTION__) _T("\n")); + if (!m_menuTheme.IsThemeNull()) + m_menuTheme.CloseThemeData(); } - virtual T* GetThis() + virtual HWND GetOwnerHWND() { - return dynamic_cast(this); + return NULL; } LRESULT UxModeOnThemeChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) @@ -391,7 +399,7 @@ class CUxModeBase if (m_lastModeWasDark != uxTheme.IsInDarkMode()) { bHandled = TRUE; - UxModeSetup(); + UxModeSetup(false); auto hwnd = GetOwnerHWND(); if (::IsWindow(hwnd)) ::UpdateWindow(hwnd); @@ -402,53 +410,60 @@ class CUxModeBase LRESULT UxModeOnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { bHandled = FALSE; - if (!m_menuTheme.IsThemeNull()) - m_menuTheme.CloseThemeData(); - + UxModeCleanup(); return 1; } protected: + bool m_uxModeInitialized{ false }; bool m_lastModeWasDark{ false }; CTheme m_menuTheme; }; template -class CUxModeMenuHelper - : public virtual CUxModeBase +class CUxModeMenuBase + : public CUxModeBase { public: - BEGIN_MSG_MAP(CUxModeMenuHelper) - MESSAGE_HANDLER(WM_THEMECHANGED, UxModeOnThemeChange) - MESSAGE_HANDLER(WM_DESTROY, UxModeOnDestroy) + BEGIN_MSG_MAP(CUxModeMenuBase) + CHAIN_MSG_MAP(CUxModeBase) END_MSG_MAP() protected: - virtual void UxModeSetup() override + T* GetThis() { - CBitmap bmpArrow; - BITMAP bm; - if (bmpArrow.LoadOEMBitmap(OBM_MNARROW) && bmpArrow.GetBitmap(bm)) - { - m_menuMetrics.sizeMnuArrow.cx = bm.bmWidth; - m_menuMetrics.sizeMnuArrow.cy = bm.bmHeight; - } + return static_cast(this); + } - m_menuMetrics.metricsNC.cbSize = sizeof(NONCLIENTMETRICS); - if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, m_menuMetrics.metricsNC.cbSize, &m_menuMetrics.metricsNC, 0)) + virtual void UxModeSetup(bool init = true) override + { + ATLTRACE(_T(__FUNCTION__) _T("\n")); + if (init) { - m_menuMetrics.itemHeight = max(m_menuMetrics.metricsNC.iMenuHeight, ::abs(m_menuMetrics.metricsNC.lfMenuFont.lfHeight) + (m_menuMetrics.paddingText.cy * 2)); - if (m_menuMetrics.sizeIcon.cy && m_menuMetrics.itemHeight < (m_menuMetrics.paddingIcon.cy * 2) + m_menuMetrics.sizeIcon.cy) + CBitmap bmpArrow; + BITMAP bm; + if (bmpArrow.LoadOEMBitmap(OBM_MNARROW) && bmpArrow.GetBitmap(bm)) { - m_menuMetrics.itemHeight = (m_menuMetrics.paddingIcon.cy * 2) + m_menuMetrics.sizeIcon.cy; + m_menuMetrics.sizeMnuArrow.cx = bm.bmWidth; + m_menuMetrics.sizeMnuArrow.cy = bm.bmHeight; } - if (m_menuMetrics.paddingIcon.cy > m_menuMetrics.itemHeight - m_menuMetrics.sizeIcon.cy - m_menuMetrics.paddingIcon.cy) + + m_menuMetrics.metricsNC.cbSize = sizeof(NONCLIENTMETRICS); + if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, m_menuMetrics.metricsNC.cbSize, &m_menuMetrics.metricsNC, 0)) { - m_menuMetrics.paddingIcon.cy = (m_menuMetrics.itemHeight - m_menuMetrics.sizeIcon.cy) / 2; + m_menuMetrics.itemHeight = max(m_menuMetrics.metricsNC.iMenuHeight, ::abs(m_menuMetrics.metricsNC.lfMenuFont.lfHeight) + (m_menuMetrics.paddingText.cy * 2)); + if (m_menuMetrics.sizeIcon.cy && m_menuMetrics.itemHeight < (m_menuMetrics.paddingIcon.cy * 2) + m_menuMetrics.sizeIcon.cy) + { + m_menuMetrics.itemHeight = (m_menuMetrics.paddingIcon.cy * 2) + m_menuMetrics.sizeIcon.cy; + } + if (m_menuMetrics.paddingIcon.cy > m_menuMetrics.itemHeight - m_menuMetrics.sizeIcon.cy - m_menuMetrics.paddingIcon.cy) + { + m_menuMetrics.paddingIcon.cy = (m_menuMetrics.itemHeight - m_menuMetrics.sizeIcon.cy) / 2; + } } } - CUxModeBase::UxModeSetup(); + CUxModeBase::UxModeSetup(init); if (!m_menuTheme.IsThemeNull()) { HBITMAP hBmp = NULL; @@ -476,6 +491,85 @@ class CUxModeMenuHelper } } + BOOL MeasurePopupMenuItem(LPMEASUREITEMSTRUCT lpMis, LPCTSTR caption) + { + auto isSeparator = NULL == caption || 0 == ::lstrlen(caption); + if (isSeparator) + { + lpMis->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2; + lpMis->itemWidth = 0; + } + else + { + CWindowDC dc(GetOwnerHWND()); + CRect rcText; + m_menuTheme.GetThemeTextExtent(dc, MENU_POPUPITEM, MPI_NORMAL, caption, -1 + , DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_EXPANDTABS| DT_CALCRECT, NULL, rcText); + + lpMis->itemHeight = m_menuMetrics.itemHeight; + lpMis->itemWidth = rcText.Width() + m_menuMetrics.paddingIcon.cx + m_menuMetrics.sizeMnuArrow.cx; + if (m_menuMetrics.sizeIcon.cx) + { + lpMis->itemWidth += (m_menuMetrics.paddingText.cx * 2) + m_menuMetrics.sizeIcon.cx; + } + } + + return TRUE; + } + + HRESULT CustomDrawPopupMenuBackground(LPDRAWITEMSTRUCT lpDis) + { + CRect rcOverpaint(lpDis->rcItem); + rcOverpaint.top -= 1; + rcOverpaint.bottom += 1; + return m_menuTheme.DrawThemeBackground(lpDis->hDC, MENU_POPUPBACKGROUND, 0, rcOverpaint, NULL); + } + + POPUPITEMSTATES CustomDrawPopupMenuItemBackground(LPDRAWITEMSTRUCT lpDis) + { + CDCHandle dc = lpDis->hDC; + + auto isDisabled = ODS_GRAYED == (lpDis->itemState & ODS_GRAYED); + auto isSelected = ODS_SELECTED == (lpDis->itemState & ODS_SELECTED); + + auto result = isDisabled ? MPI_DISABLED : MPI_NORMAL; + if (isSelected) + result = isDisabled ? MPI_DISABLEDHOT : MPI_HOT; + m_menuTheme.DrawThemeBackground(dc, MENU_POPUPITEM, result, &lpDis->rcItem, NULL); + + if (isSelected && !isDisabled) + { + CPen pen; + pen.CreatePen(PS_SOLID, 1, m_menuColors.crHihghlight); + auto oldPen = dc.SelectPen(pen); + auto oldBrush = dc.SelectBrush((HBRUSH)::GetStockObject(HOLLOW_BRUSH)); + dc.Rectangle(&lpDis->rcItem); + if (oldBrush) + dc.SelectBrush(oldBrush); + if (oldPen) + dc.SelectPen(oldPen); + } + return result; + } + + HRESULT CustomDrawPopupMenuCheck(LPDRAWITEMSTRUCT lpDis) + { + auto result = S_FALSE; + if (ODS_CHECKED == (ODS_CHECKED & lpDis->itemState)) + { + auto isDisabled = ODS_GRAYED == (lpDis->itemState & ODS_GRAYED); + CRect rcCheck(lpDis->rcItem); + rcCheck.left += m_menuMetrics.paddingIcon.cx; + rcCheck.top += m_menuMetrics.paddingIcon.cy; + rcCheck.right = rcCheck.left + m_menuMetrics.sizeIcon.cx; + rcCheck.bottom = rcCheck.top + m_menuMetrics.sizeIcon.cy + m_menuMetrics.paddingIcon.cy; + + result = m_menuTheme.DrawThemeBackground(lpDis->hDC, MENU_POPUPCHECKBACKGROUND, isDisabled ? MCB_DISABLED : MCB_NORMAL, rcCheck, NULL); + result = m_menuTheme.DrawThemeBackground(lpDis->hDC, MENU_POPUPCHECK, isDisabled ? MC_CHECKMARKDISABLED : MC_CHECKMARKNORMAL, rcCheck, NULL); + } + return result; + } + BOOL CustomDrawMenuArrow(HDC hdcItem, LPRECT rcItem, bool isDisabled) { CRect rcArrow(rcItem); @@ -606,27 +700,44 @@ struct is_prop_sheet template static no test(...); +public: + + static constexpr bool value = std::is_same(0)), yes>::value; +}; +template +struct is_prop_page +{ +private: + typedef std::true_type yes; + typedef std::false_type no; + + template static auto test(int) -> decltype(std::declval().GetPropertySheet() != nullptr, yes()); + + template static no test(...); + public: static constexpr bool value = std::is_same(0)), yes>::value; }; enum class UxModeWindowType { - GENERIC, DIALOG, PROP_SHEET + GENERIC, DIALOG, PROP_SHEET, PROP_PAGE }; #define UXPROP_LISTVIEWPROC _T("UxModeListViewProc") -template +template class CUxModeWindow - : public virtual CUxModeBase + : public TBase { public: + using ThisUxWindowClass = CUxModeWindow; - BEGIN_MSG_MAP(CUxModeWindow) + BEGIN_MSG_MAP(ThisUxWindowClass) switch (UxWindowType) { case UxModeWindowType::DIALOG: + case UxModeWindowType::PROP_PAGE: MESSAGE_HANDLER(WM_INITDIALOG, UxModeOnInitDialog) break; default: @@ -635,13 +746,16 @@ class CUxModeWindow } MESSAGE_HANDLER(WM_CTLCOLORDLG, UxModeOnCtlColorDlg) MESSAGE_HANDLER(WM_CTLCOLORSTATIC, UxModeOnCtlColorDlg) + MESSAGE_HANDLER(WM_CTLCOLOREDIT, UxModeOnCtlColorDlg) MESSAGE_HANDLER(WM_SETTINGCHANGE, UxModeOnSettingChange) - MESSAGE_HANDLER(WM_THEMECHANGED, UxModeOnThemeChange) MESSAGE_HANDLER(WM_NCPAINT, UxModeOnNcPaint) MESSAGE_HANDLER(WM_NCACTIVATE, UxModeOnNcPaint) MESSAGE_HANDLER(WM_UAHDRAWMENU, UxModeOnUahDrawMenu) MESSAGE_HANDLER(WM_UAHDRAWMENUITEM, UxModeOnUahDrawMenuItem) - MESSAGE_HANDLER(WM_DESTROY, UxModeOnDestroy) +#ifdef UXMODE_SUPPORT_TABCONTROL + MESSAGE_HANDLER(WM_DRAWITEM, UxModeOnDrawItem) +#endif // UXMODE_SUPPORT_TABCONTROL + CHAIN_MSG_MAP(TBase) #ifdef UXMODE_SUPPORT_LISTVIEW #ifdef UXMODE_CUSTOMDRAW_LISTVIEW_GROUPS #pragma warning( push ) @@ -711,30 +825,55 @@ class CUxModeWindow return GetThis()->m_hWnd; } - virtual T* GetThis() override + T* GetThis() { return static_cast(this); } - virtual void UxModeSetup() override + virtual bool UsingSecondaryBgColor(HWND hWnd) + { + return UxModeWindowType::DIALOG == UxWindowType || (hWnd == GetOwnerHWND() && UxModeWindowType::PROP_SHEET == UxWindowType); + } + + virtual void UxModeCleanup() + { + TBase::UxModeCleanup(); +#ifdef UXMODE_SUPPORT_TABCONTROL + if (!m_tabTheme.IsThemeNull()) + { + m_tabTheme.CloseThemeData(); + } +#endif // UXMODE_SUPPORT_TABCONTROL + } + + virtual void UxModeSetup(bool init = true) override { - ATLTRACE(_T(__FUNCTION__) _T(" WindowType=%d IsAppThemed=%d IsThemeActive=%d bgColor=%x\n"), UxWindowType, ::IsAppThemed(), ::IsThemeActive() - , uxTheme.GetSysColorValue(CUxTheme::UIColorType::Background)); auto isDark = uxTheme.IsInDarkMode(); + m_crBgSecond = isDark ? UXCOLOR_LIGHTER(uxTheme.GetSysColorValue(CUxTheme::UIColorType::Background), 0.25) : ::GetSysColor(COLOR_BTNFACE); + m_crBg = isDark ? uxTheme.GetSysColorValue(CUxTheme::UIColorType::Background) : ::GetSysColor(COLOR_WINDOW); + ATLTRACE(_T(__FUNCTION__) _T(" WindowType=%d IsAppThemed=%d IsThemeActive=%d bgColor=%x\n"), UxWindowType, ::IsAppThemed(), ::IsThemeActive() + , m_crBg); if (isDark && m_lastModeWasDark != isDark) { if (!m_brushBg.IsNull()) m_brushBg.DeleteObject(); - m_brushBg.CreateSolidBrush(uxTheme.GetSysColorValue(CUxTheme::UIColorType::Background)); + m_brushBg.CreateSolidBrush(m_crBg); + if (!m_brushBgSecond.IsNull()) + m_brushBgSecond.DeleteObject(); + m_brushBgSecond.CreateSolidBrush(m_crBgSecond); } m_lastModeWasDark = isDark; auto pSelf = GetThis(); - if (!m_initialized) + if (!m_uxModeInitialized) { - uxTheme.AllowDarkModeForWindow(pSelf->m_hWnd, true); +#ifdef UXMODE_SUPPORT_TABCONTROL + m_tabTheme.OpenThemeData(pSelf->m_hWnd, VSCLASS_TAB); +#endif // UXMODE_SUPPORT_TABCONTROL + + uxTheme.AllowDarkModeForWindow(pSelf->m_hWnd, true); MENUBARINFO mbi = { sizeof(mbi) }; m_hasMenuBar = ::GetMenuBarInfo(pSelf->m_hWnd, OBJID_MENU, 0, &mbi); #ifdef UXMODE_SUPPORT_SCROLLBAR @@ -743,7 +882,7 @@ class CUxModeWindow } uxTheme.SwitchWindowDarkMode(pSelf->m_hWnd, isDark); - CUxModeBase::UxModeSetup(); + TBase::UxModeSetup(init); ::EnumChildWindows(pSelf->m_hWnd, [](HWND hwnd, LPARAM lParam) -> BOOL { @@ -751,13 +890,27 @@ class CUxModeWindow CString str; ::GetClassName(hwnd, str.GetBufferSetLength(MAX_PATH), MAX_PATH); str.ReleaseBuffer(); - if (_T("Button") == str || _T("Edit") == str) + auto dwStyle = ::GetWindowLongPtr(hwnd, GWL_STYLE); + LPCWSTR strTheme = NULL; + if (_T("Button") == str) { - pParent->SetUxModeForThemedControl(hwnd, L"Explorer"); + auto isCheck = BS_DEFPUSHBUTTON < ((BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE | BS_RADIOBUTTON | BS_AUTORADIOBUTTON) & dwStyle); + if (isCheck) + { + pParent->SetUxModeForCheckbox(hwnd); + } + else + { + strTheme = L"Explorer"; + } + } + else if (_T("Edit") == str) + { + strTheme = L"Explorer"; } else if (_T("ComboBox") == str) { - pParent->SetUxModeForThemedControl(hwnd, L"CFD"); + strTheme = L"CFD"; } #ifdef UXMODE_SUPPORT_LISTVIEW else if (_T("SysListView32") == str) @@ -774,7 +927,7 @@ class CUxModeWindow #ifdef UXMODE_SUPPORT_TABCONTROL else if (_T("SysTabControl32") == str) { - pParent->SetUxModeForThemedControl(hwnd, L"DarkMode_Explorer"); + pParent->SetUxModeForTabControl(hwnd); } #endif // UXMODE_SUPPORT_TABCONTROL else @@ -782,19 +935,22 @@ class CUxModeWindow ::SendMessage(hwnd, WM_THEMECHANGED, 0, 0); } + if (strTheme) + pParent->SetUxModeForThemedControl(hwnd, strTheme); + return TRUE; }, reinterpret_cast(this)); - if (!m_initialized) + if (!m_uxModeInitialized) pSelf->SendMessage(WM_THEMECHANGED); - m_initialized = true; + m_uxModeInitialized = true; } bool SetUxModeForThemedControl(HWND hWnd, LPCWSTR strTheme, LPCWSTR strSublist = NULL, bool force = false) const { auto r = uxTheme.AllowDarkModeForWindow(hWnd, uxTheme.IsInDarkMode()); - auto hr = !force && m_initialized ? S_FALSE : ::SetWindowTheme(hWnd, strTheme, strSublist); + auto hr = !force && m_uxModeInitialized ? S_FALSE : ::SetWindowTheme(hWnd, strTheme, strSublist); if (S_FALSE == hr) { ::SendMessage(hWnd, WM_THEMECHANGED, 0, 0); @@ -802,6 +958,27 @@ class CUxModeWindow return r && SUCCEEDED(hr); } + bool SetUxModeForCheckbox(HWND hWnd) + { + auto isDark = uxTheme.IsInDarkMode(); + // ugly but I don't feel like owner drawing this one too + if (isDark) + { + CWindow wnd(hWnd); + wnd.ModifyStyle(0, BS_FLAT); + } + return SetUxModeForThemedControl(hWnd, isDark ? L"" : VSCLASS_BUTTONSTYLE, isDark ? L"" : VSCLASS_BUTTON, true); + } + +#ifdef UXMODE_SUPPORT_TABCONTROL + bool SetUxModeForTabControl(HWND hWnd) + { + auto isDark = uxTheme.IsInDarkMode(); + CWindow win(hWnd); + return TRUE == win.ModifyStyle(isDark ? 0 : TCS_OWNERDRAWFIXED, isDark ? TCS_OWNERDRAWFIXED : 0); + } +#endif // UXMODE_SUPPORT_TABCONTROL + #ifdef UXMODE_SUPPORT_PROGRESSBAR bool SetUxModeForProgressBar(HWND hWnd) { @@ -812,7 +989,7 @@ class CUxModeWindow ::SendMessage(hWnd, PBM_SETBKCOLOR, 0, UXCOLOR_LIGHTER(uxTheme.GetSysColorValue(CUxTheme::UIColorType::Background), 0.18)); } else { - hr = ::SetWindowTheme(hWnd, VSCLASS_PROGRESS, NULL); + hr = ::SetWindowTheme(hWnd, VSCLASS_PROGRESSSTYLE, VSCLASS_PROGRESS); } return SUCCEEDED(hr); } @@ -957,6 +1134,126 @@ class CUxModeWindow return FALSE; } +#ifdef UXMODE_SUPPORT_TABCONTROL + BOOL UxModeCustomDrawTabItem(LPDRAWITEMSTRUCT lpDis) + { + if (0 > lpDis->itemID) + return FALSE; + + BOOL result = TRUE; + + CString caption; + TCITEM tci; + ZeroMemory(&tci, sizeof(TCITEM)); + tci.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_STATE; + tci.dwStateMask = TCIS_HIGHLIGHTED; + tci.pszText = caption.GetBufferSetLength(MAX_PATH); + tci.cchTextMax = MAX_PATH; + result = TabCtrl_GetItem(lpDis->hwndItem, lpDis->itemID, &tci); + caption.ReleaseBuffer(); + if (!result) + { + return result; + } + + auto cItems = TabCtrl_GetItemCount(lpDis->hwndItem); + + auto isDisabled = ODS_DISABLED == (ODS_DISABLED & lpDis->itemState) || ODS_GRAYED == (ODS_GRAYED & lpDis->itemState); + auto isSelected = ODS_SELECTED == (ODS_SELECTED & lpDis->itemState); + auto isDark = uxTheme.IsInDarkMode(); + + CDCHandle dc(lpDis->hDC); + CRect rcItem(lpDis->rcItem); + CRect rcFullItem(lpDis->rcItem); + if (isSelected) + { + rcFullItem.left += 2; + rcFullItem.right -= 1; + //rcFullItem.bottom -= 1; + } + else + { + rcFullItem.InflateRect(2, 2); + } + + CRect rcBg(rcFullItem); + if (isSelected) + { + rcBg.left += 2; + } + else + { + rcBg.top += 2; + } + + auto crBg = m_crBgSecond; + if (isDark) + { + auto isLastTab = lpDis->itemID == (UINT)cItems - 1; + CRect rcWnd; + ::GetWindowRect(lpDis->hwndItem, rcWnd); + ::ScreenToClient(lpDis->hwndItem, &rcWnd.BottomRight()); + ::ScreenToClient(lpDis->hwndItem, &rcWnd.TopLeft()); + + CRect rcCtlBg(rcItem); + rcCtlBg.top = rcWnd.top; + if (isLastTab) + { + rcCtlBg.right = rcWnd.right; + rcCtlBg.bottom += 1; + } + else + { + rcCtlBg.bottom = rcCtlBg.top + 2; + if (0 == lpDis->itemID) + { + rcCtlBg.left = rcWnd.left; + if (isSelected) + { + rcCtlBg.left += 2; + } + } + } + //ATLTRACE(_T(__FUNCTION__) _T(" l=%d, t=%d, r=%d, b=%d\n"), rcCtlBg.left, rcCtlBg.top, rcCtlBg.right, rcCtlBg.bottom); + dc.FillSolidRect(rcCtlBg, crBg); + } + + crBg = isSelected ? m_crBg : m_crBgSecond; + dc.FillSolidRect(rcBg, crBg); + + DWORD dwFlags = DT_CENTER | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS; + if (ODS_NOACCEL == (ODS_NOACCEL & lpDis->itemState)) { + dwFlags |= DT_HIDEPREFIX; + } + DTTOPTS opts = { sizeof(opts), DTT_TEXTCOLOR}; + if (isDark) + { + opts.crText = uxTheme.GetSysColorValue(CUxTheme::UIColorType::Foreground); + if (isDisabled) + opts.crText = UXCOLOR_DARKER(opts.crText, 0.3); + } + else + { + opts.crText = isDisabled ? ::GetSysColor(COLOR_GRAYTEXT) : ::GetSysColor(COLOR_BTNTEXT); + } + //m_tabTheme.GetThemeColor(TABP_TABITEM, isDisabled ? TIS_DISABLED : TIS_NORMAL, TMT_BTNTEXT, &opts.crText); + m_tabTheme.DrawThemeTextEx(dc, TABP_TABITEM, TIS_NORMAL, caption, -1, dwFlags, rcItem, &opts); + + //CRect rcClip(rcFullItem); + //if (isSelected) + //{ + // rcClip.left -= 3; + // rcClip.right += 3; + //} + //else + //{ + // rcClip.top += 2; + //} + //dc.ExcludeClipRect(rcClip); + return result; + } +#endif // UXMODE_SUPPORT_TABCONTROL + #ifdef UXMODE_SUPPORT_LISTVIEW #ifdef UXMODE_CUSTOMDRAW_LISTVIEW_GROUPS LRESULT UxModeCustomDrawListView(LPNMLVCUSTOMDRAW pNMLVCD) @@ -1063,18 +1360,27 @@ class CUxModeWindow bHandled = TRUE; CWindow wnd(reinterpret_cast(lParam)); + auto useSecondBg = UsingSecondaryBgColor(wnd.m_hWnd); CDCHandle dc(reinterpret_cast(wParam)); - dc.SetBkColor(uxTheme.GetSysColorValue(CUxTheme::UIColorType::Background)); + dc.SetBkColor(useSecondBg ? m_crBgSecond : m_crBg); dc.SetTextColor(uxTheme.GetSysColorValue(CUxTheme::UIColorType::Foreground)); - if (BS_GROUPBOX == (BS_GROUPBOX & wnd.GetWindowLongPtr(GWL_STYLE))) + CString strClass; + ::GetClassName(wnd, strClass.GetBufferSetLength(MAX_PATH), MAX_PATH); + strClass.ReleaseBuffer(); + if (_T("Button") == strClass) { - UxModeDrawGroupBox(wnd, dc); + auto dwStyle = wnd.GetWindowLongPtr(GWL_STYLE); + if (BS_GROUPBOX == (BS_GROUPBOX & dwStyle)) + { + UxModeDrawGroupBox(wnd, dc); + } } - return reinterpret_cast(WS_EX_TRANSPARENT == (WS_EX_TRANSPARENT & wnd.GetWindowLongPtr(GWL_EXSTYLE)) - ? ::GetStockObject(HOLLOW_BRUSH) - : m_brushBg.m_hBrush); + //return reinterpret_cast(WS_EX_TRANSPARENT == (WS_EX_TRANSPARENT & wnd.GetWindowLongPtr(GWL_EXSTYLE)) + // ? ::GetStockObject(HOLLOW_BRUSH) + // : m_brushBg.m_hBrush); + return reinterpret_cast(useSecondBg ? m_brushBgSecond.m_hBrush : m_brushBg.m_hBrush); } return FALSE; } @@ -1121,6 +1427,24 @@ class CUxModeWindow return FALSE; } +#ifdef UXMODE_SUPPORT_TABCONTROL + LRESULT UxModeOnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) + { + bHandled = FALSE; + auto lpDis = reinterpret_cast(lParam); + if (NULL != lpDis || ODT_TAB == lpDis->CtlType) + { + auto result = UxModeCustomDrawTabItem(lpDis); + if (result) + { + bHandled = TRUE; + return result; + } + } + return FALSE; + } +#endif // UXMODE_SUPPORT_TABCONTROL + #ifdef UXMODE_CUSTOMDRAW_LISTVIEW_GROUPS LRESULT UxModeOnCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { @@ -1141,7 +1465,7 @@ class CUxModeWindow } return CDRF_DODEFAULT; } -#endif +#endif // UXMODE_CUSTOMDRAW_LISTVIEW_GROUPS LRESULT UxModeOnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { @@ -1155,10 +1479,15 @@ class CUxModeWindow } protected: - bool m_initialized{ false }; bool m_hasMenuBar{ false }; + COLORREF m_crBgSecond; + CBrush m_brushBgSecond; + COLORREF m_crBg; CBrush m_brushBg; +#ifdef UXMODE_SUPPORT_TABCONTROL + CTheme m_tabTheme; +#endif // UXMODE_SUPPORT_TABCONTROL }; -template -UxModeWindowType CUxModeWindow::UxWindowType = (is_dialog::value ? UxModeWindowType::DIALOG : (is_prop_sheet::value ? UxModeWindowType::PROP_SHEET : UxModeWindowType::GENERIC)); +template +UxModeWindowType CUxModeWindow::UxWindowType = is_prop_page::value ? UxModeWindowType::PROP_PAGE : (is_dialog::value ? UxModeWindowType::DIALOG : (is_prop_sheet::value ? UxModeWindowType::PROP_SHEET : UxModeWindowType::GENERIC));