1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 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_
|