]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp
Added drag-shrinking
[wxWidgets.git] / src / generic / grid.cpp
CommitLineData
5612a518 1/////////////////////////////////////////////////////////////////////////////
f85afd4e
MB
2// Name: grid.cpp
3// Purpose: wxGrid and related classes
4// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5// Modified by:
6// Created: 1/08/1999
7// RCS-ID: $Id$
8// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
f85afd4e
MB
12#ifdef __GNUG__
13 #pragma implementation "grid.h"
14#endif
15
4d85bcd1
JS
16// For compilers that support precompilation, includes "wx/wx.h".
17#include "wx/wxprec.h"
18
19#include "wx/defs.h"
f85afd4e
MB
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
8f177c8e 25#if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
4d85bcd1
JS
26#include "gridg.cpp"
27#else
28
f85afd4e
MB
29#ifndef WX_PRECOMP
30 #include "wx/utils.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/log.h"
2d66e025 34 #include "wx/sizer.h"
f85afd4e
MB
35#endif
36
37#include "wx/generic/grid.h"
38
39
40//////////////////////////////////////////////////////////////////////
41
42wxGridCellCoords wxGridNoCellCoords( -1, -1 );
43wxRect wxGridNoCellRect( -1, -1, -1, -1 );
44
2d66e025
MB
45// this is a magic incantation which must be done!
46#include "wx/arrimpl.cpp"
47
48WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
f85afd4e
MB
49
50
51//////////////////////////////////////////////////////////////////////
52//
53// Abstract base class for grid data (the model)
54//
55IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
56
57
58wxGridTableBase::wxGridTableBase()
59 : wxObject()
60{
61 m_view = (wxGrid *) NULL;
62}
63
64wxGridTableBase::~wxGridTableBase()
65{
66}
67
68
69bool wxGridTableBase::InsertRows( size_t pos, size_t numRows )
70{
6eec2bee
OK
71 wxLogWarning( wxT("Called grid table class function InsertRows(pos=%d, N=%d)\n"
72 "but your derived table class does not override this function"),
f85afd4e 73 pos, numRows );
8f177c8e 74
f85afd4e
MB
75 return FALSE;
76}
77
78bool wxGridTableBase::AppendRows( size_t numRows )
79{
6eec2bee
OK
80 wxLogWarning( wxT("Called grid table class function AppendRows(N=%d)\n"
81 "but your derived table class does not override this function"),
f85afd4e 82 numRows );
8f177c8e 83
f85afd4e
MB
84 return FALSE;
85}
86
87bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows )
88{
6eec2bee
OK
89 wxLogWarning( wxT("Called grid table class function DeleteRows(pos=%d, N=%d)\n"
90 "but your derived table class does not override this function"),
f85afd4e 91 pos, numRows );
8f177c8e 92
f85afd4e
MB
93 return FALSE;
94}
95
96bool wxGridTableBase::InsertCols( size_t pos, size_t numCols )
97{
6eec2bee
OK
98 wxLogWarning( wxT("Called grid table class function InsertCols(pos=%d, N=%d)\n"
99 "but your derived table class does not override this function"),
f85afd4e 100 pos, numCols );
8f177c8e 101
f85afd4e
MB
102 return FALSE;
103}
104
105bool wxGridTableBase::AppendCols( size_t numCols )
106{
6eec2bee
OK
107 wxLogWarning( wxT("Called grid table class function AppendCols(N=%d)\n"
108 "but your derived table class does not override this function"),
f85afd4e 109 numCols );
8f177c8e 110
f85afd4e
MB
111 return FALSE;
112}
113
114bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols )
115{
6eec2bee
OK
116 wxLogWarning( wxT("Called grid table class function DeleteCols(pos=%d, N=%d)\n"
117 "but your derived table class does not override this function"),
f85afd4e 118 pos, numCols );
8f177c8e 119
f85afd4e
MB
120 return FALSE;
121}
122
123
124wxString wxGridTableBase::GetRowLabelValue( int row )
125{
126 wxString s;
127 s << row;
128 return s;
129}
130
131wxString wxGridTableBase::GetColLabelValue( int col )
132{
133 // default col labels are:
134 // cols 0 to 25 : A-Z
135 // cols 26 to 675 : AA-ZZ
136 // etc.
137
138 wxString s;
139 unsigned int i, n;
140 for ( n = 1; ; n++ )
141 {
142 s += ('A' + (char)( col%26 ));
143 col = col/26 - 1;
144 if ( col < 0 ) break;
145 }
146
147 // reverse the string...
148 wxString s2;
149 for ( i = 0; i < n; i++ )
150 {
151 s2 += s[n-i-1];
152 }
153
154 return s2;
155}
156
157
158
159//////////////////////////////////////////////////////////////////////
160//
161// Message class for the grid table to send requests and notifications
162// to the grid view
163//
164
165wxGridTableMessage::wxGridTableMessage()
166{
167 m_table = (wxGridTableBase *) NULL;
168 m_id = -1;
169 m_comInt1 = -1;
170 m_comInt2 = -1;
171}
172
173wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
174 int commandInt1, int commandInt2 )
175{
176 m_table = table;
177 m_id = id;
178 m_comInt1 = commandInt1;
179 m_comInt2 = commandInt2;
180}
181
182
183
184//////////////////////////////////////////////////////////////////////
185//
186// A basic grid table for string data. An object of this class will
187// created by wxGrid if you don't specify an alternative table class.
188//
189
223d09f6 190WX_DEFINE_OBJARRAY(wxGridStringArray)
f85afd4e
MB
191
192IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
193
194wxGridStringTable::wxGridStringTable()
195 : wxGridTableBase()
196{
197}
198
199wxGridStringTable::wxGridStringTable( int numRows, int numCols )
200 : wxGridTableBase()
201{
202 int row, col;
8f177c8e 203
f85afd4e
MB
204 m_data.Alloc( numRows );
205
206 wxArrayString sa;
207 sa.Alloc( numCols );
208 for ( col = 0; col < numCols; col++ )
209 {
210 sa.Add( wxEmptyString );
211 }
8f177c8e 212
f85afd4e
MB
213 for ( row = 0; row < numRows; row++ )
214 {
215 m_data.Add( sa );
216 }
217}
218
219wxGridStringTable::~wxGridStringTable()
220{
221}
222
223long wxGridStringTable::GetNumberRows()
224{
225 return m_data.GetCount();
226}
227
228long wxGridStringTable::GetNumberCols()
229{
230 if ( m_data.GetCount() > 0 )
231 return m_data[0].GetCount();
232 else
233 return 0;
234}
235
236wxString wxGridStringTable::GetValue( int row, int col )
237{
238 // TODO: bounds checking
239 //
240 return m_data[row][col];
241}
242
243void wxGridStringTable::SetValue( int row, int col, const wxString& s )
244{
245 // TODO: bounds checking
246 //
247 m_data[row][col] = s;
248}
249
250bool wxGridStringTable::IsEmptyCell( int row, int col )
251{
252 // TODO: bounds checking
253 //
254 return (m_data[row][col] == wxEmptyString);
255}
256
257
258void wxGridStringTable::Clear()
259{
260 int row, col;
261 int numRows, numCols;
8f177c8e 262
f85afd4e
MB
263 numRows = m_data.GetCount();
264 if ( numRows > 0 )
265 {
266 numCols = m_data[0].GetCount();
267
268 for ( row = 0; row < numRows; row++ )
269 {
270 for ( col = 0; col < numCols; col++ )
271 {
272 m_data[row][col] = wxEmptyString;
273 }
274 }
275 }
276}
277
278
279bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
280{
281 size_t row, col;
282
283 size_t curNumRows = m_data.GetCount();
284 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
8f177c8e 285
f85afd4e
MB
286 if ( pos >= curNumRows )
287 {
288 return AppendRows( numRows );
289 }
8f177c8e 290
f85afd4e
MB
291 wxArrayString sa;
292 sa.Alloc( curNumCols );
293 for ( col = 0; col < curNumCols; col++ )
294 {
295 sa.Add( wxEmptyString );
296 }
297
298 for ( row = pos; row < pos + numRows; row++ )
299 {
300 m_data.Insert( sa, row );
301 }
302
303 if ( GetView() )
304 {
305 wxGridTableMessage msg( this,
306 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
307 pos,
308 numRows );
8f177c8e 309
f85afd4e
MB
310 GetView()->ProcessTableMessage( msg );
311 }
312
313 return TRUE;
314}
315
316bool wxGridStringTable::AppendRows( size_t numRows )
317{
318 size_t row, col;
319
320 size_t curNumRows = m_data.GetCount();
321 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
8f177c8e 322
f85afd4e
MB
323 wxArrayString sa;
324 if ( curNumCols > 0 )
325 {
326 sa.Alloc( curNumCols );
327 for ( col = 0; col < curNumCols; col++ )
328 {
329 sa.Add( wxEmptyString );
330 }
331 }
8f177c8e 332
f85afd4e
MB
333 for ( row = 0; row < numRows; row++ )
334 {
335 m_data.Add( sa );
336 }
337
338 if ( GetView() )
339 {
340 wxGridTableMessage msg( this,
341 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
342 numRows );
8f177c8e 343
f85afd4e
MB
344 GetView()->ProcessTableMessage( msg );
345 }
346
8f177c8e 347 return TRUE;
f85afd4e
MB
348}
349
350bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
351{
352 size_t n;
353
354 size_t curNumRows = m_data.GetCount();
8f177c8e 355
f85afd4e
MB
356 if ( pos >= curNumRows )
357 {
6eec2bee
OK
358 wxLogError( wxT("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)...\n"
359 "Pos value is invalid for present table with %d rows"),
f85afd4e
MB
360 pos, numRows, curNumRows );
361 return FALSE;
362 }
363
364 if ( numRows > curNumRows - pos )
365 {
366 numRows = curNumRows - pos;
367 }
8f177c8e 368
f85afd4e
MB
369 if ( numRows >= curNumRows )
370 {
371 m_data.Empty(); // don't release memory just yet
372 }
373 else
374 {
375 for ( n = 0; n < numRows; n++ )
376 {
377 m_data.Remove( pos );
378 }
379 }
380
381 if ( GetView() )
382 {
383 wxGridTableMessage msg( this,
384 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
385 pos,
386 numRows );
8f177c8e 387
f85afd4e
MB
388 GetView()->ProcessTableMessage( msg );
389 }
390
8f177c8e 391 return TRUE;
f85afd4e
MB
392}
393
394bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
395{
396 size_t row, col;
397
398 size_t curNumRows = m_data.GetCount();
399 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
8f177c8e 400
f85afd4e
MB
401 if ( pos >= curNumCols )
402 {
403 return AppendCols( numCols );
404 }
405
406 for ( row = 0; row < curNumRows; row++ )
407 {
408 for ( col = pos; col < pos + numCols; col++ )
409 {
410 m_data[row].Insert( wxEmptyString, col );
411 }
412 }
413
414 if ( GetView() )
415 {
416 wxGridTableMessage msg( this,
417 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
418 pos,
419 numCols );
8f177c8e 420
f85afd4e
MB
421 GetView()->ProcessTableMessage( msg );
422 }
423
424 return TRUE;
425}
426
427bool wxGridStringTable::AppendCols( size_t numCols )
428{
429 size_t row, n;
430
431 size_t curNumRows = m_data.GetCount();
432 if ( !curNumRows )
433 {
434 // TODO: something better than this ?
435 //
6eec2bee
OK
436 wxLogError( wxT("Unable to append cols to a grid table with no rows.\n"
437 "Call AppendRows() first") );
f85afd4e
MB
438 return FALSE;
439 }
8f177c8e 440
f85afd4e
MB
441 for ( row = 0; row < curNumRows; row++ )
442 {
443 for ( n = 0; n < numCols; n++ )
444 {
445 m_data[row].Add( wxEmptyString );
446 }
447 }
448
449 if ( GetView() )
450 {
451 wxGridTableMessage msg( this,
452 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
453 numCols );
8f177c8e 454
f85afd4e
MB
455 GetView()->ProcessTableMessage( msg );
456 }
457
458 return TRUE;
459}
460
461bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
462{
463 size_t row, n;
464
465 size_t curNumRows = m_data.GetCount();
466 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
8f177c8e 467
f85afd4e
MB
468 if ( pos >= curNumCols )
469 {
8f177c8e
VZ
470 wxLogError( wxT("Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
471 "Pos value is invalid for present table with %d cols"),
472 pos, numCols, curNumCols );
473 return FALSE;
f85afd4e
MB
474 }
475
476 if ( numCols > curNumCols - pos )
477 {
8f177c8e 478 numCols = curNumCols - pos;
f85afd4e
MB
479 }
480
481 for ( row = 0; row < curNumRows; row++ )
482 {
483 if ( numCols >= curNumCols )
484 {
485 m_data[row].Clear();
486 }
487 else
488 {
489 for ( n = 0; n < numCols; n++ )
490 {
491 m_data[row].Remove( pos );
492 }
493 }
494 }
495
496 if ( GetView() )
497 {
498 wxGridTableMessage msg( this,
499 wxGRIDTABLE_NOTIFY_COLS_DELETED,
500 pos,
501 numCols );
8f177c8e 502
f85afd4e
MB
503 GetView()->ProcessTableMessage( msg );
504 }
505
8f177c8e 506 return TRUE;
f85afd4e
MB
507}
508
509wxString wxGridStringTable::GetRowLabelValue( int row )
510{
511 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
512 {
513 // using default label
514 //
515 return wxGridTableBase::GetRowLabelValue( row );
516 }
517 else
518 {
519 return m_rowLabels[ row ];
520 }
521}
522
523wxString wxGridStringTable::GetColLabelValue( int col )
524{
525 if ( col > (int)(m_colLabels.GetCount()) - 1 )
526 {
527 // using default label
528 //
529 return wxGridTableBase::GetColLabelValue( col );
530 }
531 else
532 {
533 return m_colLabels[ col ];
534 }
535}
536
537void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
538{
539 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
540 {
541 int n = m_rowLabels.GetCount();
542 int i;
543 for ( i = n; i <= row; i++ )
544 {
545 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
546 }
547 }
548
549 m_rowLabels[row] = value;
550}
551
552void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
553{
554 if ( col > (int)(m_colLabels.GetCount()) - 1 )
555 {
556 int n = m_colLabels.GetCount();
557 int i;
558 for ( i = n; i <= col; i++ )
559 {
560 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
561 }
562 }
563
564 m_colLabels[col] = value;
565}
566
567
568
569
570//////////////////////////////////////////////////////////////////////
571
572IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl, wxTextCtrl )
8f177c8e 573
f85afd4e
MB
574BEGIN_EVENT_TABLE( wxGridTextCtrl, wxTextCtrl )
575 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown )
576END_EVENT_TABLE()
577
578
579wxGridTextCtrl::wxGridTextCtrl( wxWindow *par,
2d66e025 580 wxGrid *grid,
f85afd4e
MB
581 bool isCellControl,
582 wxWindowID id,
583 const wxString& value,
584 const wxPoint& pos,
585 const wxSize& size,
586 long style )
587 : wxTextCtrl( par, id, value, pos, size, style )
588{
2d66e025 589 m_grid = grid;
f85afd4e
MB
590 m_isCellControl = isCellControl;
591}
592
593
2d66e025 594void wxGridTextCtrl::OnKeyDown( wxKeyEvent& event )
f85afd4e 595{
2d66e025 596 switch ( event.KeyCode() )
f85afd4e
MB
597 {
598 case WXK_ESCAPE:
2d66e025 599 m_grid->SetEditControlValue( startValue );
f85afd4e
MB
600 SetInsertionPointEnd();
601 break;
602
603 case WXK_UP:
604 case WXK_DOWN:
605 case WXK_LEFT:
606 case WXK_RIGHT:
edc2c290
MB
607 case WXK_PRIOR:
608 case WXK_NEXT:
f85afd4e
MB
609 case WXK_RETURN:
610 if ( m_isCellControl )
611 {
612 // send the event to the parent grid, skipping the
613 // event if nothing happens
614 //
2d66e025 615 event.Skip( m_grid->ProcessEvent( event ) );
f85afd4e
MB
616 }
617 else
618 {
619 // default text control response within the top edit
620 // control
621 //
2d66e025 622 event.Skip();
f85afd4e
MB
623 }
624 break;
625
626 case WXK_HOME:
627 case WXK_END:
628 if ( m_isCellControl )
629 {
630 // send the event to the parent grid, skipping the
631 // event if nothing happens
632 //
2d66e025 633 event.Skip( m_grid->ProcessEvent( event ) );
f85afd4e
MB
634 }
635 else
636 {
637 // default text control response within the top edit
638 // control
639 //
2d66e025 640 event.Skip();
f85afd4e
MB
641 }
642 break;
8f177c8e 643
f85afd4e 644 default:
2d66e025 645 event.Skip();
f85afd4e
MB
646 }
647}
648
649void wxGridTextCtrl::SetStartValue( const wxString& s )
650{
651 startValue = s;
652 wxTextCtrl::SetValue( s.c_str() );
653}
654
655
2d66e025
MB
656
657//////////////////////////////////////////////////////////////////////
658
659IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
660
661BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
662 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
663 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
664 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
665END_EVENT_TABLE()
666
60ff3b99
VZ
667wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
668 wxWindowID id,
2d66e025
MB
669 const wxPoint &pos, const wxSize &size )
670 : wxWindow( parent, id, pos, size )
671{
672 m_owner = parent;
673}
674
675void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
676{
677 wxPaintDC dc(this);
678
679 // NO - don't do this because it will set both the x and y origin
680 // coords to match the parent scrolled window and we just want to
681 // set the y coord - MB
682 //
683 // m_owner->PrepareDC( dc );
60ff3b99 684
2d66e025
MB
685 wxCoord x, y;
686 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
687 dc.SetDeviceOrigin( 0, -y );
60ff3b99 688
2d66e025
MB
689 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
690 m_owner->DrawRowLabels( dc );
691}
692
693
694void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
695{
696 m_owner->ProcessRowLabelMouseEvent( event );
697}
698
699
700// This seems to be required for wxMotif otherwise the mouse
701// cursor must be in the cell edit control to get key events
702//
703void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
704{
705 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
706}
707
708
709
710//////////////////////////////////////////////////////////////////////
711
712IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
713
714BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
715 EVT_PAINT( wxGridColLabelWindow::OnPaint )
716 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
717 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
718END_EVENT_TABLE()
719
60ff3b99
VZ
720wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
721 wxWindowID id,
2d66e025
MB
722 const wxPoint &pos, const wxSize &size )
723 : wxWindow( parent, id, pos, size )
724{
725 m_owner = parent;
726}
727
728void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
729{
730 wxPaintDC dc(this);
731
732 // NO - don't do this because it will set both the x and y origin
733 // coords to match the parent scrolled window and we just want to
734 // set the x coord - MB
735 //
736 // m_owner->PrepareDC( dc );
60ff3b99 737
2d66e025
MB
738 wxCoord x, y;
739 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
740 dc.SetDeviceOrigin( -x, 0 );
741
60ff3b99
VZ
742 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
743 m_owner->DrawColLabels( dc );
2d66e025
MB
744}
745
746
747void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
748{
749 m_owner->ProcessColLabelMouseEvent( event );
750}
751
752
753// This seems to be required for wxMotif otherwise the mouse
754// cursor must be in the cell edit control to get key events
755//
756void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
757{
758 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
759}
760
761
762
763//////////////////////////////////////////////////////////////////////
764
765IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
766
767BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
768 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
769 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
770END_EVENT_TABLE()
771
60ff3b99
VZ
772wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
773 wxWindowID id,
2d66e025
MB
774 const wxPoint &pos, const wxSize &size )
775 : wxWindow( parent, id, pos, size, wxRAISED_BORDER )
776{
777 m_owner = parent;
778}
779
780
781void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
782{
783 m_owner->ProcessCornerLabelMouseEvent( event );
784}
785
786
787// This seems to be required for wxMotif otherwise the mouse
788// cursor must be in the cell edit control to get key events
789//
790void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
791{
792 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
793}
794
795
796
f85afd4e
MB
797//////////////////////////////////////////////////////////////////////
798
2d66e025
MB
799IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
800
801BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
802 EVT_PAINT( wxGridWindow::OnPaint )
803 EVT_SCROLLWIN( wxGridWindow::ScrollWindow )
804 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
805 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
806END_EVENT_TABLE()
807
60ff3b99
VZ
808wxGridWindow::wxGridWindow( wxGrid *parent,
809 wxGridRowLabelWindow *rowLblWin,
2d66e025
MB
810 wxGridColLabelWindow *colLblWin,
811 wxWindowID id, const wxPoint &pos, const wxSize &size )
812 : wxPanel( parent, id, pos, size, wxSUNKEN_BORDER, "grid window" )
813{
814 m_owner = parent;
815 m_rowLabelWin = rowLblWin;
816 m_colLabelWin = colLblWin;
60ff3b99 817
2d66e025
MB
818 SetBackgroundColour( "WHITE" );
819}
820
821
822wxGridWindow::~wxGridWindow()
823{
824}
825
826
827void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
828{
829 wxPaintDC dc( this );
830 m_owner->PrepareDC( dc );
831
832 m_owner->CalcCellsExposed( GetUpdateRegion() );
833 m_owner->DrawGridCellArea( dc );
834}
835
836
837void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
838{
839 wxPanel::ScrollWindow( dx, dy, rect );
840 m_rowLabelWin->ScrollWindow( 0, dy, rect );
841 m_colLabelWin->ScrollWindow( dx, 0, rect );
842}
843
844
845void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
846{
847 m_owner->ProcessGridCellMouseEvent( event );
848}
849
850
851// This seems to be required for wxMotif otherwise the mouse
852// cursor must be in the cell edit control to get key events
853//
854void wxGridWindow::OnKeyDown( wxKeyEvent& event )
855{
856 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
857}
f85afd4e 858
8f177c8e 859
2d66e025
MB
860
861//////////////////////////////////////////////////////////////////////
862
863IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
864
865BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
f85afd4e
MB
866 EVT_PAINT( wxGrid::OnPaint )
867 EVT_SIZE( wxGrid::OnSize )
f85afd4e 868 EVT_KEY_DOWN( wxGrid::OnKeyDown )
f85afd4e 869END_EVENT_TABLE()
8f177c8e 870
2d66e025
MB
871wxGrid::wxGrid( wxWindow *parent,
872 wxWindowID id,
873 const wxPoint& pos,
874 const wxSize& size,
875 long style,
876 const wxString& name )
877 : wxScrolledWindow( parent, id, pos, size, style, name )
878{
879 Create();
880
881 int colLblH = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
882 int rowLblW = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
883
60ff3b99
VZ
884 m_rowLabelWin = new wxGridRowLabelWindow( this,
885 -1,
886 wxDefaultPosition,
2d66e025
MB
887 wxSize(rowLblW,-1) );
888
889 m_colLabelWin = new wxGridColLabelWindow( this,
890 -1,
891 wxDefaultPosition,
892 wxSize(-1, colLblH ) );
60ff3b99 893
2d66e025
MB
894 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
895 -1,
896 wxDefaultPosition,
897 wxSize(rowLblW, colLblH ) );
60ff3b99
VZ
898
899 m_gridWin = new wxGridWindow( this,
900 m_rowLabelWin,
901 m_colLabelWin,
902 -1,
903 wxDefaultPosition,
2d66e025
MB
904 wxDefaultSize );
905
906 SetTargetWindow( m_gridWin );
60ff3b99 907
2d66e025 908 m_mainSizer = new wxBoxSizer( wxVERTICAL );
60ff3b99 909
2d66e025
MB
910 m_topSizer = new wxBoxSizer( wxHORIZONTAL );
911 m_topSizer->Add( m_cornerLabelWin, 0 );
912 m_topSizer->Add( m_colLabelWin, 1 );
60ff3b99 913
2d66e025 914 m_mainSizer->Add( m_topSizer, 0, wxEXPAND );
60ff3b99 915
2d66e025
MB
916 m_middleSizer = new wxBoxSizer( wxHORIZONTAL );
917 m_middleSizer->Add( m_rowLabelWin, 0, wxEXPAND );
918 m_middleSizer->Add( m_gridWin, 1, wxEXPAND );
60ff3b99 919
2d66e025
MB
920 m_mainSizer->Add( m_middleSizer, 1, wxEXPAND );
921
922 SetAutoLayout( TRUE );
923 SetSizer( m_mainSizer );
924}
f85afd4e
MB
925
926wxGrid::~wxGrid()
927{
928 delete m_table;
929}
930
931
932//
933// ----- internal init and update functions
934//
935
936void wxGrid::Create()
937{
938 m_table = (wxGridTableBase *) NULL;
2d66e025
MB
939 m_gridWin = (wxGridWindow *) NULL;
940 m_rowLabelWin = (wxGridRowLabelWindow *) NULL;
941 m_colLabelWin = (wxGridColLabelWindow *) NULL;
942 m_cornerLabelWin = (wxGridCornerLabelWindow *) NULL;
60ff3b99 943 m_cellEditCtrl = (wxWindow *) NULL;
2d66e025
MB
944}
945
946
947bool wxGrid::CreateGrid( int numRows, int numCols )
948{
949 if ( m_created )
950 {
951 wxLogError( wxT("wxGrid::CreateGrid(numRows, numCols) called more than once") );
952 return FALSE;
953 }
954 else
955 {
956 m_numRows = numRows;
957 m_numCols = numCols;
958
959 m_table = new wxGridStringTable( m_numRows, m_numCols );
960 m_table->SetView( this );
961 Init();
962 m_created = TRUE;
963 }
f85afd4e 964
2d66e025 965 return m_created;
f85afd4e
MB
966}
967
2d66e025 968
f85afd4e
MB
969void wxGrid::Init()
970{
971 int i;
972
f85afd4e
MB
973 if ( m_numRows <= 0 )
974 m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
975
976 if ( m_numCols <= 0 )
977 m_numCols = WXGRID_DEFAULT_NUMBER_COLS;
978
979 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
980 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
981
60ff3b99
VZ
982 if ( m_rowLabelWin )
983 {
984 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
985 }
986 else
987 {
988 m_labelBackgroundColour = wxColour( _T("WHITE") );
989 }
990
991 m_labelTextColour = wxColour( _T("BLACK") );
f85afd4e
MB
992
993 // TODO: something better than this ?
994 //
995 m_labelFont = this->GetFont();
996 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
8f177c8e 997
f85afd4e
MB
998 m_rowLabelHorizAlign = wxLEFT;
999 m_rowLabelVertAlign = wxCENTRE;
1000
1001 m_colLabelHorizAlign = wxCENTRE;
1002 m_colLabelVertAlign = wxTOP;
1003
f85afd4e 1004 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
1f1ce288
MB
1005 m_defaultRowHeight = m_gridWin->GetCharHeight();
1006
1007#if defined (__WXMOTIF__) // see also text ctrl sizing in ShowCellEditControl()
1008 m_defaultRowHeight += 8;
1009#else
1010 m_defaultRowHeight += 4;
1011#endif
1012
f85afd4e
MB
1013 m_rowHeights.Alloc( m_numRows );
1014 m_rowBottoms.Alloc( m_numRows );
2d66e025 1015 int rowBottom = 0;
f85afd4e
MB
1016 for ( i = 0; i < m_numRows; i++ )
1017 {
1018 m_rowHeights.Add( m_defaultRowHeight );
2d66e025
MB
1019 rowBottom += m_defaultRowHeight;
1020 m_rowBottoms.Add( rowBottom );
f85afd4e 1021 }
8f177c8e 1022
f85afd4e 1023 m_colWidths.Alloc( m_numCols );
2d66e025
MB
1024 m_colRights.Alloc( m_numCols );
1025 int colRight = 0;
f85afd4e
MB
1026 for ( i = 0; i < m_numCols; i++ )
1027 {
1028 m_colWidths.Add( m_defaultColWidth );
2d66e025
MB
1029 colRight += m_defaultColWidth;
1030 m_colRights.Add( colRight );
f85afd4e 1031 }
8f177c8e 1032
f85afd4e
MB
1033 // TODO: improve this ?
1034 //
1035 m_defaultCellFont = this->GetFont();
8f177c8e 1036
2d66e025 1037 m_gridLineColour = wxColour( 128, 128, 255 );
f85afd4e 1038 m_gridLinesEnabled = TRUE;
8f177c8e 1039
f85afd4e
MB
1040 m_cursorMode = WXGRID_CURSOR_DEFAULT;
1041 m_dragLastPos = -1;
1042 m_dragRowOrCol = -1;
1043 m_isDragging = FALSE;
1044
1045 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
1046 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
1047
1048 m_currentCellCoords = wxGridNoCellCoords;
f85afd4e
MB
1049
1050 m_selectedTopLeft = wxGridNoCellCoords;
1051 m_selectedBottomRight = wxGridNoCellCoords;
8f177c8e 1052
f85afd4e
MB
1053 m_editable = TRUE; // default for whole grid
1054
2d66e025
MB
1055 m_inOnKeyDown = FALSE;
1056 m_batchCount = 0;
1057
f85afd4e
MB
1058 // TODO: extend this to other types of controls
1059 //
2d66e025
MB
1060 m_cellEditCtrl = new wxGridTextCtrl( m_gridWin,
1061 this,
f85afd4e
MB
1062 TRUE,
1063 wxGRID_CELLCTRL,
1064 "",
1065 wxPoint(1,1),
edc2c290 1066 wxSize(1,1)
f85afd4e 1067#ifdef __WXMSW__
edc2c290 1068 , wxTE_MULTILINE | wxTE_NO_VSCROLL
f85afd4e
MB
1069#endif
1070 );
8f177c8e
VZ
1071
1072 m_cellEditCtrl->Show( FALSE );
f85afd4e 1073 m_cellEditCtrlEnabled = TRUE;
8f177c8e 1074 m_editCtrlType = wxGRID_TEXTCTRL;
f85afd4e
MB
1075}
1076
1077
1078void wxGrid::CalcDimensions()
1079{
f85afd4e 1080 int cw, ch;
2d66e025 1081 GetClientSize( &cw, &ch );
f85afd4e 1082
2d66e025 1083 if ( m_numRows > 0 && m_numCols > 0 )
f85afd4e 1084 {
2d66e025
MB
1085 int right = m_colRights[ m_numCols-1 ] + 20;
1086 int bottom = m_rowBottoms[ m_numRows-1 ] + 20;
60ff3b99 1087
2d66e025
MB
1088 // TODO: restore the scroll position that we had before sizing
1089 //
1090 int x, y;
1091 GetViewStart( &x, &y );
60ff3b99 1092 SetScrollbars( 10, 10,
2d66e025
MB
1093 right/10, bottom/10,
1094 x, y );
f85afd4e 1095 }
f85afd4e
MB
1096}
1097
1098
1099// this is called when the grid table sends a message to say that it
1100// has been redimensioned
1101//
1102bool wxGrid::Redimension( wxGridTableMessage& msg )
1103{
1104 int i;
8f177c8e 1105
f85afd4e
MB
1106 switch ( msg.GetId() )
1107 {
1108 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
1109 {
1110 size_t pos = msg.GetCommandInt();
1111 int numRows = msg.GetCommandInt2();
1112 for ( i = 0; i < numRows; i++ )
1113 {
1114 m_rowHeights.Insert( m_defaultRowHeight, pos );
1115 m_rowBottoms.Insert( 0, pos );
1116 }
1117 m_numRows += numRows;
2d66e025
MB
1118
1119 int bottom = 0;
1120 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
60ff3b99 1121
2d66e025
MB
1122 for ( i = pos; i < m_numRows; i++ )
1123 {
1124 bottom += m_rowHeights[i];
1125 m_rowBottoms[i] = bottom;
1126 }
f85afd4e
MB
1127 CalcDimensions();
1128 }
1129 return TRUE;
1130
1131 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
1132 {
1133 int numRows = msg.GetCommandInt();
1134 for ( i = 0; i < numRows; i++ )
1135 {
1136 m_rowHeights.Add( m_defaultRowHeight );
1137 m_rowBottoms.Add( 0 );
1138 }
2d66e025
MB
1139
1140 int oldNumRows = m_numRows;
f85afd4e 1141 m_numRows += numRows;
2d66e025
MB
1142
1143 int bottom = 0;
1144 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
60ff3b99 1145
2d66e025
MB
1146 for ( i = oldNumRows; i < m_numRows; i++ )
1147 {
1148 bottom += m_rowHeights[i];
1149 m_rowBottoms[i] = bottom;
1150 }
f85afd4e
MB
1151 CalcDimensions();
1152 }
1153 return TRUE;
1154
1155 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
1156 {
1157 size_t pos = msg.GetCommandInt();
1158 int numRows = msg.GetCommandInt2();
1159 for ( i = 0; i < numRows; i++ )
1160 {
1161 m_rowHeights.Remove( pos );
1162 m_rowBottoms.Remove( pos );
1163 }
1164 m_numRows -= numRows;
1165
f85afd4e
MB
1166 if ( !m_numRows )
1167 {
1168 m_numCols = 0;
1169 m_colWidths.Clear();
1170 m_colRights.Clear();
1171 m_currentCellCoords = wxGridNoCellCoords;
1172 }
2d66e025 1173 else
f85afd4e 1174 {
2d66e025
MB
1175 if ( m_currentCellCoords.GetRow() >= m_numRows )
1176 m_currentCellCoords.Set( 0, 0 );
1177
1178 int h = 0;
1179 for ( i = 0; i < m_numRows; i++ )
1180 {
1181 h += m_rowHeights[i];
1182 m_rowBottoms[i] = h;
1183 }
f85afd4e 1184 }
60ff3b99 1185
f85afd4e
MB
1186 CalcDimensions();
1187 }
1188 return TRUE;
1189
1190 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
1191 {
1192 size_t pos = msg.GetCommandInt();
1193 int numCols = msg.GetCommandInt2();
1194 for ( i = 0; i < numCols; i++ )
1195 {
1196 m_colWidths.Insert( m_defaultColWidth, pos );
1197 m_colRights.Insert( 0, pos );
1198 }
1199 m_numCols += numCols;
2d66e025
MB
1200
1201 int right = 0;
1202 if ( pos > 0 ) right = m_colRights[pos-1];
60ff3b99 1203
2d66e025
MB
1204 for ( i = pos; i < m_numCols; i++ )
1205 {
1206 right += m_colWidths[i];
1207 m_colRights[i] = right;
1208 }
f85afd4e
MB
1209 CalcDimensions();
1210 }
1211 return TRUE;
1212
1213 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
1214 {
1215 int numCols = msg.GetCommandInt();
1216 for ( i = 0; i < numCols; i++ )
1217 {
1218 m_colWidths.Add( m_defaultColWidth );
1219 m_colRights.Add( 0 );
1220 }
2d66e025
MB
1221
1222 int oldNumCols = m_numCols;
f85afd4e 1223 m_numCols += numCols;
2d66e025
MB
1224
1225 int right = 0;
1226 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
60ff3b99 1227
2d66e025
MB
1228 for ( i = oldNumCols; i < m_numCols; i++ )
1229 {
1230 right += m_colWidths[i];
1231 m_colRights[i] = right;
1232 }
f85afd4e
MB
1233 CalcDimensions();
1234 }
1235 return TRUE;
1236
1237 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
1238 {
1239 size_t pos = msg.GetCommandInt();
1240 int numCols = msg.GetCommandInt2();
1241 for ( i = 0; i < numCols; i++ )
1242 {
1243 m_colWidths.Remove( pos );
1244 m_colRights.Remove( pos );
1245 }
1246 m_numCols -= numCols;
f85afd4e
MB
1247
1248 if ( !m_numCols )
1249 {
1250#if 0 // leave the row alone here so that AppendCols will work subsequently
1251 m_numRows = 0;
1252 m_rowHeights.Clear();
1253 m_rowBottoms.Clear();
8f177c8e 1254#endif
f85afd4e
MB
1255 m_currentCellCoords = wxGridNoCellCoords;
1256 }
60ff3b99 1257 else
f85afd4e 1258 {
2d66e025
MB
1259 if ( m_currentCellCoords.GetCol() >= m_numCols )
1260 m_currentCellCoords.Set( 0, 0 );
1261
1262 int w = 0;
1263 for ( i = 0; i < m_numCols; i++ )
1264 {
1265 w += m_colWidths[i];
1266 m_colRights[i] = w;
1267 }
f85afd4e
MB
1268 }
1269 CalcDimensions();
1270 }
1271 return TRUE;
1272 }
1273
1274 return FALSE;
1275}
1276
1277
2d66e025 1278void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
f85afd4e 1279{
2d66e025
MB
1280 wxRegionIterator iter( reg );
1281 wxRect r;
f85afd4e 1282
2d66e025 1283 m_rowLabelsExposed.Empty();
f85afd4e 1284
2d66e025
MB
1285 int top, bottom;
1286 while ( iter )
f85afd4e 1287 {
2d66e025 1288 r = iter.GetRect();
f85afd4e 1289
2d66e025
MB
1290 // TODO: remove this when we can...
1291 // There is a bug in wxMotif that gives garbage update
1292 // rectangles if you jump-scroll a long way by clicking the
1293 // scrollbar with middle button. This is a work-around
1294 //
1295#if defined(__WXMOTIF__)
1296 int cw, ch;
1297 m_gridWin->GetClientSize( &cw, &ch );
1298 if ( r.GetTop() > ch ) r.SetTop( 0 );
1299 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1300#endif
f85afd4e 1301
2d66e025
MB
1302 // logical bounds of update region
1303 //
1304 int dummy;
1305 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
1306 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
1307
1308 // find the row labels within these bounds
1309 //
1310 int row;
1311 int rowTop;
1312 for ( row = 0; row < m_numRows; row++ )
1313 {
1314 if ( m_rowBottoms[row] < top ) continue;
1315
1316 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1317 if ( rowTop > bottom ) break;
60ff3b99 1318
2d66e025
MB
1319 m_rowLabelsExposed.Add( row );
1320 }
60ff3b99 1321
2d66e025 1322 iter++ ;
f85afd4e
MB
1323 }
1324}
1325
1326
2d66e025 1327void wxGrid::CalcColLabelsExposed( wxRegion& reg )
f85afd4e 1328{
2d66e025
MB
1329 wxRegionIterator iter( reg );
1330 wxRect r;
f85afd4e 1331
2d66e025 1332 m_colLabelsExposed.Empty();
f85afd4e 1333
2d66e025
MB
1334 int left, right;
1335 while ( iter )
f85afd4e 1336 {
2d66e025 1337 r = iter.GetRect();
f85afd4e 1338
2d66e025
MB
1339 // TODO: remove this when we can...
1340 // There is a bug in wxMotif that gives garbage update
1341 // rectangles if you jump-scroll a long way by clicking the
1342 // scrollbar with middle button. This is a work-around
1343 //
1344#if defined(__WXMOTIF__)
1345 int cw, ch;
1346 m_gridWin->GetClientSize( &cw, &ch );
1347 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1348 r.SetRight( wxMin( r.GetRight(), cw ) );
1349#endif
1350
1351 // logical bounds of update region
1352 //
1353 int dummy;
1354 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
1355 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
1356
1357 // find the cells within these bounds
1358 //
1359 int col;
1360 int colLeft;
1361 for ( col = 0; col < m_numCols; col++ )
1362 {
1363 if ( m_colRights[col] < left ) continue;
60ff3b99 1364
2d66e025
MB
1365 colLeft = m_colRights[col] - m_colWidths[col];
1366 if ( colLeft > right ) break;
1367
1368 m_colLabelsExposed.Add( col );
1369 }
60ff3b99 1370
2d66e025 1371 iter++ ;
f85afd4e
MB
1372 }
1373}
1374
1375
2d66e025 1376void wxGrid::CalcCellsExposed( wxRegion& reg )
f85afd4e 1377{
2d66e025
MB
1378 wxRegionIterator iter( reg );
1379 wxRect r;
f85afd4e 1380
2d66e025
MB
1381 m_cellsExposed.Empty();
1382 m_rowsExposed.Empty();
1383 m_colsExposed.Empty();
f85afd4e 1384
2d66e025
MB
1385 int left, top, right, bottom;
1386 while ( iter )
1387 {
1388 r = iter.GetRect();
f85afd4e 1389
2d66e025
MB
1390 // TODO: remove this when we can...
1391 // There is a bug in wxMotif that gives garbage update
1392 // rectangles if you jump-scroll a long way by clicking the
1393 // scrollbar with middle button. This is a work-around
1394 //
1395#if defined(__WXMOTIF__)
f85afd4e 1396 int cw, ch;
2d66e025
MB
1397 m_gridWin->GetClientSize( &cw, &ch );
1398 if ( r.GetTop() > ch ) r.SetTop( 0 );
1399 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1400 r.SetRight( wxMin( r.GetRight(), cw ) );
1401 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1402#endif
8f177c8e 1403
2d66e025
MB
1404 // logical bounds of update region
1405 //
1406 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
1407 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
f85afd4e 1408
2d66e025 1409 // find the cells within these bounds
f85afd4e 1410 //
2d66e025
MB
1411 int row, col;
1412 int colLeft, rowTop;
1413 for ( row = 0; row < m_numRows; row++ )
f85afd4e 1414 {
2d66e025 1415 if ( m_rowBottoms[row] < top ) continue;
f85afd4e 1416
2d66e025
MB
1417 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1418 if ( rowTop > bottom ) break;
60ff3b99 1419
2d66e025 1420 m_rowsExposed.Add( row );
f85afd4e 1421
2d66e025
MB
1422 for ( col = 0; col < m_numCols; col++ )
1423 {
1424 if ( m_colRights[col] < left ) continue;
60ff3b99 1425
2d66e025
MB
1426 colLeft = m_colRights[col] - m_colWidths[col];
1427 if ( colLeft > right ) break;
60ff3b99 1428
2d66e025
MB
1429 if ( m_colsExposed.Index( col ) == wxNOT_FOUND ) m_colsExposed.Add( col );
1430 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
1431 }
1432 }
60ff3b99 1433
2d66e025 1434 iter++ ;
f85afd4e
MB
1435 }
1436}
1437
1438
2d66e025 1439void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
f85afd4e 1440{
2d66e025
MB
1441 int x, y, row;
1442 wxPoint pos( event.GetPosition() );
1443 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 1444
2d66e025 1445 if ( event.Dragging() )
f85afd4e
MB
1446 {
1447 m_isDragging = TRUE;
8f177c8e 1448
2d66e025 1449 if ( event.LeftIsDown() )
f85afd4e
MB
1450 {
1451 switch( m_cursorMode )
1452 {
f85afd4e
MB
1453 case WXGRID_CURSOR_RESIZE_ROW:
1454 {
2d66e025
MB
1455 int cw, ch, left, dummy;
1456 m_gridWin->GetClientSize( &cw, &ch );
1457 CalcUnscrolledPosition( 0, 0, &left, &dummy );
60ff3b99 1458
2d66e025
MB
1459 wxClientDC dc( m_gridWin );
1460 PrepareDC( dc );
f85afd4e
MB
1461 dc.SetLogicalFunction(wxXOR);
1462 if ( m_dragLastPos >= 0 )
1463 {
2d66e025 1464 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
f85afd4e 1465 }
2d66e025
MB
1466 dc.DrawLine( left, y, left+cw, y );
1467 m_dragLastPos = y;
f85afd4e
MB
1468 }
1469 break;
1470
1471 case WXGRID_CURSOR_SELECT_ROW:
1472 {
1473 if ( (row = YToRow( y )) >= 0 &&
1474 !IsInSelection( row, 0 ) )
1475 {
1476 SelectRow( row, TRUE );
1477 }
1478 }
1479 break;
f85afd4e
MB
1480 }
1481 }
1482 return;
1483 }
1484
1485 m_isDragging = FALSE;
8f177c8e 1486
60ff3b99 1487
2d66e025 1488 // ------------ Left button pressed
f85afd4e 1489 //
2d66e025 1490 if ( event.LeftDown() )
f85afd4e 1491 {
2d66e025
MB
1492 // don't send a label click event for a hit on the
1493 // edge of the row label - this is probably the user
1494 // wanting to resize the row
1495 //
1496 if ( YToEdgeOfRow(y) < 0 )
f85afd4e 1497 {
2d66e025
MB
1498 row = YToRow(y);
1499 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
f85afd4e 1500 {
2d66e025
MB
1501 SelectRow( row, event.ShiftDown() );
1502 m_cursorMode = WXGRID_CURSOR_SELECT_ROW;
f85afd4e 1503 }
2d66e025
MB
1504 }
1505 else
1506 {
1507 // starting to drag-resize a row
1508 //
1509 m_rowLabelWin->CaptureMouse();
1510 }
1511 }
f85afd4e 1512
f85afd4e 1513
2d66e025
MB
1514 // ------------ Left double click
1515 //
1516 else if (event.LeftDClick() )
1517 {
1518 if ( YToEdgeOfRow(y) < 0 )
1519 {
1520 row = YToRow(y);
1521 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
f85afd4e
MB
1522 }
1523 }
60ff3b99
VZ
1524
1525
2d66e025 1526 // ------------ Left button released
f85afd4e 1527 //
2d66e025 1528 else if ( event.LeftUp() )
f85afd4e 1529 {
2d66e025 1530 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
f85afd4e 1531 {
2d66e025 1532 m_rowLabelWin->ReleaseMouse();
60ff3b99 1533
2d66e025 1534 if ( m_dragLastPos >= 0 )
f85afd4e 1535 {
2d66e025 1536 // erase the last line and resize the row
f85afd4e 1537 //
2d66e025
MB
1538 int cw, ch, left, dummy;
1539 m_gridWin->GetClientSize( &cw, &ch );
1540 CalcUnscrolledPosition( 0, 0, &left, &dummy );
60ff3b99 1541
2d66e025
MB
1542 wxClientDC dc( m_gridWin );
1543 PrepareDC( dc );
1544 dc.SetLogicalFunction( wxINVERT );
1545 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
1546 HideCellEditControl();
1547
1548 int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
60ff3b99 1549 SetRowSize( m_dragRowOrCol, wxMax( y - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
2d66e025 1550 if ( !GetBatchCount() )
f85afd4e 1551 {
2d66e025
MB
1552 // TODO: optimize this
1553 m_rowLabelWin->Refresh();
1554 m_gridWin->Refresh();
f85afd4e 1555 }
60ff3b99 1556
2d66e025 1557 ShowCellEditControl();
f85afd4e 1558
2d66e025
MB
1559 // Note: we are ending the event *after* doing
1560 // default processing in this case
f85afd4e 1561 //
2d66e025 1562 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
f85afd4e 1563 }
2d66e025 1564 }
f85afd4e 1565
2d66e025
MB
1566 m_dragLastPos = -1;
1567 }
f85afd4e 1568
f85afd4e 1569
2d66e025
MB
1570 // ------------ Right button down
1571 //
1572 else if ( event.RightDown() )
1573 {
1574 row = YToRow(y);
1575 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
1576 {
1577 // no default action at the moment
f85afd4e
MB
1578 }
1579 }
60ff3b99
VZ
1580
1581
2d66e025 1582 // ------------ Right double click
f85afd4e 1583 //
2d66e025
MB
1584 else if ( event.RightDClick() )
1585 {
1586 row = YToRow(y);
1587 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
1588 {
1589 // no default action at the moment
1590 }
1591 }
60ff3b99
VZ
1592
1593
2d66e025 1594 // ------------ No buttons down and mouse moving
f85afd4e 1595 //
2d66e025 1596 else if ( event.Moving() )
f85afd4e 1597 {
2d66e025
MB
1598 m_dragRowOrCol = YToEdgeOfRow( y );
1599 if ( m_dragRowOrCol >= 0 )
8f177c8e 1600 {
2d66e025 1601 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
8f177c8e 1602 {
2d66e025
MB
1603 m_cursorMode = WXGRID_CURSOR_RESIZE_ROW;
1604 m_rowLabelWin->SetCursor( m_rowResizeCursor );
8f177c8e 1605 }
2d66e025
MB
1606 }
1607 else
1608 {
1609 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
8f177c8e 1610 {
2d66e025
MB
1611 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1612 m_rowLabelWin->SetCursor( *wxSTANDARD_CURSOR );
8f177c8e 1613 }
8f177c8e 1614 }
f85afd4e 1615 }
2d66e025
MB
1616}
1617
1618
1619void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
1620{
1621 int x, y, col;
1622 wxPoint pos( event.GetPosition() );
1623 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 1624
2d66e025 1625 if ( event.Dragging() )
f85afd4e 1626 {
2d66e025 1627 m_isDragging = TRUE;
8f177c8e 1628
2d66e025 1629 if ( event.LeftIsDown() )
8f177c8e 1630 {
2d66e025 1631 switch( m_cursorMode )
8f177c8e 1632 {
2d66e025 1633 case WXGRID_CURSOR_RESIZE_COL:
8f177c8e 1634 {
2d66e025
MB
1635 int cw, ch, dummy, top;
1636 m_gridWin->GetClientSize( &cw, &ch );
1637 CalcUnscrolledPosition( 0, 0, &dummy, &top );
60ff3b99 1638
2d66e025
MB
1639 wxClientDC dc( m_gridWin );
1640 PrepareDC( dc );
1641 dc.SetLogicalFunction(wxXOR);
1642 if ( m_dragLastPos >= 0 )
1643 {
1644 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
1645 }
1646 dc.DrawLine( x, top, x, top+ch );
1647 m_dragLastPos = x;
f85afd4e 1648 }
2d66e025 1649 break;
f85afd4e 1650
2d66e025 1651 case WXGRID_CURSOR_SELECT_COL:
f85afd4e 1652 {
2d66e025
MB
1653 if ( (col = XToCol( x )) >= 0 &&
1654 !IsInSelection( 0, col ) )
1655 {
1656 SelectCol( col, TRUE );
1657 }
f85afd4e 1658 }
f85afd4e 1659 break;
2d66e025 1660 }
f85afd4e 1661 }
2d66e025 1662 return;
f85afd4e 1663 }
2d66e025
MB
1664
1665 m_isDragging = FALSE;
1666
60ff3b99 1667
2d66e025 1668 // ------------ Left button pressed
f85afd4e 1669 //
2d66e025 1670 if ( event.LeftDown() )
f85afd4e 1671 {
2d66e025
MB
1672 // don't send a label click event for a hit on the
1673 // edge of the col label - this is probably the user
1674 // wanting to resize the col
1675 //
1676 if ( XToEdgeOfCol(x) < 0 )
8f177c8e 1677 {
2d66e025
MB
1678 col = XToCol(x);
1679 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
8f177c8e 1680 {
2d66e025
MB
1681 SelectCol( col, event.ShiftDown() );
1682 m_cursorMode = WXGRID_CURSOR_SELECT_COL;
f85afd4e 1683 }
2d66e025
MB
1684 }
1685 else
1686 {
1687 // starting to drag-resize a col
1688 //
1689 m_colLabelWin->CaptureMouse();
1690 }
1691 }
f85afd4e 1692
f85afd4e 1693
2d66e025
MB
1694 // ------------ Left double click
1695 //
1696 if ( event.LeftDClick() )
1697 {
1698 if ( XToEdgeOfCol(x) < 0 )
1699 {
1700 col = XToCol(x);
1701 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
1702 }
1703 }
60ff3b99
VZ
1704
1705
2d66e025
MB
1706 // ------------ Left button released
1707 //
1708 else if ( event.LeftUp() )
1709 {
1710 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
1711 {
1712 m_colLabelWin->ReleaseMouse();
60ff3b99 1713
2d66e025 1714 if ( m_dragLastPos >= 0 )
f85afd4e 1715 {
2d66e025 1716 // erase the last line and resize the col
f85afd4e 1717 //
2d66e025
MB
1718 int cw, ch, dummy, top;
1719 m_gridWin->GetClientSize( &cw, &ch );
1720 CalcUnscrolledPosition( 0, 0, &dummy, &top );
60ff3b99 1721
2d66e025
MB
1722 wxClientDC dc( m_gridWin );
1723 PrepareDC( dc );
1724 dc.SetLogicalFunction( wxINVERT );
1725 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
1726 HideCellEditControl();
1727
1728 int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
60ff3b99
VZ
1729 SetColSize( m_dragRowOrCol, wxMax( x - colLeft, WXGRID_MIN_COL_WIDTH ) );
1730
2d66e025
MB
1731 if ( !GetBatchCount() )
1732 {
1733 // TODO: optimize this
1734 m_colLabelWin->Refresh();
1735 m_gridWin->Refresh();
1736 }
60ff3b99 1737
2d66e025 1738 ShowCellEditControl();
f85afd4e 1739
2d66e025
MB
1740 // Note: we are ending the event *after* doing
1741 // default processing in this case
1742 //
1743 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
f85afd4e 1744 }
2d66e025 1745 }
f85afd4e 1746
2d66e025 1747 m_dragLastPos = -1;
60ff3b99
VZ
1748 }
1749
1750
2d66e025
MB
1751 // ------------ Right button down
1752 //
1753 else if ( event.RightDown() )
1754 {
1755 col = XToCol(x);
1756 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
1757 {
1758 // no default action at the moment
f85afd4e
MB
1759 }
1760 }
60ff3b99
VZ
1761
1762
2d66e025 1763 // ------------ Right double click
f85afd4e 1764 //
2d66e025
MB
1765 else if ( event.RightDClick() )
1766 {
1767 col = XToCol(x);
1768 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
1769 {
1770 // no default action at the moment
1771 }
1772 }
60ff3b99
VZ
1773
1774
2d66e025 1775 // ------------ No buttons down and mouse moving
f85afd4e 1776 //
2d66e025 1777 else if ( event.Moving() )
f85afd4e 1778 {
2d66e025
MB
1779 m_dragRowOrCol = XToEdgeOfCol( x );
1780 if ( m_dragRowOrCol >= 0 )
f85afd4e 1781 {
2d66e025 1782 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 1783 {
2d66e025
MB
1784 m_cursorMode = WXGRID_CURSOR_RESIZE_COL;
1785 m_colLabelWin->SetCursor( m_colResizeCursor );
f85afd4e 1786 }
2d66e025
MB
1787 }
1788 else
1789 {
1790 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
f85afd4e 1791 {
2d66e025
MB
1792 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1793 m_colLabelWin->SetCursor( *wxSTANDARD_CURSOR );
f85afd4e 1794 }
8f177c8e 1795 }
f85afd4e
MB
1796 }
1797}
1798
1799
2d66e025 1800void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
f85afd4e 1801{
2d66e025 1802 if ( event.LeftDown() )
f85afd4e 1803 {
2d66e025
MB
1804 // indicate corner label by having both row and
1805 // col args == -1
f85afd4e 1806 //
2d66e025
MB
1807 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
1808 {
1809 SelectAll();
1810 }
f85afd4e
MB
1811 }
1812
2d66e025
MB
1813 else if ( event.LeftDClick() )
1814 {
1815 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
1816 }
8f177c8e 1817
2d66e025 1818 else if ( event.RightDown() )
f85afd4e 1819 {
2d66e025 1820 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
f85afd4e 1821 {
2d66e025
MB
1822 // no default action at the moment
1823 }
1824 }
f85afd4e 1825
2d66e025
MB
1826 else if ( event.RightDClick() )
1827 {
1828 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
1829 {
1830 // no default action at the moment
1831 }
1832 }
1833}
f85afd4e 1834
8f177c8e 1835
2d66e025
MB
1836void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
1837{
1838 int x, y;
1839 wxPoint pos( event.GetPosition() );
1840 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 1841
2d66e025
MB
1842 wxGridCellCoords coords;
1843 XYToCell( x, y, coords );
60ff3b99 1844
2d66e025
MB
1845 if ( event.Dragging() )
1846 {
1847 m_isDragging = TRUE;
2d66e025
MB
1848 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
1849 {
da6af900
SN
1850 // Hide the edit control, so it
1851 // won't interfer with drag-shrinking.
1852 if ( IsCellEditControlEnabled() )
1853 HideCellEditControl();
2d66e025
MB
1854 if ( coords != wxGridNoCellCoords )
1855 {
1856 if ( !IsSelection() )
f85afd4e 1857 {
2d66e025 1858 SelectBlock( coords, coords );
f85afd4e
MB
1859 }
1860 else
1861 {
da6af900 1862 SelectBlock( m_currentCellCoords, coords );
f85afd4e 1863 }
2d66e025
MB
1864 }
1865 }
8f177c8e 1866
2d66e025
MB
1867 return;
1868 }
66242c80 1869
2d66e025 1870 m_isDragging = FALSE;
8f177c8e 1871
2d66e025
MB
1872 if ( event.LeftDown() )
1873 {
1874 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
1875 coords.GetRow(),
1876 coords.GetCol(),
1877 event ) )
1878 {
1879 MakeCellVisible( coords );
1880 SetCurrentCell( coords );
f85afd4e
MB
1881 }
1882 }
1883
f85afd4e 1884
2d66e025
MB
1885 // ------------ Left double click
1886 //
1887 else if ( event.LeftDClick() )
f85afd4e 1888 {
2d66e025
MB
1889 SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
1890 coords.GetRow(),
1891 coords.GetCol(),
1892 event );
1893 }
f85afd4e 1894
8f177c8e 1895
2d66e025
MB
1896 // ------------ Left button released
1897 //
1898 else if ( event.LeftUp() )
1899 {
1900 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 1901 {
2d66e025 1902 if ( IsSelection() )
52068ea5 1903 {
2d66e025 1904 SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
f85afd4e 1905 }
da6af900
SN
1906 // Show the edit control, if it has
1907 // been hidden for drag-shrinking.
1908 if ( IsCellEditControlEnabled() )
1909 ShowCellEditControl();
f85afd4e 1910 }
2d66e025
MB
1911
1912 m_dragLastPos = -1;
f85afd4e
MB
1913 }
1914
f85afd4e 1915
2d66e025 1916 // ------------ Right button down
f85afd4e 1917 //
2d66e025 1918 else if ( event.RightDown() )
f85afd4e 1919 {
2d66e025
MB
1920 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
1921 coords.GetRow(),
1922 coords.GetCol(),
1923 event ) )
f85afd4e 1924 {
2d66e025 1925 // no default action at the moment
60ff3b99 1926 }
f85afd4e 1927 }
2d66e025 1928
60ff3b99 1929
2d66e025
MB
1930 // ------------ Right double click
1931 //
1932 else if ( event.RightDClick() )
f85afd4e 1933 {
2d66e025
MB
1934 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
1935 coords.GetRow(),
1936 coords.GetCol(),
1937 event ) )
f85afd4e 1938 {
2d66e025 1939 // no default action at the moment
60ff3b99 1940 }
f85afd4e 1941 }
f85afd4e
MB
1942}
1943
1944
2d66e025
MB
1945//
1946// ------ interaction with data model
1947//
1948bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
f85afd4e 1949{
2d66e025 1950 switch ( msg.GetId() )
17732cec 1951 {
2d66e025
MB
1952 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
1953 return GetModelValues();
17732cec 1954
2d66e025
MB
1955 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
1956 return SetModelValues();
f85afd4e 1957
2d66e025
MB
1958 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
1959 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
1960 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
1961 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
1962 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
1963 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
1964 return Redimension( msg );
1965
1966 default:
1967 return FALSE;
f85afd4e 1968 }
2d66e025 1969}
f85afd4e 1970
f85afd4e 1971
f85afd4e 1972
2d66e025
MB
1973// The behaviour of this function depends on the grid table class
1974// Clear() function. For the default wxGridStringTable class the
1975// behavious is to replace all cell contents with wxEmptyString but
1976// not to change the number of rows or cols.
1977//
1978void wxGrid::ClearGrid()
1979{
1980 if ( m_table )
f85afd4e 1981 {
2d66e025
MB
1982 m_table->Clear();
1983 SetEditControlValue();
1f1ce288 1984 if ( !GetBatchCount() ) m_gridWin->Refresh();
f85afd4e
MB
1985 }
1986}
1987
1988
2d66e025 1989bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 1990{
2d66e025 1991 // TODO: something with updateLabels flag
8f177c8e 1992
2d66e025 1993 if ( !m_created )
f85afd4e 1994 {
2d66e025
MB
1995 wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
1996 return FALSE;
1997 }
8f177c8e 1998
2d66e025
MB
1999 if ( m_table )
2000 {
2001 bool ok = m_table->InsertRows( pos, numRows );
f85afd4e 2002
2d66e025
MB
2003 // the table will have sent the results of the insert row
2004 // operation to this view object as a grid table message
2005 //
2006 if ( ok )
2007 {
2008 if ( m_numCols == 0 )
f85afd4e 2009 {
2d66e025
MB
2010 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
2011 //
2012 // TODO: perhaps instead of appending the default number of cols
2013 // we should remember what the last non-zero number of cols was ?
2014 //
2015 }
8f177c8e 2016
2d66e025
MB
2017 if ( m_currentCellCoords == wxGridNoCellCoords )
2018 {
2019 // if we have just inserted cols into an empty grid the current
2020 // cell will be undefined...
2021 //
2022 SetCurrentCell( 0, 0 );
f85afd4e
MB
2023 }
2024
2d66e025
MB
2025 ClearSelection();
2026 if ( !GetBatchCount() ) Refresh();
f85afd4e 2027 }
2d66e025
MB
2028
2029 SetEditControlValue();
2030 return ok;
2031 }
2032 else
2033 {
2034 return FALSE;
f85afd4e
MB
2035 }
2036}
2037
2038
2d66e025 2039bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 2040{
2d66e025
MB
2041 // TODO: something with updateLabels flag
2042
2043 if ( !m_created )
f85afd4e 2044 {
2d66e025
MB
2045 wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2046 return FALSE;
2047 }
2048
2049 if ( m_table && m_table->AppendRows( numRows ) )
2050 {
2051 if ( m_currentCellCoords == wxGridNoCellCoords )
2052 {
2053 // if we have just inserted cols into an empty grid the current
2054 // cell will be undefined...
2055 //
2056 SetCurrentCell( 0, 0 );
2057 }
2058
2059 // the table will have sent the results of the append row
2060 // operation to this view object as a grid table message
2061 //
2062 ClearSelection();
2063 if ( !GetBatchCount() ) Refresh();
2064 return TRUE;
2065 }
2066 else
2067 {
2068 return FALSE;
f85afd4e
MB
2069 }
2070}
2071
2d66e025
MB
2072
2073bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 2074{
2d66e025
MB
2075 // TODO: something with updateLabels flag
2076
2077 if ( !m_created )
f85afd4e 2078 {
2d66e025
MB
2079 wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2080 return FALSE;
2081 }
2082
2083 if ( m_table && m_table->DeleteRows( pos, numRows ) )
2084 {
2085 // the table will have sent the results of the delete row
2086 // operation to this view object as a grid table message
2087 //
2088 if ( m_numRows > 0 )
2089 SetEditControlValue();
2b37dc19 2090 else
2d66e025 2091 HideCellEditControl();
f85afd4e 2092
2d66e025
MB
2093 ClearSelection();
2094 if ( !GetBatchCount() ) Refresh();
2095 return TRUE;
2096 }
2097 else
2098 {
2099 return FALSE;
2100 }
2101}
f85afd4e 2102
f85afd4e 2103
2d66e025
MB
2104bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2105{
2106 // TODO: something with updateLabels flag
8f177c8e 2107
2d66e025
MB
2108 if ( !m_created )
2109 {
2110 wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2111 return FALSE;
2112 }
f85afd4e 2113
2d66e025
MB
2114 if ( m_table )
2115 {
2116 HideCellEditControl();
2117 bool ok = m_table->InsertCols( pos, numCols );
2118
2119 // the table will have sent the results of the insert col
2120 // operation to this view object as a grid table message
2121 //
2122 if ( ok )
f85afd4e 2123 {
2d66e025 2124 if ( m_currentCellCoords == wxGridNoCellCoords )
f85afd4e 2125 {
2d66e025
MB
2126 // if we have just inserted cols into an empty grid the current
2127 // cell will be undefined...
2128 //
2129 SetCurrentCell( 0, 0 );
f85afd4e 2130 }
2d66e025
MB
2131
2132 ClearSelection();
2133 if ( !GetBatchCount() ) Refresh();
f85afd4e 2134 }
2d66e025
MB
2135
2136 SetEditControlValue();
2137 return ok;
2138 }
2139 else
2140 {
2141 return FALSE;
f85afd4e
MB
2142 }
2143}
2144
2d66e025
MB
2145
2146bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 2147{
2d66e025
MB
2148 // TODO: something with updateLabels flag
2149
2150 if ( !m_created )
f85afd4e 2151 {
2d66e025
MB
2152 wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2153 return FALSE;
2154 }
f85afd4e 2155
2d66e025
MB
2156 if ( m_table && m_table->AppendCols( numCols ) )
2157 {
2158 // the table will have sent the results of the append col
2159 // operation to this view object as a grid table message
2160 //
2161 if ( m_currentCellCoords == wxGridNoCellCoords )
f85afd4e 2162 {
2d66e025
MB
2163 // if we have just inserted cols into an empty grid the current
2164 // cell will be undefined...
2165 //
2166 SetCurrentCell( 0, 0 );
f85afd4e 2167 }
8f177c8e 2168
2d66e025
MB
2169 ClearSelection();
2170 if ( !GetBatchCount() ) Refresh();
2171 return TRUE;
f85afd4e 2172 }
2d66e025 2173 else
f85afd4e 2174 {
2d66e025 2175 return FALSE;
f85afd4e 2176 }
f85afd4e
MB
2177}
2178
2179
2d66e025 2180bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 2181{
2d66e025 2182 // TODO: something with updateLabels flag
8f177c8e 2183
2d66e025 2184 if ( !m_created )
f85afd4e 2185 {
2d66e025
MB
2186 wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2187 return FALSE;
f85afd4e
MB
2188 }
2189
2d66e025
MB
2190 if ( m_table && m_table->DeleteCols( pos, numCols ) )
2191 {
2192 // the table will have sent the results of the delete col
2193 // operation to this view object as a grid table message
2194 //
2195 if ( m_numCols > 0 )
2196 SetEditControlValue();
2197 else
2198 HideCellEditControl();
8f177c8e 2199
2d66e025
MB
2200 ClearSelection();
2201 if ( !GetBatchCount() ) Refresh();
2202 return TRUE;
2203 }
2204 else
f85afd4e 2205 {
2d66e025 2206 return FALSE;
f85afd4e 2207 }
f85afd4e
MB
2208}
2209
2210
2d66e025
MB
2211
2212//
2213// ----- event handlers
f85afd4e 2214//
8f177c8e 2215
2d66e025
MB
2216// Generate a grid event based on a mouse event and
2217// return the result of ProcessEvent()
2218//
2219bool wxGrid::SendEvent( const wxEventType type,
2220 int row, int col,
2221 wxMouseEvent& mouseEv )
2222{
2223 if ( type == EVT_GRID_ROW_SIZE ||
2224 type == EVT_GRID_COL_SIZE )
f85afd4e 2225 {
2d66e025
MB
2226 int rowOrCol = (row == -1 ? col : row);
2227
2228 wxGridSizeEvent gridEvt( GetId(),
2229 type,
2230 this,
2231 rowOrCol,
2232 mouseEv.GetX(), mouseEv.GetY(),
2233 mouseEv.ControlDown(),
2234 mouseEv.ShiftDown(),
2235 mouseEv.AltDown(),
2236 mouseEv.MetaDown() );
2237
2238 return GetEventHandler()->ProcessEvent(gridEvt);
f85afd4e 2239 }
2d66e025
MB
2240 else if ( type == EVT_GRID_RANGE_SELECT )
2241 {
2242 wxGridRangeSelectEvent gridEvt( GetId(),
2243 type,
2244 this,
2245 m_selectedTopLeft,
2246 m_selectedBottomRight,
2247 mouseEv.ControlDown(),
2248 mouseEv.ShiftDown(),
2249 mouseEv.AltDown(),
2250 mouseEv.MetaDown() );
f85afd4e 2251
2d66e025
MB
2252 return GetEventHandler()->ProcessEvent(gridEvt);
2253 }
2254 else
2255 {
2256 wxGridEvent gridEvt( GetId(),
2257 type,
2258 this,
2259 row, col,
2260 mouseEv.GetX(), mouseEv.GetY(),
2261 mouseEv.ControlDown(),
2262 mouseEv.ShiftDown(),
2263 mouseEv.AltDown(),
2264 mouseEv.MetaDown() );
8f177c8e 2265
2d66e025
MB
2266 return GetEventHandler()->ProcessEvent(gridEvt);
2267 }
f85afd4e
MB
2268}
2269
2270
2d66e025
MB
2271// Generate a grid event of specified type and return the result
2272// of ProcessEvent().
f85afd4e 2273//
2d66e025
MB
2274bool wxGrid::SendEvent( const wxEventType type,
2275 int row, int col )
f85afd4e 2276{
2d66e025
MB
2277 if ( type == EVT_GRID_ROW_SIZE ||
2278 type == EVT_GRID_COL_SIZE )
f85afd4e 2279 {
2d66e025 2280 int rowOrCol = (row == -1 ? col : row);
f85afd4e 2281
2d66e025
MB
2282 wxGridSizeEvent gridEvt( GetId(),
2283 type,
2284 this,
2285 rowOrCol );
2286
2287 return GetEventHandler()->ProcessEvent(gridEvt);
2288 }
2289 else
2290 {
2291 wxGridEvent gridEvt( GetId(),
2292 type,
2293 this,
2294 row, col );
8f177c8e 2295
2d66e025
MB
2296 return GetEventHandler()->ProcessEvent(gridEvt);
2297 }
f85afd4e
MB
2298}
2299
2300
2d66e025 2301void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
f85afd4e 2302{
2d66e025 2303 wxPaintDC dc( this );
f85afd4e 2304
2d66e025
MB
2305 if ( m_currentCellCoords == wxGridNoCellCoords &&
2306 m_numRows && m_numCols )
f85afd4e 2307 {
2d66e025
MB
2308 m_currentCellCoords.Set(0, 0);
2309 SetEditControlValue();
2310 ShowCellEditControl();
f85afd4e 2311 }
8f177c8e 2312}
f85afd4e
MB
2313
2314
2d66e025
MB
2315// This is just here to make sure that CalcDimensions gets called when
2316// the grid view is resized... then the size event is skipped to allow
2317// the box sizers to handle everything
2318//
2319void wxGrid::OnSize( wxSizeEvent& event )
f85afd4e 2320{
2d66e025
MB
2321 CalcDimensions();
2322 event.Skip();
f85afd4e
MB
2323}
2324
f85afd4e 2325
2d66e025 2326void wxGrid::OnKeyDown( wxKeyEvent& event )
f85afd4e 2327{
2d66e025 2328 if ( m_inOnKeyDown )
f85afd4e 2329 {
2d66e025
MB
2330 // shouldn't be here - we are going round in circles...
2331 //
2332 wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") );
f85afd4e
MB
2333 }
2334
2d66e025 2335 m_inOnKeyDown = TRUE;
f85afd4e 2336
2d66e025
MB
2337 // propagate the event up and see if it gets processed
2338 //
2339 wxWindow *parent = GetParent();
2340 wxKeyEvent keyEvt( event );
2341 keyEvt.SetEventObject( parent );
2342
2343 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
f85afd4e 2344 {
2d66e025
MB
2345 // try local handlers
2346 //
2347 switch ( event.KeyCode() )
2348 {
2349 case WXK_UP:
2350 if ( event.ControlDown() )
2351 {
2352 MoveCursorUpBlock();
2353 }
2354 else
2355 {
2356 MoveCursorUp();
2357 }
2358 break;
f85afd4e 2359
2d66e025
MB
2360 case WXK_DOWN:
2361 if ( event.ControlDown() )
2362 {
2363 MoveCursorDownBlock();
2364 }
2365 else
2366 {
2367 MoveCursorDown();
2368 }
2369 break;
8f177c8e 2370
2d66e025
MB
2371 case WXK_LEFT:
2372 if ( event.ControlDown() )
2373 {
2374 MoveCursorLeftBlock();
2375 }
2376 else
2377 {
2378 MoveCursorLeft();
2379 }
2380 break;
2381
2382 case WXK_RIGHT:
2383 if ( event.ControlDown() )
2384 {
2385 MoveCursorRightBlock();
2386 }
2387 else
2388 {
2389 MoveCursorRight();
2390 }
2391 break;
2392
2393 case WXK_RETURN:
2394 MoveCursorDown();
2395 break;
2396
2397 case WXK_HOME:
2398 if ( event.ControlDown() )
2399 {
2400 MakeCellVisible( 0, 0 );
2401 SetCurrentCell( 0, 0 );
2402 }
2403 else
2404 {
2405 event.Skip();
2406 }
2407 break;
2408
2409 case WXK_END:
2410 if ( event.ControlDown() )
2411 {
2412 MakeCellVisible( m_numRows-1, m_numCols-1 );
2413 SetCurrentCell( m_numRows-1, m_numCols-1 );
2414 }
2415 else
2416 {
2417 event.Skip();
2418 }
2419 break;
2420
2421 case WXK_PRIOR:
2422 MovePageUp();
2423 break;
2424
2425 case WXK_NEXT:
2426 MovePageDown();
2427 break;
2428
2429 default:
2430 // now try the cell edit control
2431 //
2432 if ( IsCellEditControlEnabled() )
2433 {
2434 event.SetEventObject( m_cellEditCtrl );
2435 m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
2436 }
2437 break;
2438 }
f85afd4e
MB
2439 }
2440
2d66e025 2441 m_inOnKeyDown = FALSE;
f85afd4e
MB
2442}
2443
2d66e025
MB
2444
2445void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
66242c80 2446{
2d66e025 2447 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
66242c80 2448 {
2d66e025
MB
2449 // the event has been intercepted - do nothing
2450 return;
2451 }
66242c80 2452
2d66e025
MB
2453 wxClientDC dc( m_gridWin );
2454 PrepareDC( dc );
2455
2456 if ( m_currentCellCoords != wxGridNoCellCoords )
2457 {
2d66e025
MB
2458 HideCellEditControl();
2459 SaveEditControlValue();
66242c80 2460 }
8f177c8e 2461
2d66e025
MB
2462 m_currentCellCoords = coords;
2463
2464 SetEditControlValue();
2465 ShowCellEditControl();
2d66e025
MB
2466
2467 if ( IsSelection() )
2468 {
2469 wxRect r( SelectionToDeviceRect() );
2470 ClearSelection();
2471 if ( !GetBatchCount() ) m_gridWin->Refresh( TRUE, &r );
2472 }
66242c80
MB
2473}
2474
2d66e025
MB
2475
2476//
2477// ------ functions to get/send data (see also public functions)
2478//
2479
2480bool wxGrid::GetModelValues()
66242c80 2481{
2d66e025 2482 if ( m_table )
66242c80 2483 {
2d66e025 2484 // all we need to do is repaint the grid
66242c80 2485 //
2d66e025 2486 m_gridWin->Refresh();
66242c80
MB
2487 return TRUE;
2488 }
8f177c8e 2489
66242c80
MB
2490 return FALSE;
2491}
2492
2d66e025
MB
2493
2494bool wxGrid::SetModelValues()
f85afd4e 2495{
2d66e025 2496 int row, col;
8f177c8e 2497
2d66e025
MB
2498 if ( m_table )
2499 {
2500 for ( row = 0; row < m_numRows; row++ )
f85afd4e 2501 {
2d66e025 2502 for ( col = 0; col < m_numCols; col++ )
f85afd4e 2503 {
2d66e025 2504 m_table->SetValue( row, col, GetCellValue(row, col) );
f85afd4e
MB
2505 }
2506 }
8f177c8e 2507
f85afd4e
MB
2508 return TRUE;
2509 }
2510
2511 return FALSE;
2512}
2513
2d66e025
MB
2514
2515
2516// Note - this function only draws cells that are in the list of
2517// exposed cells (usually set from the update region by
2518// CalcExposedCells)
2519//
2520void wxGrid::DrawGridCellArea( wxDC& dc )
f85afd4e 2521{
2d66e025 2522 if ( !m_numRows || !m_numCols ) return;
60ff3b99 2523
2d66e025
MB
2524 size_t i;
2525 size_t numCells = m_cellsExposed.GetCount();
60ff3b99 2526
2d66e025 2527 for ( i = 0; i < numCells; i++ )
f85afd4e 2528 {
2d66e025
MB
2529 DrawCell( dc, m_cellsExposed[i] );
2530 }
2531}
8f177c8e 2532
8f177c8e 2533
2d66e025
MB
2534void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
2535{
2536 if ( m_colWidths[coords.GetCol()] <=0 ||
2537 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2538
2d66e025
MB
2539 if ( m_gridLinesEnabled )
2540 DrawCellBorder( dc, coords );
f85afd4e 2541
2d66e025 2542 DrawCellBackground( dc, coords );
f85afd4e 2543
2d66e025
MB
2544 // TODO: separate functions here for different kinds of cells ?
2545 // e.g. text, image
2546 //
2547 DrawCellValue( dc, coords );
2548}
f85afd4e 2549
2d66e025
MB
2550
2551void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
2552{
2553 if ( m_colWidths[coords.GetCol()] <=0 ||
2554 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2555
2d66e025
MB
2556 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
2557 int row = coords.GetRow();
2558 int col = coords.GetCol();
60ff3b99 2559
2d66e025
MB
2560 // right hand border
2561 //
2562 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
2563 m_colRights[col], m_rowBottoms[row] );
2564
2565 // bottom border
2566 //
2567 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
2568 m_colRights[col], m_rowBottoms[row] );
f85afd4e
MB
2569}
2570
2d66e025
MB
2571
2572void wxGrid::DrawCellBackground( wxDC& dc, const wxGridCellCoords& coords )
f85afd4e 2573{
2d66e025
MB
2574 if ( m_colWidths[coords.GetCol()] <=0 ||
2575 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2576
2d66e025
MB
2577 int row = coords.GetRow();
2578 int col = coords.GetCol();
8f177c8e 2579
2d66e025 2580 dc.SetBackgroundMode( wxSOLID );
f85afd4e 2581
2d66e025
MB
2582 if ( IsInSelection( coords ) )
2583 {
2584 // TODO: improve this
2585 //
2586 dc.SetBrush( *wxBLACK_BRUSH );
f85afd4e 2587 }
2d66e025 2588 else
f85afd4e 2589 {
2d66e025 2590 dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
f85afd4e
MB
2591 }
2592
2d66e025 2593 dc.SetPen( *wxTRANSPARENT_PEN );
8f177c8e 2594
2d66e025
MB
2595 dc.DrawRectangle( m_colRights[col] - m_colWidths[col] + 1,
2596 m_rowBottoms[row] - m_rowHeights[row] + 1,
2597 m_colWidths[col]-1,
2598 m_rowHeights[row]-1 );
f85afd4e
MB
2599}
2600
2601
2d66e025 2602void wxGrid::DrawCellValue( wxDC& dc, const wxGridCellCoords& coords )
f85afd4e 2603{
2d66e025
MB
2604 if ( m_colWidths[coords.GetCol()] <=0 ||
2605 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2606
2d66e025
MB
2607 int row = coords.GetRow();
2608 int col = coords.GetCol();
f85afd4e 2609
2d66e025 2610 dc.SetBackgroundMode( wxTRANSPARENT );
8f177c8e 2611
2d66e025
MB
2612 if ( IsInSelection( row, col ) )
2613 {
2614 // TODO: improve this
2615 //
2616 dc.SetTextBackground( wxColour(0, 0, 0) );
2617 dc.SetTextForeground( wxColour(255, 255, 255) );
2618 }
2619 else
f85afd4e 2620 {
2d66e025
MB
2621 dc.SetTextBackground( GetCellBackgroundColour(row, col) );
2622 dc.SetTextForeground( GetCellTextColour(row, col) );
2623 }
2624 dc.SetFont( GetCellFont(row, col) );
f85afd4e 2625
2d66e025
MB
2626 int hAlign, vAlign;
2627 GetCellAlignment( row, col, &hAlign, &vAlign );
8f177c8e 2628
2d66e025
MB
2629 wxRect rect;
2630 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
2631 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
2632 rect.SetWidth( m_colWidths[col] - 4 );
2633 rect.SetHeight( m_rowHeights[row] - 4 );
60ff3b99 2634
2d66e025 2635 DrawTextRectangle( dc, GetCellValue( row, col ), rect, hAlign, vAlign );
f85afd4e
MB
2636}
2637
2638
2d66e025
MB
2639
2640// TODO: remove this ???
2641// This is used to redraw all grid lines e.g. when the grid line colour
2642// has been changed
2643//
2644void wxGrid::DrawAllGridLines( wxDC& dc )
f85afd4e 2645{
60ff3b99
VZ
2646 if ( !m_gridLinesEnabled ||
2647 !m_numRows ||
2d66e025 2648 !m_numCols ) return;
f85afd4e 2649
f85afd4e 2650 int cw, ch;
2d66e025 2651 m_gridWin->GetClientSize(&cw, &ch);
8f177c8e 2652
2d66e025 2653 // virtual coords of visible area
f85afd4e 2654 //
2d66e025
MB
2655 int top, bottom, left, right;
2656 CalcUnscrolledPosition( 0, 0, &left, &top );
2657 CalcUnscrolledPosition( cw, ch, &right, &bottom );
f85afd4e 2658
2d66e025 2659 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
f85afd4e 2660
2d66e025 2661 // horizontal grid lines
f85afd4e 2662 //
60ff3b99 2663 int i;
2d66e025 2664 for ( i = 0; i <= m_numRows; i++ )
f85afd4e 2665 {
2d66e025
MB
2666 if ( m_rowBottoms[i] > bottom )
2667 {
2668 break;
2669 }
2670 else if ( m_rowBottoms[i] >= top )
2671 {
2672 dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] );
2673 }
f85afd4e
MB
2674 }
2675
f85afd4e 2676
2d66e025
MB
2677 // vertical grid lines
2678 //
2679 for ( i = 0; i <= m_numCols; i++ )
f85afd4e 2680 {
2d66e025
MB
2681 if ( m_colRights[i] > right )
2682 {
2683 break;
2684 }
2685 else if ( m_colRights[i] >= left )
2686 {
2687 dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom );
2688 }
2689 }
2690}
f85afd4e 2691
8f177c8e 2692
2d66e025
MB
2693void wxGrid::DrawRowLabels( wxDC& dc )
2694{
2695 if ( !m_numRows || !m_numCols ) return;
60ff3b99 2696
2d66e025
MB
2697 size_t i;
2698 size_t numLabels = m_rowLabelsExposed.GetCount();
60ff3b99 2699
2d66e025
MB
2700 for ( i = 0; i < numLabels; i++ )
2701 {
2702 DrawRowLabel( dc, m_rowLabelsExposed[i] );
60ff3b99 2703 }
f85afd4e
MB
2704}
2705
2706
2d66e025 2707void wxGrid::DrawRowLabel( wxDC& dc, int row )
f85afd4e 2708{
2d66e025 2709 if ( m_rowHeights[row] <= 0 ) return;
60ff3b99 2710
2d66e025
MB
2711 // draw the label's horizontal border (the vertical border is
2712 // provided by the cell area window margin)
2713 //
2714 dc.SetPen( *wxBLACK_PEN );
8f177c8e 2715
2d66e025
MB
2716 dc.DrawLine( 0, m_rowBottoms[row]+1,
2717 m_rowLabelWidth, m_rowBottoms[row]+1 );
2718
2719 dc.SetPen( *wxWHITE_PEN );
2720
2721 dc.DrawLine( 0, m_rowBottoms[row]+2,
2722 m_rowLabelWidth, m_rowBottoms[row]+2 );
60ff3b99 2723
f85afd4e 2724 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
2725 dc.SetTextForeground( GetLabelTextColour() );
2726 dc.SetFont( GetLabelFont() );
8f177c8e 2727
f85afd4e 2728 int hAlign, vAlign;
2d66e025 2729 GetRowLabelAlignment( &hAlign, &vAlign );
60ff3b99 2730
2d66e025
MB
2731 wxRect rect;
2732 rect.SetX( 2 );
2733 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
2734 rect.SetWidth( m_rowLabelWidth - 4 );
2735 rect.SetHeight( m_rowHeights[row] - 4 );
60ff3b99 2736 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
f85afd4e
MB
2737}
2738
2739
2d66e025 2740void wxGrid::DrawColLabels( wxDC& dc )
f85afd4e 2741{
2d66e025 2742 if ( !m_numRows || !m_numCols ) return;
60ff3b99 2743
2d66e025
MB
2744 size_t i;
2745 size_t numLabels = m_colLabelsExposed.GetCount();
60ff3b99 2746
2d66e025 2747 for ( i = 0; i < numLabels; i++ )
f85afd4e 2748 {
2d66e025 2749 DrawColLabel( dc, m_colLabelsExposed[i] );
60ff3b99 2750 }
f85afd4e
MB
2751}
2752
2753
2d66e025 2754void wxGrid::DrawColLabel( wxDC& dc, int col )
f85afd4e 2755{
2d66e025 2756 if ( m_colWidths[col] <= 0 ) return;
60ff3b99 2757
2d66e025
MB
2758 // draw the label's vertical border (the horizontal border is
2759 // provided by the cell area window margin)
f85afd4e 2760 //
2d66e025 2761 dc.SetPen( *wxBLACK_PEN );
f85afd4e 2762
2d66e025
MB
2763 dc.DrawLine( m_colRights[col]+1, 0,
2764 m_colRights[col]+1, m_colLabelHeight );
f85afd4e 2765
f85afd4e
MB
2766 dc.SetPen( *wxWHITE_PEN );
2767
2d66e025
MB
2768 dc.DrawLine( m_colRights[col]+2, 0,
2769 m_colRights[col]+2, m_colLabelHeight );
8f177c8e 2770
f85afd4e 2771 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
2772 dc.SetTextForeground( GetLabelTextColour() );
2773 dc.SetFont( GetLabelFont() );
8f177c8e 2774
f85afd4e 2775 int hAlign, vAlign;
2d66e025 2776 GetColLabelAlignment( &hAlign, &vAlign );
60ff3b99 2777
2d66e025
MB
2778 wxRect rect;
2779 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
2780 rect.SetY( 2 );
2781 rect.SetWidth( m_colWidths[col] - 4 );
2782 rect.SetHeight( m_colLabelHeight - 4 );
60ff3b99 2783 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
f85afd4e
MB
2784}
2785
2786
2d66e025
MB
2787void wxGrid::DrawTextRectangle( wxDC& dc,
2788 const wxString& value,
2789 const wxRect& rect,
2790 int horizAlign,
2791 int vertAlign )
f85afd4e 2792{
2d66e025
MB
2793 long textWidth, textHeight;
2794 long lineWidth, lineHeight;
2795 wxArrayString lines;
f85afd4e 2796
2d66e025
MB
2797 dc.SetClippingRegion( rect );
2798 StringToLines( value, lines );
2799 if ( lines.GetCount() )
2800 {
2801 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
2802 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
f85afd4e 2803
2d66e025
MB
2804 float x, y;
2805 switch ( horizAlign )
2806 {
2807 case wxRIGHT:
2808 x = rect.x + (rect.width - textWidth - 1);
2809 break;
f85afd4e 2810
2d66e025
MB
2811 case wxCENTRE:
2812 x = rect.x + ((rect.width - textWidth)/2);
2813 break;
f85afd4e 2814
2d66e025
MB
2815 case wxLEFT:
2816 default:
2817 x = rect.x + 1;
2818 break;
2819 }
f85afd4e 2820
2d66e025
MB
2821 switch ( vertAlign )
2822 {
2823 case wxBOTTOM:
2824 y = rect.y + (rect.height - textHeight - 1);
2825 break;
f85afd4e
MB
2826
2827 case wxCENTRE:
8f177c8e 2828 y = rect.y + ((rect.height - textHeight)/2);
f85afd4e
MB
2829 break;
2830
2831 case wxTOP:
2832 default:
8f177c8e 2833 y = rect.y + 1;
f85afd4e
MB
2834 break;
2835 }
2836
b540eb2b 2837 for ( size_t i = 0; i < lines.GetCount(); i++ )
f85afd4e
MB
2838 {
2839 dc.DrawText( lines[i], (long)x, (long)y );
2840 y += lineHeight;
2841 }
2842 }
8f177c8e 2843
f85afd4e 2844 dc.DestroyClippingRegion();
f85afd4e
MB
2845}
2846
2847
2848// Split multi line text up into an array of strings. Any existing
2849// contents of the string array are preserved.
2850//
2851void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
2852{
2853 // TODO: this won't work for WXMAC ? (lines end with '\r')
b540eb2b 2854 // => use wxTextFile functions then (VZ)
f85afd4e
MB
2855 int startPos = 0;
2856 int pos;
b540eb2b 2857 while ( startPos < (int)value.Length() )
f85afd4e
MB
2858 {
2859 pos = value.Mid(startPos).Find( '\n' );
2860 if ( pos < 0 )
2861 {
2862 break;
2863 }
2864 else if ( pos == 0 )
2865 {
2866 lines.Add( wxEmptyString );
2867 }
2868 else
2869 {
2870 if ( value[startPos+pos-1] == '\r' )
2871 {
2872 lines.Add( value.Mid(startPos, pos-1) );
2873 }
2874 else
2875 {
2876 lines.Add( value.Mid(startPos, pos) );
2877 }
2878 }
2879 startPos += pos+1;
2880 }
b540eb2b 2881 if ( startPos < (int)value.Length() )
f85afd4e
MB
2882 {
2883 lines.Add( value.Mid( startPos ) );
2884 }
2885}
2886
2887
2888void wxGrid::GetTextBoxSize( wxDC& dc,
2889 wxArrayString& lines,
2890 long *width, long *height )
2891{
2892 long w = 0;
2893 long h = 0;
2894 long lineW, lineH;
2895
b540eb2b 2896 size_t i;
f85afd4e
MB
2897 for ( i = 0; i < lines.GetCount(); i++ )
2898 {
2899 dc.GetTextExtent( lines[i], &lineW, &lineH );
2900 w = wxMax( w, lineW );
2901 h += lineH;
2902 }
2903
2904 *width = w;
2905 *height = h;
2906}
2907
2908
2909//
2d66e025 2910// ------ Edit control functions
f85afd4e
MB
2911//
2912
2d66e025
MB
2913
2914void wxGrid::EnableEditing( bool edit )
f85afd4e 2915{
2d66e025
MB
2916 // TODO: improve this ?
2917 //
2918 if ( edit != m_editable )
f85afd4e 2919 {
2d66e025 2920 m_editable = edit;
1f1ce288
MB
2921
2922 // TODO: extend this for other edit control types
2923 //
2924 if ( m_editCtrlType == wxGRID_TEXTCTRL )
2925 {
2926 ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable );
2927 }
f85afd4e 2928 }
f85afd4e
MB
2929}
2930
2931
1f1ce288 2932#if 0 // disabled for the moment - the cell control is always active
2d66e025 2933void wxGrid::EnableCellEditControl( bool enable )
f85afd4e 2934{
2d66e025
MB
2935 if ( m_cellEditCtrl &&
2936 enable != m_cellEditCtrlEnabled )
f85afd4e 2937 {
2d66e025 2938 m_cellEditCtrlEnabled = enable;
60ff3b99 2939
2d66e025 2940 if ( m_cellEditCtrlEnabled )
f85afd4e 2941 {
2d66e025
MB
2942 SetEditControlValue();
2943 ShowCellEditControl();
2d66e025
MB
2944 }
2945 else
2946 {
2d66e025
MB
2947 HideCellEditControl();
2948 SaveEditControlValue();
f85afd4e 2949 }
f85afd4e 2950 }
f85afd4e 2951}
1f1ce288 2952#endif
f85afd4e
MB
2953
2954
2d66e025 2955void wxGrid::ShowCellEditControl()
f85afd4e 2956{
2d66e025
MB
2957 wxRect rect;
2958
2959 if ( IsCellEditControlEnabled() )
f85afd4e 2960 {
2d66e025
MB
2961 if ( !IsVisible( m_currentCellCoords ) )
2962 {
2963 return;
2964 }
2965 else
2966 {
2967 rect = CellToRect( m_currentCellCoords );
2968
2969 // convert to scrolled coords
2970 //
2971 int left, top, right, bottom;
2972 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
2973 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
60ff3b99 2974
2d66e025
MB
2975 int cw, ch;
2976 m_gridWin->GetClientSize( &cw, &ch );
1f1ce288
MB
2977
2978 // Make the edit control large enough to allow for internal margins
2979 // TODO: remove this if the text ctrl sizing is improved esp. for unix
2980 //
60ff3b99 2981#if defined (__WXMOTIF__)
1f1ce288
MB
2982 rect.SetLeft( wxMax(0, left-4) );
2983 rect.SetTop( wxMax(0, top-4) );
2984 rect.SetRight( rect.GetRight() + 8 );
2985 rect.SetBottom( rect.GetBottom() + 8 );
2986#else
2987 rect.SetLeft( wxMax(0, left-2) );
2988 rect.SetTop( wxMax(0, top-2) );
2989 rect.SetRight( rect.GetRight() + 4 );
60ff3b99 2990 rect.SetBottom( rect.GetBottom() + 4 );
1f1ce288 2991#endif
60ff3b99 2992
2d66e025
MB
2993 m_cellEditCtrl->SetSize( rect );
2994 m_cellEditCtrl->Show( TRUE );
2995
2996 switch ( m_editCtrlType )
2997 {
2998 case wxGRID_TEXTCTRL:
2999 ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
3000 break;
3001
3002 case wxGRID_CHECKBOX:
3003 // TODO: anything ???
3004 //
3005 break;
3006
3007 case wxGRID_CHOICE:
3008 // TODO: anything ???
3009 //
3010 break;
3011
3012 case wxGRID_COMBOBOX:
3013 // TODO: anything ???
3014 //
3015 break;
3016 }
3017
3018 m_cellEditCtrl->SetFocus();
3019 }
f85afd4e
MB
3020 }
3021}
3022
3023
2d66e025 3024void wxGrid::HideCellEditControl()
f85afd4e 3025{
2d66e025 3026 if ( IsCellEditControlEnabled() )
f85afd4e 3027 {
2d66e025 3028 m_cellEditCtrl->Show( FALSE );
f85afd4e 3029 }
2d66e025 3030}
8f177c8e 3031
2d66e025
MB
3032
3033void wxGrid::SetEditControlValue( const wxString& value )
3034{
f85afd4e
MB
3035 if ( m_table )
3036 {
2d66e025
MB
3037 wxString s;
3038 if ( !value )
3039 s = GetCellValue(m_currentCellCoords);
3040 else
3041 s = value;
f85afd4e 3042
2d66e025
MB
3043 if ( IsCellEditControlEnabled() )
3044 {
3045 switch ( m_editCtrlType )
3f296516 3046 {
2d66e025
MB
3047 case wxGRID_TEXTCTRL:
3048 ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
3049 break;
8f177c8e 3050
2d66e025
MB
3051 case wxGRID_CHECKBOX:
3052 // TODO: implement this
3053 //
3054 break;
3f296516 3055
2d66e025
MB
3056 case wxGRID_CHOICE:
3057 // TODO: implement this
3058 //
3059 break;
3060
3061 case wxGRID_COMBOBOX:
3062 // TODO: implement this
3063 //
3064 break;
3065 }
3066 }
f85afd4e
MB
3067 }
3068}
3069
8f177c8e 3070
2d66e025
MB
3071void wxGrid::SaveEditControlValue()
3072{
3073 if ( m_table )
f85afd4e 3074 {
2d66e025 3075 wxWindow *ctrl = (wxWindow *)NULL;
8f177c8e 3076
2d66e025 3077 if ( IsCellEditControlEnabled() )
3f296516 3078 {
2d66e025
MB
3079 ctrl = m_cellEditCtrl;
3080 }
2d66e025
MB
3081 else
3082 {
3083 return;
3f296516 3084 }
8f177c8e 3085
2d66e025
MB
3086 bool valueChanged = FALSE;
3087
3088 switch ( m_editCtrlType )
3089 {
3090 case wxGRID_TEXTCTRL:
3091 valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() !=
3092 ((wxGridTextCtrl *)ctrl)->GetStartValue());
3093 SetCellValue( m_currentCellCoords,
3094 ((wxTextCtrl *) ctrl)->GetValue() );
3095 break;
3096
3097 case wxGRID_CHECKBOX:
3098 // TODO: implement this
3099 //
3100 break;
3101
3102 case wxGRID_CHOICE:
3103 // TODO: implement this
3104 //
3105 break;
3106
3107 case wxGRID_COMBOBOX:
3108 // TODO: implement this
3109 //
3110 break;
3111 }
3112
3113 if ( valueChanged )
3114 {
3115 SendEvent( EVT_GRID_CELL_CHANGE,
3116 m_currentCellCoords.GetRow(),
3117 m_currentCellCoords.GetCol() );
3118 }
f85afd4e
MB
3119 }
3120}
3121
2d66e025
MB
3122
3123//
60ff3b99
VZ
3124// ------ Grid location functions
3125// Note that all of these functions work with the logical coordinates of
2d66e025
MB
3126// grid cells and labels so you will need to convert from device
3127// coordinates for mouse events etc.
3128//
3129
3130void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
f85afd4e 3131{
2d66e025
MB
3132 coords.SetRow( YToRow(y) );
3133 coords.SetCol( XToCol(x) );
3134}
f85afd4e 3135
8f177c8e 3136
2d66e025
MB
3137int wxGrid::YToRow( int y )
3138{
3139 int i;
8f177c8e 3140
2d66e025 3141 for ( i = 0; i < m_numRows; i++ )
f85afd4e 3142 {
2d66e025 3143 if ( y < m_rowBottoms[i] ) return i;
f85afd4e 3144 }
2d66e025
MB
3145
3146 return -1;
f85afd4e
MB
3147}
3148
2d66e025
MB
3149
3150int wxGrid::XToCol( int x )
f85afd4e 3151{
2d66e025 3152 int i;
8f177c8e 3153
2d66e025 3154 for ( i = 0; i < m_numCols; i++ )
f85afd4e 3155 {
2d66e025 3156 if ( x < m_colRights[i] ) return i;
f85afd4e
MB
3157 }
3158
2d66e025
MB
3159 return -1;
3160}
8f177c8e 3161
2d66e025
MB
3162
3163// return the row number that that the y coord is near the edge of, or
3164// -1 if not near an edge
3165//
3166int wxGrid::YToEdgeOfRow( int y )
3167{
3168 int i, d;
3169
3170 for ( i = 0; i < m_numRows; i++ )
3171 {
3172 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
f85afd4e 3173 {
2d66e025 3174 d = abs( y - m_rowBottoms[i] );
3f296516 3175 {
2d66e025 3176 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3f296516 3177 }
f85afd4e 3178 }
f85afd4e 3179 }
2d66e025
MB
3180
3181 return -1;
3182}
3183
3184
3185// return the col number that that the x coord is near the edge of, or
3186// -1 if not near an edge
3187//
3188int wxGrid::XToEdgeOfCol( int x )
3189{
3190 int i, d;
3191
3192 for ( i = 0; i < m_numCols; i++ )
f85afd4e 3193 {
2d66e025
MB
3194 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
3195 {
3196 d = abs( x - m_colRights[i] );
3197 {
3198 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3199 }
3200 }
f85afd4e 3201 }
2d66e025
MB
3202
3203 return -1;
f85afd4e
MB
3204}
3205
2d66e025
MB
3206
3207wxRect wxGrid::CellToRect( int row, int col )
f85afd4e 3208{
2d66e025 3209 wxRect rect( -1, -1, -1, -1 );
f85afd4e 3210
2d66e025
MB
3211 if ( row >= 0 && row < m_numRows &&
3212 col >= 0 && col < m_numCols )
f85afd4e 3213 {
2d66e025
MB
3214 rect.x = m_colRights[col] - m_colWidths[col];
3215 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3216 rect.width = m_colWidths[col];
3217 rect.height = m_rowHeights[ row ];
f85afd4e
MB
3218 }
3219
2d66e025
MB
3220 return rect;
3221}
3222
3223
3224bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
3225{
3226 // get the cell rectangle in logical coords
3227 //
3228 wxRect r( CellToRect( row, col ) );
60ff3b99 3229
2d66e025
MB
3230 // convert to device coords
3231 //
3232 int left, top, right, bottom;
3233 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3234 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 3235
2d66e025
MB
3236 // check against the client area of the grid window
3237 //
3238 int cw, ch;
3239 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3240
2d66e025 3241 if ( wholeCellVisible )
f85afd4e 3242 {
2d66e025 3243 // is the cell wholly visible ?
8f177c8e 3244 //
2d66e025
MB
3245 return ( left >= 0 && right <= cw &&
3246 top >= 0 && bottom <= ch );
3247 }
3248 else
3249 {
3250 // is the cell partly visible ?
3251 //
3252 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
3253 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
3254 }
3255}
3256
3257
3258// make the specified cell location visible by doing a minimal amount
3259// of scrolling
3260//
3261void wxGrid::MakeCellVisible( int row, int col )
3262{
3263 int i;
60ff3b99 3264 int xpos = -1, ypos = -1;
2d66e025
MB
3265
3266 if ( row >= 0 && row < m_numRows &&
3267 col >= 0 && col < m_numCols )
3268 {
3269 // get the cell rectangle in logical coords
3270 //
3271 wxRect r( CellToRect( row, col ) );
60ff3b99 3272
2d66e025
MB
3273 // convert to device coords
3274 //
3275 int left, top, right, bottom;
3276 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3277 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 3278
2d66e025
MB
3279 int cw, ch;
3280 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3281
2d66e025 3282 if ( top < 0 )
3f296516 3283 {
2d66e025 3284 ypos = r.GetTop();
3f296516 3285 }
2d66e025
MB
3286 else if ( bottom > ch )
3287 {
3288 int h = r.GetHeight();
3289 ypos = r.GetTop();
3290 for ( i = row-1; i >= 0; i-- )
3291 {
3292 if ( h + m_rowHeights[i] > ch ) break;
3293
3294 h += m_rowHeights[i];
3295 ypos -= m_rowHeights[i];
3296 }
3297 }
3298
3299 if ( left < 0 )
3300 {
3301 xpos = r.GetLeft();
3302 }
3303 else if ( right > cw )
3304 {
3305 int w = r.GetWidth();
3306 xpos = r.GetLeft();
3307 for ( i = col-1; i >= 0; i-- )
3308 {
3309 if ( w + m_colWidths[i] > cw ) break;
3310
3311 w += m_colWidths[i];
3312 xpos -= m_colWidths[i];
3313 }
3314 }
3315
3316 if ( xpos != -1 || ypos != -1 )
3317 {
3318 if ( xpos != -1 ) xpos = xpos/10;
3319 if ( ypos != -1 ) ypos = ypos/10;
3320 Scroll( xpos, ypos );
3321 AdjustScrollbars();
3322 }
3323 }
3324}
3325
3326
3327//
3328// ------ Grid cursor movement functions
3329//
3330
3331bool wxGrid::MoveCursorUp()
3332{
3333 if ( m_currentCellCoords != wxGridNoCellCoords &&
3334 m_currentCellCoords.GetRow() > 0 )
3335 {
3336 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
3337 m_currentCellCoords.GetCol() );
60ff3b99 3338
2d66e025
MB
3339 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
3340 m_currentCellCoords.GetCol() );
3341
8f177c8e 3342 return TRUE;
f85afd4e 3343 }
2d66e025
MB
3344
3345 return FALSE;
3346}
3347
3348
3349bool wxGrid::MoveCursorDown()
3350{
3351 // TODO: allow for scrolling
3352 //
3353 if ( m_currentCellCoords != wxGridNoCellCoords &&
3354 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 3355 {
2d66e025
MB
3356 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
3357 m_currentCellCoords.GetCol() );
60ff3b99 3358
2d66e025
MB
3359 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
3360 m_currentCellCoords.GetCol() );
3361
3362 return TRUE;
f85afd4e 3363 }
2d66e025
MB
3364
3365 return FALSE;
f85afd4e
MB
3366}
3367
2d66e025
MB
3368
3369bool wxGrid::MoveCursorLeft()
f85afd4e 3370{
2d66e025
MB
3371 if ( m_currentCellCoords != wxGridNoCellCoords &&
3372 m_currentCellCoords.GetCol() > 0 )
3373 {
3374 MakeCellVisible( m_currentCellCoords.GetRow(),
3375 m_currentCellCoords.GetCol() - 1 );
60ff3b99 3376
2d66e025
MB
3377 SetCurrentCell( m_currentCellCoords.GetRow(),
3378 m_currentCellCoords.GetCol() - 1 );
8f177c8e 3379
2d66e025
MB
3380 return TRUE;
3381 }
3382
3383 return FALSE;
3384}
3385
3386
3387bool wxGrid::MoveCursorRight()
3388{
3389 if ( m_currentCellCoords != wxGridNoCellCoords &&
3390 m_currentCellCoords.GetCol() < m_numCols - 1 )
f85afd4e 3391 {
2d66e025
MB
3392 MakeCellVisible( m_currentCellCoords.GetRow(),
3393 m_currentCellCoords.GetCol() + 1 );
60ff3b99 3394
2d66e025
MB
3395 SetCurrentCell( m_currentCellCoords.GetRow(),
3396 m_currentCellCoords.GetCol() + 1 );
3397
3398 return TRUE;
f85afd4e 3399 }
8f177c8e 3400
2d66e025
MB
3401 return FALSE;
3402}
3403
3404
3405bool wxGrid::MovePageUp()
3406{
3407 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 3408
2d66e025
MB
3409 int row = m_currentCellCoords.GetRow();
3410 if ( row > 0 )
f85afd4e 3411 {
2d66e025
MB
3412 int cw, ch;
3413 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3414
2d66e025
MB
3415 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3416 int newRow = YToRow( y - ch + 1 );
3417 if ( newRow == -1 )
3418 {
3419 newRow = 0;
3420 }
60ff3b99 3421 else if ( newRow == row )
2d66e025
MB
3422 {
3423 newRow = row - 1;
3424 }
8f177c8e 3425
2d66e025
MB
3426 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3427 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 3428
f85afd4e
MB
3429 return TRUE;
3430 }
2d66e025
MB
3431
3432 return FALSE;
3433}
3434
3435bool wxGrid::MovePageDown()
3436{
3437 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 3438
2d66e025
MB
3439 int row = m_currentCellCoords.GetRow();
3440 if ( row < m_numRows )
f85afd4e 3441 {
2d66e025
MB
3442 int cw, ch;
3443 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3444
2d66e025
MB
3445 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3446 int newRow = YToRow( y + ch );
3447 if ( newRow == -1 )
3448 {
3449 newRow = m_numRows - 1;
3450 }
60ff3b99 3451 else if ( newRow == row )
2d66e025
MB
3452 {
3453 newRow = row + 1;
3454 }
3455
3456 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3457 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 3458
2d66e025 3459 return TRUE;
f85afd4e 3460 }
2d66e025
MB
3461
3462 return FALSE;
f85afd4e 3463}
8f177c8e 3464
2d66e025
MB
3465bool wxGrid::MoveCursorUpBlock()
3466{
3467 if ( m_table &&
3468 m_currentCellCoords != wxGridNoCellCoords &&
3469 m_currentCellCoords.GetRow() > 0 )
3470 {
3471 int row = m_currentCellCoords.GetRow();
3472 int col = m_currentCellCoords.GetCol();
3473
3474 if ( m_table->IsEmptyCell(row, col) )
3475 {
3476 // starting in an empty cell: find the next block of
3477 // non-empty cells
3478 //
3479 while ( row > 0 )
3480 {
3481 row-- ;
3482 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3483 }
3484 }
3485 else if ( m_table->IsEmptyCell(row-1, col) )
3486 {
3487 // starting at the top of a block: find the next block
3488 //
3489 row--;
3490 while ( row > 0 )
3491 {
3492 row-- ;
3493 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3494 }
3495 }
3496 else
3497 {
3498 // starting within a block: find the top of the block
3499 //
3500 while ( row > 0 )
3501 {
3502 row-- ;
3503 if ( m_table->IsEmptyCell(row, col) )
3504 {
3505 row++ ;
3506 break;
3507 }
3508 }
3509 }
f85afd4e 3510
2d66e025
MB
3511 MakeCellVisible( row, col );
3512 SetCurrentCell( row, col );
f85afd4e 3513
2d66e025
MB
3514 return TRUE;
3515 }
f85afd4e 3516
2d66e025
MB
3517 return FALSE;
3518}
f85afd4e 3519
2d66e025 3520bool wxGrid::MoveCursorDownBlock()
f85afd4e 3521{
2d66e025
MB
3522 if ( m_table &&
3523 m_currentCellCoords != wxGridNoCellCoords &&
3524 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 3525 {
2d66e025
MB
3526 int row = m_currentCellCoords.GetRow();
3527 int col = m_currentCellCoords.GetCol();
3528
3529 if ( m_table->IsEmptyCell(row, col) )
3530 {
3531 // starting in an empty cell: find the next block of
3532 // non-empty cells
3533 //
3534 while ( row < m_numRows-1 )
3535 {
3536 row++ ;
3537 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3538 }
3539 }
3540 else if ( m_table->IsEmptyCell(row+1, col) )
3541 {
3542 // starting at the bottom of a block: find the next block
3543 //
3544 row++;
3545 while ( row < m_numRows-1 )
3546 {
3547 row++ ;
3548 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3549 }
3550 }
3551 else
3552 {
3553 // starting within a block: find the bottom of the block
3554 //
3555 while ( row < m_numRows-1 )
3556 {
3557 row++ ;
3558 if ( m_table->IsEmptyCell(row, col) )
3559 {
3560 row-- ;
3561 break;
3562 }
3563 }
3564 }
3565
3566 MakeCellVisible( row, col );
3567 SetCurrentCell( row, col );
3568
3569 return TRUE;
f85afd4e 3570 }
f85afd4e 3571
2d66e025
MB
3572 return FALSE;
3573}
f85afd4e 3574
2d66e025 3575bool wxGrid::MoveCursorLeftBlock()
f85afd4e 3576{
2d66e025
MB
3577 if ( m_table &&
3578 m_currentCellCoords != wxGridNoCellCoords &&
3579 m_currentCellCoords.GetCol() > 0 )
f85afd4e 3580 {
2d66e025
MB
3581 int row = m_currentCellCoords.GetRow();
3582 int col = m_currentCellCoords.GetCol();
3583
3584 if ( m_table->IsEmptyCell(row, col) )
3585 {
3586 // starting in an empty cell: find the next block of
3587 // non-empty cells
3588 //
3589 while ( col > 0 )
3590 {
3591 col-- ;
3592 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3593 }
3594 }
3595 else if ( m_table->IsEmptyCell(row, col-1) )
3596 {
3597 // starting at the left of a block: find the next block
3598 //
3599 col--;
3600 while ( col > 0 )
3601 {
3602 col-- ;
3603 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3604 }
3605 }
3606 else
3607 {
3608 // starting within a block: find the left of the block
3609 //
3610 while ( col > 0 )
3611 {
3612 col-- ;
3613 if ( m_table->IsEmptyCell(row, col) )
3614 {
3615 col++ ;
3616 break;
3617 }
3618 }
3619 }
f85afd4e 3620
2d66e025
MB
3621 MakeCellVisible( row, col );
3622 SetCurrentCell( row, col );
8f177c8e 3623
2d66e025 3624 return TRUE;
f85afd4e 3625 }
2d66e025
MB
3626
3627 return FALSE;
f85afd4e
MB
3628}
3629
2d66e025 3630bool wxGrid::MoveCursorRightBlock()
f85afd4e 3631{
2d66e025
MB
3632 if ( m_table &&
3633 m_currentCellCoords != wxGridNoCellCoords &&
3634 m_currentCellCoords.GetCol() < m_numCols-1 )
f85afd4e 3635 {
2d66e025
MB
3636 int row = m_currentCellCoords.GetRow();
3637 int col = m_currentCellCoords.GetCol();
8f177c8e 3638
2d66e025
MB
3639 if ( m_table->IsEmptyCell(row, col) )
3640 {
3641 // starting in an empty cell: find the next block of
3642 // non-empty cells
3643 //
3644 while ( col < m_numCols-1 )
3645 {
3646 col++ ;
3647 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3648 }
3649 }
3650 else if ( m_table->IsEmptyCell(row, col+1) )
3651 {
3652 // starting at the right of a block: find the next block
3653 //
3654 col++;
3655 while ( col < m_numCols-1 )
3656 {
3657 col++ ;
3658 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3659 }
3660 }
3661 else
3662 {
3663 // starting within a block: find the right of the block
3664 //
3665 while ( col < m_numCols-1 )
3666 {
3667 col++ ;
3668 if ( m_table->IsEmptyCell(row, col) )
3669 {
3670 col-- ;
3671 break;
3672 }
3673 }
3674 }
8f177c8e 3675
2d66e025
MB
3676 MakeCellVisible( row, col );
3677 SetCurrentCell( row, col );
f85afd4e 3678
2d66e025 3679 return TRUE;
f85afd4e 3680 }
2d66e025
MB
3681
3682 return FALSE;
f85afd4e
MB
3683}
3684
3685
2d66e025 3686
f85afd4e 3687//
2d66e025 3688// ------ Label values and formatting
f85afd4e
MB
3689//
3690
3691void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
3692{
3693 *horiz = m_rowLabelHorizAlign;
3694 *vert = m_rowLabelVertAlign;
3695}
3696
3697void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
3698{
3699 *horiz = m_colLabelHorizAlign;
3700 *vert = m_colLabelVertAlign;
3701}
3702
3703wxString wxGrid::GetRowLabelValue( int row )
3704{
3705 if ( m_table )
3706 {
3707 return m_table->GetRowLabelValue( row );
3708 }
3709 else
3710 {
3711 wxString s;
3712 s << row;
3713 return s;
3714 }
3715}
3716
3717wxString wxGrid::GetColLabelValue( int col )
3718{
3719 if ( m_table )
3720 {
3721 return m_table->GetColLabelValue( col );
3722 }
3723 else
3724 {
3725 wxString s;
3726 s << col;
3727 return s;
3728 }
3729}
3730
3731void wxGrid::SetRowLabelSize( int width )
3732{
2d66e025 3733 // TODO: how to do this with the box sizers ?
f85afd4e
MB
3734}
3735
3736void wxGrid::SetColLabelSize( int height )
3737{
2d66e025 3738 // TODO: how to do this with the box sizers ?
f85afd4e
MB
3739}
3740
3741void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
3742{
2d66e025
MB
3743 if ( m_labelBackgroundColour != colour )
3744 {
3745 m_labelBackgroundColour = colour;
3746 m_rowLabelWin->SetBackgroundColour( colour );
3747 m_colLabelWin->SetBackgroundColour( colour );
3748 m_cornerLabelWin->SetBackgroundColour( colour );
3749
3750 if ( !GetBatchCount() )
3751 {
3752 m_rowLabelWin->Refresh();
3753 m_colLabelWin->Refresh();
3754 m_cornerLabelWin->Refresh();
3755 }
3756 }
f85afd4e
MB
3757}
3758
3759void wxGrid::SetLabelTextColour( const wxColour& colour )
3760{
2d66e025
MB
3761 if ( m_labelTextColour != colour )
3762 {
3763 m_labelTextColour = colour;
3764 if ( !GetBatchCount() )
3765 {
3766 m_rowLabelWin->Refresh();
3767 m_colLabelWin->Refresh();
3768 }
3769 }
f85afd4e
MB
3770}
3771
3772void wxGrid::SetLabelFont( const wxFont& font )
3773{
3774 m_labelFont = font;
2d66e025
MB
3775 if ( !GetBatchCount() )
3776 {
3777 m_rowLabelWin->Refresh();
3778 m_colLabelWin->Refresh();
3779 }
f85afd4e
MB
3780}
3781
3782void wxGrid::SetRowLabelAlignment( int horiz, int vert )
3783{
3784 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
3785 {
3786 m_rowLabelHorizAlign = horiz;
3787 }
8f177c8e 3788
f85afd4e
MB
3789 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
3790 {
3791 m_rowLabelVertAlign = vert;
3792 }
3793
2d66e025
MB
3794 if ( !GetBatchCount() )
3795 {
3796 m_rowLabelWin->Refresh();
3797 m_colLabelWin->Refresh();
60ff3b99 3798 }
f85afd4e
MB
3799}
3800
3801void wxGrid::SetColLabelAlignment( int horiz, int vert )
3802{
3803 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
3804 {
3805 m_colLabelHorizAlign = horiz;
3806 }
8f177c8e 3807
f85afd4e
MB
3808 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
3809 {
3810 m_colLabelVertAlign = vert;
3811 }
3812
2d66e025
MB
3813 if ( !GetBatchCount() )
3814 {
3815 m_rowLabelWin->Refresh();
3816 m_colLabelWin->Refresh();
60ff3b99 3817 }
f85afd4e
MB
3818}
3819
3820void wxGrid::SetRowLabelValue( int row, const wxString& s )
3821{
3822 if ( m_table )
3823 {
3824 m_table->SetRowLabelValue( row, s );
2d66e025
MB
3825 if ( !GetBatchCount() )
3826 {
3827 // TODO: Optimize this
3828 //
3829 m_rowLabelWin->Refresh();
3830 }
f85afd4e
MB
3831 }
3832}
3833
3834void wxGrid::SetColLabelValue( int col, const wxString& s )
3835{
3836 if ( m_table )
3837 {
3838 m_table->SetColLabelValue( col, s );
2d66e025
MB
3839 if ( !GetBatchCount() )
3840 {
3841 // TODO: optimize this
3842 //
3843 m_colLabelWin->Refresh();
3844 }
f85afd4e
MB
3845 }
3846}
3847
3848void wxGrid::SetGridLineColour( const wxColour& colour )
3849{
2d66e025
MB
3850 if ( m_gridLineColour != colour )
3851 {
3852 m_gridLineColour = colour;
60ff3b99 3853
2d66e025
MB
3854 wxClientDC dc( m_gridWin );
3855 PrepareDC( dc );
3856 DrawAllGridLines( dc );
3857 }
f85afd4e
MB
3858}
3859
3860void wxGrid::EnableGridLines( bool enable )
3861{
3862 if ( enable != m_gridLinesEnabled )
3863 {
3864 m_gridLinesEnabled = enable;
2d66e025
MB
3865
3866 if ( !GetBatchCount() )
3867 {
3868 if ( enable )
3869 {
3870 wxClientDC dc( m_gridWin );
3871 PrepareDC( dc );
3872 DrawAllGridLines( dc );
3873 }
3874 else
3875 {
3876 m_gridWin->Refresh();
3877 }
3878 }
f85afd4e
MB
3879 }
3880}
3881
3882
3883int wxGrid::GetDefaultRowSize()
3884{
3885 return m_defaultRowHeight;
3886}
3887
3888int wxGrid::GetRowSize( int row )
3889{
3890 if ( row >= 0 && row < m_numRows )
3891 return m_rowHeights[row];
3892 else
3893 return 0; // TODO: log an error here
3894}
3895
3896int wxGrid::GetDefaultColSize()
3897{
3898 return m_defaultColWidth;
3899}
3900
3901int wxGrid::GetColSize( int col )
3902{
3903 if ( col >= 0 && col < m_numCols )
3904 return m_colWidths[col];
3905 else
3906 return 0; // TODO: log an error here
3907}
3908
3909wxColour wxGrid::GetDefaultCellBackgroundColour()
3910{
3911 // TODO: replace this temp test code
3912 //
3913 return wxColour( 255, 255, 255 );
3914}
3915
af111fc3 3916wxColour wxGrid::GetCellBackgroundColour( int WXUNUSED(row), int WXUNUSED(col) )
f85afd4e
MB
3917{
3918 // TODO: replace this temp test code
3919 //
8f177c8e 3920 return wxColour( 255, 255, 255 );
f85afd4e
MB
3921}
3922
3923wxColour wxGrid::GetDefaultCellTextColour()
3924{
3925 // TODO: replace this temp test code
3926 //
8f177c8e 3927 return wxColour( 0, 0, 0 );
f85afd4e
MB
3928}
3929
af111fc3 3930wxColour wxGrid::GetCellTextColour( int WXUNUSED(row), int WXUNUSED(col) )
f85afd4e
MB
3931{
3932 // TODO: replace this temp test code
3933 //
8f177c8e 3934 return wxColour( 0, 0, 0 );
f85afd4e
MB
3935}
3936
3937
f85afd4e
MB
3938wxFont wxGrid::GetDefaultCellFont()
3939{
3940 return m_defaultCellFont;
3941}
3942
af111fc3 3943wxFont wxGrid::GetCellFont( int WXUNUSED(row), int WXUNUSED(col) )
f85afd4e
MB
3944{
3945 // TODO: replace this temp test code
3946 //
3947 return m_defaultCellFont;
3948}
3949
3950void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
3951{
3952 // TODO: replace this temp test code
3953 //
3954 *horiz = wxLEFT;
3955 *vert = wxTOP;
3956}
3957
af111fc3 3958void wxGrid::GetCellAlignment( int WXUNUSED(row), int WXUNUSED(col), int *horiz, int *vert )
f85afd4e
MB
3959{
3960 // TODO: replace this temp test code
3961 //
3962 *horiz = wxLEFT;
3963 *vert = wxTOP;
3964}
3965
3966void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
3967{
3968 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
3969
3970 if ( resizeExistingRows )
3971 {
f85afd4e 3972 int row;
2d66e025 3973 int bottom = 0;
f85afd4e
MB
3974 for ( row = 0; row < m_numRows; row++ )
3975 {
3976 m_rowHeights[row] = m_defaultRowHeight;
2d66e025
MB
3977 bottom += m_defaultRowHeight;
3978 m_rowBottoms[row] = bottom;
f85afd4e
MB
3979 }
3980 CalcDimensions();
f85afd4e
MB
3981 }
3982}
3983
3984void wxGrid::SetRowSize( int row, int height )
3985{
2d66e025 3986 int i;
60ff3b99 3987
f85afd4e
MB
3988 if ( row >= 0 && row < m_numRows )
3989 {
2d66e025
MB
3990 int h = wxMax( 0, height );
3991 int diff = h - m_rowHeights[row];
60ff3b99 3992
2d66e025
MB
3993 m_rowHeights[row] = h;
3994 for ( i = row; i < m_numRows; i++ )
3995 {
3996 m_rowBottoms[i] += diff;
3997 }
f85afd4e 3998 CalcDimensions();
60ff3b99 3999
f85afd4e
MB
4000 // Note: we are ending the event *after* doing
4001 // default processing in this case
4002 //
b5f788a5 4003 SendEvent( EVT_GRID_ROW_SIZE,
f85afd4e
MB
4004 row, -1 );
4005 }
4006 else
4007 {
4008 // TODO: log an error here
4009 }
4010}
4011
4012void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
4013{
4014 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
4015
4016 if ( resizeExistingCols )
4017 {
f85afd4e 4018 int col;
2d66e025 4019 int right = 0;
f85afd4e
MB
4020 for ( col = 0; col < m_numCols; col++ )
4021 {
4022 m_colWidths[col] = m_defaultColWidth;
2d66e025
MB
4023 right += m_defaultColWidth;
4024 m_colRights[col] = right;
f85afd4e
MB
4025 }
4026 CalcDimensions();
f85afd4e
MB
4027 }
4028}
4029
4030void wxGrid::SetColSize( int col, int width )
4031{
2d66e025 4032 int i;
60ff3b99 4033
f85afd4e
MB
4034 if ( col >= 0 && col < m_numCols )
4035 {
2d66e025
MB
4036 int w = wxMax( 0, width );
4037 int diff = w - m_colWidths[col];
4038 m_colWidths[col] = w;
f85afd4e 4039
2d66e025
MB
4040 for ( i = col; i < m_numCols; i++ )
4041 {
4042 m_colRights[i] += diff;
4043 }
4044 CalcDimensions();
60ff3b99 4045
f85afd4e
MB
4046 // Note: we are ending the event *after* doing
4047 // default processing in this case
4048 //
b5f788a5 4049 SendEvent( EVT_GRID_COL_SIZE,
f85afd4e
MB
4050 -1, col );
4051 }
4052 else
4053 {
4054 // TODO: log an error here
4055 }
4056}
4057
4058void wxGrid::SetDefaultCellBackgroundColour( const wxColour& )
4059{
4060 // TODO: everything !!!
4061 //
4062}
4063
af111fc3 4064void wxGrid::SetCellBackgroundColour( int WXUNUSED(row), int WXUNUSED(col), const wxColour& )
f85afd4e
MB
4065{
4066 // TODO: everything !!!
4067 //
4068}
4069
4070void wxGrid::SetDefaultCellTextColour( const wxColour& )
4071{
4072 // TODO: everything !!!
4073 //
4074}
4075
af111fc3 4076void wxGrid::SetCellTextColour( int WXUNUSED(row), int WXUNUSED(col), const wxColour& )
f85afd4e
MB
4077{
4078 // TODO: everything !!!
4079 //
4080}
4081
f85afd4e
MB
4082void wxGrid::SetDefaultCellFont( const wxFont& )
4083{
4084 // TODO: everything !!!
4085 //
4086}
4087
af111fc3 4088void wxGrid::SetCellFont( int WXUNUSED(row), int WXUNUSED(col), const wxFont& )
f85afd4e
MB
4089{
4090 // TODO: everything !!!
4091 //
4092}
4093
af111fc3 4094void wxGrid::SetDefaultCellAlignment( int WXUNUSED(horiz), int WXUNUSED(vert) )
f85afd4e
MB
4095{
4096 // TODO: everything !!!
4097 //
4098}
4099
af111fc3 4100void wxGrid::SetCellAlignment( int WXUNUSED(row), int WXUNUSED(col), int WXUNUSED(horiz), int WXUNUSED(vert) )
f85afd4e
MB
4101{
4102 // TODO: everything !!!
4103 //
4104}
4105
4106
2d66e025 4107
f85afd4e
MB
4108//
4109// ------ cell value accessor functions
4110//
4111
4112void wxGrid::SetCellValue( int row, int col, const wxString& s )
4113{
4114 if ( m_table )
4115 {
4116 m_table->SetValue( row, col, s.c_str() );
2d66e025
MB
4117 if ( !GetBatchCount() )
4118 {
4119 wxClientDC dc( m_gridWin );
4120 PrepareDC( dc );
4121 DrawCell( dc, wxGridCellCoords(row, col) );
4122 }
60ff3b99 4123
2d66e025 4124#if 0 // TODO: edit in place
60ff3b99 4125
f85afd4e
MB
4126 if ( m_currentCellCoords.GetRow() == row &&
4127 m_currentCellCoords.GetCol() == col )
4128 {
4129 SetEditControlValue( s );
4130 }
2d66e025 4131#endif
f85afd4e 4132
f85afd4e
MB
4133 }
4134}
4135
4136
4137//
2d66e025 4138// ------ Block, row and col selection
f85afd4e
MB
4139//
4140
4141void wxGrid::SelectRow( int row, bool addToSelected )
4142{
2d66e025 4143 wxRect r;
60ff3b99 4144
f85afd4e
MB
4145 if ( IsSelection() && addToSelected )
4146 {
4147 if ( m_selectedTopLeft.GetRow() > row )
4148 m_selectedTopLeft.SetRow( row );
8f177c8e 4149
f85afd4e 4150 m_selectedTopLeft.SetCol( 0 );
8f177c8e 4151
f85afd4e
MB
4152 if ( m_selectedBottomRight.GetRow() < row )
4153 m_selectedBottomRight.SetRow( row );
8f177c8e 4154
f85afd4e 4155 m_selectedBottomRight.SetCol( m_numCols - 1 );
2d66e025
MB
4156
4157 // TODO: optimize this so that we only refresh the newly
4158 // selected cells
4159 //
4160 r = SelectionToDeviceRect();
4161 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
f85afd4e
MB
4162 }
4163 else
4164 {
2d66e025 4165 r = SelectionToDeviceRect();
f85afd4e 4166 ClearSelection();
2d66e025 4167 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
60ff3b99 4168
f85afd4e
MB
4169 m_selectedTopLeft.Set( row, 0 );
4170 m_selectedBottomRight.Set( row, m_numCols-1 );
2d66e025
MB
4171 r = SelectionToDeviceRect();
4172 m_gridWin->Refresh( TRUE, &r );
f85afd4e 4173 }
8f177c8e 4174
f85afd4e 4175 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 4176 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
4177 this,
4178 m_selectedTopLeft,
4179 m_selectedBottomRight );
4180
4181 GetEventHandler()->ProcessEvent(gridEvt);
4182}
4183
4184
4185void wxGrid::SelectCol( int col, bool addToSelected )
4186{
2d66e025 4187 wxRect r;
60ff3b99 4188
2d66e025 4189 if ( IsSelection() && addToSelected )
f85afd4e
MB
4190 {
4191 if ( m_selectedTopLeft.GetCol() > col )
4192 m_selectedTopLeft.SetCol( col );
4193
4194 m_selectedTopLeft.SetRow( 0 );
4195
4196 if ( m_selectedBottomRight.GetCol() < col )
4197 m_selectedBottomRight.SetCol( col );
4198
4199 m_selectedBottomRight.SetRow( m_numRows - 1 );
2d66e025
MB
4200
4201 // TODO: optimize this so that we only refresh the newly
4202 // selected cells
4203 //
4204 r = SelectionToDeviceRect();
4205 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
f85afd4e
MB
4206 }
4207 else
4208 {
2d66e025 4209 r = SelectionToDeviceRect();
f85afd4e 4210 ClearSelection();
2d66e025 4211 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
60ff3b99 4212
f85afd4e
MB
4213 m_selectedTopLeft.Set( 0, col );
4214 m_selectedBottomRight.Set( m_numRows-1, col );
2d66e025
MB
4215 r = SelectionToDeviceRect();
4216 m_gridWin->Refresh( TRUE, &r );
f85afd4e
MB
4217 }
4218
4219 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 4220 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
4221 this,
4222 m_selectedTopLeft,
4223 m_selectedBottomRight );
4224
4225 GetEventHandler()->ProcessEvent(gridEvt);
4226}
4227
4228
4229void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
4230{
4231 int temp;
da6af900
SN
4232 bool changed = false;
4233 wxGridCellCoords updateTopLeft, updateBottomRight;
8f177c8e 4234
f85afd4e
MB
4235 if ( topRow > bottomRow )
4236 {
4237 temp = topRow;
4238 topRow = bottomRow;
4239 bottomRow = temp;
4240 }
4241
4242 if ( leftCol > rightCol )
4243 {
4244 temp = leftCol;
4245 leftCol = rightCol;
4246 rightCol = temp;
4247 }
da6af900
SN
4248
4249 updateTopLeft = m_selectedTopLeft;
4250 if (m_selectedTopLeft != wxGridCellCoords( topRow, leftCol ) )
4251 {
4252 m_selectedTopLeft = wxGridCellCoords( topRow, leftCol );
4253 if (updateTopLeft == wxGridNoCellCoords)
4254 {
4255 updateTopLeft = m_selectedTopLeft;
4256 }
4257 else
4258 {
4259 if(updateTopLeft.GetRow() > topRow)
4260 updateTopLeft.SetRow(topRow);
4261 if (updateTopLeft.GetCol() > leftCol)
4262 updateTopLeft.SetCol(leftCol);
4263 }
4264 changed = true;
4265 }
4266
4267 updateBottomRight = m_selectedBottomRight;
4268 if (m_selectedBottomRight != wxGridCellCoords( bottomRow, rightCol ) )
4269 {
4270 m_selectedBottomRight = wxGridCellCoords( bottomRow, rightCol );
4271 if (updateBottomRight == wxGridNoCellCoords)
4272 {
4273 updateBottomRight = m_selectedBottomRight;
4274 }
4275 else
4276 {
4277 if (updateBottomRight.GetRow() < bottomRow)
4278 updateBottomRight.SetRow(bottomRow);
4279 if (updateBottomRight.GetCol() < rightCol)
4280 updateBottomRight.SetCol(rightCol);
4281 }
4282 changed = true;
4283 }
4284
4285 if (changed)
4286 {
4287 wxRect r( BlockToDeviceRect( updateTopLeft, updateBottomRight ) );
4288 m_gridWin->Refresh( TRUE, &r );
4289 }
f85afd4e
MB
4290
4291 // only generate an event if the block is not being selected by
4292 // dragging the mouse (in which case the event will be generated in
2d66e025 4293 // the mouse event handler)
f85afd4e
MB
4294 if ( !m_isDragging )
4295 {
4296 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 4297 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
4298 this,
4299 m_selectedTopLeft,
4300 m_selectedBottomRight );
8f177c8e 4301
f85afd4e
MB
4302 GetEventHandler()->ProcessEvent(gridEvt);
4303 }
4304}
4305
4306void wxGrid::SelectAll()
4307{
4308 m_selectedTopLeft.Set( 0, 0 );
4309 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
4310
2d66e025 4311 m_gridWin->Refresh();
f85afd4e
MB
4312}
4313
4314
4315void wxGrid::ClearSelection()
4316{
2d66e025
MB
4317 m_selectedTopLeft = wxGridNoCellCoords;
4318 m_selectedBottomRight = wxGridNoCellCoords;
8f177c8e 4319}
f85afd4e
MB
4320
4321
da6af900 4322// This function returns the rectangle that encloses the given block
2d66e025
MB
4323// in device coords clipped to the client size of the grid window.
4324//
da6af900
SN
4325wxRect wxGrid::BlockToDeviceRect(const wxGridCellCoords & TopLeft,
4326 const wxGridCellCoords & BottomRight)
f85afd4e
MB
4327{
4328 wxRect rect;
4329 wxRect cellRect;
4330
4331 if ( IsSelection() )
4332 {
da6af900 4333 cellRect = CellToRect( TopLeft );
f85afd4e
MB
4334 if ( cellRect != wxGridNoCellRect )
4335 {
4336 rect = cellRect;
4337 }
4338 else
4339 {
2d66e025 4340 rect = wxRect( 0, 0, 0, 0 );
f85afd4e 4341 }
8f177c8e 4342
da6af900 4343 cellRect = CellToRect( BottomRight );
f85afd4e
MB
4344 if ( cellRect != wxGridNoCellRect )
4345 {
4346 rect += cellRect;
4347 }
4348 else
4349 {
4350 return wxGridNoCellRect;
4351 }
2d66e025
MB
4352
4353 // convert to scrolled coords
4354 //
4355 int left, top, right, bottom;
4356 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
4357 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
60ff3b99 4358
2d66e025
MB
4359 int cw, ch;
4360 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 4361
2d66e025
MB
4362 rect.SetLeft( wxMax(0, left) );
4363 rect.SetTop( wxMax(0, top) );
4364 rect.SetRight( wxMin(cw, right) );
4365 rect.SetBottom( wxMin(ch, bottom) );
4366 }
4367 else
4368 {
4369 return wxGridNoCellRect;
f85afd4e
MB
4370 }
4371
4372 return rect;
4373}
4374
4375
f85afd4e
MB
4376//
4377// ------ Grid event classes
4378//
4379
4380IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
4381
4382wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
4383 int row, int col, int x, int y,
4384 bool control, bool shift, bool alt, bool meta )
4385 : wxNotifyEvent( type, id )
4386{
4387 m_row = row;
4388 m_col = col;
4389 m_x = x;
4390 m_y = y;
4391 m_control = control;
4392 m_shift = shift;
4393 m_alt = alt;
4394 m_meta = meta;
8f177c8e 4395
f85afd4e
MB
4396 SetEventObject(obj);
4397}
4398
4399
4400IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
4401
4402wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
4403 int rowOrCol, int x, int y,
4404 bool control, bool shift, bool alt, bool meta )
4405 : wxNotifyEvent( type, id )
4406{
4407 m_rowOrCol = rowOrCol;
4408 m_x = x;
4409 m_y = y;
4410 m_control = control;
4411 m_shift = shift;
4412 m_alt = alt;
4413 m_meta = meta;
8f177c8e 4414
f85afd4e
MB
4415 SetEventObject(obj);
4416}
4417
4418
4419IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
4420
4421wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8f177c8e
VZ
4422 const wxGridCellCoords& topLeft,
4423 const wxGridCellCoords& bottomRight,
4424 bool control, bool shift, bool alt, bool meta )
4425 : wxNotifyEvent( type, id )
f85afd4e
MB
4426{
4427 m_topLeft = topLeft;
4428 m_bottomRight = bottomRight;
4429 m_control = control;
4430 m_shift = shift;
4431 m_alt = alt;
4432 m_meta = meta;
4433
4434 SetEventObject(obj);
4435}
4436
4437
4438#endif // ifndef wxUSE_NEW_GRID
4439