Fix toolbar repainting after deleting a tool in wxMSW.

The toolbar was in an inconsistent state when recalculating the sizes of the
separators used as placeholders for the controls and stretch spacers as the
tool was already deleted from the native toolbar but still present in wx
internal toolbar data and this resulted in discrepancies between the indices
in the native and wx toolbars.

Fix this by specially marking the already deleted but not yet removed tool and
ignoring it during the recalculations.

This makes the old, and only partially successful, attempt to work around this
bug in DoDeleteTool() unnecessary and so the code is actually simplified by
this change.

Closes #16095.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76189 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2014-03-23 00:57:18 +00:00
parent b5f4eaf6bc
commit c3b5dc5e8f

View File

@@ -150,6 +150,7 @@ public:
{ {
m_nSepCount = 0; m_nSepCount = 0;
m_staticText = NULL; m_staticText = NULL;
m_toBeDeleted = false;
} }
wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label) wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
@@ -174,6 +175,7 @@ public:
} }
m_nSepCount = 1; m_nSepCount = 1;
m_toBeDeleted = false;
} }
virtual ~wxToolBarTool() virtual ~wxToolBarTool()
@@ -233,9 +235,13 @@ public:
} }
} }
void ToBeDeleted() { m_toBeDeleted = true; }
bool IsToBeDeleted() const { return m_toBeDeleted; }
private: private:
size_t m_nSepCount; size_t m_nSepCount;
wxStaticText *m_staticText; wxStaticText *m_staticText;
bool m_toBeDeleted;
wxDECLARE_NO_COPY_CLASS(wxToolBarTool); wxDECLARE_NO_COPY_CLASS(wxToolBarTool);
}; };
@@ -617,48 +623,11 @@ bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
return false; return false;
} }
} }
static_cast<wxToolBarTool*>(tool)->ToBeDeleted();
// and finally rearrange the tools // and finally rearrange the tools
// by recalculating stretchable spacers, if there are any
// search for any stretch spacers before the removed tool UpdateStretchableSpacersSize();
bool hasPrecedingStrechables = false;
for ( wxToolBarToolsList::compatibility_iterator nodeStch = m_tools.GetFirst();
nodeStch != node; nodeStch = nodeStch->GetNext() )
{
if ( ((wxToolBarTool*)nodeStch->GetData())->IsStretchable() )
{
hasPrecedingStrechables = true;
break;
}
}
if ( hasPrecedingStrechables )
{
// if the removed tool is preceded by stretch spacers
// just redistribute the space
UpdateStretchableSpacersSize();
}
else
{
// reposition all the controls after this button but before any
// stretch spacer (the toolbar takes care of all normal items)
for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
{
wxToolBarTool *tool2 = (wxToolBarTool*)node->GetData();
if ( tool2->IsControl() )
{
tool2->MoveBy(-delta);
}
// if a stretch spacer is found just redistribute the available space
else if ( tool2->IsStretchable() )
{
UpdateStretchableSpacersSize();
break;
}
}
}
InvalidateBestSize(); InvalidateBestSize();
@@ -1318,9 +1287,13 @@ void wxToolBar::UpdateStretchableSpacersSize()
unsigned numSpaces = 0; unsigned numSpaces = 0;
wxToolBarToolsList::compatibility_iterator node; wxToolBarToolsList::compatibility_iterator node;
int toolIndex = 0; int toolIndex = 0;
for ( node = m_tools.GetFirst(); node; node = node->GetNext(), toolIndex++ ) for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
{ {
wxToolBarTool * const tool = (wxToolBarTool*)node->GetData(); wxToolBarTool * const tool = (wxToolBarTool*)node->GetData();
if ( tool->IsToBeDeleted() )
continue;
if ( tool->IsStretchableSpace() ) if ( tool->IsStretchableSpace() )
{ {
// Count only enabled items // Count only enabled items
@@ -1328,6 +1301,8 @@ void wxToolBar::UpdateStretchableSpacersSize()
if ( !::IsRectEmpty(&rcItem) ) if ( !::IsRectEmpty(&rcItem) )
numSpaces++; numSpaces++;
} }
toolIndex++;
} }
if ( !numSpaces ) if ( !numSpaces )
@@ -1351,19 +1326,25 @@ void wxToolBar::UpdateStretchableSpacersSize()
// correct place // correct place
int offset = 0; int offset = 0;
toolIndex = 0; toolIndex = 0;
for ( node = m_tools.GetFirst(); node; node = node->GetNext(), toolIndex++ ) for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
{ {
wxToolBarTool * const tool = (wxToolBarTool*)node->GetData(); wxToolBarTool * const tool = (wxToolBarTool*)node->GetData();
if ( tool->IsToBeDeleted() )
continue;
if ( tool->IsControl() && offset ) if ( tool->IsControl() && offset )
{ {
tool->MoveBy(offset); tool->MoveBy(offset);
toolIndex++;
continue; continue;
} }
if ( !tool->IsStretchableSpace() ) if ( !tool->IsStretchableSpace() )
{
toolIndex++;
continue; continue;
}
const RECT rcOld = wxGetTBItemRect(GetHwnd(), toolIndex); const RECT rcOld = wxGetTBItemRect(GetHwnd(), toolIndex);
@@ -1398,6 +1379,8 @@ void wxToolBar::UpdateStretchableSpacersSize()
} }
} }
} }
toolIndex++;
} }
} }
@@ -1837,12 +1820,20 @@ bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
int rowPosX = INT_MIN; int rowPosX = INT_MIN;
wxToolBarToolsList::compatibility_iterator node; wxToolBarToolsList::compatibility_iterator node;
int i = 0; int i = 0;
for ( node = m_tools.GetFirst(); node; node = node->GetNext(), i++) for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
{ {
wxToolBarTool * const
tool = static_cast<wxToolBarTool *>(node->GetData());
if ( tool->IsToBeDeleted() )
continue;
// Skip hidden buttons // Skip hidden buttons
const RECT rcItem = wxGetTBItemRect(GetHwnd(), i); const RECT rcItem = wxGetTBItemRect(GetHwnd(), i);
if ( ::IsRectEmpty(&rcItem) ) if ( ::IsRectEmpty(&rcItem) )
{
i++;
continue; continue;
}
if ( rcItem.top > rowPosX ) if ( rcItem.top > rowPosX )
{ {
@@ -1859,8 +1850,6 @@ bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
::SetRectEmpty(&rcRow); ::SetRectEmpty(&rcRow);
} }
wxToolBarTool * const tool = (wxToolBarTool*)node->GetData();
// Separators shouldn't be taken into account as they are sometimes // Separators shouldn't be taken into account as they are sometimes
// reported to have the width of the entire client area by the toolbar. // reported to have the width of the entire client area by the toolbar.
// And we know that they are not the biggest items in the toolbar in // And we know that they are not the biggest items in the toolbar in
@@ -1870,6 +1859,8 @@ bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
// Update bounding box of current row // Update bounding box of current row
::UnionRect(&rcRow, &rcRow, &rcItem); ::UnionRect(&rcRow, &rcRow, &rcItem);
} }
i++;
} }
// Take into account the last row rectangle too. // Take into account the last row rectangle too.
@@ -1934,6 +1925,9 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
wxToolBarTool * const wxToolBarTool * const
tool = static_cast<wxToolBarTool *>(node->GetData()); tool = static_cast<wxToolBarTool *>(node->GetData());
if ( tool->IsToBeDeleted() )
continue;
if ( tool->IsControl() || tool->IsStretchableSpace() ) if ( tool->IsControl() || tool->IsStretchableSpace() )
{ {
const size_t numSeps = tool->GetSeparatorsCount(); const size_t numSeps = tool->GetSeparatorsCount();