206 lines
6.6 KiB
C++
206 lines
6.6 KiB
C++
/*---------------------------------------------------------------------------*/
|
|
// Author : adzm
|
|
// Web : https://github.com/adzm/win32-custom-menubar-aero-theme
|
|
// License : MIT License
|
|
// https://github.com/adzm/win32-custom-menubar-aero-theme/blob/main/LICENSE
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#include "stdafx.h"
|
|
#include <Uxtheme.h>
|
|
#include <vsstyle.h>
|
|
#include "UAHMenuBar.h"
|
|
|
|
#pragma comment(lib, "uxtheme.lib")
|
|
|
|
static HTHEME g_menuTheme = nullptr;
|
|
extern bool g_darkModeEnabled;
|
|
|
|
// ugly colors for illustration purposes
|
|
static HBRUSH g_brBarBackground = CreateSolidBrush(RGB(0x2C, 0x2C, 0x2C));
|
|
|
|
void UAHDrawMenuNCBottomLine(HWND hWnd)
|
|
{
|
|
MENUBARINFO mbi = { sizeof(mbi) };
|
|
if (!GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi))
|
|
{
|
|
return;
|
|
}
|
|
|
|
RECT rcClient = { 0 };
|
|
GetClientRect(hWnd, &rcClient);
|
|
MapWindowPoints(hWnd, nullptr, (POINT*)&rcClient, 2);
|
|
|
|
RECT rcWindow = { 0 };
|
|
GetWindowRect(hWnd, &rcWindow);
|
|
|
|
OffsetRect(&rcClient, -rcWindow.left, -rcWindow.top);
|
|
|
|
// the rcBar is offset by the window rect
|
|
RECT rcAnnoyingLine = rcClient;
|
|
rcAnnoyingLine.bottom = rcAnnoyingLine.top;
|
|
rcAnnoyingLine.top--;
|
|
|
|
|
|
HDC hdc = GetWindowDC(hWnd);
|
|
FillRect(hdc, &rcAnnoyingLine, g_brBarBackground);
|
|
ReleaseDC(hWnd, hdc);
|
|
}
|
|
|
|
// processes messages related to UAH / custom menubar drawing.
|
|
// return true if handled, false to continue with normal processing in your wndproc
|
|
bool UAHWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr)
|
|
{
|
|
if (! g_darkModeEnabled)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch (message)
|
|
{
|
|
case WM_UAHDRAWMENU:
|
|
{
|
|
UAHMENU* pUDM = (UAHMENU*)lParam;
|
|
RECT rc = { 0 };
|
|
|
|
// get the menubar rect
|
|
{
|
|
MENUBARINFO mbi = { sizeof(mbi) };
|
|
GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi);
|
|
|
|
RECT rcWindow;
|
|
GetWindowRect(hWnd, &rcWindow);
|
|
|
|
// the rcBar is offset by the window rect
|
|
rc = mbi.rcBar;
|
|
OffsetRect(&rc, -rcWindow.left, -rcWindow.top);
|
|
}
|
|
|
|
FillRect(pUDM->hdc, &rc, g_brBarBackground);
|
|
|
|
return true;
|
|
}
|
|
case WM_UAHDRAWMENUITEM:
|
|
{
|
|
typedef HRESULT(WINAPI* FuncDrawThemeTextEx)(HTHEME hTheme, HDC hdc,
|
|
int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags,
|
|
LPRECT pRect, const DTTOPTS* pOptions);
|
|
|
|
static bool bInitialized = false;
|
|
static FuncDrawThemeTextEx pDrawThemeTextEx = NULL;
|
|
|
|
if (bInitialized == false)
|
|
{
|
|
HMODULE hModule = GetModuleHandle(_T("UxTheme.dll"));
|
|
if (hModule)
|
|
{
|
|
pDrawThemeTextEx = (FuncDrawThemeTextEx)GetProcAddress(hModule, "DrawThemeTextEx");
|
|
}
|
|
bInitialized = true;
|
|
}
|
|
|
|
if (pDrawThemeTextEx == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UAHDRAWMENUITEM* pUDMI = (UAHDRAWMENUITEM*)lParam;
|
|
|
|
// ugly colors for illustration purposes
|
|
static HBRUSH g_brItemBackground = CreateSolidBrush(RGB(0x2C, 0x2C, 0x2C));
|
|
static HBRUSH g_brItemBackgroundHot = CreateSolidBrush(RGB(0x35, 0x35, 0x35));
|
|
static HBRUSH g_brItemBackgroundSelected = CreateSolidBrush(RGB(0x35, 0x35, 0x35));
|
|
|
|
HBRUSH* pbrBackground = &g_brItemBackground;
|
|
|
|
// get the menu item string
|
|
wchar_t menuString[256] = { 0 };
|
|
MENUITEMINFO mii = { sizeof(mii), MIIM_STRING };
|
|
{
|
|
mii.dwTypeData = menuString;
|
|
mii.cch = (sizeof(menuString) / 2) - 1;
|
|
|
|
GetMenuItemInfo(pUDMI->um.hmenu, pUDMI->umi.iPosition, TRUE, &mii);
|
|
}
|
|
|
|
// get the item state for drawing
|
|
|
|
DWORD dwFlags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
|
|
|
|
int iTextStateID = 0;
|
|
int iBackgroundStateID = 0;
|
|
{
|
|
if ((pUDMI->dis.itemState & ODS_INACTIVE) | (pUDMI->dis.itemState & ODS_DEFAULT)) {
|
|
// normal display
|
|
iTextStateID = MPI_NORMAL;
|
|
iBackgroundStateID = MPI_NORMAL;
|
|
}
|
|
if (pUDMI->dis.itemState & ODS_HOTLIGHT) {
|
|
// hot tracking
|
|
iTextStateID = MPI_HOT;
|
|
iBackgroundStateID = MPI_HOT;
|
|
|
|
pbrBackground = &g_brItemBackgroundHot;
|
|
}
|
|
if (pUDMI->dis.itemState & ODS_SELECTED) {
|
|
// clicked -- MENU_POPUPITEM has no state for this, though MENU_BARITEM does
|
|
iTextStateID = MPI_HOT;
|
|
iBackgroundStateID = MPI_HOT;
|
|
|
|
pbrBackground = &g_brItemBackgroundSelected;
|
|
}
|
|
if ((pUDMI->dis.itemState & ODS_GRAYED) || (pUDMI->dis.itemState & ODS_DISABLED)) {
|
|
// disabled / grey text
|
|
iTextStateID = MPI_DISABLED;
|
|
iBackgroundStateID = MPI_DISABLED;
|
|
}
|
|
if (pUDMI->dis.itemState & ODS_NOACCEL) {
|
|
dwFlags |= DT_HIDEPREFIX;
|
|
}
|
|
}
|
|
|
|
if (!g_menuTheme) {
|
|
g_menuTheme = OpenThemeData(hWnd, L"Menu");
|
|
}
|
|
|
|
DTTOPTS opts = { sizeof(opts), DTT_TEXTCOLOR | DTT_COMPOSITED | DTT_GLOWSIZE, RGB(0xFF, 0xFF, 0xFF), iTextStateID != MPI_DISABLED ? RGB(0xFF, 0xFF, 0xFF) : RGB(0xC0, 0xC0, 0xC0) };
|
|
//opts.dwFlags = ;
|
|
|
|
FillRect(pUDMI->um.hdc, &pUDMI->dis.rcItem, *pbrBackground);
|
|
pDrawThemeTextEx(g_menuTheme, pUDMI->um.hdc, MENU_BARITEM, MBI_NORMAL, menuString, mii.cch, dwFlags, &pUDMI->dis.rcItem, &opts);
|
|
|
|
return true;
|
|
}
|
|
case WM_UAHMEASUREMENUITEM:
|
|
{
|
|
UAHMEASUREMENUITEM* pMmi = (UAHMEASUREMENUITEM*)lParam;
|
|
|
|
// allow the default window procedure to handle the message
|
|
// since we don't really care about changing the width
|
|
*lr = DefWindowProc(hWnd, message, wParam, lParam);
|
|
|
|
// but we can modify it here to make it 1/3rd wider for example
|
|
//pMmi->mis.itemWidth = (pMmi->mis.itemWidth * 5) / 4;
|
|
|
|
return true;
|
|
}
|
|
case WM_THEMECHANGED:
|
|
{
|
|
if (g_menuTheme) {
|
|
CloseThemeData(g_menuTheme);
|
|
g_menuTheme = nullptr;
|
|
}
|
|
// continue processing in main wndproc
|
|
return false;
|
|
}
|
|
case WM_NCPAINT:
|
|
case WM_NCACTIVATE:
|
|
*lr = DefWindowProc(hWnd, message, wParam, lParam);
|
|
UAHDrawMenuNCBottomLine(hWnd);
|
|
return true;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|