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