]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/tbar95.cpp
Better fix
[wxWidgets.git] / src / msw / tbar95.cpp
index 48e70146585ff59670428760cbc6f3388e907f0b..16ebe1ffc1e571455afdd10fc5bfc5c56fada6e5 100644 (file)
     #include "wx/control.h"
     #include "wx/app.h"         // for GetComCtl32Version
     #include "wx/image.h"
+    #include "wx/stattext.h"
 #endif
 
 #include "wx/sysopt.h"
+#include "wx/dcclient.h"
 
 #include "wx/msw/private.h"
+#include "wx/msw/dc.h"
 
 #if wxUSE_UXTHEME
 #include "wx/msw/uxtheme.h"
@@ -257,7 +260,7 @@ void wxToolBar::Init()
     m_defaultWidth = DEFAULTBITMAPX;
     m_defaultHeight = DEFAULTBITMAPY;
 
-    m_pInTool = 0;
+    m_pInTool = NULL;
 }
 
 bool wxToolBar::Create(wxWindow *parent,
@@ -302,6 +305,11 @@ bool wxToolBar::MSWCreateToolbar(const wxPoint& pos, const wxSize& size)
     // toolbar-specific post initialisation
     ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
 
+#ifdef TB_SETEXTENDEDSTYLE
+    if ( wxApp::GetComCtl32Version() >= 471 )
+        ::SendMessage(GetHwnd(), TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
+#endif
+
     return true;
 }
 
@@ -399,6 +407,17 @@ wxSize wxToolBar::DoGetBestSize() const
         sizeBest.y = size.cy;
     }
 
+    if (!IsVertical())
+    {
+        // Without the extra height, DoGetBestSize can report a size that's
+        // smaller than the actual window, causing windows to overlap slightly
+        // in some circumstances, leading to missing borders (especially noticeable
+        // in AUI layouts).
+        if (!(GetWindowStyle() & wxTB_NODIVIDER))
+            sizeBest.y += 2;
+        sizeBest.y ++;
+    }
+
     CacheBestSize(sizeBest);
 
     return sizeBest;
@@ -786,8 +805,8 @@ bool wxToolBar::Realize()
                 TBREPLACEBITMAP replaceBitmap;
                 replaceBitmap.hInstOld = NULL;
                 replaceBitmap.hInstNew = NULL;
-                replaceBitmap.nIDOld = (UINToldToolBarBitmap;
-                replaceBitmap.nIDNew = (UINThBitmap;
+                replaceBitmap.nIDOld = (UINT_PTR)oldToolBarBitmap;
+                replaceBitmap.nIDNew = (UINT_PTR)hBitmap;
                 replaceBitmap.nButtons = nButtons;
                 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
                                     0, (LPARAM) &replaceBitmap) )
@@ -816,7 +835,7 @@ bool wxToolBar::Realize()
         {
             TBADDBITMAP addBitmap;
             addBitmap.hInst = 0;
-            addBitmap.nID = (UINThBitmap;
+            addBitmap.nID = (UINT_PTR)hBitmap;
             if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
                                (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
             {
@@ -896,7 +915,7 @@ bool wxToolBar::Realize()
                 {
                     const wxString& label = tool->GetLabel();
                     if ( !label.empty() )
-                        button.iString = (int)label.wx_str();
+                        button.iString = (INT_PTR)label.wx_str();
                 }
 
                 button.idCommand = tool->GetId();
@@ -923,7 +942,7 @@ bool wxToolBar::Realize()
                                 DoToggleTool(tool, true);
                             }
                         }
-                        else if (tool->IsToggled())
+                        else if ( tool->IsToggled() )
                         {
                             wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious();
                             int prevIndex = i - 1;
@@ -937,7 +956,7 @@ bool wxToolBar::Realize()
                                 if ( tool->Toggle(false) )
                                     DoToggleTool(tool, false);
 
-                                prevButton.fsState = TBSTATE_ENABLED;
+                                prevButton.fsState &= ~TBSTATE_CHECKED;
                                 nodePrev = nodePrev->GetPrevious();
                                 prevIndex--;
                             }
@@ -954,6 +973,10 @@ bool wxToolBar::Realize()
                         button.fsStyle = TBSTYLE_BUTTON;
                         break;
 
+                   case wxITEM_DROPDOWN:
+                        button.fsStyle = TBSTYLE_DROPDOWN;
+                        break;
+
                     default:
                         wxFAIL_MSG( _T("unexpected toolbar button kind") );
                         button.fsStyle = TBSTYLE_BUTTON;
@@ -1157,9 +1180,14 @@ bool wxToolBar::Realize()
 // message handlers
 // ----------------------------------------------------------------------------
 
-bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
+bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id_)
 {
-    wxToolBarToolBase *tool = FindById((int)id);
+    // cast to signed is important as we compare this id with (signed) ints in
+    // FindById() and without the cast we'd get a positive int from a
+    // "negative" (i.e. > 32767) WORD
+    const int id = (signed short)id_;
+
+    wxToolBarToolBase *tool = FindById(id);
     if ( !tool )
         return false;
 
@@ -1181,7 +1209,7 @@ bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
 
     // OnLeftClick() can veto the button state change - for buttons which
     // may be toggled only, of couse
-    if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
+    if ( !OnLeftClick(id, toggled) && tool->CanBeToggled() )
     {
         // revert back
         tool->Toggle(!toggled);
@@ -1196,11 +1224,38 @@ bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl),
                             WXLPARAM lParam,
                             WXLPARAM *WXUNUSED(result))
 {
+    LPNMHDR hdr = (LPNMHDR)lParam;
+    if ( hdr->code == TBN_DROPDOWN )
+    {
+        LPNMTOOLBAR tbhdr = (LPNMTOOLBAR)lParam;
+
+        wxCommandEvent evt(wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED, tbhdr->iItem);
+        if ( HandleWindowEvent(evt) )
+        {
+            // Event got handled, don't display default popup menu
+            return false;
+        }
+
+        const wxToolBarToolBase * const tool = FindById(tbhdr->iItem);
+        wxCHECK_MSG( tool, false, _T("drop down message for unknown tool") );
+
+        wxMenu * const menu = tool->GetDropdownMenu();
+        if ( !menu )
+            return false;
+
+        // Display popup menu below button
+        RECT r;
+        if (::SendMessage(GetHwnd(), TB_GETITEMRECT, GetToolPos(tbhdr->iItem), (LPARAM)&r))
+            PopupMenu(menu, r.left, r.bottom);
+
+        return true;
+    }
+
+
     if( !HasFlag(wxTB_NO_TOOLTIPS) )
     {
 #if wxUSE_TOOLTIPS
         // First check if this applies to us
-        NMHDR *hdr = (NMHDR *)lParam;
 
         // the tooltips control created by the toolbar is sometimes Unicode, even
         // in an ANSI application - this seems to be a bug in comctl32.dll v5
@@ -1451,9 +1506,14 @@ void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
 
 void wxToolBar::OnMouseEvent(wxMouseEvent& event)
 {
-    if (event.Leaving() && m_pInTool)
+    if ( event.Leaving() )
     {
-        OnMouseEnter( -1 );
+        if ( m_pInTool )
+        {
+            OnMouseEnter(wxID_ANY);
+            m_pInTool = NULL;
+        }
+
         event.Skip();
         return;
     }
@@ -1478,7 +1538,14 @@ void wxToolBar::OnMouseEvent(wxMouseEvent& event)
 void wxToolBar::OnEraseBackground(wxEraseEvent& event)
 {
     RECT rect = wxGetClientRect(GetHwnd());
-    HDC hdc = GetHdcOf((*event.GetDC()));
+    
+    wxDC *dc = event.GetDC();
+    if (!dc) return;
+    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc->GetImpl();
+    HDC hdc = GetHdcOf(*impl);
+
+    int majorVersion, minorVersion;
+    wxGetOsVersion(& majorVersion, & minorVersion);
 
 #if wxUSE_UXTHEME
     // we may need to draw themed colour so that we appear correctly on
@@ -1500,9 +1567,36 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event)
                 wxLogApiError(_T("DrawThemeParentBackground(toolbar)"), hr);
         }
     }
+
+    // Only draw a rebar theme on Vista, since it doesn't jive so well with XP
+    if ( !UseBgCol() && majorVersion >= 6 )
+    {
+        wxUxThemeEngine *theme = wxUxThemeEngine::GetIfActive();
+        if ( theme )
+        {
+            wxUxThemeHandle hTheme(this, L"REBAR");
+
+            RECT r;
+            wxRect rect = GetClientRect();
+            wxCopyRectToRECT(rect, r);
+
+            HRESULT hr = theme->DrawThemeBackground(hTheme, hdc, 0, 0, & r, NULL);
+            if ( hr == S_OK )
+                return;
+
+            // it can also return S_FALSE which seems to simply say that it
+            // didn't draw anything but no error really occurred
+            if ( FAILED(hr) )
+                wxLogApiError(_T("DrawThemeParentBackground(toolbar)"), hr);
+        }
+    }
+
 #endif // wxUSE_UXTHEME
 
-    if ( UseBgCol() || (GetMSWToolbarStyle() & TBSTYLE_TRANSPARENT) )
+    // we need to always draw our background under XP, as otherwise it doesn't
+    // appear correctly with some themes (e.g. Zune one)
+    if ( majorVersion == 5 ||
+            UseBgCol() || (GetMSWToolbarStyle() & TBSTYLE_TRANSPARENT) )
     {
         // do draw our background
         //
@@ -1584,6 +1678,10 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
         // no controls, nothing to erase
         return false;
 
+    wxSize clientSize = GetClientSize();
+    int majorVersion, minorVersion;
+    wxGetOsVersion(& majorVersion, & minorVersion);
+
     // prepare the DC on which we'll be drawing
     wxClientDC dc(this);
     dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
@@ -1653,20 +1751,54 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
                 // does it intersect the control?
                 wxRect rectItem;
                 wxCopyRECTToRect(r, rectItem);
-                if ( rectCtrl.Intersects(rectItem) )
+                if ( rectCtrl.Intersects(rectItem) || (staticText && rectStaticText.Intersects(rectItem)))
                 {
                     // yes, do erase it!
-                    dc.DrawRectangle(rectItem);
 
+                    bool haveRefreshed = false;
+
+#if wxUSE_UXTHEME
+                    if ( !UseBgCol() && !GetParent()->UseBgCol() )
+                    {
+                        // Don't use DrawThemeBackground
+                    }
+                    else if ( !UseBgCol() && majorVersion >= 6 )
+                    {
+                        wxUxThemeEngine *theme = wxUxThemeEngine::GetIfActive();
+                        if ( theme )
+                        {
+                            wxUxThemeHandle hTheme(this, L"REBAR");
+
+                            RECT clipRect = r;
+
+                            // Draw the whole background since the pattern may be position sensitive;
+                            // but clip it to the area of interest.
+                            r.left = 0;
+                            r.right = clientSize.x;
+                            r.top = 0;
+                            r.bottom = clientSize.y;
+                            
+                            wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+                            HRESULT hr = theme->DrawThemeBackground(hTheme, GetHdcOf(*impl), 0, 0, & r, & clipRect);
+                            if ( hr == S_OK )
+                                haveRefreshed = true;
+                        }
+                    }
+#endif
+
+                    if (!haveRefreshed)
+                        dc.DrawRectangle(rectItem);
+                }
+
+                if ( rectCtrl.Intersects(rectItem) )
+                {
                     // Necessary in case we use a no-paint-on-size
                     // style in the parent: the controls can disappear
                     control->Refresh(false);
                 }
+
                 if ( staticText && rectStaticText.Intersects(rectItem) )
                 {
-                    // yes, do erase it!
-                    dc.DrawRectangle(rectItem);
-
                     // Necessary in case we use a no-paint-on-size
                     // style in the parent: the controls can disappear
                     staticText->Refresh(false);
@@ -1684,18 +1816,11 @@ void wxToolBar::HandleMouseMove(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
             y = GET_Y_LPARAM(lParam);
     wxToolBarToolBase* tool = FindToolForPosition( x, y );
 
-    // cursor left current tool
-    if ( tool != m_pInTool && !tool )
-    {
-        m_pInTool = 0;
-        OnMouseEnter( -1 );
-    }
-
-    // cursor entered a tool
-    if ( tool != m_pInTool && tool )
+    // has the current tool changed?
+    if ( tool != m_pInTool )
     {
         m_pInTool = tool;
-        OnMouseEnter( tool->GetId() );
+        OnMouseEnter(tool ? tool->GetId() : wxID_ANY);
     }
 }