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