Fix updating radio groups when non-radio item is inserted to wxMenu (MSW)
When wxMenu contains radio groups and a new item (radio and non-radio) is being added to the menu, data describing exisiting groups have to be updated accordingly. Because adding radio and non-radio items has a different impact on the groups, adding non-radio items has to be handled separately. (The main difference between adding radio and non-radio item is that when a radio item is inserted inside the group this group is extended, but for non-radio item the group is split into two subgroups.)
This commit is contained in:
@@ -199,6 +199,7 @@ wxMSW:
|
|||||||
- Fix handling wxClipboard data when wxUSE_OLE == 0.
|
- Fix handling wxClipboard data when wxUSE_OLE == 0.
|
||||||
- Fix caching of wxFONTSTYLE_SLANT fonts in wxTheFontList.
|
- Fix caching of wxFONTSTYLE_SLANT fonts in wxTheFontList.
|
||||||
- Fix wxTextCtrl::XYToPosition() and PositionToXY().
|
- Fix wxTextCtrl::XYToPosition() and PositionToXY().
|
||||||
|
- Fix updating radio groups when non-radio item is inserted to wxMenu.
|
||||||
|
|
||||||
wxOSX:
|
wxOSX:
|
||||||
|
|
||||||
|
@@ -102,11 +102,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Take into account the new radio item about to be added at the given
|
// Take into account the new radio item about to be added at the given
|
||||||
// position.
|
// position. The are two cases to handle:
|
||||||
//
|
// - If item precedes the range, the range indices have to be updated.
|
||||||
|
// - If item falls inside the range, this range is extended to include
|
||||||
|
// the item.
|
||||||
// Returns true if this item starts a new radio group, false if it extends
|
// Returns true if this item starts a new radio group, false if it extends
|
||||||
// an existing one.
|
// an existing one.
|
||||||
bool UpdateOnInsert(int pos)
|
bool UpdateOnInsertRadio(int pos)
|
||||||
{
|
{
|
||||||
bool inExistingGroup = false;
|
bool inExistingGroup = false;
|
||||||
|
|
||||||
@@ -124,6 +126,8 @@ public:
|
|||||||
}
|
}
|
||||||
else if ( pos <= r.end + 1 )
|
else if ( pos <= r.end + 1 )
|
||||||
{
|
{
|
||||||
|
wxASSERT_MSG( !inExistingGroup,
|
||||||
|
wxS("Item already inserted inside another range") );
|
||||||
// Item is inserted in the middle of this range or immediately
|
// Item is inserted in the middle of this range or immediately
|
||||||
// after it in which case it extends this range so make it span
|
// after it in which case it extends this range so make it span
|
||||||
// one more item in any case.
|
// one more item in any case.
|
||||||
@@ -146,6 +150,58 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take into account the new non-radio item about to be added at the given
|
||||||
|
// position. The are two cases to handle:
|
||||||
|
// - If item precedes the range, the range indices have to be updated.
|
||||||
|
// - If item falls inside the range, this range has to be split into
|
||||||
|
// two new ranges.
|
||||||
|
// Returns true if existing group has been split into two subgroups.
|
||||||
|
bool UpdateOnInsertNonRadio(int pos)
|
||||||
|
{
|
||||||
|
bool wasSplit = false;
|
||||||
|
Range newRange;
|
||||||
|
|
||||||
|
for ( Ranges::iterator it = m_ranges.begin();
|
||||||
|
it != m_ranges.end();
|
||||||
|
++it )
|
||||||
|
{
|
||||||
|
Range& r = *it;
|
||||||
|
|
||||||
|
if ( pos <= r.start )
|
||||||
|
{
|
||||||
|
// Item is inserted before this range or just at its start,
|
||||||
|
// update its indices.
|
||||||
|
r.start++;
|
||||||
|
r.end++;
|
||||||
|
}
|
||||||
|
else if ( pos <= r.end )
|
||||||
|
{
|
||||||
|
wxASSERT_MSG( !wasSplit,
|
||||||
|
wxS("Item already inserted inside another range") );
|
||||||
|
// Item is inserted inside this range in which case
|
||||||
|
// it breaks the range into two parts: one ending before
|
||||||
|
// the item and one started after it.
|
||||||
|
|
||||||
|
// The new range after the item has to be stored and added to the list
|
||||||
|
// after finishing the iteration through the ranges.
|
||||||
|
newRange.start = pos + 1; // start after the item
|
||||||
|
newRange.end = r.end + 1; // inherits current end "moved up" by one item
|
||||||
|
wasSplit = true;
|
||||||
|
// Current range ends just before the item position.
|
||||||
|
r.end = pos - 1;
|
||||||
|
}
|
||||||
|
//else: Item is inserted after this range, nothing to do for it.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !wasSplit )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Add a split range to the list.
|
||||||
|
m_ranges.push_back(newRange);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the ranges of the existing radio groups after removing the menu
|
// Update the ranges of the existing radio groups after removing the menu
|
||||||
// item at the given position.
|
// item at the given position.
|
||||||
//
|
//
|
||||||
@@ -498,20 +554,27 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
|
|||||||
pos = GetMenuItemCount() - 1;
|
pos = GetMenuItemCount() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update radio groups data if we're inserting a new radio item.
|
// Update radio groups data if we're inserting a new menu item.
|
||||||
|
// Inserting radio and non-radio item has a different impact
|
||||||
|
// on radio groups so we have to handle each case separately.
|
||||||
|
// (Inserting a radio item in the middle of exisiting group extends
|
||||||
|
// the group, but inserting non-radio item breaks it into two subgroups.)
|
||||||
//
|
//
|
||||||
// NB: If we supported inserting non-radio items in the middle of existing
|
|
||||||
// radio groups to break them into two subgroups, we'd need to update
|
|
||||||
// m_radioData in this case too but currently this is not supported.
|
|
||||||
bool checkInitially = false;
|
bool checkInitially = false;
|
||||||
if ( pItem->GetKind() == wxITEM_RADIO )
|
if ( pItem->GetKind() == wxITEM_RADIO )
|
||||||
{
|
{
|
||||||
if ( !m_radioData )
|
if ( !m_radioData )
|
||||||
m_radioData = new wxMenuRadioItemsData;
|
m_radioData = new wxMenuRadioItemsData;
|
||||||
|
|
||||||
if ( m_radioData->UpdateOnInsert(pos) )
|
if ( m_radioData->UpdateOnInsertRadio(pos) )
|
||||||
checkInitially = true;
|
checkInitially = true;
|
||||||
}
|
}
|
||||||
|
else if ( m_radioData )
|
||||||
|
{
|
||||||
|
bool groupWasSplit = m_radioData->UpdateOnInsertNonRadio(pos);
|
||||||
|
wxASSERT_MSG( !groupWasSplit,
|
||||||
|
wxS("Inserting non-radio item inside a radio group?") );
|
||||||
|
}
|
||||||
|
|
||||||
// Also handle the case of check menu items that had been checked before
|
// Also handle the case of check menu items that had been checked before
|
||||||
// being attached to the menu: we don't need to actually call Check() on
|
// being attached to the menu: we don't need to actually call Check() on
|
||||||
|
Reference in New Issue
Block a user