winamp/Src/Plugins/General/gen_ml/skinnedmenuwnd.cpp
2024-09-24 14:54:57 +02:00

1538 lines
No EOL
40 KiB
C++

#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);
}