NCBI C++ ToolKit
selection_control.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: selection_control.cpp 23985 2011-06-30 17:59:06Z kuznets $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrey Yazhuk
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
31 
32 #include <corelib/ncbistd.hpp>
33 
35 
36 #include <wx/event.h>
37 
38 
40 
41 
42 //////////////////////////////////////////////////////////////////////////////
43 // CSelectionControl
44 
45 
47 : m_Style(0),
48  m_SelectedCount(0),
49  m_SingleSelected(-1),
50  m_FocusedIndex(-1),
51  m_AnchorIndex(-1)
52 {
53 }
54 
55 
56 ///////////////////////////////////////////////////////////////////////////////
57 /// Low-level worker functions - implementation dependend
59 {
60  return m_Style;
61 }
62 
63 
65 {
66  m_Style = style;
67 }
68 
69 
71 {
72  bool valid = x_AssertIndexValid(index);
73 
74  int state = 0;
75  if(valid) {
76  if(IsItemSelected(index)) {
78  }
79  if(IsItemFocused(index)) {
81  }
82  }
83  return state;
84 }
85 
86 
88 {
89  bool valid = x_AssertIndexValid(index);
90 
91  if(valid) {
92  bool select = (state & fItemSelected) != 0;
93  bool selected = IsItemSelected(index);
94  if(selected != select) {
95  SelectItem(index, select);
96  }
97 
98  bool focus = (state & fItemFocused) != 0;
99  bool focused = IsItemFocused(index);
100  if(focus != focused) {
101  FocusItem(focus ? index : -1);
102  }
103  }
104 }
105 
106 
108 {
109  x_AssertIndexValid(index);
110 
111  return m_FocusedIndex == index;
112 }
113 
114 
116 {
117  return m_FocusedIndex;
118 }
119 
120 
122 {
123  bool valid = x_AssertIndexValid(index);
124  return valid ? m_Entries[index].second : false;
125 }
126 
127 
129 {
130  bool single = (GetStyle() & fSingleSelection) != 0;
131  _ASSERT(single && m_SelectedCount <= 1);
132 
133  if(single && m_SelectedCount == 1) {
135  for( TIndex i = 0; i < count; i++ ) {
136  if(m_Entries[i].second) {
137  return i;
138  }
139  }
140  }
141  return -1;
142 }
143 
144 
146 {
147  return m_SelectedCount;
148 }
149 
150 
152 {
154  indexes.reserve(m_SelectedCount);
155 
156  for( TIndex i = 0; i < count; i++ ) {
157  if(m_Entries[i].second) {
158  indexes.push_back(i);
159  }
160  }
161  _ASSERT((int)indexes.size() == m_SelectedCount);
162  x_DebugValid();
163 }
164 
165 
167 {
168  bool valid = (index >= -1 && index < x_GetItemsCount());
169  _ASSERT(valid);
170 
171  if (valid && index != m_FocusedIndex) {
172  TIndexVector update_items;
173  update_items.push_back(m_FocusedIndex); // update old focus
174 
175  m_FocusedIndex = index;
176  if(m_FocusedIndex > -1) {
177  update_items.push_back(m_FocusedIndex); // update new one
178  }
179 
180  x_UpdateItems(update_items); // repaint affected items
181  }
182  x_DebugValid();
183 }
184 
185 
186 void CSelectionControl::SelectItem(TIndex index, bool select)
187 {
188  bool valid = x_AssertIndexValid(index);
189  if(valid) {
190  x_SelectItem(index, select);
191  x_UpdateItemsRange(index, index);
192  }
193 }
194 
195 
196 void CSelectionControl::SelectItems(TIndexVector& indexes, bool select)
197 {
198  x_SelectItems(indexes, select);
199 }
200 
201 
203 {
204  x_SelectAll(select);
205 }
206 
207 
209 {
211  for( TIndex i = 0; i < count; i++ ) {
212  m_Entries[i].second = select;
213  }
214  m_SelectedCount = select ? count : 0;
215 
216  if(count) {
217  x_UpdateItemsRange(0, count - 1);
218  }
219  x_DebugValid();
220 }
221 
222 
224 {
225  return (TIndex)m_Entries.size();
226 }
227 
228 
230  const TIndexVector& indices,
231  bool update)
232 {
233  size_t n_items = items.size();
234  _ASSERT(n_items == indices.size());
235 
236  TIndex i_min = x_GetItemsCount();
237  for( size_t i = 0; i < n_items; i++ ) {
238  TIndex ind = indices[i];
239  ind = min(ind, x_GetItemsCount());
240 
241  m_Entries.insert(m_Entries.begin() + ind, make_pair(items[i], false));
242 
243  i_min = min(i_min, ind);
244  }
246 
247  if(update) {
248  TIndex i_max = max(0, x_GetItemsCount() - 1);
249  x_UpdateItemsRange(i_min, i_max);
250  }
251 }
252 
253 
254 
255 bool CSelectionControl::x_InsertItem(TIndex index, const TItemHandle& item, bool update)
256 {
257  if(index >= 0 && index <= x_GetItemsCount()) {
258  m_Entries.insert(m_Entries.begin() + index, make_pair(item, false));
260 
261  if(update) {
262  TIndex i_max = max(0, x_GetItemsCount() - 1);
263  x_UpdateItemsRange(index, i_max);
264  }
265  return true;
266  }
267  return false;
268 }
269 
270 
271 bool CSelectionControl::x_DeleteItem(TIndex index, bool update)
272 {
273  bool valid = x_AssertIndexValid(index);
274 
275  if(valid) {
276  TIndex count = x_GetItemsCount(); // take it before deleting
277 
278  if(m_FocusedIndex == index)
279  m_FocusedIndex = -1;
280  if(m_AnchorIndex == index)
282 
283  if(IsItemSelected(index))
284  m_SelectedCount--;
285 
286  TItemHandle handle = m_Entries[index].first;
287  m_ItemToIndex.erase(handle);
288  m_Entries.erase(m_Entries.begin() + index);
289 
290  if (update) {
291  TIndex i_max = max(0, count - 1);
292  x_UpdateItemsRange(index, i_max);
293  }
294  return true;
295  }
296  x_DebugValid();
297  return false;
298 }
299 
300 
302 {
303  x_Clear();
304  x_UpdateItemsRange(0, -1);
305 }
306 
307 
309 {
310  m_Entries.clear();
312 
314  m_SelectedCount = 0;
315 }
316 
317 
318 ///////////////////////////////////////////////////////////////////////////////
319 /// Protected API -
320 
321 /// TODO move up
322 // inline
324 {
325  bool valid = (index >= 0 && index < (TIndex) m_Entries.size());
326  _ASSERT(valid);
327  return valid;
328 }
329 
330 
331 void CSelectionControl::x_SelectItem(TIndex index, bool select)
332 {
333  bool valid = x_AssertIndexValid(index);
334  if(valid) {
335  bool selected = m_Entries[index].second;
336  if(selected != select) {
337  m_Entries[index].second = select;
338  m_SelectedCount += (select ? 1 : -1);
339 
340  x_SendSelectionEvent(index);
341  }
342  }
343 }
344 
345 
346 /// handles selection of a single item from UI
348 {
349  TIndexVector prev_sel;
350  GetSelectedIndexes(prev_sel);
351 
352  if(m_FocusedIndex != index) {
354  prev_sel.push_back(m_FocusedIndex); // if it is not selected - we need update it separately
355  m_FocusedIndex = index;
356  }
357  // reset previous selection
358  for(size_t i = 0; i < prev_sel.size(); i++ ) {
359  TIndex index = prev_sel[i];
360  x_SelectItem(index, false);
361  }
362  if(index > -1) {
363  x_SelectItem(index, true);
364  prev_sel.push_back(index);
365  m_AnchorIndex = index;
366  m_SelectedCount = 1;
367  } else m_SelectedCount = 0;
368 
369  x_UpdateItems(prev_sel);
370 
371  x_DebugValid();
372 }
373 
374 
376 {
377  bool valid = x_AssertIndexValid(index);
378  if(valid) {
379  TIndexVector indexes;
380  if(index > -1) {
381  if(m_FocusedIndex != index) {
382  indexes.push_back(m_FocusedIndex);
383  m_FocusedIndex = index;
384  }
385  bool old_sel = IsItemSelected(index);
386 
387  x_SelectItem(index, ! old_sel);
388  indexes.push_back(index);
389  m_AnchorIndex = index;
390  } else m_SelectedCount = 0;
391 
392  x_UpdateItems(indexes);
393  }
394 
395  x_DebugValid();
396 }
397 
398 /// Select items with given indices. If "invert_others" == "true" - deselects
399 /// all other items.
401  bool reset_others)
402 {
403  if(reset_others) {
404  TIndex n_items = x_GetItemsCount();
405  vector<bool> v_sel(n_items, false);
406 
407  for( size_t i = 0; i < indexes.size(); i++ ) {
408  v_sel[indexes[i]] = true;
409  }
410  for( TIndex j = 0; j < n_items; j++ ) {
411  x_SelectItem(j, v_sel[j]);
412  }
413 
414  m_SelectedCount = (TIndex)indexes.size();
415 
416  x_UpdateItemsRange(0, n_items - 1);
417  } else {
418  TIndexVector update_indexes;
419 
420  ITERATE(TIndexVector, it, indexes) {
421  if ( ! IsItemSelected(*it)) {
422  x_SelectItem(*it, true);
423  update_indexes.push_back(*it);
424  }
425  }
426  m_SelectedCount += (TIndex)update_indexes.size();
427 
428  x_UpdateItems(update_indexes);
429  }
430 
431  x_DebugValid();
432 }
433 
434 
435 // selects a rabge of itmes from m_AnchorIndex to index
437 {
438  if(m_AnchorIndex<0)
439  m_AnchorIndex = 0;
440 
441  TIndex iStart = min(m_AnchorIndex, index);
442  TIndex iEnd = max(m_AnchorIndex, index);
443 
444  // reset old selection and select from iStart to iEnd
445  TIndexVector update_indexes;
446  bool bPrevFocusedChanged = false;
447 
449 
450  for( TIndex i = 0; i < count; i++ ) {
451  bool b_select = (i >= iStart && i <= iEnd);
452  if (IsItemSelected(i) != b_select) {
453  x_SelectItem(i, b_select);
454  update_indexes.push_back(i);
455  if(i == m_FocusedIndex)
456  bPrevFocusedChanged = true;
457  }
458  }
459  if(m_FocusedIndex != index) {
460  if( ! bPrevFocusedChanged)
461  update_indexes.push_back(m_FocusedIndex); // need to update
462  m_FocusedIndex = index;
463  }
464 
465  x_UpdateItems(update_indexes);
466 
467  x_DebugValid();
468 }
469 
470 ///////////////////////////////////////////////////////////////////////////////
471 /// Event handling
472 
473 void CSelectionControl::OnMouseDown(wxMouseEvent& event)
474 {
475  int index = x_GetIndexByWindowPos(event.GetX(), event.GetY(), true);
477 
478  if(index == -1) {
479  x_SelectAll(false);
480  } else {
481  switch(state) {
483  x_SelectSingleItem(index);
484  break;
486  if(m_Style == fSingleSelection) {
487  x_SelectSingleItem(index);
488  } else {
489  x_SelectTo(index);
490  }
491  break;
493  x_InvertSingleItem(index);
494  break;
495  default:
496  break;
497  }
498  }
499 }
500 
501 
502 void CSelectionControl::OnKeyDown(wxKeyEvent& event)
503 {
505  bool ctrl = (state == CGUIEvent::eSelectIncState);
506 
507  int key = event.GetKeyCode();
508  switch(key) {
509  case WXK_HOME:
510  x_SelectTo(0, state);
511  break;
512  case WXK_END:
514  break;
515  case WXK_DOWN:
517  break;
518  case WXK_UP:
520  break;
521  case ' ':
522  x_SelectFocusedItem(ctrl);
523  break;
524  case 'a':
525  case 'A':
526  if(ctrl) {
527  x_SelectAll(true);
528  }
529  break;
530  default:
531  event.Skip();
532  break;
533  }
534 }
535 
536 
538 {
539  int count = x_GetItemsCount();
540  if(count > 0) {
541  int i_focused = GetFocusedIndex();
542  i_focused = max(i_focused, 0);
543 
544  i_focused += shift;
545 
546  i_focused = max(i_focused, 0);
547  i_focused = min(i_focused, count - 1);
548 
549  x_SelectTo(i_focused, state);
550  }
551 }
552 
553 
555 {
556  switch(state) {
558  x_SelectSingleItem(index);
559  break;
561  FocusItem(index);
562  break;
564  if(m_Style == fSingleSelection) {
565  x_SelectSingleItem(index);
566  } else {
567  x_SelectTo(index);
568  }
569  break;
570  default: break;
571  }
572 
573  x_MakeVisible(index);
574  x_DebugValid();
575 }
576 
577 
579 {
580  int i_focused = GetFocusedIndex();
581  if(i_focused != -1) {
582  bool bSel = IsItemSelected(i_focused);
583  if( ! bSel || (bSel && deselect_en))
584  x_InvertSingleItem(i_focused);
585  }
586 
587  x_DebugValid();
588 }
589 
590 
592 {
594  for( TIndex i = 0; i < (TIndex) m_Entries.size(); i++ ) {
595  TItemHandle handle = m_Entries[i].first;
596  m_ItemToIndex[handle] = i;
597  }
598 }
599 
601 {
602  _ASSERT(m_Entries.size() == m_ItemToIndex.size());
603 
604  int selected = 0;
605  for( size_t i = 0; i< m_Entries.size(); i++ ) {
606  if(m_Entries[i].second) {
607  selected++;
608  }
609  }
610  _ASSERT(m_SelectedCount == selected);
611 
612 }
613 
614 
static EGUIState wxGetSelectState(const wxMouseEvent &event)
Definition: gui_event.cpp:42
@ eSelectExtState
Definition: gui_event.hpp:110
@ eSelectIncState
Definition: gui_event.hpp:109
virtual TIndex GetFocusedIndex() const
virtual void SelectAll(bool select=true)
void x_InsertItems(const TItemHandleVector &items, const TIndexVector &indices, bool update)
virtual int GetStyle() const
Low-level worker functions - implementation dependend.
virtual void GetSelectedIndexes(TIndexVector &indexes) const
virtual TIndex GetSelectedIndex() const
virtual void x_InvertSingleItem(TIndex index)
virtual void x_UpdateItems(TIndexVector &indexes)=0
virtual void x_SelectAll(bool select=true)
bool x_InsertItem(TIndex index, const TItemHandle &item, bool update)
virtual void SelectItem(TIndex index, bool select=true)
virtual void x_SelectTo(TIndex index)
virtual void SetStyle(int style)
virtual int GetItemState(TIndex index) const
Items state and selection.
void x_SelectFocusedItem(bool deselect_en)
virtual void SelectItems(TIndexVector &indexes, bool select=true)
virtual void FocusItem(TIndex index)
TIndex x_GetItemsCount() const
virtual void x_SelectItem(TIndex index, bool select)
vector< TItemHandle > TItemHandleVector
void OnMouseDown(wxMouseEvent &event)
Event handling.
bool x_DeleteItem(TIndex index, bool update=true)
virtual void SetItemState(TIndex index, int state)
virtual int x_GetIndexByWindowPos(int win_x, int win_y, bool clip=false)=0
virtual bool IsItemFocused(TIndex index) const
virtual TIndex GetSelectedCount() const
TIndex m_FocusedIndex
index of the selected itme (valid only in fSingleSelection mode)
vector< TIndex > TIndexVector
virtual void x_SelectSingleItem(TIndex index)
handles selection of a single item from UI
virtual void x_MakeVisible(TIndex index)=0
virtual void x_UpdateItemsRange(TIndex start, TIndex end)=0
virtual void x_SendSelectionEvent(TIndex index)=0
TItemToIndexMap m_ItemToIndex
virtual void x_SelectItems(const TIndexVector &vIndexes, bool reset_others=false)
Select items with given indices.
bool x_AssertIndexValid(TIndex index) const
Protected API -.
void OnKeyDown(wxKeyEvent &event)
virtual bool IsItemSelected(TIndex index) const
void x_MoveSelectionBy(int shift, CGUIEvent::EGUIState state)
void erase(iterator pos)
Definition: map.hpp:167
size_type size() const
Definition: map.hpp:148
void clear()
Definition: map.hpp:169
Include a standard set of the NCBI C++ Toolkit most basic headers.
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
int i
const struct ncbi::grid::netcache::search::fields::KEY key
T max(T x_, T y_)
T min(T x_, T y_)
#define count
#define _ASSERT
Modified on Fri Sep 20 14:57:29 2024 by modify_doxy.py rev. 669887