diff --git a/src/Config/Config.cpp b/src/Config/Config.cpp index eee7da9e7..c4f5eb564 100644 --- a/src/Config/Config.cpp +++ b/src/Config/Config.cpp @@ -1316,6 +1316,9 @@ void LoadSettings() Settings2.DarkModeTxtColor = rgbDarkTxtColorRef; } + Globals.hbrDarkModeBkgHotBrush = CreateSolidBrush(Settings2.DarkModeBtnFaceColor); + Globals.hbrDarkModeBkgSelBrush = CreateSolidBrush(Settings2.DarkModeBtnFaceColor); + #endif // -------------------------------------------------------------------------- diff --git a/src/Dialogs.c b/src/Dialogs.c index ebe8d968c..56c3f0dd8 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -4233,7 +4233,6 @@ bool WarnIndentationDlg(HWND hwnd, EditFileIOStatus* fioStatus) // // RelAdjustRectForDPI() // -// void RelAdjustRectForDPI(LPRECT rc, const UINT oldDPI, const UINT newDPI) { float const scale = (float)newDPI / (float)(oldDPI != 0 ? oldDPI : 1); LONG const oldWidth = (rc->right - rc->left); @@ -4247,6 +4246,23 @@ void RelAdjustRectForDPI(LPRECT rc, const UINT oldDPI, const UINT newDPI) { } +//============================================================================= +// +// MapRectClientToWndCoords() +// +void MapRectClientToWndCoords(HWND hwnd, RECT* rc) +{ + // map to screen (left-top as point) + MapWindowPoints(hwnd, NULL, (POINT*)rc, 1); + + RECT scrc; + GetWindowRect(hwnd, &scrc); + + // map to window coords by substracting the window coord origin in screen coords. + OffsetRect(rc, -scrc.left, -scrc.top); +} + + //============================================================================= // // GetMonitorInfoFromRect() diff --git a/src/Dialogs.h b/src/Dialogs.h index c7f1d330c..21d57d9f6 100644 --- a/src/Dialogs.h +++ b/src/Dialogs.h @@ -61,12 +61,13 @@ bool SelectDefLineEndingDlg(HWND hwnd,LPARAM piOption); bool WarnLineEndingDlg(HWND hwnd, EditFileIOStatus* fioStatus); bool WarnIndentationDlg(HWND hwnd, EditFileIOStatus* fioStatus); -void RelAdjustRectForDPI(LPRECT rc, const UINT oldDPI, const UINT newDPI); -bool GetMonitorInfoFromRect(const LPRECT rc, MONITORINFO *hMonitorInfo); -void WinInfoToScreenCoord(WININFO* pWinInfo); -WININFO GetMyWindowPlacement(HWND hwnd, MONITORINFO *hMonitorInfo, const int offset); -bool GetWindowRectEx(HWND hwnd, LPRECT pRect); -void FitIntoMonitorGeometry(LPRECT pRect, WININFO *pWinInfo, SCREEN_MODE mode, bool bTopLeft); +void RelAdjustRectForDPI(LPRECT rc, const UINT oldDPI, const UINT newDPI); +void MapRectClientToWndCoords(HWND hwnd, LPRECT rc); +bool GetMonitorInfoFromRect(const LPRECT rc, MONITORINFO* hMonitorInfo); +void WinInfoToScreenCoord(WININFO* pWinInfo); +WININFO GetMyWindowPlacement(HWND hwnd, MONITORINFO* hMonitorInfo, const int offset); +bool GetWindowRectEx(HWND hwnd, LPRECT pRect); +void FitIntoMonitorGeometry(LPRECT pRect, WININFO* pWinInfo, SCREEN_MODE mode, bool bTopLeft); WINDOWPLACEMENT WindowPlacementFromInfo(HWND hwnd, const WININFO* pWinInfo, SCREEN_MODE mode); void DialogNewWindow(HWND hwnd, bool bSaveOnRunTools, LPCWSTR lpcwFilePath, WININFO* wi); diff --git a/src/Notepad3.c b/src/Notepad3.c index e0bca3967..99863f8fa 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -26,7 +26,7 @@ #include #include #include -//#include +#include #include "Edit.h" #include "Styles.h" @@ -1876,6 +1876,14 @@ LRESULT CALLBACK MainWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) Globals.bIsCJKInputCodePage = IsDBCSCodePage(Scintilla_InputCodePage()); break; + case WM_UAHINITMENU: + case WM_UAHDRAWMENU: + case WM_UAHDRAWMENUITEM: + case WM_UAHDESTROYWINDOW: + case WM_UAHMEASUREMENUITEM: + case WM_UAHNCPAINTMENUPOPUP: + return MsgUahMenuBar(hwnd, umsg, wParam, lParam); + default: if (umsg == s_msgTaskbarCreated) { if (!IsWindowVisible(hwnd)) { @@ -2235,6 +2243,8 @@ static void _InitEditWndFrame() s_bIsAppThemed = IsAppThemed(); + InitWindowCommon(s_hwndEditFrame, true); + if (s_bIsAppThemed) { SetWindowLongPtr(Globals.hwndEdit, GWL_EXSTYLE, GetWindowLongPtr(Globals.hwndEdit, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE); @@ -6892,6 +6902,160 @@ LRESULT MsgSysCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) } +//============================================================================= +// +// MsgUahMenuBar() - Handles WM_UAH... commands +// https://github.com/adzm/win32-custom-menubar-aero-theme +// https://stackoverflow.com/questions/57177310/how-to-paint-over-white-line-between-menu-bar-and-client-area-of-window +// + +#if 0 +inline static RECT GetNonclientMenuBorderRect(HWND hwnd) +{ + RECT rc; + GetClientRect(hwnd, &rc); + MapRectClientToWndCoords(hwnd, &rc); + rc.top = rc.bottom + 1; + rc.bottom += 2; + return rc; +} +#endif + + +LRESULT MsgUahMenuBar(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) +{ + static HTHEME s_darkMenuTheme = NULL; + + switch (umsg) { + + case WM_UAHINITMENU: { + if (!s_darkMenuTheme) { + s_darkMenuTheme = OpenThemeData(hwnd, L"Menu"); + } + } break; + + case WM_UAHDESTROYWINDOW: { + if (s_darkMenuTheme) { + CloseThemeData(s_darkMenuTheme); + s_darkMenuTheme = NULL; + } + } break; + + case WM_UAHDRAWMENU: { + + if (!UseDarkMode()) { + break; + } + + UAHMENU* const 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); + // fill line below bar + //~rc.bottom += 2; + FillRect(pUDM->hdc, &rc, Globals.hbrDarkModeBkgBrush); + + return TRUE; + } + + + case WM_UAHDRAWMENUITEM: { + + if (!UseDarkMode()) { + break; + } + + UAHDRAWMENUITEM* pUDMI = (UAHDRAWMENUITEM*)lParam; + + HBRUSH* pbrBackground = &Globals.hbrDarkModeBkgBrush; + + // 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 = &Globals.hbrDarkModeBkgHotBrush; + } + 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 = &Globals.hbrDarkModeBkgSelBrush; + } + 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; + } + } + + DTTOPTS opts = { sizeof(opts), DTT_TEXTCOLOR, iTextStateID != MPI_DISABLED ? Settings2.DarkModeTxtColor : RGB(0x80, 0x80, 0x80) }; + + FillRect(pUDMI->um.hdc, &pUDMI->dis.rcItem, *pbrBackground); + DrawThemeTextEx(s_darkMenuTheme, pUDMI->um.hdc, MENU_BARITEM, MBI_NORMAL, menuString, mii.cch, dwFlags, &pUDMI->dis.rcItem, &opts); + + return TRUE; + + } break; + + case WM_UAHMEASUREMENUITEM: { + + // allow the default window procedure to handle the message + // since we don't really care about changing the width + //LRESULT const res = DefWindowProc(hwnd, umsg, wParam, lParam); + + // but we can modify it here to make it 1/3rd wider and higher for example + //UAHMEASUREMENUITEM* const pMmi = (UAHMEASUREMENUITEM*)lParam; + //pMmi->mis.itemWidth = (pMmi->mis.itemWidth * 4) / 3; + //pMmi->mis.itemHeight = (pMmi->mis.itemHeight * 4) / 3; + + //return res; + + } break; + + // don't care + case WM_UAHNCPAINTMENUPOPUP: + default: + break; + } + + return DefWindowProc(hwnd, umsg, wParam, lParam); +} + + //============================================================================= // // HandleDWellStartEnd() diff --git a/src/Notepad3.h b/src/Notepad3.h index 3e0b8ea6a..4a516ea25 100644 --- a/src/Notepad3.h +++ b/src/Notepad3.h @@ -184,8 +184,10 @@ LRESULT MsgFileChangeNotify(HWND hwnd, WPARAM wParam, LPARAM lParam); LRESULT MsgTrayMessage(HWND hwnd, WPARAM wParam, LPARAM lParam); //~LRESULT MsgKeyDown(HWND hwnd, WPARAM wParam, LPARAM lParam); LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam); - LRESULT MsgSysCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam); +LRESULT MsgUahMenuBar(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam); + +LRESULT MsgNonClientAreaPaint(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam); // ---------------------------------------------------------------------------- diff --git a/src/TypeDefs.h b/src/TypeDefs.h index 2cd86d589..af6337943 100644 --- a/src/TypeDefs.h +++ b/src/TypeDefs.h @@ -280,7 +280,10 @@ typedef struct _cmq #define rgbRedColorRef (RGB(255, 170, 170)) #define rgbGreenColorRef (RGB(170, 255, 170)) #define rgbBlueColorRef (RGB(170, 200, 255)) -#define rgbDarkBtnFcColorRef (RGB(0x33, 0x33, 0x33)) + +// GetSysColor(...) not working for DarkMode +//#define rgbDarkBtnFcColorRef (RGB(0x33, 0x33, 0x33)) +#define rgbDarkBtnFcColorRef (RGB(0x41, 0x41, 0x41)) #define rgbDarkTxtColorRef (RGB(0xDE, 0xDE, 0xDE)) #define rgbDarkBkgColorRef (RGB(0x14, 0x14, 0x14)) @@ -425,6 +428,8 @@ typedef struct _globals_t #ifdef D_NP3_WIN10_DARK_MODE HBRUSH hbrDarkModeBkgBrush; HBRUSH hbrDarkModeBtnFcBrush; + HBRUSH hbrDarkModeBkgHotBrush; + HBRUSH hbrDarkModeBkgSelBrush; #endif FR_STATES FindReplaceMatchFoundState; diff --git a/src/win/dlgs.h b/src/win/dlgs.h index e212d2d21..df5b350f4 100644 --- a/src/win/dlgs.h +++ b/src/win/dlgs.h @@ -256,8 +256,18 @@ Abstract: #define IDC_MANAGE_LINK 1592 #endif -#ifndef RC_INVOKED +// undocumented window proc messages regarding menu bar +// https://github.com/adzm/win32-custom-menubar-aero-theme +// +#define WM_UAHDESTROYWINDOW 0x0090 +#define WM_UAHDRAWMENU 0x0091 // lParam is UAHMENU +#define WM_UAHDRAWMENUITEM 0x0092 // lParam is UAHDRAWMENUITEM +#define WM_UAHINITMENU 0x0093 +#define WM_UAHMEASUREMENUITEM 0x0094 // lParam is UAHMEASUREMENUITEM +#define WM_UAHNCPAINTMENUPOPUP 0x0095 +//#define WM_UAHUPDATE 0x???? +#ifndef RC_INVOKED // // Typedef Declarations. // @@ -269,10 +279,60 @@ typedef struct tagCRGB BYTE bExtra; } CRGB; /* RGB Color */ +// describes the sizes of the menu bar or menu item +typedef union tagUAHMENUITEMMETRICS { + struct { + DWORD cx; + DWORD cy; + } rgsizeBar[2]; + struct { + DWORD cx; + DWORD cy; + } rgsizePopup[4]; +} UAHMENUITEMMETRICS; + +// not really used in our case but part of the other structures +typedef struct tagUAHMENUPOPUPMETRICS { + DWORD rgcx[4]; + DWORD fUpdateMaxWidths : 2; // from kernel symbols, padded to full dword +} UAHMENUPOPUPMETRICS; + +// hmenu is the main window menu; hdc is the context to draw in +typedef struct tagUAHMENU { + HMENU hmenu; + HDC hdc; + DWORD dwFlags; // no idea what these mean, in my testing it's either 0x00000a00 or sometimes 0x00000a10 +} UAHMENU; + +// menu items are always referred to by iPosition here +typedef struct tagUAHMENUITEM { + int iPosition; // 0-based position of menu item in menubar + UAHMENUITEMMETRICS umim; + UAHMENUPOPUPMETRICS umpm; +} UAHMENUITEM; + +// the DRAWITEMSTRUCT contains the states of the menu items, as well as +// the position index of the item in the menu, which is duplicated in +// the UAHMENUITEM's iPosition as well +typedef struct UAHDRAWMENUITEM { + DRAWITEMSTRUCT dis; // itemID looks uninitialized + UAHMENU um; + UAHMENUITEM umi; +} UAHDRAWMENUITEM; + +// the MEASUREITEMSTRUCT is intended to be filled with the size of the item +// height appears to be ignored, but width can be modified +typedef struct tagUAHMEASUREMENUITEM { + MEASUREITEMSTRUCT mis; + UAHMENU um; + UAHMENUITEM umi; +} UAHMEASUREMENUITEM; + #endif /* !RC_INVOKED */ #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */ #pragma endregion + #endif // _DLGSH_INCLUDED_