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