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