Extract wxMenuRadioItemsData to a separate file
wxMenuRadioItemsData implementation is not MSW-specific and can be reused on other platforms. See #14213.
This commit is contained in:
216
include/wx/private/menuradio.h
Normal file
216
include/wx/private/menuradio.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/private/menuradio.h
|
||||
// Purpose: wxMenuRadioItemsData implementation
|
||||
// Author: Vadim Zeitlin
|
||||
// Modified: Artur Wieczorek: added UpdateOnInsertNonRadio()
|
||||
// Created: 2017-08-12
|
||||
// Copyright: (c) 2011 Vadim Zeitlin et al
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WX_PRIVATE_MENURADIO_H_
|
||||
#define WX_PRIVATE_MENURADIO_H_
|
||||
|
||||
#include "wx/vector.h"
|
||||
|
||||
// Contains the data about the radio items groups in the given menu.
|
||||
class wxMenuRadioItemsData
|
||||
{
|
||||
public:
|
||||
wxMenuRadioItemsData() { }
|
||||
|
||||
// Default copy ctor, assignment operator and dtor are all ok.
|
||||
|
||||
// Find the start and end of the group containing the given position or
|
||||
// return false if it's not inside any range.
|
||||
bool GetGroupRange(int pos, int *start, int *end) const
|
||||
{
|
||||
// We use a simple linear search here because there are not that many
|
||||
// items in a menu and hence even fewer radio items ranges anyhow, so
|
||||
// normally there is no need to do anything fancy (like keeping the
|
||||
// array sorted and using binary search).
|
||||
for ( Ranges::const_iterator it = m_ranges.begin();
|
||||
it != m_ranges.end();
|
||||
++it )
|
||||
{
|
||||
const Range& r = *it;
|
||||
|
||||
if ( r.start <= pos && pos <= r.end )
|
||||
{
|
||||
if ( start )
|
||||
*start = r.start;
|
||||
if ( end )
|
||||
*end = r.end;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Take into account the new 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 is extended to include
|
||||
// the item.
|
||||
// Returns true if this item starts a new radio group, false if it extends
|
||||
// an existing one.
|
||||
bool UpdateOnInsertRadio(int pos)
|
||||
{
|
||||
bool inExistingGroup = false;
|
||||
|
||||
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, update its indices.
|
||||
r.start++;
|
||||
r.end++;
|
||||
}
|
||||
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
|
||||
// after it in which case it extends this range so make it span
|
||||
// one more item in any case.
|
||||
r.end++;
|
||||
|
||||
inExistingGroup = true;
|
||||
}
|
||||
//else: Item is inserted after this range, nothing to do for it.
|
||||
}
|
||||
|
||||
if ( inExistingGroup )
|
||||
return false;
|
||||
|
||||
// Make a new range for the group this item will belong to.
|
||||
Range r;
|
||||
r.start = pos;
|
||||
r.end = pos;
|
||||
m_ranges.push_back(r);
|
||||
|
||||
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
|
||||
// item at the given position.
|
||||
//
|
||||
// The item being removed can be the item of any kind, not only the radio
|
||||
// button belonging to the radio group, and this function checks for it
|
||||
// and, as a side effect, returns true if this item was found inside an
|
||||
// existing radio group.
|
||||
bool UpdateOnRemoveItem(int pos)
|
||||
{
|
||||
bool inExistingGroup = false;
|
||||
|
||||
// Pointer to (necessarily unique) empty group which could be left
|
||||
// after removing the last radio button from it.
|
||||
Ranges::iterator itEmptyGroup = m_ranges.end();
|
||||
|
||||
for ( Ranges::iterator it = m_ranges.begin();
|
||||
it != m_ranges.end();
|
||||
++it )
|
||||
{
|
||||
Range& r = *it;
|
||||
|
||||
if ( pos < r.start )
|
||||
{
|
||||
// Removed item was positioned before this range, update its
|
||||
// indices.
|
||||
r.start--;
|
||||
r.end--;
|
||||
}
|
||||
else if ( pos <= r.end )
|
||||
{
|
||||
// Removed item belongs to this radio group (it is a radio
|
||||
// button), update index of its end.
|
||||
r.end--;
|
||||
|
||||
// Check if empty group left after removal.
|
||||
// If so, it will be deleted later on.
|
||||
if ( r.end < r.start )
|
||||
itEmptyGroup = it;
|
||||
|
||||
inExistingGroup = true;
|
||||
}
|
||||
//else: Removed item was after this range, nothing to do for it.
|
||||
}
|
||||
|
||||
// Remove empty group from the list.
|
||||
if ( itEmptyGroup != m_ranges.end() )
|
||||
m_ranges.erase(itEmptyGroup);
|
||||
|
||||
return inExistingGroup;
|
||||
}
|
||||
|
||||
private:
|
||||
// Contains the inclusive positions of the range start and end.
|
||||
struct Range
|
||||
{
|
||||
int start;
|
||||
int end;
|
||||
};
|
||||
|
||||
typedef wxVector<Range> Ranges;
|
||||
Ranges m_ranges;
|
||||
};
|
||||
|
||||
#endif // WX_PRIVATE_MENURADIO_H_
|
Reference in New Issue
Block a user