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