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