1: /*
2: ============================================================================
3: xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
4: Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
5: Copyright © 2001-2004 The Blackbox for Windows Development Team
6: http://xoblite.net/ + https://github.com/xoblite/
7: ============================================================================
8:
9: Blackbox for Windows is free software, released under the
10: GNU General Public License (GPL version 2 or later), with an extension
11: that allows linking of proprietary modules under a controlled interface.
12: What this means is that plugins etc. are allowed to be released
13: under any license the author wishes. Please note, however, that the
14: original Blackbox gradient math code used in Blackbox for Windows
15: is available under the BSD license.
16:
17: http://www.fsf.org/licenses/gpl.html
18: http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
19: http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
20:
21: This program is distributed in the hope that it will be useful,
22: but WITHOUT ANY WARRANTY; without even the implied warranty of
23: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24: GNU General Public License for more details.
25:
26: For additional license information, please read the included license.html.
27:
28: ============================================================================
29: */
30:
31: #include "MenuCommon.h"
32: #include "Menu.h"
33: #include "MenuItem.h"
34: #include "PreviewItem.h"
35: #include "StringItem.h"
36: #include "..\API\BBApi.h"
37: #include "..\Settings\Settings.h"
38: #include <algorithm>
39:
40: const char szMenuName[] = "BBMenu"; // Window class etc.
41:
42: extern BImage* pBImage;
43: extern Settings* pSettings;
44: extern MenuCommon* pMenuCommon;
45: extern PreviewItem* pPreviewItem;
46:
47: vector<Menu*> g_Menues;
48: int Menu::m_nInstances = 0;
49:
50: int menuMessageSubscription[] = { BB_RECONFIGURE, BB_REDRAWGUI, 0 };
51:
52: //===========================================================================
53:
54: Menu::Menu(HINSTANCE hInstance)
55: {
56: hMenuInstance = hInstance;
57:
58: isValidated = false;
59: m_pParent = NULL;
60: hMenuWnd = NULL;
61: m_pszFolderPath = NULL;
62: ZeroMemory(&data, sizeof(data));
63:
64: isPinned = false;
65: m_bMoved = false;
66: mouseIsHovering = false;
67: keyboardNavigationInProgress = false;
68:
69: menuHDC = cachedMenuBackground = cachedMenuActive = NULL;
70: cachedMenuGradientsExist = false;
71:
72: //====================
73:
74: // If this is the first menu instance created, we also create a common
75: // window class to be used by this and all future menu instances...
76: if (m_nInstances == 0)
77: {
78: WNDCLASS wc;
79: ZeroMemory(&wc, sizeof(wc));
80: wc.hInstance = hMenuInstance;
81: wc.lpfnWndProc = MenuWindowProc;
82: wc.lpszClassName = szMenuName;
83: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
84: wc.hbrBackground = NULL;
85: wc.style = CS_DBLCLKS;
86:
87: if (!RegisterClass(&wc))
88: {
89: MessageBox(0, "Error registering menu window class!", szMenuName, MB_OK | MB_ICONERROR | MB_TOPMOST);
90: Log("Menu", "Error registering window class!");
91: return;
92: }
93: }
94:
95: // Add the new menu instance to the global list of menues...
96: g_Menues.push_back(this);
97:
98: //====================
99:
100: // Create a window for this particular menu instance...
101: hMenuWnd = CreateWindowEx(
102: WS_EX_TOOLWINDOW | WS_EX_ACCEPTFILES | WS_EX_TOPMOST | WS_EX_LAYERED, // window style
103: szMenuName, // window class
104: NULL, // window name
105: WS_POPUP, // window parameters
106: 0, // x position
107: 0, // y position
108: 0, // window width
109: 0, // window height
110: GetBBWnd(), // owner window
111: NULL, // no menu
112: hMenuInstance, // hInstance
113: NULL // no window creation data
114: );
115:
116: if (!hMenuWnd)
117: {
118: MessageBox(0, "Error creating menu window!", szMenuName, MB_OK | MB_ICONERROR | MB_TOPMOST);
119: Log("Menu", "Error creating window!");
120: return;
121: }
122:
123: m_nInstances++;
124:
125: // Hide the menu window... (nb. menues are not shown until opened/navigated to by the user)
126: ShowWindow(hMenuWnd, SW_HIDE);
127: // Make the menu window sticky...
128: MakeSticky(hMenuWnd);
129:
130: // Subscribe to Blackbox messages applicable to menus...
131: SendMessage(GetBBWnd(), BB_REGISTERMESSAGE, (WPARAM)hMenuWnd, (LPARAM)menuMessageSubscription);
132: }
133:
134: //===========================================================================
135:
136: Menu::~Menu()
137: {
138: // Unsubscribe to previously subscribed Blackbox messages...
139: SendMessage (GetBBWnd(), BB_UNREGISTERMESSAGE, (WPARAM)hMenuWnd, (LPARAM)menuMessageSubscription);
140:
141: // Remove this menu instance to the global list of menues...
142: for (unsigned int i=0; i<g_Menues.size(); i++)
143: {
144: if (g_Menues[i] == this)
145: {
146: g_Menues.erase(g_Menues.begin()+i);
147: break;
148: }
149: }
150:
151: // Destroy the menu window...
152: if (hMenuWnd) DestroyWindow(hMenuWnd);
153: hMenuWnd = NULL;
154:
155: // Delete the cached gradients...
156: if (cachedMenuBackground) DeleteDC(cachedMenuBackground);
157: if (cachedMenuActive) DeleteDC(cachedMenuActive);
158: if (menuHDC) DeleteDC(menuHDC);
159:
160: // Delete all menu items belonging to this menu...
161: DeleteMenuItems();
162:
163: // Decrease the global count of menu instances...
164: m_nInstances--;
165: if (m_nInstances == 0)
166: {
167: // This is the last menu instance,
168: // so we can unregister the common window class...
169: UnregisterClass(szMenuName, hMenuInstance);
170: }
171:
172: // ...and finally, clean up some miscellaneous stuff...
173: if (m_pszFolderPath) free(m_pszFolderPath);
174: m_pszFolderPath = NULL;
175: }
176:
177: //===========================================================================
178: // Function: UpdateMenuWindow
179: // Purpose: ...
180: //===========================================================================
181:
182: void Menu::UpdateMenuWindow()
183: {
184: if (!isValidated) return;
185:
186: //====================
187:
188: // Get the bounding rect of the entire menu...
189: GetClientRect(hMenuWnd, &menuRect);
190: menuWidth = menuRect.right - menuRect.left;
191: menuHeight = menuRect.bottom - menuRect.top;
192:
193: // Get the bounding rect of the menu title...
194: CopyRect(&menuTitleRect, &menuRect);
195: menuTitleRect.bottom = pMenuCommon->m_nTitleHeight;
196:
197: if (pSettings->MenuFrame->borderWidth > pSettings->MenuTitle->borderWidth)
198: {
199: // Offset the menu title according to a bbLean bug/feature... (see further below)
200: OffsetRect(&menuTitleRect, 0, (pSettings->MenuFrame->borderWidth - pSettings->MenuTitle->borderWidth));
201: InflateRect(&menuTitleRect, (pSettings->MenuFrame->borderWidth - pSettings->MenuTitle->borderWidth), 0);
202: // ##### WORK IN PROGRESS - COMMENTED OUT EQUIVALENT CODE IN THE "Draw menu title" SECTION BELOW #####
203: }
204:
205: // Get the bounding rect of the menu grip... (drawn only if defined in the style file)
206: if (!pSettings->MenuGrip->parentRelative)
207: {
208: CopyRect(&menuGripRect, &menuRect);
209: menuGripRect.top = menuGripRect.bottom - pMenuCommon->m_nGripHeight;
210:
211: if (pSettings->MenuFrame->borderWidth > pSettings->MenuGrip->borderWidth)
212: {
213: // Offset the menu grip according to a bbLean bug/feature... (see further below)
214: OffsetRect(&menuGripRect, 0, (pSettings->MenuFrame->borderWidth - pSettings->MenuGrip->borderWidth));
215: }
216: }
217:
218: // Get the bounding rect of the menu frame...
219: CopyRect(&menuFrameRect, &menuRect);
220: // if (!pMenuCommon->m_nTitleDisabled) menuFrameRect.top = pMenuCommon->m_nTitleHeight - pSettings->MenuFrame->borderWidth;
221: if (!pMenuCommon->m_nTitleDisabled) menuFrameRect.top = menuTitleRect.bottom - pSettings->MenuFrame->borderWidth;
222: else menuFrameRect.top = 0;
223: // if (!pSettings->MenuGrip->parentRelative) menuFrameRect.bottom = menuFrameRect.bottom - pMenuCommon->m_nGripHeight + pSettings->MenuFrame->borderWidth;
224: if (!pSettings->MenuGrip->parentRelative) menuFrameRect.bottom = menuGripRect.top + pSettings->MenuFrame->borderWidth;
225: else menuFrameRect.bottom = menuRect.bottom;
226:
227: // Get the dimensions of the menu hilite/active...
228: menuActiveRect.left = pSettings->MenuFrame->borderWidth + pSettings->MenuFrame->marginWidth;
229: menuActiveRect.right = menuRect.right - pSettings->MenuFrame->borderWidth - pSettings->MenuFrame->marginWidth;
230: menuActiveWidth = menuActiveRect.right - menuActiveRect.left;
231: menuActiveHeight = pMenuCommon->m_nSubmenuHeight;
232:
233: //====================
234:
235: if (menuHDC == NULL) menuHDC = CreateCompatibleDC(NULL);
236:
237: HDC hdc = GetWindowDC(hMenuWnd);
238: HBITMAP bufbmp = CreateCompatibleBitmap(hdc, menuWidth, menuHeight);
239: DeleteObject(SelectObject(menuHDC, bufbmp));
240: ReleaseDC(hMenuWnd, hdc);
241:
242: //====================
243:
244: // If we have not yet created cached menu gradients, let's do that...
245: if (!cachedMenuGradientsExist)
246: {
247: RECT r;
248: HBITMAP tempBitmap, oldBitmap;
249:
250: int menuTitleWidth = menuTitleRect.right - menuTitleRect.left;
251: int menuTitleHeight = menuTitleRect.bottom - menuTitleRect.top;
252: int menuFrameWidth = menuFrameRect.right - menuFrameRect.left;
253: int menuFrameHeight = menuFrameRect.bottom - menuFrameRect.top;
254:
255: //====================
256:
257: // The menu title, frame and (if enabled) grip do not move,
258: // so we can draw them directly onto the same bitmap...
259: if (cachedMenuBackground) DeleteDC(cachedMenuBackground);
260: cachedMenuBackground = CreateCompatibleDC(NULL);
261:
262: tempBitmap = CreateCompatibleBitmap(menuHDC, menuWidth, menuHeight);
263: oldBitmap = (HBITMAP)SelectObject(cachedMenuBackground, tempBitmap);
264: DeleteObject(oldBitmap);
265:
266: // Draw menu frame...
267: if (pSettings->MenuFrame->type == B_IMAGEFROMFILE) DrawImageIntoRect(cachedMenuBackground, menuFrameRect, pSettings->MenuFrame, false, true);
268: else MakeGradientSuper(cachedMenuBackground, menuFrameRect, pSettings->MenuFrame->type, pSettings->MenuFrame->Color1, pSettings->MenuFrame->Color2, pSettings->MenuFrame->Color3, pSettings->MenuFrame->Color4, pSettings->MenuFrame->Color5, pSettings->MenuFrame->Color6, pSettings->MenuFrame->Color7, pSettings->MenuFrame->Color8, pSettings->MenuFrame->interlaced, pSettings->MenuFrame->bevelstyle, pSettings->MenuFrame->bevelposition, pSettings->bevelWidth, pSettings->MenuFrame->borderColor, pSettings->MenuFrame->borderWidth);
269:
270: // Draw menu title...
271: if (!pMenuCommon->m_nTitleDisabled)
272: {
273: if ((pSettings->MenuTitle->borderColor != pSettings->MenuFrame->borderColor) || (pSettings->MenuTitle->borderWidth < pSettings->MenuFrame->borderWidth))
274: {
275: // A bug/feature (?) in bbLean draws the menu.frame border along the entire menu edge, i.e. the
276: // menu.title border is only visible in between the title and the frame, not along the edges
277: // of the menu. As long as the menu.title and menu.frame borders are the same width and colour,
278: // this does not make any difference. But if they are not, drawing the menu border this way will
279: // create a distinct change in appearance of the menu that is often used by bbLean stylists,
280: // e.g. "Urban Tower" by Shawan -> http://www.boxshots.org/style/3889 . This is not the way the
281: // menu is rendered in our "baseline" bb4nix, but... Let's call this a Request For Comments! ;)
282: // ---------------------------------------------------------------------------------------------
283: // A variant of this bug/feature is when there is a menu.frame border but no menu.title border,
284: // e.g. cthu1hu's "ridge" style -> http://www.boxshots.org/style/4335
285:
286: RECT tempTitleRect;
287: CopyRect(&tempTitleRect, &menuTitleRect);
288: if (pSettings->MenuTitle->borderWidth == 0)
289: {
290: // InflateRect(&tempTitleRect, -pSettings->MenuFrame->borderWidth, -pSettings->MenuFrame->borderWidth);
291: // tempTitleRect.bottom += pSettings->MenuFrame->borderWidth;
292: }
293:
294: // Draw the menu title gradient, or image (stretch resized as applicable to fit the x/y dimensions of the menu item), as applicable...
295: if (pSettings->MenuTitle->type == B_IMAGEFROMFILE) DrawImageIntoRect(cachedMenuBackground, tempTitleRect, pSettings->MenuTitle, false, true);
296: else MakeGradientSuper(cachedMenuBackground, tempTitleRect, pSettings->MenuTitle->type, pSettings->MenuTitle->Color1, pSettings->MenuTitle->Color2, pSettings->MenuTitle->Color3, pSettings->MenuTitle->Color4, pSettings->MenuTitle->Color5, pSettings->MenuTitle->Color6, pSettings->MenuTitle->Color7, pSettings->MenuTitle->Color8, pSettings->MenuTitle->interlaced, pSettings->MenuTitle->bevelstyle, pSettings->MenuTitle->bevelposition, pSettings->bevelWidth, pSettings->MenuTitle->borderColor, pSettings->MenuTitle->borderWidth);
297:
298: // Draw the menu.frame border along the entire menu edge...
299: CreateBorder(cachedMenuBackground, &menuRect, pSettings->MenuFrame->borderColor, pSettings->MenuFrame->borderWidth);
300: }
301: else
302: {
303: // Draw the menu title gradient, or image (stretch resized as applicable to fit the x/y dimensions of the menu item), as applicable...
304: if (pSettings->MenuTitle->type == B_IMAGEFROMFILE) DrawImageIntoRect(cachedMenuBackground, menuTitleRect, pSettings->MenuTitle, false, true);
305: else MakeGradientSuper(cachedMenuBackground, menuTitleRect, pSettings->MenuTitle->type, pSettings->MenuTitle->Color1, pSettings->MenuTitle->Color2, pSettings->MenuTitle->Color3, pSettings->MenuTitle->Color4, pSettings->MenuTitle->Color5, pSettings->MenuTitle->Color6, pSettings->MenuTitle->Color7, pSettings->MenuTitle->Color8, pSettings->MenuTitle->interlaced, pSettings->MenuTitle->bevelstyle, pSettings->MenuTitle->bevelposition, pSettings->bevelWidth, pSettings->MenuTitle->borderColor, pSettings->MenuTitle->borderWidth);
306: }
307: }
308:
309: // Draw menu grip...
310: if (!pSettings->MenuGrip->parentRelative)
311: {
312: if ((pSettings->MenuGrip->borderColor != pSettings->MenuFrame->borderColor) || (pSettings->MenuGrip->borderWidth < pSettings->MenuFrame->borderWidth))
313: {
314: // Using the same bug/feature approach for the grip as described above for the title...
315:
316: RECT tempGripRect;
317: CopyRect(&tempGripRect, &menuGripRect);
318: if (pSettings->MenuGrip->borderWidth == 0)
319: {
320: InflateRect(&tempGripRect, -pSettings->MenuFrame->borderWidth, -pSettings->MenuFrame->borderWidth);
321: tempGripRect.top -= pSettings->MenuFrame->borderWidth;
322: }
323:
324: // Draw the menu grip gradient, or image (stretch resized as applicable to fit the x/y dimensions of the menu item), as applicable...
325: if (pSettings->MenuGrip->type == B_IMAGEFROMFILE) DrawImageIntoRect(cachedMenuBackground, tempGripRect, pSettings->MenuGrip, false, true);
326: else MakeGradientSuper(cachedMenuBackground, tempGripRect, pSettings->MenuGrip->type, pSettings->MenuGrip->Color1, pSettings->MenuGrip->Color2, pSettings->MenuGrip->Color3, pSettings->MenuGrip->Color4, pSettings->MenuGrip->Color5, pSettings->MenuGrip->Color6, pSettings->MenuGrip->Color7, pSettings->MenuGrip->Color8, pSettings->MenuGrip->interlaced, pSettings->MenuGrip->bevelstyle, pSettings->MenuGrip->bevelposition, pSettings->bevelWidth, pSettings->MenuGrip->borderColor, pSettings->MenuGrip->borderWidth);
327:
328: // Draw the menu.frame border along the menu edge, but this time only for the bottom part
329: // of the menu to avoid messing up any menu title/frame border overlaps... (see above)
330: RECT borderRect;
331: CopyRect(&borderRect, &menuRect);
332: int top = menuFrameRect.top + pSettings->MenuFrame->borderWidth + 1;
333:
334: HPEN borderPen = CreatePen(PS_SOLID, 1, pSettings->MenuFrame->borderColor);
335: HPEN oldPen = (HPEN) SelectObject(cachedMenuBackground, borderPen);
336: for (int i = 0; i < pSettings->MenuFrame->borderWidth; i++)
337: {
338: // Draw border...
339: MoveToEx(cachedMenuBackground, borderRect.left, top, NULL);
340: LineTo(cachedMenuBackground, borderRect.left, borderRect.bottom-1);
341: LineTo(cachedMenuBackground, borderRect.right-1, borderRect.bottom-1);
342: LineTo(cachedMenuBackground, borderRect.right-1, top);
343:
344: InflateRect(&borderRect, -1, -1); // Shrink rectangle by 1 pixel...
345: }
346: SelectObject(cachedMenuBackground, oldPen);
347: DeleteObject(borderPen);
348: }
349: else
350: {
351: // Draw the menu grip gradient, or image (stretch resized as applicable to fit the x/y dimensions of the menu item), as applicable...
352: if (pSettings->MenuGrip->type == B_IMAGEFROMFILE) DrawImageIntoRect(cachedMenuBackground, menuGripRect, pSettings->MenuGrip, false, true);
353: else MakeGradientSuper(cachedMenuBackground, menuGripRect, pSettings->MenuGrip->type, pSettings->MenuGrip->Color1, pSettings->MenuGrip->Color2, pSettings->MenuGrip->Color3, pSettings->MenuGrip->Color4, pSettings->MenuGrip->Color5, pSettings->MenuGrip->Color6, pSettings->MenuGrip->Color7, pSettings->MenuGrip->Color8, pSettings->MenuGrip->interlaced, pSettings->MenuGrip->bevelstyle, pSettings->MenuGrip->bevelposition, pSettings->bevelWidth, pSettings->MenuGrip->borderColor, pSettings->MenuGrip->borderWidth);
354: }
355: }
356:
357: // ##################################################################################################
358: // ##### BELOW: EXPERIMENTAL SUPPORT FOR GRADIENT BORDERS, NOT YET MEANT FOR PUBLIC CONSUMPTION #####
359: // ##################################################################################################
360: if (!pSettings->MenuFrameBorder->parentRelative && (pSettings->MenuFrame->borderWidth > 0)
361: && (pMenuCommon->m_nTitleDisabled || (pSettings->MenuFrame->borderWidth >= pSettings->MenuTitle->borderWidth))
362: && (pMenuCommon->m_nGripDisabled || (pSettings->MenuFrame->borderWidth >= pSettings->MenuGrip->borderWidth)))
363: {
364: CreateBorderSuper(cachedMenuBackground, menuRect, pSettings->MenuFrameBorder->type, pSettings->MenuFrameBorder->Color1, pSettings->MenuFrameBorder->Color2, pSettings->MenuFrameBorder->Color3, pSettings->MenuFrameBorder->Color4, pSettings->MenuFrameBorder->Color5, pSettings->MenuFrameBorder->Color6, pSettings->MenuFrameBorder->Color7, pSettings->MenuFrameBorder->Color8, pSettings->MenuFrame->borderWidth);
365: }
366:
367: DeleteObject(tempBitmap);
368:
369: //====================
370:
371: // Should the menu's corners be rounded off? If so, we need to perform some related pixel re-shuffling
372: // *before* any subsequent per pixel alpha operations... (see further below; these in turn affect pixel data)
373: if (pSettings->menuRoundedCorners)
374: {
375: if (!pMenuCommon->m_nTitleDisabled)
376: {
377: if (pSettings->MenuFrame->borderWidth >= pSettings->MenuTitle->borderWidth) PrepareCorner(cachedMenuBackground, menuRect, CORNER_TOPLEFT | CORNER_TOPRIGHT, pSettings->MenuTitle->bevelstyle, pSettings->MenuTitle->bevelposition, 1, pSettings->MenuFrame->borderWidth);
378: else PrepareCorner(cachedMenuBackground, menuRect, CORNER_TOPLEFT | CORNER_TOPRIGHT, pSettings->MenuTitle->bevelstyle, pSettings->MenuTitle->bevelposition, 1, pSettings->MenuTitle->borderWidth);
379: }
380: else PrepareCorner(cachedMenuBackground, menuRect, CORNER_TOPLEFT | CORNER_TOPRIGHT, pSettings->MenuFrame->bevelstyle, pSettings->MenuFrame->bevelposition, 1, pSettings->MenuFrame->borderWidth);
381:
382: if (!pMenuCommon->m_nGripDisabled)
383: {
384: if (pSettings->MenuFrame->borderWidth >= pSettings->MenuGrip->borderWidth) PrepareCorner(cachedMenuBackground, menuRect, CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT, pSettings->MenuGrip->bevelstyle, pSettings->MenuGrip->bevelposition, 1, pSettings->MenuFrame->borderWidth);
385: else PrepareCorner(cachedMenuBackground, menuRect, CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT, pSettings->MenuGrip->bevelstyle, pSettings->MenuGrip->bevelposition, 1, pSettings->MenuGrip->borderWidth);
386: }
387: else PrepareCorner(cachedMenuBackground, menuRect, CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT, pSettings->MenuFrame->bevelstyle, pSettings->MenuFrame->bevelposition, 1, pSettings->MenuFrame->borderWidth);
388: }
389:
390: //====================
391:
392: // We can also draw all menu items in their *non-active* state onto the same bitmap...
393: SetBkMode(cachedMenuBackground, TRANSPARENT);
394:
395: MENUITERATOR i;
396: for (i = m_MenuItems.begin(); i != m_MenuItems.end(); i++)
397: {
398: DrawMenuItem(cachedMenuBackground, (MenuItem*)(*i), false);
399: }
400:
401: //====================
402:
403: // The menu hilite/active follows the mouse pointer,
404: // so we need to be able to draw it separately from
405: // the menu title and frame, i.e. it needs its own bitmap...
406: if (cachedMenuActive) DeleteDC(cachedMenuActive);
407:
408: cachedMenuActive = CreateCompatibleDC(NULL);
409: tempBitmap = CreateCompatibleBitmap(menuHDC, menuActiveWidth, menuActiveHeight);
410: oldBitmap = (HBITMAP)SelectObject(cachedMenuActive, tempBitmap);
411: DeleteObject(oldBitmap);
412:
413: // Draw the menu active gradient, or image (stretch resized as applicable to fit the x/y dimensions of the menu item), as applicable...
414: SetRect(&r, 0, 0, menuActiveWidth, menuActiveHeight);
415: if (pSettings->MenuActive->type == B_IMAGEFROMFILE) DrawImageIntoRect(cachedMenuActive, r, pSettings->MenuActive, false, true);
416: else MakeGradientSuper(cachedMenuActive, r, pSettings->MenuActive->type, pSettings->MenuActive->Color1, pSettings->MenuActive->Color2, pSettings->MenuActive->Color3, pSettings->MenuActive->Color4, pSettings->MenuActive->Color5, pSettings->MenuActive->Color6, pSettings->MenuActive->Color7, pSettings->MenuActive->Color8, pSettings->MenuActive->interlaced, pSettings->MenuActive->bevelstyle, pSettings->MenuActive->bevelposition, pSettings->bevelWidth, pSettings->MenuActive->borderColor, pSettings->MenuActive->borderWidth);
417:
418: DeleteObject(tempBitmap);
419:
420: //====================
421:
422: // Finally, we set the "cached menu gradients created" indicator...
423: cachedMenuGradientsExist = true;
424: }
425:
426: //====================
427:
428: // Copy the cached menu background into the display buffer...
429: BitBlt(menuHDC, 0, 0, menuWidth, menuHeight, cachedMenuBackground, 0, 0, SRCCOPY);
430:
431: //====================
432:
433: // Draw the active menu item and some dynamically updating things
434: // (e.g. boolean indicators etc) on top of the copied menu background...
435: MENUITERATOR i;
436: for (i = m_MenuItems.begin(); i != m_MenuItems.end(); i++)
437: {
438: // Is this the currently active menu item?
439: if ((*i)->IsActive())
440: {
441: SetBkMode(menuHDC, TRANSPARENT);
442:
443: if (pSettings->MenuActive->type != B_PARENTRELATIVE)
444: {
445: // Unless it is parentRelative, we first copy the
446: // cached menu.active gradient into the display buffer...
447: RECT itemRect;
448: (*i)->GetItemRect(&itemRect);
449: menuActiveRect.top = itemRect.top;
450: menuActiveRect.bottom = itemRect.top + menuActiveHeight;
451: BitBlt(menuHDC, menuActiveRect.left, menuActiveRect.top, menuActiveWidth, menuActiveHeight, cachedMenuActive, 0, 0, SRCCOPY);
452: }
453:
454: // ...and then draw text, glyphs etc as applicable on top of it...
455: DrawMenuItem(menuHDC, (MenuItem*)(*i), true);
456: }
457:
458: //====================
459:
460: if ((*i)->itemType == MENUITEM_EDITSTRING)
461: {
462: StringItem* si = (StringItem*)(*i);
463: if (si->editboxActive)
464: {
465: // Draw the "OK?" button...
466: RECT itemRect;
467: (*i)->GetItemRect(&itemRect);
468: int padding = pSettings->MenuFrame->borderWidth + pSettings->MenuFrame->marginWidth;
469: InflateRect(&itemRect, -padding, 0);
470: MakeGradientSuper(menuHDC, itemRect, pSettings->MenuActive->type, pSettings->MenuActive->Color1, pSettings->MenuActive->Color2, pSettings->MenuActive->Color3, pSettings->MenuActive->Color4, pSettings->MenuActive->Color5, pSettings->MenuActive->Color6, pSettings->MenuActive->Color7, pSettings->MenuActive->Color8, pSettings->MenuActive->interlaced, pSettings->MenuActive->bevelstyle, pSettings->MenuActive->bevelposition, pSettings->bevelWidth, pSettings->MenuActive->borderColor, pSettings->MenuActive->borderWidth);
471: if (pMenuCommon->m_hFrameFont != NULL) SelectObject(menuHDC, pMenuCommon->m_hFrameFont);
472: DrawTextWithEffects(menuHDC, itemRect, "OK?", DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP, pSettings->MenuActive->TextColor, pSettings->MenuActive->FontOutline, pSettings->MenuActive->OutlineColor, pSettings->MenuActive->FontShadow, pSettings->MenuActive->ShadowColor, pSettings->MenuActive->ShadowX, pSettings->MenuActive->ShadowY);
473: }
474: }
475:
476: //====================
477:
478: if ((*i)->m_isSelected) pMenuCommon->DrawMenuIndicator((*i), menuHDC, (*i)->m_nTop);
479: }
480:
481: //====================
482:
483: // Apply per pixel alpha transparency selectively per menu element...
484: AlphaRect(menuHDC, menuRect, pSettings->menuTransparencyAlpha);
485:
486: RECT r;
487:
488: if (!pMenuCommon->m_nTitleDisabled)
489: {
490: if (pSettings->menuTitleTransparencyAlpha != pSettings->menuTransparencyAlpha)
491: {
492: SetRect(&r, pSettings->MenuFrame->borderWidth, pSettings->MenuFrame->borderWidth, menuRect.right-pSettings->MenuFrame->borderWidth, menuTitleRect.bottom);
493: AlphaRect(menuHDC, r, pSettings->menuTitleTransparencyAlpha);
494: }
495: }
496:
497: if (pSettings->menuFrameTransparencyAlpha != pSettings->menuTransparencyAlpha)
498: {
499: if (!pMenuCommon->m_nTitleDisabled)
500: {
501: if (!pMenuCommon->m_nGripDisabled) SetRect(&r, pSettings->MenuFrame->borderWidth, menuTitleRect.bottom, menuRect.right-pSettings->MenuFrame->borderWidth, menuGripRect.top-pSettings->MenuFrame->borderWidth);
502: else SetRect(&r, pSettings->MenuFrame->borderWidth, menuTitleRect.bottom, menuRect.right-pSettings->MenuFrame->borderWidth, menuRect.bottom-pSettings->MenuFrame->borderWidth);
503: }
504: else
505: {
506: if (!pMenuCommon->m_nGripDisabled) SetRect(&r, pSettings->MenuFrame->borderWidth, pSettings->MenuFrame->borderWidth, menuRect.right-pSettings->MenuFrame->borderWidth, menuGripRect.top-pSettings->MenuFrame->borderWidth);
507: else SetRect(&r, pSettings->MenuFrame->borderWidth, pSettings->MenuFrame->borderWidth, menuRect.right-pSettings->MenuFrame->borderWidth, menuRect.bottom-pSettings->MenuFrame->borderWidth);
508: }
509: AlphaRect(menuHDC, r, pSettings->menuFrameTransparencyAlpha);
510: }
511:
512: if (!pMenuCommon->m_nGripDisabled)
513: {
514: if (pSettings->menuGripTransparencyAlpha != pSettings->menuTransparencyAlpha)
515: {
516: SetRect(&r, pSettings->MenuFrame->borderWidth, menuGripRect.top, menuGripRect.right - pSettings->MenuFrame->borderWidth, menuRect.bottom - pSettings->MenuFrame->borderWidth);
517: AlphaRect(menuHDC, r, pSettings->menuGripTransparencyAlpha);
518: }
519: }
520:
521: for (i = m_MenuItems.begin(); i != m_MenuItems.end(); i++)
522: {
523: if ((*i)->m_bActive)
524: {
525: // (*i)->GetItemRect(&r);
526: // if (!pSettings->MenuActive->parentRelative) AlphaRect(menuHDC, r, pSettings->menuActiveTransparencyAlpha);
527: if (!pSettings->MenuActive->parentRelative) AlphaRect(menuHDC, menuActiveRect, pSettings->menuActiveTransparencyAlpha);
528: }
529: }
530:
531: if (pSettings->menuRoundedCorners)
532: {
533: if (!pMenuCommon->m_nTitleDisabled) AlphaCorner(menuHDC, menuRect, CORNER_TOPLEFT | CORNER_TOPRIGHT, 0, 0, 0, pSettings->MenuTitle->borderWidth, 0, pSettings->menuTransparencyAlpha);
534: else AlphaCorner(menuHDC, menuRect, CORNER_TOPLEFT | CORNER_TOPRIGHT, 0, 0, 0, pSettings->MenuFrame->borderWidth, 0, pSettings->menuTransparencyAlpha);
535: if (!pMenuCommon->m_nGripDisabled) AlphaCorner(menuHDC, menuRect, CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT, 0, 0, 0, pSettings->MenuGrip->borderWidth, 0, pSettings->menuTransparencyAlpha);
536: else AlphaCorner(menuHDC, menuRect, CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT, 0, 0, 0, pSettings->MenuFrame->borderWidth, 0, pSettings->menuTransparencyAlpha);
537: }
538:
539: AlphaApply(menuHDC, menuRect);
540:
541: //====================
542:
543: if (bufbmp) DeleteObject(bufbmp);
544:
545: POINT pt;
546: pt.x = menuX, pt.y = menuY;
547: POINT ptSrc;
548: ptSrc.x = 0, ptSrc.y = 0;
549:
550: BLENDFUNCTION bf;
551: bf.BlendOp = AC_SRC_OVER;
552: bf.BlendFlags = 0;
553: bf.AlphaFormat = AC_SRC_ALPHA;
554: bf.SourceConstantAlpha = (unsigned char)255;
555:
556: SIZE windowSize = { menuWidth, menuHeight };
557: BOOL result = UpdateLayeredWindow(hMenuWnd, NULL, &pt, &windowSize, menuHDC, &ptSrc, 0, &bf, ULW_ALPHA);
558: /*
559: if (!menuHDC) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)"xoblite -> Menu -> Invalid menuHDC!");
560:
561: if (result == 0)
562: {
563: int error = GetLastError();
564: char msg[255];
565: sprintf_s(msg, sizeofArray(msg), "xoblite -> Menu -> UpdateLayeredWindow failed! [error code %d]", error);
566: SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_ERROR_MESSAGE, (LPARAM)msg);
567: }
568: */
569: }
570:
571: //===========================================================================
572: // Function: DrawMenuItem
573: // Purpose: Support function to UpdateMenuWindow (see above)
574: //===========================================================================
575:
576: void Menu::DrawMenuItem(HDC hdc, MenuItem* i, bool active)
577: {
578: if (i->itemType == MENUITEM_MARGINPAD) return;
579:
580: SetBkMode(hdc, TRANSPARENT);
581:
582: RECT itemRect, textRect;
583: i->GetItemRect(&itemRect);
584: i->GetTitleRect(&textRect);
585:
586: //====================
587:
588: if (i->itemType == MENUITEM_FOLDER)
589: {
590: pMenuCommon->DrawMenuBullet((FolderItem*)i, hdc, itemRect.top, pMenuCommon->m_nBulletStyle);
591: }
592:
593: //====================
594:
595: if (i->itemType == MENUITEM_HEADER)
596: {
597: if (!pMenuCommon->m_nTitleDisabled)
598: {
599: // Is the menu pinned? If so, let's draw the menu pinned indicator on the title item...
600: if (IsPinned())
601: {
602: int indentText = pMenuCommon->DrawMenuPinned(i, hdc, itemRect);
603: if (pSettings->MenuTitle->Justify == DT_CENTER)
604: {
605: textRect.left = itemRect.left + indentText;
606: textRect.right = itemRect.right - indentText;
607: }
608: else if (pMenuCommon->m_nBulletPosition == DT_LEFT) textRect.right = itemRect.right - indentText;
609: else textRect.left = itemRect.left + indentText;
610: }
611:
612: // Draw the menu title text...
613: if (pMenuCommon->m_hTitleFont != NULL) SelectObject(hdc, pMenuCommon->m_hTitleFont);
614: if (wcslen(i->m_pszTitleUnicode) > 0) DrawTextWithEffectsUnicode(hdc, textRect, i->m_pszTitleUnicode, i->GetDrawTextFormat(), pSettings->MenuTitle->TextColor, pSettings->MenuTitle->FontOutline, pSettings->MenuTitle->OutlineColor, pSettings->MenuTitle->FontShadow, pSettings->MenuTitle->ShadowColor, pSettings->MenuTitle->ShadowX, pSettings->MenuTitle->ShadowY);
615: else DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuTitle->TextColor, pSettings->MenuTitle->FontOutline, pSettings->MenuTitle->OutlineColor, pSettings->MenuTitle->FontShadow, pSettings->MenuTitle->ShadowColor, pSettings->MenuTitle->ShadowX, pSettings->MenuTitle->ShadowY);
616: }
617: }
618:
619: //====================
620:
621: else if (i->itemType == MENUITEM_FOOTER)
622: {
623: if (!pSettings->MenuGrip->parentRelative)
624: {
625: if ((pSettings->MenuGrip->FontHeight > 0) && strlen(i->m_pszTitleANSI))
626: {
627: // Draw the menu grip text...
628: if (pMenuCommon->m_hGripFont != NULL) SelectObject(hdc, pMenuCommon->m_hGripFont);
629: if (wcslen(i->m_pszTitleUnicode) > 0) DrawTextWithEffectsUnicode(hdc, textRect, i->m_pszTitleUnicode, i->GetDrawTextFormat(), pSettings->MenuGrip->TextColor, pSettings->MenuGrip->FontOutline, pSettings->MenuGrip->OutlineColor, pSettings->MenuGrip->FontShadow, pSettings->MenuGrip->ShadowColor, pSettings->MenuGrip->ShadowX, pSettings->MenuGrip->ShadowY);
630: else DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuGrip->TextColor, pSettings->MenuGrip->FontOutline, pSettings->MenuGrip->OutlineColor, pSettings->MenuGrip->FontShadow, pSettings->MenuGrip->ShadowColor, pSettings->MenuGrip->ShadowX, pSettings->MenuGrip->ShadowY);
631: }
632: }
633: }
634:
635: //====================
636:
637: else if (i->itemType == MENUITEM_SEPARATOR)
638: {
639: RECT sepRect;
640: sepRect.left = itemRect.left + pSettings->MenuFrame->borderWidth + pSettings->MenuFrame->marginWidth + 3;
641: sepRect.right = itemRect.left + i->GetWidth() - pSettings->MenuFrame->borderWidth - pSettings->MenuFrame->marginWidth - 3;
642: if (pSettings->MenuSeparator->ShadowX < 0) sepRect.left -= pSettings->MenuSeparator->ShadowX;
643: else sepRect.right -= pSettings->MenuSeparator->ShadowX;
644:
645: sepRect.top = itemRect.top + (2 * pSettings->scalingFactorHiDPI);
646: sepRect.bottom = sepRect.top + (1 * pSettings->scalingFactorHiDPI);
647:
648: if (pSettings->MenuSeparator->FontShadow)
649: {
650: OffsetRect(&sepRect, pSettings->MenuSeparator->ShadowX, pSettings->MenuSeparator->ShadowY);
651: if (pSettings->MenuSeparator->type == B_MIRRORHORIZONTAL) MakeGradientSuper(hdc, sepRect, B_SPLITHORIZONTAL, GetPixel(hdc, sepRect.left, sepRect.top), pSettings->MenuSeparator->ShadowColor, pSettings->MenuSeparator->ShadowColor, GetPixel(hdc, sepRect.right, sepRect.bottom), 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
652: else MakeGradientSuper(hdc, sepRect, B_SOLID, pSettings->MenuSeparator->ShadowColor, 0, 0, 0, 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
653: OffsetRect(&sepRect, -pSettings->MenuSeparator->ShadowX, -pSettings->MenuSeparator->ShadowY);
654: }
655:
656: // MakeGradientSuper(hdc, sepRect, B_MIRRORHORIZONTAL, pSettings->MenuFrame->Color, pSettings->MenuSeparator->Color, 0, 0, 0, 0, 0, 0, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
657: MakeGradientSuper(hdc, sepRect, pSettings->MenuSeparator->type, pSettings->MenuSeparator->Color1, pSettings->MenuSeparator->Color2, pSettings->MenuSeparator->Color3, pSettings->MenuSeparator->Color4, pSettings->MenuSeparator->Color5, pSettings->MenuSeparator->Color6, pSettings->MenuSeparator->Color7, pSettings->MenuSeparator->Color8, false, BEVEL_FLAT, BEVEL1, 0, 0, 0);
658: }
659:
660: //====================
661:
662: else if (i->itemType == MENUITEM_NOP)
663: {
664: if (pMenuCommon->m_hFrameFont != NULL) SelectObject(hdc, pMenuCommon->m_hFrameFont);
665: // DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuFrame->disabledColor, pSettings->MenuFrame->FontOutline, pSettings->MenuFrame->OutlineColor, pSettings->MenuFrame->FontShadow, pSettings->MenuFrame->ShadowColor, pSettings->MenuFrame->ShadowX, pSettings->MenuFrame->ShadowY);
666: if (wcslen(i->m_pszTitleUnicode) > 0) DrawTextWithEffectsUnicode(hdc, textRect, i->m_pszTitleUnicode, i->GetDrawTextFormat(), pSettings->MenuFrame->disabledColor, false, 0, pSettings->MenuFrame->FontShadow, pSettings->MenuFrame->ShadowColor, pSettings->MenuFrame->ShadowX, pSettings->MenuFrame->ShadowY);
667: else DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuFrame->disabledColor, false, 0, pSettings->MenuFrame->FontShadow, pSettings->MenuFrame->ShadowColor, pSettings->MenuFrame->ShadowX, pSettings->MenuFrame->ShadowY);
668: }
669:
670: //====================
671:
672: else if (i->itemType == MENUITEM_EDITSTRING)
673: {
674: StringItem* si = (StringItem*)i;
675: if (!si->editboxActive)
676: {
677: // Draw the regular string item text... (i.e. OK button hidden)
678: if (pMenuCommon->m_hFrameFont != NULL) SelectObject(hdc, pMenuCommon->m_hFrameFont);
679:
680: if (wcslen(i->m_pszTitleUnicode) > 0)
681: {
682: if (active) DrawTextWithEffectsUnicode(hdc, textRect, i->m_pszTitleUnicode, i->GetDrawTextFormat(), pSettings->MenuActive->TextColor, pSettings->MenuActive->FontOutline, pSettings->MenuActive->OutlineColor, pSettings->MenuActive->FontShadow, pSettings->MenuActive->ShadowColor, pSettings->MenuActive->ShadowX, pSettings->MenuActive->ShadowY);
683: else DrawTextWithEffectsUnicode(hdc, textRect, i->m_pszTitleUnicode, i->GetDrawTextFormat(), pSettings->MenuFrame->TextColor, pSettings->MenuFrame->FontOutline, pSettings->MenuFrame->OutlineColor, pSettings->MenuFrame->FontShadow, pSettings->MenuFrame->ShadowColor, pSettings->MenuFrame->ShadowX, pSettings->MenuFrame->ShadowY);
684: }
685: else
686: {
687: if (active) DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuActive->TextColor, pSettings->MenuActive->FontOutline, pSettings->MenuActive->OutlineColor, pSettings->MenuActive->FontShadow, pSettings->MenuActive->ShadowColor, pSettings->MenuActive->ShadowX, pSettings->MenuActive->ShadowY);
688: else DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuFrame->TextColor, pSettings->MenuFrame->FontOutline, pSettings->MenuFrame->OutlineColor, pSettings->MenuFrame->FontShadow, pSettings->MenuFrame->ShadowColor, pSettings->MenuFrame->ShadowX, pSettings->MenuFrame->ShadowY);
689: }
690:
691: // if (i->m_isSelected) pMenuCommon->DrawMenuIndicator(i, hdc, i->m_nTop);
692: }
693: }
694:
695: //====================
696:
697: else // MENUITEM_COMMAND, MENUITEM_EDITINT, etc
698: {
699:
700: if (pMenuCommon->m_hFrameFont != NULL) SelectObject(hdc, pMenuCommon->m_hFrameFont);
701:
702: if (wcslen(i->m_pszTitleUnicode) > 0)
703: {
704: if (active) DrawTextWithEffectsUnicode(hdc, textRect, i->m_pszTitleUnicode, i->GetDrawTextFormat(), pSettings->MenuActive->TextColor, pSettings->MenuActive->FontOutline, pSettings->MenuActive->OutlineColor, pSettings->MenuActive->FontShadow, pSettings->MenuActive->ShadowColor, pSettings->MenuActive->ShadowX, pSettings->MenuActive->ShadowY);
705: else DrawTextWithEffectsUnicode(hdc, textRect, i->m_pszTitleUnicode, i->GetDrawTextFormat(), pSettings->MenuFrame->TextColor, pSettings->MenuFrame->FontOutline, pSettings->MenuFrame->OutlineColor, pSettings->MenuFrame->FontShadow, pSettings->MenuFrame->ShadowColor, pSettings->MenuFrame->ShadowX, pSettings->MenuFrame->ShadowY);
706: }
707: else
708: {
709: if (active) DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuActive->TextColor, pSettings->MenuActive->FontOutline, pSettings->MenuActive->OutlineColor, pSettings->MenuActive->FontShadow, pSettings->MenuActive->ShadowColor, pSettings->MenuActive->ShadowX, pSettings->MenuActive->ShadowY);
710: else DrawTextWithEffects(hdc, textRect, i->m_pszTitleANSI, i->GetDrawTextFormat(), pSettings->MenuFrame->TextColor, pSettings->MenuFrame->FontOutline, pSettings->MenuFrame->OutlineColor, pSettings->MenuFrame->FontShadow, pSettings->MenuFrame->ShadowColor, pSettings->MenuFrame->ShadowX, pSettings->MenuFrame->ShadowY);
711: }
712:
713: // if (i->m_isSelected) pMenuCommon->DrawMenuIndicator(i, hdc, i->m_nTop);
714: }
715: }
716:
717: //===========================================================================
718: // Function: Show
719: // Purpose: Shows the menu at calculated or specified screen coordinates
720: //===========================================================================
721:
722: void Menu::Show()
723: {
724: POINT p;
725: GetCursorPos(&p);
726:
727: if (m_pParent != NULL)
728: {
729: RECT r;
730: GetWindowRect(m_pParent->GetWindow(), &r);
731: int width = r.right - r.left;
732: p.x -= width / 2;
733: p.y -= pMenuCommon->m_nTitleHeight / 2;
734: Show(r.right - 5, p.y - 5);
735: }
736: else
737: {
738: RECT r;
739: GetWindowRect(GetWindow(), &r);
740: int width = r.right - r.left;
741: p.x -= width / 2;
742: p.y -= pMenuCommon->m_nTitleHeight / 2;
743: Show(p.x, p.y);
744: }
745: }
746:
747: //====================
748:
749: void Menu::Show(int x, int y)
750: {
751: OnShow(true);
752:
753: GetClientRect(hMenuWnd, &menuRect);
754: menuWidth = menuRect.right - menuRect.left;
755: menuHeight = menuRect.bottom - menuRect.top;
756:
757: //====================
758:
759: RECT screenRect;
760: POINT pt = { x ,y };
761:
762: HMONITOR hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
763:
764: MONITORINFO mi;
765: mi.cbSize = sizeof(mi);
766:
767: if (GetMonitorInfo(hMon, &mi))
768: {
769: screenRect.left = mi.rcMonitor.left;
770: screenRect.top = mi.rcMonitor.top;
771: screenRect.right = mi.rcMonitor.right;
772: screenRect.bottom = mi.rcMonitor.bottom;
773: }
774: else
775: {
776: screenRect.left = 0;
777: screenRect.top = 0;
778: screenRect.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
779: screenRect.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);
780: }
781:
782: if ((pt.x + menuWidth) > screenRect.right) pt.x = screenRect.right - menuWidth;
783: if ((pt.y + menuHeight) > screenRect.bottom) pt.y = screenRect.bottom - menuHeight;
784:
785: if (pt.x < screenRect.left) pt.x = screenRect.left;
786: if (pt.y < screenRect.top) pt.y = screenRect.top;
787:
788: menuX = pt.x;
789: menuY = pt.y;
790:
791: //====================
792:
793: UpdateMenuWindow();
794:
795: SetWindowPos(hMenuWnd, HWND_TOP, menuX, menuY, 0, 0, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOSIZE);
796: // ShowWindow(hMenuWnd, SW_SHOWNOACTIVATE);
797: ShowWindow(hMenuWnd, SW_SHOWNORMAL);
798:
799: if (m_pParent == NULL) SetForegroundWindow(hMenuWnd); // Note: Submenus set focus themselves, see FolderItem.cpp
800: }
801:
802: //===========================================================================
803: // Function: Hide
804: // Purpose: Hides the menu
805: //===========================================================================
806:
807: bool Menu::Hide(int h)
808: {
809: bool menusHaveBeenHidden = false;
810:
811: if (h != HIDE_OTHERS) // Hide this menu?
812: {
813: if (!IsPinned())
814: {
815: if (IsWindowVisible(hMenuWnd))
816: {
817: if (m_pParent != NULL) SetForegroundWindow(m_pParent->GetWindow());
818:
819: ShowWindow(hMenuWnd, SW_HIDE);
820: OnShow(false);
821:
822: // Destroy the cached menu gradients to save GDI objects + memory...
823: cachedMenuGradientsExist = false;
824: if (cachedMenuBackground) DeleteDC(cachedMenuBackground);
825: if (cachedMenuActive) DeleteDC(cachedMenuActive);
826: cachedMenuBackground = cachedMenuActive = 0;
827:
828: keyboardNavigationInProgress = false;
829:
830: menusHaveBeenHidden = true;
831: }
832: }
833:
834: MENUITERATOR item;
835: for (item = m_MenuItems.begin(); item != m_MenuItems.end(); item++)
836: {
837: (*item)->Active(false);
838:
839: if ((*item)->itemType == MENUITEM_EDITSTRING)
840: {
841: StringItem* si = (StringItem*)*item;
842: if (si->editboxActive) // Any open string editor window belonging to the menu item?
843: {
844: // If so, we destroy the string editor window and
845: // clear the global "menu item editbox open" flag...
846: si->DestroyEditWindow();
847: pSettings->menuEditboxAlreadyActive = false;
848: si->editboxActive = false;
849: }
850: }
851: }
852: }
853:
854: //====================
855:
856: if (h == HIDE_CHILDREN || h == HIDE_OTHERS) // Hide child menus?
857: {
858: for (unsigned int i = 0; i < m_Children.size(); i++)
859: {
860: // Hide all child menus of this menu...
861: if (IsWindowVisible(m_Children[i]->GetWindow()) && !m_Children[i]->IsPinned())
862: {
863: ShowWindow(m_Children[i]->GetWindow(), SW_HIDE);
864: menusHaveBeenHidden = true;
865: }
866: // Hide any lower level child menus... (i.e. children of children and downwards)
867: if (m_Children[i]->Hide(HIDE_CHILDREN)) menusHaveBeenHidden = true;
868: }
869: }
870:
871: //====================
872:
873: if (h == HIDE_PARENTS || h == HIDE_OTHERS) // Hide parent menus?
874: {
875: if (m_pParent)
876: {
877: // Hide parent menu...
878: if (IsWindowVisible(m_pParent->GetWindow()) && !m_pParent->IsPinned())
879: {
880: ShowWindow(m_pParent->GetWindow(), SW_HIDE);
881: menusHaveBeenHidden = true;
882: }
883: // Hide any higher level parent menus... (i.e. parent of parent and upwards)
884: if (m_pParent->Hide(HIDE_PARENTS)) menusHaveBeenHidden = true;
885: }
886: }
887:
888: //====================
889:
890: return menusHaveBeenHidden;
891: }
892:
893: //===========================================================================
894: // Functions: Mouse + TrackMouseProc/MouseLeave
895: // Purpose: ...
896: //===========================================================================
897:
898: void Menu::Mouse(UINT nMsg, int x, int y)
899: {
900: if (!isValidated) return;
901:
902: MENUITERATOR item;
903: POINT pt = {x, y};
904:
905: //====================
906:
907: if (!m_bMoved)
908: {
909: for (item = m_MenuItems.begin(); item != m_MenuItems.end() && !m_MenuItems.empty(); item++) // Note: By checking for the empty list we keep the core shell from crashing if a message box is opened, the shell reconfigured, and the message box closed... / Tres`ni
910: {
911: (*item)->Mouse(nMsg, pt);
912: }
913: }
914:
915: //====================
916:
917: if (nMsg == WM_MOUSEMOVE)
918: {
919: RECT r;
920: m_bMoved = false;
921: GetWindowRect(hMenuWnd, &r);
922: ClientToScreen(hMenuWnd, &pt);
923:
924: int screenTop = GetSystemMetrics(SM_YVIRTUALSCREEN);
925: int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
926:
927: if ((r.bottom > screenHeight) && (pt.y + 1 >= screenHeight))
928: {
929: // The popup is larger than the screen and the
930: // cursor is at the bottom -> scroll down a bit...
931: // r.top -= pSettings->scrollSpeed;
932: r.top -= pMenuCommon->m_nSubmenuHeight;
933: m_bMoved = true;
934: }
935: else if ((r.top < screenTop) && (pt.y <= screenTop))
936: {
937: // The popup is larger than the screen and the
938: // cursor is at the top -> scroll up at bit...
939: // r.top += pSettings->scrollSpeed;
940: r.top += pMenuCommon->m_nSubmenuHeight;
941: m_bMoved = true;
942: }
943:
944: if (m_bMoved)
945: {
946: pMenuCommon->FindActiveAndDeactivate(this, true);
947: if (pPreviewItem) pPreviewItem->Hide();
948: menuX = r.left;
949: menuY = r.top;
950: SetWindowPos(hMenuWnd, NULL, menuX, menuY, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING);
951: }
952:
953: // Track the mouse...
954: if (!mouseIsHovering)
955: {
956: mouseIsHovering = true;
957: SetTimer(hMenuWnd, MENU_TRACK_MOUSE_TIMER, 100, Menu::TrackMouseProc);
958: }
959: }
960:
961: //====================
962:
963: else if (nMsg == WM_MOUSEWHEEL)
964: {
965: if (pPreviewItem) pPreviewItem->Hide();
966:
967: RECT r;
968: GetWindowRect(hMenuWnd, &r);
969:
970: // Only allow mousewheel scrolling if the menu is taller than the screen...
971: int height = r.bottom - r.top;
972: int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
973: if (height < screenHeight) return;
974:
975: //====================
976:
977: if (x > 0) // Scrolling upwards...
978: {
979: // r.top += pSettings->wheelSpeed;
980: r.top += pMenuCommon->m_nSubmenuHeight;
981: r.bottom = r.top + height;
982:
983: if (r.top > 0)
984: {
985: r.top = 0;
986: r.bottom = height;
987: }
988: }
989: else // Scrolling downwards...
990: {
991: // r.top -= pSettings->wheelSpeed;
992: r.top -= pMenuCommon->m_nSubmenuHeight;
993: r.bottom = r.top + height;
994:
995: if (r.bottom < screenHeight)
996: {
997: r.top = screenHeight - height;
998: r.bottom = screenHeight;
999: }
1000: }
1001:
1002: //====================
1003:
1004: menuX = r.left;
1005: menuY = r.top;
1006: SetWindowPos(hMenuWnd, NULL, menuX, menuY, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING);
1007: }
1008: }
1009:
1010: //===========================================================================
1011:
1012: void Menu::TrackMouseProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
1013: {
1014: if (pSettings->menuEditboxAlreadyActive) return;
1015:
1016: POINT pt;
1017: HWND hWndNew;
1018:
1019: GetCursorPos(&pt);
1020: hWndNew = WindowFromPoint(pt);
1021:
1022: // if (hWnd != GetForegroundWindow()) SetForegroundWindow(hWnd);
1023:
1024: if (::GetParent(hWndNew) != hWnd)
1025: {
1026: RECT rect;
1027:
1028: GetClientRect(hWnd, &rect);
1029: MapWindowPoints(hWnd, NULL, (LPPOINT)&rect,2);
1030:
1031: if (!PtInRect(&rect, pt) || (hWndNew != hWnd))
1032: {
1033: KillTimer(hWnd, idEvent);
1034: PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
1035: }
1036: }
1037: }
1038:
1039: //===========================================================================
1040:
1041: void Menu::MouseLeave()
1042: {
1043: if (!isValidated) return;
1044:
1045: POINT p;
1046: HWND hWnd;
1047:
1048: GetCursorPos(&p);
1049: hWnd = WindowFromPoint(p);
1050:
1051: if (!IsChildWindow(hWnd)) pMenuCommon->FindActiveAndDeactivate(this, true);
1052: if (pPreviewItem) pPreviewItem->Hide();
1053:
1054: mouseIsHovering = false;
1055: }
1056:
1057: //===========================================================================
1058: // Function: AddMenuItem
1059: // Purpose: ...
1060: //===========================================================================
1061:
1062: void Menu::AddMenuItem(MenuItem* m)
1063: {
1064: m_MenuItems.push_back(m);
1065:
1066: // Notify the menu item that it has been attached...
1067: m->Attached(this);
1068: }
1069:
1070: //===========================================================================
1071: /*
1072: void Menu::AddMenuItem(MenuItem *m, bool (*pfnSort)(void *, MenuItem *, MenuItem *), void *pvSortParam)
1073: {
1074: MENUITERATOR i;
1075:
1076: for (i=m_MenuItems.begin(); i != m_MenuItems.end(); i++)
1077: {
1078: if (!pfnSort(pvSortParam, m, *i))
1079: {
1080: m_MenuItems.insert(i, m);
1081: break;
1082: }
1083: }
1084:
1085: if (i == m_MenuItems.end()) m_MenuItems.push_back(m);
1086:
1087: m->Attached(this);
1088: }
1089: */
1090:
1091: //===========================================================================
1092: // Function: DeleteMenuItems
1093: // Purpose: ...
1094: //===========================================================================
1095:
1096: void Menu::DeleteMenuItems()
1097: {
1098: // Block access to the menu structure until validated again...
1099: Invalidate();
1100:
1101: // Remove the menu from the set of global menues...
1102: MENUITERATOR item;
1103: for (item = m_MenuItems.begin(); item != m_MenuItems.end(); ++item)
1104: {
1105: delete *item;
1106: }
1107: m_MenuItems.clear();
1108: }
1109:
1110: //===========================================================================
1111: // Function: Activate
1112: // Purpose: Called when the menu window is activated or de-activated
1113: //===========================================================================
1114:
1115: void Menu::Activate(int fActive, HWND hWnd)
1116: {
1117: // Nothing to do here... :)
1118: }
1119:
1120: //===========================================================================
1121: // Function: IsActive
1122: // Purpose: ...
1123: //===========================================================================
1124:
1125: bool Menu::IsActive()
1126: {
1127: return GetActiveWindow() == hMenuWnd;
1128: }
1129:
1130: //===========================================================================
1131: // Function: Timer
1132: // Purpose: ...
1133: //===========================================================================
1134:
1135: void Menu::Timer(int nTimer)
1136: {
1137: if (!isValidated) return;
1138:
1139: MENUITERATOR item;
1140: for (item = m_MenuItems.begin(); item != m_MenuItems.end(); item++)
1141: {
1142: (*item)->Timer(nTimer);
1143: }
1144:
1145: OnTimer(nTimer);
1146: }
1147:
1148: //===========================================================================
1149: // Function: SetMenuFolderPath
1150: // Purpose: ...
1151: //===========================================================================
1152:
1153: void Menu::SetMenuFolderPath(char* pszFolderPath)
1154: {
1155: if (m_pszFolderPath) free(m_pszFolderPath);
1156: m_pszFolderPath = pszFolderPath ? _strdup(pszFolderPath) : _strdup("");
1157: }
1158:
1159: //===========================================================================
1160: // Function: NcHitTest
1161: // Purpose:
1162: //===========================================================================
1163:
1164: LRESULT Menu::NcHitTest(int x, int y)
1165: {
1166: if (!isValidated) return 0;
1167:
1168: LRESULT r;
1169: MENUITERATOR item;
1170:
1171: for (item=m_MenuItems.begin(); item != m_MenuItems.end(); item++)
1172: {
1173: if ((r = (*item)->NcHitTest(x, y)) != 0) return r;
1174: }
1175:
1176: return 0;
1177: }
1178:
1179: //===========================================================================
1180: // Function: GetWindow
1181: // Purpose: ...
1182: //===========================================================================
1183:
1184: HWND Menu::GetWindow()
1185: {
1186: return hMenuWnd;
1187: }
1188:
1189:
1190: //===========================================================================
1191: // Functions: SetParent/GetParent
1192: // Purpose: Sets/gets the parent menu of this menu
1193: //===========================================================================
1194:
1195: void Menu::SetParent(Menu* pParent)
1196: {
1197: m_pParent = pParent;
1198: }
1199:
1200: //====================
1201:
1202: Menu* Menu::GetParent()
1203: {
1204: return m_pParent;
1205: }
1206:
1207: //===========================================================================
1208: // Functions: AddChild/RemoveChild
1209: // Purpose: Adds/removes a child menu (submenu) to this menu
1210: //===========================================================================
1211:
1212: void Menu::AddChild(Menu* pChild)
1213: {
1214: m_Children.push_back(pChild);
1215: }
1216:
1217: //====================
1218:
1219: void Menu::RemoveChild(Menu* pChild)
1220: {
1221: for (unsigned int i=0; i<m_Children.size(); i++)
1222: {
1223: if (m_Children[i] == pChild) m_Children.erase(m_Children.begin()+i);
1224: }
1225: }
1226:
1227: //===========================================================================
1228: // Function: IsChildWindow
1229: // Purpose: Helper function that returns true if hWnd is a child of this menu
1230: //===========================================================================
1231:
1232: bool Menu::IsChildWindow(HWND hWnd)
1233: {
1234: for (unsigned int i = 0; i < m_Children.size(); i++)
1235: {
1236: if (hWnd == m_Children[i]->hMenuWnd) return true;
1237: else if (m_Children[i]->IsChildWindow(hWnd)) return true;
1238: }
1239:
1240: return false;
1241: }
1242:
1243: //===========================================================================
1244: // Function: Moving
1245: // Purpose:
1246: //===========================================================================
1247:
1248: void Menu::Moving()
1249: {
1250: if (!isValidated) return;
1251:
1252: if (pPreviewItem) pPreviewItem->Hide();
1253:
1254: MENUITERATOR item;
1255: HCURSOR hCurs = LoadCursor(NULL, IDC_SIZEALL);
1256:
1257: for (item=m_MenuItems.begin(); item != m_MenuItems.end(); item++)
1258: {
1259: (*item)->Moving();
1260: SetCursor(hCurs);
1261: }
1262: }
1263:
1264: //===========================================================================
1265: // Function: OnUser
1266: // Purpose:
1267: //===========================================================================
1268:
1269: bool Menu::OnUser(int nMessage, WPARAM wParam, LPARAM lParam, LRESULT &lResult)
1270: {
1271: if (!isValidated) return false;
1272:
1273: for (MENUITERATOR i = m_MenuItems.begin(); i != m_MenuItems.end(); i++)
1274: {
1275: if ((*i)->OnUser(nMessage, wParam, lParam, lResult)) return true;
1276: }
1277:
1278: return false;
1279: }
1280:
1281: //===========================================================================
1282: // Function: Command
1283: // Purpose:
1284: //===========================================================================
1285:
1286: LRESULT Menu::Command(WPARAM wParam, LPARAM lParam)
1287: {
1288: if (!isValidated) return 0;
1289:
1290: LRESULT l=0;
1291: MENUITERATOR item;
1292:
1293: for (item = m_MenuItems.begin(); item != m_MenuItems.end(); ++item)
1294: {
1295: l = (*item)->Command(wParam, lParam);
1296: if (l != 0) break;
1297: }
1298:
1299: return l;
1300: }
1301:
1302: //===========================================================================
1303: // Function: Sort
1304: // Purpose: Sorts the menu items in this menu
1305: //===========================================================================
1306:
1307: void Menu::Sort(int beginOffset, int endOffset)
1308: {
1309: // Sort the menu items...
1310: sort(m_MenuItems.begin()+beginOffset, m_MenuItems.end()-endOffset, MenuItem::Compare);
1311: }
1312:
1313: //===========================================================================
1314: // Functions: Invalidate/Validate
1315: // Purpose: Validates all aspects of the menu, including dimensions etc.
1316: // Invalidate() forces validation the next time Validate() is called
1317: //===========================================================================
1318:
1319: void Menu::Invalidate()
1320: {
1321: isValidated = false;
1322: }
1323:
1324: //====================
1325:
1326: void Menu::Validate()
1327: {
1328: if (isValidated) return;
1329:
1330: //====================
1331:
1332: // Calculate width padding for the menu title, frame and grip items...
1333:
1334: int titleWidthPadding;
1335: if (pSettings->MenuTitle->marginWidth > 0)
1336: {
1337: titleWidthPadding = (2 * pSettings->MenuTitle->borderWidth) + (2 * pSettings->MenuTitle->marginWidth);
1338: }
1339: else // "Legacy fallback"
1340: {
1341: titleWidthPadding = (2 * pSettings->MenuTitle->borderWidth) + (2 * pSettings->bevelWidth) + 4;
1342: }
1343: if (pSettings->MenuTitle->FontOutline) titleWidthPadding += 2;
1344:
1345: int frameWidthPadding;
1346: frameWidthPadding = pMenuCommon->m_nLeftIndent + pMenuCommon->m_nRightIndent + pSettings->bevelWidth;
1347: if (pSettings->MenuFrame->FontOutline || pSettings->MenuActive->FontOutline) frameWidthPadding += 2;
1348:
1349: int gripWidthPadding;
1350: if (pSettings->MenuGrip->marginWidth > 0)
1351: {
1352: gripWidthPadding = (2 * pSettings->MenuGrip->borderWidth) + (2 * pSettings->MenuGrip->marginWidth);
1353: }
1354: else // "Legacy fallback"
1355: {
1356: gripWidthPadding = (2 * pSettings->MenuGrip->borderWidth) + (2 * pSettings->bevelWidth) + 4;
1357: }
1358: if (pSettings->MenuGrip->FontOutline) gripWidthPadding += 2;
1359:
1360: //====================
1361:
1362: MENUITERATOR i;
1363: HDC hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
1364: HFONT hFontSaved = NULL;
1365: SIZE size;
1366: int tempMenuWidth = 0;
1367:
1368: for (i = m_MenuItems.begin(); i != m_MenuItems.end(); i++)
1369: {
1370: if ((strlen((*i)->m_pszTitleANSI) > 0) || (wcslen((*i)->m_pszTitleUnicode) > 0))
1371: {
1372: // Get the non-truncated width of this menu item's text...
1373: if ((*i)->itemType == MENUITEM_HEADER) hFontSaved = (HFONT) SelectObject(hDC, pMenuCommon->m_hTitleFont);
1374: else if ((*i)->itemType == MENUITEM_FOOTER) hFontSaved = (HFONT) SelectObject(hDC, pMenuCommon->m_hGripFont);
1375: else hFontSaved = (HFONT) SelectObject(hDC, pMenuCommon->m_hFrameFont);
1376:
1377: if (wcslen((*i)->m_pszTitleUnicode) > 0) GetTextExtentPoint32W(hDC, (*i)->m_pszTitleUnicode, wcslen((*i)->m_pszTitleUnicode), &size);
1378: else GetTextExtentPoint32(hDC, (*i)->m_pszTitleANSI, strlen((*i)->m_pszTitleANSI), &size);
1379:
1380: SelectObject(hDC, hFontSaved);
1381:
1382: if ((*i)->itemType == MENUITEM_HEADER)
1383: {
1384: if (!pSettings->MenuTitle->parentRelative && (pSettings->MenuTitle->FontHeight > 0))
1385: {
1386: (*i)->SetWidth(size.cx + 2 + titleWidthPadding);
1387: }
1388: else (*i)->SetWidth(0); // menu.title disabled, do not include it when calculating the menu width...
1389: }
1390: else if ((*i)->itemType == MENUITEM_FOOTER)
1391: {
1392: if (!pSettings->MenuGrip->parentRelative && (pSettings->MenuGrip->FontHeight > 0))
1393: {
1394: (*i)->SetWidth(size.cx + 2 + gripWidthPadding);
1395: }
1396: else (*i)->SetWidth(0); // menu.grip disabled, do not include it when calculating the menu width...
1397: }
1398: else (*i)->SetWidth(size.cx + 2 + frameWidthPadding);
1399:
1400: // Find the widest menu item belonging to this menu...
1401: tempMenuWidth = max((*i)->GetWidth(), tempMenuWidth);
1402: }
1403: }
1404:
1405: DeleteDC(hDC);
1406:
1407: //====================
1408:
1409: // Make sure that no menu item is wider than the maximum... (-> 300 pixels multiplied by the HiDPI scaling factor)
1410: tempMenuWidth = min((tempMenuWidth + (pSettings->MenuFrame->borderWidth * 2)), (300 * pSettings->scalingFactorHiDPI));
1411:
1412: //====================
1413:
1414: int tempMenuHeight = 0;
1415:
1416: if (pSettings->MenuFrame->borderWidth > pSettings->MenuTitle->borderWidth)
1417: {
1418: // Offset menu title according to bbLean bug/feature... (see above)
1419: tempMenuHeight = pSettings->MenuFrame->borderWidth - pSettings->MenuTitle->borderWidth;
1420: }
1421: else tempMenuHeight = 0;
1422: /*
1423: if (!pSettings->MenuTitle->parentRelative && ((pSettings->MenuTitle->FontHeight > 0) || (pSettings->MenuTitle->marginWidth > 0)))
1424: {
1425: if (pSettings->MenuFrame->borderWidth > pSettings->MenuTitle->borderWidth) tempMenuHeight += (pSettings->MenuFrame->borderWidth - pSettings->MenuTitle->borderWidth);
1426: }
1427: */
1428: for (i = m_MenuItems.begin(); i != m_MenuItems.end(); i++)
1429: {
1430: (*i)->SetWidth(tempMenuWidth);
1431: (*i)->SetPosition(0, tempMenuHeight);
1432:
1433: tempMenuHeight += (*i)->GetHeight();
1434: }
1435: /*
1436: if (!pSettings->MenuGrip->parentRelative && ((pSettings->MenuGrip->FontHeight > 0) || (pSettings->MenuGrip->marginWidth > 0)))
1437: {
1438: if (pSettings->MenuFrame->borderWidth > pSettings->MenuGrip->borderWidth) tempMenuHeight -= (pSettings->MenuFrame->borderWidth - pSettings->MenuGrip->borderWidth);
1439: }
1440: */
1441: //====================
1442:
1443: SetWindowPos(hMenuWnd, HWND_TOPMOST, 0, 0, tempMenuWidth, tempMenuHeight, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCOPYBITS|SWP_NOSENDCHANGING);
1444:
1445: // HRGN menuRegion = CreateRoundRectRgn(0,0,tempMenuWidth+1,tempMenuHeight+1,12,12);
1446: // SetWindowRgn(hMenuWnd, menuRegion, true);
1447: // DeleteObject(menuRegion);
1448:
1449: // Refresh menu gradients cache and repaint the window...
1450: cachedMenuGradientsExist = false;
1451: if (cachedMenuBackground) DeleteDC(cachedMenuBackground);
1452: if (cachedMenuActive) DeleteDC(cachedMenuActive);
1453: cachedMenuBackground = cachedMenuActive = 0;
1454: // UpdateMenuWindow();
1455:
1456: isValidated = true;
1457: }
1458:
1459: //===========================================================================
1460: // Functions: TogglePinned/IsPinned
1461: // Purpose:
1462: //===========================================================================
1463:
1464: void Menu::TogglePinned()
1465: {
1466: Menu* pParent = this;
1467: while (pParent->m_pParent != NULL) pParent = pParent->m_pParent;
1468: // For the time being, we do not allow pinning of plugin menus... (tbd)
1469: // if (pParent == pMenuCommon->m_pPluginMenu) return;
1470: // ...and there's no use pinning the themes menu since clicking
1471: // on a [theme] menu item will restart the core elements anyway...
1472: if (pParent == pMenuCommon->m_pThemesMenu) return;
1473:
1474: //====================
1475:
1476: if (isPinned)
1477: {
1478: // Unpin and hide the menu...
1479: isPinned = false;
1480: if (pParent == pMenuCommon->m_pStylesMenu) pMenuCommon->stylesMenusPinned--;
1481: pMenuCommon->Hide();
1482: }
1483: else
1484: {
1485: // Pin the menu...
1486: isPinned = true;
1487: if (pParent == pMenuCommon->m_pStylesMenu) pMenuCommon->stylesMenusPinned++;
1488: }
1489:
1490: Invalidate();
1491: Validate();
1492:
1493: UpdateMenuWindow();
1494: }
1495:
1496: //====================
1497:
1498: bool Menu::IsPinned()
1499: {
1500: return isPinned;
1501: };
1502:
1503: //===========================================================================
1504: // Function: ClearSelectionGroup
1505: // Purpose:
1506: //===========================================================================
1507:
1508: void Menu::ClearSelectionGroup(int group)
1509: {
1510: MENUITERATOR i;
1511: for (i = m_MenuItems.begin(); i != m_MenuItems.end(); i++)
1512: {
1513: if ((*i)->m_selectionGroup == group) (*i)->m_isSelected = false;
1514: }
1515: }
1516:
1517: //===========================================================================
1518: // Function: MenuWindowProc
1519: // Purpose: Window procedure for all popup menus
1520: //===========================================================================
1521:
1522: LRESULT CALLBACK MenuWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1523: {
1524: POINT point;
1525: Menu* p = NULL;
1526: LRESULT ret = 0;
1527:
1528: //====================
1529:
1530: // Find the menu that should receive the message...
1531: for (unsigned int i=0; i < g_Menues.size(); i++)
1532: {
1533: if (hwnd == g_Menues[i]->GetWindow())
1534: {
1535: p = g_Menues[i];
1536: break;
1537: }
1538: }
1539:
1540: // Return DefWindowProc if no matching menu could be found...
1541: if (p == NULL) return DefWindowProc(hwnd, uMsg, wParam, lParam);
1542: // ...or if the receiving menu is not validated...
1543: // if (!p->isValidated) return DefWindowProc(hwnd, uMsg, wParam, lParam);
1544:
1545: //====================
1546:
1547: if (uMsg >= WM_USER) // Nb. this includes messages such as BB_DESKTOPINFO etc
1548: {
1549: LRESULT lResult = 0;
1550:
1551: if (p->OnUser((int) uMsg, wParam, lParam, lResult)) return lResult;
1552: }
1553:
1554: //====================
1555:
1556: switch (uMsg)
1557: {
1558: case WM_NCHITTEST:
1559: {
1560: /*
1561: point.x = GET_X_LPARAM(lParam);
1562: point.y = GET_Y_LPARAM(lParam);
1563: ScreenToClient(hwnd, &point);
1564: ret = p->NcHitTest(point.x, point.y);
1565: if (ret == 0) ret = HTCLIENT;
1566: */
1567: if (!p->isValidated) return HTCLIENT;
1568:
1569: GetCursorPos(&point);
1570: ScreenToClient(hwnd, &point);
1571: RECT r;
1572: GetClientRect(hwnd, &r);
1573: r.top += pMenuCommon->m_nTitleHeight;
1574: r.bottom -= pMenuCommon->m_nGripHeight;
1575: r.left += pSettings->MenuFrame->borderWidth;
1576: r.right -= pSettings->MenuFrame->borderWidth;
1577:
1578: if (!PtInRect(&r, point))
1579: {
1580: // if (!p->GetParent() || p->IsPinned()) return HTCAPTION;
1581: return HTCAPTION; // -> PRELIMINARY: Allow dragging away submenus from its parent without prior pinning == subject to change/reversal pending any negative side-effects
1582: }
1583:
1584: return HTCLIENT;
1585: }
1586: break;
1587:
1588: //====================
1589:
1590: case WM_NCMOUSEMOVE:
1591: {
1592: if (!pSettings->menuEditboxAlreadyActive && !p->keyboardNavigationInProgress)
1593: {
1594: point.x = GET_X_LPARAM(lParam);
1595: point.y = GET_Y_LPARAM(lParam);
1596: ScreenToClient(hwnd, &point);
1597: p->Mouse(WM_MOUSEMOVE, point.x, point.y);
1598: }
1599:
1600: return 0;
1601: }
1602: break;
1603:
1604: //====================
1605:
1606: case WM_NCLBUTTONUP:
1607: case WM_NCRBUTTONUP:
1608: case WM_NCMBUTTONUP: // Midclick on title items -> Pin/Unpin menu
1609: case WM_NCLBUTTONDBLCLK: // Doubleclick on title items -> Pin/Unpin menu
1610: {
1611: point.x = GET_X_LPARAM(lParam);
1612: point.y = GET_Y_LPARAM(lParam);
1613: ScreenToClient(hwnd, &point);
1614: p->Mouse(uMsg, point.x, point.y);
1615: return 0;
1616: }
1617: break;
1618: /*
1619: case WM_NCLBUTTONDOWN:
1620: case WM_NCRBUTTONDOWN:
1621: case WM_NCMBUTTONDOWN:
1622: {
1623: return DefWindowProc(hwnd, uMsg, wParam, lParam);
1624: }
1625: break;
1626: */
1627: //====================
1628:
1629: case WM_MOUSEMOVE:
1630: {
1631: if (!pSettings->menuEditboxAlreadyActive)
1632: {
1633: // Hack to make keyboard navigation work
1634: // when the mouse is above the window...
1635: static int lastX = 0;
1636: static int lastY = 0;
1637:
1638: if (lastX == GET_X_LPARAM(lParam) && lastY == GET_Y_LPARAM(lParam))
1639: return 0;
1640:
1641: lastX = GET_X_LPARAM(lParam);
1642: lastY = GET_Y_LPARAM(lParam);
1643:
1644: p->Mouse(uMsg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
1645: }
1646:
1647: return 0;
1648: }
1649: break;
1650:
1651: //====================
1652:
1653: case WM_LBUTTONUP:
1654: case WM_RBUTTONUP:
1655: case WM_MBUTTONUP:
1656: case WM_LBUTTONDOWN:
1657: case WM_RBUTTONDOWN:
1658: case WM_MBUTTONDOWN:
1659: case WM_LBUTTONDBLCLK:
1660: {
1661: p->Mouse(uMsg, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
1662: return 0;
1663: }
1664: break;
1665:
1666: //====================
1667:
1668: case WM_EXITSIZEMOVE:
1669: {
1670: RECT r;
1671: GetWindowRect(p->GetWindow(), &r);
1672: p->menuX = r.left;
1673: p->menuY = r.top;
1674: return 0;
1675: }
1676: break;
1677:
1678: //====================
1679:
1680: case WM_MOUSEWHEEL:
1681: {
1682: if (GET_WHEEL_DELTA_WPARAM(wParam) < 0) p->Mouse(uMsg, 0, 0);
1683: else p->Mouse(uMsg, 1, 0);
1684: return 0;
1685: }
1686: break;
1687:
1688: // case WM_MOUSEHWHEEL: { } break;
1689:
1690: //====================
1691:
1692: case WM_KEYDOWN: // -> Allow keyboard navigation when the menu is the foreground window...
1693: {
1694: p->keyboardNavigationInProgress = true;
1695: KillTimer(p->GetWindow(), MENU_TRACK_MOUSE_TIMER);
1696:
1697: switch(wParam)
1698: {
1699: case VK_DOWN: // Move to the next menu item
1700: case VK_UP: // Move to the previous menu item
1701: case VK_RIGHT: // Enter submenu (if the menu item is a folder item)
1702: case VK_LEFT: // Return from submenu (moving back to the parent menu)
1703: case VK_HOME: // Jump to the first menu item
1704: case VK_END: // Jump to the last menu item
1705: case VK_SPACE: // Simulate a *right* click on command, boolean or string editing items, keeping the menu open.
1706: case VK_RETURN: // Simulate a *left* click on command items, closing the menu.
1707: case VK_PRIOR: // (PageUp) Increase the value of integer editing menu items
1708: case VK_ADD: // (NumPad Add) ...
1709: case VK_NEXT: // (PageDown) Decrease the value of integer editing menu items
1710: case VK_SUBTRACT: // (NumPad Subtract) ...
1711: {
1712: MENUITERATOR i1, i2;
1713: Menu* m = NULL;
1714:
1715: if (wParam == VK_HOME) // -> Jump to the first menu item!
1716: {
1717: pMenuCommon->FindActiveAndDeactivate(p, false);
1718: if (pPreviewItem) pPreviewItem->Hide();
1719:
1720: int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
1721: int screenY = GetSystemMetrics(SM_YVIRTUALSCREEN);
1722: if (p->menuHeight > screenHeight) p->menuY = screenY; // -> Scroll to the top if the menu is taller than the screen...
1723:
1724: i1 = p->m_MenuItems.begin() + 2; // -> Skip MENUITEM_HEADER (i.e. menu title item) and first MENUITEM_MARGINPAD (i.e. padding in between the menu title and frame)
1725: (*i1)->Active(true);
1726:
1727: if ((*i1)->itemType != MENUITEM_FOLDER) PlaySoundFX(SFX_MENU_NAVIGATE);
1728: }
1729: else if (wParam == VK_END) // -> Jump to the last menu item!
1730: {
1731: pMenuCommon->FindActiveAndDeactivate(p, false);
1732: if (pPreviewItem) pPreviewItem->Hide();
1733:
1734: int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
1735: if (p->menuHeight > screenHeight) p->menuY = screenHeight - p->menuHeight; // -> Scroll to the bottom if the menu is taller than the screen...
1736:
1737: i1 = p->m_MenuItems.end() - 3; // -> Skip MENUITEM_FOOTER (i.e. menu grip or non-visible footer item) and last MENUITEM_MARGINPAD (i.e. padding in between the menu frame and footer/grip)
1738: (*i1)->Active(true);
1739:
1740: if ((*i1)->itemType != MENUITEM_FOLDER) PlaySoundFX(SFX_MENU_NAVIGATE);
1741: }
1742: else
1743: {
1744: bool activeFound = false;
1745: for (i1 = p->m_MenuItems.begin(); i1 != p->m_MenuItems.end(); i1++)
1746: {
1747: if ((*i1)->IsActive())
1748: {
1749: m = (*i1)->m_pParent;
1750: activeFound = true;
1751: break;
1752: }
1753: }
1754:
1755: if (!activeFound)
1756: {
1757: i1 = p->m_MenuItems.begin();
1758: i1++; // Skip MENUITEM_HEADER (i.e. menu title item)
1759: i1++; // Skip first MENUITEM_MARGINPAD (i.e. padding in between the menu title and frame)
1760: (*i1)->Active(true);
1761: }
1762: else
1763: {
1764: i2 = i1;
1765:
1766: if (wParam == VK_DOWN)
1767: {
1768: while (i2 < p->m_MenuItems.end()-2)
1769: {
1770: i2++;
1771: if ((*i2)->m_pParent == m)
1772: {
1773: if ((*i2)->itemType != MENUITEM_SEPARATOR && (*i2)->itemType != MENUITEM_MARGINPAD && (*i2)->itemType != MENUITEM_FOOTER)
1774: {
1775: (*i1)->Active(false);
1776: if (pPreviewItem) pPreviewItem->Hide();
1777:
1778: // Allow menu scrolling if the menu is taller than the screen...
1779: int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
1780: if (p->menuHeight > screenHeight)
1781: {
1782: p->menuY -= pMenuCommon->m_nSubmenuHeight;
1783: if ((p->menuY + p->menuHeight) < screenHeight) p->menuY = screenHeight - p->menuHeight;
1784: }
1785:
1786: (*i2)->Active(true);
1787:
1788: if ((*i2)->itemType != MENUITEM_FOLDER) PlaySoundFX(SFX_MENU_NAVIGATE);
1789: break;
1790: }
1791: }
1792: }
1793: }
1794: else if (wParam == VK_UP)
1795: {
1796: while (i2 > p->m_MenuItems.begin()+2)
1797: {
1798: i2--;
1799: if ((*i2)->m_pParent == m)
1800: {
1801: if ((*i2)->itemType != MENUITEM_SEPARATOR && (*i2)->itemType != MENUITEM_MARGINPAD && (*i2)->itemType != MENUITEM_HEADER)
1802: {
1803: (*i1)->Active(false);
1804: if (pPreviewItem) pPreviewItem->Hide();
1805:
1806: // Allow menu scrolling if the menu is taller than the screen...
1807: int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
1808: if (p->menuHeight > screenHeight)
1809: {
1810: p->menuY += pMenuCommon->m_nSubmenuHeight;
1811: int screenY = GetSystemMetrics(SM_YVIRTUALSCREEN);
1812: if (p->menuY > screenY) p->menuY = screenY;
1813: }
1814:
1815: (*i2)->Active(true);
1816:
1817: if ((*i2)->itemType != MENUITEM_FOLDER) PlaySoundFX(SFX_MENU_NAVIGATE);
1818: break;
1819: }
1820: }
1821: }
1822: }
1823: else if (wParam == VK_RIGHT)
1824: {
1825: if ((*i1)->itemType == MENUITEM_FOLDER)
1826: {
1827: FolderItem* item = (FolderItem*)*i1;
1828: item->ShowSubMenu();
1829: SetForegroundWindow((*i1)->m_pSubMenu->GetWindow());
1830: SendMessage((*i1)->m_pSubMenu->GetWindow(), WM_KEYDOWN, VK_HOME, NULL);
1831: return 0;
1832: }
1833: }
1834: else if (wParam == VK_LEFT)
1835: {
1836: if ((*i1)->m_pParent->GetParent() != NULL)
1837: {
1838: (*i1)->Active(false);
1839: (*i1)->m_pParent->Hide(HIDE_THIS);
1840: if (pPreviewItem) pPreviewItem->Hide();
1841: Menu* parentMenu = (*i1)->m_pParent->GetParent();
1842: SetForegroundWindow(parentMenu->GetWindow());
1843: PlaySoundFX(SFX_MENU_NAVIGATE);
1844: }
1845: }
1846: else if (wParam == VK_SPACE)
1847: {
1848: if (((*i1)->itemType == MENUITEM_COMMAND) || ((*i1)->itemType == MENUITEM_BOOLEAN) || ((*i1)->itemType == MENUITEM_EDITSTRING)) (*i1)->Invoke(2); // -> Simulating a *right* click on command, boolean or string editing items, keeping the menu open...
1849: return 0;
1850: }
1851: else if (wParam == VK_RETURN)
1852: {
1853: if (((*i1)->itemType == MENUITEM_COMMAND)) (*i1)->Invoke(1); // -> Simulating a *left* click on command items, closing the menu.
1854: return 0;
1855: }
1856: else if ((wParam == VK_PRIOR) || (wParam == VK_ADD))
1857: {
1858: if ((*i1)->itemType == MENUITEM_EDITINT)
1859: {
1860: POINT pt;
1861: pt.x = (*i1)->m_nLeft + (*i1)->m_nWidth - 1; // Simulating a mouse click on the right hand side of the menu item -> Increase value!
1862: pt.y = (*i1)->m_nTop;
1863: (*i1)->Mouse(WM_LBUTTONUP, pt);
1864: return 0;
1865: }
1866: }
1867: else if ((wParam == VK_NEXT) || (wParam == VK_SUBTRACT))
1868: {
1869: if ((*i1)->itemType == MENUITEM_EDITINT)
1870: {
1871: POINT pt;
1872: pt.x = (*i1)->m_nLeft + 1; // Simulating a mouse click on the left hand side of the menu item -> Decrease value!
1873: pt.y = (*i1)->m_nTop;
1874: (*i1)->Mouse(WM_LBUTTONUP, pt);
1875: return 0;
1876: }
1877: }
1878: }
1879: }
1880:
1881: // p->UpdateMenuWindow();
1882: return 0;
1883: }
1884: break;
1885:
1886: case VK_INSERT: // Toggle menu pinned
1887: {
1888: // if (!p->isPinned) p->isPinned = true;
1889: // else p->isPinned = false;
1890: // p->UpdateMenuWindow();
1891: p->TogglePinned();
1892: return 0;
1893: }
1894: break;
1895:
1896: case VK_ESCAPE: // Close the menu
1897: case VK_DELETE:
1898: {
1899: if (pPreviewItem) pPreviewItem->Hide();
1900: if (pMenuCommon) pMenuCommon->Hide();
1901: return 0;
1902: }
1903: break;
1904:
1905: default: { return 0; }
1906: }
1907: }
1908: break;
1909:
1910: //====================
1911:
1912: case WM_CHAR: // -> Allow keyboard search on the *first* character of menu item titles when the menu is the foreground window...
1913: {
1914: p->keyboardNavigationInProgress = true;
1915: KillTimer(p->GetWindow(), MENU_TRACK_MOUSE_TIMER);
1916:
1917: char typeAhead = tolower((char)wParam); // If applicable, use the lowercase version of the character...
1918:
1919: MENUITERATOR i;
1920: bool activeFound = false, searchFound = false;
1921:
1922: for (i = p->m_MenuItems.begin()+2; i != p->m_MenuItems.end()-2; i++) // Skip MENUITEM_HEADER/MARGINPAD/FOOTER items...
1923: {
1924: if (!activeFound)
1925: {
1926: // Skip up to the currently active menu item... (i.e. accept any *following* match)
1927: if ((*i)->IsActive()) activeFound = true;
1928: continue;
1929: }
1930:
1931: if (((tolower((*i)->m_pszTitleANSI[0]) == typeAhead)))
1932: {
1933: searchFound = true;
1934: pMenuCommon->ScrollToItem(p, (*i));
1935: break;
1936: }
1937: }
1938:
1939: if (!searchFound)
1940: {
1941: for (i = p->m_MenuItems.begin()+2; i != p->m_MenuItems.end()-2; i++) // Skip MENUITEM_HEADER/MARGINPAD/FOOTER items...
1942: {
1943: if (((tolower((*i)->m_pszTitleANSI[0]) == typeAhead))) // Accept *any* match...
1944: {
1945: pMenuCommon->ScrollToItem(p, (*i));
1946: break;
1947: }
1948: }
1949: }
1950:
1951: return 0;
1952: }
1953:
1954: //====================
1955:
1956: case WM_CLOSE:
1957: return 0;
1958:
1959: //====================
1960:
1961: case WM_ACTIVATE:
1962: {
1963: p->Activate(LOWORD(wParam), (HWND)lParam);
1964: }
1965: break;
1966:
1967: //====================
1968:
1969: case WM_TIMER:
1970: {
1971: p->Timer(wParam);
1972: return 0;
1973: }
1974: break;
1975:
1976: //====================
1977:
1978: case WM_MOVING:
1979: {
1980: p->Moving();
1981: }
1982: break;
1983:
1984: //====================
1985: /*
1986: case WM_WINDOWPOSCHANGING:
1987: {
1988: if (IsWindowVisible(hwnd)) SnapWindowToEdge((WINDOWPOS*)lParam, pSettings->edgeSnapThreshold, true);
1989: }
1990: break;
1991: */
1992: //====================
1993: /*
1994: case WM_ERASEBKGND:
1995: return true;
1996: */
1997: //====================
1998:
1999: case WM_COMMAND:
2000: {
2001: if (pSettings->menuEditboxAlreadyActive)
2002: {
2003: // char msg[300];
2004: // if (HIWORD(wParam) == EN_CHANGE) sprintf_s(msg, sizeofArray(msg), "Menu -> WM_COMMAND -> EN_CHANGE received...");
2005: // else if (HIWORD(wParam) == EN_UPDATE) sprintf_s(msg, sizeofArray(msg), "Menu -> WM_COMMAND -> EN_UPDATE received...");
2006: // else sprintf_s(msg, sizeofArray(msg), "Menu -> WM_COMMAND -> Unknown message received... -> 0x%x", (int)wParam);
2007: // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
2008: return 0;
2009: }
2010: else p->Command(wParam, lParam);
2011: }
2012: break;
2013:
2014: //====================
2015:
2016: case WM_MOUSELEAVE:
2017: {
2018: p->MouseLeave();
2019: }
2020: break;
2021:
2022: //====================
2023: /*
2024: case WM_DROPFILES:
2025: {
2026: static TCHAR source[MAX_LINE_LENGTH];
2027: DragQueryFile((HDROP)wParam, 0, source, sizeof(source));
2028: DragFinish((HDROP)wParam);
2029:
2030: RECT r;
2031: MENUITERATOR item;
2032: for (item = p->m_MenuItems.begin(); item != p->m_MenuItems.end() && !p->m_MenuItems.empty(); item++)
2033: {
2034: POINT mousepos;
2035: GetCursorPos(&mousepos);
2036: ScreenToClient(hwnd, &mousepos);
2037: (*item)->GetItemRect(&r);
2038:
2039: if (PtInRect(&r, mousepos) && (*item)->itemType == MENUITEM_COMMAND)
2040: {
2041: if (!strlen((*item)->m_pszArgument)) break;
2042:
2043: char destination[MAX_PATH];
2044: strcpy_s(destination, sizeofArray(destination), (*item)->m_pszArgument);
2045: if (destination[0] == '\"') StrRemoveEncap(destination);
2046: if (destination[1] == ':')
2047: {
2048: if (source[0] == '\"') StrRemoveEncap(source);
2049: char tempSource[MAX_PATH];
2050: strcpy_s(tempSource, sizeofArray(tempSource), source);
2051: int n = GetParentFolder(tempSource);
2052:
2053: GetParentFolder(destination);
2054: strcat_s(destination, sizeofArray(destination), &source[n]);
2055:
2056: // Move file from the source folder to the destination folder...
2057: MoveFile(source, destination);
2058:
2059: // Look for a line that should "always" exist in a style file; if it
2060: // does we create a [style] menu item, otherwise an [exec] menu item...
2061: char cmd[8];
2062: if (strlen(ReadString(destination, "menu.frame", ""))) strcpy_s(cmd, sizeofArray(cmd), "[style]");
2063: else strcpy_s(cmd, sizeofArray(cmd), "[exec]");
2064:
2065: // Create a new menu item for the moved file in the destination menu...
2066: // (note that this new menu item gets added *after* the bottom items,
2067: // so we need to sort the menu items afterwards)...
2068: pMenuCommon->CreateMenuItem(p, MENUITEM_COMMAND, cmd, destination, &source[n], false);
2069: p->Sort(2,0); // Skip the header item and top marginWidth padding item...
2070:
2071: // Recalculate menu dimensions and redraw window...
2072: p->Invalidate();
2073: p->Validate();
2074: }
2075: break;
2076: }
2077: }
2078:
2079: return 0;
2080: }
2081: break;
2082: */
2083: //====================
2084:
2085: case BB_RECONFIGURE:
2086: case BB_REDRAWGUI:
2087: {
2088: if ((uMsg == BB_REDRAWGUI) && !(wParam & BBRG_MENU)) break;
2089:
2090: // Block access to the menu...
2091: p->Invalidate();
2092:
2093: // Set new menu item dimensions based on values calculated in MenuCommon...
2094: MENUITERATOR m;
2095: for (m = p->m_MenuItems.begin(); m != p->m_MenuItems.end(); m++)
2096: {
2097: if ((*m)->itemType == MENUITEM_HEADER) (*m)->SetHeight(pMenuCommon->m_nTitleHeight);
2098: else if ((*m)->itemType == MENUITEM_SEPARATOR) (*m)->SetHeight(pMenuCommon->m_nSeparatorHeight);
2099: else if ((*m)->itemType == MENUITEM_MARGINPAD) (*m)->SetHeight(pMenuCommon->m_nMarginHeight);
2100: else if ((*m)->itemType == MENUITEM_FOOTER) (*m)->SetHeight(pMenuCommon->m_nGripHeight);
2101: else (*m)->SetHeight(pMenuCommon->m_nSubmenuHeight);
2102: }
2103:
2104: // Recalculate the menu dimensions...
2105: p->Validate();
2106: // ...and update the menu window if its currently visible...
2107: if (IsWindowVisible(p->hMenuWnd)) p->UpdateMenuWindow();
2108: }
2109: break;
2110:
2111: //====================
2112:
2113: case BB_MENU:
2114: {
2115: Menu* pMenu = NULL;
2116:
2117: if (wParam == 0) // Main menu
2118: {
2119: WIN32_FIND_DATA oldData = p->data;
2120: HANDLE hFind = FindFirstFile(pSettings->menuFile, &p->data);
2121: FindClose(hFind);
2122: if (CompareFileTime(&p->data.ftLastWriteTime, &oldData.ftLastWriteTime) == 1)
2123: {
2124: pMenuCommon->Hide();
2125: pMenuCommon->UpdateMainMenu(false);
2126: }
2127:
2128: pMenu = pMenuCommon->m_pMainMenu;
2129: }
2130: else if (wParam == 1) // Workspaces menu
2131: {
2132: pMenu = pMenuCommon->m_pWorkspacesMenu;
2133: }
2134: else if (wParam == 2 || wParam == 3 || wParam == 4) // Configuration menu (nb. previously used for the legacy Toolbar/Systembar/Dock menus, now replaced with the common Configuration menu)
2135: {
2136: pMenu = pMenuCommon->m_pConfigMenu;
2137: }
2138: else if (wParam == 5) // Styles menu
2139: {
2140: pMenu = pMenuCommon->m_pStylesMenu;
2141: }
2142: else if (wParam == 6) // Themes menu
2143: {
2144: pMenu = pMenuCommon->m_pThemesMenu;
2145: }
2146:
2147: if (pMenu != NULL)
2148: {
2149: pMenuCommon->Hide();
2150: pMenu->Show();
2151: }
2152: }
2153: break;
2154:
2155: //====================
2156:
2157: case BB_HIDEMENU:
2158: {
2159: pMenuCommon->Hide();
2160: // p->Hide(HIDE_PARENTS);
2161: // p->Hide(HIDE_CHILDREN);
2162: }
2163: break;
2164:
2165: //====================
2166:
2167: case WM_CTLCOLOREDIT: // -> Used by StringItem editor popup dialog windows
2168: {
2169: // SetTextColor((HDC)wParam, pSettings->MenuFrame->TextColor);
2170: // SetBkColor((HDC)wParam, pSettings->MenuFrame->Color);
2171: SetTextColor((HDC)wParam, 0x000000);
2172: SetBkColor((HDC)wParam, 0xffffff);
2173: return (LRESULT)GetStockObject(NULL_BRUSH);
2174: }
2175: break;
2176:
2177: //====================
2178:
2179: default:
2180: {
2181: ret = DefWindowProc(hwnd, uMsg, wParam, lParam);
2182: }
2183:
2184: //====================
2185: }
2186:
2187: return ret;
2188: }
2189:
2190: //===========================================================================
2191: