aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp
diff options
context:
space:
mode:
authorJean-Francois Mauguit <jfmauguit@mac.com>2024-09-24 09:03:25 -0400
committerGitHub <noreply@github.com>2024-09-24 09:03:25 -0400
commitbab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp
parent4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff)
parent20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff)
downloadwinamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp')
-rw-r--r--Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp1538
1 files changed, 1538 insertions, 0 deletions
diff --git a/Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp b/Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp
new file mode 100644
index 00000000..f1591737
--- /dev/null
+++ b/Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp
@@ -0,0 +1,1538 @@
+#include "api__gen_ml.h"
+#include "main.h"
+#include "./skinnedmenuwnd.h"
+#include "./skinnedmenu.h"
+#include "./skinning.h"
+
+#include "./ml_imagelist.h"
+#include "./colors.h"
+#include "./resource.h"
+
+#include "../winamp/wa_dlg.h"
+
+
+#define MENU_BORDER_WIDTH 3
+
+static HMLIMGLST hmlilCheck = NULL;
+static INT imageCheckMark = -1;
+static INT imageRadioMark = -1;
+static INT imageExpandArrow = -1;
+
+// menu hit test codes
+#define MHF_NOWHERE 0xFFFFFFFF
+#define MHF_SCROLLUP 0xFFFFFFFD
+#define MHF_SCROLLDOWN 0xFFFFFFFC
+
+#define MN_SIZEWINDOW 0x01E2
+#define MN_SELECTITEM 0x01E5 // wParam - item position or MHF_XXX
+#define MN_LBUTTONDOWN 0x01ED // wParam - item position or MHF_XXX
+#define MN_LBUTTONUP 0x01EF // wParam - item position or MHF_XXX
+#define MN_LBUTTONDBLCLK 0x01F1 // ?
+
+// menu timer id
+#define MTID_OPENSUBMENU 0x0000FFFE
+#define MTID_SCROLLUP 0xFFFFFFFD
+#define MTID_SCROLLDOWN 0xFFFFFFFC
+
+
+#define MTID_EX_UNBLOCKDRAW 0x0001980
+
+extern HMLIMGFLTRMNGR hmlifMngr; // default gen_ml fitler manager
+
+#define SMIF_BLOCKDRAW 0x00000001
+#define SMIF_REMOVEREFLECTOR 0x00000002
+
+static HBRUSH SkinnedMenuWnd_GetBackBrush(HMENU hMenu)
+{
+ MENUINFO mi = {0};
+ mi.cbSize = sizeof(MENUINFO);
+ mi.fMask = MIM_BACKGROUND;
+ if (NULL == hMenu || !GetMenuInfo(hMenu, &mi))
+ mi.hbrBack = NULL;
+ return (NULL != mi.hbrBack) ? mi.hbrBack : GetSysColorBrush(COLOR_MENU);
+}
+
+static INT SkinnedMenuWnd_AddPngResource(HMLIMGLST imageList, INT resourceId)
+{
+ MLIMAGESOURCE_I src;
+ ZeroMemory(&src, sizeof(MLIMAGESOURCE_I));
+ src.type = SRC_TYPE_PNG_I;
+ src.hInst = plugin.hDllInstance;
+ src.lpszName = MAKEINTRESOURCEW(resourceId);
+ return MLImageListI_Add(hmlilCheck, &src, MLIF_FILTER1_UID, 0);
+}
+
+static HBITMAP SkinnedMenuWnd_LoadPngResource(INT resourceId, COLORREF rgbBk, COLORREF rgbFg)
+{
+ MLIMAGESOURCE_I imageSource;
+ ZeroMemory(&imageSource, sizeof(MLIMAGESOURCE_I));
+ imageSource.type = SRC_TYPE_PNG_I;
+ imageSource.hInst = plugin.hDllInstance;
+ imageSource.lpszName = MAKEINTRESOURCEW(resourceId);
+ HBITMAP hbmp = MLImageLoaderI_LoadDib(&imageSource);
+ if (NULL != hbmp)
+ MLImageFilterI_Apply(hmlifMngr, &MLIF_FILTER1_UID, hbmp, rgbBk, rgbFg, NULL);
+ return hbmp;
+}
+
+SkinnedMenuWnd::SkinnedMenuWnd(UINT menuExStyle, HMLIMGLST hmlil, INT forcedWidth, MENUCUSTOMIZEPROC _customProc, ULONG_PTR customParam) :
+ SkinnedWnd(FALSE)
+{
+ if (FAILED(SkinnedMenuThreadInfo::GetInstance(TRUE, &threadInfo)))
+ threadInfo = NULL;
+
+ hMenu = NULL;
+ hOwner = NULL;
+ this->menuExStyle = menuExStyle;
+ this->hmlil = hmlil;
+ this->lineWidth = forcedWidth;
+ bRestoreShadow = FALSE;
+ hBoldFont = NULL;
+
+ menuFlags = 0;
+
+ backBrush = NULL;
+ borderPen = NULL;
+
+ menuOrigBrush = NULL;
+ skinnedItems = NULL;
+ skinnedItemCount = 0;
+ skinnedItemCursor = 0;
+ prevSelectedItem = 0;
+
+ shortcutCX = 0;
+ textCX = 0;
+
+ scrollBitmap = NULL;
+ disabledScrollBitmap = NULL;
+
+ this->customProc = _customProc;
+ this->customParam = customParam;
+}
+
+SkinnedMenuWnd::~SkinnedMenuWnd(void)
+{
+ SetOwnerWindow(NULL);
+
+ if (hMenu)
+ {
+ MENUINFO mi = {0};
+ mi.cbSize = sizeof(MENUINFO);
+ mi.fMask = MIM_BACKGROUND;
+ if (GetMenuInfo(hMenu, &mi))
+ {
+ mi.fMask = 0;
+ if (menuOrigBrush != mi.hbrBack)
+ {
+ mi.hbrBack = menuOrigBrush;
+ mi.fMask |= MIM_BACKGROUND;
+ }
+
+ if (0 != mi.fMask)
+ SetMenuInfo(hMenu, &mi);
+ }
+
+ if (NULL != skinnedItems && skinnedItemCount > 0)
+ {
+ MENUITEMINFOW mii = {0};
+ mii.cbSize = sizeof(MENUITEMINFOW);
+
+ for (INT i = 0; i < skinnedItemCount; i++)
+ {
+ SkinnedItemRecord *record = &skinnedItems[i];
+ if(FALSE == record->failed)
+ {
+ mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_BITMAP;
+ if (FALSE != GetMenuItemInfoW(hMenu, i, TRUE, &mii))
+ {
+ mii.fMask = 0;
+ if (FALSE != record->skinned)
+ {
+ mii.fMask |= (MIIM_FTYPE | MIIM_BITMAP);
+ mii.fType &= ~MFT_OWNERDRAW;
+ record->skinned = FALSE;
+ }
+
+ if (record->itemId != record->originalId &&
+ record->itemId == mii.wID)
+ {
+ mii.fMask |= MIIM_ID;
+ mii.wID = record->originalId;
+ }
+
+ if (NULL != threadInfo)
+ {
+ threadInfo->ReleaseId(record->itemId);
+ if (record->itemId != record->originalId)
+ threadInfo->ReleaseId(record->originalId);
+ }
+
+ if (0 != mii.fMask)
+ {
+ if (FALSE == SetMenuItemInfoW(hMenu, i, TRUE, &mii))
+ {
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (NULL != threadInfo)
+ threadInfo->UnregisterMenu(hMenu);
+ }
+
+ if (NULL != skinnedItems)
+ free(skinnedItems);
+
+ if (hwnd && bRestoreShadow)
+ {
+ SetClassLongPtrW(hwnd, GCL_STYLE, GetClassLongPtrW(hwnd, GCL_STYLE) | 0x00020000/*CS_DROPSHADOW*/);
+ }
+
+ if (NULL != hBoldFont)
+ DeleteObject(hBoldFont);
+
+ if (NULL != backBrush)
+ DeleteObject(backBrush);
+
+ if (NULL != borderPen)
+ DeleteObject(borderPen);
+
+ if (NULL != scrollBitmap)
+ DeleteObject(scrollBitmap);
+
+ if (NULL != disabledScrollBitmap)
+ DeleteObject(disabledScrollBitmap);
+
+ if (NULL != threadInfo)
+ {
+ threadInfo->RemoveValidationHook(this);
+ threadInfo->Release();
+ }
+}
+
+HMENU SkinnedMenuWnd::GetMenuHandle()
+{
+ return hMenu;
+}
+
+HWND SkinnedMenuWnd::GetOwnerWindow()
+{
+ return hOwner;
+}
+
+HWND SkinnedMenuWnd::SetOwnerWindow(HWND hwndOwner)
+{
+ if (hOwner == hwndOwner)
+ return hOwner;
+
+ HWND prevOwner = hOwner;
+
+ if (NULL != hOwner &&
+ 0 != (SMIF_REMOVEREFLECTOR & menuFlags))
+ {
+ RemoveReflector(hOwner);
+ }
+
+ menuFlags &= ~SMIF_REMOVEREFLECTOR;
+
+ hOwner = hwndOwner;
+
+ if (NULL != hOwner &&
+ S_OK == InstallReflector(hOwner))
+ {
+ menuFlags |= SMIF_REMOVEREFLECTOR;
+ }
+
+ return prevOwner;
+}
+
+BOOL SkinnedMenuWnd::AttachMenu(HMENU hMenuToAttach)
+{
+ MENUINFO mi = {0};
+ MENUITEMINFOW mii = {0};
+
+ if (NULL != hMenu ||
+ NULL == hMenuToAttach)
+ {
+ return FALSE;
+ }
+
+ hMenu = hMenuToAttach;
+
+ mi.cbSize = sizeof(MENUINFO);
+ mi.fMask = MIM_BACKGROUND;
+
+ if (GetMenuInfo(hMenu, &mi))
+ {
+ menuOrigBrush = mi.hbrBack;
+ mi.fMask = 0;
+
+ if (NULL == mi.hbrBack)
+ {
+ COLORREF rgb;
+
+ if (0 != (SMS_SYSCOLORS & menuExStyle) ||
+ FAILED(MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, MBS_NORMAL, &rgb)))
+ {
+ rgb = GetSysColor(COLOR_MENU);
+ }
+
+ backBrush = CreateSolidBrush(rgb);
+
+ mi.hbrBack = backBrush;
+ mi.fMask |= MIM_BACKGROUND;
+ }
+
+ if (0 != mi.fMask)
+ SetMenuInfo(hMenu, &mi);
+ }
+
+ if (NULL != threadInfo)
+ threadInfo->RegisterMenu(hMenu, hwnd);
+
+ mii.cbSize = sizeof(MENUITEMINFOW);
+
+ INT count = GetMenuItemCount(hMenu);
+
+ if (count > 0)
+ {
+ skinnedItems = (SkinnedItemRecord*)calloc(count, sizeof(SkinnedItemRecord));
+ if (NULL != skinnedItems)
+ {
+ skinnedItemCount = count;
+ }
+ }
+
+ if (NULL == skinnedItems)
+ return FALSE;
+
+ skinnedItemCursor = 0;
+
+ for (int i = 0; i < count; i++)
+ {
+ SkinnedItemRecord *record = &skinnedItems[i];
+ mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_BITMAP; // MIIM_BITMAP - keep it... this forces menu to call WM_MEASUREITEM
+ if (FALSE != GetMenuItemInfoW(hMenu, i, TRUE, &mii))
+ {
+ record->originalId = mii.wID;
+ record->itemId = record->originalId;
+
+ if (NULL != threadInfo)
+ threadInfo->ClaimId(record->originalId);
+
+ if (0 == (MFT_OWNERDRAW & mii.fType))
+ {
+ mii.fType |= MFT_OWNERDRAW;
+ mii.fMask &= ~MIIM_ID;
+
+ // copes with separators and popup menus (menu and menuex types)
+ if (0 == mii.wID || (UINT)-1 == mii.wID || 65535 == mii.wID)
+ {
+ if (NULL != threadInfo)
+ {
+ mii.wID = threadInfo->GetAvailableId();
+ if ((unsigned int)-1 != mii.wID)
+ {
+ record->itemId = mii.wID;
+ mii.fMask |= MIIM_ID;
+ }
+ else
+ mii.wID = record->itemId;
+ }
+ }
+
+ record->skinned = TRUE;
+ if (FALSE == SetMenuItemInfoW(hMenu, i, TRUE, &mii))
+ {
+ record->skinned = FALSE;
+ record->itemId = record->originalId;
+ }
+ else
+ {
+ if (record->itemId != record->originalId &&
+ NULL != threadInfo)
+ {
+ threadInfo->ClaimId(record->itemId);
+ }
+ }
+ }
+ }
+ else
+ {
+ record->failed = TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL SkinnedMenuWnd::Attach(HWND hwndMenu, HWND hwndOwner)
+{
+ menuFlags &= ~SMIF_BLOCKDRAW;
+
+ if(!__super::Attach(hwndMenu))
+ return FALSE;
+
+ SetOwnerWindow(hwndOwner);
+
+ DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
+ DWORD windowStyleEx = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
+ DWORD newStyle = windowStyle & ~(WS_BORDER | WS_THICKFRAME | WS_DLGFRAME);
+ if (newStyle != windowStyle)
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+ newStyle = windowStyleEx & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
+ if (newStyle != windowStyleEx)
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, newStyle);
+
+ if (0 == (SMS_SYSCOLORS & menuExStyle))
+ {
+ SetStyle(SWS_USESKINCOLORS, FALSE);
+ }
+
+ SetType(SKINNEDWND_TYPE_POPUPMENU);
+
+ if (!hmlilCheck)
+ hmlilCheck = MLImageListI_Create(16, 16, MLILC_COLOR24_I, 2, 1, 2, hmlifMngr);
+
+ if ((SMS_FORCEWIDTH & menuExStyle) && lineWidth > 0)
+ {
+ lineWidth -= ((GetSystemMetrics(SM_CXMENUCHECK) - 1) + WASABI_API_APP->getScaleX(MENU_BORDER_WIDTH*2));
+ if (lineWidth < 0) lineWidth = 0;
+ }
+ else lineWidth = 0;
+
+ lineHeight = GetLineHeight();
+ if (!hmlil || !MLImageListI_GetImageSize(hmlil, &imageWidth, &imageHeight)) { imageWidth = WASABI_API_APP->getScaleX(24); imageHeight = 0; }
+ if (hmlilCheck)
+ {
+ INT imageCX, imageCY;
+ if(MLImageListI_GetImageSize(hmlilCheck, &imageCX, &imageCY))
+ {
+ if (imageWidth < imageCX) imageWidth = imageCX;
+ if (imageWidth < WASABI_API_APP->getScaleX(25)) imageWidth = WASABI_API_APP->getScaleX(25); // clamp to a min width to better match the OS
+ if (imageHeight < imageCY) imageHeight = imageCY;
+ }
+ }
+ if (lineHeight < (imageHeight + WASABI_API_APP->getScaleY(4))) lineHeight = (imageHeight + WASABI_API_APP->getScaleY(4));
+
+ if ((SMS_DISABLESHADOW & menuExStyle))
+ {
+ UINT cs = GetClassLongPtrW(hwnd, GCL_STYLE);
+ if (0x00020000/*CS_DROPSHADOW*/ & cs)
+ {
+ bRestoreShadow = TRUE;
+ SetClassLongPtrW(hwnd, GCL_STYLE, cs & ~0x00020000/*CS_DROPSHADOW*/);
+ }
+ }
+ return TRUE;
+}
+
+HPEN SkinnedMenuWnd::GetBorderPen(void)
+{
+ if (NULL == borderPen)
+ {
+ COLORREF rgb;
+ if (0 != (SMS_SYSCOLORS & menuExStyle))
+ rgb = GetSysColor(COLOR_GRAYTEXT);
+ else
+ MLGetSkinColor(MLSO_MENU, MP_FRAME, 0, &rgb);
+ borderPen = CreatePen(PS_SOLID, 0, rgb);
+ }
+
+ return borderPen;
+}
+
+INT SkinnedMenuWnd::GetLineHeight()
+{
+ INT h = 0;
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
+ if (hdc)
+ {
+ HFONT hf = GetMenuFont(TRUE);
+ if (NULL != hf)
+ {
+ TEXTMETRICW tm = {0};
+ HFONT hfo = (HFONT)SelectObject(hdc, hf);
+ if (GetTextMetricsW(hdc, &tm)) h = tm.tmHeight + WASABI_API_APP->getScaleY(4);
+ SelectObject(hdc, hfo);
+ }
+ ReleaseDC(hwnd, hdc);
+ }
+ return h;
+}
+
+HFONT SkinnedMenuWnd::GetMenuFont(BOOL fBold)
+{
+ HFONT hFont = NULL;
+ if (SMS_USESKINFONT & menuExStyle)
+ {
+ hFont = (HFONT)MlStockObjects_Get(SKIN_FONT);
+ }
+
+ if (NULL == hFont)
+ hFont = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
+
+ if (FALSE != fBold)
+ {
+ if (NULL == hBoldFont)
+ {
+ LOGFONTW lf = {0};
+ if (sizeof(LOGFONTW) == GetObjectW(hFont, sizeof(LOGFONTW), &lf))
+ {
+ if (lf.lfWeight < FW_BOLD)
+ lf.lfWeight = FW_BOLD;
+ hBoldFont = CreateFontIndirectW(&lf);
+ }
+ }
+
+ if (NULL != hBoldFont)
+ {
+ hFont = hBoldFont;
+ }
+ }
+
+ return hFont;
+}
+
+INT SkinnedMenuWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS *pncsp)
+{
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ DWORD windowStyleEx = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+ DWORD newStyle = windowStyle & ~(WS_BORDER | WS_THICKFRAME | WS_DLGFRAME);
+ if (newStyle != windowStyle)
+ SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
+
+ newStyle = windowStyleEx & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
+ if (newStyle != windowStyleEx)
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, newStyle);
+
+ LRESULT result = CallPrevWndProc(WM_NCCALCSIZE, (WPARAM)bCalcValidRects, (LPARAM)pncsp);
+
+ InflateRect(&pncsp->rgrc[0], WASABI_API_APP->getScaleX(-MENU_BORDER_WIDTH), WASABI_API_APP->getScaleY(-MENU_BORDER_WIDTH));
+ if (bCalcValidRects)
+ {
+ InflateRect(&pncsp->rgrc[1], WASABI_API_APP->getScaleX(-MENU_BORDER_WIDTH), WASABI_API_APP->getScaleY(-MENU_BORDER_WIDTH));
+ InflateRect(&pncsp->rgrc[2], WASABI_API_APP->getScaleX(-MENU_BORDER_WIDTH), WASABI_API_APP->getScaleY(-MENU_BORDER_WIDTH));
+ }
+
+ return (INT)result;
+}
+
+void SkinnedMenuWnd::PaintScrollButton(HDC hdc, const RECT *prc, UINT scrollButton, BOOL buttonState)
+{
+ COLORREF rgbBk, rgbFg;
+
+ MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, MBS_NORMAL, &rgbBk);
+ MLGetSkinColor(MLSO_MENU, MP_TEXT, MTS_NORMAL, &rgbFg);
+
+ HBITMAP hbmp;
+
+ if (0 == (MENU_BUTTON_STATE_DISABLED & buttonState))
+ {
+ if (NULL == scrollBitmap)
+ scrollBitmap = SkinnedMenuWnd_LoadPngResource(IDB_MENU_SCROLLARROW, rgbBk, rgbFg);
+ hbmp = scrollBitmap;
+ }
+ else
+ {
+ if (NULL == disabledScrollBitmap)
+ disabledScrollBitmap = SkinnedMenuWnd_LoadPngResource(IDB_MENU_SCROLLARROW_DISABLED, rgbBk, rgbFg);
+ hbmp = disabledScrollBitmap;
+ }
+
+ BOOL imageFailed = TRUE;
+ if (NULL != hbmp)
+ {
+ DIBSECTION bitmapInfo;
+ if (!GetObjectW(hbmp, sizeof(bitmapInfo), &bitmapInfo))
+ ZeroMemory(&bitmapInfo, sizeof(bitmapInfo));
+
+ INT h = abs(bitmapInfo.dsBm.bmHeight);
+ INT w = bitmapInfo.dsBm.bmWidth;
+ if (h > 0 && w > 0)
+ {
+ INT x, y, nWidth, nHeight;
+ x = prc->left + ((prc->right - prc->left) - w) / 2;
+ y = prc->top + ((prc->bottom - prc->top) - h) / 2;
+ if (MENU_BUTTON_SCROLLDOWN == scrollButton)
+ {
+ nWidth = -w;
+ nHeight = h;
+ x += w;
+ }
+ else
+ {
+ nWidth = w;
+ nHeight = -h;
+ y += h;
+ }
+
+ SetBkColor(hdc, rgbBk);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
+ StretchDIBits(hdc, x, y, nWidth, nHeight, 0, 0, w, h, bitmapInfo.dsBm.bmBits,
+ (BITMAPINFO*)&bitmapInfo.dsBmih, DIB_RGB_COLORS, SRCCOPY);
+ imageFailed = FALSE;
+ }
+ }
+
+ if (imageFailed)
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
+}
+
+BOOL SkinnedMenuWnd::DrawScrollButton(HDC hdc, UINT scrollButton)
+{
+ RECT rc, rcWindow, rcPaint;
+
+ if (0 == scrollButton ||
+ 0 == GetWindowRect(hwnd, &rcWindow) ||
+ 0 == GetClientRect(hwnd, &rc))
+ {
+ return FALSE;
+ }
+
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
+
+ HDC hdcOwned = NULL;
+ if (NULL == hdc)
+ {
+ hdcOwned = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_WINDOW | DCX_CLIPSIBLINGS);
+ hdc = hdcOwned;
+
+ if (NULL == hdcOwned)
+ return FALSE;
+ }
+
+ rcPaint.left = rc.left - rcWindow.left;
+ rcPaint.right = rc.right - rcWindow.left;
+
+ BOOL scrollEnabled;
+
+ POINT ptTest;
+ ptTest.x = rc.left + (rc.right - rc.left) / 2;
+
+ if (0 != (MENU_BUTTON_SCROLLUP & scrollButton))
+ {
+ rcPaint.top = MENU_BORDER_WIDTH;
+ rcPaint.bottom = rc.top - rcWindow.top;
+
+ if (rcPaint.bottom > rcPaint.top && rcPaint.right > rcPaint.left)
+ {
+ ptTest.y = rc.top;
+ scrollEnabled = (MenuItemFromPoint(hwnd, hMenu, ptTest) > 0);
+ PaintScrollButton(hdc, &rcPaint, MENU_BUTTON_SCROLLUP, (scrollEnabled) ? 0 : MENU_BUTTON_STATE_DISABLED);
+ }
+ }
+
+ if (0 != (MENU_BUTTON_SCROLLDOWN & scrollButton))
+ {
+ rcPaint.top = rc.bottom - rcWindow.top;
+ rcPaint.bottom = (rcWindow.bottom - rcWindow.top) - MENU_BORDER_WIDTH;
+
+ if (rcPaint.bottom > rcPaint.top && rcPaint.right > rcPaint.left)
+ {
+ ptTest.y = rc.bottom - WASABI_API_APP->getScaleY(1);
+ INT last = MenuItemFromPoint(hwnd, hMenu, ptTest);
+ scrollEnabled = FALSE;
+ if (last >= 0)
+ {
+ INT count = GetMenuItemCount(hMenu);
+ if (last != (count - 1))
+ scrollEnabled = TRUE;
+ }
+ PaintScrollButton(hdc, &rcPaint, MENU_BUTTON_SCROLLDOWN, (scrollEnabled) ? 0 : MENU_BUTTON_STATE_DISABLED);
+ }
+ }
+ if (NULL != hdcOwned)
+ ReleaseDC(hwnd, hdcOwned);
+
+ return TRUE;
+}
+
+void SkinnedMenuWnd::DrawBorder(HDC hdc)
+{
+ RECT rc, rcWindow, rp;
+ GetClientRect(hwnd, &rc);
+ GetWindowRect(hwnd, &rcWindow);
+
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
+
+ OffsetRect(&rc, -rcWindow.left, -rcWindow.top);
+ OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
+
+ SkinnedWnd::DrawBorder(hdc, &rcWindow, BORDER_FLAT, GetBorderPen());
+
+ HBRUSH brushBk = SkinnedMenuWnd_GetBackBrush(hMenu);
+
+ SetRect(&rp, rcWindow.left + 1, rcWindow.top + 1, rc.left, rcWindow.bottom - 1);
+ FillRect(hdc, &rp, brushBk);
+ SetRect(&rp, rc.left, rcWindow.top + 1, rc.right, rc.top);
+ FillRect(hdc, &rp, brushBk);
+ SetRect(&rp, rc.right, rcWindow.top + 1, rcWindow.right - 1, rcWindow.bottom - 1);
+ FillRect(hdc, &rp, brushBk);
+ SetRect(&rp, rc.left, rc.bottom, rc.right, rcWindow.bottom - 1);
+ FillRect(hdc, &rp, brushBk);
+
+ if ((rc.top - rcWindow.top) > MENU_BORDER_WIDTH || (rcWindow.bottom - rc.bottom) > MENU_BORDER_WIDTH)
+ DrawScrollButton(hdc, MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN);
+}
+
+BOOL SkinnedMenuWnd::IsSkinnedItem(UINT itemId)
+{
+ if (NULL == skinnedItems)
+ return TRUE;
+
+ if (skinnedItemCursor >= skinnedItemCount)
+ skinnedItemCursor = 0;
+
+ INT start = skinnedItemCursor;
+
+ while(itemId != skinnedItems[skinnedItemCursor].itemId)
+ {
+ skinnedItemCursor++;
+ if (skinnedItemCursor == skinnedItemCount)
+ skinnedItemCursor = 0;
+ if (skinnedItemCursor == start)
+ {
+ skinnedItemCursor = 0;
+ return FALSE;
+ }
+ }
+
+ return skinnedItems[skinnedItemCursor].skinned;
+}
+
+static void SkinnedMenuWnd_DrawFrame(HDC hdc, const RECT *prc, INT width, COLORREF rgbFrame)
+{
+ if (width > 0)
+ {
+ COLORREF rgbOld = SetBkColor(hdc, rgbFrame);
+
+ RECT rcPart;
+ SetRect(&rcPart, prc->left, prc->top, prc->right, prc->top + width);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
+ SetRect(&rcPart, prc->left, prc->bottom - width, prc->right, prc->bottom);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
+ SetRect(&rcPart, prc->left, prc->top + width, prc->left + width, prc->bottom - width);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
+ SetRect(&rcPart, prc->right - width, prc->top + width, prc->right, prc->bottom - width);
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
+
+ if (rgbOld != rgbFrame)
+ SetBkColor(hdc, rgbOld);
+ }
+}
+
+BOOL SkinnedMenuWnd::OnReflectedDrawItem(DRAWITEMSTRUCT *pdis)
+{
+ if (0 != (SMIF_BLOCKDRAW & menuFlags))
+ {
+ ExcludeClipRect(pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, pdis->rcItem.right, pdis->rcItem.bottom);
+ }
+
+ if (!IsSkinnedItem(pdis->itemID))
+ return FALSE;
+
+ MENUITEMINFOW mii = {0};
+ wchar_t szText[256] = {0};
+ INT imageCX, imageCY, realIndex;
+ LONG imageTop;
+
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_STATE | MIIM_SUBMENU;
+ mii.cch = ARRAYSIZE(szText);
+ mii.dwTypeData = szText;
+
+ if (!GetMenuItemInfoW((HMENU)pdis->hwndItem, pdis->itemID, FALSE, &mii))
+ mii.cch = 0;
+
+ COLORREF rgbText, rgbTextBk, rgbTextFrame;
+ if (0 != (SMS_SYSCOLORS & menuExStyle))
+ {
+ INT foreIndex = (0 != (MFS_GRAYED & mii.fState)) ? COLOR_GRAYTEXT : COLOR_MENUTEXT;
+ INT backIndex = (0 != (ODS_SELECTED & pdis->itemState)) ? COLOR_HIGHLIGHT : COLOR_MENU;
+
+ rgbText = GetSysColor(foreIndex);
+ rgbTextBk = GetSysColor(backIndex);
+ rgbTextFrame = rgbTextBk;
+ }
+ else
+ {
+ MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, (0 != (ODS_SELECTED & pdis->itemState)) ? MBS_SELECTED : MBS_NORMAL, &rgbTextBk);
+ MLGetSkinColor(MLSO_MENU, MP_TEXT, (0 != (MFS_GRAYED & mii.fState)) ? MTS_DISABLED : ((0 != (ODS_SELECTED & pdis->itemState)) ? MBS_SELECTED : MBS_NORMAL), &rgbText);
+ rgbTextFrame = rgbTextBk;
+ if (0 != (ODS_SELECTED & pdis->itemState))
+ {
+ MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, MBS_SELECTEDFRAME, &rgbTextFrame);
+ }
+ }
+
+ COLORREF origText = SetTextColor(pdis->hDC, rgbText);
+ COLORREF origTextBk = SetBkColor(pdis->hDC, rgbTextBk);
+
+ if (0 != (MFT_MENUBARBREAK & mii.fType))
+ {
+ RECT rect;
+ if (FALSE != GetClientRect(hwnd, &rect))
+ {
+ COLORREF lineColor, prevColor;
+ HBRUSH brush = SkinnedMenuWnd_GetBackBrush(hMenu);
+ if(NULL == brush)
+ brush = GetSysColorBrush(COLOR_WINDOW);
+
+ rect.right = pdis->rcItem.left - WASABI_API_APP->getScaleX(1);
+ rect.left = pdis->rcItem.left - WASABI_API_APP->getScaleX(2);
+ FillRect(pdis->hDC, &rect, brush);
+
+ if (0 != (SMS_SYSCOLORS & menuExStyle) ||
+ FAILED(MLGetSkinColor(MLSO_MENU, MP_SEPARATOR, 0, &lineColor)))
+ {
+ lineColor = GetSysColor(COLOR_3DSHADOW);
+ }
+
+ prevColor = SetBkColor(pdis->hDC, lineColor);
+ OffsetRect(&rect, -1, 0);
+ ExtTextOut(pdis->hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
+ SetBkColor(pdis->hDC, prevColor);
+ }
+ }
+
+ if (NULL != customProc)
+ {
+ INT customResult = customProc(MLMENU_ACTION_DRAWITEM, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam);
+ if (MLMENU_WANT_DRAWPART != customResult && FALSE != customResult)
+ return TRUE;
+ }
+
+ INT type = ((MFT_STRING | MFT_SEPARATOR) & mii.fType);
+ switch(type)
+ {
+ case MFT_STRING:
+ if (NULL == customProc ||
+ FALSE == customProc(MLMENU_ACTION_DRAWBACK, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam))
+ {
+ ExtTextOutW(pdis->hDC, 0, 0, ETO_OPAQUE, &pdis->rcItem, NULL, 0, NULL);
+ if (rgbTextFrame != rgbTextBk)
+ {
+ SkinnedMenuWnd_DrawFrame(pdis->hDC, &pdis->rcItem, 1, rgbTextFrame);
+ }
+ }
+
+ if (NULL == customProc ||
+ FALSE == customProc(MLMENU_ACTION_DRAWICON, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam))
+ {
+ if (hmlil)
+ {
+ if (MLImageListI_GetImageSize(hmlil, &imageCX, &imageCY))
+ {
+ imageTop = pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top - imageCY) / 2;
+ if (imageTop < pdis->rcItem.top) imageTop = pdis->rcItem.top;
+
+ INT index = MLImageListI_GetIndexFromTag(hmlil, pdis->itemID);
+ if (-1 != index)
+ {
+ HIMAGELIST himl = MLImageListI_GetRealList(hmlil);
+ realIndex = MLImageListI_GetRealIndex(hmlil, index, rgbTextBk, rgbText);
+ if (-1 != realIndex)
+ {
+ ImageList_Draw(himl, realIndex, pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(1) + (imageWidth - imageCX) / 2, imageTop, ILD_NORMAL);
+ }
+ }
+ }
+ }
+ else if ((MFS_CHECKED & mii.fState) && hmlilCheck)
+ {
+ if (0 != (MFT_RADIOCHECK & mii.fType))
+ {
+ if (-1 == imageRadioMark)
+ imageRadioMark = SkinnedMenuWnd_AddPngResource(hmlilCheck, IDB_MENU_RADIOMARK);
+ }
+ else
+ {
+ if (-1 == imageCheckMark)
+ imageCheckMark = SkinnedMenuWnd_AddPngResource(hmlilCheck, IDB_MENU_CHECKMARK);
+ }
+
+ if (MLImageListI_GetImageSize(hmlilCheck, &imageCX, &imageCY))
+ {
+ imageTop = pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top - imageCY) / 2;
+ if (imageTop < pdis->rcItem.top) imageTop = pdis->rcItem.top;
+ HIMAGELIST himl = MLImageListI_GetRealList(hmlilCheck);
+ realIndex = MLImageListI_GetRealIndex(hmlilCheck, (MFT_RADIOCHECK & mii.fType) ? imageRadioMark : imageCheckMark, rgbTextBk, rgbText);
+ if (-1 != realIndex)
+ {
+ ImageList_Draw(himl, realIndex, pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(1) + (imageWidth - imageCX) / 2, imageTop, ILD_NORMAL);
+ }
+ }
+ }
+ }
+
+ if (NULL != mii.hSubMenu && hmlilCheck)
+ {
+ if (-1 == imageExpandArrow)
+ imageExpandArrow = SkinnedMenuWnd_AddPngResource(hmlilCheck, IDB_MENU_EXPANDARROW);
+
+ if (MLImageListI_GetImageSize(hmlilCheck, &imageCX, &imageCY))
+ {
+ imageTop = pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top - imageCY) / 2;
+ if (imageTop < pdis->rcItem.top) imageTop = pdis->rcItem.top;
+ HIMAGELIST himl = MLImageListI_GetRealList(hmlilCheck);
+ realIndex = MLImageListI_GetRealIndex(hmlilCheck, imageExpandArrow, rgbTextBk, rgbText);
+ if (-1 != realIndex)
+ ImageList_Draw(himl, realIndex, pdis->hDC, pdis->rcItem.right - imageCX - WASABI_API_APP->getScaleX(1), imageTop, ILD_NORMAL);
+ }
+ }
+
+ if (NULL == customProc ||
+ FALSE == customProc(MLMENU_ACTION_DRAWTEXT, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam))
+ {
+ if (mii.cch)
+ {
+ RECT rt;
+ CopyRect(&rt, &pdis->rcItem);
+ if (imageWidth && imageHeight) rt.left += imageWidth + WASABI_API_APP->getScaleX(6);
+ rt.right -= imageWidth;
+
+ HFONT hFont = GetMenuFont(FALSE);
+ HFONT originalFont = (NULL != hFont) ? (HFONT)SelectObject(pdis->hDC, hFont) : NULL;
+ INT originalBkMode = SetBkMode(pdis->hDC, TRANSPARENT);
+
+ UINT len = mii.cch;
+ if (len > 0)
+ {
+ while(--len > 0 && L'\t' != mii.dwTypeData[len]);
+ if (0 == len)
+ len = mii.cch;
+ }
+
+ BOOL showPrefix = FALSE;
+ if (!SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &showPrefix, 0))
+ showPrefix = FALSE;
+
+ if (!showPrefix && 0 == (ODS_NOACCEL & pdis->itemState))
+ showPrefix = TRUE;
+
+ UINT drawtextFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP;
+ if (!showPrefix)
+ drawtextFlags |= 0x000100000; /*DT_HIDEPREFIX*/
+
+ if (0 != (MFS_DEFAULT & mii.fState))
+ {
+ SetTextColor(pdis->hDC, BlendColors(rgbText, rgbTextBk, 110));
+ OffsetRect(&rt, 1,0);
+ DrawTextW(pdis->hDC, mii.dwTypeData, len, &rt, drawtextFlags);
+ OffsetRect(&rt, -1,0);
+ SetTextColor(pdis->hDC, rgbText);
+ }
+
+ DrawTextW(pdis->hDC, mii.dwTypeData, len, &rt, drawtextFlags);
+
+ if (mii.cch > (len + 1))
+ {
+ len++;
+ rt.left = rt.right - shortcutCX;
+ SetTextColor(pdis->hDC, BlendColors(rgbText, rgbTextBk, 192));
+ DrawTextW(pdis->hDC, mii.dwTypeData + len, mii.cch - len, &rt, DT_LEFT | DT_VCENTER | 0x000100000/*DT_HIDEPREFIX*/ | DT_SINGLELINE | DT_NOCLIP);
+ }
+
+ SelectObject(pdis->hDC, originalFont);
+
+ if (TRANSPARENT != originalBkMode)
+ SetBkMode(pdis->hDC, originalBkMode);
+ }
+ }
+
+ ExcludeClipRect(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(23),
+ pdis->rcItem.top, pdis->rcItem.right, pdis->rcItem.bottom);
+ break;
+
+ case MFT_SEPARATOR:
+ {
+ COLORREF rgbSeparator;
+ HPEN hPen, originalPen;
+ INT y = (pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top) / 2);
+
+ if (0 != (SMS_SYSCOLORS & menuExStyle) ||
+ FAILED(MLGetSkinColor(MLSO_MENU, MP_SEPARATOR, 0, &rgbSeparator)))
+ {
+ rgbSeparator = GetSysColor(COLOR_3DSHADOW/*COLOR_GRAYTEXT*/);
+ }
+
+ hPen = CreatePen(PS_SOLID, 0, rgbSeparator);
+ originalPen = (HPEN)SelectObject(pdis->hDC, hPen);
+
+ ExtTextOutW(pdis->hDC, 0, 0, ETO_OPAQUE, &pdis->rcItem, NULL, 0, NULL);
+ MoveToEx(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(23), y, NULL);
+ LineTo(pdis->hDC, pdis->rcItem.right, y);
+
+ SelectObject(pdis->hDC, originalPen);
+ DeleteObject(hPen);
+
+ // draws a edge on the separator so it looks more like the OS when trying to 'fake it'
+ if (0 != (SMS_SYSCOLORS & menuExStyle))
+ {
+ RECT bottomRect = pdis->rcItem;
+ HBRUSH brush = GetSysColorBrush(COLOR_3DHIGHLIGHT);
+
+ y += WASABI_API_APP->getScaleY(1);
+ bottomRect.top = y;
+ bottomRect.bottom = y + WASABI_API_APP->getScaleY(1);
+ FillRect(pdis->hDC,&bottomRect, brush);
+ }
+ }
+ ExcludeClipRect(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(23),
+ pdis->rcItem.top, pdis->rcItem.right, pdis->rcItem.bottom);
+ break;
+ }
+
+ {
+ COLORREF rgbSeparator;
+ if (0 != (SMS_SYSCOLORS & menuExStyle) ||
+ FAILED(MLGetSkinColor(MLSO_MENU, MP_SEPARATOR, 0, &rgbSeparator)))
+ {
+ rgbSeparator = GetSysColor(COLOR_3DSHADOW/*COLOR_GRAYTEXT*/);
+ }
+
+ HPEN hPen = CreatePen(PS_SOLID, 0, rgbSeparator);
+ HPEN originalPen = (HPEN)SelectObject(pdis->hDC, hPen);
+
+ MoveToEx(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(22), pdis->rcItem.top, NULL);
+ LineTo(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(22), pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top));
+
+ SelectObject(pdis->hDC, originalPen);
+ DeleteObject(hPen);
+ }
+
+ if (origText != rgbText)
+ SetTextColor(pdis->hDC, origText);
+ if (origTextBk != rgbTextBk)
+ SetBkColor(pdis->hDC, origTextBk);
+
+ return TRUE;
+}
+
+BOOL SkinnedMenuWnd::OnReflectedMeasureItem(MEASUREITEMSTRUCT *pmis)
+{
+ pmis->itemHeight = lineHeight;
+ pmis->itemWidth = lineWidth;
+
+ if (!IsSkinnedItem(pmis->itemID))
+ return FALSE;
+
+ HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
+ if (NULL == hdc) return FALSE;
+
+ MENUITEMINFOW mii = {0};
+ wchar_t szText[128] = {0};
+
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_STATE;
+ mii.cch = ARRAYSIZE(szText);
+ mii.dwTypeData = szText;
+
+ if (!GetMenuItemInfoW(hMenu, pmis->itemID, FALSE, &mii))
+ mii.cch = 0;
+
+ HFONT originalFont = (HFONT)SelectObject(hdc, GetMenuFont(0 != (MFS_DEFAULT & mii.fState)));
+
+ if (NULL == customProc ||
+ FALSE == customProc(MLMENU_ACTION_MEASUREITEM, hMenu, hdc, (LPARAM)pmis, customParam))
+ {
+ if (0 == lineWidth || 0 == lineHeight)
+ {
+ INT type = ((MFT_STRING | MFT_SEPARATOR) & mii.fType);
+ switch(type)
+ {
+ case MFT_STRING:
+ if (mii.cch != 0)
+ {
+ SIZE sz;
+ UINT len = mii.cch;
+ while(--len > 0 && L'\t' != mii.dwTypeData[len]);
+ if (0 == len) len = mii.cch;
+
+ if (len != mii.cch)
+ {
+ szText[len] = L' ';
+ if (GetTextExtentPoint32W(hdc, szText + len, mii.cch - len, &sz) &&
+ shortcutCX < sz.cx)
+ {
+ shortcutCX = sz.cx;
+ }
+ }
+
+ if (GetTextExtentPoint32W(hdc, szText, len, &sz))
+ {
+ if (textCX <= sz.cx)
+ textCX = sz.cx;
+
+ if (lineHeight < sz.cy)
+ pmis->itemHeight = sz.cy + WASABI_API_APP->getScaleY(2);
+
+ if (0 == lineWidth)
+ pmis->itemWidth = textCX + shortcutCX + 8;
+ }
+ }
+ if(imageHeight > (INT)(pmis->itemHeight + WASABI_API_APP->getScaleY(2))) pmis->itemHeight = imageHeight + WASABI_API_APP->getScaleY(2);
+ if (0 == lineWidth && imageWidth) pmis->itemWidth += imageWidth;
+ pmis->itemWidth -= (GetSystemMetrics(SM_CXMENUCHECK) - imageWidth - WASABI_API_APP->getScaleX(36));
+ break;
+ case MFT_SEPARATOR:
+ pmis->itemHeight = WASABI_API_APP->getScaleY(7);
+ break;
+ }
+ }
+ }
+
+ SelectObject(hdc, originalFont);
+ ReleaseDC(hwnd, hdc);
+ return TRUE;
+}
+
+void SkinnedMenuWnd::OnNcPaint(HRGN rgnUpdate)
+{
+ if (0 != (SMIF_BLOCKDRAW & menuFlags))
+ return;
+
+ UINT flags = DCX_PARENTCLIP | DCX_WINDOW | DCX_CLIPSIBLINGS |
+ DCX_INTERSECTUPDATE | DCX_VALIDATE;
+
+ HDC hdc = GetDCEx(hwnd, ((HRGN)NULLREGION != rgnUpdate) ? rgnUpdate : NULL, flags);
+ if (NULL == hdc)
+ return;
+
+ DrawBorder(hdc);
+ ReleaseDC(hwnd, hdc);
+}
+
+LRESULT SkinnedMenuWnd::OnEraseBackground(HDC hdc)
+{
+ HBRUSH brush;
+
+ brush = SkinnedMenuWnd_GetBackBrush(hMenu);
+ if (NULL != brush)
+ {
+ RECT rect;
+ if (FALSE != GetClientRect(hwnd, &rect) &&
+ FALSE != FillRect(hdc, &rect, brush))
+ {
+ return 1;
+ }
+ }
+
+ return __super::WindowProc(WM_ERASEBKGND, (WPARAM)hdc, 0L);
+}
+
+void SkinnedMenuWnd::OnPrint(HDC hdc, UINT options)
+{
+ if (0 != (PRF_CHECKVISIBLE & options))
+ {
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ if (0 == (WS_VISIBLE & windowStyle))
+ {
+ return;
+ }
+ }
+
+ if (0 != (PRF_NONCLIENT & options))
+ {
+ DrawBorder(hdc);
+ }
+
+ if (0 == ((PRF_ERASEBKGND | PRF_CLIENT) & options))
+ {
+ return;
+ }
+
+ POINT ptOrig;
+ RECT rc, rcWindow;
+
+ if (GetClientRect(hwnd, &rc) &&
+ GetWindowRect(hwnd, &rcWindow))
+ {
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
+ }
+ else
+ {
+ SetRectEmpty(&rc);
+ SetRectEmpty(&rcWindow);
+ }
+
+ INT clipRegionCode;
+ HRGN clipRegion = CreateRectRgn(0, 0, 0, 0);
+ clipRegionCode = (NULL != clipRegion) ? GetClipRgn(hdc, clipRegion) : -1;
+
+ OffsetViewportOrgEx(hdc, rc.left - rcWindow.left, rc.top - rcWindow.top, &ptOrig);
+ if (-1 != clipRegionCode)
+ {
+ IntersectClipRect(hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top);
+ }
+ OffsetRect(&rc, -rc.left, -rc.top);
+
+ if (0 != (PRF_ERASEBKGND & options))
+ {
+ MENUINFO mi = {0};
+ mi.cbSize = sizeof(MENUINFO);
+ mi.fMask = MIM_BACKGROUND;
+ HBRUSH brushBk = NULL;
+ if (GetMenuInfo(hMenu, &mi) && mi.hbrBack)
+ brushBk = mi.hbrBack;
+
+ if (NULL == brushBk)
+ brushBk = GetSysColorBrush(COLOR_WINDOW);
+
+ FillRect(hdc, &rc, brushBk);
+ }
+
+ if (0 != (PRF_CLIENT & options))
+ {
+ menuFlags &= ~SMIF_BLOCKDRAW;
+ SendMessage(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, (LPARAM)(~(PRF_NONCLIENT | PRF_ERASEBKGND) & options));
+ menuFlags |= SMIF_BLOCKDRAW;
+ }
+
+ if (-1 != clipRegionCode)
+ {
+ SelectClipRgn(hdc, (0 != clipRegionCode) ? clipRegion : NULL);
+ }
+ if (NULL != clipRegion)
+ DeleteObject(clipRegion);
+
+ SetViewportOrgEx(hdc, ptOrig.x, ptOrig.y, NULL);
+ SetTimer(hwnd, MTID_EX_UNBLOCKDRAW, 250, NULL);
+}
+
+LRESULT SkinnedMenuWnd::OnMenuSelect(UINT selectedItem)
+{
+ if (((UINT)-1) != selectedItem)
+ menuFlags &= ~SMIF_BLOCKDRAW;
+
+ UINT updateScroll = 0;
+
+ if (MHF_SCROLLUP == prevSelectedItem)
+ updateScroll |= MENU_BUTTON_SCROLLUP;
+ else if (MHF_SCROLLDOWN == prevSelectedItem)
+ updateScroll |= MENU_BUTTON_SCROLLDOWN;
+
+ switch(selectedItem)
+ {
+ case MHF_SCROLLUP:
+ updateScroll |= MENU_BUTTON_SCROLLUP;
+ break;
+ case MHF_SCROLLDOWN:
+ updateScroll |= MENU_BUTTON_SCROLLDOWN;
+ break;
+ }
+
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
+ rc.top += WASABI_API_APP->getScaleY(1);
+ INT item = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
+
+ LRESULT result;
+ BOOL fInvalidate = FALSE;
+
+ if (0 != updateScroll)
+ {
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ result = __super::WindowProc(MN_SELECTITEM, selectedItem, 0L);
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
+ if (MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc)) != item)
+ {
+ updateScroll = MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN;
+ fInvalidate = TRUE;
+ }
+ }
+ else
+ {
+ result = __super::WindowProc(MN_SELECTITEM, selectedItem, 0L);
+ }
+
+ prevSelectedItem = selectedItem;
+
+ if (0 != updateScroll)
+ {
+ DrawScrollButton(NULL, updateScroll);
+ if (FALSE != fInvalidate)
+ {
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ }
+
+ return result;
+}
+
+LRESULT SkinnedMenuWnd::CallHookedWindowProc(UINT uItem, BOOL fByPosition, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ MENUITEMINFOW mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_SUBMENU;
+
+ if (FALSE != GetMenuItemInfoW(hMenu, uItem, fByPosition, &mii) &&
+ NULL != mii.hSubMenu)
+ {
+ SkinnedMenu sm;
+ sm.InitializeHook(NULL, (menuExStyle & ~SMS_FORCEWIDTH), hmlil, 0, customProc, customParam);
+ return __super::WindowProc(uMsg, wParam, lParam);
+ }
+
+ return __super::WindowProc(uMsg, wParam, lParam);
+}
+
+INT SkinnedMenuWnd::FindHiliteItem(HMENU hMenu)
+{
+ MENUITEMINFOW mii = {0};
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_STATE;
+
+ INT count = GetMenuItemCount(hMenu);
+ for (INT i = 0; i < count; i++)
+ {
+ if (0 != GetMenuItemInfoW(hMenu, i, TRUE, &mii))
+ {
+ if (MFS_HILITE == ((MFS_HILITE | MFS_DISABLED | MFS_GRAYED) & mii.fState))
+ return i;
+ }
+ }
+ return -1;
+}
+
+LRESULT SkinnedMenuWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_ERASEBKGND:
+ return OnEraseBackground((HDC)wParam);
+
+ case REFLECTED_DRAWITEM:
+ if (OnReflectedDrawItem((DRAWITEMSTRUCT*)((REFLECTPARAM*)lParam)->lParam))
+ {
+ ((REFLECTPARAM*)lParam)->result = TRUE;
+ return TRUE;
+ }
+ break;
+
+ case REFLECTED_MEASUREITEM:
+ if (OnReflectedMeasureItem((MEASUREITEMSTRUCT*)((REFLECTPARAM*)lParam)->lParam))
+ {
+ ((REFLECTPARAM*)lParam)->result = TRUE;
+ return TRUE;
+ }
+ break;
+
+ case MN_SIZEWINDOW:
+ {
+ BOOL validateOwner = FALSE;
+
+ if (NULL == hMenu)
+ {
+ textCX = 0;
+ shortcutCX = 0;
+ HMENU menuToAttach = (HMENU)SendMessageW(hwnd, MN_GETHMENU, 0, 0L);
+
+ if (FALSE != AttachMenu(menuToAttach))
+ validateOwner = TRUE;
+ }
+
+ if (NULL != threadInfo)
+ {
+ threadInfo->SetActiveMeasureMenu(hMenu);
+ if (FALSE != validateOwner &&
+ FALSE == threadInfo->SetValidationHook(this))
+ {
+ validateOwner = FALSE;
+ }
+ }
+
+ LRESULT result = __super::WindowProc(uMsg, wParam, lParam);
+
+ if (NULL != threadInfo)
+ {
+ threadInfo->SetActiveMeasureMenu(NULL);
+ if (FALSE != validateOwner)
+ threadInfo->RemoveValidationHook(this);
+ }
+ return result;
+ }
+ break;
+
+ case MN_SELECTITEM:
+ return OnMenuSelect((UINT)wParam);
+
+ case MN_LBUTTONDBLCLK:
+ case MN_LBUTTONDOWN:
+ case MN_LBUTTONUP:
+ menuFlags &= ~SMIF_BLOCKDRAW;
+ switch(wParam)
+ {
+ case MHF_SCROLLUP:
+ case MHF_SCROLLDOWN:
+ {
+ LRESULT result = __super::WindowProc(uMsg, wParam, lParam);
+ DrawScrollButton(NULL, MENU_BUTTON_SCROLLDOWN | MENU_BUTTON_SCROLLUP);
+ return result;
+ }
+ break;
+ default:
+ if (wParam >= 0)
+ {
+ return CallHookedWindowProc((UINT)wParam, TRUE, uMsg, wParam, lParam);
+ }
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch(wParam)
+ {
+ case MTID_OPENSUBMENU:
+ {
+ POINT pt;
+ INT iItem;
+ if (GetCursorPos(&pt) &&
+ -1 != (iItem = MenuItemFromPoint(NULL, hMenu, pt)))
+ {
+ CallHookedWindowProc(iItem, TRUE, uMsg, wParam, lParam);
+ return 0;
+ }
+ }
+ break;
+ case MHF_SCROLLUP:
+ case MHF_SCROLLDOWN:
+ __super::WindowProc(uMsg, wParam, lParam);
+ DrawScrollButton(NULL, MENU_BUTTON_SCROLLDOWN | MENU_BUTTON_SCROLLUP);
+ return 0;
+ case MTID_EX_UNBLOCKDRAW:
+ KillTimer(hwnd, wParam);
+ menuFlags &= ~SMIF_BLOCKDRAW;
+ return 0;
+ }
+ break;
+
+ case WM_KEYDOWN:
+ menuFlags &= ~SMIF_BLOCKDRAW;
+ switch(wParam)
+ {
+ case VK_RETURN:
+ case VK_RIGHT:
+ {
+ INT iItem = FindHiliteItem(hMenu);
+ if (-1 != iItem)
+ return CallHookedWindowProc(iItem, TRUE, uMsg, wParam, lParam);
+ }
+ break;
+
+ case VK_UP:
+ {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
+ rc.top += 1;
+
+ INT iItem = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
+ if (iItem >= 0)
+ {
+ MENUITEMINFOW mii = {0};
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_STATE;
+
+ if (GetMenuItemInfoW(hMenu, iItem, TRUE, &mii) &&
+ 0 != (MFS_HILITE & mii.fState))
+ {
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ if (0 != (WS_VISIBLE & windowStyle))
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ __super::WindowProc(uMsg, wParam, lParam);
+
+ if (0 != (WS_VISIBLE & windowStyle))
+ {
+ windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ if (0 == (WS_VISIBLE & windowStyle))
+ {
+ windowStyle |= WS_VISIBLE;
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
+ }
+
+ INT iNew = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
+ if (iNew != iItem)
+ {
+ DrawScrollButton(NULL, MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN);
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ else
+ {
+ int iHilite = GetMenuItemCount(hMenu);
+ while(0 < iHilite--)
+ {
+ if (FALSE != GetMenuItemInfoW(hMenu, iHilite, TRUE, &mii) &&
+ 0 != (MFS_HILITE & mii.fState))
+ {
+ break;
+ }
+ }
+
+ if (FALSE != GetMenuItemRect(hwnd, hMenu, iItem, &rc))
+ {
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rc, 2);
+ InvalidateRect(hwnd, &rc, FALSE);
+ }
+
+ if (iHilite != iItem &&
+ FALSE != GetMenuItemRect(hwnd, hMenu, iHilite, &rc))
+ {
+ MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rc, 2);
+ InvalidateRect(hwnd, &rc, FALSE);
+ }
+ }
+ }
+ return 0;
+ }
+ }
+ }
+ break;
+ case VK_DOWN:
+ {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
+ rc.top = rc.bottom - 1;
+ INT item = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
+ if (item >= 0)
+ {
+ MENUITEMINFOW mii = {0};
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_STATE;
+
+ if (GetMenuItemInfoW(hMenu, item, TRUE, &mii) &&
+ MFS_HILITE == ((MFS_HILITE | MFS_DISABLED | MFS_GRAYED) & mii.fState))
+ {
+ DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
+
+ __super::WindowProc(uMsg, wParam, lParam);
+
+ SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
+ INT iNew = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
+ if (iNew != item)
+ {
+ DrawScrollButton(NULL, MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN);
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ return 0;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return __super::WindowProc(uMsg, wParam, lParam);
+} \ No newline at end of file