File: menuradio.h

package info (click to toggle)
wxpython4.0 4.2.3%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 221,752 kB
  • sloc: cpp: 962,555; python: 230,573; ansic: 170,731; makefile: 51,756; sh: 9,342; perl: 1,564; javascript: 584; php: 326; xml: 200
file content (216 lines) | stat: -rw-r--r-- 7,140 bytes parent folder | download | duplicates (4)
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_