]> git.saurik.com Git - wxWidgets.git/blob - src/generic/selstore.cpp
Fix horizontal mouse wheel scrolling in wxGTK.
[wxWidgets.git] / src / generic / selstore.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/selstore.cpp
3 // Purpose: wxSelectionStore implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 08.06.03 (extracted from src/generic/listctrl.cpp)
7 // Copyright: (c) 2000-2003 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #include "wx/selstore.h"
26
27 // ============================================================================
28 // wxSelectionStore
29 // ============================================================================
30
31 // ----------------------------------------------------------------------------
32 // tests
33 // ----------------------------------------------------------------------------
34
35 bool wxSelectionStore::IsSelected(unsigned item) const
36 {
37 bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND;
38
39 // if the default state is to be selected, being in m_itemsSel means that
40 // the item is not selected, so we have to inverse the logic
41 return m_defaultState ? !isSel : isSel;
42 }
43
44 // ----------------------------------------------------------------------------
45 // Select*()
46 // ----------------------------------------------------------------------------
47
48 bool wxSelectionStore::SelectItem(unsigned item, bool select)
49 {
50 // search for the item ourselves as like this we get the index where to
51 // insert it later if needed, so we do only one search in the array instead
52 // of two (adding item to a sorted array requires a search)
53 size_t index = m_itemsSel.IndexForInsert(item);
54 bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item;
55
56 if ( select != m_defaultState )
57 {
58 if ( !isSel )
59 {
60 m_itemsSel.AddAt(item, index);
61
62 return true;
63 }
64 }
65 else // reset to default state
66 {
67 if ( isSel )
68 {
69 m_itemsSel.RemoveAt(index);
70 return true;
71 }
72 }
73
74 return false;
75 }
76
77 bool wxSelectionStore::SelectRange(unsigned itemFrom, unsigned itemTo,
78 bool select,
79 wxArrayInt *itemsChanged)
80 {
81 // 100 is hardcoded but it shouldn't matter much: the important thing is
82 // that we don't refresh everything when really few (e.g. 1 or 2) items
83 // change state
84 static const unsigned MANY_ITEMS = 100;
85
86 wxASSERT_MSG( itemFrom <= itemTo, wxT("should be in order") );
87
88 // are we going to have more [un]selected items than the other ones?
89 if ( itemTo - itemFrom > m_count/2 )
90 {
91 if ( select != m_defaultState )
92 {
93 // the default state now becomes the same as 'select'
94 m_defaultState = select;
95
96 // so all the old selections (which had state select) shouldn't be
97 // selected any more, but all the other ones should
98 wxSelectedIndices selOld = m_itemsSel;
99 m_itemsSel.Empty();
100
101 // TODO: it should be possible to optimize the searches a bit
102 // knowing the possible range
103
104 unsigned item;
105 for ( item = 0; item < itemFrom; item++ )
106 {
107 if ( selOld.Index(item) == wxNOT_FOUND )
108 m_itemsSel.Add(item);
109 }
110
111 for ( item = itemTo + 1; item < m_count; item++ )
112 {
113 if ( selOld.Index(item) == wxNOT_FOUND )
114 m_itemsSel.Add(item);
115 }
116
117 // many items (> half) changed state
118 itemsChanged = NULL;
119 }
120 else // select == m_defaultState
121 {
122 // get the inclusive range of items between itemFrom and itemTo
123 size_t count = m_itemsSel.GetCount(),
124 start = m_itemsSel.IndexForInsert(itemFrom),
125 end = m_itemsSel.IndexForInsert(itemTo);
126
127 if ( start == count || m_itemsSel[start] < itemFrom )
128 {
129 start++;
130 }
131
132 if ( end == count || m_itemsSel[end] > itemTo )
133 {
134 end--;
135 }
136
137 if ( start <= end )
138 {
139 // delete all of them (from end to avoid changing indices)
140 for ( int i = end; i >= (int)start; i-- )
141 {
142 if ( itemsChanged )
143 {
144 if ( itemsChanged->GetCount() > MANY_ITEMS )
145 {
146 // stop counting (see comment below)
147 itemsChanged = NULL;
148 }
149 else
150 {
151 itemsChanged->Add(m_itemsSel[i]);
152 }
153 }
154
155 m_itemsSel.RemoveAt(i);
156 }
157 }
158 }
159 }
160 else // "few" items change state
161 {
162 if ( itemsChanged )
163 {
164 itemsChanged->Empty();
165 }
166
167 // just add the items to the selection
168 for ( unsigned item = itemFrom; item <= itemTo; item++ )
169 {
170 if ( SelectItem(item, select) && itemsChanged )
171 {
172 itemsChanged->Add(item);
173
174 if ( itemsChanged->GetCount() > MANY_ITEMS )
175 {
176 // stop counting them, we'll just eat gobs of memory
177 // for nothing at all - faster to refresh everything in
178 // this case
179 itemsChanged = NULL;
180 }
181 }
182 }
183 }
184
185 // we set it to NULL if there are many items changing state
186 return itemsChanged != NULL;
187 }
188
189 // ----------------------------------------------------------------------------
190 // callbacks
191 // ----------------------------------------------------------------------------
192
193 void wxSelectionStore::OnItemDelete(unsigned item)
194 {
195 size_t count = m_itemsSel.GetCount(),
196 i = m_itemsSel.IndexForInsert(item);
197
198 if ( i < count && m_itemsSel[i] == item )
199 {
200 // this item itself was in m_itemsSel, remove it from there
201 m_itemsSel.RemoveAt(i);
202
203 count--;
204 }
205
206 // and adjust the index of all which follow it
207 while ( i < count )
208 {
209 // all following elements must be greater than the one we deleted
210 wxASSERT_MSG( m_itemsSel[i] > item, wxT("logic error") );
211
212 m_itemsSel[i++]--;
213 }
214 }
215
216 void wxSelectionStore::SetItemCount(unsigned count)
217 {
218 // forget about all items whose indices are now invalid if the size
219 // decreased
220 if ( count < m_count )
221 {
222 for ( size_t i = m_itemsSel.GetCount(); i > 0; i-- )
223 {
224 if ( m_itemsSel[i - 1] >= count )
225 m_itemsSel.RemoveAt(i - 1);
226 }
227 }
228
229 // remember the new number of items
230 m_count = count;
231 }