From 8c118ca4cb5b10428e48867ee2a50838d739d740 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 18 Dec 2009 22:31:48 +0000 Subject: [PATCH] Don't draw over dummy separators in MSW toolbar, just don't draw them at all. Prevent the native toolbar from drawing the separators which we use simply as placeholders by excluding them from the update region when handling WM_PAINT. This reduces flicker by not redrawing the areas occupied by these separators twice and also prevents them from ever being shown (you could see them briefly appear before being erased before). The other toolbar tools still flicker though, there doesn't seem to be any simple way to prevent the control from entirely invalidating itself whenever it is resized. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62934 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/toolbar.h | 6 -- src/msw/toolbar.cpp | 141 +++++++++------------------------------ 2 files changed, 32 insertions(+), 115 deletions(-) diff --git a/include/wx/msw/toolbar.h b/include/wx/msw/toolbar.h index eadf5217c4..2161bc49c4 100644 --- a/include/wx/msw/toolbar.h +++ b/include/wx/msw/toolbar.h @@ -156,12 +156,6 @@ private: // have void UpdateStretchableSpacersSize(); -#ifndef __WXWINCE__ - // redraw the background of the given part of the window to erase separator - // drawn in it - void MSWEraseRect(wxDC& dc, const wxRect& rectItem); -#endif // !__WXWINCE__ - DECLARE_EVENT_TABLE() DECLARE_DYNAMIC_CLASS(wxToolBar) wxDECLARE_NO_COPY_CLASS(wxToolBar); diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index 1a9e9efe86..71aec08351 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -940,6 +940,10 @@ bool wxToolBar::Realize() // so we need a valid id for it and not wxID_SEPARATOR // which is used by spacers by default tool->AllocSpacerId(); + + // also set the number of separators so that the logic in + // HandlePaint() works correctly + tool->SetSeparatorsCount(1); } button.idCommand = tool->GetId(); @@ -1196,7 +1200,11 @@ bool wxToolBar::Realize() void wxToolBar::UpdateStretchableSpacersSize() { - // we can't resize the spacers if TB_SETBUTTONINFO is not supported +#ifdef TB_SETBUTTONINFO + // we can't resize the spacers if TB_SETBUTTONINFO is not supported (we + // could try to do it with multiple separators as for the controls but this + // is too painful and it just doesn't seem to be worth doing for the + // ancient systems) if ( wxApp::GetComCtl32Version() < 471 ) return; @@ -1263,6 +1271,7 @@ void wxToolBar::UpdateStretchableSpacersSize() offset += tbbi.cx - (rcOld.right - rcOld.left); } } +#endif // TB_SETBUTTONINFO } // ---------------------------------------------------------------------------- @@ -1700,127 +1709,41 @@ bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam) #ifndef __WXWINCE__ -void wxToolBar::MSWEraseRect(wxDC& dc, const wxRect& rectItem) +bool wxToolBar::HandlePaint(WXWPARAM WXUNUSED(wParam), WXLPARAM WXUNUSED(lParam)) { - dc.DrawRectangle(rectItem); -} - -bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam) -{ - // erase any dummy separators which were used only for reserving space in - // the toolbar (either for a control or just for a stretchable space) - - // first of all, are there any controls at all? - wxToolBarToolsList::compatibility_iterator node; - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - wxToolBarToolBase * const tool = node->GetData(); - if ( tool->IsControl() || tool->IsStretchableSpace() ) - break; - } - - if ( !node ) - { - // no controls, nothing to erase - return false; - } - - // prepare the DC on which we'll be drawing - wxClientDC dc(this); - dc.SetBrush(GetBackgroundColour()); - dc.SetPen(*wxTRANSPARENT_PEN); - - RECT rcUpdate; - if ( !::GetUpdateRect(GetHwnd(), &rcUpdate, FALSE) ) - { - // nothing to redraw anyhow - return false; - } - - const wxRect rectUpdate = wxRectFromRECT(rcUpdate); - dc.SetClippingRegion(rectUpdate); - - // draw the toolbar tools, separators &c normally - wxControl::MSWWindowProc(WM_PAINT, wParam, lParam); - - // for each control in the toolbar find all the separators intersecting it - // and erase them - // - // NB: this is really the only way to do it as we don't know if a separator - // corresponds to a control (i.e. is a dummy one) or a real one - // otherwise + // exclude the area occupied by the controls and stretchable spaces from + // the update region to prevent the toolbar from drawing separators in it int toolIndex = 0; - for ( node = m_tools.GetFirst(); node; node = node->GetNext(), toolIndex++ ) + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) { - wxToolBarTool *tool = (wxToolBarTool*)node->GetData(); - if ( tool->IsControl() ) + wxToolBarTool * const + tool = static_cast(node->GetData()); + + if ( tool->IsControl() || tool->IsStretchableSpace() ) { - // get the control rect in our client coords - wxControl *control = tool->GetControl(); - wxStaticText *staticText = tool->GetStaticText(); - wxRect rectCtrl = control->GetRect(); - wxRect rectStaticText; - if ( staticText ) - rectStaticText = staticText->GetRect(); - - if ( !rectCtrl.Intersects(rectUpdate) && - (!staticText || !rectStaticText.Intersects(rectUpdate)) ) - continue; - - // iterate over all buttons to find all separators intersecting - // this control - TBBUTTON tbb; - int count = ::SendMessage(GetHwnd(), TB_BUTTONCOUNT, 0, 0); - for ( int n = 0; n < count; n++ ) + const size_t numSeps = tool->GetSeparatorsCount(); + for ( size_t n = 0; n < numSeps; n++, toolIndex++ ) { - // is it a separator? - if ( !::SendMessage(GetHwnd(), TB_GETBUTTON, - n, (LPARAM)&tbb) ) + const RECT rcItem = wxGetTBItemRect(GetHwnd(), toolIndex); + + const wxRegion rgnItem(wxRectFromRECT(rcItem)); + if ( !ValidateRgn(GetHwnd(), GetHrgnOf(rgnItem)) ) { - wxLogDebug(wxT("TB_GETBUTTON failed?")); - - continue; + wxLogLastError(wxT("ValidateRgn()")); } - - if ( tbb.fsStyle != TBSTYLE_SEP ) - continue; - - // get the bounding rect of the separator - RECT r = wxGetTBItemRect(GetHwnd(), n); - if ( !r.right ) - continue; - - const wxRect rectItem = wxRectFromRECT(r); - - // does it intersect the update region at all? - if ( !rectUpdate.Intersects(rectItem) ) - continue; - - // does it intersect the control itself or its label? - // - // if it does, refresh it so it's redrawn on top of the - // background - if ( rectCtrl.Intersects(rectItem) ) - control->Refresh(false); - else if ( staticText && rectStaticText.Intersects(rectItem) ) - staticText->Refresh(false); - else - continue; - - MSWEraseRect(dc, rectItem); } } - else if ( tool->IsStretchableSpace() ) + else { - const wxRect - rectItem = wxRectFromRECT(wxGetTBItemRect(GetHwnd(), toolIndex)); - - if ( rectUpdate.Intersects(rectItem) ) - MSWEraseRect(dc, rectItem); + // normal tools never correspond to more than one native button + toolIndex++; } } - return true; + // still let the native control draw everything else normally + return false; } #endif // __WXWINCE__