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