Store row/column selection more appropriately in wxGrid.
[wxWidgets.git] / src / generic / gridsel.cpp
1 ///////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/gridsel.cpp
3 // Purpose: wxGridSelection
4 // Author: Stefan Neis
5 // Modified by:
6 // Created: 20/02/1999
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Neis (Stefan.Neis@t-online.de)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 // ============================================================================
20 // declarations
21 // ============================================================================
22
23 // ----------------------------------------------------------------------------
24 // headers
25 // ----------------------------------------------------------------------------
26
27 #if wxUSE_GRID
28
29 #include "wx/generic/gridsel.h"
30
31
32 // Some explanation for the members of the class:
33 // m_cellSelection stores individual selected cells
34 // -- this is only used if m_selectionMode == wxGridSelectCells
35 // m_blockSelectionTopLeft and m_blockSelectionBottomRight
36 // store the upper left and lower right corner of selected Blocks
37 // m_rowSelection and m_colSelection store individual selected
38 // rows and columns; maybe those are superfluous and should be
39 // treated as blocks?
40
41 wxGridSelection::wxGridSelection( wxGrid * grid,
42 wxGrid::wxGridSelectionModes sel )
43 {
44 m_grid = grid;
45 m_selectionMode = sel;
46 }
47
48 bool wxGridSelection::IsSelection()
49 {
50 return ( m_cellSelection.GetCount() || m_blockSelectionTopLeft.GetCount() ||
51 m_rowSelection.GetCount() || m_colSelection.GetCount() );
52 }
53
54 bool wxGridSelection::IsInSelection( int row, int col )
55 {
56 size_t count;
57
58 // First check whether the given cell is individually selected
59 // (if m_selectionMode is wxGridSelectCells).
60 if ( m_selectionMode == wxGrid::wxGridSelectCells )
61 {
62 count = m_cellSelection.GetCount();
63 for ( size_t n = 0; n < count; n++ )
64 {
65 wxGridCellCoords& coords = m_cellSelection[n];
66 if ( row == coords.GetRow() && col == coords.GetCol() )
67 return true;
68 }
69 }
70
71 // Now check whether the given cell is
72 // contained in one of the selected blocks.
73 count = m_blockSelectionTopLeft.GetCount();
74 for ( size_t n = 0; n < count; n++ )
75 {
76 wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n];
77 wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n];
78 if ( BlockContainsCell(coords1.GetRow(), coords1.GetCol(),
79 coords2.GetRow(), coords2.GetCol(),
80 row, col ) )
81 return true;
82 }
83
84 // Now check whether the given cell is
85 // contained in one of the selected rows
86 // (unless we are in column selection mode).
87 if ( m_selectionMode != wxGrid::wxGridSelectColumns )
88 {
89 count = m_rowSelection.GetCount();
90 for ( size_t n = 0; n < count; n++ )
91 {
92 if ( row == m_rowSelection[n] )
93 return true;
94 }
95 }
96
97 // Now check whether the given cell is
98 // contained in one of the selected columns
99 // (unless we are in row selection mode).
100 if ( m_selectionMode != wxGrid::wxGridSelectRows )
101 {
102 count = m_colSelection.GetCount();
103 for ( size_t n = 0; n < count; n++ )
104 {
105 if ( col == m_colSelection[n] )
106 return true;
107 }
108 }
109
110 return false;
111 }
112
113 // Change the selection mode
114 void wxGridSelection::SetSelectionMode( wxGrid::wxGridSelectionModes selmode )
115 {
116 // if selection mode is unchanged return immediately
117 if (selmode == m_selectionMode)
118 return;
119
120 if ( m_selectionMode != wxGrid::wxGridSelectCells )
121 {
122 // if changing form row to column selection
123 // or vice versa, clear the selection.
124 if ( selmode != wxGrid::wxGridSelectCells )
125 ClearSelection();
126
127 m_selectionMode = selmode;
128 }
129 else
130 {
131 // if changing from cell selection to something else,
132 // promote selected cells/blocks to whole rows/columns.
133 size_t n;
134 while ( ( n = m_cellSelection.GetCount() ) > 0 )
135 {
136 n--;
137 wxGridCellCoords& coords = m_cellSelection[n];
138 int row = coords.GetRow();
139 int col = coords.GetCol();
140 m_cellSelection.RemoveAt(n);
141 if (selmode == wxGrid::wxGridSelectRows)
142 SelectRow( row );
143 else // selmode == wxGridSelectColumns)
144 SelectCol( col );
145 }
146
147 // Note that m_blockSelectionTopLeft's size may be changing!
148 for (n = 0; n < m_blockSelectionTopLeft.GetCount(); n++)
149 {
150 wxGridCellCoords& coords = m_blockSelectionTopLeft[n];
151 int topRow = coords.GetRow();
152 int leftCol = coords.GetCol();
153 coords = m_blockSelectionBottomRight[n];
154 int bottomRow = coords.GetRow();
155 int rightCol = coords.GetCol();
156
157 if (selmode == wxGrid::wxGridSelectRows)
158 {
159 if (leftCol != 0 || rightCol != m_grid->GetNumberCols() - 1 )
160 {
161 m_blockSelectionTopLeft.RemoveAt(n);
162 m_blockSelectionBottomRight.RemoveAt(n);
163 SelectBlockNoEvent( topRow, 0,
164 bottomRow, m_grid->GetNumberCols() - 1);
165 }
166 }
167 else // selmode == wxGridSelectColumns)
168 {
169 if (topRow != 0 || bottomRow != m_grid->GetNumberRows() - 1 )
170 {
171 m_blockSelectionTopLeft.RemoveAt(n);
172 m_blockSelectionBottomRight.RemoveAt(n);
173 SelectBlockNoEvent(0, leftCol,
174 m_grid->GetNumberRows() - 1, rightCol);
175 }
176 }
177 }
178
179 m_selectionMode = selmode;
180 }
181 }
182
183 void wxGridSelection::SelectRow(int row, const wxKeyboardState& kbd)
184 {
185 if ( m_selectionMode == wxGrid::wxGridSelectColumns )
186 return;
187
188 size_t count, n;
189
190 // Remove single cells contained in newly selected block.
191 if ( m_selectionMode == wxGrid::wxGridSelectCells )
192 {
193 count = m_cellSelection.GetCount();
194 for ( n = 0; n < count; n++ )
195 {
196 wxGridCellCoords& coords = m_cellSelection[n];
197 if ( BlockContainsCell( row, 0, row, m_grid->GetNumberCols() - 1,
198 coords.GetRow(), coords.GetCol() ) )
199 {
200 m_cellSelection.RemoveAt(n);
201 n--;
202 count--;
203 }
204 }
205 }
206
207 // Simplify list of selected blocks (if possible)
208 count = m_blockSelectionTopLeft.GetCount();
209 bool done = false;
210
211 for ( n = 0; n < count; n++ )
212 {
213 wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n];
214 wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n];
215
216 // Remove block if it is a subset of the row
217 if ( coords1.GetRow() == row && row == coords2.GetRow() )
218 {
219 m_blockSelectionTopLeft.RemoveAt(n);
220 m_blockSelectionBottomRight.RemoveAt(n);
221 n--;
222 count--;
223 }
224 else if ( coords1.GetCol() == 0 &&
225 coords2.GetCol() == m_grid->GetNumberCols() - 1 )
226 {
227 // silently return, if row is contained in block
228 if ( coords1.GetRow() <= row && row <= coords2.GetRow() )
229 return;
230 // expand block, if it touched row
231 else if ( coords1.GetRow() == row + 1)
232 {
233 coords1.SetRow(row);
234 done = true;
235 }
236 else if ( coords2.GetRow() == row - 1)
237 {
238 coords2.SetRow(row);
239 done = true;
240 }
241 }
242 }
243
244 // Unless we successfully handled the row,
245 // check whether row is already selected.
246 if ( !done )
247 {
248 count = m_rowSelection.GetCount();
249 for ( n = 0; n < count; n++ )
250 {
251 if ( row == m_rowSelection[n] )
252 return;
253 }
254
255 // Add row to selection
256 m_rowSelection.Add(row);
257 }
258
259 // Update View:
260 if ( !m_grid->GetBatchCount() )
261 {
262 wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( row, 0 ),
263 wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) );
264 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
265 }
266
267 // Send Event
268 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
269 wxEVT_GRID_RANGE_SELECT,
270 m_grid,
271 wxGridCellCoords( row, 0 ),
272 wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ),
273 true,
274 kbd);
275
276 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
277 }
278
279 void wxGridSelection::SelectCol(int col, const wxKeyboardState& kbd)
280 {
281 if ( m_selectionMode == wxGrid::wxGridSelectRows )
282 return;
283 size_t count, n;
284
285 // Remove single cells contained in newly selected block.
286 if ( m_selectionMode == wxGrid::wxGridSelectCells )
287 {
288 count = m_cellSelection.GetCount();
289 for ( n = 0; n < count; n++ )
290 {
291 wxGridCellCoords& coords = m_cellSelection[n];
292 if ( BlockContainsCell( 0, col, m_grid->GetNumberRows() - 1, col,
293 coords.GetRow(), coords.GetCol() ) )
294 {
295 m_cellSelection.RemoveAt(n);
296 n--;
297 count--;
298 }
299 }
300 }
301
302 // Simplify list of selected blocks (if possible)
303 count = m_blockSelectionTopLeft.GetCount();
304 bool done = false;
305 for ( n = 0; n < count; n++ )
306 {
307 wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n];
308 wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n];
309
310 // Remove block if it is a subset of the column
311 if ( coords1.GetCol() == col && col == coords2.GetCol() )
312 {
313 m_blockSelectionTopLeft.RemoveAt(n);
314 m_blockSelectionBottomRight.RemoveAt(n);
315 n--;
316 count--;
317 }
318 else if ( coords1.GetRow() == 0 &&
319 coords2.GetRow() == m_grid->GetNumberRows() - 1 )
320 {
321 // silently return, if row is contained in block
322 if ( coords1.GetCol() <= col && col <= coords2.GetCol() )
323 return;
324 // expand block, if it touched col
325 else if ( coords1.GetCol() == col + 1)
326 {
327 coords1.SetCol(col);
328 done = true;
329 }
330 else if ( coords2.GetCol() == col - 1)
331 {
332 coords2.SetCol(col);
333 done = true;
334 }
335 }
336 }
337
338 // Unless we successfully handled the column,
339 // Check whether col is already selected.
340 if ( !done )
341 {
342 count = m_colSelection.GetCount();
343 for ( n = 0; n < count; n++ )
344 {
345 if ( col == m_colSelection[n] )
346 return;
347 }
348
349 // Add col to selection
350 m_colSelection.Add(col);
351 }
352
353 // Update View:
354 if ( !m_grid->GetBatchCount() )
355 {
356 wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( 0, col ),
357 wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) );
358 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
359 }
360
361 // Send Event
362 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
363 wxEVT_GRID_RANGE_SELECT,
364 m_grid,
365 wxGridCellCoords( 0, col ),
366 wxGridCellCoords( m_grid->GetNumberRows() - 1, col ),
367 true,
368 kbd );
369
370 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
371 }
372
373 void wxGridSelection::SelectBlock( int topRow, int leftCol,
374 int bottomRow, int rightCol,
375 const wxKeyboardState& kbd,
376 bool sendEvent )
377 {
378 // Fix the coordinates of the block if needed.
379 switch ( m_selectionMode )
380 {
381 default:
382 wxFAIL_MSG( "unknown selection mode" );
383 // fall through
384
385 case wxGrid::wxGridSelectCells:
386 // nothing to do -- in this mode arbitrary blocks can be selected
387 break;
388
389 case wxGrid::wxGridSelectRows:
390 leftCol = 0;
391 rightCol = m_grid->GetNumberCols() - 1;
392 break;
393
394 case wxGrid::wxGridSelectColumns:
395 topRow = 0;
396 bottomRow = m_grid->GetNumberRows() - 1;
397 break;
398
399 case wxGrid::wxGridSelectRowsOrColumns:
400 // block selection doesn't make sense for this mode, we could only
401 // select the entire grid but this wouldn't be useful
402 return;
403 }
404
405 if ( topRow > bottomRow )
406 {
407 int temp = topRow;
408 topRow = bottomRow;
409 bottomRow = temp;
410 }
411
412 if ( leftCol > rightCol )
413 {
414 int temp = leftCol;
415 leftCol = rightCol;
416 rightCol = temp;
417 }
418
419 // Handle single cell selection in SelectCell.
420 // (MB: added check for selection mode here to prevent
421 // crashes if, for example, we are select rows and the
422 // grid only has 1 col)
423 if ( m_selectionMode == wxGrid::wxGridSelectCells &&
424 topRow == bottomRow && leftCol == rightCol )
425 {
426 SelectCell( topRow, leftCol, kbd, sendEvent );
427 }
428
429 size_t count, n;
430
431 if ( m_selectionMode == wxGrid::wxGridSelectRows )
432 {
433 // find out which rows are already selected:
434 wxArrayInt alreadyselected;
435 alreadyselected.Add(0,bottomRow-topRow+1);
436 for( n = 0; n < m_rowSelection.GetCount(); n++)
437 {
438 int row = m_rowSelection[n];
439 if( (row >= topRow) && (row <= bottomRow) )
440 {
441 alreadyselected[ row - topRow ]=1;
442 }
443 }
444
445 // add the newly selected rows:
446 for ( int row = topRow; row <= bottomRow; row++ )
447 {
448 if ( alreadyselected[ row - topRow ] == 0 )
449 {
450 m_rowSelection.Add( row );
451 }
452 }
453 }
454 else if ( m_selectionMode == wxGrid::wxGridSelectColumns )
455 {
456 // find out which columns are already selected:
457 wxArrayInt alreadyselected;
458 alreadyselected.Add(0,rightCol-leftCol+1);
459 for( n = 0; n < m_colSelection.GetCount(); n++)
460 {
461 int col = m_colSelection[n];
462 if( (col >= leftCol) && (col <= rightCol) )
463 {
464 alreadyselected[ col - leftCol ]=1;
465 }
466 }
467
468 // add the newly selected columns:
469 for ( int col = leftCol; col <= rightCol; col++ )
470 {
471 if ( alreadyselected[ col - leftCol ] == 0 )
472 {
473 m_colSelection.Add( col );
474 }
475 }
476 }
477 else
478 {
479 // Remove single cells contained in newly selected block.
480 if ( m_selectionMode == wxGrid::wxGridSelectCells )
481 {
482 count = m_cellSelection.GetCount();
483 for ( n = 0; n < count; n++ )
484 {
485 wxGridCellCoords& coords = m_cellSelection[n];
486 if ( BlockContainsCell( topRow, leftCol, bottomRow, rightCol,
487 coords.GetRow(), coords.GetCol() ) )
488 {
489 m_cellSelection.RemoveAt(n);
490 n--;
491 count--;
492 }
493 }
494 }
495
496 // If a block containing the selection is already selected, return,
497 // if a block contained in the selection is found, remove it.
498
499 count = m_blockSelectionTopLeft.GetCount();
500 for ( n = 0; n < count; n++ )
501 {
502 wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n];
503 wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n];
504
505 switch ( BlockContain( coords1.GetRow(), coords1.GetCol(),
506 coords2.GetRow(), coords2.GetCol(),
507 topRow, leftCol, bottomRow, rightCol ) )
508 {
509 case 1:
510 return;
511
512 case -1:
513 m_blockSelectionTopLeft.RemoveAt(n);
514 m_blockSelectionBottomRight.RemoveAt(n);
515 n--;
516 count--;
517 break;
518
519 default:
520 break;
521 }
522 }
523
524 // If a row containing the selection is already selected, return,
525 // if a row contained in newly selected block is found, remove it.
526 count = m_rowSelection.GetCount();
527 for ( n = 0; n < count; n++ )
528 {
529 switch ( BlockContain( m_rowSelection[n], 0,
530 m_rowSelection[n], m_grid->GetNumberCols() - 1,
531 topRow, leftCol, bottomRow, rightCol ) )
532 {
533 case 1:
534 return;
535
536 case -1:
537 m_rowSelection.RemoveAt(n);
538 n--;
539 count--;
540 break;
541
542 default:
543 break;
544 }
545 }
546
547 // Same for columns.
548 count = m_colSelection.GetCount();
549 for ( n = 0; n < count; n++ )
550 {
551 switch ( BlockContain( 0, m_colSelection[n],
552 m_grid->GetNumberRows() - 1, m_colSelection[n],
553 topRow, leftCol, bottomRow, rightCol ) )
554 {
555 case 1:
556 return;
557
558 case -1:
559 m_colSelection.RemoveAt(n);
560 n--;
561 count--;
562 break;
563
564 default:
565 break;
566 }
567 }
568
569 m_blockSelectionTopLeft.Add( wxGridCellCoords( topRow, leftCol ) );
570 m_blockSelectionBottomRight.Add( wxGridCellCoords( bottomRow, rightCol ) );
571 }
572 // Update View:
573 if ( !m_grid->GetBatchCount() )
574 {
575 wxRect r = m_grid->BlockToDeviceRect( wxGridCellCoords( topRow, leftCol ),
576 wxGridCellCoords( bottomRow, rightCol ) );
577 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
578 }
579
580 // Send Event, if not disabled.
581 if ( sendEvent )
582 {
583 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
584 wxEVT_GRID_RANGE_SELECT,
585 m_grid,
586 wxGridCellCoords( topRow, leftCol ),
587 wxGridCellCoords( bottomRow, rightCol ),
588 true,
589 kbd);
590 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
591 }
592 }
593
594 void wxGridSelection::SelectCell( int row, int col,
595 const wxKeyboardState& kbd,
596 bool sendEvent )
597 {
598 if ( IsInSelection ( row, col ) )
599 return;
600
601 wxGridCellCoords selectedTopLeft, selectedBottomRight;
602 if ( m_selectionMode == wxGrid::wxGridSelectRows )
603 {
604 m_rowSelection.Add( row );
605 selectedTopLeft = wxGridCellCoords( row, 0 );
606 selectedBottomRight = wxGridCellCoords( row, m_grid->GetNumberCols() - 1 );
607 }
608 else if ( m_selectionMode == wxGrid::wxGridSelectColumns )
609 {
610 m_colSelection.Add( col );
611 selectedTopLeft = wxGridCellCoords( 0, col );
612 selectedBottomRight = wxGridCellCoords( m_grid->GetNumberRows() - 1, col );
613 }
614 else
615 {
616 m_cellSelection.Add( wxGridCellCoords( row, col ) );
617 selectedTopLeft = wxGridCellCoords( row, col );
618 selectedBottomRight = wxGridCellCoords( row, col );
619 }
620
621 // Update View:
622 if ( !m_grid->GetBatchCount() )
623 {
624 wxRect r = m_grid->BlockToDeviceRect(
625 selectedTopLeft,
626 selectedBottomRight );
627 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
628 }
629
630 // Send event
631 if (sendEvent)
632 {
633 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
634 wxEVT_GRID_RANGE_SELECT,
635 m_grid,
636 selectedTopLeft,
637 selectedBottomRight,
638 true,
639 kbd);
640 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
641 }
642 }
643
644 void
645 wxGridSelection::ToggleCellSelection(int row, int col,
646 const wxKeyboardState& kbd)
647 {
648 // if the cell is not selected, select it
649 if ( !IsInSelection ( row, col ) )
650 {
651 SelectCell(row, col, kbd);
652
653 return;
654 }
655
656 // otherwise deselect it. This can be simple or more or
657 // less difficult, depending on how the cell is selected.
658 size_t count, n;
659
660 // The simplest case: The cell is contained in m_cellSelection
661 // Then it can't be contained in rows/cols/block (since those
662 // would remove the cell from m_cellSelection on creation), so
663 // we just have to remove it from m_cellSelection.
664
665 if ( m_selectionMode == wxGrid::wxGridSelectCells )
666 {
667 count = m_cellSelection.GetCount();
668 for ( n = 0; n < count; n++ )
669 {
670 const wxGridCellCoords& sel = m_cellSelection[n];
671 if ( row == sel.GetRow() && col == sel.GetCol() )
672 {
673 wxGridCellCoords coords = m_cellSelection[n];
674 m_cellSelection.RemoveAt(n);
675 if ( !m_grid->GetBatchCount() )
676 {
677 wxRect r = m_grid->BlockToDeviceRect( coords, coords );
678 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
679 }
680
681 // Send event
682 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
683 wxEVT_GRID_RANGE_SELECT,
684 m_grid,
685 wxGridCellCoords( row, col ),
686 wxGridCellCoords( row, col ),
687 false,
688 kbd );
689 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
690
691 return;
692 }
693 }
694 }
695
696 // The most difficult case: The cell is member of one or even several
697 // blocks. Split each such block in up to 4 new parts, that don't
698 // contain the cell to be selected, like this:
699 // |---------------------------|
700 // | |
701 // | part 1 |
702 // | |
703 // |---------------------------|
704 // | part 3 |x| part 4 |
705 // |---------------------------|
706 // | |
707 // | part 2 |
708 // | |
709 // |---------------------------|
710 // (The x marks the newly deselected cell).
711 // Note: in row selection mode, we only need part1 and part2;
712 // in column selection mode, we only need part 3 and part4,
713 // which are expanded to whole columns automatically!
714
715 count = m_blockSelectionTopLeft.GetCount();
716 for ( n = 0; n < count; n++ )
717 {
718 wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n];
719 wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n];
720 int topRow = coords1.GetRow();
721 int leftCol = coords1.GetCol();
722 int bottomRow = coords2.GetRow();
723 int rightCol = coords2.GetCol();
724
725 if ( BlockContainsCell( topRow, leftCol, bottomRow, rightCol, row, col ) )
726 {
727 // remove the block
728 m_blockSelectionTopLeft.RemoveAt(n);
729 m_blockSelectionBottomRight.RemoveAt(n);
730 n--;
731 count--;
732
733 // add up to 4 smaller blocks and set update region
734 if ( m_selectionMode != wxGrid::wxGridSelectColumns )
735 {
736 if ( topRow < row )
737 SelectBlockNoEvent(topRow, leftCol, row - 1, rightCol);
738 if ( bottomRow > row )
739 SelectBlockNoEvent(row + 1, leftCol, bottomRow, rightCol);
740 }
741
742 if ( m_selectionMode != wxGrid::wxGridSelectRows )
743 {
744 if ( leftCol < col )
745 SelectBlockNoEvent(row, leftCol, row, col - 1);
746 if ( rightCol > col )
747 SelectBlockNoEvent(row, col + 1, row, rightCol);
748 }
749 }
750 }
751
752 bool rowSelectionWasChanged = false;
753 // remove a cell from a row, adding up to two new blocks
754 if ( m_selectionMode != wxGrid::wxGridSelectColumns )
755 {
756 count = m_rowSelection.GetCount();
757 for ( n = 0; n < count; n++ )
758 {
759 if ( m_rowSelection[n] == row )
760 {
761 m_rowSelection.RemoveAt(n);
762 n--;
763 count--;
764
765 rowSelectionWasChanged = true;
766
767 if (m_selectionMode == wxGrid::wxGridSelectCells)
768 {
769 if ( col > 0 )
770 SelectBlockNoEvent(row, 0, row, col - 1);
771 if ( col < m_grid->GetNumberCols() - 1 )
772 SelectBlockNoEvent( row, col + 1,
773 row, m_grid->GetNumberCols() - 1);
774 }
775 }
776 }
777 }
778
779 bool colSelectionWasChanged = false;
780 // remove a cell from a column, adding up to two new blocks
781 if ( m_selectionMode != wxGrid::wxGridSelectRows )
782 {
783 count = m_colSelection.GetCount();
784 for ( n = 0; n < count; n++ )
785 {
786 if ( m_colSelection[n] == col )
787 {
788 m_colSelection.RemoveAt(n);
789 n--;
790 count--;
791
792 colSelectionWasChanged = true;
793
794 if (m_selectionMode == wxGrid::wxGridSelectCells)
795 {
796 if ( row > 0 )
797 SelectBlockNoEvent(0, col, row - 1, col);
798 if ( row < m_grid->GetNumberRows() - 1 )
799 SelectBlockNoEvent(row + 1, col,
800 m_grid->GetNumberRows() - 1, col);
801 }
802 }
803 }
804 }
805
806 // Refresh the screen and send the event; according to m_selectionMode,
807 // we need to either update only the cell, or the whole row/column.
808 wxRect r;
809 if ( m_selectionMode == wxGrid::wxGridSelectCells )
810 {
811 if ( !m_grid->GetBatchCount() )
812 {
813 r = m_grid->BlockToDeviceRect(
814 wxGridCellCoords( row, col ),
815 wxGridCellCoords( row, col ) );
816 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
817 }
818
819 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
820 wxEVT_GRID_RANGE_SELECT,
821 m_grid,
822 wxGridCellCoords( row, col ),
823 wxGridCellCoords( row, col ),
824 false,
825 kbd );
826 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
827 }
828 else // rows/columns selection mode
829 {
830 if ( m_selectionMode != wxGrid::wxGridSelectColumns &&
831 rowSelectionWasChanged )
832 {
833 int numCols = m_grid->GetNumberCols();
834 for ( int colFrom = 0, colTo = 0; colTo <= numCols; ++colTo )
835 {
836 if ( m_colSelection.Index(colTo) >= 0 || colTo == numCols )
837 {
838 if ( colFrom < colTo )
839 {
840 if ( !m_grid->GetBatchCount() )
841 {
842 r = m_grid->BlockToDeviceRect(
843 wxGridCellCoords( row, colFrom ),
844 wxGridCellCoords( row, colTo-1 ) );
845 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
846 }
847
848 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
849 wxEVT_GRID_RANGE_SELECT,
850 m_grid,
851 wxGridCellCoords( row, colFrom ),
852 wxGridCellCoords( row, colTo - 1 ),
853 false,
854 kbd );
855 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
856 }
857
858 colFrom = colTo + 1;
859 }
860 }
861 }
862
863 if ( m_selectionMode != wxGrid::wxGridSelectRows &&
864 colSelectionWasChanged )
865 {
866 int numRows = m_grid->GetNumberRows();
867 for ( int rowFrom = 0, rowTo = 0; rowTo <= numRows; ++rowTo )
868 {
869 if ( m_rowSelection.Index(rowTo) >= 0 || rowTo == numRows )
870 {
871 if (rowFrom < rowTo)
872 {
873 if ( !m_grid->GetBatchCount() )
874 {
875 r = m_grid->BlockToDeviceRect(
876 wxGridCellCoords( rowFrom, col ),
877 wxGridCellCoords( rowTo - 1, col ) );
878 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
879 }
880
881 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
882 wxEVT_GRID_RANGE_SELECT,
883 m_grid,
884 wxGridCellCoords( rowFrom, col ),
885 wxGridCellCoords( rowTo - 1, col ),
886 false,
887 kbd );
888 m_grid->GetEventHandler()->ProcessEvent( gridEvt );
889 }
890
891 rowFrom = rowTo + 1;
892 }
893 }
894 }
895 }
896 }
897
898 void wxGridSelection::ClearSelection()
899 {
900 size_t n;
901 wxRect r;
902 wxGridCellCoords coords1, coords2;
903
904 // deselect all individual cells and update the screen
905 if ( m_selectionMode == wxGrid::wxGridSelectCells )
906 {
907 while ( ( n = m_cellSelection.GetCount() ) > 0)
908 {
909 n--;
910 coords1 = m_cellSelection[n];
911 m_cellSelection.RemoveAt(n);
912 if ( !m_grid->GetBatchCount() )
913 {
914 r = m_grid->BlockToDeviceRect( coords1, coords1 );
915 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
916
917 #ifdef __WXMAC__
918 ((wxWindow *)m_grid->m_gridWin)->Update();
919 #endif
920 }
921 }
922 }
923
924 // deselect all blocks and update the screen
925 while ( ( n = m_blockSelectionTopLeft.GetCount() ) > 0)
926 {
927 n--;
928 coords1 = m_blockSelectionTopLeft[n];
929 coords2 = m_blockSelectionBottomRight[n];
930 m_blockSelectionTopLeft.RemoveAt(n);
931 m_blockSelectionBottomRight.RemoveAt(n);
932 if ( !m_grid->GetBatchCount() )
933 {
934 r = m_grid->BlockToDeviceRect( coords1, coords2 );
935 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
936
937 #ifdef __WXMAC__
938 ((wxWindow *)m_grid->m_gridWin)->Update();
939 #endif
940 }
941 }
942
943 // deselect all rows and update the screen
944 if ( m_selectionMode != wxGrid::wxGridSelectColumns )
945 {
946 while ( ( n = m_rowSelection.GetCount() ) > 0)
947 {
948 n--;
949 int row = m_rowSelection[n];
950 m_rowSelection.RemoveAt(n);
951 if ( !m_grid->GetBatchCount() )
952 {
953 r = m_grid->BlockToDeviceRect( wxGridCellCoords( row, 0 ),
954 wxGridCellCoords( row, m_grid->GetNumberCols() - 1 ) );
955 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
956
957 #ifdef __WXMAC__
958 ((wxWindow *)m_grid->m_gridWin)->Update();
959 #endif
960 }
961 }
962 }
963
964 // deselect all columns and update the screen
965 if ( m_selectionMode != wxGrid::wxGridSelectRows )
966 {
967 while ( ( n = m_colSelection.GetCount() ) > 0)
968 {
969 n--;
970 int col = m_colSelection[n];
971 m_colSelection.RemoveAt(n);
972 if ( !m_grid->GetBatchCount() )
973 {
974 r = m_grid->BlockToDeviceRect( wxGridCellCoords( 0, col ),
975 wxGridCellCoords( m_grid->GetNumberRows() - 1, col ) );
976 ((wxWindow *)m_grid->m_gridWin)->Refresh( false, &r );
977
978 #ifdef __WXMAC__
979 ((wxWindow *)m_grid->m_gridWin)->Update();
980 #endif
981 }
982 }
983 }
984
985 // One deselection event, indicating deselection of _all_ cells.
986 // (No finer grained events for each of the smaller regions
987 // deselected above!)
988 wxGridRangeSelectEvent gridEvt( m_grid->GetId(),
989 wxEVT_GRID_RANGE_SELECT,
990 m_grid,
991 wxGridCellCoords( 0, 0 ),
992 wxGridCellCoords(
993 m_grid->GetNumberRows() - 1,
994 m_grid->GetNumberCols() - 1 ),
995 false );
996
997 m_grid->GetEventHandler()->ProcessEvent(gridEvt);
998 }
999
1000
1001 void wxGridSelection::UpdateRows( size_t pos, int numRows )
1002 {
1003 size_t count = m_cellSelection.GetCount();
1004 size_t n;
1005 for ( n = 0; n < count; n++ )
1006 {
1007 wxGridCellCoords& coords = m_cellSelection[n];
1008 wxCoord row = coords.GetRow();
1009 if ((size_t)row >= pos)
1010 {
1011 if (numRows > 0)
1012 {
1013 // If rows inserted, increase row counter where necessary
1014 coords.SetRow(row + numRows);
1015 }
1016 else if (numRows < 0)
1017 {
1018 // If rows deleted ...
1019 if ((size_t)row >= pos - numRows)
1020 {
1021 // ...either decrement row counter (if row still exists)...
1022 coords.SetRow(row + numRows);
1023 }
1024 else
1025 {
1026 // ...or remove the attribute
1027 m_cellSelection.RemoveAt(n);
1028 n--;
1029 count--;
1030 }
1031 }
1032 }
1033 }
1034
1035 count = m_blockSelectionTopLeft.GetCount();
1036 for ( n = 0; n < count; n++ )
1037 {
1038 wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n];
1039 wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n];
1040 wxCoord row1 = coords1.GetRow();
1041 wxCoord row2 = coords2.GetRow();
1042
1043 if ((size_t)row2 >= pos)
1044 {
1045 if (numRows > 0)
1046 {
1047 // If rows inserted, increase row counter where necessary
1048 coords2.SetRow( row2 + numRows );
1049 if ((size_t)row1 >= pos)
1050 coords1.SetRow( row1 + numRows );
1051 }
1052 else if (numRows < 0)
1053 {
1054 // If rows deleted ...
1055 if ((size_t)row2 >= pos - numRows)
1056 {
1057 // ...either decrement row counter (if row still exists)...
1058 coords2.SetRow( row2 + numRows );
1059 if ((size_t)row1 >= pos)
1060 coords1.SetRow( wxMax(row1 + numRows, (int)pos) );
1061
1062 }
1063 else
1064 {
1065 if ((size_t)row1 >= pos)
1066 {
1067 // ...or remove the attribute
1068 m_blockSelectionTopLeft.RemoveAt(n);
1069 m_blockSelectionBottomRight.RemoveAt(n);
1070 n--;
1071 count--;
1072 }
1073 else
1074 coords2.SetRow( pos );
1075 }
1076 }
1077 }
1078 }
1079
1080 count = m_rowSelection.GetCount();
1081 for ( n = 0; n < count; n++ )
1082 {
1083 int rowOrCol_ = m_rowSelection[n];
1084
1085 if ((size_t) rowOrCol_ >= pos)
1086 {
1087 if ( numRows > 0 )
1088 {
1089 m_rowSelection[n] += numRows;
1090 }
1091 else if ( numRows < 0 )
1092 {
1093 if ((size_t)rowOrCol_ >= (pos - numRows))
1094 m_rowSelection[n] += numRows;
1095 else
1096 {
1097 m_rowSelection.RemoveAt( n );
1098 n--;
1099 count--;
1100 }
1101 }
1102 }
1103 }
1104 // No need to touch selected columns, unless we removed _all_
1105 // rows, in this case, we remove all columns from the selection.
1106
1107 if ( !m_grid->GetNumberRows() )
1108 m_colSelection.Clear();
1109 }
1110
1111
1112 void wxGridSelection::UpdateCols( size_t pos, int numCols )
1113 {
1114 size_t count = m_cellSelection.GetCount();
1115 size_t n;
1116
1117 for ( n = 0; n < count; n++ )
1118 {
1119 wxGridCellCoords& coords = m_cellSelection[n];
1120 wxCoord col = coords.GetCol();
1121 if ((size_t)col >= pos)
1122 {
1123 if (numCols > 0)
1124 {
1125 // If rows inserted, increase row counter where necessary
1126 coords.SetCol(col + numCols);
1127 }
1128 else if (numCols < 0)
1129 {
1130 // If rows deleted ...
1131 if ((size_t)col >= pos - numCols)
1132 {
1133 // ...either decrement row counter (if row still exists)...
1134 coords.SetCol(col + numCols);
1135 }
1136 else
1137 {
1138 // ...or remove the attribute
1139 m_cellSelection.RemoveAt(n);
1140 n--;
1141 count--;
1142 }
1143 }
1144 }
1145 }
1146
1147 count = m_blockSelectionTopLeft.GetCount();
1148 for ( n = 0; n < count; n++ )
1149 {
1150 wxGridCellCoords& coords1 = m_blockSelectionTopLeft[n];
1151 wxGridCellCoords& coords2 = m_blockSelectionBottomRight[n];
1152 wxCoord col1 = coords1.GetCol();
1153 wxCoord col2 = coords2.GetCol();
1154
1155 if ((size_t)col2 >= pos)
1156 {
1157 if (numCols > 0)
1158 {
1159 // If rows inserted, increase row counter where necessary
1160 coords2.SetCol(col2 + numCols);
1161 if ((size_t)col1 >= pos)
1162 coords1.SetCol(col1 + numCols);
1163 }
1164 else if (numCols < 0)
1165 {
1166 // If cols deleted ...
1167 if ((size_t)col2 >= pos - numCols)
1168 {
1169 // ...either decrement col counter (if col still exists)...
1170 coords2.SetCol(col2 + numCols);
1171 if ( (size_t) col1 >= pos)
1172 coords1.SetCol( wxMax(col1 + numCols, (int)pos) );
1173
1174 }
1175 else
1176 {
1177 if ((size_t)col1 >= pos)
1178 {
1179 // ...or remove the attribute
1180 m_blockSelectionTopLeft.RemoveAt(n);
1181 m_blockSelectionBottomRight.RemoveAt(n);
1182 n--;
1183 count--;
1184 }
1185 else
1186 coords2.SetCol(pos);
1187 }
1188 }
1189 }
1190 }
1191
1192 count = m_colSelection.GetCount();
1193 for ( n = 0; n < count; n++ )
1194 {
1195 int rowOrCol = m_colSelection[n];
1196
1197 if ((size_t)rowOrCol >= pos)
1198 {
1199 if ( numCols > 0 )
1200 m_colSelection[n] += numCols;
1201 else if ( numCols < 0 )
1202 {
1203 if ((size_t)rowOrCol >= (pos - numCols))
1204 m_colSelection[n] += numCols;
1205 else
1206 {
1207 m_colSelection.RemoveAt( n );
1208 n--;
1209 count--;
1210 }
1211 }
1212 }
1213 }
1214
1215 // No need to touch selected rows, unless we removed _all_
1216 // columns, in this case, we remove all rows from the selection.
1217 if ( !m_grid->GetNumberCols() )
1218 m_rowSelection.Clear();
1219 }
1220
1221 int wxGridSelection::BlockContain( int topRow1, int leftCol1,
1222 int bottomRow1, int rightCol1,
1223 int topRow2, int leftCol2,
1224 int bottomRow2, int rightCol2 )
1225 // returns 1, if Block1 contains Block2,
1226 // -1, if Block2 contains Block1,
1227 // 0, otherwise
1228 {
1229 if ( topRow1 <= topRow2 && bottomRow2 <= bottomRow1 &&
1230 leftCol1 <= leftCol2 && rightCol2 <= rightCol1 )
1231 return 1;
1232 else if ( topRow2 <= topRow1 && bottomRow1 <= bottomRow2 &&
1233 leftCol2 <= leftCol1 && rightCol1 <= rightCol2 )
1234 return -1;
1235
1236 return 0;
1237 }
1238
1239 #endif