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