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