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