skinnedmenuwnd.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538
  1. #include "api__gen_ml.h"
  2. #include "main.h"
  3. #include "./skinnedmenuwnd.h"
  4. #include "./skinnedmenu.h"
  5. #include "./skinning.h"
  6. #include "./ml_imagelist.h"
  7. #include "./colors.h"
  8. #include "./resource.h"
  9. #include "../winamp/wa_dlg.h"
  10. #define MENU_BORDER_WIDTH 3
  11. static HMLIMGLST hmlilCheck = NULL;
  12. static INT imageCheckMark = -1;
  13. static INT imageRadioMark = -1;
  14. static INT imageExpandArrow = -1;
  15. // menu hit test codes
  16. #define MHF_NOWHERE 0xFFFFFFFF
  17. #define MHF_SCROLLUP 0xFFFFFFFD
  18. #define MHF_SCROLLDOWN 0xFFFFFFFC
  19. #define MN_SIZEWINDOW 0x01E2
  20. #define MN_SELECTITEM 0x01E5 // wParam - item position or MHF_XXX
  21. #define MN_LBUTTONDOWN 0x01ED // wParam - item position or MHF_XXX
  22. #define MN_LBUTTONUP 0x01EF // wParam - item position or MHF_XXX
  23. #define MN_LBUTTONDBLCLK 0x01F1 // ?
  24. // menu timer id
  25. #define MTID_OPENSUBMENU 0x0000FFFE
  26. #define MTID_SCROLLUP 0xFFFFFFFD
  27. #define MTID_SCROLLDOWN 0xFFFFFFFC
  28. #define MTID_EX_UNBLOCKDRAW 0x0001980
  29. extern HMLIMGFLTRMNGR hmlifMngr; // default gen_ml fitler manager
  30. #define SMIF_BLOCKDRAW 0x00000001
  31. #define SMIF_REMOVEREFLECTOR 0x00000002
  32. static HBRUSH SkinnedMenuWnd_GetBackBrush(HMENU hMenu)
  33. {
  34. MENUINFO mi = {0};
  35. mi.cbSize = sizeof(MENUINFO);
  36. mi.fMask = MIM_BACKGROUND;
  37. if (NULL == hMenu || !GetMenuInfo(hMenu, &mi))
  38. mi.hbrBack = NULL;
  39. return (NULL != mi.hbrBack) ? mi.hbrBack : GetSysColorBrush(COLOR_MENU);
  40. }
  41. static INT SkinnedMenuWnd_AddPngResource(HMLIMGLST imageList, INT resourceId)
  42. {
  43. MLIMAGESOURCE_I src;
  44. ZeroMemory(&src, sizeof(MLIMAGESOURCE_I));
  45. src.type = SRC_TYPE_PNG_I;
  46. src.hInst = plugin.hDllInstance;
  47. src.lpszName = MAKEINTRESOURCEW(resourceId);
  48. return MLImageListI_Add(hmlilCheck, &src, MLIF_FILTER1_UID, 0);
  49. }
  50. static HBITMAP SkinnedMenuWnd_LoadPngResource(INT resourceId, COLORREF rgbBk, COLORREF rgbFg)
  51. {
  52. MLIMAGESOURCE_I imageSource;
  53. ZeroMemory(&imageSource, sizeof(MLIMAGESOURCE_I));
  54. imageSource.type = SRC_TYPE_PNG_I;
  55. imageSource.hInst = plugin.hDllInstance;
  56. imageSource.lpszName = MAKEINTRESOURCEW(resourceId);
  57. HBITMAP hbmp = MLImageLoaderI_LoadDib(&imageSource);
  58. if (NULL != hbmp)
  59. MLImageFilterI_Apply(hmlifMngr, &MLIF_FILTER1_UID, hbmp, rgbBk, rgbFg, NULL);
  60. return hbmp;
  61. }
  62. SkinnedMenuWnd::SkinnedMenuWnd(UINT menuExStyle, HMLIMGLST hmlil, INT forcedWidth, MENUCUSTOMIZEPROC _customProc, ULONG_PTR customParam) :
  63. SkinnedWnd(FALSE)
  64. {
  65. if (FAILED(SkinnedMenuThreadInfo::GetInstance(TRUE, &threadInfo)))
  66. threadInfo = NULL;
  67. hMenu = NULL;
  68. hOwner = NULL;
  69. this->menuExStyle = menuExStyle;
  70. this->hmlil = hmlil;
  71. this->lineWidth = forcedWidth;
  72. bRestoreShadow = FALSE;
  73. hBoldFont = NULL;
  74. menuFlags = 0;
  75. backBrush = NULL;
  76. borderPen = NULL;
  77. menuOrigBrush = NULL;
  78. skinnedItems = NULL;
  79. skinnedItemCount = 0;
  80. skinnedItemCursor = 0;
  81. prevSelectedItem = 0;
  82. shortcutCX = 0;
  83. textCX = 0;
  84. scrollBitmap = NULL;
  85. disabledScrollBitmap = NULL;
  86. this->customProc = _customProc;
  87. this->customParam = customParam;
  88. }
  89. SkinnedMenuWnd::~SkinnedMenuWnd(void)
  90. {
  91. SetOwnerWindow(NULL);
  92. if (hMenu)
  93. {
  94. MENUINFO mi = {0};
  95. mi.cbSize = sizeof(MENUINFO);
  96. mi.fMask = MIM_BACKGROUND;
  97. if (GetMenuInfo(hMenu, &mi))
  98. {
  99. mi.fMask = 0;
  100. if (menuOrigBrush != mi.hbrBack)
  101. {
  102. mi.hbrBack = menuOrigBrush;
  103. mi.fMask |= MIM_BACKGROUND;
  104. }
  105. if (0 != mi.fMask)
  106. SetMenuInfo(hMenu, &mi);
  107. }
  108. if (NULL != skinnedItems && skinnedItemCount > 0)
  109. {
  110. MENUITEMINFOW mii = {0};
  111. mii.cbSize = sizeof(MENUITEMINFOW);
  112. for (INT i = 0; i < skinnedItemCount; i++)
  113. {
  114. SkinnedItemRecord *record = &skinnedItems[i];
  115. if(FALSE == record->failed)
  116. {
  117. mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_BITMAP;
  118. if (FALSE != GetMenuItemInfoW(hMenu, i, TRUE, &mii))
  119. {
  120. mii.fMask = 0;
  121. if (FALSE != record->skinned)
  122. {
  123. mii.fMask |= (MIIM_FTYPE | MIIM_BITMAP);
  124. mii.fType &= ~MFT_OWNERDRAW;
  125. record->skinned = FALSE;
  126. }
  127. if (record->itemId != record->originalId &&
  128. record->itemId == mii.wID)
  129. {
  130. mii.fMask |= MIIM_ID;
  131. mii.wID = record->originalId;
  132. }
  133. if (NULL != threadInfo)
  134. {
  135. threadInfo->ReleaseId(record->itemId);
  136. if (record->itemId != record->originalId)
  137. threadInfo->ReleaseId(record->originalId);
  138. }
  139. if (0 != mii.fMask)
  140. {
  141. if (FALSE == SetMenuItemInfoW(hMenu, i, TRUE, &mii))
  142. {
  143. }
  144. }
  145. }
  146. }
  147. }
  148. }
  149. if (NULL != threadInfo)
  150. threadInfo->UnregisterMenu(hMenu);
  151. }
  152. if (NULL != skinnedItems)
  153. free(skinnedItems);
  154. if (hwnd && bRestoreShadow)
  155. {
  156. SetClassLongPtrW(hwnd, GCL_STYLE, GetClassLongPtrW(hwnd, GCL_STYLE) | 0x00020000/*CS_DROPSHADOW*/);
  157. }
  158. if (NULL != hBoldFont)
  159. DeleteObject(hBoldFont);
  160. if (NULL != backBrush)
  161. DeleteObject(backBrush);
  162. if (NULL != borderPen)
  163. DeleteObject(borderPen);
  164. if (NULL != scrollBitmap)
  165. DeleteObject(scrollBitmap);
  166. if (NULL != disabledScrollBitmap)
  167. DeleteObject(disabledScrollBitmap);
  168. if (NULL != threadInfo)
  169. {
  170. threadInfo->RemoveValidationHook(this);
  171. threadInfo->Release();
  172. }
  173. }
  174. HMENU SkinnedMenuWnd::GetMenuHandle()
  175. {
  176. return hMenu;
  177. }
  178. HWND SkinnedMenuWnd::GetOwnerWindow()
  179. {
  180. return hOwner;
  181. }
  182. HWND SkinnedMenuWnd::SetOwnerWindow(HWND hwndOwner)
  183. {
  184. if (hOwner == hwndOwner)
  185. return hOwner;
  186. HWND prevOwner = hOwner;
  187. if (NULL != hOwner &&
  188. 0 != (SMIF_REMOVEREFLECTOR & menuFlags))
  189. {
  190. RemoveReflector(hOwner);
  191. }
  192. menuFlags &= ~SMIF_REMOVEREFLECTOR;
  193. hOwner = hwndOwner;
  194. if (NULL != hOwner &&
  195. S_OK == InstallReflector(hOwner))
  196. {
  197. menuFlags |= SMIF_REMOVEREFLECTOR;
  198. }
  199. return prevOwner;
  200. }
  201. BOOL SkinnedMenuWnd::AttachMenu(HMENU hMenuToAttach)
  202. {
  203. MENUINFO mi = {0};
  204. MENUITEMINFOW mii = {0};
  205. if (NULL != hMenu ||
  206. NULL == hMenuToAttach)
  207. {
  208. return FALSE;
  209. }
  210. hMenu = hMenuToAttach;
  211. mi.cbSize = sizeof(MENUINFO);
  212. mi.fMask = MIM_BACKGROUND;
  213. if (GetMenuInfo(hMenu, &mi))
  214. {
  215. menuOrigBrush = mi.hbrBack;
  216. mi.fMask = 0;
  217. if (NULL == mi.hbrBack)
  218. {
  219. COLORREF rgb;
  220. if (0 != (SMS_SYSCOLORS & menuExStyle) ||
  221. FAILED(MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, MBS_NORMAL, &rgb)))
  222. {
  223. rgb = GetSysColor(COLOR_MENU);
  224. }
  225. backBrush = CreateSolidBrush(rgb);
  226. mi.hbrBack = backBrush;
  227. mi.fMask |= MIM_BACKGROUND;
  228. }
  229. if (0 != mi.fMask)
  230. SetMenuInfo(hMenu, &mi);
  231. }
  232. if (NULL != threadInfo)
  233. threadInfo->RegisterMenu(hMenu, hwnd);
  234. mii.cbSize = sizeof(MENUITEMINFOW);
  235. INT count = GetMenuItemCount(hMenu);
  236. if (count > 0)
  237. {
  238. skinnedItems = (SkinnedItemRecord*)calloc(count, sizeof(SkinnedItemRecord));
  239. if (NULL != skinnedItems)
  240. {
  241. skinnedItemCount = count;
  242. }
  243. }
  244. if (NULL == skinnedItems)
  245. return FALSE;
  246. skinnedItemCursor = 0;
  247. for (int i = 0; i < count; i++)
  248. {
  249. SkinnedItemRecord *record = &skinnedItems[i];
  250. mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_BITMAP; // MIIM_BITMAP - keep it... this forces menu to call WM_MEASUREITEM
  251. if (FALSE != GetMenuItemInfoW(hMenu, i, TRUE, &mii))
  252. {
  253. record->originalId = mii.wID;
  254. record->itemId = record->originalId;
  255. if (NULL != threadInfo)
  256. threadInfo->ClaimId(record->originalId);
  257. if (0 == (MFT_OWNERDRAW & mii.fType))
  258. {
  259. mii.fType |= MFT_OWNERDRAW;
  260. mii.fMask &= ~MIIM_ID;
  261. // copes with separators and popup menus (menu and menuex types)
  262. if (0 == mii.wID || (UINT)-1 == mii.wID || 65535 == mii.wID)
  263. {
  264. if (NULL != threadInfo)
  265. {
  266. mii.wID = threadInfo->GetAvailableId();
  267. if ((unsigned int)-1 != mii.wID)
  268. {
  269. record->itemId = mii.wID;
  270. mii.fMask |= MIIM_ID;
  271. }
  272. else
  273. mii.wID = record->itemId;
  274. }
  275. }
  276. record->skinned = TRUE;
  277. if (FALSE == SetMenuItemInfoW(hMenu, i, TRUE, &mii))
  278. {
  279. record->skinned = FALSE;
  280. record->itemId = record->originalId;
  281. }
  282. else
  283. {
  284. if (record->itemId != record->originalId &&
  285. NULL != threadInfo)
  286. {
  287. threadInfo->ClaimId(record->itemId);
  288. }
  289. }
  290. }
  291. }
  292. else
  293. {
  294. record->failed = TRUE;
  295. }
  296. }
  297. return TRUE;
  298. }
  299. BOOL SkinnedMenuWnd::Attach(HWND hwndMenu, HWND hwndOwner)
  300. {
  301. menuFlags &= ~SMIF_BLOCKDRAW;
  302. if(!__super::Attach(hwndMenu))
  303. return FALSE;
  304. SetOwnerWindow(hwndOwner);
  305. DWORD windowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
  306. DWORD windowStyleEx = GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
  307. DWORD newStyle = windowStyle & ~(WS_BORDER | WS_THICKFRAME | WS_DLGFRAME);
  308. if (newStyle != windowStyle)
  309. SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
  310. newStyle = windowStyleEx & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
  311. if (newStyle != windowStyleEx)
  312. SetWindowLongPtr(hwnd, GWL_EXSTYLE, newStyle);
  313. if (0 == (SMS_SYSCOLORS & menuExStyle))
  314. {
  315. SetStyle(SWS_USESKINCOLORS, FALSE);
  316. }
  317. SetType(SKINNEDWND_TYPE_POPUPMENU);
  318. if (!hmlilCheck)
  319. hmlilCheck = MLImageListI_Create(16, 16, MLILC_COLOR24_I, 2, 1, 2, hmlifMngr);
  320. if ((SMS_FORCEWIDTH & menuExStyle) && lineWidth > 0)
  321. {
  322. lineWidth -= ((GetSystemMetrics(SM_CXMENUCHECK) - 1) + WASABI_API_APP->getScaleX(MENU_BORDER_WIDTH*2));
  323. if (lineWidth < 0) lineWidth = 0;
  324. }
  325. else lineWidth = 0;
  326. lineHeight = GetLineHeight();
  327. if (!hmlil || !MLImageListI_GetImageSize(hmlil, &imageWidth, &imageHeight)) { imageWidth = WASABI_API_APP->getScaleX(24); imageHeight = 0; }
  328. if (hmlilCheck)
  329. {
  330. INT imageCX, imageCY;
  331. if(MLImageListI_GetImageSize(hmlilCheck, &imageCX, &imageCY))
  332. {
  333. if (imageWidth < imageCX) imageWidth = imageCX;
  334. if (imageWidth < WASABI_API_APP->getScaleX(25)) imageWidth = WASABI_API_APP->getScaleX(25); // clamp to a min width to better match the OS
  335. if (imageHeight < imageCY) imageHeight = imageCY;
  336. }
  337. }
  338. if (lineHeight < (imageHeight + WASABI_API_APP->getScaleY(4))) lineHeight = (imageHeight + WASABI_API_APP->getScaleY(4));
  339. if ((SMS_DISABLESHADOW & menuExStyle))
  340. {
  341. UINT cs = GetClassLongPtrW(hwnd, GCL_STYLE);
  342. if (0x00020000/*CS_DROPSHADOW*/ & cs)
  343. {
  344. bRestoreShadow = TRUE;
  345. SetClassLongPtrW(hwnd, GCL_STYLE, cs & ~0x00020000/*CS_DROPSHADOW*/);
  346. }
  347. }
  348. return TRUE;
  349. }
  350. HPEN SkinnedMenuWnd::GetBorderPen(void)
  351. {
  352. if (NULL == borderPen)
  353. {
  354. COLORREF rgb;
  355. if (0 != (SMS_SYSCOLORS & menuExStyle))
  356. rgb = GetSysColor(COLOR_GRAYTEXT);
  357. else
  358. MLGetSkinColor(MLSO_MENU, MP_FRAME, 0, &rgb);
  359. borderPen = CreatePen(PS_SOLID, 0, rgb);
  360. }
  361. return borderPen;
  362. }
  363. INT SkinnedMenuWnd::GetLineHeight()
  364. {
  365. INT h = 0;
  366. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
  367. if (hdc)
  368. {
  369. HFONT hf = GetMenuFont(TRUE);
  370. if (NULL != hf)
  371. {
  372. TEXTMETRICW tm = {0};
  373. HFONT hfo = (HFONT)SelectObject(hdc, hf);
  374. if (GetTextMetricsW(hdc, &tm)) h = tm.tmHeight + WASABI_API_APP->getScaleY(4);
  375. SelectObject(hdc, hfo);
  376. }
  377. ReleaseDC(hwnd, hdc);
  378. }
  379. return h;
  380. }
  381. HFONT SkinnedMenuWnd::GetMenuFont(BOOL fBold)
  382. {
  383. HFONT hFont = NULL;
  384. if (SMS_USESKINFONT & menuExStyle)
  385. {
  386. hFont = (HFONT)MlStockObjects_Get(SKIN_FONT);
  387. }
  388. if (NULL == hFont)
  389. hFont = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
  390. if (FALSE != fBold)
  391. {
  392. if (NULL == hBoldFont)
  393. {
  394. LOGFONTW lf = {0};
  395. if (sizeof(LOGFONTW) == GetObjectW(hFont, sizeof(LOGFONTW), &lf))
  396. {
  397. if (lf.lfWeight < FW_BOLD)
  398. lf.lfWeight = FW_BOLD;
  399. hBoldFont = CreateFontIndirectW(&lf);
  400. }
  401. }
  402. if (NULL != hBoldFont)
  403. {
  404. hFont = hBoldFont;
  405. }
  406. }
  407. return hFont;
  408. }
  409. INT SkinnedMenuWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS *pncsp)
  410. {
  411. DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  412. DWORD windowStyleEx = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
  413. DWORD newStyle = windowStyle & ~(WS_BORDER | WS_THICKFRAME | WS_DLGFRAME);
  414. if (newStyle != windowStyle)
  415. SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
  416. newStyle = windowStyleEx & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
  417. if (newStyle != windowStyleEx)
  418. SetWindowLongPtr(hwnd, GWL_EXSTYLE, newStyle);
  419. LRESULT result = CallPrevWndProc(WM_NCCALCSIZE, (WPARAM)bCalcValidRects, (LPARAM)pncsp);
  420. InflateRect(&pncsp->rgrc[0], WASABI_API_APP->getScaleX(-MENU_BORDER_WIDTH), WASABI_API_APP->getScaleY(-MENU_BORDER_WIDTH));
  421. if (bCalcValidRects)
  422. {
  423. InflateRect(&pncsp->rgrc[1], WASABI_API_APP->getScaleX(-MENU_BORDER_WIDTH), WASABI_API_APP->getScaleY(-MENU_BORDER_WIDTH));
  424. InflateRect(&pncsp->rgrc[2], WASABI_API_APP->getScaleX(-MENU_BORDER_WIDTH), WASABI_API_APP->getScaleY(-MENU_BORDER_WIDTH));
  425. }
  426. return (INT)result;
  427. }
  428. void SkinnedMenuWnd::PaintScrollButton(HDC hdc, const RECT *prc, UINT scrollButton, BOOL buttonState)
  429. {
  430. COLORREF rgbBk, rgbFg;
  431. MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, MBS_NORMAL, &rgbBk);
  432. MLGetSkinColor(MLSO_MENU, MP_TEXT, MTS_NORMAL, &rgbFg);
  433. HBITMAP hbmp;
  434. if (0 == (MENU_BUTTON_STATE_DISABLED & buttonState))
  435. {
  436. if (NULL == scrollBitmap)
  437. scrollBitmap = SkinnedMenuWnd_LoadPngResource(IDB_MENU_SCROLLARROW, rgbBk, rgbFg);
  438. hbmp = scrollBitmap;
  439. }
  440. else
  441. {
  442. if (NULL == disabledScrollBitmap)
  443. disabledScrollBitmap = SkinnedMenuWnd_LoadPngResource(IDB_MENU_SCROLLARROW_DISABLED, rgbBk, rgbFg);
  444. hbmp = disabledScrollBitmap;
  445. }
  446. BOOL imageFailed = TRUE;
  447. if (NULL != hbmp)
  448. {
  449. DIBSECTION bitmapInfo;
  450. if (!GetObjectW(hbmp, sizeof(bitmapInfo), &bitmapInfo))
  451. ZeroMemory(&bitmapInfo, sizeof(bitmapInfo));
  452. INT h = abs(bitmapInfo.dsBm.bmHeight);
  453. INT w = bitmapInfo.dsBm.bmWidth;
  454. if (h > 0 && w > 0)
  455. {
  456. INT x, y, nWidth, nHeight;
  457. x = prc->left + ((prc->right - prc->left) - w) / 2;
  458. y = prc->top + ((prc->bottom - prc->top) - h) / 2;
  459. if (MENU_BUTTON_SCROLLDOWN == scrollButton)
  460. {
  461. nWidth = -w;
  462. nHeight = h;
  463. x += w;
  464. }
  465. else
  466. {
  467. nWidth = w;
  468. nHeight = -h;
  469. y += h;
  470. }
  471. SetBkColor(hdc, rgbBk);
  472. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
  473. StretchDIBits(hdc, x, y, nWidth, nHeight, 0, 0, w, h, bitmapInfo.dsBm.bmBits,
  474. (BITMAPINFO*)&bitmapInfo.dsBmih, DIB_RGB_COLORS, SRCCOPY);
  475. imageFailed = FALSE;
  476. }
  477. }
  478. if (imageFailed)
  479. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
  480. }
  481. BOOL SkinnedMenuWnd::DrawScrollButton(HDC hdc, UINT scrollButton)
  482. {
  483. RECT rc, rcWindow, rcPaint;
  484. if (0 == scrollButton ||
  485. 0 == GetWindowRect(hwnd, &rcWindow) ||
  486. 0 == GetClientRect(hwnd, &rc))
  487. {
  488. return FALSE;
  489. }
  490. MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
  491. HDC hdcOwned = NULL;
  492. if (NULL == hdc)
  493. {
  494. hdcOwned = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_WINDOW | DCX_CLIPSIBLINGS);
  495. hdc = hdcOwned;
  496. if (NULL == hdcOwned)
  497. return FALSE;
  498. }
  499. rcPaint.left = rc.left - rcWindow.left;
  500. rcPaint.right = rc.right - rcWindow.left;
  501. BOOL scrollEnabled;
  502. POINT ptTest;
  503. ptTest.x = rc.left + (rc.right - rc.left) / 2;
  504. if (0 != (MENU_BUTTON_SCROLLUP & scrollButton))
  505. {
  506. rcPaint.top = MENU_BORDER_WIDTH;
  507. rcPaint.bottom = rc.top - rcWindow.top;
  508. if (rcPaint.bottom > rcPaint.top && rcPaint.right > rcPaint.left)
  509. {
  510. ptTest.y = rc.top;
  511. scrollEnabled = (MenuItemFromPoint(hwnd, hMenu, ptTest) > 0);
  512. PaintScrollButton(hdc, &rcPaint, MENU_BUTTON_SCROLLUP, (scrollEnabled) ? 0 : MENU_BUTTON_STATE_DISABLED);
  513. }
  514. }
  515. if (0 != (MENU_BUTTON_SCROLLDOWN & scrollButton))
  516. {
  517. rcPaint.top = rc.bottom - rcWindow.top;
  518. rcPaint.bottom = (rcWindow.bottom - rcWindow.top) - MENU_BORDER_WIDTH;
  519. if (rcPaint.bottom > rcPaint.top && rcPaint.right > rcPaint.left)
  520. {
  521. ptTest.y = rc.bottom - WASABI_API_APP->getScaleY(1);
  522. INT last = MenuItemFromPoint(hwnd, hMenu, ptTest);
  523. scrollEnabled = FALSE;
  524. if (last >= 0)
  525. {
  526. INT count = GetMenuItemCount(hMenu);
  527. if (last != (count - 1))
  528. scrollEnabled = TRUE;
  529. }
  530. PaintScrollButton(hdc, &rcPaint, MENU_BUTTON_SCROLLDOWN, (scrollEnabled) ? 0 : MENU_BUTTON_STATE_DISABLED);
  531. }
  532. }
  533. if (NULL != hdcOwned)
  534. ReleaseDC(hwnd, hdcOwned);
  535. return TRUE;
  536. }
  537. void SkinnedMenuWnd::DrawBorder(HDC hdc)
  538. {
  539. RECT rc, rcWindow, rp;
  540. GetClientRect(hwnd, &rc);
  541. GetWindowRect(hwnd, &rcWindow);
  542. MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
  543. OffsetRect(&rc, -rcWindow.left, -rcWindow.top);
  544. OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
  545. SkinnedWnd::DrawBorder(hdc, &rcWindow, BORDER_FLAT, GetBorderPen());
  546. HBRUSH brushBk = SkinnedMenuWnd_GetBackBrush(hMenu);
  547. SetRect(&rp, rcWindow.left + 1, rcWindow.top + 1, rc.left, rcWindow.bottom - 1);
  548. FillRect(hdc, &rp, brushBk);
  549. SetRect(&rp, rc.left, rcWindow.top + 1, rc.right, rc.top);
  550. FillRect(hdc, &rp, brushBk);
  551. SetRect(&rp, rc.right, rcWindow.top + 1, rcWindow.right - 1, rcWindow.bottom - 1);
  552. FillRect(hdc, &rp, brushBk);
  553. SetRect(&rp, rc.left, rc.bottom, rc.right, rcWindow.bottom - 1);
  554. FillRect(hdc, &rp, brushBk);
  555. if ((rc.top - rcWindow.top) > MENU_BORDER_WIDTH || (rcWindow.bottom - rc.bottom) > MENU_BORDER_WIDTH)
  556. DrawScrollButton(hdc, MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN);
  557. }
  558. BOOL SkinnedMenuWnd::IsSkinnedItem(UINT itemId)
  559. {
  560. if (NULL == skinnedItems)
  561. return TRUE;
  562. if (skinnedItemCursor >= skinnedItemCount)
  563. skinnedItemCursor = 0;
  564. INT start = skinnedItemCursor;
  565. while(itemId != skinnedItems[skinnedItemCursor].itemId)
  566. {
  567. skinnedItemCursor++;
  568. if (skinnedItemCursor == skinnedItemCount)
  569. skinnedItemCursor = 0;
  570. if (skinnedItemCursor == start)
  571. {
  572. skinnedItemCursor = 0;
  573. return FALSE;
  574. }
  575. }
  576. return skinnedItems[skinnedItemCursor].skinned;
  577. }
  578. static void SkinnedMenuWnd_DrawFrame(HDC hdc, const RECT *prc, INT width, COLORREF rgbFrame)
  579. {
  580. if (width > 0)
  581. {
  582. COLORREF rgbOld = SetBkColor(hdc, rgbFrame);
  583. RECT rcPart;
  584. SetRect(&rcPart, prc->left, prc->top, prc->right, prc->top + width);
  585. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  586. SetRect(&rcPart, prc->left, prc->bottom - width, prc->right, prc->bottom);
  587. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  588. SetRect(&rcPart, prc->left, prc->top + width, prc->left + width, prc->bottom - width);
  589. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  590. SetRect(&rcPart, prc->right - width, prc->top + width, prc->right, prc->bottom - width);
  591. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rcPart, NULL, 0, NULL);
  592. if (rgbOld != rgbFrame)
  593. SetBkColor(hdc, rgbOld);
  594. }
  595. }
  596. BOOL SkinnedMenuWnd::OnReflectedDrawItem(DRAWITEMSTRUCT *pdis)
  597. {
  598. if (0 != (SMIF_BLOCKDRAW & menuFlags))
  599. {
  600. ExcludeClipRect(pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, pdis->rcItem.right, pdis->rcItem.bottom);
  601. }
  602. if (!IsSkinnedItem(pdis->itemID))
  603. return FALSE;
  604. MENUITEMINFOW mii = {0};
  605. wchar_t szText[256] = {0};
  606. INT imageCX, imageCY, realIndex;
  607. LONG imageTop;
  608. mii.cbSize = sizeof(MENUITEMINFO);
  609. mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_STATE | MIIM_SUBMENU;
  610. mii.cch = ARRAYSIZE(szText);
  611. mii.dwTypeData = szText;
  612. if (!GetMenuItemInfoW((HMENU)pdis->hwndItem, pdis->itemID, FALSE, &mii))
  613. mii.cch = 0;
  614. COLORREF rgbText, rgbTextBk, rgbTextFrame;
  615. if (0 != (SMS_SYSCOLORS & menuExStyle))
  616. {
  617. INT foreIndex = (0 != (MFS_GRAYED & mii.fState)) ? COLOR_GRAYTEXT : COLOR_MENUTEXT;
  618. INT backIndex = (0 != (ODS_SELECTED & pdis->itemState)) ? COLOR_HIGHLIGHT : COLOR_MENU;
  619. rgbText = GetSysColor(foreIndex);
  620. rgbTextBk = GetSysColor(backIndex);
  621. rgbTextFrame = rgbTextBk;
  622. }
  623. else
  624. {
  625. MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, (0 != (ODS_SELECTED & pdis->itemState)) ? MBS_SELECTED : MBS_NORMAL, &rgbTextBk);
  626. MLGetSkinColor(MLSO_MENU, MP_TEXT, (0 != (MFS_GRAYED & mii.fState)) ? MTS_DISABLED : ((0 != (ODS_SELECTED & pdis->itemState)) ? MBS_SELECTED : MBS_NORMAL), &rgbText);
  627. rgbTextFrame = rgbTextBk;
  628. if (0 != (ODS_SELECTED & pdis->itemState))
  629. {
  630. MLGetSkinColor(MLSO_MENU, MP_BACKGROUND, MBS_SELECTEDFRAME, &rgbTextFrame);
  631. }
  632. }
  633. COLORREF origText = SetTextColor(pdis->hDC, rgbText);
  634. COLORREF origTextBk = SetBkColor(pdis->hDC, rgbTextBk);
  635. if (0 != (MFT_MENUBARBREAK & mii.fType))
  636. {
  637. RECT rect;
  638. if (FALSE != GetClientRect(hwnd, &rect))
  639. {
  640. COLORREF lineColor, prevColor;
  641. HBRUSH brush = SkinnedMenuWnd_GetBackBrush(hMenu);
  642. if(NULL == brush)
  643. brush = GetSysColorBrush(COLOR_WINDOW);
  644. rect.right = pdis->rcItem.left - WASABI_API_APP->getScaleX(1);
  645. rect.left = pdis->rcItem.left - WASABI_API_APP->getScaleX(2);
  646. FillRect(pdis->hDC, &rect, brush);
  647. if (0 != (SMS_SYSCOLORS & menuExStyle) ||
  648. FAILED(MLGetSkinColor(MLSO_MENU, MP_SEPARATOR, 0, &lineColor)))
  649. {
  650. lineColor = GetSysColor(COLOR_3DSHADOW);
  651. }
  652. prevColor = SetBkColor(pdis->hDC, lineColor);
  653. OffsetRect(&rect, -1, 0);
  654. ExtTextOut(pdis->hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  655. SetBkColor(pdis->hDC, prevColor);
  656. }
  657. }
  658. if (NULL != customProc)
  659. {
  660. INT customResult = customProc(MLMENU_ACTION_DRAWITEM, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam);
  661. if (MLMENU_WANT_DRAWPART != customResult && FALSE != customResult)
  662. return TRUE;
  663. }
  664. INT type = ((MFT_STRING | MFT_SEPARATOR) & mii.fType);
  665. switch(type)
  666. {
  667. case MFT_STRING:
  668. if (NULL == customProc ||
  669. FALSE == customProc(MLMENU_ACTION_DRAWBACK, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam))
  670. {
  671. ExtTextOutW(pdis->hDC, 0, 0, ETO_OPAQUE, &pdis->rcItem, NULL, 0, NULL);
  672. if (rgbTextFrame != rgbTextBk)
  673. {
  674. SkinnedMenuWnd_DrawFrame(pdis->hDC, &pdis->rcItem, 1, rgbTextFrame);
  675. }
  676. }
  677. if (NULL == customProc ||
  678. FALSE == customProc(MLMENU_ACTION_DRAWICON, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam))
  679. {
  680. if (hmlil)
  681. {
  682. if (MLImageListI_GetImageSize(hmlil, &imageCX, &imageCY))
  683. {
  684. imageTop = pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top - imageCY) / 2;
  685. if (imageTop < pdis->rcItem.top) imageTop = pdis->rcItem.top;
  686. INT index = MLImageListI_GetIndexFromTag(hmlil, pdis->itemID);
  687. if (-1 != index)
  688. {
  689. HIMAGELIST himl = MLImageListI_GetRealList(hmlil);
  690. realIndex = MLImageListI_GetRealIndex(hmlil, index, rgbTextBk, rgbText);
  691. if (-1 != realIndex)
  692. {
  693. ImageList_Draw(himl, realIndex, pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(1) + (imageWidth - imageCX) / 2, imageTop, ILD_NORMAL);
  694. }
  695. }
  696. }
  697. }
  698. else if ((MFS_CHECKED & mii.fState) && hmlilCheck)
  699. {
  700. if (0 != (MFT_RADIOCHECK & mii.fType))
  701. {
  702. if (-1 == imageRadioMark)
  703. imageRadioMark = SkinnedMenuWnd_AddPngResource(hmlilCheck, IDB_MENU_RADIOMARK);
  704. }
  705. else
  706. {
  707. if (-1 == imageCheckMark)
  708. imageCheckMark = SkinnedMenuWnd_AddPngResource(hmlilCheck, IDB_MENU_CHECKMARK);
  709. }
  710. if (MLImageListI_GetImageSize(hmlilCheck, &imageCX, &imageCY))
  711. {
  712. imageTop = pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top - imageCY) / 2;
  713. if (imageTop < pdis->rcItem.top) imageTop = pdis->rcItem.top;
  714. HIMAGELIST himl = MLImageListI_GetRealList(hmlilCheck);
  715. realIndex = MLImageListI_GetRealIndex(hmlilCheck, (MFT_RADIOCHECK & mii.fType) ? imageRadioMark : imageCheckMark, rgbTextBk, rgbText);
  716. if (-1 != realIndex)
  717. {
  718. ImageList_Draw(himl, realIndex, pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(1) + (imageWidth - imageCX) / 2, imageTop, ILD_NORMAL);
  719. }
  720. }
  721. }
  722. }
  723. if (NULL != mii.hSubMenu && hmlilCheck)
  724. {
  725. if (-1 == imageExpandArrow)
  726. imageExpandArrow = SkinnedMenuWnd_AddPngResource(hmlilCheck, IDB_MENU_EXPANDARROW);
  727. if (MLImageListI_GetImageSize(hmlilCheck, &imageCX, &imageCY))
  728. {
  729. imageTop = pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top - imageCY) / 2;
  730. if (imageTop < pdis->rcItem.top) imageTop = pdis->rcItem.top;
  731. HIMAGELIST himl = MLImageListI_GetRealList(hmlilCheck);
  732. realIndex = MLImageListI_GetRealIndex(hmlilCheck, imageExpandArrow, rgbTextBk, rgbText);
  733. if (-1 != realIndex)
  734. ImageList_Draw(himl, realIndex, pdis->hDC, pdis->rcItem.right - imageCX - WASABI_API_APP->getScaleX(1), imageTop, ILD_NORMAL);
  735. }
  736. }
  737. if (NULL == customProc ||
  738. FALSE == customProc(MLMENU_ACTION_DRAWTEXT, (HMENU)pdis->hwndItem, pdis->hDC, (LPARAM)pdis, customParam))
  739. {
  740. if (mii.cch)
  741. {
  742. RECT rt;
  743. CopyRect(&rt, &pdis->rcItem);
  744. if (imageWidth && imageHeight) rt.left += imageWidth + WASABI_API_APP->getScaleX(6);
  745. rt.right -= imageWidth;
  746. HFONT hFont = GetMenuFont(FALSE);
  747. HFONT originalFont = (NULL != hFont) ? (HFONT)SelectObject(pdis->hDC, hFont) : NULL;
  748. INT originalBkMode = SetBkMode(pdis->hDC, TRANSPARENT);
  749. UINT len = mii.cch;
  750. if (len > 0)
  751. {
  752. while(--len > 0 && L'\t' != mii.dwTypeData[len]);
  753. if (0 == len)
  754. len = mii.cch;
  755. }
  756. BOOL showPrefix = FALSE;
  757. if (!SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &showPrefix, 0))
  758. showPrefix = FALSE;
  759. if (!showPrefix && 0 == (ODS_NOACCEL & pdis->itemState))
  760. showPrefix = TRUE;
  761. UINT drawtextFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP;
  762. if (!showPrefix)
  763. drawtextFlags |= 0x000100000; /*DT_HIDEPREFIX*/
  764. if (0 != (MFS_DEFAULT & mii.fState))
  765. {
  766. SetTextColor(pdis->hDC, BlendColors(rgbText, rgbTextBk, 110));
  767. OffsetRect(&rt, 1,0);
  768. DrawTextW(pdis->hDC, mii.dwTypeData, len, &rt, drawtextFlags);
  769. OffsetRect(&rt, -1,0);
  770. SetTextColor(pdis->hDC, rgbText);
  771. }
  772. DrawTextW(pdis->hDC, mii.dwTypeData, len, &rt, drawtextFlags);
  773. if (mii.cch > (len + 1))
  774. {
  775. len++;
  776. rt.left = rt.right - shortcutCX;
  777. SetTextColor(pdis->hDC, BlendColors(rgbText, rgbTextBk, 192));
  778. DrawTextW(pdis->hDC, mii.dwTypeData + len, mii.cch - len, &rt, DT_LEFT | DT_VCENTER | 0x000100000/*DT_HIDEPREFIX*/ | DT_SINGLELINE | DT_NOCLIP);
  779. }
  780. SelectObject(pdis->hDC, originalFont);
  781. if (TRANSPARENT != originalBkMode)
  782. SetBkMode(pdis->hDC, originalBkMode);
  783. }
  784. }
  785. ExcludeClipRect(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(23),
  786. pdis->rcItem.top, pdis->rcItem.right, pdis->rcItem.bottom);
  787. break;
  788. case MFT_SEPARATOR:
  789. {
  790. COLORREF rgbSeparator;
  791. HPEN hPen, originalPen;
  792. INT y = (pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top) / 2);
  793. if (0 != (SMS_SYSCOLORS & menuExStyle) ||
  794. FAILED(MLGetSkinColor(MLSO_MENU, MP_SEPARATOR, 0, &rgbSeparator)))
  795. {
  796. rgbSeparator = GetSysColor(COLOR_3DSHADOW/*COLOR_GRAYTEXT*/);
  797. }
  798. hPen = CreatePen(PS_SOLID, 0, rgbSeparator);
  799. originalPen = (HPEN)SelectObject(pdis->hDC, hPen);
  800. ExtTextOutW(pdis->hDC, 0, 0, ETO_OPAQUE, &pdis->rcItem, NULL, 0, NULL);
  801. MoveToEx(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(23), y, NULL);
  802. LineTo(pdis->hDC, pdis->rcItem.right, y);
  803. SelectObject(pdis->hDC, originalPen);
  804. DeleteObject(hPen);
  805. // draws a edge on the separator so it looks more like the OS when trying to 'fake it'
  806. if (0 != (SMS_SYSCOLORS & menuExStyle))
  807. {
  808. RECT bottomRect = pdis->rcItem;
  809. HBRUSH brush = GetSysColorBrush(COLOR_3DHIGHLIGHT);
  810. y += WASABI_API_APP->getScaleY(1);
  811. bottomRect.top = y;
  812. bottomRect.bottom = y + WASABI_API_APP->getScaleY(1);
  813. FillRect(pdis->hDC,&bottomRect, brush);
  814. }
  815. }
  816. ExcludeClipRect(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(23),
  817. pdis->rcItem.top, pdis->rcItem.right, pdis->rcItem.bottom);
  818. break;
  819. }
  820. {
  821. COLORREF rgbSeparator;
  822. if (0 != (SMS_SYSCOLORS & menuExStyle) ||
  823. FAILED(MLGetSkinColor(MLSO_MENU, MP_SEPARATOR, 0, &rgbSeparator)))
  824. {
  825. rgbSeparator = GetSysColor(COLOR_3DSHADOW/*COLOR_GRAYTEXT*/);
  826. }
  827. HPEN hPen = CreatePen(PS_SOLID, 0, rgbSeparator);
  828. HPEN originalPen = (HPEN)SelectObject(pdis->hDC, hPen);
  829. MoveToEx(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(22), pdis->rcItem.top, NULL);
  830. LineTo(pdis->hDC, pdis->rcItem.left + WASABI_API_APP->getScaleX(22), pdis->rcItem.top + (pdis->rcItem.bottom - pdis->rcItem.top));
  831. SelectObject(pdis->hDC, originalPen);
  832. DeleteObject(hPen);
  833. }
  834. if (origText != rgbText)
  835. SetTextColor(pdis->hDC, origText);
  836. if (origTextBk != rgbTextBk)
  837. SetBkColor(pdis->hDC, origTextBk);
  838. return TRUE;
  839. }
  840. BOOL SkinnedMenuWnd::OnReflectedMeasureItem(MEASUREITEMSTRUCT *pmis)
  841. {
  842. pmis->itemHeight = lineHeight;
  843. pmis->itemWidth = lineWidth;
  844. if (!IsSkinnedItem(pmis->itemID))
  845. return FALSE;
  846. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE);
  847. if (NULL == hdc) return FALSE;
  848. MENUITEMINFOW mii = {0};
  849. wchar_t szText[128] = {0};
  850. mii.cbSize = sizeof(MENUITEMINFO);
  851. mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_STATE;
  852. mii.cch = ARRAYSIZE(szText);
  853. mii.dwTypeData = szText;
  854. if (!GetMenuItemInfoW(hMenu, pmis->itemID, FALSE, &mii))
  855. mii.cch = 0;
  856. HFONT originalFont = (HFONT)SelectObject(hdc, GetMenuFont(0 != (MFS_DEFAULT & mii.fState)));
  857. if (NULL == customProc ||
  858. FALSE == customProc(MLMENU_ACTION_MEASUREITEM, hMenu, hdc, (LPARAM)pmis, customParam))
  859. {
  860. if (0 == lineWidth || 0 == lineHeight)
  861. {
  862. INT type = ((MFT_STRING | MFT_SEPARATOR) & mii.fType);
  863. switch(type)
  864. {
  865. case MFT_STRING:
  866. if (mii.cch != 0)
  867. {
  868. SIZE sz;
  869. UINT len = mii.cch;
  870. while(--len > 0 && L'\t' != mii.dwTypeData[len]);
  871. if (0 == len) len = mii.cch;
  872. if (len != mii.cch)
  873. {
  874. szText[len] = L' ';
  875. if (GetTextExtentPoint32W(hdc, szText + len, mii.cch - len, &sz) &&
  876. shortcutCX < sz.cx)
  877. {
  878. shortcutCX = sz.cx;
  879. }
  880. }
  881. if (GetTextExtentPoint32W(hdc, szText, len, &sz))
  882. {
  883. if (textCX <= sz.cx)
  884. textCX = sz.cx;
  885. if (lineHeight < sz.cy)
  886. pmis->itemHeight = sz.cy + WASABI_API_APP->getScaleY(2);
  887. if (0 == lineWidth)
  888. pmis->itemWidth = textCX + shortcutCX + 8;
  889. }
  890. }
  891. if(imageHeight > (INT)(pmis->itemHeight + WASABI_API_APP->getScaleY(2))) pmis->itemHeight = imageHeight + WASABI_API_APP->getScaleY(2);
  892. if (0 == lineWidth && imageWidth) pmis->itemWidth += imageWidth;
  893. pmis->itemWidth -= (GetSystemMetrics(SM_CXMENUCHECK) - imageWidth - WASABI_API_APP->getScaleX(36));
  894. break;
  895. case MFT_SEPARATOR:
  896. pmis->itemHeight = WASABI_API_APP->getScaleY(7);
  897. break;
  898. }
  899. }
  900. }
  901. SelectObject(hdc, originalFont);
  902. ReleaseDC(hwnd, hdc);
  903. return TRUE;
  904. }
  905. void SkinnedMenuWnd::OnNcPaint(HRGN rgnUpdate)
  906. {
  907. if (0 != (SMIF_BLOCKDRAW & menuFlags))
  908. return;
  909. UINT flags = DCX_PARENTCLIP | DCX_WINDOW | DCX_CLIPSIBLINGS |
  910. DCX_INTERSECTUPDATE | DCX_VALIDATE;
  911. HDC hdc = GetDCEx(hwnd, ((HRGN)NULLREGION != rgnUpdate) ? rgnUpdate : NULL, flags);
  912. if (NULL == hdc)
  913. return;
  914. DrawBorder(hdc);
  915. ReleaseDC(hwnd, hdc);
  916. }
  917. LRESULT SkinnedMenuWnd::OnEraseBackground(HDC hdc)
  918. {
  919. HBRUSH brush;
  920. brush = SkinnedMenuWnd_GetBackBrush(hMenu);
  921. if (NULL != brush)
  922. {
  923. RECT rect;
  924. if (FALSE != GetClientRect(hwnd, &rect) &&
  925. FALSE != FillRect(hdc, &rect, brush))
  926. {
  927. return 1;
  928. }
  929. }
  930. return __super::WindowProc(WM_ERASEBKGND, (WPARAM)hdc, 0L);
  931. }
  932. void SkinnedMenuWnd::OnPrint(HDC hdc, UINT options)
  933. {
  934. if (0 != (PRF_CHECKVISIBLE & options))
  935. {
  936. DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  937. if (0 == (WS_VISIBLE & windowStyle))
  938. {
  939. return;
  940. }
  941. }
  942. if (0 != (PRF_NONCLIENT & options))
  943. {
  944. DrawBorder(hdc);
  945. }
  946. if (0 == ((PRF_ERASEBKGND | PRF_CLIENT) & options))
  947. {
  948. return;
  949. }
  950. POINT ptOrig;
  951. RECT rc, rcWindow;
  952. if (GetClientRect(hwnd, &rc) &&
  953. GetWindowRect(hwnd, &rcWindow))
  954. {
  955. MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
  956. }
  957. else
  958. {
  959. SetRectEmpty(&rc);
  960. SetRectEmpty(&rcWindow);
  961. }
  962. INT clipRegionCode;
  963. HRGN clipRegion = CreateRectRgn(0, 0, 0, 0);
  964. clipRegionCode = (NULL != clipRegion) ? GetClipRgn(hdc, clipRegion) : -1;
  965. OffsetViewportOrgEx(hdc, rc.left - rcWindow.left, rc.top - rcWindow.top, &ptOrig);
  966. if (-1 != clipRegionCode)
  967. {
  968. IntersectClipRect(hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top);
  969. }
  970. OffsetRect(&rc, -rc.left, -rc.top);
  971. if (0 != (PRF_ERASEBKGND & options))
  972. {
  973. MENUINFO mi = {0};
  974. mi.cbSize = sizeof(MENUINFO);
  975. mi.fMask = MIM_BACKGROUND;
  976. HBRUSH brushBk = NULL;
  977. if (GetMenuInfo(hMenu, &mi) && mi.hbrBack)
  978. brushBk = mi.hbrBack;
  979. if (NULL == brushBk)
  980. brushBk = GetSysColorBrush(COLOR_WINDOW);
  981. FillRect(hdc, &rc, brushBk);
  982. }
  983. if (0 != (PRF_CLIENT & options))
  984. {
  985. menuFlags &= ~SMIF_BLOCKDRAW;
  986. SendMessage(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, (LPARAM)(~(PRF_NONCLIENT | PRF_ERASEBKGND) & options));
  987. menuFlags |= SMIF_BLOCKDRAW;
  988. }
  989. if (-1 != clipRegionCode)
  990. {
  991. SelectClipRgn(hdc, (0 != clipRegionCode) ? clipRegion : NULL);
  992. }
  993. if (NULL != clipRegion)
  994. DeleteObject(clipRegion);
  995. SetViewportOrgEx(hdc, ptOrig.x, ptOrig.y, NULL);
  996. SetTimer(hwnd, MTID_EX_UNBLOCKDRAW, 250, NULL);
  997. }
  998. LRESULT SkinnedMenuWnd::OnMenuSelect(UINT selectedItem)
  999. {
  1000. if (((UINT)-1) != selectedItem)
  1001. menuFlags &= ~SMIF_BLOCKDRAW;
  1002. UINT updateScroll = 0;
  1003. if (MHF_SCROLLUP == prevSelectedItem)
  1004. updateScroll |= MENU_BUTTON_SCROLLUP;
  1005. else if (MHF_SCROLLDOWN == prevSelectedItem)
  1006. updateScroll |= MENU_BUTTON_SCROLLDOWN;
  1007. switch(selectedItem)
  1008. {
  1009. case MHF_SCROLLUP:
  1010. updateScroll |= MENU_BUTTON_SCROLLUP;
  1011. break;
  1012. case MHF_SCROLLDOWN:
  1013. updateScroll |= MENU_BUTTON_SCROLLDOWN;
  1014. break;
  1015. }
  1016. RECT rc;
  1017. GetClientRect(hwnd, &rc);
  1018. MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
  1019. rc.top += WASABI_API_APP->getScaleY(1);
  1020. INT item = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
  1021. LRESULT result;
  1022. BOOL fInvalidate = FALSE;
  1023. if (0 != updateScroll)
  1024. {
  1025. DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  1026. SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
  1027. result = __super::WindowProc(MN_SELECTITEM, selectedItem, 0L);
  1028. SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
  1029. if (MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc)) != item)
  1030. {
  1031. updateScroll = MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN;
  1032. fInvalidate = TRUE;
  1033. }
  1034. }
  1035. else
  1036. {
  1037. result = __super::WindowProc(MN_SELECTITEM, selectedItem, 0L);
  1038. }
  1039. prevSelectedItem = selectedItem;
  1040. if (0 != updateScroll)
  1041. {
  1042. DrawScrollButton(NULL, updateScroll);
  1043. if (FALSE != fInvalidate)
  1044. {
  1045. InvalidateRect(hwnd, NULL, FALSE);
  1046. }
  1047. }
  1048. return result;
  1049. }
  1050. LRESULT SkinnedMenuWnd::CallHookedWindowProc(UINT uItem, BOOL fByPosition, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1051. {
  1052. MENUITEMINFOW mii = {0};
  1053. mii.cbSize = sizeof(mii);
  1054. mii.fMask = MIIM_SUBMENU;
  1055. if (FALSE != GetMenuItemInfoW(hMenu, uItem, fByPosition, &mii) &&
  1056. NULL != mii.hSubMenu)
  1057. {
  1058. SkinnedMenu sm;
  1059. sm.InitializeHook(NULL, (menuExStyle & ~SMS_FORCEWIDTH), hmlil, 0, customProc, customParam);
  1060. return __super::WindowProc(uMsg, wParam, lParam);
  1061. }
  1062. return __super::WindowProc(uMsg, wParam, lParam);
  1063. }
  1064. INT SkinnedMenuWnd::FindHiliteItem(HMENU hMenu)
  1065. {
  1066. MENUITEMINFOW mii = {0};
  1067. mii.cbSize = sizeof(MENUITEMINFOW);
  1068. mii.fMask = MIIM_STATE;
  1069. INT count = GetMenuItemCount(hMenu);
  1070. for (INT i = 0; i < count; i++)
  1071. {
  1072. if (0 != GetMenuItemInfoW(hMenu, i, TRUE, &mii))
  1073. {
  1074. if (MFS_HILITE == ((MFS_HILITE | MFS_DISABLED | MFS_GRAYED) & mii.fState))
  1075. return i;
  1076. }
  1077. }
  1078. return -1;
  1079. }
  1080. LRESULT SkinnedMenuWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1081. {
  1082. switch(uMsg)
  1083. {
  1084. case WM_ERASEBKGND:
  1085. return OnEraseBackground((HDC)wParam);
  1086. case REFLECTED_DRAWITEM:
  1087. if (OnReflectedDrawItem((DRAWITEMSTRUCT*)((REFLECTPARAM*)lParam)->lParam))
  1088. {
  1089. ((REFLECTPARAM*)lParam)->result = TRUE;
  1090. return TRUE;
  1091. }
  1092. break;
  1093. case REFLECTED_MEASUREITEM:
  1094. if (OnReflectedMeasureItem((MEASUREITEMSTRUCT*)((REFLECTPARAM*)lParam)->lParam))
  1095. {
  1096. ((REFLECTPARAM*)lParam)->result = TRUE;
  1097. return TRUE;
  1098. }
  1099. break;
  1100. case MN_SIZEWINDOW:
  1101. {
  1102. BOOL validateOwner = FALSE;
  1103. if (NULL == hMenu)
  1104. {
  1105. textCX = 0;
  1106. shortcutCX = 0;
  1107. HMENU menuToAttach = (HMENU)SendMessageW(hwnd, MN_GETHMENU, 0, 0L);
  1108. if (FALSE != AttachMenu(menuToAttach))
  1109. validateOwner = TRUE;
  1110. }
  1111. if (NULL != threadInfo)
  1112. {
  1113. threadInfo->SetActiveMeasureMenu(hMenu);
  1114. if (FALSE != validateOwner &&
  1115. FALSE == threadInfo->SetValidationHook(this))
  1116. {
  1117. validateOwner = FALSE;
  1118. }
  1119. }
  1120. LRESULT result = __super::WindowProc(uMsg, wParam, lParam);
  1121. if (NULL != threadInfo)
  1122. {
  1123. threadInfo->SetActiveMeasureMenu(NULL);
  1124. if (FALSE != validateOwner)
  1125. threadInfo->RemoveValidationHook(this);
  1126. }
  1127. return result;
  1128. }
  1129. break;
  1130. case MN_SELECTITEM:
  1131. return OnMenuSelect((UINT)wParam);
  1132. case MN_LBUTTONDBLCLK:
  1133. case MN_LBUTTONDOWN:
  1134. case MN_LBUTTONUP:
  1135. menuFlags &= ~SMIF_BLOCKDRAW;
  1136. switch(wParam)
  1137. {
  1138. case MHF_SCROLLUP:
  1139. case MHF_SCROLLDOWN:
  1140. {
  1141. LRESULT result = __super::WindowProc(uMsg, wParam, lParam);
  1142. DrawScrollButton(NULL, MENU_BUTTON_SCROLLDOWN | MENU_BUTTON_SCROLLUP);
  1143. return result;
  1144. }
  1145. break;
  1146. default:
  1147. if (wParam >= 0)
  1148. {
  1149. return CallHookedWindowProc((UINT)wParam, TRUE, uMsg, wParam, lParam);
  1150. }
  1151. break;
  1152. }
  1153. break;
  1154. case WM_TIMER:
  1155. switch(wParam)
  1156. {
  1157. case MTID_OPENSUBMENU:
  1158. {
  1159. POINT pt;
  1160. INT iItem;
  1161. if (GetCursorPos(&pt) &&
  1162. -1 != (iItem = MenuItemFromPoint(NULL, hMenu, pt)))
  1163. {
  1164. CallHookedWindowProc(iItem, TRUE, uMsg, wParam, lParam);
  1165. return 0;
  1166. }
  1167. }
  1168. break;
  1169. case MHF_SCROLLUP:
  1170. case MHF_SCROLLDOWN:
  1171. __super::WindowProc(uMsg, wParam, lParam);
  1172. DrawScrollButton(NULL, MENU_BUTTON_SCROLLDOWN | MENU_BUTTON_SCROLLUP);
  1173. return 0;
  1174. case MTID_EX_UNBLOCKDRAW:
  1175. KillTimer(hwnd, wParam);
  1176. menuFlags &= ~SMIF_BLOCKDRAW;
  1177. return 0;
  1178. }
  1179. break;
  1180. case WM_KEYDOWN:
  1181. menuFlags &= ~SMIF_BLOCKDRAW;
  1182. switch(wParam)
  1183. {
  1184. case VK_RETURN:
  1185. case VK_RIGHT:
  1186. {
  1187. INT iItem = FindHiliteItem(hMenu);
  1188. if (-1 != iItem)
  1189. return CallHookedWindowProc(iItem, TRUE, uMsg, wParam, lParam);
  1190. }
  1191. break;
  1192. case VK_UP:
  1193. {
  1194. RECT rc;
  1195. GetClientRect(hwnd, &rc);
  1196. MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
  1197. rc.top += 1;
  1198. INT iItem = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
  1199. if (iItem >= 0)
  1200. {
  1201. MENUITEMINFOW mii = {0};
  1202. mii.cbSize = sizeof(MENUITEMINFOW);
  1203. mii.fMask = MIIM_STATE;
  1204. if (GetMenuItemInfoW(hMenu, iItem, TRUE, &mii) &&
  1205. 0 != (MFS_HILITE & mii.fState))
  1206. {
  1207. DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  1208. if (0 != (WS_VISIBLE & windowStyle))
  1209. SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
  1210. __super::WindowProc(uMsg, wParam, lParam);
  1211. if (0 != (WS_VISIBLE & windowStyle))
  1212. {
  1213. windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  1214. if (0 == (WS_VISIBLE & windowStyle))
  1215. {
  1216. windowStyle |= WS_VISIBLE;
  1217. SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
  1218. }
  1219. INT iNew = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
  1220. if (iNew != iItem)
  1221. {
  1222. DrawScrollButton(NULL, MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN);
  1223. InvalidateRect(hwnd, NULL, FALSE);
  1224. }
  1225. else
  1226. {
  1227. int iHilite = GetMenuItemCount(hMenu);
  1228. while(0 < iHilite--)
  1229. {
  1230. if (FALSE != GetMenuItemInfoW(hMenu, iHilite, TRUE, &mii) &&
  1231. 0 != (MFS_HILITE & mii.fState))
  1232. {
  1233. break;
  1234. }
  1235. }
  1236. if (FALSE != GetMenuItemRect(hwnd, hMenu, iItem, &rc))
  1237. {
  1238. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rc, 2);
  1239. InvalidateRect(hwnd, &rc, FALSE);
  1240. }
  1241. if (iHilite != iItem &&
  1242. FALSE != GetMenuItemRect(hwnd, hMenu, iHilite, &rc))
  1243. {
  1244. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rc, 2);
  1245. InvalidateRect(hwnd, &rc, FALSE);
  1246. }
  1247. }
  1248. }
  1249. return 0;
  1250. }
  1251. }
  1252. }
  1253. break;
  1254. case VK_DOWN:
  1255. {
  1256. RECT rc;
  1257. GetClientRect(hwnd, &rc);
  1258. MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
  1259. rc.top = rc.bottom - 1;
  1260. INT item = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
  1261. if (item >= 0)
  1262. {
  1263. MENUITEMINFOW mii = {0};
  1264. mii.cbSize = sizeof(MENUITEMINFOW);
  1265. mii.fMask = MIIM_STATE;
  1266. if (GetMenuItemInfoW(hMenu, item, TRUE, &mii) &&
  1267. MFS_HILITE == ((MFS_HILITE | MFS_DISABLED | MFS_GRAYED) & mii.fState))
  1268. {
  1269. DWORD windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
  1270. SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE);
  1271. __super::WindowProc(uMsg, wParam, lParam);
  1272. SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
  1273. INT iNew = MenuItemFromPoint(hwnd, hMenu, *((POINT*)&rc));
  1274. if (iNew != item)
  1275. {
  1276. DrawScrollButton(NULL, MENU_BUTTON_SCROLLUP | MENU_BUTTON_SCROLLDOWN);
  1277. InvalidateRect(hwnd, NULL, FALSE);
  1278. }
  1279. return 0;
  1280. }
  1281. }
  1282. }
  1283. break;
  1284. }
  1285. break;
  1286. }
  1287. return __super::WindowProc(uMsg, wParam, lParam);
  1288. }