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