]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp
long -> wxCoord
[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
796df70a
SN
39#ifndef DRAW_LINES
40#define DRAW_LINES 1
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 );
796df70a
SN
879#if DRAW_LINES
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,
2d66e025 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;
1598 rect.width = m_rowLabelWidth;
1599 rect.height = ch - rect.y;
1600 m_rowLabelWin->Refresh( TRUE, &rect );
1601 rect.width = cw;
1602 m_gridWin->Refresh( TRUE, &rect );
f85afd4e 1603 }
60ff3b99 1604
2d66e025 1605 ShowCellEditControl();
f85afd4e 1606
2d66e025
MB
1607 // Note: we are ending the event *after* doing
1608 // default processing in this case
f85afd4e 1609 //
2d66e025 1610 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
f85afd4e 1611 }
2d66e025 1612 }
f85afd4e 1613
2d66e025
MB
1614 m_dragLastPos = -1;
1615 }
f85afd4e 1616
f85afd4e 1617
2d66e025
MB
1618 // ------------ Right button down
1619 //
1620 else if ( event.RightDown() )
1621 {
1622 row = YToRow(y);
1623 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
1624 {
1625 // no default action at the moment
f85afd4e
MB
1626 }
1627 }
60ff3b99
VZ
1628
1629
2d66e025 1630 // ------------ Right double click
f85afd4e 1631 //
2d66e025
MB
1632 else if ( event.RightDClick() )
1633 {
1634 row = YToRow(y);
1635 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
1636 {
1637 // no default action at the moment
1638 }
1639 }
60ff3b99
VZ
1640
1641
2d66e025 1642 // ------------ No buttons down and mouse moving
f85afd4e 1643 //
2d66e025 1644 else if ( event.Moving() )
f85afd4e 1645 {
2d66e025
MB
1646 m_dragRowOrCol = YToEdgeOfRow( y );
1647 if ( m_dragRowOrCol >= 0 )
8f177c8e 1648 {
2d66e025 1649 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
8f177c8e 1650 {
2d66e025
MB
1651 m_cursorMode = WXGRID_CURSOR_RESIZE_ROW;
1652 m_rowLabelWin->SetCursor( m_rowResizeCursor );
8f177c8e 1653 }
2d66e025
MB
1654 }
1655 else
1656 {
1657 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
8f177c8e 1658 {
2d66e025
MB
1659 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1660 m_rowLabelWin->SetCursor( *wxSTANDARD_CURSOR );
8f177c8e 1661 }
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;
1785 rect.width = cw - rect.x;
1786 rect.height = m_colLabelHeight;
1787 m_colLabelWin->Refresh( TRUE, &rect );
1788 rect.height = ch;
1789 m_gridWin->Refresh( TRUE, &rect );
2d66e025 1790 }
60ff3b99 1791
2d66e025 1792 ShowCellEditControl();
f85afd4e 1793
2d66e025
MB
1794 // Note: we are ending the event *after* doing
1795 // default processing in this case
1796 //
1797 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
f85afd4e 1798 }
2d66e025 1799 }
f85afd4e 1800
2d66e025 1801 m_dragLastPos = -1;
60ff3b99
VZ
1802 }
1803
1804
2d66e025
MB
1805 // ------------ Right button down
1806 //
1807 else if ( event.RightDown() )
1808 {
1809 col = XToCol(x);
1810 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
1811 {
1812 // no default action at the moment
f85afd4e
MB
1813 }
1814 }
60ff3b99
VZ
1815
1816
2d66e025 1817 // ------------ Right double click
f85afd4e 1818 //
2d66e025
MB
1819 else if ( event.RightDClick() )
1820 {
1821 col = XToCol(x);
1822 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
1823 {
1824 // no default action at the moment
1825 }
1826 }
60ff3b99
VZ
1827
1828
2d66e025 1829 // ------------ No buttons down and mouse moving
f85afd4e 1830 //
2d66e025 1831 else if ( event.Moving() )
f85afd4e 1832 {
2d66e025
MB
1833 m_dragRowOrCol = XToEdgeOfCol( x );
1834 if ( m_dragRowOrCol >= 0 )
f85afd4e 1835 {
2d66e025 1836 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 1837 {
2d66e025
MB
1838 m_cursorMode = WXGRID_CURSOR_RESIZE_COL;
1839 m_colLabelWin->SetCursor( m_colResizeCursor );
f85afd4e 1840 }
2d66e025
MB
1841 }
1842 else
1843 {
1844 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
f85afd4e 1845 {
2d66e025
MB
1846 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1847 m_colLabelWin->SetCursor( *wxSTANDARD_CURSOR );
f85afd4e 1848 }
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 }
f85afd4e 2006 }
f85afd4e
MB
2007}
2008
2009
2d66e025
MB
2010//
2011// ------ interaction with data model
2012//
2013bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
f85afd4e 2014{
2d66e025 2015 switch ( msg.GetId() )
17732cec 2016 {
2d66e025
MB
2017 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
2018 return GetModelValues();
17732cec 2019
2d66e025
MB
2020 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
2021 return SetModelValues();
f85afd4e 2022
2d66e025
MB
2023 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
2024 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
2025 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
2026 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
2027 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
2028 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
2029 return Redimension( msg );
2030
2031 default:
2032 return FALSE;
f85afd4e 2033 }
2d66e025 2034}
f85afd4e 2035
f85afd4e 2036
f85afd4e 2037
2d66e025
MB
2038// The behaviour of this function depends on the grid table class
2039// Clear() function. For the default wxGridStringTable class the
2040// behavious is to replace all cell contents with wxEmptyString but
2041// not to change the number of rows or cols.
2042//
2043void wxGrid::ClearGrid()
2044{
2045 if ( m_table )
f85afd4e 2046 {
2d66e025
MB
2047 m_table->Clear();
2048 SetEditControlValue();
1f1ce288 2049 if ( !GetBatchCount() ) m_gridWin->Refresh();
f85afd4e
MB
2050 }
2051}
2052
2053
2d66e025 2054bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 2055{
2d66e025 2056 // TODO: something with updateLabels flag
8f177c8e 2057
2d66e025 2058 if ( !m_created )
f85afd4e 2059 {
2d66e025
MB
2060 wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2061 return FALSE;
2062 }
8f177c8e 2063
2d66e025
MB
2064 if ( m_table )
2065 {
2066 bool ok = m_table->InsertRows( pos, numRows );
f85afd4e 2067
2d66e025
MB
2068 // the table will have sent the results of the insert row
2069 // operation to this view object as a grid table message
2070 //
2071 if ( ok )
2072 {
2073 if ( m_numCols == 0 )
f85afd4e 2074 {
2d66e025
MB
2075 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
2076 //
2077 // TODO: perhaps instead of appending the default number of cols
2078 // we should remember what the last non-zero number of cols was ?
2079 //
2080 }
8f177c8e 2081
2d66e025
MB
2082 if ( m_currentCellCoords == wxGridNoCellCoords )
2083 {
2084 // if we have just inserted cols into an empty grid the current
2085 // cell will be undefined...
2086 //
2087 SetCurrentCell( 0, 0 );
f85afd4e
MB
2088 }
2089
2d66e025
MB
2090 ClearSelection();
2091 if ( !GetBatchCount() ) Refresh();
f85afd4e 2092 }
2d66e025
MB
2093
2094 SetEditControlValue();
2095 return ok;
2096 }
2097 else
2098 {
2099 return FALSE;
f85afd4e
MB
2100 }
2101}
2102
2103
2d66e025 2104bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 2105{
2d66e025
MB
2106 // TODO: something with updateLabels flag
2107
2108 if ( !m_created )
f85afd4e 2109 {
2d66e025
MB
2110 wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2111 return FALSE;
2112 }
2113
2114 if ( m_table && m_table->AppendRows( numRows ) )
2115 {
2116 if ( m_currentCellCoords == wxGridNoCellCoords )
2117 {
2118 // if we have just inserted cols into an empty grid the current
2119 // cell will be undefined...
2120 //
2121 SetCurrentCell( 0, 0 );
2122 }
2123
2124 // the table will have sent the results of the append row
2125 // operation to this view object as a grid table message
2126 //
2127 ClearSelection();
2128 if ( !GetBatchCount() ) Refresh();
2129 return TRUE;
2130 }
2131 else
2132 {
2133 return FALSE;
f85afd4e
MB
2134 }
2135}
2136
2d66e025
MB
2137
2138bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 2139{
2d66e025
MB
2140 // TODO: something with updateLabels flag
2141
2142 if ( !m_created )
f85afd4e 2143 {
2d66e025
MB
2144 wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2145 return FALSE;
2146 }
2147
2148 if ( m_table && m_table->DeleteRows( pos, numRows ) )
2149 {
2150 // the table will have sent the results of the delete row
2151 // operation to this view object as a grid table message
2152 //
2153 if ( m_numRows > 0 )
2154 SetEditControlValue();
2b37dc19 2155 else
2d66e025 2156 HideCellEditControl();
f85afd4e 2157
2d66e025
MB
2158 ClearSelection();
2159 if ( !GetBatchCount() ) Refresh();
2160 return TRUE;
2161 }
2162 else
2163 {
2164 return FALSE;
2165 }
2166}
f85afd4e 2167
f85afd4e 2168
2d66e025
MB
2169bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2170{
2171 // TODO: something with updateLabels flag
8f177c8e 2172
2d66e025
MB
2173 if ( !m_created )
2174 {
2175 wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2176 return FALSE;
2177 }
f85afd4e 2178
2d66e025
MB
2179 if ( m_table )
2180 {
2181 HideCellEditControl();
2182 bool ok = m_table->InsertCols( pos, numCols );
2183
2184 // the table will have sent the results of the insert col
2185 // operation to this view object as a grid table message
2186 //
2187 if ( ok )
f85afd4e 2188 {
2d66e025 2189 if ( m_currentCellCoords == wxGridNoCellCoords )
f85afd4e 2190 {
2d66e025
MB
2191 // if we have just inserted cols into an empty grid the current
2192 // cell will be undefined...
2193 //
2194 SetCurrentCell( 0, 0 );
f85afd4e 2195 }
2d66e025
MB
2196
2197 ClearSelection();
2198 if ( !GetBatchCount() ) Refresh();
f85afd4e 2199 }
2d66e025
MB
2200
2201 SetEditControlValue();
2202 return ok;
2203 }
2204 else
2205 {
2206 return FALSE;
f85afd4e
MB
2207 }
2208}
2209
2d66e025
MB
2210
2211bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 2212{
2d66e025
MB
2213 // TODO: something with updateLabels flag
2214
2215 if ( !m_created )
f85afd4e 2216 {
2d66e025
MB
2217 wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2218 return FALSE;
2219 }
f85afd4e 2220
2d66e025
MB
2221 if ( m_table && m_table->AppendCols( numCols ) )
2222 {
2223 // the table will have sent the results of the append col
2224 // operation to this view object as a grid table message
2225 //
2226 if ( m_currentCellCoords == wxGridNoCellCoords )
f85afd4e 2227 {
2d66e025
MB
2228 // if we have just inserted cols into an empty grid the current
2229 // cell will be undefined...
2230 //
2231 SetCurrentCell( 0, 0 );
f85afd4e 2232 }
8f177c8e 2233
2d66e025
MB
2234 ClearSelection();
2235 if ( !GetBatchCount() ) Refresh();
2236 return TRUE;
f85afd4e 2237 }
2d66e025 2238 else
f85afd4e 2239 {
2d66e025 2240 return FALSE;
f85afd4e 2241 }
f85afd4e
MB
2242}
2243
2244
2d66e025 2245bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 2246{
2d66e025 2247 // TODO: something with updateLabels flag
8f177c8e 2248
2d66e025 2249 if ( !m_created )
f85afd4e 2250 {
2d66e025
MB
2251 wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2252 return FALSE;
f85afd4e
MB
2253 }
2254
2d66e025
MB
2255 if ( m_table && m_table->DeleteCols( pos, numCols ) )
2256 {
2257 // the table will have sent the results of the delete col
2258 // operation to this view object as a grid table message
2259 //
2260 if ( m_numCols > 0 )
2261 SetEditControlValue();
2262 else
2263 HideCellEditControl();
8f177c8e 2264
2d66e025
MB
2265 ClearSelection();
2266 if ( !GetBatchCount() ) Refresh();
2267 return TRUE;
2268 }
2269 else
f85afd4e 2270 {
2d66e025 2271 return FALSE;
f85afd4e 2272 }
f85afd4e
MB
2273}
2274
2275
2d66e025
MB
2276
2277//
2278// ----- event handlers
f85afd4e 2279//
8f177c8e 2280
2d66e025
MB
2281// Generate a grid event based on a mouse event and
2282// return the result of ProcessEvent()
2283//
2284bool wxGrid::SendEvent( const wxEventType type,
2285 int row, int col,
2286 wxMouseEvent& mouseEv )
2287{
2288 if ( type == EVT_GRID_ROW_SIZE ||
2289 type == EVT_GRID_COL_SIZE )
f85afd4e 2290 {
2d66e025
MB
2291 int rowOrCol = (row == -1 ? col : row);
2292
2293 wxGridSizeEvent gridEvt( GetId(),
2294 type,
2295 this,
2296 rowOrCol,
2297 mouseEv.GetX(), mouseEv.GetY(),
2298 mouseEv.ControlDown(),
2299 mouseEv.ShiftDown(),
2300 mouseEv.AltDown(),
2301 mouseEv.MetaDown() );
2302
2303 return GetEventHandler()->ProcessEvent(gridEvt);
f85afd4e 2304 }
2d66e025
MB
2305 else if ( type == EVT_GRID_RANGE_SELECT )
2306 {
2307 wxGridRangeSelectEvent gridEvt( GetId(),
2308 type,
2309 this,
2310 m_selectedTopLeft,
2311 m_selectedBottomRight,
2312 mouseEv.ControlDown(),
2313 mouseEv.ShiftDown(),
2314 mouseEv.AltDown(),
2315 mouseEv.MetaDown() );
f85afd4e 2316
2d66e025
MB
2317 return GetEventHandler()->ProcessEvent(gridEvt);
2318 }
2319 else
2320 {
2321 wxGridEvent gridEvt( GetId(),
2322 type,
2323 this,
2324 row, col,
2325 mouseEv.GetX(), mouseEv.GetY(),
2326 mouseEv.ControlDown(),
2327 mouseEv.ShiftDown(),
2328 mouseEv.AltDown(),
2329 mouseEv.MetaDown() );
8f177c8e 2330
2d66e025
MB
2331 return GetEventHandler()->ProcessEvent(gridEvt);
2332 }
f85afd4e
MB
2333}
2334
2335
2d66e025
MB
2336// Generate a grid event of specified type and return the result
2337// of ProcessEvent().
f85afd4e 2338//
2d66e025
MB
2339bool wxGrid::SendEvent( const wxEventType type,
2340 int row, int col )
f85afd4e 2341{
2d66e025
MB
2342 if ( type == EVT_GRID_ROW_SIZE ||
2343 type == EVT_GRID_COL_SIZE )
f85afd4e 2344 {
2d66e025 2345 int rowOrCol = (row == -1 ? col : row);
f85afd4e 2346
2d66e025
MB
2347 wxGridSizeEvent gridEvt( GetId(),
2348 type,
2349 this,
2350 rowOrCol );
2351
2352 return GetEventHandler()->ProcessEvent(gridEvt);
2353 }
2354 else
2355 {
2356 wxGridEvent gridEvt( GetId(),
2357 type,
2358 this,
2359 row, col );
8f177c8e 2360
2d66e025
MB
2361 return GetEventHandler()->ProcessEvent(gridEvt);
2362 }
f85afd4e
MB
2363}
2364
2365
2d66e025 2366void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
f85afd4e 2367{
2d66e025 2368 wxPaintDC dc( this );
f85afd4e 2369
2d66e025
MB
2370 if ( m_currentCellCoords == wxGridNoCellCoords &&
2371 m_numRows && m_numCols )
f85afd4e 2372 {
2d66e025
MB
2373 m_currentCellCoords.Set(0, 0);
2374 SetEditControlValue();
2375 ShowCellEditControl();
f85afd4e 2376 }
8f177c8e 2377}
f85afd4e
MB
2378
2379
2d66e025
MB
2380// This is just here to make sure that CalcDimensions gets called when
2381// the grid view is resized... then the size event is skipped to allow
2382// the box sizers to handle everything
2383//
2384void wxGrid::OnSize( wxSizeEvent& event )
f85afd4e 2385{
2d66e025
MB
2386 CalcDimensions();
2387 event.Skip();
f85afd4e
MB
2388}
2389
f85afd4e 2390
2d66e025 2391void wxGrid::OnKeyDown( wxKeyEvent& event )
f85afd4e 2392{
2d66e025 2393 if ( m_inOnKeyDown )
f85afd4e 2394 {
2d66e025
MB
2395 // shouldn't be here - we are going round in circles...
2396 //
2397 wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") );
f85afd4e
MB
2398 }
2399
2d66e025 2400 m_inOnKeyDown = TRUE;
f85afd4e 2401
2d66e025
MB
2402 // propagate the event up and see if it gets processed
2403 //
2404 wxWindow *parent = GetParent();
2405 wxKeyEvent keyEvt( event );
2406 keyEvt.SetEventObject( parent );
2407
2408 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
f85afd4e 2409 {
2d66e025
MB
2410 // try local handlers
2411 //
2412 switch ( event.KeyCode() )
2413 {
2414 case WXK_UP:
2415 if ( event.ControlDown() )
2416 {
2417 MoveCursorUpBlock();
2418 }
2419 else
2420 {
2421 MoveCursorUp();
2422 }
2423 break;
f85afd4e 2424
2d66e025
MB
2425 case WXK_DOWN:
2426 if ( event.ControlDown() )
2427 {
2428 MoveCursorDownBlock();
2429 }
2430 else
2431 {
2432 MoveCursorDown();
2433 }
2434 break;
8f177c8e 2435
2d66e025
MB
2436 case WXK_LEFT:
2437 if ( event.ControlDown() )
2438 {
2439 MoveCursorLeftBlock();
2440 }
2441 else
2442 {
2443 MoveCursorLeft();
2444 }
2445 break;
2446
2447 case WXK_RIGHT:
2448 if ( event.ControlDown() )
2449 {
2450 MoveCursorRightBlock();
2451 }
2452 else
2453 {
2454 MoveCursorRight();
2455 }
2456 break;
f603012f
MB
2457
2458 case WXK_SPACE:
2459 if ( !IsEditable() )
2460 {
2461 MoveCursorRight();
2462 }
2463 else
2464 {
8a9a9d58 2465 event.Skip();
f603012f 2466 }
8febdd39 2467 break;
2d66e025
MB
2468
2469 case WXK_RETURN:
58dd5b3b
MB
2470 if ( event.ControlDown() )
2471 {
2472 event.Skip(); // to let the edit control have the return
2473 }
2474 else
2475 {
2476 MoveCursorDown();
2477 }
2d66e025
MB
2478 break;
2479
2480 case WXK_HOME:
2481 if ( event.ControlDown() )
2482 {
2483 MakeCellVisible( 0, 0 );
2484 SetCurrentCell( 0, 0 );
2485 }
2486 else
2487 {
2488 event.Skip();
2489 }
2490 break;
2491
2492 case WXK_END:
2493 if ( event.ControlDown() )
2494 {
2495 MakeCellVisible( m_numRows-1, m_numCols-1 );
2496 SetCurrentCell( m_numRows-1, m_numCols-1 );
2497 }
2498 else
2499 {
2500 event.Skip();
2501 }
2502 break;
2503
2504 case WXK_PRIOR:
2505 MovePageUp();
2506 break;
2507
2508 case WXK_NEXT:
2509 MovePageDown();
2510 break;
2511
2512 default:
2513 // now try the cell edit control
2514 //
2515 if ( IsCellEditControlEnabled() )
2516 {
2517 event.SetEventObject( m_cellEditCtrl );
2518 m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
2519 }
2520 break;
2521 }
f85afd4e
MB
2522 }
2523
2d66e025 2524 m_inOnKeyDown = FALSE;
f85afd4e
MB
2525}
2526
2d66e025
MB
2527
2528void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
66242c80 2529{
2d66e025 2530 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
66242c80 2531 {
2d66e025
MB
2532 // the event has been intercepted - do nothing
2533 return;
2534 }
66242c80 2535
2d66e025
MB
2536 wxClientDC dc( m_gridWin );
2537 PrepareDC( dc );
2538
2539 if ( m_currentCellCoords != wxGridNoCellCoords )
2540 {
2d66e025
MB
2541 HideCellEditControl();
2542 SaveEditControlValue();
66242c80 2543 }
8f177c8e 2544
2d66e025
MB
2545 m_currentCellCoords = coords;
2546
2547 SetEditControlValue();
2548 ShowCellEditControl();
2d66e025
MB
2549
2550 if ( IsSelection() )
2551 {
2552 wxRect r( SelectionToDeviceRect() );
2553 ClearSelection();
2554 if ( !GetBatchCount() ) m_gridWin->Refresh( TRUE, &r );
2555 }
66242c80
MB
2556}
2557
2d66e025
MB
2558
2559//
2560// ------ functions to get/send data (see also public functions)
2561//
2562
2563bool wxGrid::GetModelValues()
66242c80 2564{
2d66e025 2565 if ( m_table )
66242c80 2566 {
2d66e025 2567 // all we need to do is repaint the grid
66242c80 2568 //
2d66e025 2569 m_gridWin->Refresh();
66242c80
MB
2570 return TRUE;
2571 }
8f177c8e 2572
66242c80
MB
2573 return FALSE;
2574}
2575
2d66e025
MB
2576
2577bool wxGrid::SetModelValues()
f85afd4e 2578{
2d66e025 2579 int row, col;
8f177c8e 2580
2d66e025
MB
2581 if ( m_table )
2582 {
2583 for ( row = 0; row < m_numRows; row++ )
f85afd4e 2584 {
2d66e025 2585 for ( col = 0; col < m_numCols; col++ )
f85afd4e 2586 {
2d66e025 2587 m_table->SetValue( row, col, GetCellValue(row, col) );
f85afd4e
MB
2588 }
2589 }
8f177c8e 2590
f85afd4e
MB
2591 return TRUE;
2592 }
2593
2594 return FALSE;
2595}
2596
2d66e025
MB
2597
2598
2599// Note - this function only draws cells that are in the list of
2600// exposed cells (usually set from the update region by
2601// CalcExposedCells)
2602//
2603void wxGrid::DrawGridCellArea( wxDC& dc )
f85afd4e 2604{
2d66e025 2605 if ( !m_numRows || !m_numCols ) return;
60ff3b99 2606
2d66e025
MB
2607 size_t i;
2608 size_t numCells = m_cellsExposed.GetCount();
60ff3b99 2609
2d66e025 2610 for ( i = 0; i < numCells; i++ )
f85afd4e 2611 {
2d66e025
MB
2612 DrawCell( dc, m_cellsExposed[i] );
2613 }
2614}
8f177c8e 2615
8f177c8e 2616
2d66e025
MB
2617void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
2618{
2619 if ( m_colWidths[coords.GetCol()] <=0 ||
2620 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2621
796df70a 2622#if !DRAW_LINES
2d66e025
MB
2623 if ( m_gridLinesEnabled )
2624 DrawCellBorder( dc, coords );
796df70a 2625#endif
f85afd4e 2626
2d66e025 2627 DrawCellBackground( dc, coords );
f85afd4e 2628
2d66e025
MB
2629 // TODO: separate functions here for different kinds of cells ?
2630 // e.g. text, image
2631 //
2632 DrawCellValue( dc, coords );
2633}
f85afd4e 2634
2d66e025
MB
2635
2636void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
2637{
2638 if ( m_colWidths[coords.GetCol()] <=0 ||
2639 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2640
2d66e025
MB
2641 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
2642 int row = coords.GetRow();
2643 int col = coords.GetCol();
60ff3b99 2644
2d66e025
MB
2645 // right hand border
2646 //
2647 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
2648 m_colRights[col], m_rowBottoms[row] );
2649
2650 // bottom border
2651 //
2652 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
2653 m_colRights[col], m_rowBottoms[row] );
f85afd4e
MB
2654}
2655
2d66e025
MB
2656
2657void wxGrid::DrawCellBackground( wxDC& dc, const wxGridCellCoords& coords )
f85afd4e 2658{
2d66e025
MB
2659 if ( m_colWidths[coords.GetCol()] <=0 ||
2660 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2661
2d66e025
MB
2662 int row = coords.GetRow();
2663 int col = coords.GetCol();
8f177c8e 2664
2d66e025 2665 dc.SetBackgroundMode( wxSOLID );
f85afd4e 2666
2d66e025
MB
2667 if ( IsInSelection( coords ) )
2668 {
2669 // TODO: improve this
2670 //
2671 dc.SetBrush( *wxBLACK_BRUSH );
f85afd4e 2672 }
2d66e025 2673 else
f85afd4e 2674 {
2d66e025 2675 dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
f85afd4e
MB
2676 }
2677
2d66e025 2678 dc.SetPen( *wxTRANSPARENT_PEN );
8f177c8e 2679
2d66e025
MB
2680 dc.DrawRectangle( m_colRights[col] - m_colWidths[col] + 1,
2681 m_rowBottoms[row] - m_rowHeights[row] + 1,
2682 m_colWidths[col]-1,
2683 m_rowHeights[row]-1 );
f85afd4e
MB
2684}
2685
2686
2d66e025 2687void wxGrid::DrawCellValue( wxDC& dc, const wxGridCellCoords& coords )
f85afd4e 2688{
2d66e025
MB
2689 if ( m_colWidths[coords.GetCol()] <=0 ||
2690 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 2691
2d66e025
MB
2692 int row = coords.GetRow();
2693 int col = coords.GetCol();
f85afd4e 2694
2d66e025 2695 dc.SetBackgroundMode( wxTRANSPARENT );
8f177c8e 2696
2d66e025
MB
2697 if ( IsInSelection( row, col ) )
2698 {
2699 // TODO: improve this
2700 //
2701 dc.SetTextBackground( wxColour(0, 0, 0) );
2702 dc.SetTextForeground( wxColour(255, 255, 255) );
2703 }
2704 else
f85afd4e 2705 {
2d66e025
MB
2706 dc.SetTextBackground( GetCellBackgroundColour(row, col) );
2707 dc.SetTextForeground( GetCellTextColour(row, col) );
2708 }
2709 dc.SetFont( GetCellFont(row, col) );
f85afd4e 2710
2d66e025
MB
2711 int hAlign, vAlign;
2712 GetCellAlignment( row, col, &hAlign, &vAlign );
8f177c8e 2713
2d66e025
MB
2714 wxRect rect;
2715 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
2716 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
2717 rect.SetWidth( m_colWidths[col] - 4 );
2718 rect.SetHeight( m_rowHeights[row] - 4 );
60ff3b99 2719
2d66e025 2720 DrawTextRectangle( dc, GetCellValue( row, col ), rect, hAlign, vAlign );
f85afd4e
MB
2721}
2722
2723
2d66e025
MB
2724
2725// TODO: remove this ???
2726// This is used to redraw all grid lines e.g. when the grid line colour
2727// has been changed
2728//
796df70a 2729void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
f85afd4e 2730{
60ff3b99
VZ
2731 if ( !m_gridLinesEnabled ||
2732 !m_numRows ||
2d66e025 2733 !m_numCols ) return;
f85afd4e 2734
2d66e025 2735 int top, bottom, left, right;
796df70a
SN
2736
2737 if (reg.IsEmpty()){
2738 int cw, ch;
2739 m_gridWin->GetClientSize(&cw, &ch);
2740
2741 // virtual coords of visible area
2742 //
2743 CalcUnscrolledPosition( 0, 0, &left, &top );
2744 CalcUnscrolledPosition( cw, ch, &right, &bottom );
2745 }
2746 else{
2747 wxCoord x, y, w, h;
2748 reg.GetBox(x, y, w, h);
2749 CalcUnscrolledPosition( x, y, &left, &top );
2750 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
2751 }
f85afd4e 2752
2d66e025 2753 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
f85afd4e 2754
2d66e025 2755 // horizontal grid lines
f85afd4e 2756 //
60ff3b99 2757 int i;
2d66e025 2758 for ( i = 0; i <= m_numRows; i++ )
f85afd4e 2759 {
2d66e025
MB
2760 if ( m_rowBottoms[i] > bottom )
2761 {
2762 break;
2763 }
2764 else if ( m_rowBottoms[i] >= top )
2765 {
2766 dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] );
2767 }
f85afd4e
MB
2768 }
2769
f85afd4e 2770
2d66e025
MB
2771 // vertical grid lines
2772 //
2773 for ( i = 0; i <= m_numCols; i++ )
f85afd4e 2774 {
2d66e025
MB
2775 if ( m_colRights[i] > right )
2776 {
2777 break;
2778 }
2779 else if ( m_colRights[i] >= left )
2780 {
2781 dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom );
2782 }
2783 }
2784}
f85afd4e 2785
8f177c8e 2786
2d66e025
MB
2787void wxGrid::DrawRowLabels( wxDC& dc )
2788{
2789 if ( !m_numRows || !m_numCols ) return;
60ff3b99 2790
2d66e025
MB
2791 size_t i;
2792 size_t numLabels = m_rowLabelsExposed.GetCount();
60ff3b99 2793
2d66e025
MB
2794 for ( i = 0; i < numLabels; i++ )
2795 {
2796 DrawRowLabel( dc, m_rowLabelsExposed[i] );
60ff3b99 2797 }
f85afd4e
MB
2798}
2799
2800
2d66e025 2801void wxGrid::DrawRowLabel( wxDC& dc, int row )
f85afd4e 2802{
2d66e025 2803 if ( m_rowHeights[row] <= 0 ) return;
60ff3b99 2804
2d66e025
MB
2805 // draw the label's horizontal border (the vertical border is
2806 // provided by the cell area window margin)
2807 //
2808 dc.SetPen( *wxBLACK_PEN );
8f177c8e 2809
2d66e025
MB
2810 dc.DrawLine( 0, m_rowBottoms[row]+1,
2811 m_rowLabelWidth, m_rowBottoms[row]+1 );
2812
2813 dc.SetPen( *wxWHITE_PEN );
2814
2815 dc.DrawLine( 0, m_rowBottoms[row]+2,
2816 m_rowLabelWidth, m_rowBottoms[row]+2 );
60ff3b99 2817
f85afd4e 2818 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
2819 dc.SetTextForeground( GetLabelTextColour() );
2820 dc.SetFont( GetLabelFont() );
8f177c8e 2821
f85afd4e 2822 int hAlign, vAlign;
2d66e025 2823 GetRowLabelAlignment( &hAlign, &vAlign );
60ff3b99 2824
2d66e025
MB
2825 wxRect rect;
2826 rect.SetX( 2 );
2827 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
2828 rect.SetWidth( m_rowLabelWidth - 4 );
2829 rect.SetHeight( m_rowHeights[row] - 4 );
60ff3b99 2830 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
f85afd4e
MB
2831}
2832
2833
2d66e025 2834void wxGrid::DrawColLabels( wxDC& dc )
f85afd4e 2835{
2d66e025 2836 if ( !m_numRows || !m_numCols ) return;
60ff3b99 2837
2d66e025
MB
2838 size_t i;
2839 size_t numLabels = m_colLabelsExposed.GetCount();
60ff3b99 2840
2d66e025 2841 for ( i = 0; i < numLabels; i++ )
f85afd4e 2842 {
2d66e025 2843 DrawColLabel( dc, m_colLabelsExposed[i] );
60ff3b99 2844 }
f85afd4e
MB
2845}
2846
2847
2d66e025 2848void wxGrid::DrawColLabel( wxDC& dc, int col )
f85afd4e 2849{
2d66e025 2850 if ( m_colWidths[col] <= 0 ) return;
60ff3b99 2851
2d66e025
MB
2852 // draw the label's vertical border (the horizontal border is
2853 // provided by the cell area window margin)
f85afd4e 2854 //
2d66e025 2855 dc.SetPen( *wxBLACK_PEN );
f85afd4e 2856
2d66e025
MB
2857 dc.DrawLine( m_colRights[col]+1, 0,
2858 m_colRights[col]+1, m_colLabelHeight );
f85afd4e 2859
f85afd4e
MB
2860 dc.SetPen( *wxWHITE_PEN );
2861
2d66e025
MB
2862 dc.DrawLine( m_colRights[col]+2, 0,
2863 m_colRights[col]+2, m_colLabelHeight );
8f177c8e 2864
f85afd4e 2865 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
2866 dc.SetTextForeground( GetLabelTextColour() );
2867 dc.SetFont( GetLabelFont() );
8f177c8e 2868
f85afd4e 2869 int hAlign, vAlign;
2d66e025 2870 GetColLabelAlignment( &hAlign, &vAlign );
60ff3b99 2871
2d66e025
MB
2872 wxRect rect;
2873 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
2874 rect.SetY( 2 );
2875 rect.SetWidth( m_colWidths[col] - 4 );
2876 rect.SetHeight( m_colLabelHeight - 4 );
60ff3b99 2877 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
f85afd4e
MB
2878}
2879
2880
2d66e025
MB
2881void wxGrid::DrawTextRectangle( wxDC& dc,
2882 const wxString& value,
2883 const wxRect& rect,
2884 int horizAlign,
2885 int vertAlign )
f85afd4e 2886{
2d66e025
MB
2887 long textWidth, textHeight;
2888 long lineWidth, lineHeight;
2889 wxArrayString lines;
f85afd4e 2890
2d66e025
MB
2891 dc.SetClippingRegion( rect );
2892 StringToLines( value, lines );
2893 if ( lines.GetCount() )
2894 {
2895 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
2896 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
f85afd4e 2897
2d66e025
MB
2898 float x, y;
2899 switch ( horizAlign )
2900 {
2901 case wxRIGHT:
2902 x = rect.x + (rect.width - textWidth - 1);
2903 break;
f85afd4e 2904
2d66e025
MB
2905 case wxCENTRE:
2906 x = rect.x + ((rect.width - textWidth)/2);
2907 break;
f85afd4e 2908
2d66e025
MB
2909 case wxLEFT:
2910 default:
2911 x = rect.x + 1;
2912 break;
2913 }
f85afd4e 2914
2d66e025
MB
2915 switch ( vertAlign )
2916 {
2917 case wxBOTTOM:
2918 y = rect.y + (rect.height - textHeight - 1);
2919 break;
f85afd4e
MB
2920
2921 case wxCENTRE:
8f177c8e 2922 y = rect.y + ((rect.height - textHeight)/2);
f85afd4e
MB
2923 break;
2924
2925 case wxTOP:
2926 default:
8f177c8e 2927 y = rect.y + 1;
f85afd4e
MB
2928 break;
2929 }
2930
b540eb2b 2931 for ( size_t i = 0; i < lines.GetCount(); i++ )
f85afd4e
MB
2932 {
2933 dc.DrawText( lines[i], (long)x, (long)y );
2934 y += lineHeight;
2935 }
2936 }
8f177c8e 2937
f85afd4e 2938 dc.DestroyClippingRegion();
f85afd4e
MB
2939}
2940
2941
2942// Split multi line text up into an array of strings. Any existing
2943// contents of the string array are preserved.
2944//
2945void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
2946{
2947 // TODO: this won't work for WXMAC ? (lines end with '\r')
b540eb2b 2948 // => use wxTextFile functions then (VZ)
f85afd4e
MB
2949 int startPos = 0;
2950 int pos;
b540eb2b 2951 while ( startPos < (int)value.Length() )
f85afd4e
MB
2952 {
2953 pos = value.Mid(startPos).Find( '\n' );
2954 if ( pos < 0 )
2955 {
2956 break;
2957 }
2958 else if ( pos == 0 )
2959 {
2960 lines.Add( wxEmptyString );
2961 }
2962 else
2963 {
2964 if ( value[startPos+pos-1] == '\r' )
2965 {
2966 lines.Add( value.Mid(startPos, pos-1) );
2967 }
2968 else
2969 {
2970 lines.Add( value.Mid(startPos, pos) );
2971 }
2972 }
2973 startPos += pos+1;
2974 }
b540eb2b 2975 if ( startPos < (int)value.Length() )
f85afd4e
MB
2976 {
2977 lines.Add( value.Mid( startPos ) );
2978 }
2979}
2980
2981
2982void wxGrid::GetTextBoxSize( wxDC& dc,
2983 wxArrayString& lines,
2984 long *width, long *height )
2985{
2986 long w = 0;
2987 long h = 0;
2988 long lineW, lineH;
2989
b540eb2b 2990 size_t i;
f85afd4e
MB
2991 for ( i = 0; i < lines.GetCount(); i++ )
2992 {
2993 dc.GetTextExtent( lines[i], &lineW, &lineH );
2994 w = wxMax( w, lineW );
2995 h += lineH;
2996 }
2997
2998 *width = w;
2999 *height = h;
3000}
3001
3002
3003//
2d66e025 3004// ------ Edit control functions
f85afd4e
MB
3005//
3006
2d66e025
MB
3007
3008void wxGrid::EnableEditing( bool edit )
f85afd4e 3009{
2d66e025
MB
3010 // TODO: improve this ?
3011 //
3012 if ( edit != m_editable )
f85afd4e 3013 {
2d66e025 3014 m_editable = edit;
1f1ce288
MB
3015
3016 // TODO: extend this for other edit control types
3017 //
3018 if ( m_editCtrlType == wxGRID_TEXTCTRL )
3019 {
3020 ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable );
3021 }
f85afd4e 3022 }
f85afd4e
MB
3023}
3024
3025
1f1ce288 3026#if 0 // disabled for the moment - the cell control is always active
2d66e025 3027void wxGrid::EnableCellEditControl( bool enable )
f85afd4e 3028{
2d66e025
MB
3029 if ( m_cellEditCtrl &&
3030 enable != m_cellEditCtrlEnabled )
f85afd4e 3031 {
2d66e025 3032 m_cellEditCtrlEnabled = enable;
60ff3b99 3033
2d66e025 3034 if ( m_cellEditCtrlEnabled )
f85afd4e 3035 {
2d66e025
MB
3036 SetEditControlValue();
3037 ShowCellEditControl();
2d66e025
MB
3038 }
3039 else
3040 {
2d66e025
MB
3041 HideCellEditControl();
3042 SaveEditControlValue();
f85afd4e 3043 }
f85afd4e 3044 }
f85afd4e 3045}
1f1ce288 3046#endif
f85afd4e
MB
3047
3048
2d66e025 3049void wxGrid::ShowCellEditControl()
f85afd4e 3050{
2d66e025
MB
3051 wxRect rect;
3052
3053 if ( IsCellEditControlEnabled() )
f85afd4e 3054 {
2d66e025
MB
3055 if ( !IsVisible( m_currentCellCoords ) )
3056 {
3057 return;
3058 }
3059 else
3060 {
3061 rect = CellToRect( m_currentCellCoords );
3062
3063 // convert to scrolled coords
3064 //
3065 int left, top, right, bottom;
3066 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
3067 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
60ff3b99 3068
2d66e025
MB
3069 int cw, ch;
3070 m_gridWin->GetClientSize( &cw, &ch );
1f1ce288
MB
3071
3072 // Make the edit control large enough to allow for internal margins
3073 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3074 //
58dd5b3b 3075 int extra;
d2fdd8d2 3076#if defined(__WXMOTIF__)
58dd5b3b
MB
3077 if ( m_currentCellCoords.GetRow() == 0 ||
3078 m_currentCellCoords.GetCol() == 0 )
3079 {
3080 extra = 2;
3081 }
3082 else
3083 {
3084 extra = 4;
3085 }
1f1ce288 3086#else
58dd5b3b
MB
3087 if ( m_currentCellCoords.GetRow() == 0 ||
3088 m_currentCellCoords.GetCol() == 0 )
3089 {
3090 extra = 1;
3091 }
3092 else
3093 {
3094 extra = 2;
3095 }
1f1ce288 3096#endif
d2fdd8d2
RR
3097
3098#if defined(__WXGTK__)
3099 int top_diff = 0;
3100 int left_diff = 0;
3101 if (left != 0) left_diff++;
3102 if (top != 0) top_diff++;
3103 rect.SetLeft( left + left_diff );
3104 rect.SetTop( top + top_diff );
3105 rect.SetRight( rect.GetRight() - left_diff );
3106 rect.SetBottom( rect.GetBottom() - top_diff );
3107#else
58dd5b3b
MB
3108 rect.SetLeft( wxMax(0, left - extra) );
3109 rect.SetTop( wxMax(0, top - extra) );
3110 rect.SetRight( rect.GetRight() + 2*extra );
3111 rect.SetBottom( rect.GetBottom() + 2*extra );
d2fdd8d2 3112#endif
f0102d2a 3113
2d66e025
MB
3114 m_cellEditCtrl->SetSize( rect );
3115 m_cellEditCtrl->Show( TRUE );
3116
3117 switch ( m_editCtrlType )
3118 {
3119 case wxGRID_TEXTCTRL:
3120 ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
3121 break;
3122
3123 case wxGRID_CHECKBOX:
3124 // TODO: anything ???
3125 //
3126 break;
3127
3128 case wxGRID_CHOICE:
3129 // TODO: anything ???
3130 //
3131 break;
3132
3133 case wxGRID_COMBOBOX:
3134 // TODO: anything ???
3135 //
3136 break;
3137 }
3138
3139 m_cellEditCtrl->SetFocus();
3140 }
f85afd4e
MB
3141 }
3142}
3143
3144
2d66e025 3145void wxGrid::HideCellEditControl()
f85afd4e 3146{
2d66e025 3147 if ( IsCellEditControlEnabled() )
f85afd4e 3148 {
2d66e025 3149 m_cellEditCtrl->Show( FALSE );
f85afd4e 3150 }
2d66e025 3151}
8f177c8e 3152
2d66e025
MB
3153
3154void wxGrid::SetEditControlValue( const wxString& value )
3155{
f85afd4e
MB
3156 if ( m_table )
3157 {
2d66e025
MB
3158 wxString s;
3159 if ( !value )
3160 s = GetCellValue(m_currentCellCoords);
3161 else
3162 s = value;
f85afd4e 3163
2d66e025
MB
3164 if ( IsCellEditControlEnabled() )
3165 {
3166 switch ( m_editCtrlType )
3f296516 3167 {
2d66e025
MB
3168 case wxGRID_TEXTCTRL:
3169 ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
3170 break;
8f177c8e 3171
2d66e025
MB
3172 case wxGRID_CHECKBOX:
3173 // TODO: implement this
3174 //
3175 break;
3f296516 3176
2d66e025
MB
3177 case wxGRID_CHOICE:
3178 // TODO: implement this
3179 //
3180 break;
3181
3182 case wxGRID_COMBOBOX:
3183 // TODO: implement this
3184 //
3185 break;
3186 }
3187 }
f85afd4e
MB
3188 }
3189}
3190
8f177c8e 3191
2d66e025
MB
3192void wxGrid::SaveEditControlValue()
3193{
3194 if ( m_table )
f85afd4e 3195 {
2d66e025 3196 wxWindow *ctrl = (wxWindow *)NULL;
8f177c8e 3197
2d66e025 3198 if ( IsCellEditControlEnabled() )
3f296516 3199 {
2d66e025
MB
3200 ctrl = m_cellEditCtrl;
3201 }
2d66e025
MB
3202 else
3203 {
3204 return;
3f296516 3205 }
8f177c8e 3206
2d66e025
MB
3207 bool valueChanged = FALSE;
3208
3209 switch ( m_editCtrlType )
3210 {
3211 case wxGRID_TEXTCTRL:
3212 valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() !=
3213 ((wxGridTextCtrl *)ctrl)->GetStartValue());
3214 SetCellValue( m_currentCellCoords,
3215 ((wxTextCtrl *) ctrl)->GetValue() );
3216 break;
3217
3218 case wxGRID_CHECKBOX:
3219 // TODO: implement this
3220 //
3221 break;
3222
3223 case wxGRID_CHOICE:
3224 // TODO: implement this
3225 //
3226 break;
3227
3228 case wxGRID_COMBOBOX:
3229 // TODO: implement this
3230 //
3231 break;
3232 }
3233
3234 if ( valueChanged )
3235 {
3236 SendEvent( EVT_GRID_CELL_CHANGE,
3237 m_currentCellCoords.GetRow(),
3238 m_currentCellCoords.GetCol() );
3239 }
f85afd4e
MB
3240 }
3241}
3242
2d66e025
MB
3243
3244//
60ff3b99
VZ
3245// ------ Grid location functions
3246// Note that all of these functions work with the logical coordinates of
2d66e025
MB
3247// grid cells and labels so you will need to convert from device
3248// coordinates for mouse events etc.
3249//
3250
3251void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
f85afd4e 3252{
58dd5b3b
MB
3253 int row = YToRow(y);
3254 int col = XToCol(x);
3255
3256 if ( row == -1 || col == -1 )
3257 {
3258 coords = wxGridNoCellCoords;
3259 }
3260 else
3261 {
3262 coords.Set( row, col );
3263 }
2d66e025 3264}
f85afd4e 3265
8f177c8e 3266
2d66e025
MB
3267int wxGrid::YToRow( int y )
3268{
3269 int i;
8f177c8e 3270
2d66e025 3271 for ( i = 0; i < m_numRows; i++ )
f85afd4e 3272 {
2d66e025 3273 if ( y < m_rowBottoms[i] ) return i;
f85afd4e 3274 }
2d66e025
MB
3275
3276 return -1;
f85afd4e
MB
3277}
3278
2d66e025
MB
3279
3280int wxGrid::XToCol( int x )
f85afd4e 3281{
2d66e025 3282 int i;
8f177c8e 3283
2d66e025 3284 for ( i = 0; i < m_numCols; i++ )
f85afd4e 3285 {
2d66e025 3286 if ( x < m_colRights[i] ) return i;
f85afd4e
MB
3287 }
3288
2d66e025
MB
3289 return -1;
3290}
8f177c8e 3291
2d66e025
MB
3292
3293// return the row number that that the y coord is near the edge of, or
3294// -1 if not near an edge
3295//
3296int wxGrid::YToEdgeOfRow( int y )
3297{
3298 int i, d;
3299
3300 for ( i = 0; i < m_numRows; i++ )
3301 {
3302 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
f85afd4e 3303 {
2d66e025 3304 d = abs( y - m_rowBottoms[i] );
3f296516 3305 {
2d66e025 3306 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3f296516 3307 }
f85afd4e 3308 }
f85afd4e 3309 }
2d66e025
MB
3310
3311 return -1;
3312}
3313
3314
3315// return the col number that that the x coord is near the edge of, or
3316// -1 if not near an edge
3317//
3318int wxGrid::XToEdgeOfCol( int x )
3319{
3320 int i, d;
3321
3322 for ( i = 0; i < m_numCols; i++ )
f85afd4e 3323 {
2d66e025
MB
3324 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
3325 {
3326 d = abs( x - m_colRights[i] );
3327 {
3328 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3329 }
3330 }
f85afd4e 3331 }
2d66e025
MB
3332
3333 return -1;
f85afd4e
MB
3334}
3335
2d66e025
MB
3336
3337wxRect wxGrid::CellToRect( int row, int col )
f85afd4e 3338{
2d66e025 3339 wxRect rect( -1, -1, -1, -1 );
f85afd4e 3340
2d66e025
MB
3341 if ( row >= 0 && row < m_numRows &&
3342 col >= 0 && col < m_numCols )
f85afd4e 3343 {
2d66e025
MB
3344 rect.x = m_colRights[col] - m_colWidths[col];
3345 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3346 rect.width = m_colWidths[col];
3347 rect.height = m_rowHeights[ row ];
f85afd4e
MB
3348 }
3349
2d66e025
MB
3350 return rect;
3351}
3352
3353
3354bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
3355{
3356 // get the cell rectangle in logical coords
3357 //
3358 wxRect r( CellToRect( row, col ) );
60ff3b99 3359
2d66e025
MB
3360 // convert to device coords
3361 //
3362 int left, top, right, bottom;
3363 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3364 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 3365
2d66e025
MB
3366 // check against the client area of the grid window
3367 //
3368 int cw, ch;
3369 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3370
2d66e025 3371 if ( wholeCellVisible )
f85afd4e 3372 {
2d66e025 3373 // is the cell wholly visible ?
8f177c8e 3374 //
2d66e025
MB
3375 return ( left >= 0 && right <= cw &&
3376 top >= 0 && bottom <= ch );
3377 }
3378 else
3379 {
3380 // is the cell partly visible ?
3381 //
3382 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
3383 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
3384 }
3385}
3386
3387
3388// make the specified cell location visible by doing a minimal amount
3389// of scrolling
3390//
3391void wxGrid::MakeCellVisible( int row, int col )
3392{
3393 int i;
60ff3b99 3394 int xpos = -1, ypos = -1;
2d66e025
MB
3395
3396 if ( row >= 0 && row < m_numRows &&
3397 col >= 0 && col < m_numCols )
3398 {
3399 // get the cell rectangle in logical coords
3400 //
3401 wxRect r( CellToRect( row, col ) );
60ff3b99 3402
2d66e025
MB
3403 // convert to device coords
3404 //
3405 int left, top, right, bottom;
3406 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3407 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 3408
2d66e025
MB
3409 int cw, ch;
3410 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3411
2d66e025 3412 if ( top < 0 )
3f296516 3413 {
2d66e025 3414 ypos = r.GetTop();
3f296516 3415 }
2d66e025
MB
3416 else if ( bottom > ch )
3417 {
3418 int h = r.GetHeight();
3419 ypos = r.GetTop();
3420 for ( i = row-1; i >= 0; i-- )
3421 {
3422 if ( h + m_rowHeights[i] > ch ) break;
3423
3424 h += m_rowHeights[i];
3425 ypos -= m_rowHeights[i];
3426 }
f0102d2a
VZ
3427
3428 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3429 // have rounding errors (this is important, because if we do, we
3430 // might not scroll at all and some cells won't be redrawn)
3431 ypos += GRID_SCROLL_LINE / 2;
2d66e025
MB
3432 }
3433
3434 if ( left < 0 )
3435 {
3436 xpos = r.GetLeft();
3437 }
3438 else if ( right > cw )
3439 {
3440 int w = r.GetWidth();
3441 xpos = r.GetLeft();
3442 for ( i = col-1; i >= 0; i-- )
3443 {
3444 if ( w + m_colWidths[i] > cw ) break;
3445
3446 w += m_colWidths[i];
3447 xpos -= m_colWidths[i];
3448 }
f0102d2a
VZ
3449
3450 // see comment for ypos above
3451 xpos += GRID_SCROLL_LINE / 2;
2d66e025
MB
3452 }
3453
3454 if ( xpos != -1 || ypos != -1 )
3455 {
f0102d2a
VZ
3456 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
3457 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
2d66e025
MB
3458 Scroll( xpos, ypos );
3459 AdjustScrollbars();
3460 }
3461 }
3462}
3463
3464
3465//
3466// ------ Grid cursor movement functions
3467//
3468
3469bool wxGrid::MoveCursorUp()
3470{
3471 if ( m_currentCellCoords != wxGridNoCellCoords &&
3472 m_currentCellCoords.GetRow() > 0 )
3473 {
3474 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
3475 m_currentCellCoords.GetCol() );
60ff3b99 3476
2d66e025
MB
3477 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
3478 m_currentCellCoords.GetCol() );
3479
8f177c8e 3480 return TRUE;
f85afd4e 3481 }
2d66e025
MB
3482
3483 return FALSE;
3484}
3485
3486
3487bool wxGrid::MoveCursorDown()
3488{
3489 // TODO: allow for scrolling
3490 //
3491 if ( m_currentCellCoords != wxGridNoCellCoords &&
3492 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 3493 {
2d66e025
MB
3494 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
3495 m_currentCellCoords.GetCol() );
60ff3b99 3496
2d66e025
MB
3497 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
3498 m_currentCellCoords.GetCol() );
3499
3500 return TRUE;
f85afd4e 3501 }
2d66e025
MB
3502
3503 return FALSE;
f85afd4e
MB
3504}
3505
2d66e025
MB
3506
3507bool wxGrid::MoveCursorLeft()
f85afd4e 3508{
2d66e025
MB
3509 if ( m_currentCellCoords != wxGridNoCellCoords &&
3510 m_currentCellCoords.GetCol() > 0 )
3511 {
3512 MakeCellVisible( m_currentCellCoords.GetRow(),
3513 m_currentCellCoords.GetCol() - 1 );
60ff3b99 3514
2d66e025
MB
3515 SetCurrentCell( m_currentCellCoords.GetRow(),
3516 m_currentCellCoords.GetCol() - 1 );
8f177c8e 3517
2d66e025
MB
3518 return TRUE;
3519 }
3520
3521 return FALSE;
3522}
3523
3524
3525bool wxGrid::MoveCursorRight()
3526{
3527 if ( m_currentCellCoords != wxGridNoCellCoords &&
3528 m_currentCellCoords.GetCol() < m_numCols - 1 )
f85afd4e 3529 {
2d66e025
MB
3530 MakeCellVisible( m_currentCellCoords.GetRow(),
3531 m_currentCellCoords.GetCol() + 1 );
60ff3b99 3532
2d66e025
MB
3533 SetCurrentCell( m_currentCellCoords.GetRow(),
3534 m_currentCellCoords.GetCol() + 1 );
3535
3536 return TRUE;
f85afd4e 3537 }
8f177c8e 3538
2d66e025
MB
3539 return FALSE;
3540}
3541
3542
3543bool wxGrid::MovePageUp()
3544{
3545 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 3546
2d66e025
MB
3547 int row = m_currentCellCoords.GetRow();
3548 if ( row > 0 )
f85afd4e 3549 {
2d66e025
MB
3550 int cw, ch;
3551 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3552
2d66e025
MB
3553 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3554 int newRow = YToRow( y - ch + 1 );
3555 if ( newRow == -1 )
3556 {
3557 newRow = 0;
3558 }
60ff3b99 3559 else if ( newRow == row )
2d66e025
MB
3560 {
3561 newRow = row - 1;
3562 }
8f177c8e 3563
2d66e025
MB
3564 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3565 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 3566
f85afd4e
MB
3567 return TRUE;
3568 }
2d66e025
MB
3569
3570 return FALSE;
3571}
3572
3573bool wxGrid::MovePageDown()
3574{
3575 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 3576
2d66e025
MB
3577 int row = m_currentCellCoords.GetRow();
3578 if ( row < m_numRows )
f85afd4e 3579 {
2d66e025
MB
3580 int cw, ch;
3581 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 3582
2d66e025
MB
3583 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3584 int newRow = YToRow( y + ch );
3585 if ( newRow == -1 )
3586 {
3587 newRow = m_numRows - 1;
3588 }
60ff3b99 3589 else if ( newRow == row )
2d66e025
MB
3590 {
3591 newRow = row + 1;
3592 }
3593
3594 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3595 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 3596
2d66e025 3597 return TRUE;
f85afd4e 3598 }
2d66e025
MB
3599
3600 return FALSE;
f85afd4e 3601}
8f177c8e 3602
2d66e025
MB
3603bool wxGrid::MoveCursorUpBlock()
3604{
3605 if ( m_table &&
3606 m_currentCellCoords != wxGridNoCellCoords &&
3607 m_currentCellCoords.GetRow() > 0 )
3608 {
3609 int row = m_currentCellCoords.GetRow();
3610 int col = m_currentCellCoords.GetCol();
3611
3612 if ( m_table->IsEmptyCell(row, col) )
3613 {
3614 // starting in an empty cell: find the next block of
3615 // non-empty cells
3616 //
3617 while ( row > 0 )
3618 {
3619 row-- ;
3620 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3621 }
3622 }
3623 else if ( m_table->IsEmptyCell(row-1, col) )
3624 {
3625 // starting at the top of a block: find the next block
3626 //
3627 row--;
3628 while ( row > 0 )
3629 {
3630 row-- ;
3631 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3632 }
3633 }
3634 else
3635 {
3636 // starting within a block: find the top of the block
3637 //
3638 while ( row > 0 )
3639 {
3640 row-- ;
3641 if ( m_table->IsEmptyCell(row, col) )
3642 {
3643 row++ ;
3644 break;
3645 }
3646 }
3647 }
f85afd4e 3648
2d66e025
MB
3649 MakeCellVisible( row, col );
3650 SetCurrentCell( row, col );
f85afd4e 3651
2d66e025
MB
3652 return TRUE;
3653 }
f85afd4e 3654
2d66e025
MB
3655 return FALSE;
3656}
f85afd4e 3657
2d66e025 3658bool wxGrid::MoveCursorDownBlock()
f85afd4e 3659{
2d66e025
MB
3660 if ( m_table &&
3661 m_currentCellCoords != wxGridNoCellCoords &&
3662 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 3663 {
2d66e025
MB
3664 int row = m_currentCellCoords.GetRow();
3665 int col = m_currentCellCoords.GetCol();
3666
3667 if ( m_table->IsEmptyCell(row, col) )
3668 {
3669 // starting in an empty cell: find the next block of
3670 // non-empty cells
3671 //
3672 while ( row < m_numRows-1 )
3673 {
3674 row++ ;
3675 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3676 }
3677 }
3678 else if ( m_table->IsEmptyCell(row+1, col) )
3679 {
3680 // starting at the bottom of a block: find the next block
3681 //
3682 row++;
3683 while ( row < m_numRows-1 )
3684 {
3685 row++ ;
3686 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3687 }
3688 }
3689 else
3690 {
3691 // starting within a block: find the bottom of the block
3692 //
3693 while ( row < m_numRows-1 )
3694 {
3695 row++ ;
3696 if ( m_table->IsEmptyCell(row, col) )
3697 {
3698 row-- ;
3699 break;
3700 }
3701 }
3702 }
3703
3704 MakeCellVisible( row, col );
3705 SetCurrentCell( row, col );
3706
3707 return TRUE;
f85afd4e 3708 }
f85afd4e 3709
2d66e025
MB
3710 return FALSE;
3711}
f85afd4e 3712
2d66e025 3713bool wxGrid::MoveCursorLeftBlock()
f85afd4e 3714{
2d66e025
MB
3715 if ( m_table &&
3716 m_currentCellCoords != wxGridNoCellCoords &&
3717 m_currentCellCoords.GetCol() > 0 )
f85afd4e 3718 {
2d66e025
MB
3719 int row = m_currentCellCoords.GetRow();
3720 int col = m_currentCellCoords.GetCol();
3721
3722 if ( m_table->IsEmptyCell(row, col) )
3723 {
3724 // starting in an empty cell: find the next block of
3725 // non-empty cells
3726 //
3727 while ( col > 0 )
3728 {
3729 col-- ;
3730 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3731 }
3732 }
3733 else if ( m_table->IsEmptyCell(row, col-1) )
3734 {
3735 // starting at the left of a block: find the next block
3736 //
3737 col--;
3738 while ( col > 0 )
3739 {
3740 col-- ;
3741 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3742 }
3743 }
3744 else
3745 {
3746 // starting within a block: find the left of the block
3747 //
3748 while ( col > 0 )
3749 {
3750 col-- ;
3751 if ( m_table->IsEmptyCell(row, col) )
3752 {
3753 col++ ;
3754 break;
3755 }
3756 }
3757 }
f85afd4e 3758
2d66e025
MB
3759 MakeCellVisible( row, col );
3760 SetCurrentCell( row, col );
8f177c8e 3761
2d66e025 3762 return TRUE;
f85afd4e 3763 }
2d66e025
MB
3764
3765 return FALSE;
f85afd4e
MB
3766}
3767
2d66e025 3768bool wxGrid::MoveCursorRightBlock()
f85afd4e 3769{
2d66e025
MB
3770 if ( m_table &&
3771 m_currentCellCoords != wxGridNoCellCoords &&
3772 m_currentCellCoords.GetCol() < m_numCols-1 )
f85afd4e 3773 {
2d66e025
MB
3774 int row = m_currentCellCoords.GetRow();
3775 int col = m_currentCellCoords.GetCol();
8f177c8e 3776
2d66e025
MB
3777 if ( m_table->IsEmptyCell(row, col) )
3778 {
3779 // starting in an empty cell: find the next block of
3780 // non-empty cells
3781 //
3782 while ( col < m_numCols-1 )
3783 {
3784 col++ ;
3785 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3786 }
3787 }
3788 else if ( m_table->IsEmptyCell(row, col+1) )
3789 {
3790 // starting at the right of a block: find the next block
3791 //
3792 col++;
3793 while ( col < m_numCols-1 )
3794 {
3795 col++ ;
3796 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3797 }
3798 }
3799 else
3800 {
3801 // starting within a block: find the right of the block
3802 //
3803 while ( col < m_numCols-1 )
3804 {
3805 col++ ;
3806 if ( m_table->IsEmptyCell(row, col) )
3807 {
3808 col-- ;
3809 break;
3810 }
3811 }
3812 }
8f177c8e 3813
2d66e025
MB
3814 MakeCellVisible( row, col );
3815 SetCurrentCell( row, col );
f85afd4e 3816
2d66e025 3817 return TRUE;
f85afd4e 3818 }
2d66e025
MB
3819
3820 return FALSE;
f85afd4e
MB
3821}
3822
3823
2d66e025 3824
f85afd4e 3825//
2d66e025 3826// ------ Label values and formatting
f85afd4e
MB
3827//
3828
3829void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
3830{
3831 *horiz = m_rowLabelHorizAlign;
3832 *vert = m_rowLabelVertAlign;
3833}
3834
3835void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
3836{
3837 *horiz = m_colLabelHorizAlign;
3838 *vert = m_colLabelVertAlign;
3839}
3840
3841wxString wxGrid::GetRowLabelValue( int row )
3842{
3843 if ( m_table )
3844 {
3845 return m_table->GetRowLabelValue( row );
3846 }
3847 else
3848 {
3849 wxString s;
3850 s << row;
3851 return s;
3852 }
3853}
3854
3855wxString wxGrid::GetColLabelValue( int col )
3856{
3857 if ( m_table )
3858 {
3859 return m_table->GetColLabelValue( col );
3860 }
3861 else
3862 {
3863 wxString s;
3864 s << col;
3865 return s;
3866 }
3867}
3868
3869void wxGrid::SetRowLabelSize( int width )
3870{
2d66e025 3871 // TODO: how to do this with the box sizers ?
f85afd4e
MB
3872}
3873
3874void wxGrid::SetColLabelSize( int height )
3875{
2d66e025 3876 // TODO: how to do this with the box sizers ?
f85afd4e
MB
3877}
3878
3879void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
3880{
2d66e025
MB
3881 if ( m_labelBackgroundColour != colour )
3882 {
3883 m_labelBackgroundColour = colour;
3884 m_rowLabelWin->SetBackgroundColour( colour );
3885 m_colLabelWin->SetBackgroundColour( colour );
3886 m_cornerLabelWin->SetBackgroundColour( colour );
3887
3888 if ( !GetBatchCount() )
3889 {
3890 m_rowLabelWin->Refresh();
3891 m_colLabelWin->Refresh();
3892 m_cornerLabelWin->Refresh();
3893 }
3894 }
f85afd4e
MB
3895}
3896
3897void wxGrid::SetLabelTextColour( const wxColour& colour )
3898{
2d66e025
MB
3899 if ( m_labelTextColour != colour )
3900 {
3901 m_labelTextColour = colour;
3902 if ( !GetBatchCount() )
3903 {
3904 m_rowLabelWin->Refresh();
3905 m_colLabelWin->Refresh();
3906 }
3907 }
f85afd4e
MB
3908}
3909
3910void wxGrid::SetLabelFont( const wxFont& font )
3911{
3912 m_labelFont = font;
2d66e025
MB
3913 if ( !GetBatchCount() )
3914 {
3915 m_rowLabelWin->Refresh();
3916 m_colLabelWin->Refresh();
3917 }
f85afd4e
MB
3918}
3919
3920void wxGrid::SetRowLabelAlignment( int horiz, int vert )
3921{
3922 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
3923 {
3924 m_rowLabelHorizAlign = horiz;
3925 }
8f177c8e 3926
f85afd4e
MB
3927 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
3928 {
3929 m_rowLabelVertAlign = vert;
3930 }
3931
2d66e025
MB
3932 if ( !GetBatchCount() )
3933 {
3934 m_rowLabelWin->Refresh();
60ff3b99 3935 }
f85afd4e
MB
3936}
3937
3938void wxGrid::SetColLabelAlignment( int horiz, int vert )
3939{
3940 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
3941 {
3942 m_colLabelHorizAlign = horiz;
3943 }
8f177c8e 3944
f85afd4e
MB
3945 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
3946 {
3947 m_colLabelVertAlign = vert;
3948 }
3949
2d66e025
MB
3950 if ( !GetBatchCount() )
3951 {
2d66e025 3952 m_colLabelWin->Refresh();
60ff3b99 3953 }
f85afd4e
MB
3954}
3955
3956void wxGrid::SetRowLabelValue( int row, const wxString& s )
3957{
3958 if ( m_table )
3959 {
3960 m_table->SetRowLabelValue( row, s );
2d66e025
MB
3961 if ( !GetBatchCount() )
3962 {
70c7a608
SN
3963 wxRect rect = CellToRect( row, 0);
3964 if ( rect.height > 0 )
3965 {
3966 rect.x = m_left;
3967 rect.width = m_rowLabelWidth;
3968 m_rowLabelWin->Refresh( TRUE, &rect );
3969 }
2d66e025 3970 }
f85afd4e
MB
3971 }
3972}
3973
3974void wxGrid::SetColLabelValue( int col, const wxString& s )
3975{
3976 if ( m_table )
3977 {
3978 m_table->SetColLabelValue( col, s );
2d66e025
MB
3979 if ( !GetBatchCount() )
3980 {
70c7a608
SN
3981 wxRect rect = CellToRect( 0, col );
3982 if ( rect.width > 0 )
3983 {
3984 rect.y = m_top;
3985 rect.height = m_colLabelHeight;
3986 m_colLabelWin->Refresh( TRUE, &rect );
3987 }
2d66e025 3988 }
f85afd4e
MB
3989 }
3990}
3991
3992void wxGrid::SetGridLineColour( const wxColour& colour )
3993{
2d66e025
MB
3994 if ( m_gridLineColour != colour )
3995 {
3996 m_gridLineColour = colour;
60ff3b99 3997
2d66e025
MB
3998 wxClientDC dc( m_gridWin );
3999 PrepareDC( dc );
4000 DrawAllGridLines( dc );
4001 }
f85afd4e
MB
4002}
4003
4004void wxGrid::EnableGridLines( bool enable )
4005{
4006 if ( enable != m_gridLinesEnabled )
4007 {
4008 m_gridLinesEnabled = enable;
2d66e025
MB
4009
4010 if ( !GetBatchCount() )
4011 {
4012 if ( enable )
4013 {
4014 wxClientDC dc( m_gridWin );
4015 PrepareDC( dc );
4016 DrawAllGridLines( dc );
4017 }
4018 else
4019 {
4020 m_gridWin->Refresh();
4021 }
4022 }
f85afd4e
MB
4023 }
4024}
4025
4026
4027int wxGrid::GetDefaultRowSize()
4028{
4029 return m_defaultRowHeight;
4030}
4031
4032int wxGrid::GetRowSize( int row )
4033{
4034 if ( row >= 0 && row < m_numRows )
4035 return m_rowHeights[row];
4036 else
4037 return 0; // TODO: log an error here
4038}
4039
4040int wxGrid::GetDefaultColSize()
4041{
4042 return m_defaultColWidth;
4043}
4044
4045int wxGrid::GetColSize( int col )
4046{
4047 if ( col >= 0 && col < m_numCols )
4048 return m_colWidths[col];
4049 else
4050 return 0; // TODO: log an error here
4051}
4052
4053wxColour wxGrid::GetDefaultCellBackgroundColour()
4054{
4055 // TODO: replace this temp test code
4056 //
4057 return wxColour( 255, 255, 255 );
4058}
4059
af111fc3 4060wxColour wxGrid::GetCellBackgroundColour( int WXUNUSED(row), int WXUNUSED(col) )
f85afd4e
MB
4061{
4062 // TODO: replace this temp test code
4063 //
8f177c8e 4064 return wxColour( 255, 255, 255 );
f85afd4e
MB
4065}
4066
4067wxColour wxGrid::GetDefaultCellTextColour()
4068{
4069 // TODO: replace this temp test code
4070 //
8f177c8e 4071 return wxColour( 0, 0, 0 );
f85afd4e
MB
4072}
4073
af111fc3 4074wxColour wxGrid::GetCellTextColour( int WXUNUSED(row), int WXUNUSED(col) )
f85afd4e
MB
4075{
4076 // TODO: replace this temp test code
4077 //
8f177c8e 4078 return wxColour( 0, 0, 0 );
f85afd4e
MB
4079}
4080
4081
f85afd4e
MB
4082wxFont wxGrid::GetDefaultCellFont()
4083{
4084 return m_defaultCellFont;
4085}
4086
af111fc3 4087wxFont wxGrid::GetCellFont( int WXUNUSED(row), int WXUNUSED(col) )
f85afd4e
MB
4088{
4089 // TODO: replace this temp test code
4090 //
4091 return m_defaultCellFont;
4092}
4093
4094void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
4095{
4096 // TODO: replace this temp test code
4097 //
4098 *horiz = wxLEFT;
4099 *vert = wxTOP;
4100}
4101
af111fc3 4102void wxGrid::GetCellAlignment( int WXUNUSED(row), int WXUNUSED(col), int *horiz, int *vert )
f85afd4e
MB
4103{
4104 // TODO: replace this temp test code
4105 //
4106 *horiz = wxLEFT;
4107 *vert = wxTOP;
4108}
4109
4110void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
4111{
4112 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
4113
4114 if ( resizeExistingRows )
4115 {
f85afd4e 4116 int row;
2d66e025 4117 int bottom = 0;
f85afd4e
MB
4118 for ( row = 0; row < m_numRows; row++ )
4119 {
4120 m_rowHeights[row] = m_defaultRowHeight;
2d66e025
MB
4121 bottom += m_defaultRowHeight;
4122 m_rowBottoms[row] = bottom;
f85afd4e
MB
4123 }
4124 CalcDimensions();
f85afd4e
MB
4125 }
4126}
4127
4128void wxGrid::SetRowSize( int row, int height )
4129{
2d66e025 4130 int i;
60ff3b99 4131
f85afd4e
MB
4132 if ( row >= 0 && row < m_numRows )
4133 {
2d66e025
MB
4134 int h = wxMax( 0, height );
4135 int diff = h - m_rowHeights[row];
60ff3b99 4136
2d66e025
MB
4137 m_rowHeights[row] = h;
4138 for ( i = row; i < m_numRows; i++ )
4139 {
4140 m_rowBottoms[i] += diff;
4141 }
f85afd4e 4142 CalcDimensions();
60ff3b99 4143
f85afd4e
MB
4144 // Note: we are ending the event *after* doing
4145 // default processing in this case
4146 //
b5f788a5 4147 SendEvent( EVT_GRID_ROW_SIZE,
f85afd4e
MB
4148 row, -1 );
4149 }
4150 else
4151 {
4152 // TODO: log an error here
4153 }
4154}
4155
4156void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
4157{
4158 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
4159
4160 if ( resizeExistingCols )
4161 {
f85afd4e 4162 int col;
2d66e025 4163 int right = 0;
f85afd4e
MB
4164 for ( col = 0; col < m_numCols; col++ )
4165 {
4166 m_colWidths[col] = m_defaultColWidth;
2d66e025
MB
4167 right += m_defaultColWidth;
4168 m_colRights[col] = right;
f85afd4e
MB
4169 }
4170 CalcDimensions();
f85afd4e
MB
4171 }
4172}
4173
4174void wxGrid::SetColSize( int col, int width )
4175{
2d66e025 4176 int i;
60ff3b99 4177
f85afd4e
MB
4178 if ( col >= 0 && col < m_numCols )
4179 {
2d66e025
MB
4180 int w = wxMax( 0, width );
4181 int diff = w - m_colWidths[col];
4182 m_colWidths[col] = w;
f85afd4e 4183
2d66e025
MB
4184 for ( i = col; i < m_numCols; i++ )
4185 {
4186 m_colRights[i] += diff;
4187 }
4188 CalcDimensions();
60ff3b99 4189
f85afd4e
MB
4190 // Note: we are ending the event *after* doing
4191 // default processing in this case
4192 //
b5f788a5 4193 SendEvent( EVT_GRID_COL_SIZE,
f85afd4e
MB
4194 -1, col );
4195 }
4196 else
4197 {
4198 // TODO: log an error here
4199 }
4200}
4201
4202void wxGrid::SetDefaultCellBackgroundColour( const wxColour& )
4203{
4204 // TODO: everything !!!
4205 //
4206}
4207
af111fc3 4208void wxGrid::SetCellBackgroundColour( int WXUNUSED(row), int WXUNUSED(col), const wxColour& )
f85afd4e
MB
4209{
4210 // TODO: everything !!!
4211 //
4212}
4213
4214void wxGrid::SetDefaultCellTextColour( const wxColour& )
4215{
4216 // TODO: everything !!!
4217 //
4218}
4219
af111fc3 4220void wxGrid::SetCellTextColour( int WXUNUSED(row), int WXUNUSED(col), const wxColour& )
f85afd4e
MB
4221{
4222 // TODO: everything !!!
4223 //
4224}
4225
f85afd4e
MB
4226void wxGrid::SetDefaultCellFont( const wxFont& )
4227{
4228 // TODO: everything !!!
4229 //
4230}
4231
af111fc3 4232void wxGrid::SetCellFont( int WXUNUSED(row), int WXUNUSED(col), const wxFont& )
f85afd4e
MB
4233{
4234 // TODO: everything !!!
4235 //
4236}
4237
af111fc3 4238void wxGrid::SetDefaultCellAlignment( int WXUNUSED(horiz), int WXUNUSED(vert) )
f85afd4e
MB
4239{
4240 // TODO: everything !!!
4241 //
4242}
4243
af111fc3 4244void wxGrid::SetCellAlignment( int WXUNUSED(row), int WXUNUSED(col), int WXUNUSED(horiz), int WXUNUSED(vert) )
f85afd4e
MB
4245{
4246 // TODO: everything !!!
4247 //
4248}
4249
4250
2d66e025 4251
f85afd4e
MB
4252//
4253// ------ cell value accessor functions
4254//
4255
4256void wxGrid::SetCellValue( int row, int col, const wxString& s )
4257{
4258 if ( m_table )
4259 {
4260 m_table->SetValue( row, col, s.c_str() );
2d66e025
MB
4261 if ( !GetBatchCount() )
4262 {
4263 wxClientDC dc( m_gridWin );
4264 PrepareDC( dc );
4265 DrawCell( dc, wxGridCellCoords(row, col) );
4266 }
60ff3b99 4267
2d66e025 4268#if 0 // TODO: edit in place
60ff3b99 4269
f85afd4e
MB
4270 if ( m_currentCellCoords.GetRow() == row &&
4271 m_currentCellCoords.GetCol() == col )
4272 {
4273 SetEditControlValue( s );
4274 }
2d66e025 4275#endif
f85afd4e 4276
f85afd4e
MB
4277 }
4278}
4279
4280
4281//
2d66e025 4282// ------ Block, row and col selection
f85afd4e
MB
4283//
4284
4285void wxGrid::SelectRow( int row, bool addToSelected )
4286{
2d66e025 4287 wxRect r;
60ff3b99 4288
f85afd4e
MB
4289 if ( IsSelection() && addToSelected )
4290 {
70c7a608
SN
4291 wxRect rect[4];
4292 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4293 int i;
4294
4295 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4296 wxCoord oldTop = m_selectedTopLeft.GetRow();
4297 wxCoord oldRight = m_selectedBottomRight.GetCol();
4298 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4299
4300 if ( oldTop > row )
4301 {
4302 need_refresh[0] = TRUE;
4303 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
4304 wxGridCellCoords ( oldTop - 1,
4305 m_numCols - 1 ) );
f85afd4e 4306 m_selectedTopLeft.SetRow( row );
70c7a608 4307 }
8f177c8e 4308
70c7a608
SN
4309 if ( oldLeft > 0 )
4310 {
4311 need_refresh[1] = TRUE;
4312 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
4313 wxGridCellCoords ( oldBottom,
4314 oldLeft - 1 ) );
8f177c8e 4315
70c7a608
SN
4316 m_selectedTopLeft.SetCol( 0 );
4317 }
4318
4319 if ( oldBottom < row )
4320 {
4321 need_refresh[2] = TRUE;
4322 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
4323 wxGridCellCoords ( row,
4324 m_numCols - 1 ) );
f85afd4e 4325 m_selectedBottomRight.SetRow( row );
70c7a608 4326 }
8f177c8e 4327
70c7a608
SN
4328 if ( oldRight < m_numCols - 1 )
4329 {
4330 need_refresh[3] = TRUE;
4331 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
4332 oldRight + 1 ),
4333 wxGridCellCoords ( oldBottom,
4334 m_numCols - 1 ) );
4335 m_selectedBottomRight.SetCol( m_numCols - 1 );
4336 }
2d66e025 4337
70c7a608
SN
4338 for (i = 0; i < 4; i++ )
4339 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4340 m_gridWin->Refresh( TRUE, &(rect[i]) );
f85afd4e
MB
4341 }
4342 else
4343 {
2d66e025 4344 r = SelectionToDeviceRect();
f85afd4e 4345 ClearSelection();
2d66e025 4346 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
60ff3b99 4347
f85afd4e
MB
4348 m_selectedTopLeft.Set( row, 0 );
4349 m_selectedBottomRight.Set( row, m_numCols-1 );
2d66e025
MB
4350 r = SelectionToDeviceRect();
4351 m_gridWin->Refresh( TRUE, &r );
f85afd4e 4352 }
8f177c8e 4353
f85afd4e 4354 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 4355 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
4356 this,
4357 m_selectedTopLeft,
4358 m_selectedBottomRight );
4359
4360 GetEventHandler()->ProcessEvent(gridEvt);
4361}
4362
4363
4364void wxGrid::SelectCol( int col, bool addToSelected )
4365{
2d66e025 4366 if ( IsSelection() && addToSelected )
f85afd4e 4367 {
70c7a608
SN
4368 wxRect rect[4];
4369 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4370 int i;
4371
4372 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4373 wxCoord oldTop = m_selectedTopLeft.GetRow();
4374 wxCoord oldRight = m_selectedBottomRight.GetCol();
4375 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4376
4377 if ( oldLeft > col )
4378 {
4379 need_refresh[0] = TRUE;
4380 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
4381 wxGridCellCoords ( m_numRows - 1,
4382 oldLeft - 1 ) );
f85afd4e 4383 m_selectedTopLeft.SetCol( col );
70c7a608 4384 }
f85afd4e 4385
70c7a608
SN
4386 if ( oldTop > 0 )
4387 {
4388 need_refresh[1] = TRUE;
4389 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
4390 wxGridCellCoords ( oldTop - 1,
4391 oldRight ) );
4392 m_selectedTopLeft.SetRow( 0 );
4393 }
f85afd4e 4394
70c7a608
SN
4395 if ( oldRight < col )
4396 {
4397 need_refresh[2] = TRUE;
4398 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
4399 wxGridCellCoords ( m_numRows - 1,
4400 col ) );
f85afd4e 4401 m_selectedBottomRight.SetCol( col );
70c7a608 4402 }
f85afd4e 4403
70c7a608
SN
4404 if ( oldBottom < m_numRows - 1 )
4405 {
4406 need_refresh[3] = TRUE;
4407 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
4408 oldLeft ),
4409 wxGridCellCoords ( m_numRows - 1,
4410 oldRight ) );
4411 m_selectedBottomRight.SetRow( m_numRows - 1 );
4412 }
2d66e025 4413
70c7a608
SN
4414 for (i = 0; i < 4; i++ )
4415 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4416 m_gridWin->Refresh( TRUE, &(rect[i]) );
f85afd4e
MB
4417 }
4418 else
4419 {
70c7a608
SN
4420 wxRect r;
4421
2d66e025 4422 r = SelectionToDeviceRect();
f85afd4e 4423 ClearSelection();
2d66e025 4424 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( TRUE, &r );
60ff3b99 4425
f85afd4e
MB
4426 m_selectedTopLeft.Set( 0, col );
4427 m_selectedBottomRight.Set( m_numRows-1, col );
2d66e025
MB
4428 r = SelectionToDeviceRect();
4429 m_gridWin->Refresh( TRUE, &r );
f85afd4e
MB
4430 }
4431
4432 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 4433 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
4434 this,
4435 m_selectedTopLeft,
4436 m_selectedBottomRight );
4437
4438 GetEventHandler()->ProcessEvent(gridEvt);
4439}
4440
4441
4442void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
4443{
4444 int temp;
da6af900 4445 wxGridCellCoords updateTopLeft, updateBottomRight;
8f177c8e 4446
f85afd4e
MB
4447 if ( topRow > bottomRow )
4448 {
4449 temp = topRow;
4450 topRow = bottomRow;
4451 bottomRow = temp;
4452 }
4453
4454 if ( leftCol > rightCol )
4455 {
4456 temp = leftCol;
4457 leftCol = rightCol;
4458 rightCol = temp;
4459 }
f0102d2a 4460
70c7a608
SN
4461 updateTopLeft = wxGridCellCoords( topRow, leftCol );
4462 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
da6af900 4463
70c7a608
SN
4464 if ( m_selectedTopLeft != updateTopLeft ||
4465 m_selectedBottomRight != updateBottomRight )
da6af900 4466 {
70c7a608
SN
4467 // Compute two optimal update rectangles:
4468 // Either one rectangle is a real subset of the
4469 // other, or they are (almost) disjoint!
4470 wxRect rect[4];
4471 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4472 int i;
4473
4474 // Store intermediate values
4475 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4476 wxCoord oldTop = m_selectedTopLeft.GetRow();
4477 wxCoord oldRight = m_selectedBottomRight.GetCol();
4478 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4479
4480 // Determine the outer/inner coordinates.
4481 if (oldLeft > leftCol)
f0102d2a 4482 {
70c7a608
SN
4483 temp = oldLeft;
4484 oldLeft = leftCol;
4485 leftCol = temp;
4486 }
4487 if (oldTop > topRow )
f0102d2a 4488 {
70c7a608
SN
4489 temp = oldTop;
4490 oldTop = topRow;
4491 topRow = temp;
4492 }
4493 if (oldRight < rightCol )
4494 {
4495 temp = oldRight;
4496 oldRight = rightCol;
4497 rightCol = temp;
4498 }
4499 if (oldBottom < bottomRow)
4500 {
4501 temp = oldBottom;
4502 oldBottom = bottomRow;
4503 bottomRow = temp;
4504 }
4505
4506 // Now, either the stuff marked old is the outer
4507 // rectangle or we don't have a situation where one
4508 // is contained in the other.
4509
4510 if ( oldLeft < leftCol )
4511 {
4512 need_refresh[0] = TRUE;
4513 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4514 oldLeft ),
4515 wxGridCellCoords ( oldBottom,
4516 leftCol - 1 ) );
4517 }
4518
4519 if ( oldTop < topRow )
4520 {
4521 need_refresh[1] = TRUE;
4522 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4523 leftCol ),
4524 wxGridCellCoords ( topRow - 1,
4525 rightCol ) );
4526 }
4527
4528 if ( oldRight > rightCol )
4529 {
4530 need_refresh[2] = TRUE;
4531 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4532 rightCol + 1 ),
4533 wxGridCellCoords ( oldBottom,
4534 oldRight ) );
4535 }
4536
4537 if ( oldBottom > bottomRow )
4538 {
4539 need_refresh[3] = TRUE;
4540 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
4541 leftCol ),
4542 wxGridCellCoords ( oldBottom,
4543 rightCol ) );
4544 }
4545
4546
4547 // Change Selection
4548 m_selectedTopLeft = updateTopLeft;
4549 m_selectedBottomRight = updateBottomRight;
4550
4551 // various Refresh() calls
4552 for (i = 0; i < 4; i++ )
4553 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4554 m_gridWin->Refresh( TRUE, &(rect[i]) );
da6af900 4555 }
f85afd4e
MB
4556
4557 // only generate an event if the block is not being selected by
4558 // dragging the mouse (in which case the event will be generated in
2d66e025 4559 // the mouse event handler)
f85afd4e
MB
4560 if ( !m_isDragging )
4561 {
4562 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 4563 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
4564 this,
4565 m_selectedTopLeft,
4566 m_selectedBottomRight );
8f177c8e 4567
f85afd4e
MB
4568 GetEventHandler()->ProcessEvent(gridEvt);
4569 }
4570}
4571
4572void wxGrid::SelectAll()
4573{
4574 m_selectedTopLeft.Set( 0, 0 );
4575 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
4576
2d66e025 4577 m_gridWin->Refresh();
f85afd4e
MB
4578}
4579
4580
4581void wxGrid::ClearSelection()
4582{
2d66e025
MB
4583 m_selectedTopLeft = wxGridNoCellCoords;
4584 m_selectedBottomRight = wxGridNoCellCoords;
8f177c8e 4585}
f85afd4e
MB
4586
4587
da6af900 4588// This function returns the rectangle that encloses the given block
2d66e025
MB
4589// in device coords clipped to the client size of the grid window.
4590//
58dd5b3b
MB
4591wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
4592 const wxGridCellCoords &bottomRight )
f85afd4e 4593{
58dd5b3b 4594 wxRect rect( wxGridNoCellRect );
f85afd4e
MB
4595 wxRect cellRect;
4596
58dd5b3b
MB
4597 cellRect = CellToRect( topLeft );
4598 if ( cellRect != wxGridNoCellRect )
f85afd4e 4599 {
58dd5b3b
MB
4600 rect = cellRect;
4601 }
4602 else
4603 {
4604 rect = wxRect( 0, 0, 0, 0 );
4605 }
60ff3b99 4606
58dd5b3b
MB
4607 cellRect = CellToRect( bottomRight );
4608 if ( cellRect != wxGridNoCellRect )
4609 {
4610 rect += cellRect;
2d66e025
MB
4611 }
4612 else
4613 {
4614 return wxGridNoCellRect;
f85afd4e
MB
4615 }
4616
58dd5b3b
MB
4617 // convert to scrolled coords
4618 //
4619 int left, top, right, bottom;
4620 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
4621 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
4622
4623 int cw, ch;
4624 m_gridWin->GetClientSize( &cw, &ch );
4625
4626 rect.SetLeft( wxMax(0, left) );
4627 rect.SetTop( wxMax(0, top) );
4628 rect.SetRight( wxMin(cw, right) );
4629 rect.SetBottom( wxMin(ch, bottom) );
4630
f85afd4e
MB
4631 return rect;
4632}
4633
4634
58dd5b3b 4635
f85afd4e
MB
4636//
4637// ------ Grid event classes
4638//
4639
4640IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
4641
4642wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
4643 int row, int col, int x, int y,
4644 bool control, bool shift, bool alt, bool meta )
4645 : wxNotifyEvent( type, id )
4646{
4647 m_row = row;
4648 m_col = col;
4649 m_x = x;
4650 m_y = y;
4651 m_control = control;
4652 m_shift = shift;
4653 m_alt = alt;
4654 m_meta = meta;
8f177c8e 4655
f85afd4e
MB
4656 SetEventObject(obj);
4657}
4658
4659
4660IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
4661
4662wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
4663 int rowOrCol, int x, int y,
4664 bool control, bool shift, bool alt, bool meta )
4665 : wxNotifyEvent( type, id )
4666{
4667 m_rowOrCol = rowOrCol;
4668 m_x = x;
4669 m_y = y;
4670 m_control = control;
4671 m_shift = shift;
4672 m_alt = alt;
4673 m_meta = meta;
8f177c8e 4674
f85afd4e
MB
4675 SetEventObject(obj);
4676}
4677
4678
4679IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
4680
4681wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8f177c8e
VZ
4682 const wxGridCellCoords& topLeft,
4683 const wxGridCellCoords& bottomRight,
4684 bool control, bool shift, bool alt, bool meta )
4685 : wxNotifyEvent( type, id )
f85afd4e
MB
4686{
4687 m_topLeft = topLeft;
4688 m_bottomRight = bottomRight;
4689 m_control = control;
4690 m_shift = shift;
4691 m_alt = alt;
4692 m_meta = meta;
4693
4694 SetEventObject(obj);
4695}
4696
4697
4698#endif // ifndef wxUSE_NEW_GRID
4699