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