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