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