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