]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp
missing event.Skip() added (it was impossible to use mouse without it...)
[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;
d1c0b4f9
VZ
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 }
4d60017a
SN
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;
d1c0b4f9
VZ
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 }
4d60017a
SN
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];
d1c0b4f9
VZ
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 }
4d60017a
SN
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
d1c0b4f9 872 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
4d60017a
SN
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
d1c0b4f9 882 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
4d60017a
SN
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 );
d1c0b4f9
VZ
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 );
d1c0b4f9
VZ
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);
d1c0b4f9
VZ
3703
3704 // Otherwise refresh redraws the highlight!
3705 m_currentCellCoords = coords;
3706
07296f0b 3707 m_gridWin->Refresh( FALSE, &r );
66242c80 3708 }
8f177c8e 3709
2d66e025
MB
3710 m_currentCellCoords = coords;
3711
3712 SetEditControlValue();
07296f0b 3713
4634a5d6 3714 if ( m_displayed )
2d66e025 3715 {
07296f0b
RD
3716 wxClientDC dc(m_gridWin);
3717 PrepareDC(dc);
3718 DrawCellHighlight(dc);
4634a5d6
MB
3719
3720 if ( IsSelection() )
3721 {
3722 wxRect r( SelectionToDeviceRect() );
3723 ClearSelection();
3724 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
3725 }
2d66e025 3726 }
66242c80
MB
3727}
3728
2d66e025
MB
3729
3730//
3731// ------ functions to get/send data (see also public functions)
3732//
3733
3734bool wxGrid::GetModelValues()
66242c80 3735{
2d66e025 3736 if ( m_table )
66242c80 3737 {
2d66e025 3738 // all we need to do is repaint the grid
66242c80 3739 //
2d66e025 3740 m_gridWin->Refresh();
66242c80
MB
3741 return TRUE;
3742 }
8f177c8e 3743
66242c80
MB
3744 return FALSE;
3745}
3746
2d66e025
MB
3747
3748bool wxGrid::SetModelValues()
f85afd4e 3749{
2d66e025 3750 int row, col;
8f177c8e 3751
2d66e025
MB
3752 if ( m_table )
3753 {
3754 for ( row = 0; row < m_numRows; row++ )
f85afd4e 3755 {
2d66e025 3756 for ( col = 0; col < m_numCols; col++ )
f85afd4e 3757 {
2d66e025 3758 m_table->SetValue( row, col, GetCellValue(row, col) );
f85afd4e
MB
3759 }
3760 }
8f177c8e 3761
f85afd4e
MB
3762 return TRUE;
3763 }
3764
3765 return FALSE;
3766}
3767
2d66e025
MB
3768
3769
3770// Note - this function only draws cells that are in the list of
3771// exposed cells (usually set from the update region by
3772// CalcExposedCells)
3773//
3774void wxGrid::DrawGridCellArea( wxDC& dc )
f85afd4e 3775{
2d66e025 3776 if ( !m_numRows || !m_numCols ) return;
60ff3b99 3777
2d66e025
MB
3778 size_t i;
3779 size_t numCells = m_cellsExposed.GetCount();
60ff3b99 3780
2d66e025 3781 for ( i = 0; i < numCells; i++ )
f85afd4e 3782 {
2d66e025
MB
3783 DrawCell( dc, m_cellsExposed[i] );
3784 }
3785}
8f177c8e 3786
8f177c8e 3787
2d66e025
MB
3788void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
3789{
ab79958a
VZ
3790 int row = coords.GetRow();
3791 int col = coords.GetCol();
60ff3b99 3792
ab79958a
VZ
3793 if ( m_colWidths[col] <= 0 || m_rowHeights[row] <= 0 )
3794 return;
3795
3796 // we draw the cell border ourselves
9496deb5 3797#if !WXGRID_DRAW_LINES
2d66e025
MB
3798 if ( m_gridLinesEnabled )
3799 DrawCellBorder( dc, coords );
796df70a 3800#endif
f85afd4e 3801
ab79958a
VZ
3802 // but all the rest is drawn by the cell renderer and hence may be
3803 // customized
ab79958a 3804 wxRect rect;
dcfe4c3d
SN
3805 rect.x = m_colRights[col] - m_colWidths[col];
3806 rect.y = m_rowBottoms[row] - m_rowHeights[row];
f87ac92e
RD
3807 rect.width = m_colWidths[col]-1;
3808 rect.height = m_rowHeights[row]-1;
f85afd4e 3809
2796cce3
RD
3810 wxGridCellAttr* attr = GetCellAttr(row, col);
3811 attr->GetRenderer()->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
3812 attr->DecRef();
07296f0b
RD
3813
3814 if (m_currentCellCoords == coords)
3815 DrawCellHighlight(dc);
3816}
3817
3818
3819void wxGrid::DrawCellHighlight( wxDC& dc )
3820{
3821 int row = m_currentCellCoords.GetRow();
3822 int col = m_currentCellCoords.GetCol();
3823
3824 if ( m_colWidths[col] <= 0 || m_rowHeights[row] <= 0 )
3825 return;
3826
3827 wxRect rect;
3828 rect.x = m_colRights[col] - m_colWidths[col];
3829 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3830 rect.width = m_colWidths[col] - 1;
3831 rect.height = m_rowHeights[row] - 1;
3832
3833 dc.SetPen(wxPen(m_gridLineColour, 3, wxSOLID));
3834 dc.SetBrush(*wxTRANSPARENT_BRUSH);
07296f0b
RD
3835
3836 dc.DrawRectangle(rect);
2d66e025 3837}
f85afd4e 3838
2d66e025
MB
3839void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
3840{
3841 if ( m_colWidths[coords.GetCol()] <=0 ||
3842 m_rowHeights[coords.GetRow()] <= 0 ) return;
60ff3b99 3843
2d66e025
MB
3844 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3845 int row = coords.GetRow();
3846 int col = coords.GetCol();
60ff3b99 3847
2d66e025
MB
3848 // right hand border
3849 //
bd3c6758
MB
3850 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
3851 m_colRights[col], m_rowBottoms[row] );
2d66e025
MB
3852
3853 // bottom border
3854 //
bd3c6758
MB
3855 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
3856 m_colRights[col], m_rowBottoms[row] );
f85afd4e
MB
3857}
3858
2d66e025 3859
2d66e025
MB
3860// TODO: remove this ???
3861// This is used to redraw all grid lines e.g. when the grid line colour
3862// has been changed
3863//
796df70a 3864void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
f85afd4e 3865{
60ff3b99
VZ
3866 if ( !m_gridLinesEnabled ||
3867 !m_numRows ||
2d66e025 3868 !m_numCols ) return;
f85afd4e 3869
2d66e025 3870 int top, bottom, left, right;
796df70a
SN
3871
3872 if (reg.IsEmpty()){
3873 int cw, ch;
3874 m_gridWin->GetClientSize(&cw, &ch);
3875
3876 // virtual coords of visible area
3877 //
3878 CalcUnscrolledPosition( 0, 0, &left, &top );
3879 CalcUnscrolledPosition( cw, ch, &right, &bottom );
3880 }
3881 else{
3882 wxCoord x, y, w, h;
3883 reg.GetBox(x, y, w, h);
3884 CalcUnscrolledPosition( x, y, &left, &top );
3885 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
3886 }
f85afd4e 3887
9496deb5
MB
3888 // avoid drawing grid lines past the last row and col
3889 //
3890 right = wxMin( right, m_colRights[m_numCols-1] );
3891 bottom = wxMin( bottom, m_rowBottoms[m_numRows-1] );
3892
2d66e025 3893 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
f85afd4e 3894
2d66e025 3895 // horizontal grid lines
f85afd4e 3896 //
60ff3b99 3897 int i;
9496deb5 3898 for ( i = 0; i < m_numRows; i++ )
f85afd4e 3899 {
dcfe4c3d 3900 if ( m_rowBottoms[i]-1 > bottom )
2d66e025
MB
3901 {
3902 break;
3903 }
dcfe4c3d 3904 else if ( m_rowBottoms[i]-1 >= top )
2d66e025 3905 {
dcfe4c3d 3906 dc.DrawLine( left, m_rowBottoms[i]-1, right, m_rowBottoms[i]-1 );
2d66e025 3907 }
f85afd4e
MB
3908 }
3909
f85afd4e 3910
2d66e025
MB
3911 // vertical grid lines
3912 //
9496deb5 3913 for ( i = 0; i < m_numCols; i++ )
f85afd4e 3914 {
dcfe4c3d 3915 if ( m_colRights[i]-1 > right )
2d66e025
MB
3916 {
3917 break;
3918 }
dcfe4c3d 3919 else if ( m_colRights[i]-1 >= left )
2d66e025 3920 {
dcfe4c3d 3921 dc.DrawLine( m_colRights[i]-1, top, m_colRights[i]-1, bottom );
2d66e025
MB
3922 }
3923 }
3924}
f85afd4e 3925
8f177c8e 3926
2d66e025
MB
3927void wxGrid::DrawRowLabels( wxDC& dc )
3928{
3929 if ( !m_numRows || !m_numCols ) return;
60ff3b99 3930
2d66e025
MB
3931 size_t i;
3932 size_t numLabels = m_rowLabelsExposed.GetCount();
60ff3b99 3933
2d66e025
MB
3934 for ( i = 0; i < numLabels; i++ )
3935 {
3936 DrawRowLabel( dc, m_rowLabelsExposed[i] );
60ff3b99 3937 }
f85afd4e
MB
3938}
3939
3940
2d66e025 3941void wxGrid::DrawRowLabel( wxDC& dc, int row )
f85afd4e 3942{
2d66e025 3943 if ( m_rowHeights[row] <= 0 ) return;
60ff3b99 3944
b0d6ff2f 3945 int rowTop = m_rowBottoms[row] - m_rowHeights[row];
b99be8fb 3946
2d66e025 3947 dc.SetPen( *wxBLACK_PEN );
b0d6ff2f
MB
3948 dc.DrawLine( m_rowLabelWidth-1, rowTop,
3949 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
b99be8fb 3950
b0d6ff2f
MB
3951 dc.DrawLine( 0, m_rowBottoms[row]-1,
3952 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
b99be8fb 3953
2d66e025 3954 dc.SetPen( *wxWHITE_PEN );
b0d6ff2f
MB
3955 dc.DrawLine( 0, rowTop, 0, m_rowBottoms[row]-1 );
3956 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
60ff3b99 3957
f85afd4e 3958 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
3959 dc.SetTextForeground( GetLabelTextColour() );
3960 dc.SetFont( GetLabelFont() );
8f177c8e 3961
f85afd4e 3962 int hAlign, vAlign;
2d66e025 3963 GetRowLabelAlignment( &hAlign, &vAlign );
60ff3b99 3964
2d66e025
MB
3965 wxRect rect;
3966 rect.SetX( 2 );
3967 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3968 rect.SetWidth( m_rowLabelWidth - 4 );
3969 rect.SetHeight( m_rowHeights[row] - 4 );
60ff3b99 3970 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
f85afd4e
MB
3971}
3972
3973
2d66e025 3974void wxGrid::DrawColLabels( wxDC& dc )
f85afd4e 3975{
2d66e025 3976 if ( !m_numRows || !m_numCols ) return;
60ff3b99 3977
2d66e025
MB
3978 size_t i;
3979 size_t numLabels = m_colLabelsExposed.GetCount();
60ff3b99 3980
2d66e025 3981 for ( i = 0; i < numLabels; i++ )
f85afd4e 3982 {
2d66e025 3983 DrawColLabel( dc, m_colLabelsExposed[i] );
60ff3b99 3984 }
f85afd4e
MB
3985}
3986
3987
2d66e025 3988void wxGrid::DrawColLabel( wxDC& dc, int col )
f85afd4e 3989{
2d66e025 3990 if ( m_colWidths[col] <= 0 ) return;
60ff3b99 3991
b0d6ff2f 3992 int colLeft = m_colRights[col] - m_colWidths[col];
b99be8fb 3993
2d66e025 3994 dc.SetPen( *wxBLACK_PEN );
b0d6ff2f
MB
3995 dc.DrawLine( m_colRights[col]-1, 0,
3996 m_colRights[col]-1, m_colLabelHeight-1 );
b99be8fb 3997
b0d6ff2f
MB
3998 dc.DrawLine( colLeft, m_colLabelHeight-1,
3999 m_colRights[col]-1, m_colLabelHeight-1 );
b99be8fb 4000
f85afd4e 4001 dc.SetPen( *wxWHITE_PEN );
b0d6ff2f
MB
4002 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
4003 dc.DrawLine( colLeft, 0, m_colRights[col]-1, 0 );
f85afd4e 4004
b0d6ff2f
MB
4005 dc.SetBackgroundMode( wxTRANSPARENT );
4006 dc.SetTextForeground( GetLabelTextColour() );
4007 dc.SetFont( GetLabelFont() );
8f177c8e 4008
f85afd4e 4009 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
4010 dc.SetTextForeground( GetLabelTextColour() );
4011 dc.SetFont( GetLabelFont() );
8f177c8e 4012
f85afd4e 4013 int hAlign, vAlign;
2d66e025 4014 GetColLabelAlignment( &hAlign, &vAlign );
60ff3b99 4015
2d66e025
MB
4016 wxRect rect;
4017 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
4018 rect.SetY( 2 );
4019 rect.SetWidth( m_colWidths[col] - 4 );
4020 rect.SetHeight( m_colLabelHeight - 4 );
60ff3b99 4021 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
f85afd4e
MB
4022}
4023
4024
2d66e025
MB
4025void wxGrid::DrawTextRectangle( wxDC& dc,
4026 const wxString& value,
4027 const wxRect& rect,
4028 int horizAlign,
4029 int vertAlign )
f85afd4e 4030{
2d66e025
MB
4031 long textWidth, textHeight;
4032 long lineWidth, lineHeight;
4033 wxArrayString lines;
f85afd4e 4034
2d66e025
MB
4035 dc.SetClippingRegion( rect );
4036 StringToLines( value, lines );
4037 if ( lines.GetCount() )
4038 {
4039 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
4040 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
f85afd4e 4041
2d66e025
MB
4042 float x, y;
4043 switch ( horizAlign )
4044 {
4045 case wxRIGHT:
4046 x = rect.x + (rect.width - textWidth - 1);
4047 break;
f85afd4e 4048
2d66e025
MB
4049 case wxCENTRE:
4050 x = rect.x + ((rect.width - textWidth)/2);
4051 break;
f85afd4e 4052
2d66e025
MB
4053 case wxLEFT:
4054 default:
4055 x = rect.x + 1;
4056 break;
4057 }
f85afd4e 4058
2d66e025
MB
4059 switch ( vertAlign )
4060 {
4061 case wxBOTTOM:
4062 y = rect.y + (rect.height - textHeight - 1);
4063 break;
f85afd4e
MB
4064
4065 case wxCENTRE:
8f177c8e 4066 y = rect.y + ((rect.height - textHeight)/2);
f85afd4e
MB
4067 break;
4068
4069 case wxTOP:
4070 default:
8f177c8e 4071 y = rect.y + 1;
f85afd4e
MB
4072 break;
4073 }
4074
b540eb2b 4075 for ( size_t i = 0; i < lines.GetCount(); i++ )
f85afd4e
MB
4076 {
4077 dc.DrawText( lines[i], (long)x, (long)y );
4078 y += lineHeight;
4079 }
4080 }
8f177c8e 4081
f85afd4e 4082 dc.DestroyClippingRegion();
f85afd4e
MB
4083}
4084
4085
4086// Split multi line text up into an array of strings. Any existing
4087// contents of the string array are preserved.
4088//
4089void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
4090{
f85afd4e
MB
4091 int startPos = 0;
4092 int pos;
6d004f67 4093 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
2433bb2e 4094 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
e2b42eeb 4095
2433bb2e 4096 while ( startPos < (int)tVal.Length() )
f85afd4e 4097 {
2433bb2e 4098 pos = tVal.Mid(startPos).Find( eol );
f85afd4e
MB
4099 if ( pos < 0 )
4100 {
4101 break;
4102 }
4103 else if ( pos == 0 )
4104 {
4105 lines.Add( wxEmptyString );
4106 }
4107 else
4108 {
2433bb2e 4109 lines.Add( value.Mid(startPos, pos) );
f85afd4e
MB
4110 }
4111 startPos += pos+1;
4112 }
b540eb2b 4113 if ( startPos < (int)value.Length() )
f85afd4e
MB
4114 {
4115 lines.Add( value.Mid( startPos ) );
4116 }
4117}
4118
4119
4120void wxGrid::GetTextBoxSize( wxDC& dc,
4121 wxArrayString& lines,
4122 long *width, long *height )
4123{
4124 long w = 0;
4125 long h = 0;
4126 long lineW, lineH;
4127
b540eb2b 4128 size_t i;
f85afd4e
MB
4129 for ( i = 0; i < lines.GetCount(); i++ )
4130 {
4131 dc.GetTextExtent( lines[i], &lineW, &lineH );
4132 w = wxMax( w, lineW );
4133 h += lineH;
4134 }
4135
4136 *width = w;
4137 *height = h;
4138}
4139
4140
4141//
2d66e025 4142// ------ Edit control functions
f85afd4e
MB
4143//
4144
2d66e025
MB
4145
4146void wxGrid::EnableEditing( bool edit )
f85afd4e 4147{
2d66e025
MB
4148 // TODO: improve this ?
4149 //
4150 if ( edit != m_editable )
f85afd4e 4151 {
2d66e025 4152 m_editable = edit;
1f1ce288 4153
2c9a89e0 4154 EnableCellEditControl(m_editable);
f85afd4e 4155 }
f85afd4e
MB
4156}
4157
4158
2d66e025 4159void wxGrid::EnableCellEditControl( bool enable )
f85afd4e 4160{
2c9a89e0
RD
4161 if (! m_editable)
4162 return;
4163
dcfe4c3d
SN
4164 if ( m_currentCellCoords == wxGridNoCellCoords )
4165 SetCurrentCell( 0, 0 );
60ff3b99 4166
2c9a89e0
RD
4167 if ( enable != m_cellEditCtrlEnabled )
4168 {
dcfe4c3d 4169 if ( enable )
f85afd4e 4170 {
dcfe4c3d 4171 m_cellEditCtrlEnabled = enable;
2d66e025
MB
4172 SetEditControlValue();
4173 ShowCellEditControl();
2d66e025
MB
4174 }
4175 else
4176 {
2d66e025
MB
4177 HideCellEditControl();
4178 SaveEditControlValue();
dcfe4c3d 4179 m_cellEditCtrlEnabled = enable;
f85afd4e 4180 }
f85afd4e 4181 }
f85afd4e 4182}
f85afd4e
MB
4183
4184
2d66e025 4185void wxGrid::ShowCellEditControl()
f85afd4e 4186{
2d66e025 4187 if ( IsCellEditControlEnabled() )
f85afd4e 4188 {
2d66e025
MB
4189 if ( !IsVisible( m_currentCellCoords ) )
4190 {
4191 return;
4192 }
4193 else
4194 {
2c9a89e0
RD
4195 wxRect rect = CellToRect( m_currentCellCoords );
4196 int row = m_currentCellCoords.GetRow();
4197 int col = m_currentCellCoords.GetCol();
2d66e025
MB
4198
4199 // convert to scrolled coords
4200 //
4201 int left, top, right, bottom;
4202 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
4203 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
025562fe 4204 left--; top--; right--; bottom--; // cell is shifted by one pixel
2d66e025
MB
4205 int cw, ch;
4206 m_gridWin->GetClientSize( &cw, &ch );
1f1ce288
MB
4207
4208 // Make the edit control large enough to allow for internal margins
4209 // TODO: remove this if the text ctrl sizing is improved esp. for unix
4210 //
58dd5b3b 4211 int extra;
d2fdd8d2 4212#if defined(__WXMOTIF__)
2c9a89e0 4213 if ( row == 0 || col == 0 )
58dd5b3b
MB
4214 {
4215 extra = 2;
4216 }
4217 else
4218 {
4219 extra = 4;
4220 }
1f1ce288 4221#else
2c9a89e0 4222 if ( row == 0 || col == 0 )
58dd5b3b
MB
4223 {
4224 extra = 1;
4225 }
4226 else
4227 {
4228 extra = 2;
4229 }
1f1ce288 4230#endif
d2fdd8d2
RR
4231
4232#if defined(__WXGTK__)
4233 int top_diff = 0;
4234 int left_diff = 0;
4235 if (left != 0) left_diff++;
4236 if (top != 0) top_diff++;
4237 rect.SetLeft( left + left_diff );
4238 rect.SetTop( top + top_diff );
4239 rect.SetRight( rect.GetRight() - left_diff );
4240 rect.SetBottom( rect.GetBottom() - top_diff );
4241#else
58dd5b3b
MB
4242 rect.SetLeft( wxMax(0, left - extra) );
4243 rect.SetTop( wxMax(0, top - extra) );
4244 rect.SetRight( rect.GetRight() + 2*extra );
4245 rect.SetBottom( rect.GetBottom() + 2*extra );
d2fdd8d2 4246#endif
f0102d2a 4247
2c9a89e0
RD
4248 wxGridCellAttr* attr = GetCellAttr(row, col);
4249 wxGridCellEditor* editor = attr->GetEditor();
4250 if (! editor->IsCreated()) {
4251 editor->Create(m_gridWin, -1,
4252 new wxGridCellEditorEvtHandler(this, editor));
2d66e025
MB
4253 }
4254
2c9a89e0
RD
4255 editor->SetSize( rect );
4256 editor->Show( TRUE );
4257 editor->BeginEdit(row, col, this, attr);
4258 attr->DecRef();
4259 }
f85afd4e
MB
4260 }
4261}
4262
4263
2d66e025 4264void wxGrid::HideCellEditControl()
f85afd4e 4265{
2d66e025 4266 if ( IsCellEditControlEnabled() )
f85afd4e 4267 {
2c9a89e0
RD
4268 int row = m_currentCellCoords.GetRow();
4269 int col = m_currentCellCoords.GetCol();
4270
4271 wxGridCellAttr* attr = GetCellAttr(row, col);
4272 attr->GetEditor()->Show( FALSE );
4273 attr->DecRef();
4274 m_gridWin->SetFocus();
f85afd4e 4275 }
2d66e025 4276}
8f177c8e 4277
2d66e025
MB
4278
4279void wxGrid::SetEditControlValue( const wxString& value )
4280{
fb295790
RD
4281 // RD: The new Editors get the value from the table themselves now. This
4282 // method can probably be removed...
f85afd4e
MB
4283}
4284
8f177c8e 4285
2d66e025
MB
4286void wxGrid::SaveEditControlValue()
4287{
2c9a89e0
RD
4288 if (IsCellEditControlEnabled()) {
4289 int row = m_currentCellCoords.GetRow();
4290 int col = m_currentCellCoords.GetCol();
8f177c8e 4291
2c9a89e0
RD
4292 wxGridCellAttr* attr = GetCellAttr(row, col);
4293 bool changed = attr->GetEditor()->EndEdit(row, col, TRUE, this, attr);
2d66e025 4294
2c9a89e0 4295 attr->DecRef();
2d66e025 4296
2c9a89e0 4297 if (changed) {
2d66e025
MB
4298 SendEvent( EVT_GRID_CELL_CHANGE,
4299 m_currentCellCoords.GetRow(),
4300 m_currentCellCoords.GetCol() );
4301 }
f85afd4e
MB
4302 }
4303}
4304
2d66e025
MB
4305
4306//
60ff3b99
VZ
4307// ------ Grid location functions
4308// Note that all of these functions work with the logical coordinates of
2d66e025
MB
4309// grid cells and labels so you will need to convert from device
4310// coordinates for mouse events etc.
4311//
4312
4313void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
f85afd4e 4314{
58dd5b3b
MB
4315 int row = YToRow(y);
4316 int col = XToCol(x);
4317
4318 if ( row == -1 || col == -1 )
4319 {
4320 coords = wxGridNoCellCoords;
4321 }
4322 else
4323 {
4324 coords.Set( row, col );
4325 }
2d66e025 4326}
f85afd4e 4327
8f177c8e 4328
2d66e025
MB
4329int wxGrid::YToRow( int y )
4330{
4331 int i;
8f177c8e 4332
2d66e025 4333 for ( i = 0; i < m_numRows; i++ )
f85afd4e 4334 {
2d66e025 4335 if ( y < m_rowBottoms[i] ) return i;
f85afd4e 4336 }
2d66e025 4337
07296f0b 4338 return m_numRows; //-1;
f85afd4e
MB
4339}
4340
2d66e025
MB
4341
4342int wxGrid::XToCol( int x )
f85afd4e 4343{
2d66e025 4344 int i;
8f177c8e 4345
2d66e025 4346 for ( i = 0; i < m_numCols; i++ )
f85afd4e 4347 {
2d66e025 4348 if ( x < m_colRights[i] ) return i;
f85afd4e
MB
4349 }
4350
07296f0b 4351 return m_numCols; //-1;
2d66e025 4352}
8f177c8e 4353
2d66e025
MB
4354
4355// return the row number that that the y coord is near the edge of, or
4356// -1 if not near an edge
4357//
4358int wxGrid::YToEdgeOfRow( int y )
4359{
4360 int i, d;
4361
4362 for ( i = 0; i < m_numRows; i++ )
4363 {
4364 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
f85afd4e 4365 {
2d66e025 4366 d = abs( y - m_rowBottoms[i] );
3f296516 4367 {
2d66e025 4368 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3f296516 4369 }
f85afd4e 4370 }
f85afd4e 4371 }
2d66e025
MB
4372
4373 return -1;
4374}
4375
4376
4377// return the col number that that the x coord is near the edge of, or
4378// -1 if not near an edge
4379//
4380int wxGrid::XToEdgeOfCol( int x )
4381{
4382 int i, d;
4383
4384 for ( i = 0; i < m_numCols; i++ )
f85afd4e 4385 {
2d66e025
MB
4386 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
4387 {
4388 d = abs( x - m_colRights[i] );
4389 {
4390 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
4391 }
4392 }
f85afd4e 4393 }
2d66e025
MB
4394
4395 return -1;
f85afd4e
MB
4396}
4397
2d66e025
MB
4398
4399wxRect wxGrid::CellToRect( int row, int col )
f85afd4e 4400{
2d66e025 4401 wxRect rect( -1, -1, -1, -1 );
f85afd4e 4402
2d66e025
MB
4403 if ( row >= 0 && row < m_numRows &&
4404 col >= 0 && col < m_numCols )
f85afd4e 4405 {
2d66e025
MB
4406 rect.x = m_colRights[col] - m_colWidths[col];
4407 rect.y = m_rowBottoms[row] - m_rowHeights[row];
4408 rect.width = m_colWidths[col];
4409 rect.height = m_rowHeights[ row ];
f85afd4e
MB
4410 }
4411
2d66e025
MB
4412 return rect;
4413}
4414
4415
4416bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
4417{
4418 // get the cell rectangle in logical coords
4419 //
4420 wxRect r( CellToRect( row, col ) );
60ff3b99 4421
2d66e025
MB
4422 // convert to device coords
4423 //
4424 int left, top, right, bottom;
4425 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4426 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 4427
2d66e025
MB
4428 // check against the client area of the grid window
4429 //
4430 int cw, ch;
4431 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 4432
2d66e025 4433 if ( wholeCellVisible )
f85afd4e 4434 {
2d66e025 4435 // is the cell wholly visible ?
8f177c8e 4436 //
2d66e025
MB
4437 return ( left >= 0 && right <= cw &&
4438 top >= 0 && bottom <= ch );
4439 }
4440 else
4441 {
4442 // is the cell partly visible ?
4443 //
4444 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
4445 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
4446 }
4447}
4448
4449
4450// make the specified cell location visible by doing a minimal amount
4451// of scrolling
4452//
4453void wxGrid::MakeCellVisible( int row, int col )
4454{
4455 int i;
60ff3b99 4456 int xpos = -1, ypos = -1;
2d66e025
MB
4457
4458 if ( row >= 0 && row < m_numRows &&
4459 col >= 0 && col < m_numCols )
4460 {
4461 // get the cell rectangle in logical coords
4462 //
4463 wxRect r( CellToRect( row, col ) );
60ff3b99 4464
2d66e025
MB
4465 // convert to device coords
4466 //
4467 int left, top, right, bottom;
4468 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4469 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 4470
2d66e025
MB
4471 int cw, ch;
4472 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 4473
2d66e025 4474 if ( top < 0 )
3f296516 4475 {
2d66e025 4476 ypos = r.GetTop();
3f296516 4477 }
2d66e025
MB
4478 else if ( bottom > ch )
4479 {
4480 int h = r.GetHeight();
4481 ypos = r.GetTop();
4482 for ( i = row-1; i >= 0; i-- )
4483 {
4484 if ( h + m_rowHeights[i] > ch ) break;
4485
4486 h += m_rowHeights[i];
4487 ypos -= m_rowHeights[i];
4488 }
f0102d2a
VZ
4489
4490 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
4491 // have rounding errors (this is important, because if we do, we
4492 // might not scroll at all and some cells won't be redrawn)
4493 ypos += GRID_SCROLL_LINE / 2;
2d66e025
MB
4494 }
4495
4496 if ( left < 0 )
4497 {
4498 xpos = r.GetLeft();
4499 }
4500 else if ( right > cw )
4501 {
4502 int w = r.GetWidth();
4503 xpos = r.GetLeft();
4504 for ( i = col-1; i >= 0; i-- )
4505 {
4506 if ( w + m_colWidths[i] > cw ) break;
4507
4508 w += m_colWidths[i];
4509 xpos -= m_colWidths[i];
4510 }
f0102d2a
VZ
4511
4512 // see comment for ypos above
4513 xpos += GRID_SCROLL_LINE / 2;
2d66e025
MB
4514 }
4515
4516 if ( xpos != -1 || ypos != -1 )
4517 {
f0102d2a
VZ
4518 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
4519 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
2d66e025
MB
4520 Scroll( xpos, ypos );
4521 AdjustScrollbars();
4522 }
4523 }
4524}
4525
4526
4527//
4528// ------ Grid cursor movement functions
4529//
4530
4531bool wxGrid::MoveCursorUp()
4532{
4533 if ( m_currentCellCoords != wxGridNoCellCoords &&
4534 m_currentCellCoords.GetRow() > 0 )
4535 {
4536 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
4537 m_currentCellCoords.GetCol() );
60ff3b99 4538
2d66e025
MB
4539 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
4540 m_currentCellCoords.GetCol() );
4541
8f177c8e 4542 return TRUE;
f85afd4e 4543 }
2d66e025
MB
4544
4545 return FALSE;
4546}
4547
4548
4549bool wxGrid::MoveCursorDown()
4550{
4551 // TODO: allow for scrolling
4552 //
4553 if ( m_currentCellCoords != wxGridNoCellCoords &&
4554 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 4555 {
2d66e025
MB
4556 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
4557 m_currentCellCoords.GetCol() );
60ff3b99 4558
2d66e025
MB
4559 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
4560 m_currentCellCoords.GetCol() );
4561
4562 return TRUE;
f85afd4e 4563 }
2d66e025
MB
4564
4565 return FALSE;
f85afd4e
MB
4566}
4567
2d66e025
MB
4568
4569bool wxGrid::MoveCursorLeft()
f85afd4e 4570{
2d66e025
MB
4571 if ( m_currentCellCoords != wxGridNoCellCoords &&
4572 m_currentCellCoords.GetCol() > 0 )
4573 {
4574 MakeCellVisible( m_currentCellCoords.GetRow(),
4575 m_currentCellCoords.GetCol() - 1 );
60ff3b99 4576
2d66e025
MB
4577 SetCurrentCell( m_currentCellCoords.GetRow(),
4578 m_currentCellCoords.GetCol() - 1 );
8f177c8e 4579
2d66e025
MB
4580 return TRUE;
4581 }
4582
4583 return FALSE;
4584}
4585
4586
4587bool wxGrid::MoveCursorRight()
4588{
4589 if ( m_currentCellCoords != wxGridNoCellCoords &&
4590 m_currentCellCoords.GetCol() < m_numCols - 1 )
f85afd4e 4591 {
2d66e025
MB
4592 MakeCellVisible( m_currentCellCoords.GetRow(),
4593 m_currentCellCoords.GetCol() + 1 );
60ff3b99 4594
2d66e025
MB
4595 SetCurrentCell( m_currentCellCoords.GetRow(),
4596 m_currentCellCoords.GetCol() + 1 );
4597
4598 return TRUE;
f85afd4e 4599 }
8f177c8e 4600
2d66e025
MB
4601 return FALSE;
4602}
4603
4604
4605bool wxGrid::MovePageUp()
4606{
4607 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 4608
2d66e025
MB
4609 int row = m_currentCellCoords.GetRow();
4610 if ( row > 0 )
f85afd4e 4611 {
2d66e025
MB
4612 int cw, ch;
4613 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 4614
2d66e025
MB
4615 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4616 int newRow = YToRow( y - ch + 1 );
4617 if ( newRow == -1 )
4618 {
4619 newRow = 0;
4620 }
60ff3b99 4621 else if ( newRow == row )
2d66e025
MB
4622 {
4623 newRow = row - 1;
4624 }
8f177c8e 4625
2d66e025
MB
4626 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4627 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 4628
f85afd4e
MB
4629 return TRUE;
4630 }
2d66e025
MB
4631
4632 return FALSE;
4633}
4634
4635bool wxGrid::MovePageDown()
4636{
4637 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 4638
2d66e025
MB
4639 int row = m_currentCellCoords.GetRow();
4640 if ( row < m_numRows )
f85afd4e 4641 {
2d66e025
MB
4642 int cw, ch;
4643 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 4644
2d66e025
MB
4645 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4646 int newRow = YToRow( y + ch );
4647 if ( newRow == -1 )
4648 {
4649 newRow = m_numRows - 1;
4650 }
60ff3b99 4651 else if ( newRow == row )
2d66e025
MB
4652 {
4653 newRow = row + 1;
4654 }
4655
4656 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4657 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 4658
2d66e025 4659 return TRUE;
f85afd4e 4660 }
2d66e025
MB
4661
4662 return FALSE;
f85afd4e 4663}
8f177c8e 4664
2d66e025
MB
4665bool wxGrid::MoveCursorUpBlock()
4666{
4667 if ( m_table &&
4668 m_currentCellCoords != wxGridNoCellCoords &&
4669 m_currentCellCoords.GetRow() > 0 )
4670 {
4671 int row = m_currentCellCoords.GetRow();
4672 int col = m_currentCellCoords.GetCol();
4673
4674 if ( m_table->IsEmptyCell(row, col) )
4675 {
4676 // starting in an empty cell: find the next block of
4677 // non-empty cells
4678 //
4679 while ( row > 0 )
4680 {
4681 row-- ;
4682 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4683 }
4684 }
4685 else if ( m_table->IsEmptyCell(row-1, col) )
4686 {
4687 // starting at the top of a block: find the next block
4688 //
4689 row--;
4690 while ( row > 0 )
4691 {
4692 row-- ;
4693 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4694 }
4695 }
4696 else
4697 {
4698 // starting within a block: find the top of the block
4699 //
4700 while ( row > 0 )
4701 {
4702 row-- ;
4703 if ( m_table->IsEmptyCell(row, col) )
4704 {
4705 row++ ;
4706 break;
4707 }
4708 }
4709 }
f85afd4e 4710
2d66e025
MB
4711 MakeCellVisible( row, col );
4712 SetCurrentCell( row, col );
f85afd4e 4713
2d66e025
MB
4714 return TRUE;
4715 }
f85afd4e 4716
2d66e025
MB
4717 return FALSE;
4718}
f85afd4e 4719
2d66e025 4720bool wxGrid::MoveCursorDownBlock()
f85afd4e 4721{
2d66e025
MB
4722 if ( m_table &&
4723 m_currentCellCoords != wxGridNoCellCoords &&
4724 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 4725 {
2d66e025
MB
4726 int row = m_currentCellCoords.GetRow();
4727 int col = m_currentCellCoords.GetCol();
4728
4729 if ( m_table->IsEmptyCell(row, col) )
4730 {
4731 // starting in an empty cell: find the next block of
4732 // non-empty cells
4733 //
4734 while ( row < m_numRows-1 )
4735 {
4736 row++ ;
4737 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4738 }
4739 }
4740 else if ( m_table->IsEmptyCell(row+1, col) )
4741 {
4742 // starting at the bottom of a block: find the next block
4743 //
4744 row++;
4745 while ( row < m_numRows-1 )
4746 {
4747 row++ ;
4748 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4749 }
4750 }
4751 else
4752 {
4753 // starting within a block: find the bottom of the block
4754 //
4755 while ( row < m_numRows-1 )
4756 {
4757 row++ ;
4758 if ( m_table->IsEmptyCell(row, col) )
4759 {
4760 row-- ;
4761 break;
4762 }
4763 }
4764 }
4765
4766 MakeCellVisible( row, col );
4767 SetCurrentCell( row, col );
4768
4769 return TRUE;
f85afd4e 4770 }
f85afd4e 4771
2d66e025
MB
4772 return FALSE;
4773}
f85afd4e 4774
2d66e025 4775bool wxGrid::MoveCursorLeftBlock()
f85afd4e 4776{
2d66e025
MB
4777 if ( m_table &&
4778 m_currentCellCoords != wxGridNoCellCoords &&
4779 m_currentCellCoords.GetCol() > 0 )
f85afd4e 4780 {
2d66e025
MB
4781 int row = m_currentCellCoords.GetRow();
4782 int col = m_currentCellCoords.GetCol();
4783
4784 if ( m_table->IsEmptyCell(row, col) )
4785 {
4786 // starting in an empty cell: find the next block of
4787 // non-empty cells
4788 //
4789 while ( col > 0 )
4790 {
4791 col-- ;
4792 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4793 }
4794 }
4795 else if ( m_table->IsEmptyCell(row, col-1) )
4796 {
4797 // starting at the left of a block: find the next block
4798 //
4799 col--;
4800 while ( col > 0 )
4801 {
4802 col-- ;
4803 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4804 }
4805 }
4806 else
4807 {
4808 // starting within a block: find the left of the block
4809 //
4810 while ( col > 0 )
4811 {
4812 col-- ;
4813 if ( m_table->IsEmptyCell(row, col) )
4814 {
4815 col++ ;
4816 break;
4817 }
4818 }
4819 }
f85afd4e 4820
2d66e025
MB
4821 MakeCellVisible( row, col );
4822 SetCurrentCell( row, col );
8f177c8e 4823
2d66e025 4824 return TRUE;
f85afd4e 4825 }
2d66e025
MB
4826
4827 return FALSE;
f85afd4e
MB
4828}
4829
2d66e025 4830bool wxGrid::MoveCursorRightBlock()
f85afd4e 4831{
2d66e025
MB
4832 if ( m_table &&
4833 m_currentCellCoords != wxGridNoCellCoords &&
4834 m_currentCellCoords.GetCol() < m_numCols-1 )
f85afd4e 4835 {
2d66e025
MB
4836 int row = m_currentCellCoords.GetRow();
4837 int col = m_currentCellCoords.GetCol();
8f177c8e 4838
2d66e025
MB
4839 if ( m_table->IsEmptyCell(row, col) )
4840 {
4841 // starting in an empty cell: find the next block of
4842 // non-empty cells
4843 //
4844 while ( col < m_numCols-1 )
4845 {
4846 col++ ;
4847 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4848 }
4849 }
4850 else if ( m_table->IsEmptyCell(row, col+1) )
4851 {
4852 // starting at the right of a block: find the next block
4853 //
4854 col++;
4855 while ( col < m_numCols-1 )
4856 {
4857 col++ ;
4858 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4859 }
4860 }
4861 else
4862 {
4863 // starting within a block: find the right of the block
4864 //
4865 while ( col < m_numCols-1 )
4866 {
4867 col++ ;
4868 if ( m_table->IsEmptyCell(row, col) )
4869 {
4870 col-- ;
4871 break;
4872 }
4873 }
4874 }
8f177c8e 4875
2d66e025
MB
4876 MakeCellVisible( row, col );
4877 SetCurrentCell( row, col );
f85afd4e 4878
2d66e025 4879 return TRUE;
f85afd4e 4880 }
2d66e025
MB
4881
4882 return FALSE;
f85afd4e
MB
4883}
4884
4885
2d66e025 4886
f85afd4e 4887//
2d66e025 4888// ------ Label values and formatting
f85afd4e
MB
4889//
4890
4891void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
4892{
4893 *horiz = m_rowLabelHorizAlign;
4894 *vert = m_rowLabelVertAlign;
4895}
4896
4897void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
4898{
4899 *horiz = m_colLabelHorizAlign;
4900 *vert = m_colLabelVertAlign;
4901}
4902
4903wxString wxGrid::GetRowLabelValue( int row )
4904{
4905 if ( m_table )
4906 {
4907 return m_table->GetRowLabelValue( row );
4908 }
4909 else
4910 {
4911 wxString s;
4912 s << row;
4913 return s;
4914 }
4915}
4916
4917wxString wxGrid::GetColLabelValue( int col )
4918{
4919 if ( m_table )
4920 {
4921 return m_table->GetColLabelValue( col );
4922 }
4923 else
4924 {
4925 wxString s;
4926 s << col;
4927 return s;
4928 }
4929}
4930
2e8cd977 4931
f85afd4e
MB
4932void wxGrid::SetRowLabelSize( int width )
4933{
2e8cd977
MB
4934 width = wxMax( width, 0 );
4935 if ( width != m_rowLabelWidth )
4936 {
2e8cd977
MB
4937 if ( width == 0 )
4938 {
4939 m_rowLabelWin->Show( FALSE );
7807d81c 4940 m_cornerLabelWin->Show( FALSE );
2e8cd977 4941 }
7807d81c 4942 else if ( m_rowLabelWidth == 0 )
2e8cd977 4943 {
7807d81c
MB
4944 m_rowLabelWin->Show( TRUE );
4945 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
2e8cd977 4946 }
b99be8fb 4947
2e8cd977 4948 m_rowLabelWidth = width;
7807d81c
MB
4949 CalcWindowSizes();
4950 Refresh( TRUE );
2e8cd977 4951 }
f85afd4e
MB
4952}
4953
2e8cd977 4954
f85afd4e
MB
4955void wxGrid::SetColLabelSize( int height )
4956{
7807d81c 4957 height = wxMax( height, 0 );
2e8cd977
MB
4958 if ( height != m_colLabelHeight )
4959 {
2e8cd977
MB
4960 if ( height == 0 )
4961 {
2e8cd977 4962 m_colLabelWin->Show( FALSE );
7807d81c 4963 m_cornerLabelWin->Show( FALSE );
2e8cd977 4964 }
7807d81c 4965 else if ( m_colLabelHeight == 0 )
2e8cd977 4966 {
7807d81c
MB
4967 m_colLabelWin->Show( TRUE );
4968 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
2e8cd977 4969 }
7807d81c 4970
2e8cd977 4971 m_colLabelHeight = height;
7807d81c
MB
4972 CalcWindowSizes();
4973 Refresh( TRUE );
2e8cd977 4974 }
f85afd4e
MB
4975}
4976
2e8cd977 4977
f85afd4e
MB
4978void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
4979{
2d66e025
MB
4980 if ( m_labelBackgroundColour != colour )
4981 {
4982 m_labelBackgroundColour = colour;
4983 m_rowLabelWin->SetBackgroundColour( colour );
4984 m_colLabelWin->SetBackgroundColour( colour );
4985 m_cornerLabelWin->SetBackgroundColour( colour );
4986
4987 if ( !GetBatchCount() )
4988 {
4989 m_rowLabelWin->Refresh();
4990 m_colLabelWin->Refresh();
4991 m_cornerLabelWin->Refresh();
4992 }
4993 }
f85afd4e
MB
4994}
4995
4996void wxGrid::SetLabelTextColour( const wxColour& colour )
4997{
2d66e025
MB
4998 if ( m_labelTextColour != colour )
4999 {
5000 m_labelTextColour = colour;
5001 if ( !GetBatchCount() )
5002 {
5003 m_rowLabelWin->Refresh();
5004 m_colLabelWin->Refresh();
5005 }
5006 }
f85afd4e
MB
5007}
5008
5009void wxGrid::SetLabelFont( const wxFont& font )
5010{
5011 m_labelFont = font;
2d66e025
MB
5012 if ( !GetBatchCount() )
5013 {
5014 m_rowLabelWin->Refresh();
5015 m_colLabelWin->Refresh();
5016 }
f85afd4e
MB
5017}
5018
5019void wxGrid::SetRowLabelAlignment( int horiz, int vert )
5020{
5021 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
5022 {
5023 m_rowLabelHorizAlign = horiz;
5024 }
8f177c8e 5025
f85afd4e
MB
5026 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
5027 {
5028 m_rowLabelVertAlign = vert;
5029 }
5030
2d66e025
MB
5031 if ( !GetBatchCount() )
5032 {
5033 m_rowLabelWin->Refresh();
60ff3b99 5034 }
f85afd4e
MB
5035}
5036
5037void wxGrid::SetColLabelAlignment( int horiz, int vert )
5038{
5039 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
5040 {
5041 m_colLabelHorizAlign = horiz;
5042 }
8f177c8e 5043
f85afd4e
MB
5044 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
5045 {
5046 m_colLabelVertAlign = vert;
5047 }
5048
2d66e025
MB
5049 if ( !GetBatchCount() )
5050 {
2d66e025 5051 m_colLabelWin->Refresh();
60ff3b99 5052 }
f85afd4e
MB
5053}
5054
5055void wxGrid::SetRowLabelValue( int row, const wxString& s )
5056{
5057 if ( m_table )
5058 {
5059 m_table->SetRowLabelValue( row, s );
2d66e025
MB
5060 if ( !GetBatchCount() )
5061 {
70c7a608
SN
5062 wxRect rect = CellToRect( row, 0);
5063 if ( rect.height > 0 )
5064 {
cb309039 5065 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
70c7a608
SN
5066 rect.x = m_left;
5067 rect.width = m_rowLabelWidth;
5068 m_rowLabelWin->Refresh( TRUE, &rect );
5069 }
2d66e025 5070 }
f85afd4e
MB
5071 }
5072}
5073
5074void wxGrid::SetColLabelValue( int col, const wxString& s )
5075{
5076 if ( m_table )
5077 {
5078 m_table->SetColLabelValue( col, s );
2d66e025
MB
5079 if ( !GetBatchCount() )
5080 {
70c7a608
SN
5081 wxRect rect = CellToRect( 0, col );
5082 if ( rect.width > 0 )
5083 {
cb309039 5084 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
70c7a608
SN
5085 rect.y = m_top;
5086 rect.height = m_colLabelHeight;
5087 m_colLabelWin->Refresh( TRUE, &rect );
5088 }
2d66e025 5089 }
f85afd4e
MB
5090 }
5091}
5092
5093void wxGrid::SetGridLineColour( const wxColour& colour )
5094{
2d66e025
MB
5095 if ( m_gridLineColour != colour )
5096 {
5097 m_gridLineColour = colour;
60ff3b99 5098
2d66e025
MB
5099 wxClientDC dc( m_gridWin );
5100 PrepareDC( dc );
c6a51dcd 5101 DrawAllGridLines( dc, wxRegion() );
2d66e025 5102 }
f85afd4e
MB
5103}
5104
5105void wxGrid::EnableGridLines( bool enable )
5106{
5107 if ( enable != m_gridLinesEnabled )
5108 {
5109 m_gridLinesEnabled = enable;
2d66e025
MB
5110
5111 if ( !GetBatchCount() )
5112 {
5113 if ( enable )
5114 {
5115 wxClientDC dc( m_gridWin );
5116 PrepareDC( dc );
c6a51dcd 5117 DrawAllGridLines( dc, wxRegion() );
2d66e025
MB
5118 }
5119 else
5120 {
5121 m_gridWin->Refresh();
5122 }
5123 }
f85afd4e
MB
5124 }
5125}
5126
5127
5128int wxGrid::GetDefaultRowSize()
5129{
5130 return m_defaultRowHeight;
5131}
5132
5133int wxGrid::GetRowSize( int row )
5134{
b99be8fb
VZ
5135 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
5136
5137 return m_rowHeights[row];
f85afd4e
MB
5138}
5139
5140int wxGrid::GetDefaultColSize()
5141{
5142 return m_defaultColWidth;
5143}
5144
5145int wxGrid::GetColSize( int col )
5146{
b99be8fb
VZ
5147 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
5148
5149 return m_colWidths[col];
f85afd4e
MB
5150}
5151
2e9a6788
VZ
5152// ============================================================================
5153// access to the grid attributes: each of them has a default value in the grid
5154// itself and may be overidden on a per-cell basis
5155// ============================================================================
5156
5157// ----------------------------------------------------------------------------
5158// setting default attributes
5159// ----------------------------------------------------------------------------
5160
5161void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
5162{
2796cce3 5163 m_defaultCellAttr->SetBackgroundColour(col);
2e9a6788
VZ
5164}
5165
5166void wxGrid::SetDefaultCellTextColour( const wxColour& col )
5167{
2796cce3 5168 m_defaultCellAttr->SetTextColour(col);
2e9a6788
VZ
5169}
5170
5171void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
5172{
2796cce3 5173 m_defaultCellAttr->SetAlignment(horiz, vert);
2e9a6788
VZ
5174}
5175
5176void wxGrid::SetDefaultCellFont( const wxFont& font )
5177{
2796cce3
RD
5178 m_defaultCellAttr->SetFont(font);
5179}
5180
5181void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
5182{
5183 m_defaultCellAttr->SetRenderer(renderer);
2e9a6788
VZ
5184}
5185
9b4aede2
RD
5186void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
5187{
5188 m_defaultCellAttr->SetEditor(editor);
5189}
5190
2e9a6788
VZ
5191// ----------------------------------------------------------------------------
5192// access to the default attrbiutes
5193// ----------------------------------------------------------------------------
5194
f85afd4e
MB
5195wxColour wxGrid::GetDefaultCellBackgroundColour()
5196{
2796cce3 5197 return m_defaultCellAttr->GetBackgroundColour();
f85afd4e
MB
5198}
5199
2e9a6788
VZ
5200wxColour wxGrid::GetDefaultCellTextColour()
5201{
2796cce3 5202 return m_defaultCellAttr->GetTextColour();
2e9a6788
VZ
5203}
5204
5205wxFont wxGrid::GetDefaultCellFont()
5206{
2796cce3 5207 return m_defaultCellAttr->GetFont();
2e9a6788
VZ
5208}
5209
5210void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
5211{
2796cce3 5212 m_defaultCellAttr->GetAlignment(horiz, vert);
2e9a6788
VZ
5213}
5214
2796cce3 5215wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
ab79958a 5216{
2796cce3 5217 return m_defaultCellAttr->GetRenderer();
ab79958a
VZ
5218}
5219
9b4aede2
RD
5220wxGridCellEditor *wxGrid::GetDefaultEditor() const
5221{
5222 return m_defaultCellAttr->GetEditor();
5223}
5224
2e9a6788
VZ
5225// ----------------------------------------------------------------------------
5226// access to cell attributes
5227// ----------------------------------------------------------------------------
5228
b99be8fb 5229wxColour wxGrid::GetCellBackgroundColour(int row, int col)
f85afd4e 5230{
0a976765 5231 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 5232 wxColour colour = attr->GetBackgroundColour();
2e9a6788 5233 attr->SafeDecRef();
b99be8fb 5234 return colour;
f85afd4e
MB
5235}
5236
b99be8fb 5237wxColour wxGrid::GetCellTextColour( int row, int col )
f85afd4e 5238{
0a976765 5239 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 5240 wxColour colour = attr->GetTextColour();
2e9a6788 5241 attr->SafeDecRef();
b99be8fb 5242 return colour;
f85afd4e
MB
5243}
5244
b99be8fb 5245wxFont wxGrid::GetCellFont( int row, int col )
f85afd4e 5246{
0a976765 5247 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 5248 wxFont font = attr->GetFont();
2e9a6788 5249 attr->SafeDecRef();
b99be8fb 5250 return font;
f85afd4e
MB
5251}
5252
b99be8fb 5253void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
f85afd4e 5254{
0a976765 5255 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 5256 attr->GetAlignment(horiz, vert);
2e9a6788
VZ
5257 attr->SafeDecRef();
5258}
5259
2796cce3
RD
5260wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
5261{
5262 wxGridCellAttr* attr = GetCellAttr(row, col);
5263 wxGridCellRenderer* renderer = attr->GetRenderer();
5264 attr->DecRef();
5265 return renderer;
5266}
5267
9b4aede2
RD
5268wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
5269{
5270 wxGridCellAttr* attr = GetCellAttr(row, col);
5271 wxGridCellEditor* editor = attr->GetEditor();
5272 attr->DecRef();
5273 return editor;
5274}
5275
2e9a6788 5276// ----------------------------------------------------------------------------
758cbedf 5277// attribute support: cache, automatic provider creation, ...
2e9a6788
VZ
5278// ----------------------------------------------------------------------------
5279
5280bool wxGrid::CanHaveAttributes()
5281{
5282 if ( !m_table )
5283 {
5284 return FALSE;
5285 }
5286
2796cce3
RD
5287 // RD: Maybe m_table->CanHaveAttributes() would be better in case the
5288 // table is providing the attributes itself??? In which case
5289 // I don't think the grid should create a Provider object for the
5290 // table but the table should be smart enough to do that on its own.
2e9a6788
VZ
5291 if ( !m_table->GetAttrProvider() )
5292 {
5293 // use the default attr provider by default
5294 // (another choice would be to just return FALSE thus forcing the user
5295 // to it himself)
5296 m_table->SetAttrProvider(new wxGridCellAttrProvider);
5297 }
5298
5299 return TRUE;
5300}
5301
0a976765
VZ
5302void wxGrid::ClearAttrCache()
5303{
5304 if ( m_attrCache.row != -1 )
5305 {
5306 m_attrCache.attr->SafeDecRef();
5307 m_attrCache.row = -1;
5308 }
5309}
5310
5311void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
5312{
5313 wxGrid *self = (wxGrid *)this; // const_cast
5314
5315 self->ClearAttrCache();
5316 self->m_attrCache.row = row;
5317 self->m_attrCache.col = col;
5318 self->m_attrCache.attr = attr;
5319 attr->SafeIncRef();
5320}
5321
5322bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
5323{
5324 if ( row == m_attrCache.row && col == m_attrCache.col )
5325 {
5326 *attr = m_attrCache.attr;
5327 (*attr)->SafeIncRef();
5328
5329#ifdef DEBUG_ATTR_CACHE
5330 gs_nAttrCacheHits++;
5331#endif
5332
5333 return TRUE;
5334 }
5335 else
5336 {
5337#ifdef DEBUG_ATTR_CACHE
5338 gs_nAttrCacheMisses++;
5339#endif
5340 return FALSE;
5341 }
5342}
5343
2e9a6788
VZ
5344wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
5345{
0a976765
VZ
5346 wxGridCellAttr *attr;
5347 if ( !LookupAttr(row, col, &attr) )
2e9a6788 5348 {
0a976765
VZ
5349 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
5350 CacheAttr(row, col, attr);
5351 }
2796cce3
RD
5352 if (attr) {
5353 attr->SetDefAttr(m_defaultCellAttr);
5354 } else {
5355 attr = m_defaultCellAttr;
5356 attr->IncRef();
5357 }
2e9a6788 5358
0a976765
VZ
5359 return attr;
5360}
5361
5362wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
5363{
5364 wxGridCellAttr *attr;
5365 if ( !LookupAttr(row, col, &attr) || !attr )
5366 {
5367 wxASSERT_MSG( m_table,
5368 _T("we may only be called if CanHaveAttributes() "
5369 "returned TRUE and then m_table should be !NULL") );
5370
5371 attr = m_table->GetAttr(row, col);
5372 if ( !attr )
5373 {
5374 attr = new wxGridCellAttr;
5375
5376 // artificially inc the ref count to match DecRef() in caller
5377 attr->IncRef();
5378
5379 m_table->SetAttr(attr, row, col);
5380 }
2e9a6788 5381
0a976765 5382 CacheAttr(row, col, attr);
2e9a6788 5383 }
2796cce3 5384 attr->SetDefAttr(m_defaultCellAttr);
2e9a6788
VZ
5385 return attr;
5386}
5387
758cbedf
VZ
5388// ----------------------------------------------------------------------------
5389// setting cell attributes: this is forwarded to the table
5390// ----------------------------------------------------------------------------
5391
5392void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
5393{
5394 if ( CanHaveAttributes() )
5395 {
5396 m_table->SetRowAttr(attr, row);
5397 }
5398 else
5399 {
5400 attr->SafeDecRef();
5401 }
5402}
5403
5404void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
5405{
5406 if ( CanHaveAttributes() )
5407 {
5408 m_table->SetColAttr(attr, col);
5409 }
5410 else
5411 {
5412 attr->SafeDecRef();
5413 }
5414}
5415
2e9a6788
VZ
5416void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
5417{
5418 if ( CanHaveAttributes() )
5419 {
0a976765 5420 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
5421 attr->SetBackgroundColour(colour);
5422 attr->DecRef();
5423 }
5424}
5425
5426void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
5427{
5428 if ( CanHaveAttributes() )
5429 {
0a976765 5430 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
5431 attr->SetTextColour(colour);
5432 attr->DecRef();
5433 }
5434}
5435
5436void wxGrid::SetCellFont( int row, int col, const wxFont& font )
5437{
5438 if ( CanHaveAttributes() )
5439 {
0a976765 5440 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
5441 attr->SetFont(font);
5442 attr->DecRef();
5443 }
5444}
5445
5446void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
5447{
5448 if ( CanHaveAttributes() )
5449 {
0a976765 5450 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
5451 attr->SetAlignment(horiz, vert);
5452 attr->DecRef();
ab79958a
VZ
5453 }
5454}
5455
5456void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
5457{
5458 if ( CanHaveAttributes() )
5459 {
0a976765 5460 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
ab79958a
VZ
5461 attr->SetRenderer(renderer);
5462 attr->DecRef();
9b4aede2
RD
5463 }
5464}
5465
5466void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
5467{
5468 if ( CanHaveAttributes() )
5469 {
5470 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
5471 attr->SetEditor(editor);
5472 attr->DecRef();
2e9a6788 5473 }
f85afd4e
MB
5474}
5475
2e9a6788
VZ
5476// ----------------------------------------------------------------------------
5477// row/col size
5478// ----------------------------------------------------------------------------
5479
f85afd4e
MB
5480void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
5481{
5482 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
5483
5484 if ( resizeExistingRows )
5485 {
f85afd4e 5486 int row;
2d66e025 5487 int bottom = 0;
f85afd4e
MB
5488 for ( row = 0; row < m_numRows; row++ )
5489 {
5490 m_rowHeights[row] = m_defaultRowHeight;
2d66e025
MB
5491 bottom += m_defaultRowHeight;
5492 m_rowBottoms[row] = bottom;
f85afd4e
MB
5493 }
5494 CalcDimensions();
f85afd4e
MB
5495 }
5496}
5497
5498void wxGrid::SetRowSize( int row, int height )
5499{
b99be8fb 5500 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
60ff3b99 5501
b99be8fb 5502 int i;
60ff3b99 5503
b99be8fb
VZ
5504 int h = wxMax( 0, height );
5505 int diff = h - m_rowHeights[row];
60ff3b99 5506
b99be8fb
VZ
5507 m_rowHeights[row] = h;
5508 for ( i = row; i < m_numRows; i++ )
f85afd4e 5509 {
b99be8fb 5510 m_rowBottoms[i] += diff;
f85afd4e 5511 }
b99be8fb 5512 CalcDimensions();
f85afd4e
MB
5513}
5514
5515void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
5516{
5517 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
5518
5519 if ( resizeExistingCols )
5520 {
f85afd4e 5521 int col;
2d66e025 5522 int right = 0;
f85afd4e
MB
5523 for ( col = 0; col < m_numCols; col++ )
5524 {
5525 m_colWidths[col] = m_defaultColWidth;
2d66e025
MB
5526 right += m_defaultColWidth;
5527 m_colRights[col] = right;
f85afd4e
MB
5528 }
5529 CalcDimensions();
f85afd4e
MB
5530 }
5531}
5532
5533void wxGrid::SetColSize( int col, int width )
5534{
b99be8fb 5535 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
60ff3b99 5536
b99be8fb 5537 int i;
f85afd4e 5538
b99be8fb
VZ
5539 int w = wxMax( 0, width );
5540 int diff = w - m_colWidths[col];
5541 m_colWidths[col] = w;
60ff3b99 5542
b99be8fb 5543 for ( i = col; i < m_numCols; i++ )
f85afd4e 5544 {
b99be8fb 5545 m_colRights[i] += diff;
f85afd4e 5546 }
b99be8fb 5547 CalcDimensions();
f85afd4e
MB
5548}
5549
2d66e025 5550
f85afd4e
MB
5551//
5552// ------ cell value accessor functions
5553//
5554
5555void wxGrid::SetCellValue( int row, int col, const wxString& s )
5556{
5557 if ( m_table )
5558 {
5559 m_table->SetValue( row, col, s.c_str() );
2d66e025
MB
5560 if ( !GetBatchCount() )
5561 {
5562 wxClientDC dc( m_gridWin );
5563 PrepareDC( dc );
5564 DrawCell( dc, wxGridCellCoords(row, col) );
5565 }
60ff3b99 5566
2d66e025 5567#if 0 // TODO: edit in place
60ff3b99 5568
f85afd4e
MB
5569 if ( m_currentCellCoords.GetRow() == row &&
5570 m_currentCellCoords.GetCol() == col )
5571 {
5572 SetEditControlValue( s );
5573 }
2d66e025 5574#endif
f85afd4e 5575
f85afd4e
MB
5576 }
5577}
5578
5579
5580//
2d66e025 5581// ------ Block, row and col selection
f85afd4e
MB
5582//
5583
5584void wxGrid::SelectRow( int row, bool addToSelected )
5585{
2d66e025 5586 wxRect r;
60ff3b99 5587
f85afd4e
MB
5588 if ( IsSelection() && addToSelected )
5589 {
70c7a608
SN
5590 wxRect rect[4];
5591 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5592 int i;
5593
5594 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5595 wxCoord oldTop = m_selectedTopLeft.GetRow();
5596 wxCoord oldRight = m_selectedBottomRight.GetCol();
5597 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5598
5599 if ( oldTop > row )
5600 {
5601 need_refresh[0] = TRUE;
5602 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
5603 wxGridCellCoords ( oldTop - 1,
5604 m_numCols - 1 ) );
f85afd4e 5605 m_selectedTopLeft.SetRow( row );
70c7a608 5606 }
8f177c8e 5607
70c7a608
SN
5608 if ( oldLeft > 0 )
5609 {
5610 need_refresh[1] = TRUE;
5611 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
5612 wxGridCellCoords ( oldBottom,
5613 oldLeft - 1 ) );
8f177c8e 5614
70c7a608
SN
5615 m_selectedTopLeft.SetCol( 0 );
5616 }
5617
5618 if ( oldBottom < row )
5619 {
5620 need_refresh[2] = TRUE;
5621 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
5622 wxGridCellCoords ( row,
5623 m_numCols - 1 ) );
f85afd4e 5624 m_selectedBottomRight.SetRow( row );
70c7a608 5625 }
8f177c8e 5626
70c7a608
SN
5627 if ( oldRight < m_numCols - 1 )
5628 {
5629 need_refresh[3] = TRUE;
5630 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
5631 oldRight + 1 ),
5632 wxGridCellCoords ( oldBottom,
5633 m_numCols - 1 ) );
5634 m_selectedBottomRight.SetCol( m_numCols - 1 );
5635 }
2d66e025 5636
70c7a608
SN
5637 for (i = 0; i < 4; i++ )
5638 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
c6a51dcd 5639 m_gridWin->Refresh( FALSE, &(rect[i]) );
f85afd4e
MB
5640 }
5641 else
5642 {
2d66e025 5643 r = SelectionToDeviceRect();
f85afd4e 5644 ClearSelection();
c6a51dcd 5645 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
60ff3b99 5646
f85afd4e
MB
5647 m_selectedTopLeft.Set( row, 0 );
5648 m_selectedBottomRight.Set( row, m_numCols-1 );
2d66e025 5649 r = SelectionToDeviceRect();
c6a51dcd 5650 m_gridWin->Refresh( FALSE, &r );
f85afd4e 5651 }
8f177c8e 5652
f85afd4e 5653 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 5654 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
5655 this,
5656 m_selectedTopLeft,
5657 m_selectedBottomRight );
5658
5659 GetEventHandler()->ProcessEvent(gridEvt);
5660}
5661
5662
5663void wxGrid::SelectCol( int col, bool addToSelected )
5664{
2d66e025 5665 if ( IsSelection() && addToSelected )
f85afd4e 5666 {
70c7a608
SN
5667 wxRect rect[4];
5668 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5669 int i;
5670
5671 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5672 wxCoord oldTop = m_selectedTopLeft.GetRow();
5673 wxCoord oldRight = m_selectedBottomRight.GetCol();
5674 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5675
5676 if ( oldLeft > col )
5677 {
5678 need_refresh[0] = TRUE;
5679 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
b99be8fb 5680 wxGridCellCoords ( m_numRows - 1,
70c7a608 5681 oldLeft - 1 ) );
f85afd4e 5682 m_selectedTopLeft.SetCol( col );
70c7a608 5683 }
f85afd4e 5684
70c7a608
SN
5685 if ( oldTop > 0 )
5686 {
5687 need_refresh[1] = TRUE;
5688 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
b99be8fb 5689 wxGridCellCoords ( oldTop - 1,
70c7a608
SN
5690 oldRight ) );
5691 m_selectedTopLeft.SetRow( 0 );
5692 }
f85afd4e 5693
70c7a608
SN
5694 if ( oldRight < col )
5695 {
5696 need_refresh[2] = TRUE;
5697 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
5698 wxGridCellCoords ( m_numRows - 1,
5699 col ) );
f85afd4e 5700 m_selectedBottomRight.SetCol( col );
70c7a608 5701 }
f85afd4e 5702
70c7a608
SN
5703 if ( oldBottom < m_numRows - 1 )
5704 {
5705 need_refresh[3] = TRUE;
5706 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
5707 oldLeft ),
5708 wxGridCellCoords ( m_numRows - 1,
5709 oldRight ) );
5710 m_selectedBottomRight.SetRow( m_numRows - 1 );
5711 }
2d66e025 5712
70c7a608
SN
5713 for (i = 0; i < 4; i++ )
5714 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
c6a51dcd 5715 m_gridWin->Refresh( FALSE, &(rect[i]) );
f85afd4e
MB
5716 }
5717 else
5718 {
70c7a608 5719 wxRect r;
b99be8fb 5720
2d66e025 5721 r = SelectionToDeviceRect();
f85afd4e 5722 ClearSelection();
c6a51dcd 5723 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
60ff3b99 5724
f85afd4e
MB
5725 m_selectedTopLeft.Set( 0, col );
5726 m_selectedBottomRight.Set( m_numRows-1, col );
2d66e025 5727 r = SelectionToDeviceRect();
c6a51dcd 5728 m_gridWin->Refresh( FALSE, &r );
f85afd4e
MB
5729 }
5730
5731 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 5732 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
5733 this,
5734 m_selectedTopLeft,
5735 m_selectedBottomRight );
5736
5737 GetEventHandler()->ProcessEvent(gridEvt);
5738}
5739
5740
5741void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
5742{
5743 int temp;
da6af900 5744 wxGridCellCoords updateTopLeft, updateBottomRight;
8f177c8e 5745
f85afd4e
MB
5746 if ( topRow > bottomRow )
5747 {
5748 temp = topRow;
5749 topRow = bottomRow;
5750 bottomRow = temp;
5751 }
5752
5753 if ( leftCol > rightCol )
5754 {
5755 temp = leftCol;
5756 leftCol = rightCol;
5757 rightCol = temp;
5758 }
f0102d2a 5759
70c7a608
SN
5760 updateTopLeft = wxGridCellCoords( topRow, leftCol );
5761 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
da6af900 5762
70c7a608
SN
5763 if ( m_selectedTopLeft != updateTopLeft ||
5764 m_selectedBottomRight != updateBottomRight )
da6af900 5765 {
70c7a608
SN
5766 // Compute two optimal update rectangles:
5767 // Either one rectangle is a real subset of the
5768 // other, or they are (almost) disjoint!
5769 wxRect rect[4];
5770 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5771 int i;
5772
5773 // Store intermediate values
5774 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5775 wxCoord oldTop = m_selectedTopLeft.GetRow();
5776 wxCoord oldRight = m_selectedBottomRight.GetCol();
5777 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5778
5779 // Determine the outer/inner coordinates.
5780 if (oldLeft > leftCol)
f0102d2a 5781 {
70c7a608
SN
5782 temp = oldLeft;
5783 oldLeft = leftCol;
5784 leftCol = temp;
cb309039 5785 }
70c7a608 5786 if (oldTop > topRow )
f0102d2a 5787 {
70c7a608
SN
5788 temp = oldTop;
5789 oldTop = topRow;
5790 topRow = temp;
cb309039
SN
5791 }
5792 if (oldRight < rightCol )
70c7a608
SN
5793 {
5794 temp = oldRight;
5795 oldRight = rightCol;
5796 rightCol = temp;
cb309039
SN
5797 }
5798 if (oldBottom < bottomRow)
5799 {
70c7a608
SN
5800 temp = oldBottom;
5801 oldBottom = bottomRow;
5802 bottomRow = temp;
cb309039 5803 }
70c7a608
SN
5804
5805 // Now, either the stuff marked old is the outer
5806 // rectangle or we don't have a situation where one
5807 // is contained in the other.
b99be8fb 5808
cb309039
SN
5809 if ( oldLeft < leftCol )
5810 {
5811 need_refresh[0] = TRUE;
5812 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5813 oldLeft ),
b99be8fb 5814 wxGridCellCoords ( oldBottom,
cb309039
SN
5815 leftCol - 1 ) );
5816 }
5817
5818 if ( oldTop < topRow )
5819 {
5820 need_refresh[1] = TRUE;
5821 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5822 leftCol ),
b99be8fb 5823 wxGridCellCoords ( topRow - 1,
cb309039
SN
5824 rightCol ) );
5825 }
5826
5827 if ( oldRight > rightCol )
5828 {
5829 need_refresh[2] = TRUE;
5830 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5831 rightCol + 1 ),
5832 wxGridCellCoords ( oldBottom,
5833 oldRight ) );
5834 }
5835
5836 if ( oldBottom > bottomRow )
5837 {
5838 need_refresh[3] = TRUE;
5839 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
5840 leftCol ),
5841 wxGridCellCoords ( oldBottom,
5842 rightCol ) );
5843 }
70c7a608
SN
5844
5845
5846 // Change Selection
5847 m_selectedTopLeft = updateTopLeft;
5848 m_selectedBottomRight = updateBottomRight;
b99be8fb 5849
70c7a608
SN
5850 // various Refresh() calls
5851 for (i = 0; i < 4; i++ )
5852 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
c6a51dcd 5853 m_gridWin->Refresh( FALSE, &(rect[i]) );
da6af900 5854 }
f85afd4e
MB
5855
5856 // only generate an event if the block is not being selected by
5857 // dragging the mouse (in which case the event will be generated in
2d66e025 5858 // the mouse event handler)
f85afd4e
MB
5859 if ( !m_isDragging )
5860 {
5861 wxGridRangeSelectEvent gridEvt( GetId(),
b5f788a5 5862 EVT_GRID_RANGE_SELECT,
f85afd4e
MB
5863 this,
5864 m_selectedTopLeft,
5865 m_selectedBottomRight );
8f177c8e 5866
f85afd4e
MB
5867 GetEventHandler()->ProcessEvent(gridEvt);
5868 }
5869}
5870
5871void wxGrid::SelectAll()
5872{
5873 m_selectedTopLeft.Set( 0, 0 );
5874 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
5875
2d66e025 5876 m_gridWin->Refresh();
f85afd4e
MB
5877}
5878
5879
5880void wxGrid::ClearSelection()
5881{
2d66e025
MB
5882 m_selectedTopLeft = wxGridNoCellCoords;
5883 m_selectedBottomRight = wxGridNoCellCoords;
8f177c8e 5884}
f85afd4e
MB
5885
5886
da6af900 5887// This function returns the rectangle that encloses the given block
2d66e025
MB
5888// in device coords clipped to the client size of the grid window.
5889//
58dd5b3b
MB
5890wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
5891 const wxGridCellCoords &bottomRight )
f85afd4e 5892{
58dd5b3b 5893 wxRect rect( wxGridNoCellRect );
f85afd4e
MB
5894 wxRect cellRect;
5895
58dd5b3b
MB
5896 cellRect = CellToRect( topLeft );
5897 if ( cellRect != wxGridNoCellRect )
f85afd4e 5898 {
58dd5b3b
MB
5899 rect = cellRect;
5900 }
5901 else
5902 {
5903 rect = wxRect( 0, 0, 0, 0 );
5904 }
60ff3b99 5905
58dd5b3b
MB
5906 cellRect = CellToRect( bottomRight );
5907 if ( cellRect != wxGridNoCellRect )
5908 {
5909 rect += cellRect;
2d66e025
MB
5910 }
5911 else
5912 {
5913 return wxGridNoCellRect;
f85afd4e
MB
5914 }
5915
58dd5b3b
MB
5916 // convert to scrolled coords
5917 //
5918 int left, top, right, bottom;
5919 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
5920 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
5921
5922 int cw, ch;
5923 m_gridWin->GetClientSize( &cw, &ch );
5924
5925 rect.SetLeft( wxMax(0, left) );
5926 rect.SetTop( wxMax(0, top) );
5927 rect.SetRight( wxMin(cw, right) );
5928 rect.SetBottom( wxMin(ch, bottom) );
5929
f85afd4e
MB
5930 return rect;
5931}
5932
5933
58dd5b3b 5934
f85afd4e
MB
5935//
5936// ------ Grid event classes
5937//
5938
5939IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
5940
5941wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5942 int row, int col, int x, int y,
5943 bool control, bool shift, bool alt, bool meta )
5944 : wxNotifyEvent( type, id )
5945{
5946 m_row = row;
5947 m_col = col;
5948 m_x = x;
5949 m_y = y;
5950 m_control = control;
5951 m_shift = shift;
5952 m_alt = alt;
5953 m_meta = meta;
8f177c8e 5954
f85afd4e
MB
5955 SetEventObject(obj);
5956}
5957
5958
5959IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
5960
5961wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
5962 int rowOrCol, int x, int y,
5963 bool control, bool shift, bool alt, bool meta )
5964 : wxNotifyEvent( type, id )
5965{
5966 m_rowOrCol = rowOrCol;
5967 m_x = x;
5968 m_y = y;
5969 m_control = control;
5970 m_shift = shift;
5971 m_alt = alt;
5972 m_meta = meta;
8f177c8e 5973
f85afd4e
MB
5974 SetEventObject(obj);
5975}
5976
5977
5978IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
5979
5980wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8f177c8e
VZ
5981 const wxGridCellCoords& topLeft,
5982 const wxGridCellCoords& bottomRight,
5983 bool control, bool shift, bool alt, bool meta )
5984 : wxNotifyEvent( type, id )
f85afd4e
MB
5985{
5986 m_topLeft = topLeft;
5987 m_bottomRight = bottomRight;
5988 m_control = control;
5989 m_shift = shift;
5990 m_alt = alt;
5991 m_meta = meta;
5992
5993 SetEventObject(obj);
5994}
5995
5996
5997#endif // ifndef wxUSE_NEW_GRID
5998