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