Author: jimtabor Date: Mon Jul 10 09:52:41 2006 New Revision: 22989
URL: http://svn.reactos.org/svn/reactos?rev=22989&view=rev Log: - User32 menu - Fixed and modified MenuDrawBitmapItem, MenuGetBitmapItemSize and MenuCalcItemSize. Based on Wine ports. - Fixed menu bar drawing and maintained most callback changes (for Miranda). Implemented flat menu support. Some other misc changes. Owner drawing is still broken (Free pascal project Lazarus). Run user32_crosstest from Wine, still more rewriting is needed.
Modified: trunk/reactos/dll/win32/user32/windows/menu.c
Modified: trunk/reactos/dll/win32/user32/windows/menu.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/user32/windows/me... ============================================================================== --- trunk/reactos/dll/win32/user32/windows/menu.c (original) +++ trunk/reactos/dll/win32/user32/windows/menu.c Mon Jul 10 09:52:41 2006 @@ -331,22 +331,38 @@ * Get the size of a bitmap item. */ static void FASTCALL -MenuGetBitmapItemSize(UINT Id, DWORD Data, SIZE *Size) +MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *Size, HWND WndOwner) { BITMAP Bm; - HBITMAP Bmp = (HBITMAP) Id; + HBITMAP Bmp = lpitem->hbmpItem;
Size->cx = Size->cy = 0;
/* check if there is a magic menu item associated with this item */ - if (0 != Id && IS_MAGIC_ITEM(Id)) - { - switch((INT_PTR) LOWORD(Id)) - { + if (0 != Bmp && IS_MAGIC_ITEM((INT)(Bmp))) + { + switch((INT_PTR) Bmp) + { + case (INT_PTR)HBMMENU_CALLBACK: + { + MEASUREITEMSTRUCT measItem; + measItem.CtlType = ODT_MENU; + measItem.CtlID = 0; + measItem.itemID = lpitem->wID; + measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left; + measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top; + measItem.itemData = lpitem->dwItemData; + SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem); + Size->cx = measItem.itemWidth; + Size->cy = measItem.itemHeight; + return; + } + break; + case (INT_PTR) HBMMENU_SYSTEM: - if (0 != Data) + if (0 != lpitem->dwItemData) { - Bmp = (HBITMAP) Data; + Bmp = (HBITMAP) lpitem->dwItemData; break; } /* fall through */ @@ -359,7 +375,6 @@ Size->cx = GetSystemMetrics(SM_CXSIZE) - 2; Size->cy = GetSystemMetrics(SM_CYSIZE) - 4; return; - case (INT_PTR) HBMMENU_CALLBACK: case (INT_PTR) HBMMENU_POPUP_CLOSE: case (INT_PTR) HBMMENU_POPUP_RESTORE: case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: @@ -383,25 +398,28 @@ * Draw a bitmap item. */ static void FASTCALL -MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, BOOL MenuBar) +MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, + HMENU hmenu, HWND WndOwner, UINT odaction, BOOL MenuBar) { BITMAP Bm; DWORD Rop; HDC DcMem; - HBITMAP Bmp = (HBITMAP) Item->hbmpItem; + HBITMAP Bmp; int w = Rect->right - Rect->left; int h = Rect->bottom - Rect->top; int BmpXoffset = 0; int Left, Top; + HBITMAP hbmpToDraw = (HBITMAP) Item->hbmpItem; + Bmp = hbmpToDraw;
/* Check if there is a magic menu item associated with this item */ - if (IS_MAGIC_ITEM(Item->hbmpItem)) + if (IS_MAGIC_ITEM(hbmpToDraw)) { UINT Flags = 0; RECT r;
r = *Rect; - switch ((int) Item->hbmpItem) + switch ((INT_PTR)hbmpToDraw) { case (INT_PTR) HBMMENU_SYSTEM: if (NULL != Item->hbmpItem) @@ -442,6 +460,31 @@ Flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; break; case (INT_PTR) HBMMENU_CALLBACK: + { + DRAWITEMSTRUCT drawItem; + POINT origorg; + drawItem.CtlType = ODT_MENU; + drawItem.CtlID = 0; + drawItem.itemID = Item->wID; + drawItem.itemAction = odaction; + drawItem.itemState = (Item->fState & MF_CHECKED)?ODS_CHECKED:0; + drawItem.itemState |= (Item->fState & MF_DEFAULT)?ODS_DEFAULT:0; + drawItem.itemState |= (Item->fState & MF_DISABLED)?ODS_DISABLED:0; + drawItem.itemState |= (Item->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; + drawItem.itemState |= (Item->fState & MF_HILITE)?ODS_SELECTED:0; + drawItem.hwndItem = (HWND)hmenu; + drawItem.hDC = Dc; + drawItem.rcItem = *Rect; + drawItem.itemData = Item->dwItemData; + /* some applications make this assumption on the DC's origin */ + SetViewportOrgEx( Dc, Item->Rect.left, Item->Rect.top, &origorg); + OffsetRect( &drawItem.rcItem, - Item->Rect.left, - Item->Rect.top); + SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem); + SetViewportOrgEx( Dc, origorg.x, origorg.y, NULL); + return; + } + break; + case (INT_PTR) HBMMENU_POPUP_CLOSE: case (INT_PTR) HBMMENU_POPUP_RESTORE: case (INT_PTR) HBMMENU_POPUP_MAXIMIZE: @@ -491,7 +534,9 @@ { RECT Rect; PWCHAR Text; - + BOOL flat_menu = FALSE; + int bkgnd; + if (0 != (Item->fType & MF_SYSMENU)) { if (! IsIconic(Wnd)) @@ -504,11 +549,14 @@ return; }
+ SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); + bkgnd = (MenuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU; + /* Setup colors */
if (0 != (Item->fState & MF_HILITE)) { - if (MenuBar) + if (MenuBar && !flat_menu) { SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT)); SetBkColor(Dc, GetSysColor(COLOR_MENU)); @@ -536,7 +584,7 @@ { SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT)); } - SetBkColor(Dc, GetSysColor(COLOR_MENU)); + SetBkColor(Dc, GetSysColor(bkgnd)); }
if (0 != (Item->fType & MF_OWNERDRAW)) @@ -579,7 +627,21 @@ dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom); SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis); - /* Fall through to draw popup-menu arrow */ + /* Draw the popup-menu arrow */ + if (0 != (Item->fType & MF_POPUP)) + { + HDC DcMem = CreateCompatibleDC(Dc); + HBITMAP OrigBitmap; + + OrigBitmap = SelectObject(DcMem, StdMnArrow); + BitBlt(Dc, Rect.right - ArrowBitmapWidth - 1, + ((Rect.top + Rect.bottom) - ArrowBitmapHeight) / 2, + ArrowBitmapWidth, ArrowBitmapHeight, + DcMem, 0, 0, SRCCOPY); + SelectObject(DcMem, OrigBitmap); + DeleteDC(DcMem); + } + return; }
DPRINT("rect={%ld,%ld,%ld,%ld}\n", Item->Rect.left, Item->Rect.top, @@ -596,18 +658,28 @@ { if (Item->fState & MF_HILITE) { - if (MenuBar) - { - DrawEdge(Dc, &Rect, BDR_SUNKENOUTER, BF_RECT); + if (flat_menu) + { + InflateRect (&Rect, -1, -1); + FillRect(Dc, &Rect, GetSysColorBrush(COLOR_MENUHILIGHT)); + InflateRect (&Rect, 1, 1); + FrameRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT)); } else { - FillRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT)); + if (MenuBar) + { + DrawEdge(Dc, &Rect, BDR_SUNKENOUTER, BF_RECT); + } + else + { + FillRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT)); + } } } else { - FillRect(Dc, &Rect, GetSysColorBrush(COLOR_MENU)); + FillRect(Dc, &Rect, GetSysColorBrush(bkgnd)); } }
@@ -618,21 +690,38 @@ /* vertical separator */ if (! MenuBar && 0 != (Item->fType & MF_MENUBARBREAK)) { + HPEN oldPen; RECT rc = Rect; rc.top = 3; rc.bottom = Height - 3; - DrawEdge(Dc, &rc, EDGE_ETCHED, BF_LEFT); + if (flat_menu) + { + oldPen = SelectObject( Dc, GetSysColorPen(COLOR_BTNSHADOW) ); + MoveToEx( Dc, rc.left, rc.top, NULL ); + LineTo( Dc, rc.left, rc.bottom ); + SelectObject( Dc, oldPen ); + } + else + DrawEdge(Dc, &rc, EDGE_ETCHED, BF_LEFT); }
/* horizontal separator */ if (0 != (Item->fType & MF_SEPARATOR)) { + HPEN oldPen; RECT rc = Rect; rc.left++; rc.right--; rc.top += SEPARATOR_HEIGHT / 2; - DrawEdge(Dc, &rc, EDGE_ETCHED, BF_TOP); - + if (flat_menu) + { + oldPen = SelectObject( Dc, GetSysColorPen(COLOR_BTNSHADOW) ); + MoveToEx( Dc, rc.left, rc.top, NULL ); + LineTo( Dc, rc.right, rc.top ); + SelectObject( Dc, oldPen ); + } + else + DrawEdge(Dc, &rc, EDGE_ETCHED, BF_TOP); return; } } @@ -646,7 +735,7 @@ #endif
if (! MenuBar) - { + { INT y = Rect.top + Rect.bottom; UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK); UINT CheckBitmapHeight = GetSystemMetrics(SM_CYMENUCHECK); @@ -685,34 +774,7 @@ } if (Item->hbmpItem) { - if (Item->hbmpItem == HBMMENU_CALLBACK) - { - DRAWITEMSTRUCT drawItem; - POINT origorg; - drawItem.CtlType = ODT_MENU; - drawItem.CtlID = 0; - drawItem.itemID = Item->wID; - drawItem.itemAction = Action; - drawItem.itemState = (Item->fState & MF_CHECKED)?ODS_CHECKED:0; - drawItem.itemState |= (Item->fState & MF_DEFAULT)?ODS_DEFAULT:0; - drawItem.itemState |= (Item->fState & MF_DISABLED)?ODS_DISABLED:0; - drawItem.itemState |= (Item->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; - drawItem.itemState |= (Item->fState & MF_HILITE)?ODS_SELECTED:0; - drawItem.hwndItem = (HWND) MenuInfo->Self; - drawItem.hDC = Dc; - drawItem.rcItem = Item->Rect; - drawItem.itemData = Item->dwItemData; - /* some applications make this assumption on the DC's origin */ - SetViewportOrgEx( Dc, Item->Rect.left, Item->Rect.top, &origorg); - OffsetRect( &drawItem.rcItem, - Item->Rect.left, - Item->Rect.top); - SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem); - SetViewportOrgEx( Dc, origorg.x, origorg.y, NULL); - } - else - { - MenuDrawBitmapItem(Dc, Item, &Rect, MenuBar); - return; - } + MenuDrawBitmapItem(Dc, Item, &Rect, MenuInfo->Self, WndOwner, Action, MenuBar); } }
@@ -731,22 +793,24 @@ DeleteDC(DcMem); }
- Rect.left += CheckBitmapWidth; - Rect.right -= ArrowBitmapWidth; - } - else if( Item->hbmpItem && !(Item->fType & MF_OWNERDRAW)) - { /* Draw the bitmap */ - MenuDrawBitmapItem(Dc, Item, &Rect, MenuBar); - } + Rect.left += CheckBitmapWidth; + Rect.right -= ArrowBitmapWidth; + } + else + /* Draw the item text or bitmap */ + if (Item->hbmpItem && !(Item->fType & MF_OWNERDRAW)) //IS_BITMAP_ITEM(Item->fType)) + { + MenuDrawBitmapItem(Dc, Item, &Rect, MenuInfo->Self, WndOwner, Action, MenuBar); + }
/* Done for owner-drawn */ if (0 != (Item->fType & MF_OWNERDRAW)) { return; } - - /* process text if present */ - if (!(Item->fType & MF_SYSMENU) && Item->dwTypeData) + + /* No bitmap - process text if present */ + else if ( !(Item->fType & MF_SYSMENU) && IS_STRING_ITEM(Item->fType)) { register int i; HFONT FontOld = NULL; @@ -769,7 +833,6 @@ Rect.left += MenuInfo->maxBmpSize.cx; Rect.right -= MenuInfo->maxBmpSize.cx; } - Text = (PWCHAR) Item->dwTypeData; for (i = 0; L'\0' != Text[i]; i++) { @@ -790,6 +853,7 @@ } SetTextColor(Dc, RGB(0x80, 0x80, 0x80)); } + DrawTextW(Dc, Text, i, &Rect, uFormat);
/* paint the shortcut text */ @@ -853,7 +917,13 @@ PrevPen = SelectObject(Dc, GetStockObject(NULL_PEN)); if (NULL != PrevPen) { - DrawEdge(Dc, &Rect, EDGE_RAISED, BF_RECT); + BOOL flat_menu = FALSE; + + SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); + if (flat_menu) + FrameRect(Dc, &Rect, GetSysColorBrush(COLOR_BTNSHADOW)); + else + DrawEdge(Dc, &Rect, EDGE_RAISED, BF_RECT);
/* draw menu items */
@@ -890,7 +960,7 @@ case WM_CREATE: { CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - SetWindowLongW(Wnd, 0, (LONG) cs->lpCreateParams); + SetWindowLongPtrW(Wnd, 0, (LONG) cs->lpCreateParams); return 0; }
@@ -901,7 +971,7 @@ { PAINTSTRUCT ps; BeginPaint(Wnd, &ps); - MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongW(Wnd, 0)); + MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrW(Wnd, 0)); EndPaint(Wnd, &ps); return 0; } @@ -920,23 +990,23 @@ case WM_SHOWWINDOW: if (0 != wParam) { - if (0 == GetWindowLongW(Wnd, 0)) + if (0 == GetWindowLongPtrW(Wnd, 0)) { OutputDebugStringA("no menu to display\n"); } } else { - SetWindowLongW(Wnd, 0, 0); + SetWindowLongPtrW(Wnd, 0, 0); } break;
case MM_SETMENUHANDLE: - SetWindowLongW(Wnd, 0, wParam); + SetWindowLongPtrW(Wnd, 0, wParam); break;
case MM_GETMENUHANDLE: - return GetWindowLongW(Wnd, 0); + return GetWindowLongPtrW(Wnd, 0);
default: return DefWindowProcW(Wnd, Message, wParam, lParam); @@ -1159,11 +1229,14 @@ mis.CtlID = 0; mis.itemID = ItemInfo->wID; mis.itemData = (DWORD)ItemInfo->dwItemData; - mis.itemHeight = 0; + mis.itemHeight = HIWORD( GetDialogBaseUnits()); mis.itemWidth = 0; SendMessageW(WndOwner, WM_MEASUREITEM, 0, (LPARAM) &mis); - ItemInfo->Rect.right += mis.itemWidth; - + /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average + * width of a menufont character to the width of an owner-drawn menu. + */ + ItemInfo->Rect.right += mis.itemWidth + 2 * + GdiGetCharDimensions( Dc, NULL, NULL ); if (MenuBar) { ItemInfo->Rect.right += MENU_BAR_ITEMS_SPACE; @@ -1193,57 +1266,47 @@ return; }
- if (! MenuBar) - { - if (ItemInfo->hbmpItem) + if (ItemInfo->hbmpItem) //IS_BITMAP_ITEM(ItemInfo->fType)) + { + SIZE Size; + + if (!MenuBar) { - if (ItemInfo->hbmpItem == HBMMENU_CALLBACK) - { - MEASUREITEMSTRUCT measItem; - measItem.CtlType = ODT_MENU; - measItem.CtlID = 0; - measItem.itemID = ItemInfo->wID; - measItem.itemWidth = ItemInfo->Rect.right - ItemInfo->Rect.left; - measItem.itemHeight = ItemInfo->Rect.bottom - ItemInfo->Rect.top; - measItem.itemData = ItemInfo->dwItemData; - SendMessageW( WndOwner, WM_MEASUREITEM, ItemInfo->wID, (LPARAM)&measItem); - ItemInfo->Rect.right = ItemInfo->Rect.left + measItem.itemWidth; - if (MenuInfo->maxBmpSize.cx < abs(measItem.itemWidth) + MENU_ITEM_HBMP_SPACE || - MenuInfo->maxBmpSize.cy < abs(measItem.itemHeight)) - { - MenuInfo->maxBmpSize.cx = abs(measItem.itemWidth) + MENU_ITEM_HBMP_SPACE; - MenuInfo->maxBmpSize.cy = abs(measItem.itemHeight); - MenuSetRosMenuInfo(MenuInfo); - } - } - else - { - SIZE Size; - - MenuGetBitmapItemSize((int) ItemInfo->hbmpItem, (DWORD) ItemInfo->hbmpItem, &Size); - ItemInfo->Rect.right += Size.cx; - ItemInfo->Rect.bottom += Size.cy; - - /* Leave space for the sunken border */ - ItemInfo->Rect.right += 2; - ItemInfo->Rect.bottom += 2; - - /* Special case: Minimize button doesn't have a space behind it. */ - if (ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE || - ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D) - ItemInfo->Rect.right -= 1; - } - ItemInfo->Rect.right += 2 * CheckBitmapWidth; + MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner ); + /* Keep the size of the bitmap in callback mode to be able + * to draw it correctly */ + ItemInfo->Rect.right = ItemInfo->Rect.left + Size.cx; + if (MenuInfo->maxBmpSize.cx < abs(Size.cx) + MENU_ITEM_HBMP_SPACE || + MenuInfo->maxBmpSize.cy < abs(Size.cy)) + { + MenuInfo->maxBmpSize.cx = abs(Size.cx) + MENU_ITEM_HBMP_SPACE; + MenuInfo->maxBmpSize.cy = abs(Size.cy); + } + MenuSetRosMenuInfo(MenuInfo); + + ItemInfo->Rect.right += 2 * CheckBitmapWidth; + if (0 != (ItemInfo->fType & MF_POPUP)) + { + ItemInfo->Rect.right += ArrowBitmapWidth; + } + } else { - ItemInfo->Rect.right += 2 * CheckBitmapWidth; - if (0 != (ItemInfo->fType & MF_POPUP)) - { - ItemInfo->Rect.right += ArrowBitmapWidth; - } + MenuGetBitmapItemSize(ItemInfo, &Size, WndOwner ); + ItemInfo->Rect.right += Size.cx; + ItemInfo->Rect.bottom += Size.cy; + + /* Leave space for the sunken border */ + ItemInfo->Rect.right += 2; + ItemInfo->Rect.bottom += 2; + + /* Special case: Minimize button doesn't have a space behind it. */ + if (ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE || + ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D) + ItemInfo->Rect.right -= 1; } - } + }
/* it must be a text item - unless it's the system menu */ if (0 == (ItemInfo->fType & MF_SYSMENU) && IS_STRING_ITEM(ItemInfo->fType)) @@ -1548,7 +1611,10 @@ ROSMENUITEMINFO ItemInfo; UINT i; HFONT FontOld = NULL; - + BOOL flat_menu = FALSE; + + SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); + if (NULL == Menu) { Menu = GetMenu(Wnd); @@ -1575,7 +1641,7 @@
Rect->bottom = Rect->top + MenuInfo.Height;
- FillRect(DC, Rect, GetSysColorBrush(COLOR_MENU)); + FillRect(DC, Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
SelectObject(DC, GetSysColorPen(COLOR_3DFACE)); MoveToEx(DC, Rect->left, Rect->bottom, NULL); @@ -1759,7 +1825,7 @@ /* NOTE: In Windows, top menu popup is not owned. */ MenuInfo.Wnd = CreateWindowExW(0, POPUPMENU_CLASS_ATOMW, NULL, WS_POPUP, X, Y, Width, Height, - WndOwner, 0, (HINSTANCE) GetWindowLongW(WndOwner, GWL_HINSTANCE), + WndOwner, 0, (HINSTANCE) GetWindowLongPtrW(WndOwner, GWLP_HINSTANCE), (LPVOID) MenuInfo.Self); if (NULL == MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) { @@ -3458,7 +3524,7 @@ /* The return value is only used by TrackPopupMenu */ if (!(Flags & TPM_RETURNCMD)) return TRUE; if (ExecutedMenuId < 0) ExecutedMenuId = 0; - return ExecutedMenuId; + return ExecutedMenuId; }
/*********************************************************************** @@ -4939,3 +5005,5 @@ return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem); }; } + +