]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/menu.cpp
Handle the case of NSNotFound result properly.
[wxWidgets.git] / src / msw / menu.cpp
index 46346acca8a8482e1b29167ad43b1156c613f609..93984343d1f2d3a3c00b0218fee417ebe8d6a32d 100644 (file)
     #include "wx/utils.h"
     #include "wx/intl.h"
     #include "wx/log.h"
+    #include "wx/image.h"
 #endif
 
 #if wxUSE_OWNER_DRAWN
     #include "wx/ownerdrw.h"
 #endif
 
-#include "wx/ptr_scpd.h"
+#include "wx/scopedarray.h"
 
 #include "wx/msw/private.h"
 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
@@ -117,7 +118,9 @@ UINT GetMenuState(HMENU hMenu, UINT id, UINT flags)
     info.fMask = MIIM_STATE;
     // MF_BYCOMMAND is zero so test MF_BYPOSITION
     if ( !::GetMenuItemInfo(hMenu, id, flags & MF_BYPOSITION ? TRUE : FALSE , & info) )
+    {
         wxLogLastError(wxT("GetMenuItemInfo"));
+    }
     return info.fState;
 }
 #endif // __WXWINCE__
@@ -363,6 +366,49 @@ void wxMenu::UpdateAccel(wxMenuItem *item)
 
 #endif // wxUSE_ACCEL
 
+namespace
+{
+
+// helper of DoInsertOrAppend(): returns the HBITMAP to use in MENUITEMINFO
+HBITMAP GetHBitmapForMenu(wxMenuItem *pItem, bool checked = true)
+{
+    // Under versions of Windows older than Vista we can't pass HBITMAP
+    // directly as hbmpItem for 2 reasons:
+    //  1. We can't draw it with transparency then (this is not
+    //     very important now but would be with themed menu bg)
+    //  2. Worse, Windows inverts the bitmap for the selected
+    //     item and this looks downright ugly
+    //
+    // So we prefer to instead draw it ourselves in MSWOnDrawItem().by using
+    // HBMMENU_CALLBACK when inserting it
+    //
+    // However under Vista using HBMMENU_CALLBACK causes the entire menu to be
+    // drawn using the classic theme instead of the current one and it does
+    // handle transparency just fine so do use the real bitmap there
+#if wxUSE_IMAGE
+    if ( wxGetWinVersion() >= wxWinVersion_Vista )
+    {
+        wxBitmap bmp = pItem->GetBitmap(checked);
+        if ( bmp.IsOk() )
+        {
+            // we must use PARGB DIB for the menu bitmaps so ensure that we do
+            wxImage img(bmp.ConvertToImage());
+            if ( !img.HasAlpha() )
+            {
+                img.InitAlpha();
+                pItem->SetBitmap(img, checked);
+            }
+
+            return GetHbitmapOf(pItem->GetBitmap(checked));
+        }
+    }
+#endif // wxUSE_IMAGE
+
+    return HBMMENU_CALLBACK;
+}
+
+} // anonymous namespace
+
 // append a new item or submenu to the menu
 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
 {
@@ -419,12 +465,14 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
     BOOL ok = false;
 
 #if wxUSE_OWNER_DRAWN
-    // Currently, mixing owner-drawn and non-owner-drawn items results in
-    // inconsistent margins, so we force this to be owner-drawn if any other
-    // items already are. Later we might want to use a boolean in the wxMenu
-    // to avoid search. Also we might make this fix unnecessary by getting the correct
-    // margin using NONCLIENTMETRICS.
-    if ( !pItem->IsOwnerDrawn() && !pItem->IsSeparator() )
+    // Under older systems mixing owner-drawn and non-owner-drawn items results
+    // in inconsistent margins, so we force this one to be owner-drawn if any
+    // other items already are. Later we might want to use a boolean in the
+    // wxMenu to avoid search. Also we might make this fix unnecessary by
+    // getting the correct margin using NONCLIENTMETRICS.
+    static const wxWinVersion winver = wxGetWinVersion();
+    if ( winver < wxWinVersion_XP &&
+            !pItem->IsOwnerDrawn() && !pItem->IsSeparator() )
     {
         // Check if any other items are ownerdrawn, and make ownerdrawn if so
         wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
@@ -438,17 +486,18 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
             node = node->GetNext();
         }
     }
-#endif
+#endif // wxUSE_OWNER_DRAWN
 
     // check if we have something more than a simple text item
 #if wxUSE_OWNER_DRAWN
     if ( pItem->IsOwnerDrawn() )
     {
 #ifndef __DMC__
-        // if the item is owner-drawn just because of the [checked] bitmap and
-        // the bitmap uses standard menu bitmap size we can avoid making it
-        // owner-drawn and use built-in support for menu bitmaps instead
-        bool mustUseOwnerDrawn = pItem->GetTextColour().Ok() ||
+        // MIIM_BITMAP only works under WinME/2000+ so we always use owner
+        // drawn item under the previous versions and we also have to use them
+        // in any case if the item has custom colours or font
+        bool mustUseOwnerDrawn = winver < wxWinVersion_98 ||
+                                 pItem->GetTextColour().Ok() ||
                                  pItem->GetBackgroundColour().Ok() ||
                                  pItem->GetFont().Ok();
         if ( !mustUseOwnerDrawn )
@@ -462,27 +511,33 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
             }
         }
 
-        // MIIM_BITMAP only works under WinME/2000+
-        if ( !mustUseOwnerDrawn && wxGetWinVersion() >= wxWinVersion_98 )
+        // use InsertMenuItem() if possible as it's guaranteed to look correct
+        // while our owner-drawn code is not
+        if ( !mustUseOwnerDrawn )
         {
-            // use InsertMenuItem() as it's guaranteed to look correct while
-            // our owner-drawn code is not
             WinStruct<MENUITEMINFO> mii;
-            mii.fMask = MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
+            mii.fMask = MIIM_STRING | MIIM_DATA;
+
+            if ( pItem->GetBitmap().IsOk() )
+            {
+                mii.fMask |= MIIM_BITMAP;
+                mii.hbmpItem = GetHBitmapForMenu(pItem);
+            }
+
             if ( pItem->IsCheckable() )
             {
-                // need to set checked/unchecked bitmaps as otherwise our
-                // MSWOnDrawItem() item is not called
                 mii.fMask |= MIIM_CHECKMARKS;
+                mii.hbmpChecked = GetHBitmapForMenu(pItem, true);
+                mii.hbmpUnchecked = GetHBitmapForMenu(pItem, false);
             }
 
             mii.cch = itemText.length();
             mii.dwTypeData = const_cast<wxChar *>(itemText.wx_str());
 
-            if (flags & MF_POPUP)
+            if ( flags & MF_POPUP )
             {
                 mii.fMask |= MIIM_SUBMENU;
-                mii.hSubMenu = (HMENU)pItem->GetSubMenu()->GetHMenu();
+                mii.hSubMenu = GetHmenuOf(pItem->GetSubMenu());
             }
             else
             {
@@ -490,20 +545,7 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
                 mii.wID = id;
             }
 
-            // we can't pass HBITMAP directly as hbmpItem for 2 reasons:
-            //  1. we can't draw it with transparency then (this is not
-            //     very important now but would be with themed menu bg)
-            //  2. worse, Windows inverts the bitmap for the selected
-            //     item and this looks downright ugly
-            //
-            // so instead draw it ourselves in MSWOnDrawItem()
             mii.dwItemData = reinterpret_cast<ULONG_PTR>(pItem);
-            if ( pItem->IsCheckable() )
-            {
-                mii.hbmpChecked =
-                mii.hbmpUnchecked = HBMMENU_CALLBACK;
-            }
-            mii.hbmpItem = HBMMENU_CALLBACK;
 
             ok = ::InsertMenuItem(GetHmenu(), pos, TRUE /* by pos */, &mii);
             if ( !ok )
@@ -522,14 +564,16 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
                 // the app from starting up under Windows 95/NT 4
                 typedef BOOL (WINAPI *SetMenuInfo_t)(HMENU, MENUINFO *);
 
-                wxDynamicLibrary dllUser(_T("user32"));
+                wxDynamicLibrary dllUser(wxT("user32"));
                 wxDYNLIB_FUNCTION(SetMenuInfo_t, SetMenuInfo, dllUser);
                 if ( pfnSetMenuInfo )
                 {
                     mi.fMask = MIM_STYLE;
                     mi.dwStyle = MNS_CHECKORBMP;
                     if ( !(*pfnSetMenuInfo)(GetHmenu(), &mi) )
-                        wxLogLastError(_T("SetMenuInfo(MNS_NOCHECK)"));
+                    {
+                        wxLogLastError(wxT("SetMenuInfo(MNS_NOCHECK)"));
+                    }
                 }
 
                 // tell the item that it's not really owner-drawn but only
@@ -595,7 +639,7 @@ void wxMenu::EndRadioGroup()
 
 wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
 {
-    wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
+    wxCHECK_MSG( item, NULL, wxT("NULL item in wxMenu::DoAppend") );
 
     bool check = false;
 
@@ -627,7 +671,7 @@ wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
             }
             else
             {
-                wxFAIL_MSG( _T("where is the radio group start item?") );
+                wxFAIL_MSG( wxT("where is the radio group start item?") );
             }
         }
     }
@@ -1406,9 +1450,13 @@ bool wxMenuBar::AddAdornments(long style)
     if (style & wxCLOSE_BOX)
     {
         if (!CommandBar_AddAdornments((HWND) m_commandBar, 0, 0))
+        {
             wxLogLastError(wxT("CommandBar_AddAdornments"));
+        }
         else
+        {
             return true;
+        }
     }
     return false;
 }