4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
9 * Note: the style MF_MOUSESELECT is used to mark popup items that
10 * have been selected, i.e. their popup menu is currently displayed.
11 * This is probably not the meaning this style has in MS-Windows.
20 #include "sysmetrics.h"
30 /* Dimension of the menu bitmaps */
31 static WORD check_bitmap_width
= 0, check_bitmap_height
= 0;
32 static WORD arrow_bitmap_width
= 0, arrow_bitmap_height
= 0;
34 /* Flag set by EndMenu() to force an exit from menu tracking */
35 static BOOL fEndMenuCalled
= FALSE
;
37 /* Space between 2 menu bar items */
38 #define MENU_BAR_ITEMS_SPACE 16
40 /* Minimum width of a tab character */
41 #define MENU_TAB_SPACE 8
43 /* Height of a separator item */
44 #define SEPARATOR_HEIGHT 5
46 /* Values for menu->FocusedItem */
47 /* (other values give the position of the focused item) */
48 #define NO_SELECTED_ITEM 0xffff
49 #define SYSMENU_SELECTED 0xfffe /* Only valid on menu-bars */
51 #define IS_STRING_ITEM(flags) (!((flags) & (MF_BITMAP | MF_OWNERDRAW | \
52 MF_MENUBARBREAK | MF_MENUBREAK | MF_SEPARATOR)))
55 extern void NC_DrawSysButton(HWND hwnd
, HDC hdc
, BOOL down
); /* nonclient.c */
57 static HBITMAP hStdCheck
= 0;
58 static HBITMAP hStdMnArrow
= 0;
60 WORD
* ParseMenuResource(WORD
*first_item
, int level
, HMENU hMenu
);
63 /***********************************************************************
66 * Menus initialisation.
74 if (!(hStdCheck
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_CHECK
) )))
76 GetObject( hStdCheck
, sizeof(BITMAP
), (LPSTR
)&bm
);
77 check_bitmap_width
= bm
.bmWidth
;
78 check_bitmap_height
= bm
.bmHeight
;
79 if (!(hStdMnArrow
= LoadBitmap( 0, MAKEINTRESOURCE(OBM_MNARROW
) )))
81 GetObject( hStdMnArrow
, sizeof(BITMAP
), (LPSTR
)&bm
);
82 arrow_bitmap_width
= bm
.bmWidth
;
83 arrow_bitmap_height
= bm
.bmHeight
;
89 /***********************************************************************
92 * Check whether the window owning the menu bar has a system menu.
94 static BOOL
MENU_HasSysMenu( POPUPMENU
*menu
)
98 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
99 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
100 return (wndPtr
->dwStyle
& WS_SYSMENU
) != 0;
104 /**********************************************************************
107 static HMENU
MENU_CopySysMenu(void)
113 if (!(handle
= SYSRES_LoadResource( SYSRES_MENU_SYSMENU
))) return 0;
114 hMenu
= LoadMenuIndirect( GlobalLock( handle
) );
115 SYSRES_FreeResource( handle
);
118 dprintf_menu(stddeb
,"No SYSMENU\n");
121 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(hMenu
);
122 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
123 dprintf_menu(stddeb
,"CopySysMenu hMenu="NPFMT
" !\n", hMenu
);
128 /***********************************************************************
131 * Check whether the point (in screen coords) is in the system menu
132 * of the window owning the given menu.
134 static BOOL
MENU_IsInSysMenu( POPUPMENU
*menu
, POINT pt
)
138 if (menu
->wFlags
& MF_POPUP
) return FALSE
;
139 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return FALSE
;
140 if (!(wndPtr
->dwStyle
& WS_SYSMENU
)) return FALSE
;
141 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
142 (pt
.x
>= wndPtr
->rectClient
.left
+SYSMETRICS_CXSIZE
+SYSMETRICS_CXBORDER
))
144 if ((pt
.y
>= wndPtr
->rectClient
.top
- menu
->Height
) ||
145 (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
-
146 SYSMETRICS_CYSIZE
- SYSMETRICS_CYBORDER
)) return FALSE
;
151 /***********************************************************************
154 * Find a menu item. Return a pointer on the item, and modifies *hmenu
155 * in case the item was in a sub-menu.
157 static MENUITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
163 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR(*hmenu
))) return NULL
;
164 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
165 if (wFlags
& MF_BYPOSITION
)
167 if (*nPos
>= menu
->nItems
) return NULL
;
172 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
174 if (item
->item_id
== *nPos
)
179 else if (item
->item_flags
& MF_POPUP
)
181 HMENU hsubmenu
= (HMENU
)item
->item_id
;
182 MENUITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
195 /***********************************************************************
196 * MENU_FindItemByCoords
198 * Find the item at the specified coordinates (screen coords).
200 static MENUITEM
*MENU_FindItemByCoords( POPUPMENU
*menu
, int x
, int y
, UINT
*pos
)
206 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return NULL
;
207 x
-= wndPtr
->rectWindow
.left
;
208 y
-= wndPtr
->rectWindow
.top
;
209 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
210 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
212 if ((x
>= item
->rect
.left
) && (x
< item
->rect
.right
) &&
213 (y
>= item
->rect
.top
) && (y
< item
->rect
.bottom
))
223 /***********************************************************************
226 * Find the menu item selected by a key press.
227 * Return item id, -1 if none, -2 if we should close the menu.
229 static UINT
MENU_FindItemByKey( HWND hwndOwner
, HMENU hmenu
, UINT key
)
236 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
237 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
239 for (i
= 0; i
< menu
->nItems
; i
++, lpitem
++)
241 if (IS_STRING_ITEM(lpitem
->item_flags
))
243 char *p
= strchr( lpitem
->item_text
, '&' );
244 if (p
&& (p
[1] != '&') && (toupper(p
[1]) == key
)) return i
;
248 menuchar
= SendMessage( hwndOwner
, WM_MENUCHAR
,
249 MAKEWPARAM(key
,menu
->wFlags
), (LPARAM
)hmenu
);
251 menuchar
= SendMessage( hwndOwner
, WM_MENUCHAR
, key
,
252 MAKELONG( menu
->wFlags
, hmenu
) );
254 if (HIWORD(menuchar
) == 2) return LOWORD(menuchar
);
255 if (HIWORD(menuchar
) == 1) return -2;
260 /***********************************************************************
263 * Calculate the size of the menu item and store it in lpitem->rect.
265 static void MENU_CalcItemSize( HDC hdc
, LPMENUITEM lpitem
, HWND hwndOwner
,
266 int orgX
, int orgY
, BOOL menuBar
)
271 SetRect( &lpitem
->rect
, orgX
, orgY
, orgX
, orgY
);
273 if (lpitem
->item_flags
& MF_OWNERDRAW
) {
274 static HANDLE mistrh
= 0;
275 static SEGPTR mistrsegp
= 0;
276 static LPMEASUREITEMSTRUCT mistruct
=NULL
;
277 if (mistruct
== NULL
) {
278 mistrh
= GlobalAlloc(0,sizeof(MEASUREITEMSTRUCT
));
279 mistrsegp
= (SEGPTR
)WIN16_GlobalLock(mistrh
);
280 mistruct
= PTR_SEG_TO_LIN(mistrsegp
);
282 mistruct
->CtlType
= ODT_MENU
;
283 mistruct
->itemID
= lpitem
->item_id
;
284 mistruct
->itemData
= (long int)lpitem
->item_text
;
285 mistruct
->itemHeight
= 16;
286 mistruct
->itemWidth
= 30;
287 SendMessage(hwndOwner
,WM_MEASUREITEM
,0,(LPARAM
)mistrsegp
);
288 lpitem
->rect
.bottom
+= mistruct
->itemHeight
;
289 lpitem
->rect
.right
+= mistruct
->itemWidth
;
290 dprintf_menu(stddeb
,"DrawMenuItem: MeasureItem %04x %d:%d!\n",
291 lpitem
->item_id
,mistruct
->itemWidth
, mistruct
->itemHeight
);
295 if (lpitem
->item_flags
& MF_SEPARATOR
)
297 lpitem
->rect
.bottom
+= SEPARATOR_HEIGHT
;
303 lpitem
->rect
.right
+= 2 * check_bitmap_width
;
304 if (lpitem
->item_flags
& MF_POPUP
)
305 lpitem
->rect
.right
+= arrow_bitmap_width
;
308 if (lpitem
->item_flags
& MF_BITMAP
)
311 GetObject( (HBITMAP
)lpitem
->hText
, sizeof(BITMAP
), (LPSTR
)&bm
);
312 lpitem
->rect
.right
+= bm
.bmWidth
;
313 lpitem
->rect
.bottom
+= bm
.bmHeight
;
317 /* If we get here, then it is a text item */
319 dwSize
= (lpitem
->item_text
== NULL
) ? 0 : GetTextExtent( hdc
, lpitem
->item_text
, strlen(lpitem
->item_text
));
320 lpitem
->rect
.right
+= LOWORD(dwSize
);
321 lpitem
->rect
.bottom
+= MAX( HIWORD(dwSize
), SYSMETRICS_CYMENU
);
323 if (menuBar
) lpitem
->rect
.right
+= MENU_BAR_ITEMS_SPACE
;
324 else if ( ( lpitem
->item_text
!= NULL
) && (p
= strchr( lpitem
->item_text
, '\t' )) != NULL
)
326 /* Item contains a tab (only meaningful in popup menus) */
327 lpitem
->xTab
= check_bitmap_width
+ MENU_TAB_SPACE
+
328 LOWORD( GetTextExtent( hdc
, lpitem
->item_text
,
329 (int)(p
- lpitem
->item_text
) ));
330 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
334 if( ( lpitem
->item_text
!= NULL
) && strchr( lpitem
->item_text
, '\b' ))
335 lpitem
->rect
.right
+= MENU_TAB_SPACE
;
336 lpitem
->xTab
= lpitem
->rect
.right
- check_bitmap_width
337 - arrow_bitmap_width
;
342 /***********************************************************************
343 * MENU_PopupMenuCalcSize
345 * Calculate the size of a popup menu.
347 static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop
, HWND hwndOwner
)
349 LPMENUITEM items
, lpitem
;
352 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
;
354 lppop
->Width
= lppop
->Height
= 0;
355 if (lppop
->nItems
== 0) return;
356 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
359 while (start
< lppop
->nItems
)
361 lpitem
= &items
[start
];
364 maxTab
= maxTabWidth
= 0;
366 /* Parse items until column break or end of menu */
367 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
370 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
371 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, FALSE
);
372 if (lpitem
->item_flags
& MF_MENUBARBREAK
) orgX
++;
373 maxX
= MAX( maxX
, lpitem
->rect
.right
);
374 orgY
= lpitem
->rect
.bottom
;
377 maxTab
= MAX( maxTab
, lpitem
->xTab
);
378 maxTabWidth
= MAX(maxTabWidth
,lpitem
->rect
.right
-lpitem
->xTab
);
382 /* Finish the column (set all items to the largest width found) */
383 maxX
= MAX( maxX
, maxTab
+ maxTabWidth
);
384 for (lpitem
= &items
[start
]; start
< i
; start
++, lpitem
++)
386 lpitem
->rect
.right
= maxX
;
387 if (lpitem
->xTab
) lpitem
->xTab
= maxTab
;
389 lppop
->Height
= MAX( lppop
->Height
, orgY
);
397 /***********************************************************************
398 * MENU_MenuBarCalcSize
400 * Calculate the size of the menu bar.
402 static void MENU_MenuBarCalcSize( HDC hdc
, LPRECT lprect
, LPPOPUPMENU lppop
,
405 LPMENUITEM lpitem
, items
;
406 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
408 if ((lprect
== NULL
) || (lppop
== NULL
)) return;
409 if (lppop
->nItems
== 0) return;
410 dprintf_menucalc(stddeb
,"MenuBarCalcSize left=%ld top=%ld right=%ld bottom=%ld !\n",
411 (LONG
)lprect
->left
, (LONG
)lprect
->top
, (LONG
)lprect
->right
, (LONG
)lprect
->bottom
);
412 items
= (MENUITEM
*)USER_HEAP_LIN_ADDR( lppop
->hItems
);
413 lppop
->Width
= lprect
->right
- lprect
->left
;
418 while (start
< lppop
->nItems
)
420 lpitem
= &items
[start
];
424 /* Parse items until line break or end of menu */
425 for (i
= start
; i
< lppop
->nItems
; i
++, lpitem
++)
427 if ((helpPos
== -1) && (lpitem
->item_flags
& MF_HELP
)) helpPos
= i
;
429 (lpitem
->item_flags
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
430 MENU_CalcItemSize( hdc
, lpitem
, hwndOwner
, orgX
, orgY
, TRUE
);
431 if (lpitem
->rect
.right
> lprect
->right
)
433 if (i
!= start
) break;
434 else lpitem
->rect
.right
= lprect
->right
;
436 maxY
= MAX( maxY
, lpitem
->rect
.bottom
);
437 orgX
= lpitem
->rect
.right
;
440 /* Finish the line (set all items to the largest height found) */
441 while (start
< i
) items
[start
++].rect
.bottom
= maxY
;
444 lprect
->bottom
= maxY
;
445 lppop
->Height
= lprect
->bottom
- lprect
->top
;
447 /* Flush right all items between the MF_HELP and the last item */
448 /* (if several lines, only move the last line) */
451 lpitem
= &items
[lppop
->nItems
-1];
452 orgY
= lpitem
->rect
.top
;
453 orgX
= lprect
->right
;
454 for (i
= lppop
->nItems
- 1; i
>= helpPos
; i
--, lpitem
--)
456 if (lpitem
->rect
.top
!= orgY
) break; /* Other line */
457 if (lpitem
->rect
.right
>= orgX
) break; /* Too far right already */
458 lpitem
->rect
.left
+= orgX
- lpitem
->rect
.right
;
459 lpitem
->rect
.right
= orgX
;
460 orgX
= lpitem
->rect
.left
;
466 /***********************************************************************
469 * Draw a single menu item.
471 static void MENU_DrawMenuItem( HWND hwnd
, HDC hdc
, LPMENUITEM lpitem
,
472 UINT height
, BOOL menuBar
)
476 if (lpitem
->item_flags
& MF_OWNERDRAW
) {
477 static HANDLE distrh
= 0;
478 static SEGPTR distrsegp
= 0;
479 static LPDRAWITEMSTRUCT distruct
=NULL
;
480 if (distruct
== NULL
) {
481 distrh
= GlobalAlloc(0,sizeof(DRAWITEMSTRUCT
));
482 distrsegp
= (SEGPTR
)WIN16_GlobalLock(distrh
);
483 distruct
= PTR_SEG_TO_LIN(distrsegp
);
485 dprintf_menu(stddeb
,"DrawMenuItem: Ownerdraw!\n");
486 distruct
->CtlType
= ODT_MENU
;
487 distruct
->itemID
= lpitem
->item_id
;
488 distruct
->itemData
= (long int)lpitem
->item_text
;
489 distruct
->itemState
= 0;
490 if (lpitem
->item_flags
& MF_CHECKED
) distruct
->itemState
|= ODS_CHECKED
;
491 if (lpitem
->item_flags
& MF_GRAYED
) distruct
->itemState
|= ODS_GRAYED
;
492 if (lpitem
->item_flags
& MF_HILITE
) distruct
->itemState
|= ODS_SELECTED
;
493 distruct
->itemAction
= ODA_DRAWENTIRE
| ODA_SELECT
| ODA_FOCUS
;
494 distruct
->hwndItem
= hwnd
;
496 distruct
->rcItem
= lpitem
->rect
;
497 SendMessage(hwnd
,WM_DRAWITEM
,0,(LPARAM
)distrsegp
);
500 if (menuBar
&& (lpitem
->item_flags
& MF_SEPARATOR
)) return;
503 /* Draw the background */
505 if (lpitem
->item_flags
& MF_HILITE
)
506 FillRect( hdc
, &rect
, sysColorObjects
.hbrushHighlight
);
507 else FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
508 SetBkMode( hdc
, TRANSPARENT
);
510 /* Draw the separator bar (if any) */
512 if (!menuBar
&& (lpitem
->item_flags
& MF_MENUBARBREAK
))
514 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
515 MoveTo( hdc
, rect
.left
, 0 );
516 LineTo( hdc
, rect
.left
, height
);
518 if (lpitem
->item_flags
& MF_SEPARATOR
)
520 SelectObject( hdc
, sysColorObjects
.hpenWindowFrame
);
521 MoveTo( hdc
, rect
.left
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
522 LineTo( hdc
, rect
.right
, rect
.top
+ SEPARATOR_HEIGHT
/2 );
528 if (lpitem
->item_flags
& MF_HILITE
)
530 if (lpitem
->item_flags
& MF_GRAYED
)
531 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
533 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
534 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
538 if (lpitem
->item_flags
& MF_GRAYED
)
539 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
541 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
542 SetBkColor( hdc
, GetSysColor( COLOR_MENU
) );
547 /* Draw the check mark */
549 if (lpitem
->item_flags
& MF_CHECKED
)
551 GRAPH_DrawBitmap(hdc
, lpitem
->hCheckBit
? lpitem
->hCheckBit
:
552 hStdCheck
, rect
.left
,
553 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
554 0, 0, check_bitmap_width
, check_bitmap_height
);
556 else if (lpitem
->hUnCheckBit
!= 0) /* Not checked */
558 GRAPH_DrawBitmap(hdc
, lpitem
->hUnCheckBit
, rect
.left
,
559 (rect
.top
+rect
.bottom
-check_bitmap_height
) / 2,
560 0, 0, check_bitmap_width
, check_bitmap_height
);
563 /* Draw the popup-menu arrow */
565 if (lpitem
->item_flags
& MF_POPUP
)
567 GRAPH_DrawBitmap( hdc
, hStdMnArrow
,
568 rect
.right
-arrow_bitmap_width
-1,
569 (rect
.top
+rect
.bottom
-arrow_bitmap_height
) / 2,
570 0, 0, arrow_bitmap_width
, arrow_bitmap_height
);
573 rect
.left
+= check_bitmap_width
;
574 rect
.right
-= arrow_bitmap_width
;
577 /* Draw the item text or bitmap */
579 if (lpitem
->item_flags
& MF_BITMAP
)
581 GRAPH_DrawBitmap( hdc
, (HBITMAP
)lpitem
->hText
, rect
.left
, rect
.top
,
582 0, 0, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
);
585 /* No bitmap - process text if present */
586 else if ((lpitem
->item_text
) != ((char *) NULL
))
592 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
593 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
594 i
= strlen( lpitem
->item_text
);
598 for (i
= 0; lpitem
->item_text
[i
]; i
++)
599 if ((lpitem
->item_text
[i
] == '\t') ||
600 (lpitem
->item_text
[i
] == '\b')) break;
603 DrawText( hdc
, lpitem
->item_text
, i
, &rect
,
604 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
606 if (lpitem
->item_text
[i
]) /* There's a tab or flush-right char */
608 if (lpitem
->item_text
[i
] == '\t')
610 rect
.left
= lpitem
->xTab
;
611 DrawText( hdc
, lpitem
->item_text
+ i
+ 1, -1, &rect
,
612 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
614 else DrawText( hdc
, lpitem
->item_text
+ i
+ 1, -1, &rect
,
615 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
621 /***********************************************************************
624 * Paint a popup menu.
626 static void MENU_DrawPopupMenu( HWND hwnd
, HDC hdc
, HMENU hmenu
)
633 GetClientRect( hwnd
, &rect
);
634 FillRect( hdc
, &rect
, sysColorObjects
.hbrushMenu
);
635 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
636 if (!menu
|| !menu
->nItems
) return;
637 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
638 for (i
= menu
->nItems
; i
> 0; i
--, item
++)
639 MENU_DrawMenuItem( hwnd
, hdc
, item
, menu
->Height
, FALSE
);
643 /***********************************************************************
646 * Paint a menu bar. Returns the height of the menu bar.
648 UINT
MENU_DrawMenuBar(HDC hDC
, LPRECT lprect
, HWND hwnd
, BOOL suppress_draw
)
653 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
655 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( (HMENU
)wndPtr
->wIDmenu
);
656 if (lppop
== NULL
|| lprect
== NULL
) return SYSMETRICS_CYMENU
;
657 dprintf_menu(stddeb
,"MENU_DrawMenuBar("NPFMT
", %p, %p); !\n",
659 if (lppop
->Height
== 0) MENU_MenuBarCalcSize(hDC
, lprect
, lppop
, hwnd
);
660 lprect
->bottom
= lprect
->top
+ lppop
->Height
;
661 if (suppress_draw
) return lppop
->Height
;
663 FillRect(hDC
, lprect
, sysColorObjects
.hbrushMenu
);
664 SelectObject( hDC
, sysColorObjects
.hpenWindowFrame
);
665 MoveTo( hDC
, lprect
->left
, lprect
->bottom
);
666 LineTo( hDC
, lprect
->right
, lprect
->bottom
);
668 if (lppop
->nItems
== 0) return SYSMETRICS_CYMENU
;
669 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
670 for (i
= 0; i
< lppop
->nItems
; i
++, lpitem
++)
672 MENU_DrawMenuItem( hwnd
, hDC
, lpitem
, lppop
->Height
, TRUE
);
674 return lppop
->Height
;
678 /***********************************************************************
681 * Display a popup menu.
683 static BOOL
MENU_ShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, int x
, int y
)
687 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
688 if (menu
->FocusedItem
!= NO_SELECTED_ITEM
)
690 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
691 item
[menu
->FocusedItem
].item_flags
&= ~(MF_HILITE
| MF_MOUSESELECT
);
692 menu
->FocusedItem
= NO_SELECTED_ITEM
;
694 SendMessage( hwndOwner
, WM_INITMENUPOPUP
, (WPARAM
)hmenu
,
695 MAKELONG( id
, (menu
->wFlags
& MF_SYSMENU
) ? 1 : 0 ));
696 MENU_PopupMenuCalcSize( menu
, hwndOwner
);
699 WND
*wndPtr
= WIN_FindWndPtr( hwndOwner
);
700 if (!wndPtr
) return FALSE
;
701 menu
->hWnd
= CreateWindow( POPUPMENU_CLASS_ATOM
, (SEGPTR
)0,
702 WS_POPUP
| WS_BORDER
, x
, y
,
703 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
704 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
705 0, 0, wndPtr
->hInstance
, (SEGPTR
)hmenu
);
706 if (!menu
->hWnd
) return FALSE
;
708 else SetWindowPos( menu
->hWnd
, 0, x
, y
,
709 menu
->Width
+ 2*SYSMETRICS_CXBORDER
,
710 menu
->Height
+ 2*SYSMETRICS_CYBORDER
,
711 SWP_NOACTIVATE
| SWP_NOZORDER
);
713 /* Display the window */
715 SetWindowPos( menu
->hWnd
, HWND_TOP
, 0, 0, 0, 0,
716 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
717 UpdateWindow( menu
->hWnd
);
722 /***********************************************************************
725 static void MENU_SelectItem( HWND hwndOwner
, HMENU hmenu
, UINT wIndex
)
731 lppop
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
732 if (!lppop
->nItems
) return;
733 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
734 if ((wIndex
!= NO_SELECTED_ITEM
) &&
735 (wIndex
!= SYSMENU_SELECTED
) &&
736 (items
[wIndex
].item_flags
& MF_SEPARATOR
))
737 wIndex
= NO_SELECTED_ITEM
;
738 if (lppop
->FocusedItem
== wIndex
) return;
739 if (lppop
->wFlags
& MF_POPUP
) hdc
= GetDC( lppop
->hWnd
);
740 else hdc
= GetDCEx( lppop
->hWnd
, 0, DCX_CACHE
| DCX_WINDOW
);
742 /* Clear previous highlighted item */
743 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
745 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
746 NC_DrawSysButton( lppop
->hWnd
, hdc
, FALSE
);
749 items
[lppop
->FocusedItem
].item_flags
&=~(MF_HILITE
|MF_MOUSESELECT
);
750 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
751 !(lppop
->wFlags
& MF_POPUP
) );
755 /* Highlight new item (if any) */
756 lppop
->FocusedItem
= wIndex
;
757 if (lppop
->FocusedItem
!= NO_SELECTED_ITEM
)
759 if (lppop
->FocusedItem
== SYSMENU_SELECTED
)
761 NC_DrawSysButton( lppop
->hWnd
, hdc
, TRUE
);
764 SendMessage( hwndOwner
, WM_MENUSELECT
,
765 MAKEWPARAM( (DWORD
)GetSystemMenu( lppop
->hWnd
, FALSE
),
766 lppop
->wFlags
| MF_MOUSESELECT
),
769 SendMessage( hwndOwner
, WM_MENUSELECT
,
770 GetSystemMenu( lppop
->hWnd
, FALSE
),
771 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
776 items
[lppop
->FocusedItem
].item_flags
|= MF_HILITE
;
777 MENU_DrawMenuItem( lppop
->hWnd
, hdc
, &items
[lppop
->FocusedItem
], lppop
->Height
,
778 !(lppop
->wFlags
& MF_POPUP
) );
780 SendMessage( hwndOwner
, WM_MENUSELECT
,
781 MAKEWPARAM( items
[lppop
->FocusedItem
].item_id
,
782 items
[lppop
->FocusedItem
].item_flags
|
786 SendMessage( hwndOwner
, WM_MENUSELECT
,
787 items
[lppop
->FocusedItem
].item_id
,
788 MAKELONG( items
[lppop
->FocusedItem
].item_flags
| MF_MOUSESELECT
, hmenu
));
794 else SendMessage( hwndOwner
, WM_MENUSELECT
,
795 MAKEWPARAM( (DWORD
)hmenu
, lppop
->wFlags
| MF_MOUSESELECT
),
798 else SendMessage( hwndOwner
, WM_MENUSELECT
, hmenu
,
799 MAKELONG( lppop
->wFlags
| MF_MOUSESELECT
, hmenu
) );
802 ReleaseDC( lppop
->hWnd
, hdc
);
806 /***********************************************************************
807 * MENU_SelectNextItem
809 static void MENU_SelectNextItem( HWND hwndOwner
, HMENU hmenu
)
815 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
816 if (!menu
->nItems
) return;
817 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
818 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
819 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
821 for (i
= menu
->FocusedItem
+1; i
< menu
->nItems
; i
++)
823 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
825 MENU_SelectItem( hwndOwner
, hmenu
, i
);
829 if (MENU_HasSysMenu( menu
))
831 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
835 for (i
= 0; i
< menu
->nItems
; i
++)
837 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
839 MENU_SelectItem( hwndOwner
, hmenu
, i
);
843 if (MENU_HasSysMenu( menu
))
844 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
848 /***********************************************************************
849 * MENU_SelectPrevItem
851 static void MENU_SelectPrevItem( HWND hwndOwner
, HMENU hmenu
)
857 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
858 if (!menu
->nItems
) return;
859 items
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
860 if ((menu
->FocusedItem
!= NO_SELECTED_ITEM
) &&
861 (menu
->FocusedItem
!= SYSMENU_SELECTED
))
863 for (i
= menu
->FocusedItem
- 1; i
>= 0; i
--)
865 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
867 MENU_SelectItem( hwndOwner
, hmenu
, i
);
871 if (MENU_HasSysMenu( menu
))
873 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
877 for (i
= menu
->nItems
- 1; i
> 0; i
--)
879 if (!(items
[i
].item_flags
& MF_SEPARATOR
))
881 MENU_SelectItem( hwndOwner
, hmenu
, i
);
885 if (MENU_HasSysMenu( menu
))
886 MENU_SelectItem( hwndOwner
, hmenu
, SYSMENU_SELECTED
);
890 /***********************************************************************
893 * Return the handle of the selected sub-popup menu (if any).
895 static HMENU
MENU_GetSubPopup( HMENU hmenu
)
900 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
901 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return 0;
902 else if (menu
->FocusedItem
== SYSMENU_SELECTED
)
903 return GetSystemMenu( menu
->hWnd
, FALSE
);
905 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
906 if (!(item
->item_flags
& MF_POPUP
) || !(item
->item_flags
& MF_MOUSESELECT
))
908 return (HMENU
)item
->item_id
;
912 /***********************************************************************
915 * Hide the sub-popup menus of this menu.
917 static void MENU_HideSubPopups( HWND hwndOwner
, HMENU hmenu
)
920 POPUPMENU
*menu
, *submenu
;
923 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return;
924 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return;
925 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
927 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
931 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
932 if (!(item
->item_flags
& MF_POPUP
) ||
933 !(item
->item_flags
& MF_MOUSESELECT
)) return;
934 item
->item_flags
&= ~MF_MOUSESELECT
;
935 hsubmenu
= (HMENU
)item
->item_id
;
937 submenu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hsubmenu
);
938 MENU_HideSubPopups( hwndOwner
, hsubmenu
);
939 if (submenu
->hWnd
) ShowWindow( submenu
->hWnd
, SW_HIDE
);
940 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
);
944 /***********************************************************************
947 * Display the sub-menu of the selected item of this menu.
948 * Return the handle of the submenu, or hmenu if no submenu to display.
950 static HMENU
MENU_ShowSubPopup( HWND hwndOwner
, HMENU hmenu
, BOOL selectFirst
)
956 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return hmenu
;
957 if (!(wndPtr
= WIN_FindWndPtr( menu
->hWnd
))) return hmenu
;
958 if (menu
->FocusedItem
== NO_SELECTED_ITEM
) return hmenu
;
959 if (menu
->FocusedItem
== SYSMENU_SELECTED
)
961 MENU_ShowPopup(hwndOwner
, wndPtr
->hSysMenu
, 0, wndPtr
->rectClient
.left
,
962 wndPtr
->rectClient
.top
- menu
->Height
- 2*SYSMETRICS_CYBORDER
);
963 if (selectFirst
) MENU_SelectNextItem( hwndOwner
, wndPtr
->hSysMenu
);
964 return wndPtr
->hSysMenu
;
966 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
967 if (!(item
->item_flags
& MF_POPUP
) ||
968 (item
->item_flags
& (MF_GRAYED
| MF_DISABLED
))) return hmenu
;
969 item
->item_flags
|= MF_MOUSESELECT
;
970 if (menu
->wFlags
& MF_POPUP
)
972 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
973 wndPtr
->rectWindow
.left
+ item
->rect
.right
-arrow_bitmap_width
,
974 wndPtr
->rectWindow
.top
+ item
->rect
.top
);
978 MENU_ShowPopup( hwndOwner
, (HMENU
)item
->item_id
, menu
->FocusedItem
,
979 wndPtr
->rectWindow
.left
+ item
->rect
.left
,
980 wndPtr
->rectWindow
.top
+ item
->rect
.bottom
);
982 if (selectFirst
) MENU_SelectNextItem( hwndOwner
, (HMENU
)item
->item_id
);
983 return (HMENU
)item
->item_id
;
987 /***********************************************************************
988 * MENU_FindMenuByCoords
990 * Find the menu containing a given point (in screen coords).
992 static HMENU
MENU_FindMenuByCoords( HMENU hmenu
, POINT pt
)
997 if (!(hwnd
= WindowFromPoint( pt
))) return 0;
1000 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1001 if (menu
->hWnd
== hwnd
)
1003 if (!(menu
->wFlags
& MF_POPUP
))
1005 /* Make sure it's in the menu bar (or in system menu) */
1006 WND
*wndPtr
= WIN_FindWndPtr( menu
->hWnd
);
1007 if ((pt
.x
< wndPtr
->rectClient
.left
) ||
1008 (pt
.x
>= wndPtr
->rectClient
.right
) ||
1009 (pt
.y
>= wndPtr
->rectClient
.top
)) return 0;
1010 if (pt
.y
< wndPtr
->rectClient
.top
- menu
->Height
)
1012 if (!MENU_IsInSysMenu( menu
, pt
)) return 0;
1014 /* else it's in the menu bar */
1018 hmenu
= MENU_GetSubPopup( hmenu
);
1024 /***********************************************************************
1025 * MENU_ExecFocusedItem
1027 * Execute a menu item (for instance when user pressed Enter).
1028 * Return TRUE if we can go on with menu tracking.
1030 static BOOL
MENU_ExecFocusedItem( HWND hwndOwner
, HMENU hmenu
,
1031 HMENU
*hmenuCurrent
)
1034 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1035 if (!menu
|| !menu
->nItems
|| (menu
->FocusedItem
== NO_SELECTED_ITEM
) ||
1036 (menu
->FocusedItem
== SYSMENU_SELECTED
)) return TRUE
;
1037 item
= ((MENUITEM
*)USER_HEAP_LIN_ADDR(menu
->hItems
)) + menu
->FocusedItem
;
1038 if (!(item
->item_flags
& MF_POPUP
))
1040 if (!(item
->item_flags
& (MF_GRAYED
| MF_DISABLED
)))
1042 PostMessage( hwndOwner
, (menu
->wFlags
& MF_SYSMENU
) ?
1043 WM_SYSCOMMAND
: WM_COMMAND
, item
->item_id
, 0 );
1050 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1056 /***********************************************************************
1059 * Handle a button-down event in a menu. Point is in screen coords.
1060 * hmenuCurrent is the top-most visible popup.
1061 * Return TRUE if we can go on with menu tracking.
1063 static BOOL
MENU_ButtonDown( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1070 if (!hmenu
) return FALSE
; /* Outside all menus */
1071 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1072 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1073 if (!item
) /* Maybe in system menu */
1075 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1076 id
= SYSMENU_SELECTED
;
1079 if (menu
->FocusedItem
== id
)
1081 if (id
== SYSMENU_SELECTED
) return FALSE
;
1082 if (item
->item_flags
& MF_POPUP
)
1084 if (item
->item_flags
& MF_MOUSESELECT
)
1086 if (menu
->wFlags
& MF_POPUP
)
1088 MENU_HideSubPopups( hwndOwner
, hmenu
);
1089 *hmenuCurrent
= hmenu
;
1093 else *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1098 MENU_HideSubPopups( hwndOwner
, hmenu
);
1099 MENU_SelectItem( hwndOwner
, hmenu
, id
);
1100 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1106 /***********************************************************************
1109 * Handle a button-up event in a menu. Point is in screen coords.
1110 * hmenuCurrent is the top-most visible popup.
1111 * Return TRUE if we can go on with menu tracking.
1113 static BOOL
MENU_ButtonUp( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1121 if (!hmenu
) return FALSE
; /* Outside all menus */
1122 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1123 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1124 if (!item
) /* Maybe in system menu */
1126 if (!MENU_IsInSysMenu( menu
, pt
)) return FALSE
;
1127 id
= SYSMENU_SELECTED
;
1128 hsubmenu
= GetSystemMenu( menu
->hWnd
, FALSE
);
1131 if (menu
->FocusedItem
!= id
) return FALSE
;
1133 if (id
!= SYSMENU_SELECTED
)
1135 if (!(item
->item_flags
& MF_POPUP
))
1137 return MENU_ExecFocusedItem( hwndOwner
, hmenu
, hmenuCurrent
);
1139 hsubmenu
= (HMENU
)item
->item_id
;
1141 /* Select first item of sub-popup */
1142 MENU_SelectItem( hwndOwner
, hsubmenu
, NO_SELECTED_ITEM
);
1143 MENU_SelectNextItem( hwndOwner
, hsubmenu
);
1148 /***********************************************************************
1151 * Handle a motion event in a menu. Point is in screen coords.
1152 * hmenuCurrent is the top-most visible popup.
1153 * Return TRUE if we can go on with menu tracking.
1155 static BOOL
MENU_MouseMove( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
,
1159 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1160 UINT id
= NO_SELECTED_ITEM
;
1164 item
= MENU_FindItemByCoords( menu
, pt
.x
, pt
.y
, &id
);
1165 if (!item
) /* Maybe in system menu */
1167 if (!MENU_IsInSysMenu( menu
, pt
))
1168 id
= NO_SELECTED_ITEM
; /* Outside all items */
1169 else id
= SYSMENU_SELECTED
;
1172 if (id
== NO_SELECTED_ITEM
)
1174 MENU_SelectItem( hwndOwner
, *hmenuCurrent
, NO_SELECTED_ITEM
);
1176 else if (menu
->FocusedItem
!= id
)
1178 MENU_HideSubPopups( hwndOwner
, hmenu
);
1179 MENU_SelectItem( hwndOwner
, hmenu
, id
);
1180 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, FALSE
);
1186 /***********************************************************************
1189 * Handle a VK_LEFT key event in a menu.
1190 * hmenuCurrent is the top-most visible popup.
1192 static void MENU_KeyLeft( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1195 HMENU hmenutmp
, hmenuprev
;
1197 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1198 hmenuprev
= hmenutmp
= hmenu
;
1199 while (hmenutmp
!= *hmenuCurrent
)
1201 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1202 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1204 MENU_HideSubPopups( hwndOwner
, hmenuprev
);
1206 if ((hmenuprev
== hmenu
) && !(menu
->wFlags
& MF_POPUP
))
1208 /* Select previous item on the menu bar */
1209 MENU_SelectPrevItem( hwndOwner
, hmenu
);
1210 if (*hmenuCurrent
!= hmenu
)
1212 /* A popup menu was displayed -> display the next one */
1213 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1216 else *hmenuCurrent
= hmenuprev
;
1220 /***********************************************************************
1223 * Handle a VK_RIGHT key event in a menu.
1224 * hmenuCurrent is the top-most visible popup.
1226 static void MENU_KeyRight( HWND hwndOwner
, HMENU hmenu
, HMENU
*hmenuCurrent
)
1231 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1233 if ((menu
->wFlags
& MF_POPUP
) || (*hmenuCurrent
!= hmenu
))
1235 /* If already displaying a popup, try to display sub-popup */
1236 hmenutmp
= MENU_ShowSubPopup( hwndOwner
, *hmenuCurrent
, TRUE
);
1237 if (hmenutmp
!= *hmenuCurrent
) /* Sub-popup displayed */
1239 *hmenuCurrent
= hmenutmp
;
1244 /* If on menu-bar, go to next item */
1245 if (!(menu
->wFlags
& MF_POPUP
))
1247 MENU_HideSubPopups( hwndOwner
, hmenu
);
1248 MENU_SelectNextItem( hwndOwner
, hmenu
);
1249 if (*hmenuCurrent
!= hmenu
)
1251 /* A popup menu was displayed -> display the next one */
1252 *hmenuCurrent
= MENU_ShowSubPopup( hwndOwner
, hmenu
, TRUE
);
1255 else if (*hmenuCurrent
!= hmenu
) /* Hide last level popup */
1258 hmenuprev
= hmenutmp
= hmenu
;
1259 while (hmenutmp
!= *hmenuCurrent
)
1261 hmenutmp
= MENU_GetSubPopup( hmenuprev
);
1262 if (hmenutmp
!= *hmenuCurrent
) hmenuprev
= hmenutmp
;
1264 MENU_HideSubPopups( hwndOwner
, hmenuprev
);
1265 *hmenuCurrent
= hmenuprev
;
1270 /***********************************************************************
1273 * Menu tracking code.
1274 * If 'x' and 'y' are not 0, we simulate a button-down event at (x,y)
1275 * before beginning tracking. This is to help menu-bar tracking.
1277 static BOOL
MENU_TrackMenu( HMENU hmenu
, UINT wFlags
, int x
, int y
,
1278 HWND hwnd
, LPRECT lprect
)
1283 HMENU hmenuCurrent
= hmenu
;
1284 BOOL fClosed
= FALSE
, fRemove
;
1287 fEndMenuCalled
= FALSE
;
1288 if (!(menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
1291 POINT pt
= { x
, y
};
1292 MENU_ButtonDown( hwnd
, hmenu
, &hmenuCurrent
, pt
);
1295 hMsg
= USER_HEAP_ALLOC( sizeof(MSG
) );
1296 msg
= (MSG
*)USER_HEAP_LIN_ADDR( hMsg
);
1299 if (!MSG_InternalGetMessage( (SEGPTR
)USER_HEAP_SEG_ADDR(hMsg
), 0,
1300 hwnd
, MSGF_MENU
, 0, TRUE
))
1304 if ((msg
->message
>= WM_MOUSEFIRST
) && (msg
->message
<= WM_MOUSELAST
))
1306 /* Find the sub-popup for this mouse event (if any) */
1307 HMENU hsubmenu
= MENU_FindMenuByCoords( hmenu
, msg
->pt
);
1309 switch(msg
->message
)
1311 case WM_RBUTTONDOWN
:
1312 case WM_NCRBUTTONDOWN
:
1313 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1315 case WM_LBUTTONDOWN
:
1316 case WM_NCLBUTTONDOWN
:
1317 fClosed
= !MENU_ButtonDown( hwnd
, hsubmenu
,
1318 &hmenuCurrent
, msg
->pt
);
1322 case WM_NCRBUTTONUP
:
1323 if (!(wFlags
& TPM_RIGHTBUTTON
)) break;
1326 case WM_NCLBUTTONUP
:
1327 /* If outside all menus but inside lprect, ignore it */
1328 if (!hsubmenu
&& lprect
&& PtInRect( lprect
, msg
->pt
)) break;
1329 fClosed
= !MENU_ButtonUp( hwnd
, hsubmenu
,
1330 &hmenuCurrent
, msg
->pt
);
1331 fRemove
= TRUE
; /* Remove event even if outside menu */
1335 case WM_NCMOUSEMOVE
:
1336 if ((msg
->wParam
& MK_LBUTTON
) ||
1337 ((wFlags
& TPM_RIGHTBUTTON
) && (msg
->wParam
& MK_RBUTTON
)))
1339 fClosed
= !MENU_MouseMove( hwnd
, hsubmenu
,
1340 &hmenuCurrent
, msg
->pt
);
1345 else if ((msg
->message
>= WM_KEYFIRST
) && (msg
->message
<= WM_KEYLAST
))
1347 fRemove
= TRUE
; /* Keyboard messages are always removed */
1348 switch(msg
->message
)
1354 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
);
1355 MENU_SelectNextItem( hwnd
, hmenuCurrent
);
1359 MENU_SelectItem( hwnd
, hmenuCurrent
, NO_SELECTED_ITEM
);
1360 MENU_SelectPrevItem( hwnd
, hmenuCurrent
);
1364 MENU_SelectPrevItem( hwnd
, hmenuCurrent
);
1368 /* If on menu bar, pull-down the menu */
1369 if (!(menu
->wFlags
& MF_POPUP
) && (hmenuCurrent
== hmenu
))
1370 hmenuCurrent
= MENU_ShowSubPopup( hwnd
, hmenu
, TRUE
);
1372 MENU_SelectNextItem( hwnd
, hmenuCurrent
);
1376 MENU_KeyLeft( hwnd
, hmenu
, &hmenuCurrent
);
1380 MENU_KeyRight( hwnd
, hmenu
, &hmenuCurrent
);
1385 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1396 break; /* WM_KEYDOWN */
1406 break; /* WM_SYSKEYDOWN */
1410 /* Hack to avoid control chars. */
1411 /* We will find a better way real soon... */
1412 if ((msg
->wParam
<= 32) || (msg
->wParam
>= 127)) break;
1413 pos
= MENU_FindItemByKey( hwnd
, hmenuCurrent
, msg
->wParam
);
1414 if (pos
== (UINT
)-2) fClosed
= TRUE
;
1415 else if (pos
== (UINT
)-1) MessageBeep(0);
1418 MENU_SelectItem( hwnd
, hmenuCurrent
, pos
);
1419 fClosed
= !MENU_ExecFocusedItem( hwnd
, hmenuCurrent
,
1424 break; /* WM_CHAR */
1425 } /* switch(msg->message) */
1429 DispatchMessage( msg
);
1431 if (fEndMenuCalled
) fClosed
= TRUE
;
1432 if (!fClosed
) fRemove
= TRUE
;
1434 if (fRemove
) /* Remove the message from the queue */
1435 PeekMessage( msg
, 0, msg
->message
, msg
->message
, PM_REMOVE
);
1437 USER_HEAP_FREE( hMsg
);
1439 MENU_HideSubPopups( hwnd
, hmenu
);
1440 if (menu
->wFlags
& MF_POPUP
) ShowWindow( menu
->hWnd
, SW_HIDE
);
1441 MENU_SelectItem( hwnd
, hmenu
, NO_SELECTED_ITEM
);
1442 SendMessage( hwnd
, WM_MENUSELECT
, 0, MAKELONG( 0xffff, 0 ) );
1443 fEndMenuCalled
= FALSE
;
1448 /***********************************************************************
1449 * MENU_TrackMouseMenuBar
1451 * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
1453 void MENU_TrackMouseMenuBar( HWND hwnd
, POINT pt
)
1455 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1456 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1457 SendMessage( hwnd
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1458 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1459 pt
.x
, pt
.y
, hwnd
, NULL
);
1460 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1464 /***********************************************************************
1465 * MENU_TrackKbdMenuBar
1467 * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
1469 void MENU_TrackKbdMenuBar( HWND hwnd
, UINT wParam
)
1471 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
1472 if (!wndPtr
->wIDmenu
) return;
1473 SendMessage( hwnd
, WM_ENTERMENULOOP
, 0, 0 );
1474 SendMessage( hwnd
, WM_INITMENU
, wndPtr
->wIDmenu
, 0 );
1475 /* Select first selectable item */
1476 MENU_SelectItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
, NO_SELECTED_ITEM
);
1477 MENU_SelectNextItem( hwnd
, (HMENU
)wndPtr
->wIDmenu
);
1478 MENU_TrackMenu( (HMENU
)wndPtr
->wIDmenu
, TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
1480 SendMessage( hwnd
, WM_EXITMENULOOP
, 0, 0 );
1484 /**********************************************************************
1485 * TrackPopupMenu (USER.416)
1487 BOOL
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, short x
, short y
,
1488 short nReserved
, HWND hWnd
, LPRECT lpRect
)
1490 if (!MENU_ShowPopup( hWnd
, hMenu
, 0, x
, y
)) return FALSE
;
1491 return MENU_TrackMenu( hMenu
, wFlags
, 0, 0, hWnd
, lpRect
);
1495 /***********************************************************************
1498 LRESULT
PopupMenuWndProc(HWND hwnd
,UINT message
,WPARAM wParam
,LPARAM lParam
)
1504 CREATESTRUCT
*createStruct
= (CREATESTRUCT
*)PTR_SEG_TO_LIN(lParam
);
1506 HMENU hmenu
= (HMENU
) (createStruct
->lpCreateParams
);
1507 SetWindowLong( hwnd
, 0, (LONG
)hmenu
);
1509 HMENU hmenu
= (HMENU
) ((int)createStruct
->lpCreateParams
& 0xffff);
1510 SetWindowWord( hwnd
, 0, hmenu
);
1515 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1516 return MA_NOACTIVATE
;
1521 BeginPaint( hwnd
, &ps
);
1522 MENU_DrawPopupMenu( hwnd
, ps
.hdc
,
1524 (HMENU
)GetWindowLong( hwnd
, 0 )
1526 (HMENU
)GetWindowWord( hwnd
, 0 )
1529 EndPaint( hwnd
, &ps
);
1534 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1540 /***********************************************************************
1541 * MENU_GetMenuBarHeight
1543 * Compute the size of the menu bar height. Used by NC_HandleNCCalcSize().
1545 UINT
MENU_GetMenuBarHeight( HWND hwnd
, UINT menubarWidth
, int orgX
, int orgY
)
1552 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
1553 if (!(lppop
= (LPPOPUPMENU
)USER_HEAP_LIN_ADDR((HMENU
)wndPtr
->wIDmenu
)))
1555 hdc
= GetDC( hwnd
);
1556 SetRect( &rectBar
, orgX
, orgY
, orgX
+menubarWidth
, orgY
+SYSMETRICS_CYMENU
);
1557 MENU_MenuBarCalcSize( hdc
, &rectBar
, lppop
, hwnd
);
1558 ReleaseDC( hwnd
, hdc
);
1559 return lppop
->Height
;
1563 /**********************************************************************
1564 * ChangeMenu [USER.153]
1566 BOOL
ChangeMenu(HMENU hMenu
, UINT nPos
, LPSTR lpNewItem
,
1567 UINT wItemID
, UINT wFlags
)
1569 dprintf_menu(stddeb
,"ChangeMenu: menu="NPFMT
" pos=%d ptr=%p item=%04x flags=%04x\n",
1570 hMenu
, nPos
, lpNewItem
, wItemID
, wFlags
);
1571 if (wFlags
& MF_APPEND
) {
1572 return AppendMenu(hMenu
, wFlags
& ~MF_APPEND
, wItemID
, lpNewItem
);
1574 if (wFlags
& MF_DELETE
) {
1575 /* FIXME: Word passes the item id in nPos and 0 or 0xffff as id */
1576 /* for MF_DELETE. We should check the parameters for all others */
1577 /* MF_* actions also (anybody got a doc on ChangeMenu?). */
1578 return DeleteMenu(hMenu
, nPos
, wFlags
& ~MF_DELETE
);
1580 if (wFlags
& MF_CHANGE
) {
1581 return ModifyMenu(hMenu
, nPos
, wFlags
& ~MF_CHANGE
, wItemID
, lpNewItem
);
1583 if (wFlags
& MF_REMOVE
) {
1584 return RemoveMenu(hMenu
, wFlags
& MF_BYPOSITION
? nPos
: wItemID
,
1585 wFlags
& ~MF_REMOVE
);
1587 /* Default: MF_INSERT */
1588 return InsertMenu(hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1592 /**********************************************************************
1593 * CheckMenuItem [USER.154]
1595 BOOL
CheckMenuItem(HMENU hMenu
, UINT wItemID
, UINT wFlags
)
1598 dprintf_menu(stddeb
,"CheckMenuItem ("NPFMT
", %04X, %04X) !\n",
1599 hMenu
, wItemID
, wFlags
);
1600 if (!(lpitem
= MENU_FindItem(&hMenu
, &wItemID
, wFlags
))) return FALSE
;
1601 if (wFlags
& MF_CHECKED
) lpitem
->item_flags
|= MF_CHECKED
;
1602 else lpitem
->item_flags
&= ~MF_CHECKED
;
1607 /**********************************************************************
1608 * EnableMenuItem [USER.155]
1610 BOOL
EnableMenuItem(HMENU hMenu
, UINT wItemID
, UINT wFlags
)
1613 dprintf_menu(stddeb
,"EnableMenuItem ("NPFMT
", %04X, %04X) !\n",
1614 hMenu
, wItemID
, wFlags
);
1615 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return FALSE
;
1617 /* We can't have MF_GRAYED and MF_DISABLED together */
1618 if (wFlags
& MF_GRAYED
)
1620 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_DISABLED
) | MF_GRAYED
;
1622 else if (wFlags
& MF_DISABLED
)
1624 lpitem
->item_flags
= (lpitem
->item_flags
& ~MF_GRAYED
) | MF_DISABLED
;
1626 else /* MF_ENABLED */
1628 lpitem
->item_flags
&= ~(MF_GRAYED
| MF_DISABLED
);
1634 /*******************************************************************
1635 * GetMenuString (USER.161)
1637 int GetMenuString( HMENU hMenu
, UINT wItemID
,
1638 LPSTR str
, short nMaxSiz
, UINT wFlags
)
1642 dprintf_menu( stddeb
, "GetMenuString: menu="NPFMT
" item=%04x ptr=%p len=%d flags=%04x\n",
1643 hMenu
, wItemID
, str
, nMaxSiz
, wFlags
);
1644 if (!str
|| !nMaxSiz
) return 0;
1646 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return 0;
1647 if (!lpitem
->item_text
|| !IS_STRING_ITEM(lpitem
->item_flags
)) return 0;
1648 nMaxSiz
= MIN( nMaxSiz
-1, strlen(lpitem
->item_text
) );
1649 strncpy( str
, lpitem
->item_text
, nMaxSiz
);
1650 str
[nMaxSiz
] = '\0';
1651 dprintf_menu( stddeb
, "GetMenuString: returning '%s'\n", str
);
1656 /**********************************************************************
1657 * HiliteMenuItem [USER.162]
1659 BOOL
HiliteMenuItem(HWND hWnd
, HMENU hMenu
, UINT wItemID
, UINT wHilite
)
1663 dprintf_menu(stddeb
,"HiliteMenuItem("NPFMT
", "NPFMT
", %04X, %04X);\n",
1664 hWnd
, hMenu
, wItemID
, wHilite
);
1665 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wHilite
))) return FALSE
;
1666 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1667 if (menu
->FocusedItem
== wItemID
) return TRUE
;
1668 MENU_HideSubPopups( hWnd
, hMenu
);
1669 MENU_SelectItem( hWnd
, hMenu
, wItemID
);
1674 /**********************************************************************
1675 * GetMenuState [USER.250]
1677 UINT
GetMenuState(HMENU hMenu
, UINT wItemID
, UINT wFlags
)
1680 dprintf_menu(stddeb
,"GetMenuState("NPFMT
", %04X, %04X);\n",
1681 hMenu
, wItemID
, wFlags
);
1682 if (!(lpitem
= MENU_FindItem( &hMenu
, &wItemID
, wFlags
))) return -1;
1683 if (lpitem
->item_flags
& MF_POPUP
)
1685 POPUPMENU
*menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( (HMENU
)lpitem
->item_id
);
1686 if (!menu
) return -1;
1687 else return (menu
->nItems
<< 8) | (menu
->wFlags
& 0xff);
1689 else return lpitem
->item_flags
;
1693 /**********************************************************************
1694 * GetMenuItemCount [USER.263]
1696 INT
GetMenuItemCount(HMENU hMenu
)
1699 dprintf_menu(stddeb
,"GetMenuItemCount("NPFMT
");\n", hMenu
);
1700 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1701 if (menu
== NULL
) return (UINT
)-1;
1702 dprintf_menu(stddeb
,"GetMenuItemCount("NPFMT
") return %d \n",
1703 hMenu
, menu
->nItems
);
1704 return menu
->nItems
;
1708 /**********************************************************************
1709 * GetMenuItemID [USER.264]
1711 UINT
GetMenuItemID(HMENU hMenu
, int nPos
)
1716 dprintf_menu(stddeb
,"GetMenuItemID("NPFMT
", %d);\n", hMenu
, nPos
);
1717 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return -1;
1718 if ((nPos
< 0) || (nPos
>= menu
->nItems
)) return -1;
1719 item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
1720 if (item
[nPos
].item_flags
& MF_POPUP
) return -1;
1721 return item
[nPos
].item_id
;
1725 /**********************************************************************
1726 * InsertMenu [USER.410]
1728 BOOL
InsertMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
, UINT wItemID
, LPSTR lpNewItem
)
1731 MENUITEM
*lpitem
, *newItems
;
1734 if (IS_STRING_ITEM(wFlags
))
1736 dprintf_menu(stddeb
,"InsertMenu ("NPFMT
", %04X, %04X, %04X, '%s') !\n",
1737 hMenu
, nPos
, wFlags
, wItemID
,
1738 lpNewItem
? lpNewItem
: "(null)");
1739 if (!lpNewItem
) return FALSE
;
1742 dprintf_menu(stddeb
,"InsertMenu ("NPFMT
", %04X, %04X, %04X, %p) !\n",
1743 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1745 /* Find where to insert new item */
1747 if ((wFlags
& MF_BYPOSITION
) &&
1748 ((nPos
== (UINT
)-1) || (nPos
== (UINT
)GetMenuItemCount(hMenu
))))
1750 /* Special case: append to menu
1751 Some programs specify the menu length to do that */
1752 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1754 dprintf_menu(stddeb
,"InsertMenu: "NPFMT
" not a menu handle\n", hMenu
);
1757 nPos
= menu
->nItems
;
1761 if (!MENU_FindItem( &hMenu
, &nPos
, wFlags
))
1763 dprintf_menu(stddeb
,"InsertMenu: Item %X not found\n", nPos
);
1766 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
)))
1768 dprintf_menu(stddeb
,"InsertMenu: "NPFMT
" not a menu handle\n", hMenu
);
1773 /* Create new items array */
1775 hNewItems
= USER_HEAP_ALLOC( sizeof(MENUITEM
) * (menu
->nItems
+1) );
1778 dprintf_menu(stddeb
,"InsertMenu: allocation failed\n");
1781 newItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( hNewItems
);
1782 if (menu
->nItems
> 0)
1784 /* Copy the old array into the new */
1785 MENUITEM
*oldItems
= (MENUITEM
*) USER_HEAP_LIN_ADDR( menu
->hItems
);
1786 if (nPos
> 0) memcpy( newItems
, oldItems
, nPos
* sizeof(MENUITEM
) );
1787 if (nPos
< menu
->nItems
) memcpy( &newItems
[nPos
+1], &oldItems
[nPos
],
1788 (menu
->nItems
-nPos
)*sizeof(MENUITEM
) );
1790 USER_HEAP_FREE( menu
->hItems
);
1792 menu
->hItems
= hNewItems
;
1795 /* Store the new item data */
1797 lpitem
= &newItems
[nPos
];
1798 lpitem
->item_flags
= wFlags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1799 lpitem
->item_id
= wItemID
;
1801 if (IS_STRING_ITEM(wFlags
))
1803 /* Item beginning with a backspace is a help item */
1804 if (lpNewItem
[0] == '\b')
1806 lpitem
->item_flags
|= MF_HELP
;
1809 lpitem
->hText
= USER_HEAP_ALLOC( strlen(lpNewItem
)+1 );
1810 lpitem
->item_text
= (char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
1811 strcpy( lpitem
->item_text
, lpNewItem
);
1814 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= (HANDLE
)lpNewItem
;
1816 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= LOWORD((DWORD
)lpNewItem
);
1818 else lpitem
->item_text
= lpNewItem
;
1820 if (wFlags
& MF_POPUP
) /* Set the MF_POPUP flag on the popup-menu */
1821 ((POPUPMENU
*)USER_HEAP_LIN_ADDR((HMENU
)wItemID
))->wFlags
|= MF_POPUP
;
1823 SetRectEmpty( &lpitem
->rect
);
1824 lpitem
->hCheckBit
= hStdCheck
;
1825 lpitem
->hUnCheckBit
= 0;
1830 /**********************************************************************
1831 * AppendMenu [USER.411]
1833 BOOL
AppendMenu(HMENU hMenu
, UINT wFlags
, UINT wItemID
, LPSTR lpNewItem
)
1835 return InsertMenu( hMenu
, -1, wFlags
| MF_BYPOSITION
, wItemID
, lpNewItem
);
1839 /**********************************************************************
1840 * RemoveMenu [USER.412]
1842 BOOL
RemoveMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
)
1846 dprintf_menu(stddeb
,"RemoveMenu ("NPFMT
", %04X, %04X) !\n",
1847 hMenu
, nPos
, wFlags
);
1848 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1849 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return FALSE
;
1853 if (IS_STRING_ITEM(lpitem
->item_flags
)) USER_HEAP_FREE( lpitem
->hText
);
1854 if (--menu
->nItems
== 0)
1856 USER_HEAP_FREE( menu
->hItems
);
1861 while(nPos
< menu
->nItems
)
1863 *lpitem
= *(lpitem
+1);
1867 menu
->hItems
= USER_HEAP_REALLOC( menu
->hItems
,
1868 menu
->nItems
* sizeof(MENUITEM
) );
1874 /**********************************************************************
1875 * DeleteMenu [USER.413]
1877 BOOL
DeleteMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
)
1879 MENUITEM
*item
= MENU_FindItem( &hMenu
, &nPos
, wFlags
);
1880 if (!item
) return FALSE
;
1881 if (item
->item_flags
& MF_POPUP
) DestroyMenu( (HMENU
)item
->item_id
);
1882 /* nPos is now the position of the item */
1883 RemoveMenu( hMenu
, nPos
, wFlags
| MF_BYPOSITION
);
1888 /**********************************************************************
1889 * ModifyMenu [USER.414]
1891 BOOL
ModifyMenu(HMENU hMenu
, UINT nPos
, UINT wFlags
, UINT wItemID
, LPSTR lpNewItem
)
1894 if (IS_STRING_ITEM(wFlags
))
1896 dprintf_menu(stddeb
,"ModifyMenu ("NPFMT
", %04X, %04X, %04X, '%s') !\n",
1897 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
? lpNewItem
: "(null)");
1898 if (!lpNewItem
) return FALSE
;
1901 dprintf_menu(stddeb
,"ModifyMenu ("NPFMT
", %04X, %04X, %04X, %p) !\n",
1902 hMenu
, nPos
, wFlags
, wItemID
, lpNewItem
);
1903 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1905 if (IS_STRING_ITEM(lpitem
->item_flags
)) USER_HEAP_FREE( lpitem
->hText
);
1906 lpitem
->item_flags
= wFlags
& ~(MF_HILITE
| MF_MOUSESELECT
);
1907 lpitem
->item_id
= wItemID
;
1909 if (IS_STRING_ITEM(wFlags
))
1911 lpitem
->hText
= USER_HEAP_ALLOC( strlen(lpNewItem
)+1 );
1912 lpitem
->item_text
= (char *)USER_HEAP_LIN_ADDR( lpitem
->hText
);
1913 strcpy( lpitem
->item_text
, lpNewItem
);
1916 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= (HANDLE
)lpNewItem
;
1918 else if (wFlags
& MF_BITMAP
) lpitem
->hText
= LOWORD((DWORD
)lpNewItem
);
1920 else lpitem
->item_text
= lpNewItem
;
1921 SetRectEmpty( &lpitem
->rect
);
1926 /**********************************************************************
1927 * CreatePopupMenu [USER.415]
1929 HMENU
CreatePopupMenu()
1934 if (!(hmenu
= CreateMenu())) return 0;
1935 menu
= (POPUPMENU
*) USER_HEAP_LIN_ADDR( hmenu
);
1936 menu
->wFlags
|= MF_POPUP
;
1941 /**********************************************************************
1942 * GetMenuCheckMarkDimensions [USER.417]
1944 DWORD
GetMenuCheckMarkDimensions()
1946 return MAKELONG( check_bitmap_width
, check_bitmap_height
);
1950 /**********************************************************************
1951 * SetMenuItemBitmaps [USER.418]
1953 BOOL
SetMenuItemBitmaps(HMENU hMenu
, UINT nPos
, UINT wFlags
,
1954 HBITMAP hNewCheck
, HBITMAP hNewUnCheck
)
1957 dprintf_menu(stddeb
,"SetMenuItemBitmaps ("NPFMT
", %04X, %04X, "NPFMT
", %08lX) !\n",
1958 hMenu
, nPos
, wFlags
, hNewCheck
, (DWORD
)hNewUnCheck
);
1959 if (!(lpitem
= MENU_FindItem( &hMenu
, &nPos
, wFlags
))) return FALSE
;
1961 if (!hNewCheck
&& !hNewUnCheck
)
1963 /* If both are NULL, restore default bitmaps */
1964 lpitem
->hCheckBit
= hStdCheck
;
1965 lpitem
->hUnCheckBit
= 0;
1966 lpitem
->item_flags
&= ~MF_USECHECKBITMAPS
;
1968 else /* Install new bitmaps */
1970 lpitem
->hCheckBit
= hNewCheck
;
1971 lpitem
->hUnCheckBit
= hNewUnCheck
;
1972 lpitem
->item_flags
|= MF_USECHECKBITMAPS
;
1978 /**********************************************************************
1979 * CreateMenu [USER.151]
1985 dprintf_menu(stddeb
,"CreateMenu !\n");
1986 if (!(hMenu
= USER_HEAP_ALLOC( sizeof(POPUPMENU
) )))
1988 menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
1991 menu
->wMagic
= MENU_MAGIC
;
1998 menu
->FocusedItem
= NO_SELECTED_ITEM
;
1999 dprintf_menu(stddeb
,"CreateMenu // return "NPFMT
"\n", hMenu
);
2004 /**********************************************************************
2005 * DestroyMenu [USER.152]
2007 BOOL
DestroyMenu(HMENU hMenu
)
2010 dprintf_menu(stddeb
,"DestroyMenu ("NPFMT
") !\n", hMenu
);
2011 if (hMenu
== 0) return FALSE
;
2012 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2013 if (!lppop
|| (lppop
->wMagic
!= MENU_MAGIC
)) return FALSE
;
2014 lppop
->wMagic
= 0; /* Mark it as destroyed */
2015 if ((lppop
->wFlags
& MF_POPUP
) && lppop
->hWnd
)
2016 DestroyWindow( lppop
->hWnd
);
2021 MENUITEM
*item
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
2022 for (i
= lppop
->nItems
; i
> 0; i
--, item
++)
2024 if (item
->item_flags
& MF_POPUP
)
2025 DestroyMenu( (HMENU
)item
->item_id
);
2027 USER_HEAP_FREE( lppop
->hItems
);
2029 USER_HEAP_FREE( hMenu
);
2030 dprintf_menu(stddeb
,"DestroyMenu ("NPFMT
") // End !\n", hMenu
);
2034 /**********************************************************************
2035 * GetSystemMenu [USER.156]
2037 HMENU
GetSystemMenu(HWND hWnd
, BOOL bRevert
)
2039 WND
*wndPtr
= WIN_FindWndPtr( hWnd
);
2040 if (!wndPtr
) return 0;
2042 if (!bRevert
) return wndPtr
->hSysMenu
;
2043 if (wndPtr
->hSysMenu
) DestroyMenu(wndPtr
->hSysMenu
);
2044 wndPtr
->hSysMenu
= MENU_CopySysMenu();
2045 return wndPtr
->hSysMenu
;
2048 /**********************************************************************
2049 * SetSystemMenu [USER.280]
2051 BOOL
SetSystemMenu(HWND hWnd
, HMENU newHmenu
)
2055 if ((wndPtr
= WIN_FindWndPtr(hWnd
)) != NULL
) wndPtr
->hSysMenu
= newHmenu
;
2060 /**********************************************************************
2061 * GetMenu [USER.157]
2063 HMENU
GetMenu(HWND hWnd
)
2065 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2066 if (wndPtr
== NULL
) return 0;
2067 return (HMENU
)wndPtr
->wIDmenu
;
2071 /**********************************************************************
2072 * SetMenu [USER.158]
2074 BOOL
SetMenu(HWND hWnd
, HMENU hMenu
)
2077 WND
* wndPtr
= WIN_FindWndPtr(hWnd
);
2078 if (wndPtr
== NULL
) {
2079 fprintf(stderr
,"SetMenu("NPFMT
", "NPFMT
") // Bad window handle !\n",
2083 dprintf_menu(stddeb
,"SetMenu("NPFMT
", "NPFMT
");\n", hWnd
, hMenu
);
2084 if (GetCapture() == hWnd
) ReleaseCapture();
2085 wndPtr
->wIDmenu
= (UINT
)hMenu
;
2088 lpmenu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
);
2089 if (lpmenu
== NULL
) {
2090 fprintf(stderr
,"SetMenu("NPFMT
", "NPFMT
") // Bad menu handle !\n",
2094 lpmenu
->hWnd
= hWnd
;
2095 lpmenu
->wFlags
&= ~MF_POPUP
; /* Can't be a popup */
2096 lpmenu
->Height
= 0; /* Make sure we recalculate the size */
2098 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2099 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2105 /**********************************************************************
2106 * GetSubMenu [USER.159]
2108 HMENU
GetSubMenu(HMENU hMenu
, short nPos
)
2112 dprintf_menu(stddeb
,"GetSubMenu ("NPFMT
", %04X) !\n", hMenu
, nPos
);
2113 if (!(lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR(hMenu
))) return 0;
2114 if ((UINT
)nPos
>= lppop
->nItems
) return 0;
2115 lpitem
= (MENUITEM
*) USER_HEAP_LIN_ADDR( lppop
->hItems
);
2116 if (!(lpitem
[nPos
].item_flags
& MF_POPUP
)) return 0;
2117 return (HMENU
)lpitem
[nPos
].item_id
;
2121 /**********************************************************************
2122 * DrawMenuBar [USER.160]
2124 void DrawMenuBar(HWND hWnd
)
2128 dprintf_menu(stddeb
,"DrawMenuBar ("NPFMT
")\n", hWnd
);
2129 wndPtr
= WIN_FindWndPtr(hWnd
);
2130 if (wndPtr
!= NULL
&& (wndPtr
->dwStyle
& WS_CHILD
) == 0 &&
2131 wndPtr
->wIDmenu
!= 0) {
2132 dprintf_menu(stddeb
,"DrawMenuBar wIDmenu=%04X \n",
2134 lppop
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR((HMENU
)wndPtr
->wIDmenu
);
2135 if (lppop
== NULL
) return;
2137 lppop
->Height
= 0; /* Make sure we call MENU_MenuBarCalcSize */
2138 SetWindowPos( hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
2139 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
2144 /***********************************************************************
2145 * EndMenu (USER.187)
2149 /* Note: this won't work when we have multiple tasks... */
2150 fEndMenuCalled
= TRUE
;
2154 /***********************************************************************
2155 * LookupMenuHandle (USER.217)
2157 HMENU
LookupMenuHandle( HMENU hmenu
, INT id
)
2159 if (!MENU_FindItem( &hmenu
, &id
, MF_BYCOMMAND
)) return 0;
2164 /**********************************************************************
2165 * LoadMenu (USER.150)
2167 HMENU
LoadMenu( HINSTANCE instance
, SEGPTR name
)
2175 char *str
= (char *)PTR_SEG_TO_LIN( name
);
2176 dprintf_menu( stddeb
, "LoadMenu("NPFMT
",'%s')\n", instance
, str
);
2177 if (str
[0] == '#') name
= (SEGPTR
)atoi( str
+ 1 );
2180 dprintf_resource(stddeb
,"LoadMenu("NPFMT
",%04x)\n",instance
,LOWORD(name
));
2182 if (!name
) return 0;
2184 if (!(hRsrc
= FindResource( instance
, name
, RT_MENU
))) return 0;
2185 if (!(handle
= LoadResource( instance
, hRsrc
))) return 0;
2186 hMenu
= LoadMenuIndirect( LockResource(handle
) );
2187 FreeResource( handle
);
2192 /**********************************************************************
2193 * LoadMenuIndirect [USER.220]
2195 HMENU
LoadMenuIndirect(LPSTR menu_template
)
2198 MENU_HEADER
*menu_desc
;
2199 dprintf_menu(stddeb
,"LoadMenuIndirect: menu_template '%p'\n",
2201 hMenu
= CreateMenu();
2202 menu_desc
= (MENU_HEADER
*)menu_template
;
2203 ParseMenuResource((WORD
*)(menu_desc
+ 1), 0, hMenu
);
2208 /**********************************************************************
2209 * ParseMenuResource (from Resource or Template)
2211 WORD
* ParseMenuResource(WORD
*first_item
, int level
, HMENU hMenu
)
2219 next_item
= first_item
;
2224 if (*item
& MF_POPUP
) {
2225 MENU_POPUPITEM
*popup_item
= (MENU_POPUPITEM
*) item
;
2226 next_item
= (WORD
*) (popup_item
->item_text
+
2227 strlen(popup_item
->item_text
) + 1);
2228 hSubMenu
= CreatePopupMenu();
2229 next_item
= ParseMenuResource(next_item
, level
, hSubMenu
);
2230 AppendMenu(hMenu
, popup_item
->item_flags
,
2231 (UINT
)hSubMenu
, popup_item
->item_text
);
2235 MENUITEMTEMPLATE
*normal_item
= (MENUITEMTEMPLATE
*) item
;
2236 WORD flags
= normal_item
->item_flags
;
2237 next_item
= (WORD
*) (normal_item
->item_text
+
2238 strlen(normal_item
->item_text
) + 1);
2239 if (!normal_item
->item_text
[0] && !normal_item
->item_id
)
2240 flags
|= MF_SEPARATOR
; /* FIXME: do this in InsertMenu? */
2241 AppendMenu( hMenu
, flags
, normal_item
->item_id
,
2242 normal_item
->item_text
);
2244 } while (!(*item
& MF_END
));
2249 /**********************************************************************
2252 BOOL
IsMenu( HMENU hmenu
)
2255 if (!(menu
= (LPPOPUPMENU
) USER_HEAP_LIN_ADDR( hmenu
))) return FALSE
;
2256 return (menu
->wMagic
== MENU_MAGIC
);