]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp
don't generate wxEVT_CONTEXT_MENU messages for right clicks in the list control header
[wxWidgets.git] / src / generic / grid.cpp
Content-type: text/html ]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp


500 - Internal Server Error

Malformed UTF-8 character (fatal) at /usr/lib/x86_64-linux-gnu/perl5/5.40/HTML/Entities.pm line 485, <$fd> line 9937.
CommitLineData
2796cce3 1///////////////////////////////////////////////////////////////////////////
faa94f3e 2// Name: src/generic/grid.cpp
f85afd4e
MB
3// Purpose: wxGrid and related classes
4// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
97a9929e 5// Modified by: Robin Dunn, Vadim Zeitlin
f85afd4e
MB
6// Created: 1/08/1999
7// RCS-ID: $Id$
8// Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
65571936 9// Licence: wxWindows licence
f85afd4e
MB
10/////////////////////////////////////////////////////////////////////////////
11
f6bcfd97 12// For compilers that support precompilatixon, includes "wx/wx.h".
4d85bcd1
JS
13#include "wx/wxprec.h"
14
15#include "wx/defs.h"
f85afd4e
MB
16
17#ifdef __BORLANDC__
18 #pragma hdrstop
19#endif
20
27b92ca4
VZ
21#if wxUSE_GRID
22
f85afd4e
MB
23#ifndef WX_PRECOMP
24 #include "wx/utils.h"
25 #include "wx/dcclient.h"
26 #include "wx/settings.h"
27 #include "wx/log.h"
508011ce
VZ
28 #include "wx/textctrl.h"
29 #include "wx/checkbox.h"
4ee5fc9c 30 #include "wx/combobox.h"
816be743 31 #include "wx/valtext.h"
60d876f3 32 #include "wx/intl.h"
c77a6796 33 #include "wx/math.h"
f85afd4e
MB
34#endif
35
cb5df486 36#include "wx/textfile.h"
816be743 37#include "wx/spinctrl.h"
c4608a8a 38#include "wx/tokenzr.h"
4d1bc39c 39#include "wx/renderer.h"
6d004f67 40
07296f0b 41#include "wx/grid.h"
b5808881 42#include "wx/generic/gridsel.h"
07296f0b 43
0b7e6e7d
SN
44#if defined(__WXMOTIF__)
45 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
c78b3acd 46#else
0b7e6e7d 47 #define WXUNUSED_MOTIF(identifier) identifier
c78b3acd
SN
48#endif
49
50#if defined(__WXGTK__)
51 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
52#else
53 #define WXUNUSED_GTK(identifier) identifier
54#endif
55
3f8e5072
JS
56// Required for wxIs... functions
57#include <ctype.h>
58
b99be8fb 59// ----------------------------------------------------------------------------
758cbedf 60// array classes
b99be8fb
VZ
61// ----------------------------------------------------------------------------
62
d5d29b8a 63WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr *, wxArrayAttrs,
160ba750 64 class WXDLLIMPEXP_ADV);
758cbedf 65
b99be8fb
VZ
66struct wxGridCellWithAttr
67{
2e9a6788
VZ
68 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
69 : coords(row, col), attr(attr_)
b99be8fb
VZ
70 {
71 }
72
2e9a6788
VZ
73 ~wxGridCellWithAttr()
74 {
75 attr->DecRef();
76 }
77
b99be8fb 78 wxGridCellCoords coords;
2e9a6788 79 wxGridCellAttr *attr;
22f3361e
VZ
80
81// Cannot do this:
82// DECLARE_NO_COPY_CLASS(wxGridCellWithAttr)
83// without rewriting the macros, which require a public copy constructor.
b99be8fb
VZ
84};
85
160ba750
VS
86WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr, wxGridCellWithAttrArray,
87 class WXDLLIMPEXP_ADV);
b99be8fb
VZ
88
89#include "wx/arrimpl.cpp"
90
91WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
92WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
93
0f442030
RR
94// ----------------------------------------------------------------------------
95// events
96// ----------------------------------------------------------------------------
97
2e4df4bf
VZ
98DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK)
99DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK)
100DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK)
101DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK)
79dbea21 102DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG)
2e4df4bf
VZ
103DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK)
104DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK)
105DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK)
106DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK)
107DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE)
108DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE)
109DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT)
110DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE)
111DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL)
112DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN)
113DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN)
bf7945ce 114DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED)
0f442030 115
b99be8fb
VZ
116// ----------------------------------------------------------------------------
117// private classes
118// ----------------------------------------------------------------------------
119
12f190b0 120class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxWindow
b99be8fb
VZ
121{
122public:
123 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
124 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
125 const wxPoint &pos, const wxSize &size );
126
127private:
128 wxGrid *m_owner;
129
130 void OnPaint( wxPaintEvent& event );
131 void OnMouseEvent( wxMouseEvent& event );
b51c3f27 132 void OnMouseWheel( wxMouseEvent& event );
b99be8fb 133 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 134 void OnKeyUp( wxKeyEvent& );
63e2147c 135 void OnChar( wxKeyEvent& );
b99be8fb
VZ
136
137 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
138 DECLARE_EVENT_TABLE()
22f3361e 139 DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow)
b99be8fb
VZ
140};
141
142
12f190b0 143class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxWindow
b99be8fb
VZ
144{
145public:
146 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
147 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
148 const wxPoint &pos, const wxSize &size );
149
150private:
151 wxGrid *m_owner;
152
153 void OnPaint( wxPaintEvent &event );
154 void OnMouseEvent( wxMouseEvent& event );
b51c3f27 155 void OnMouseWheel( wxMouseEvent& event );
b99be8fb 156 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 157 void OnKeyUp( wxKeyEvent& );
63e2147c 158 void OnChar( wxKeyEvent& );
b99be8fb
VZ
159
160 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
161 DECLARE_EVENT_TABLE()
22f3361e 162 DECLARE_NO_COPY_CLASS(wxGridColLabelWindow)
b99be8fb
VZ
163};
164
165
12f190b0 166class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxWindow
b99be8fb
VZ
167{
168public:
169 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
170 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
171 const wxPoint &pos, const wxSize &size );
172
173private:
174 wxGrid *m_owner;
175
176 void OnMouseEvent( wxMouseEvent& event );
b51c3f27 177 void OnMouseWheel( wxMouseEvent& event );
b99be8fb 178 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 179 void OnKeyUp( wxKeyEvent& );
63e2147c 180 void OnChar( wxKeyEvent& );
b99be8fb
VZ
181 void OnPaint( wxPaintEvent& event );
182
183 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
184 DECLARE_EVENT_TABLE()
22f3361e 185 DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow)
b99be8fb
VZ
186};
187
12f190b0 188class WXDLLIMPEXP_ADV wxGridWindow : public wxWindow
b99be8fb
VZ
189{
190public:
191 wxGridWindow()
192 {
193 m_owner = (wxGrid *)NULL;
194 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
195 m_colLabelWin = (wxGridColLabelWindow *)NULL;
196 }
197
198 wxGridWindow( wxGrid *parent,
199 wxGridRowLabelWindow *rowLblWin,
200 wxGridColLabelWindow *colLblWin,
201 wxWindowID id, const wxPoint &pos, const wxSize &size );
4db6714b 202 ~wxGridWindow() {}
b99be8fb
VZ
203
204 void ScrollWindow( int dx, int dy, const wxRect *rect );
205
b819b854
JS
206 wxGrid* GetOwner() { return m_owner; }
207
b99be8fb
VZ
208private:
209 wxGrid *m_owner;
210 wxGridRowLabelWindow *m_rowLabelWin;
211 wxGridColLabelWindow *m_colLabelWin;
212
213 void OnPaint( wxPaintEvent &event );
b51c3f27 214 void OnMouseWheel( wxMouseEvent& event );
b99be8fb
VZ
215 void OnMouseEvent( wxMouseEvent& event );
216 void OnKeyDown( wxKeyEvent& );
f6bcfd97 217 void OnKeyUp( wxKeyEvent& );
63e2147c 218 void OnChar( wxKeyEvent& );
2796cce3 219 void OnEraseBackground( wxEraseEvent& );
80acaf25 220 void OnFocus( wxFocusEvent& );
b99be8fb
VZ
221
222 DECLARE_DYNAMIC_CLASS(wxGridWindow)
223 DECLARE_EVENT_TABLE()
22f3361e 224 DECLARE_NO_COPY_CLASS(wxGridWindow)
b99be8fb
VZ
225};
226
2796cce3 227
2796cce3
RD
228class wxGridCellEditorEvtHandler : public wxEvtHandler
229{
230public:
2796cce3 231 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
140954fd 232 : m_grid(grid),
08dd04d0
JS
233 m_editor(editor),
234 m_inSetFocus(false)
140954fd
VZ
235 {
236 }
2796cce3 237
140954fd 238 void OnKillFocus(wxFocusEvent& event);
2796cce3 239 void OnKeyDown(wxKeyEvent& event);
fb0de762 240 void OnChar(wxKeyEvent& event);
2796cce3 241
08dd04d0
JS
242 void SetInSetFocus(bool inSetFocus) { m_inSetFocus = inSetFocus; }
243
2796cce3 244private:
2f024384
DS
245 wxGrid *m_grid;
246 wxGridCellEditor *m_editor;
140954fd 247
08dd04d0
JS
248 // Work around the fact that a focus kill event can be sent to
249 // a combobox within a set focus event.
250 bool m_inSetFocus;
7448de8d 251
2796cce3 252 DECLARE_EVENT_TABLE()
140954fd 253 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
22f3361e 254 DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler)
2796cce3
RD
255};
256
257
140954fd
VZ
258IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler, wxEvtHandler)
259
2796cce3 260BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
140954fd 261 EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus )
2796cce3 262 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
fb0de762 263 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
2796cce3
RD
264END_EVENT_TABLE()
265
266
267
758cbedf 268// ----------------------------------------------------------------------------
b99be8fb 269// the internal data representation used by wxGridCellAttrProvider
758cbedf
VZ
270// ----------------------------------------------------------------------------
271
272// this class stores attributes set for cells
12f190b0 273class WXDLLIMPEXP_ADV wxGridCellAttrData
b99be8fb
VZ
274{
275public:
2e9a6788 276 void SetAttr(wxGridCellAttr *attr, int row, int col);
b99be8fb 277 wxGridCellAttr *GetAttr(int row, int col) const;
4d60017a
SN
278 void UpdateAttrRows( size_t pos, int numRows );
279 void UpdateAttrCols( size_t pos, int numCols );
b99be8fb
VZ
280
281private:
282 // searches for the attr for given cell, returns wxNOT_FOUND if not found
283 int FindIndex(int row, int col) const;
284
285 wxGridCellWithAttrArray m_attrs;
286};
287
758cbedf 288// this class stores attributes set for rows or columns
12f190b0 289class WXDLLIMPEXP_ADV wxGridRowOrColAttrData
758cbedf
VZ
290{
291public:
ee6694a7 292 // empty ctor to suppress warnings
2f024384 293 wxGridRowOrColAttrData() {}
758cbedf
VZ
294 ~wxGridRowOrColAttrData();
295
296 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
297 wxGridCellAttr *GetAttr(int rowOrCol) const;
4d60017a 298 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
758cbedf
VZ
299
300private:
301 wxArrayInt m_rowsOrCols;
302 wxArrayAttrs m_attrs;
303};
304
305// NB: this is just a wrapper around 3 objects: one which stores cell
306// attributes, and 2 others for row/col ones
12f190b0 307class WXDLLIMPEXP_ADV wxGridCellAttrProviderData
758cbedf
VZ
308{
309public:
310 wxGridCellAttrData m_cellAttrs;
311 wxGridRowOrColAttrData m_rowAttrs,
312 m_colAttrs;
313};
314
f2d76237
RD
315
316// ----------------------------------------------------------------------------
317// data structures used for the data type registry
318// ----------------------------------------------------------------------------
319
b94ae1ea
VZ
320struct wxGridDataTypeInfo
321{
f2d76237
RD
322 wxGridDataTypeInfo(const wxString& typeName,
323 wxGridCellRenderer* renderer,
324 wxGridCellEditor* editor)
325 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
2f024384 326 {}
f2d76237 327
39bcce60
VZ
328 ~wxGridDataTypeInfo()
329 {
330 wxSafeDecRef(m_renderer);
331 wxSafeDecRef(m_editor);
332 }
f2d76237
RD
333
334 wxString m_typeName;
335 wxGridCellRenderer* m_renderer;
336 wxGridCellEditor* m_editor;
22f3361e
VZ
337
338 DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo)
f2d76237
RD
339};
340
341
d5d29b8a 342WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo*, wxGridDataTypeInfoArray,
160ba750 343 class WXDLLIMPEXP_ADV);
f2d76237
RD
344
345
12f190b0 346class WXDLLIMPEXP_ADV wxGridTypeRegistry
b94ae1ea 347{
f2d76237 348public:
c78b3acd 349 wxGridTypeRegistry() {}
f2d76237 350 ~wxGridTypeRegistry();
b94ae1ea 351
f2d76237
RD
352 void RegisterDataType(const wxString& typeName,
353 wxGridCellRenderer* renderer,
354 wxGridCellEditor* editor);
c4608a8a
VZ
355
356 // find one of already registered data types
357 int FindRegisteredDataType(const wxString& typeName);
358
359 // try to FindRegisteredDataType(), if this fails and typeName is one of
360 // standard typenames, register it and return its index
f2d76237 361 int FindDataType(const wxString& typeName);
c4608a8a
VZ
362
363 // try to FindDataType(), if it fails see if it is not one of already
364 // registered data types with some params in which case clone the
365 // registered data type and set params for it
366 int FindOrCloneDataType(const wxString& typeName);
367
f2d76237
RD
368 wxGridCellRenderer* GetRenderer(int index);
369 wxGridCellEditor* GetEditor(int index);
370
371private:
372 wxGridDataTypeInfoArray m_typeinfo;
373};
374
b99be8fb
VZ
375// ----------------------------------------------------------------------------
376// conditional compilation
377// ----------------------------------------------------------------------------
378
9496deb5
MB
379#ifndef WXGRID_DRAW_LINES
380#define WXGRID_DRAW_LINES 1
796df70a
SN
381#endif
382
0a976765
VZ
383// ----------------------------------------------------------------------------
384// globals
385// ----------------------------------------------------------------------------
386
387//#define DEBUG_ATTR_CACHE
388#ifdef DEBUG_ATTR_CACHE
389 static size_t gs_nAttrCacheHits = 0;
390 static size_t gs_nAttrCacheMisses = 0;
2f024384 391#endif
f85afd4e 392
43947979
VZ
393// ----------------------------------------------------------------------------
394// constants
395// ----------------------------------------------------------------------------
396
f85afd4e 397wxGridCellCoords wxGridNoCellCoords( -1, -1 );
2f024384 398wxRect wxGridNoCellRect( -1, -1, -1, -1 );
f85afd4e 399
f0102d2a 400// scroll line size
faec5a43
SN
401// TODO: this doesn't work at all, grid cells have different sizes and approx
402// calculations don't work as because of the size mismatch scrollbars
403// sometimes fail to be shown when they should be or vice versa
b51c3f27
RD
404//
405// The scroll bars may be a little flakey once in a while, but that is
406// surely much less horrible than having scroll lines of only 1!!!
407// -- Robin
97a9929e
VZ
408//
409// Well, it's still seriously broken so it might be better but needs
410// fixing anyhow
411// -- Vadim
412static const size_t GRID_SCROLL_LINE_X = 15; // 1;
413static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
f85afd4e 414
43947979
VZ
415// the size of hash tables used a bit everywhere (the max number of elements
416// in these hash tables is the number of rows/columns)
417static const int GRID_HASH_SIZE = 100;
418
608754c4 419#if 0
97a9929e
VZ
420// ----------------------------------------------------------------------------
421// private functions
422// ----------------------------------------------------------------------------
423
d0eb7e56 424static inline int GetScrollX(int x)
97a9929e
VZ
425{
426 return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X;
427}
428
d0eb7e56 429static inline int GetScrollY(int y)
97a9929e
VZ
430{
431 return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y;
432}
608754c4 433#endif
97a9929e 434
ab79958a
VZ
435// ============================================================================
436// implementation
437// ============================================================================
438
2796cce3
RD
439// ----------------------------------------------------------------------------
440// wxGridCellEditor
441// ----------------------------------------------------------------------------
442
443wxGridCellEditor::wxGridCellEditor()
444{
445 m_control = NULL;
1bd71df9 446 m_attr = NULL;
2796cce3
RD
447}
448
2796cce3
RD
449wxGridCellEditor::~wxGridCellEditor()
450{
451 Destroy();
452}
453
508011ce
VZ
454void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
455 wxWindowID WXUNUSED(id),
456 wxEvtHandler* evtHandler)
457{
189d0213 458 if ( evtHandler )
508011ce
VZ
459 m_control->PushEventHandler(evtHandler);
460}
2796cce3 461
189d0213
VZ
462void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
463 wxGridCellAttr *attr)
464{
465 // erase the background because we might not fill the cell
466 wxClientDC dc(m_control->GetParent());
b819b854
JS
467 wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
468 if (gridWindow)
469 gridWindow->GetOwner()->PrepareDC(dc);
ef5df12b 470
189d0213
VZ
471 dc.SetPen(*wxTRANSPARENT_PEN);
472 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
473 dc.DrawRectangle(rectCell);
474
475 // redraw the control we just painted over
476 m_control->Refresh();
477}
478
2796cce3
RD
479void wxGridCellEditor::Destroy()
480{
508011ce
VZ
481 if (m_control)
482 {
ca65c044 483 m_control->PopEventHandler(true /* delete it*/);
b94ae1ea 484
2796cce3
RD
485 m_control->Destroy();
486 m_control = NULL;
487 }
488}
489
3da93aae 490void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
2796cce3 491{
2f024384
DS
492 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
493
2796cce3 494 m_control->Show(show);
3da93aae
VZ
495
496 if ( show )
497 {
498 // set the colours/fonts if we have any
499 if ( attr )
500 {
f2d76237
RD
501 m_colFgOld = m_control->GetForegroundColour();
502 m_control->SetForegroundColour(attr->GetTextColour());
3da93aae 503
f2d76237
RD
504 m_colBgOld = m_control->GetBackgroundColour();
505 m_control->SetBackgroundColour(attr->GetBackgroundColour());
3da93aae 506
0e871ad0 507// Workaround for GTK+1 font setting problem on some platforms
ea2d542c 508#if !defined(__WXGTK__) || defined(__WXGTK20__)
f2d76237
RD
509 m_fontOld = m_control->GetFont();
510 m_control->SetFont(attr->GetFont());
ea2d542c 511#endif
3da93aae
VZ
512 // can't do anything more in the base class version, the other
513 // attributes may only be used by the derived classes
514 }
515 }
516 else
517 {
518 // restore the standard colours fonts
519 if ( m_colFgOld.Ok() )
520 {
521 m_control->SetForegroundColour(m_colFgOld);
522 m_colFgOld = wxNullColour;
523 }
524
525 if ( m_colBgOld.Ok() )
526 {
527 m_control->SetBackgroundColour(m_colBgOld);
528 m_colBgOld = wxNullColour;
529 }
2f024384 530
0e871ad0 531// Workaround for GTK+1 font setting problem on some platforms
ea2d542c 532#if !defined(__WXGTK__) || defined(__WXGTK20__)
3da93aae
VZ
533 if ( m_fontOld.Ok() )
534 {
535 m_control->SetFont(m_fontOld);
536 m_fontOld = wxNullFont;
537 }
ea2d542c 538#endif
3da93aae 539 }
2796cce3
RD
540}
541
542void wxGridCellEditor::SetSize(const wxRect& rect)
543{
2f024384
DS
544 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
545
28a77bc4 546 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
2796cce3
RD
547}
548
549void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
550{
551 event.Skip();
552}
553
f6bcfd97
BP
554bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
555{
63e2147c
RD
556 bool ctrl = event.ControlDown();
557 bool alt = event.AltDown();
2f024384 558
63e2147c
RD
559#ifdef __WXMAC__
560 // On the Mac the Alt key is more like shift and is used for entry of
561 // valid characters, so check for Ctrl and Meta instead.
562 alt = event.MetaDown();
563#endif
564
565 // Assume it's not a valid char if ctrl or alt is down, but if both are
566 // down then it may be because of an AltGr key combination, so let them
567 // through in that case.
568 if ((ctrl || alt) && !(ctrl && alt))
569 return false;
902725ee 570
2f024384 571 int key = 0;
63e2147c
RD
572 bool keyOk = true;
573
2f024384 574#if wxUSE_UNICODE
63e2147c
RD
575 // if the unicode key code is not really a unicode character (it may
576 // be a function key or etc., the platforms appear to always give us a
2f024384 577 // small value in this case) then fallback to the ASCII key code but
63e2147c 578 // don't do anything for function keys or etc.
2f024384 579 key = event.GetUnicodeKey();
63e2147c
RD
580 if (key <= 127)
581 {
582 key = event.GetKeyCode();
583 keyOk = (key <= 127);
584 }
2f024384
DS
585#else
586 key = event.GetKeyCode();
587 keyOk = (key <= 255);
588#endif
589
63e2147c 590 return keyOk;
f6bcfd97 591}
2796cce3 592
2c9a89e0
RD
593void wxGridCellEditor::StartingKey(wxKeyEvent& event)
594{
e195a54c
VZ
595 event.Skip();
596}
2c9a89e0 597
e195a54c
VZ
598void wxGridCellEditor::StartingClick()
599{
b54ba671 600}
2c9a89e0 601
3a8c693a
VZ
602#if wxUSE_TEXTCTRL
603
b54ba671
VZ
604// ----------------------------------------------------------------------------
605// wxGridCellTextEditor
606// ----------------------------------------------------------------------------
2c9a89e0 607
2796cce3
RD
608wxGridCellTextEditor::wxGridCellTextEditor()
609{
c4608a8a 610 m_maxChars = 0;
2796cce3
RD
611}
612
613void wxGridCellTextEditor::Create(wxWindow* parent,
614 wxWindowID id,
2796cce3
RD
615 wxEvtHandler* evtHandler)
616{
508011ce 617 m_control = new wxTextCtrl(parent, id, wxEmptyString,
2c9a89e0 618 wxDefaultPosition, wxDefaultSize
2796cce3 619#if defined(__WXMSW__)
aaae069f 620 , wxTE_PROCESS_TAB | wxTE_AUTO_SCROLL
2796cce3 621#endif
508011ce 622 );
2796cce3 623
46a5010a
RD
624 // set max length allowed in the textctrl, if the parameter was set
625 if (m_maxChars != 0)
626 {
627 ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars);
628 }
c4608a8a 629
508011ce 630 wxGridCellEditor::Create(parent, id, evtHandler);
2796cce3
RD
631}
632
189d0213
VZ
633void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
634 wxGridCellAttr * WXUNUSED(attr))
635{
636 // as we fill the entire client area, don't do anything here to minimize
637 // flicker
638}
2796cce3 639
99306db2
VZ
640void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
641{
642 wxRect rect(rectOrig);
643
2f024384 644 // Make the edit control large enough to allow for internal margins
99306db2 645 //
2f024384 646 // TODO: remove this if the text ctrl sizing is improved esp. for unix
99306db2
VZ
647 //
648#if defined(__WXGTK__)
b0e282b3
RR
649 if (rect.x != 0)
650 {
651 rect.x += 1;
652 rect.y += 1;
653 rect.width -= 1;
654 rect.height -= 1;
655 }
99306db2 656#else // !GTK
cb105ad4 657 int extra_x = ( rect.x > 2 )? 2 : 1;
84912ef8
RD
658
659// MB: treat MSW separately here otherwise the caret doesn't show
660// when the editor is in the first row.
a0948e27
MB
661#if defined(__WXMSW__)
662 int extra_y = 2;
663#else
2f024384
DS
664 int extra_y = ( rect.y > 2 ) ? 2 : 1;
665#endif
a0948e27 666
99306db2 667#if defined(__WXMOTIF__)
cb105ad4
SN
668 extra_x *= 2;
669 extra_y *= 2;
99306db2 670#endif
2f024384 671
cb105ad4
SN
672 rect.SetLeft( wxMax(0, rect.x - extra_x) );
673 rect.SetTop( wxMax(0, rect.y - extra_y) );
2f024384
DS
674 rect.SetRight( rect.GetRight() + 2 * extra_x );
675 rect.SetBottom( rect.GetBottom() + 2 * extra_y );
99306db2
VZ
676#endif // GTK/!GTK
677
678 wxGridCellEditor::SetSize(rect);
679}
680
3da93aae 681void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
2796cce3 682{
2f024384 683 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
2796cce3
RD
684
685 m_startValue = grid->GetTable()->GetValue(row, col);
816be743
VZ
686
687 DoBeginEdit(m_startValue);
688}
689
690void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
691{
692 Text()->SetValue(startValue);
b54ba671 693 Text()->SetInsertionPointEnd();
2f024384 694 Text()->SetSelection(-1, -1);
b54ba671 695 Text()->SetFocus();
2796cce3
RD
696}
697
3324d5f5 698bool wxGridCellTextEditor::EndEdit(int row, int col,
3da93aae 699 wxGrid* grid)
2796cce3 700{
2f024384 701 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
2796cce3 702
ca65c044 703 bool changed = false;
b54ba671 704 wxString value = Text()->GetValue();
2796cce3 705 if (value != m_startValue)
ca65c044 706 changed = true;
2796cce3
RD
707
708 if (changed)
709 grid->GetTable()->SetValue(row, col, value);
2c9a89e0 710
3da93aae 711 m_startValue = wxEmptyString;
7b519e5e
JS
712 // No point in setting the text of the hidden control
713 //Text()->SetValue(m_startValue);
2796cce3
RD
714
715 return changed;
716}
717
2796cce3
RD
718void wxGridCellTextEditor::Reset()
719{
2f024384 720 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
2796cce3 721
816be743
VZ
722 DoReset(m_startValue);
723}
724
725void wxGridCellTextEditor::DoReset(const wxString& startValue)
726{
727 Text()->SetValue(startValue);
b54ba671 728 Text()->SetInsertionPointEnd();
2796cce3
RD
729}
730
f6bcfd97
BP
731bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
732{
63e2147c 733 return wxGridCellEditor::IsAcceptedKey(event);
f6bcfd97
BP
734}
735
2c9a89e0
RD
736void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
737{
63e2147c
RD
738 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
739 // longer an appropriate way to get the character into the text control.
740 // Do it ourselves instead. We know that if we get this far that we have
741 // a valid character, so not a whole lot of testing needs to be done.
742
743 wxTextCtrl* tc = Text();
744 wxChar ch;
745 long pos;
902725ee 746
63e2147c
RD
747#if wxUSE_UNICODE
748 ch = event.GetUnicodeKey();
749 if (ch <= 127)
6f0d2cee 750 ch = (wxChar)event.GetKeyCode();
63e2147c 751#else
6f0d2cee 752 ch = (wxChar)event.GetKeyCode();
63e2147c 753#endif
2f024384 754
63e2147c 755 switch (ch)
f6bcfd97 756 {
63e2147c
RD
757 case WXK_DELETE:
758 // delete the character at the cursor
759 pos = tc->GetInsertionPoint();
760 if (pos < tc->GetLastPosition())
2f024384 761 tc->Remove(pos, pos + 1);
63e2147c
RD
762 break;
763
764 case WXK_BACK:
765 // delete the character before the cursor
766 pos = tc->GetInsertionPoint();
767 if (pos > 0)
2f024384 768 tc->Remove(pos - 1, pos);
63e2147c
RD
769 break;
770
771 default:
772 tc->WriteText(ch);
773 break;
f6bcfd97 774 }
b54ba671 775}
2c9a89e0 776
c78b3acd 777void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
0b7e6e7d 778 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
2796cce3
RD
779{
780#if defined(__WXMOTIF__) || defined(__WXGTK__)
781 // wxMotif needs a little extra help...
6fc0f38f 782 size_t pos = (size_t)( Text()->GetInsertionPoint() );
b54ba671 783 wxString s( Text()->GetValue() );
8dd8f875 784 s = s.Left(pos) + wxT("\n") + s.Mid(pos);
b54ba671
VZ
785 Text()->SetValue(s);
786 Text()->SetInsertionPoint( pos );
2796cce3
RD
787#else
788 // the other ports can handle a Return key press
789 //
790 event.Skip();
791#endif
792}
793
c4608a8a
VZ
794void wxGridCellTextEditor::SetParameters(const wxString& params)
795{
796 if ( !params )
797 {
798 // reset to default
799 m_maxChars = 0;
800 }
801 else
802 {
803 long tmp;
804 if ( !params.ToLong(&tmp) )
805 {
f6bcfd97 806 wxLogDebug(_T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str());
c4608a8a
VZ
807 }
808 else
809 {
810 m_maxChars = (size_t)tmp;
811 }
812 }
813}
814
73145b0e
JS
815// return the value in the text control
816wxString wxGridCellTextEditor::GetValue() const
817{
2f024384 818 return Text()->GetValue();
73145b0e
JS
819}
820
816be743
VZ
821// ----------------------------------------------------------------------------
822// wxGridCellNumberEditor
823// ----------------------------------------------------------------------------
824
825wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
826{
827 m_min = min;
828 m_max = max;
829}
830
831void wxGridCellNumberEditor::Create(wxWindow* parent,
832 wxWindowID id,
833 wxEvtHandler* evtHandler)
834{
0e871ad0 835#if wxUSE_SPINCTRL
816be743
VZ
836 if ( HasRange() )
837 {
838 // create a spin ctrl
ca65c044 839 m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString,
816be743
VZ
840 wxDefaultPosition, wxDefaultSize,
841 wxSP_ARROW_KEYS,
842 m_min, m_max);
843
844 wxGridCellEditor::Create(parent, id, evtHandler);
845 }
846 else
0e871ad0 847#endif
816be743
VZ
848 {
849 // just a text control
850 wxGridCellTextEditor::Create(parent, id, evtHandler);
851
852#if wxUSE_VALIDATORS
85bc0351 853 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
816be743
VZ
854#endif // wxUSE_VALIDATORS
855 }
856}
857
858void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
859{
860 // first get the value
861 wxGridTableBase *table = grid->GetTable();
862 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
863 {
864 m_valueOld = table->GetValueAsLong(row, col);
865 }
866 else
867 {
8a60ff0a 868 m_valueOld = 0;
a5777624 869 wxString sValue = table->GetValue(row, col);
0e871ad0 870 if (! sValue.ToLong(&m_valueOld) && ! sValue.empty())
a5777624
RD
871 {
872 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
873 return;
874 }
816be743
VZ
875 }
876
0e871ad0 877#if wxUSE_SPINCTRL
816be743
VZ
878 if ( HasRange() )
879 {
4a64bee4 880 Spin()->SetValue((int)m_valueOld);
f6bcfd97 881 Spin()->SetFocus();
816be743
VZ
882 }
883 else
0e871ad0 884#endif
816be743
VZ
885 {
886 DoBeginEdit(GetString());
887 }
888}
889
3324d5f5 890bool wxGridCellNumberEditor::EndEdit(int row, int col,
816be743
VZ
891 wxGrid* grid)
892{
893 bool changed;
8a60ff0a
RD
894 long value = 0;
895 wxString text;
816be743 896
0e871ad0 897#if wxUSE_SPINCTRL
816be743
VZ
898 if ( HasRange() )
899 {
900 value = Spin()->GetValue();
901 changed = value != m_valueOld;
8a60ff0a
RD
902 if (changed)
903 text = wxString::Format(wxT("%ld"), value);
816be743
VZ
904 }
905 else
0e871ad0 906#endif
816be743 907 {
8a60ff0a 908 text = Text()->GetValue();
0e871ad0 909 changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld);
816be743
VZ
910 }
911
912 if ( changed )
913 {
a5777624
RD
914 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
915 grid->GetTable()->SetValueAsLong(row, col, value);
916 else
8a60ff0a 917 grid->GetTable()->SetValue(row, col, text);
816be743
VZ
918 }
919
920 return changed;
921}
922
923void wxGridCellNumberEditor::Reset()
924{
0e871ad0 925#if wxUSE_SPINCTRL
816be743
VZ
926 if ( HasRange() )
927 {
4a64bee4 928 Spin()->SetValue((int)m_valueOld);
816be743
VZ
929 }
930 else
0e871ad0 931#endif
816be743
VZ
932 {
933 DoReset(GetString());
934 }
935}
936
f6bcfd97
BP
937bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
938{
939 if ( wxGridCellEditor::IsAcceptedKey(event) )
940 {
941 int keycode = event.GetKeyCode();
63e2147c
RD
942 if ( (keycode < 128) &&
943 (wxIsdigit(keycode) || keycode == '+' || keycode == '-'))
f6bcfd97 944 {
63e2147c 945 return true;
f6bcfd97
BP
946 }
947 }
948
ca65c044 949 return false;
f6bcfd97
BP
950}
951
816be743
VZ
952void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
953{
eb5e42b6 954 int keycode = event.GetKeyCode();
816be743
VZ
955 if ( !HasRange() )
956 {
63e2147c 957 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-')
816be743
VZ
958 {
959 wxGridCellTextEditor::StartingKey(event);
960
961 // skip Skip() below
962 return;
963 }
964 }
eb5e42b6
RD
965#if wxUSE_SPINCTRL
966 else
967 {
968 if ( wxIsdigit(keycode) )
969 {
970 wxSpinCtrl* spin = (wxSpinCtrl*)m_control;
971 spin->SetValue(keycode - '0');
972 spin->SetSelection(1,1);
973 return;
974 }
975 }
976#endif
2f024384 977
816be743
VZ
978 event.Skip();
979}
9c4ba614 980
c4608a8a
VZ
981void wxGridCellNumberEditor::SetParameters(const wxString& params)
982{
983 if ( !params )
984 {
985 // reset to default
986 m_min =
987 m_max = -1;
988 }
989 else
990 {
991 long tmp;
992 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
993 {
994 m_min = (int)tmp;
995
996 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
997 {
998 m_max = (int)tmp;
999
1000 // skip the error message below
1001 return;
1002 }
1003 }
1004
f6bcfd97 1005 wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
c4608a8a
VZ
1006 }
1007}
1008
73145b0e
JS
1009// return the value in the spin control if it is there (the text control otherwise)
1010wxString wxGridCellNumberEditor::GetValue() const
1011{
0e871ad0
WS
1012 wxString s;
1013
1014#if wxUSE_SPINCTRL
4db6714b 1015 if ( HasRange() )
0e871ad0
WS
1016 {
1017 long value = Spin()->GetValue();
1018 s.Printf(wxT("%ld"), value);
1019 }
1020 else
1021#endif
1022 {
1023 s = Text()->GetValue();
1024 }
1025
1026 return s;
73145b0e
JS
1027}
1028
816be743
VZ
1029// ----------------------------------------------------------------------------
1030// wxGridCellFloatEditor
1031// ----------------------------------------------------------------------------
1032
f6bcfd97
BP
1033wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
1034{
1035 m_width = width;
1036 m_precision = precision;
1037}
1038
816be743
VZ
1039void wxGridCellFloatEditor::Create(wxWindow* parent,
1040 wxWindowID id,
1041 wxEvtHandler* evtHandler)
1042{
1043 wxGridCellTextEditor::Create(parent, id, evtHandler);
1044
1045#if wxUSE_VALIDATORS
85bc0351 1046 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
816be743
VZ
1047#endif // wxUSE_VALIDATORS
1048}
1049
1050void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
1051{
1052 // first get the value
1053 wxGridTableBase *table = grid->GetTable();
1054 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1055 {
1056 m_valueOld = table->GetValueAsDouble(row, col);
1057 }
1058 else
1059 {
8a60ff0a 1060 m_valueOld = 0.0;
a5777624 1061 wxString sValue = table->GetValue(row, col);
0e871ad0 1062 if (! sValue.ToDouble(&m_valueOld) && ! sValue.empty())
a5777624
RD
1063 {
1064 wxFAIL_MSG( _T("this cell doesn't have float value") );
1065 return;
1066 }
816be743
VZ
1067 }
1068
1069 DoBeginEdit(GetString());
1070}
1071
3324d5f5 1072bool wxGridCellFloatEditor::EndEdit(int row, int col,
816be743
VZ
1073 wxGrid* grid)
1074{
8a60ff0a
RD
1075 double value = 0.0;
1076 wxString text(Text()->GetValue());
1077
c77a6796
VZ
1078 if ( (text.empty() || text.ToDouble(&value)) &&
1079 !wxIsSameDouble(value, m_valueOld) )
816be743 1080 {
a5777624
RD
1081 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
1082 grid->GetTable()->SetValueAsDouble(row, col, value);
1083 else
8a60ff0a 1084 grid->GetTable()->SetValue(row, col, text);
816be743 1085
ca65c044 1086 return true;
816be743 1087 }
2f024384 1088
ca65c044 1089 return false;
816be743
VZ
1090}
1091
1092void wxGridCellFloatEditor::Reset()
1093{
1094 DoReset(GetString());
1095}
1096
1097void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
1098{
12a3f227 1099 int keycode = event.GetKeyCode();
3fe73755
SN
1100 char tmpbuf[2];
1101 tmpbuf[0] = (char) keycode;
1102 tmpbuf[1] = '\0';
42841dfc 1103 wxString strbuf(tmpbuf, *wxConvCurrent);
2f024384 1104
902725ee 1105#if wxUSE_INTL
42841dfc 1106 bool is_decimal_point = ( strbuf ==
63e2147c 1107 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) );
5335e9c4
MW
1108#else
1109 bool is_decimal_point = ( strbuf == _T(".") );
1110#endif
2f024384 1111
63e2147c
RD
1112 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-'
1113 || is_decimal_point )
816be743
VZ
1114 {
1115 wxGridCellTextEditor::StartingKey(event);
1116
1117 // skip Skip() below
1118 return;
1119 }
1120
1121 event.Skip();
1122}
1123
f6bcfd97
BP
1124void wxGridCellFloatEditor::SetParameters(const wxString& params)
1125{
1126 if ( !params )
1127 {
1128 // reset to default
1129 m_width =
1130 m_precision = -1;
1131 }
1132 else
1133 {
1134 long tmp;
1135 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1136 {
1137 m_width = (int)tmp;
1138
1139 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1140 {
1141 m_precision = (int)tmp;
1142
1143 // skip the error message below
1144 return;
1145 }
1146 }
1147
1148 wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
1149 }
1150}
1151
1152wxString wxGridCellFloatEditor::GetString() const
1153{
1154 wxString fmt;
fe4cb4f5 1155 if ( m_precision == -1 && m_width != -1)
f6bcfd97
BP
1156 {
1157 // default precision
ec53826c 1158 fmt.Printf(_T("%%%d.f"), m_width);
f6bcfd97 1159 }
fe4cb4f5
JS
1160 else if ( m_precision != -1 && m_width == -1)
1161 {
1162 // default width
1163 fmt.Printf(_T("%%.%df"), m_precision);
1164 }
1165 else if ( m_precision != -1 && m_width != -1 )
f6bcfd97 1166 {
ec53826c 1167 fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
f6bcfd97 1168 }
fe4cb4f5
JS
1169 else
1170 {
1171 // default width/precision
1172 fmt = _T("%f");
1173 }
f6bcfd97
BP
1174
1175 return wxString::Format(fmt, m_valueOld);
1176}
1177
1178bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1179{
1180 if ( wxGridCellEditor::IsAcceptedKey(event) )
1181 {
1182 int keycode = event.GetKeyCode();
63e2147c
RD
1183 printf("%d\n", keycode);
1184 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1185 char tmpbuf[2];
1186 tmpbuf[0] = (char) keycode;
1187 tmpbuf[1] = '\0';
1188 wxString strbuf(tmpbuf, *wxConvCurrent);
2f024384 1189
902725ee 1190#if wxUSE_INTL
63e2147c
RD
1191 bool is_decimal_point =
1192 ( strbuf == wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT,
1193 wxLOCALE_CAT_NUMBER) );
5335e9c4
MW
1194#else
1195 bool is_decimal_point = ( strbuf == _T(".") );
1196#endif
2f024384 1197
902725ee 1198 if ( (keycode < 128) &&
63e2147c
RD
1199 (wxIsdigit(keycode) || tolower(keycode) == 'e' ||
1200 is_decimal_point || keycode == '+' || keycode == '-') )
2f024384 1201 {
63e2147c 1202 return true;
2f024384 1203 }
f6bcfd97
BP
1204 }
1205
ca65c044 1206 return false;
f6bcfd97
BP
1207}
1208
3a8c693a
VZ
1209#endif // wxUSE_TEXTCTRL
1210
1211#if wxUSE_CHECKBOX
1212
508011ce
VZ
1213// ----------------------------------------------------------------------------
1214// wxGridCellBoolEditor
1215// ----------------------------------------------------------------------------
1216
1217void wxGridCellBoolEditor::Create(wxWindow* parent,
1218 wxWindowID id,
1219 wxEvtHandler* evtHandler)
1220{
1221 m_control = new wxCheckBox(parent, id, wxEmptyString,
1222 wxDefaultPosition, wxDefaultSize,
1223 wxNO_BORDER);
1224
1225 wxGridCellEditor::Create(parent, id, evtHandler);
1226}
1227
1228void wxGridCellBoolEditor::SetSize(const wxRect& r)
1229{
ca65c044 1230 bool resize = false;
b94ae1ea
VZ
1231 wxSize size = m_control->GetSize();
1232 wxCoord minSize = wxMin(r.width, r.height);
1233
1234 // check if the checkbox is not too big/small for this cell
1235 wxSize sizeBest = m_control->GetBestSize();
1236 if ( !(size == sizeBest) )
1237 {
1238 // reset to default size if it had been made smaller
1239 size = sizeBest;
1240
ca65c044 1241 resize = true;
b94ae1ea
VZ
1242 }
1243
1244 if ( size.x >= minSize || size.y >= minSize )
1245 {
1246 // leave 1 pixel margin
1247 size.x = size.y = minSize - 2;
1248
ca65c044 1249 resize = true;
b94ae1ea
VZ
1250 }
1251
1252 if ( resize )
1253 {
1254 m_control->SetSize(size);
1255 }
1256
508011ce 1257 // position it in the centre of the rectangle (TODO: support alignment?)
508011ce 1258
b94ae1ea 1259#if defined(__WXGTK__) || defined (__WXMOTIF__)
508011ce
VZ
1260 // the checkbox without label still has some space to the right in wxGTK,
1261 // so shift it to the right
b94ae1ea
VZ
1262 size.x -= 8;
1263#elif defined(__WXMSW__)
a95e38c0
VZ
1264 // here too, but in other way
1265 size.x += 1;
b94ae1ea
VZ
1266 size.y -= 2;
1267#endif
508011ce 1268
1bd71df9
JS
1269 int hAlign = wxALIGN_CENTRE;
1270 int vAlign = wxALIGN_CENTRE;
1271 if (GetCellAttr())
1272 GetCellAttr()->GetAlignment(& hAlign, & vAlign);
52d6f640 1273
1bd71df9
JS
1274 int x = 0, y = 0;
1275 if (hAlign == wxALIGN_LEFT)
1276 {
1277 x = r.x + 2;
2f024384 1278
1bd71df9
JS
1279#ifdef __WXMSW__
1280 x += 2;
52d6f640 1281#endif
2f024384
DS
1282
1283 y = r.y + r.height / 2 - size.y / 2;
1bd71df9
JS
1284 }
1285 else if (hAlign == wxALIGN_RIGHT)
1286 {
1287 x = r.x + r.width - size.x - 2;
2f024384 1288 y = r.y + r.height / 2 - size.y / 2;
1bd71df9
JS
1289 }
1290 else if (hAlign == wxALIGN_CENTRE)
1291 {
2f024384
DS
1292 x = r.x + r.width / 2 - size.x / 2;
1293 y = r.y + r.height / 2 - size.y / 2;
1bd71df9 1294 }
52d6f640 1295
1bd71df9 1296 m_control->Move(x, y);
508011ce
VZ
1297}
1298
1299void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1300{
99306db2
VZ
1301 m_control->Show(show);
1302
189d0213 1303 if ( show )
508011ce 1304 {
189d0213
VZ
1305 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1306 CBox()->SetBackgroundColour(colBg);
508011ce 1307 }
508011ce
VZ
1308}
1309
1310void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1311{
1312 wxASSERT_MSG(m_control,
1313 wxT("The wxGridCellEditor must be Created first!"));
1314
28a77bc4 1315 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
2f024384 1316 {
f2d76237 1317 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
2f024384 1318 }
f2d76237 1319 else
695a3263
MB
1320 {
1321 wxString cellval( grid->GetTable()->GetValue(row, col) );
8dd8f875 1322 m_startValue = !( !cellval || (cellval == wxT("0")) );
695a3263 1323 }
2f024384 1324
508011ce
VZ
1325 CBox()->SetValue(m_startValue);
1326 CBox()->SetFocus();
1327}
1328
1329bool wxGridCellBoolEditor::EndEdit(int row, int col,
508011ce
VZ
1330 wxGrid* grid)
1331{
1332 wxASSERT_MSG(m_control,
1333 wxT("The wxGridCellEditor must be Created first!"));
1334
ca65c044 1335 bool changed = false;
508011ce
VZ
1336 bool value = CBox()->GetValue();
1337 if ( value != m_startValue )
ca65c044 1338 changed = true;
508011ce
VZ
1339
1340 if ( changed )
1341 {
28a77bc4 1342 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
f2d76237
RD
1343 grid->GetTable()->SetValueAsBool(row, col, value);
1344 else
1345 grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
508011ce
VZ
1346 }
1347
1348 return changed;
1349}
1350
1351void wxGridCellBoolEditor::Reset()
1352{
1353 wxASSERT_MSG(m_control,
1354 wxT("The wxGridCellEditor must be Created first!"));
1355
1356 CBox()->SetValue(m_startValue);
1357}
1358
e195a54c 1359void wxGridCellBoolEditor::StartingClick()
508011ce 1360{
e195a54c 1361 CBox()->SetValue(!CBox()->GetValue());
508011ce
VZ
1362}
1363
f6bcfd97
BP
1364bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1365{
1366 if ( wxGridCellEditor::IsAcceptedKey(event) )
1367 {
1368 int keycode = event.GetKeyCode();
1369 switch ( keycode )
1370 {
f6bcfd97
BP
1371 case WXK_SPACE:
1372 case '+':
1373 case '-':
ca65c044 1374 return true;
f6bcfd97
BP
1375 }
1376 }
1377
ca65c044 1378 return false;
f6bcfd97 1379}
04418332 1380
63e2147c
RD
1381void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event)
1382{
1383 int keycode = event.GetKeyCode();
1384 switch ( keycode )
1385 {
1386 case WXK_SPACE:
1387 CBox()->SetValue(!CBox()->GetValue());
1388 break;
902725ee 1389
63e2147c
RD
1390 case '+':
1391 CBox()->SetValue(true);
1392 break;
902725ee 1393
63e2147c
RD
1394 case '-':
1395 CBox()->SetValue(false);
1396 break;
1397 }
1398}
1399
1400
73145b0e
JS
1401// return the value as "1" for true and the empty string for false
1402wxString wxGridCellBoolEditor::GetValue() const
1403{
1404 bool bSet = CBox()->GetValue();
04418332 1405 return bSet ? _T("1") : wxEmptyString;
73145b0e 1406}
f6bcfd97 1407
3a8c693a
VZ
1408#endif // wxUSE_CHECKBOX
1409
1410#if wxUSE_COMBOBOX
1411
4ee5fc9c
VZ
1412// ----------------------------------------------------------------------------
1413// wxGridCellChoiceEditor
1414// ----------------------------------------------------------------------------
1415
7db33cc3
MB
1416wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices,
1417 bool allowOthers)
1418 : m_choices(choices),
1419 m_allowOthers(allowOthers) { }
1420
4ee5fc9c 1421wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
f6bcfd97 1422 const wxString choices[],
4ee5fc9c
VZ
1423 bool allowOthers)
1424 : m_allowOthers(allowOthers)
1425{
c4608a8a 1426 if ( count )
4ee5fc9c 1427 {
c4608a8a
VZ
1428 m_choices.Alloc(count);
1429 for ( size_t n = 0; n < count; n++ )
1430 {
1431 m_choices.Add(choices[n]);
1432 }
4ee5fc9c
VZ
1433 }
1434}
1435
c4608a8a
VZ
1436wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1437{
1438 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1439 editor->m_allowOthers = m_allowOthers;
1440 editor->m_choices = m_choices;
1441
1442 return editor;
1443}
1444
4ee5fc9c
VZ
1445void wxGridCellChoiceEditor::Create(wxWindow* parent,
1446 wxWindowID id,
1447 wxEvtHandler* evtHandler)
1448{
4ee5fc9c
VZ
1449 m_control = new wxComboBox(parent, id, wxEmptyString,
1450 wxDefaultPosition, wxDefaultSize,
584ad2a3 1451 m_choices,
4ee5fc9c
VZ
1452 m_allowOthers ? 0 : wxCB_READONLY);
1453
4ee5fc9c
VZ
1454 wxGridCellEditor::Create(parent, id, evtHandler);
1455}
1456
a5777624
RD
1457void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1458 wxGridCellAttr * attr)
4ee5fc9c
VZ
1459{
1460 // as we fill the entire client area, don't do anything here to minimize
1461 // flicker
a5777624
RD
1462
1463 // TODO: It doesn't actually fill the client area since the height of a
1464 // combo always defaults to the standard... Until someone has time to
1465 // figure out the right rectangle to paint, just do it the normal way...
1466 wxGridCellEditor::PaintBackground(rectCell, attr);
4ee5fc9c
VZ
1467}
1468
1469void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1470{
1471 wxASSERT_MSG(m_control,
1472 wxT("The wxGridCellEditor must be Created first!"));
1473
08dd04d0
JS
1474 wxGridCellEditorEvtHandler* evtHandler = NULL;
1475 if (m_control)
1476 evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
1477
1478 // Don't immediately end if we get a kill focus event within BeginEdit
1479 if (evtHandler)
1480 evtHandler->SetInSetFocus(true);
1481
4ee5fc9c
VZ
1482 m_startValue = grid->GetTable()->GetValue(row, col);
1483
2b5f62a0 1484 if (m_allowOthers)
2f024384 1485 {
2b5f62a0 1486 Combo()->SetValue(m_startValue);
2f024384 1487 }
2b5f62a0 1488 else
28a77bc4 1489 {
2b5f62a0
VZ
1490 // find the right position, or default to the first if not found
1491 int pos = Combo()->FindString(m_startValue);
902725ee 1492 if (pos == wxNOT_FOUND)
2b5f62a0
VZ
1493 pos = 0;
1494 Combo()->SetSelection(pos);
28a77bc4 1495 }
2f024384 1496
4ee5fc9c
VZ
1497 Combo()->SetInsertionPointEnd();
1498 Combo()->SetFocus();
08dd04d0
JS
1499
1500 if (evtHandler)
46cbb21e
JS
1501 {
1502 // When dropping down the menu, a kill focus event
1503 // happens after this point, so we can't reset the flag yet.
1504#if !defined(__WXGTK20__)
08dd04d0 1505 evtHandler->SetInSetFocus(false);
46cbb21e
JS
1506#endif
1507 }
4ee5fc9c
VZ
1508}
1509
28a77bc4 1510bool wxGridCellChoiceEditor::EndEdit(int row, int col,
4ee5fc9c
VZ
1511 wxGrid* grid)
1512{
1513 wxString value = Combo()->GetValue();
faffacec
VZ
1514 if ( value == m_startValue )
1515 return false;
4ee5fc9c 1516
faffacec 1517 grid->GetTable()->SetValue(row, col, value);
4ee5fc9c 1518
faffacec 1519 return true;
4ee5fc9c
VZ
1520}
1521
1522void wxGridCellChoiceEditor::Reset()
1523{
1524 Combo()->SetValue(m_startValue);
1525 Combo()->SetInsertionPointEnd();
1526}
1527
c4608a8a
VZ
1528void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1529{
1530 if ( !params )
1531 {
1532 // what can we do?
1533 return;
1534 }
1535
1536 m_choices.Empty();
1537
1538 wxStringTokenizer tk(params, _T(','));
1539 while ( tk.HasMoreTokens() )
1540 {
1541 m_choices.Add(tk.GetNextToken());
1542 }
1543}
1544
73145b0e
JS
1545// return the value in the text control
1546wxString wxGridCellChoiceEditor::GetValue() const
1547{
1548 return Combo()->GetValue();
1549}
04418332 1550
3a8c693a
VZ
1551#endif // wxUSE_COMBOBOX
1552
508011ce
VZ
1553// ----------------------------------------------------------------------------
1554// wxGridCellEditorEvtHandler
1555// ----------------------------------------------------------------------------
2796cce3 1556
140954fd
VZ
1557void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event)
1558{
08dd04d0
JS
1559 // Don't disable the cell if we're just starting to edit it
1560 if (m_inSetFocus)
1561 return;
1562
140954fd
VZ
1563 // accept changes
1564 m_grid->DisableCellEditControl();
1565
1566 event.Skip();
1567}
1568
2796cce3
RD
1569void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1570{
12a3f227 1571 switch ( event.GetKeyCode() )
2796cce3
RD
1572 {
1573 case WXK_ESCAPE:
1574 m_editor->Reset();
b54ba671 1575 m_grid->DisableCellEditControl();
2796cce3
RD
1576 break;
1577
2c9a89e0 1578 case WXK_TAB:
b51c3f27 1579 m_grid->GetEventHandler()->ProcessEvent( event );
9b4aede2
RD
1580 break;
1581
2796cce3 1582 case WXK_RETURN:
faec5a43
SN
1583 case WXK_NUMPAD_ENTER:
1584 if (!m_grid->GetEventHandler()->ProcessEvent(event))
2796cce3
RD
1585 m_editor->HandleReturn(event);
1586 break;
1587
2796cce3
RD
1588 default:
1589 event.Skip();
2f024384 1590 break;
2796cce3
RD
1591 }
1592}
1593
fb0de762
RD
1594void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1595{
7db713ae
JS
1596 int row = m_grid->GetGridCursorRow();
1597 int col = m_grid->GetGridCursorCol();
1598 wxRect rect = m_grid->CellToRect( row, col );
1599 int cw, ch;
1600 m_grid->GetGridWindow()->GetClientSize( &cw, &ch );
2f024384 1601
7db713ae
JS
1602 // if cell width is smaller than grid client area, cell is wholly visible
1603 bool wholeCellVisible = (rect.GetWidth() < cw);
1604
12a3f227 1605 switch ( event.GetKeyCode() )
fb0de762
RD
1606 {
1607 case WXK_ESCAPE:
1608 case WXK_TAB:
1609 case WXK_RETURN:
a4f7bf58 1610 case WXK_NUMPAD_ENTER:
fb0de762
RD
1611 break;
1612
7db713ae
JS
1613 case WXK_HOME:
1614 {
2f024384 1615 if ( wholeCellVisible )
7db713ae
JS
1616 {
1617 // no special processing needed...
1618 event.Skip();
1619 break;
1620 }
1621
1622 // do special processing for partly visible cell...
1623
1624 // get the widths of all cells previous to this one
1625 int colXPos = 0;
faa94f3e 1626 for ( int i = 0; i < col; i++ )
7db713ae
JS
1627 {
1628 colXPos += m_grid->GetColSize(i);
1629 }
1630
1631 int xUnit = 1, yUnit = 1;
1632 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
1633 if (col != 0)
1634 {
2f024384 1635 m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL));
7db713ae
JS
1636 }
1637 else
1638 {
2f024384 1639 m_grid->Scroll(colXPos / xUnit, m_grid->GetScrollPos(wxVERTICAL));
7db713ae
JS
1640 }
1641 event.Skip();
1642 break;
1643 }
1644 case WXK_END:
1645 {
2f024384 1646 if ( wholeCellVisible )
7db713ae
JS
1647 {
1648 // no special processing needed...
1649 event.Skip();
1650 break;
1651 }
1652
1653 // do special processing for partly visible cell...
1654
1655 int textWidth = 0;
1656 wxString value = m_grid->GetCellValue(row, col);
1657 if ( wxEmptyString != value )
1658 {
1659 // get width of cell CONTENTS (text)
1660 int y;
1661 wxFont font = m_grid->GetCellFont(row, col);
1662 m_grid->GetTextExtent(value, &textWidth, &y, NULL, NULL, &font);
2f024384 1663
7db713ae
JS
1664 // try to RIGHT align the text by scrolling
1665 int client_right = m_grid->GetGridWindow()->GetClientSize().GetWidth();
2f024384 1666
7db713ae
JS
1667 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
1668 // otherwise the last part of the cell content might be hidden below the scroll bar
1669 // FIXME: maybe there is a more suitable correction?
2f024384 1670 textWidth -= (client_right - (m_grid->GetScrollLineX() * 2));
7db713ae
JS
1671 if ( textWidth < 0 )
1672 {
1673 textWidth = 0;
1674 }
1675 }
1676
1677 // get the widths of all cells previous to this one
1678 int colXPos = 0;
faa94f3e 1679 for ( int i = 0; i < col; i++ )
7db713ae
JS
1680 {
1681 colXPos += m_grid->GetColSize(i);
1682 }
2f024384 1683
7db713ae
JS
1684 // and add the (modified) text width of the cell contents
1685 // as we'd like to see the last part of the cell contents
1686 colXPos += textWidth;
1687
1688 int xUnit = 1, yUnit = 1;
1689 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
1690 m_grid->Scroll(colXPos/xUnit-1, m_grid->GetScrollPos(wxVERTICAL));
1691 event.Skip();
1692 break;
1693 }
1694
fb0de762
RD
1695 default:
1696 event.Skip();
1697 }
1698}
1699
c4608a8a
VZ
1700// ----------------------------------------------------------------------------
1701// wxGridCellWorker is an (almost) empty common base class for
1702// wxGridCellRenderer and wxGridCellEditor managing ref counting
1703// ----------------------------------------------------------------------------
1704
1705void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
1706{
1707 // nothing to do
1708}
1709
1710wxGridCellWorker::~wxGridCellWorker()
1711{
1712}
1713
508011ce
VZ
1714// ============================================================================
1715// renderer classes
1716// ============================================================================
1717
ab79958a
VZ
1718// ----------------------------------------------------------------------------
1719// wxGridCellRenderer
1720// ----------------------------------------------------------------------------
1721
1722void wxGridCellRenderer::Draw(wxGrid& grid,
2796cce3 1723 wxGridCellAttr& attr,
ab79958a
VZ
1724 wxDC& dc,
1725 const wxRect& rect,
c78b3acd 1726 int WXUNUSED(row), int WXUNUSED(col),
ab79958a
VZ
1727 bool isSelected)
1728{
1729 dc.SetBackgroundMode( wxSOLID );
1730
04418332 1731 // grey out fields if the grid is disabled
4db6714b 1732 if ( grid.IsEnabled() )
ab79958a 1733 {
ec157c8f
WS
1734 if ( isSelected )
1735 {
1736 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
1737 }
1738 else
1739 {
1740 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
1741 }
52d6f640 1742 }
ab79958a
VZ
1743 else
1744 {
ec157c8f 1745 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID));
ab79958a
VZ
1746 }
1747
1748 dc.SetPen( *wxTRANSPARENT_PEN );
ab79958a
VZ
1749 dc.DrawRectangle(rect);
1750}
1751
508011ce
VZ
1752// ----------------------------------------------------------------------------
1753// wxGridCellStringRenderer
1754// ----------------------------------------------------------------------------
1755
fbfb8bcc
VZ
1756void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid,
1757 const wxGridCellAttr& attr,
816be743
VZ
1758 wxDC& dc,
1759 bool isSelected)
ab79958a 1760{
ab79958a
VZ
1761 dc.SetBackgroundMode( wxTRANSPARENT );
1762
283b7808
VZ
1763 // TODO some special colours for attr.IsReadOnly() case?
1764
04418332 1765 // different coloured text when the grid is disabled
4db6714b 1766 if ( grid.IsEnabled() )
ab79958a 1767 {
73145b0e
JS
1768 if ( isSelected )
1769 {
1770 dc.SetTextBackground( grid.GetSelectionBackground() );
1771 dc.SetTextForeground( grid.GetSelectionForeground() );
1772 }
1773 else
1774 {
1775 dc.SetTextBackground( attr.GetBackgroundColour() );
1776 dc.SetTextForeground( attr.GetTextColour() );
1777 }
ab79958a
VZ
1778 }
1779 else
1780 {
ec157c8f
WS
1781 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
1782 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
ab79958a 1783 }
816be743 1784
2796cce3 1785 dc.SetFont( attr.GetFont() );
816be743
VZ
1786}
1787
fbfb8bcc 1788wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
65e4e78e
VZ
1789 wxDC& dc,
1790 const wxString& text)
1791{
f6bcfd97 1792 wxCoord x = 0, y = 0, max_x = 0;
65e4e78e 1793 dc.SetFont(attr.GetFont());
f6bcfd97
BP
1794 wxStringTokenizer tk(text, _T('\n'));
1795 while ( tk.HasMoreTokens() )
1796 {
1797 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
1798 max_x = wxMax(max_x, x);
1799 }
1800
1801 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
65e4e78e 1802
f6bcfd97 1803 return wxSize(max_x, y);
65e4e78e
VZ
1804}
1805
1806wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1807 wxGridCellAttr& attr,
1808 wxDC& dc,
1809 int row, int col)
1810{
1811 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1812}
1813
816be743
VZ
1814void wxGridCellStringRenderer::Draw(wxGrid& grid,
1815 wxGridCellAttr& attr,
1816 wxDC& dc,
1817 const wxRect& rectCell,
1818 int row, int col,
1819 bool isSelected)
1820{
27f35b66 1821 wxRect rect = rectCell;
dc1f566f
SN
1822 rect.Inflate(-1);
1823
1824 // erase only this cells background, overflow cells should have been erased
1825 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1826
1827 int hAlign, vAlign;
1828 attr.GetAlignment(&hAlign, &vAlign);
27f35b66 1829
39b80349
SN
1830 int overflowCols = 0;
1831
27f35b66
SN
1832 if (attr.GetOverflow())
1833 {
1834 int cols = grid.GetNumberCols();
1835 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
1836 int cell_rows, cell_cols;
2f024384 1837 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0
27f35b66
SN
1838 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
1839 {
1840 int i, c_cols, c_rows;
1841 for (i = col+cell_cols; i < cols; i++)
1842 {
ca65c044 1843 bool is_empty = true;
2f024384 1844 for (int j=row; j < row + cell_rows; j++)
27f35b66 1845 {
39b80349 1846 // check w/ anchor cell for multicell block
ef4d6ce8 1847 grid.GetCellSize(j, i, &c_rows, &c_cols);
2f024384
DS
1848 if (c_rows > 0)
1849 c_rows = 0;
1850 if (!grid.GetTable()->IsEmptyCell(j + c_rows, i))
39b80349 1851 {
ca65c044 1852 is_empty = false;
ef4d6ce8 1853 break;
39b80349 1854 }
27f35b66 1855 }
2f024384 1856
39b80349
SN
1857 if (is_empty)
1858 rect.width += grid.GetColSize(i);
dc1f566f
SN
1859 else
1860 {
1861 i--;
1862 break;
1863 }
2f024384 1864
4db6714b
KH
1865 if (rect.width >= best_width)
1866 break;
2b5f62a0 1867 }
2f024384 1868
39b80349 1869 overflowCols = i - col - cell_cols + 1;
4db6714b
KH
1870 if (overflowCols >= cols)
1871 overflowCols = cols - 1;
39b80349 1872 }
27f35b66 1873
dc1f566f
SN
1874 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
1875 {
39b80349 1876 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
2b5f62a0 1877 wxRect clip = rect;
39b80349 1878 clip.x += rectCell.width;
dc1f566f 1879 // draw each overflow cell individually
2f024384 1880 int col_end = col+cell_cols + overflowCols;
dc1f566f 1881 if (col_end >= grid.GetNumberCols())
2b5f62a0 1882 col_end = grid.GetNumberCols() - 1;
dc1f566f
SN
1883 for (int i = col+cell_cols; i <= col_end; i++)
1884 {
dc1f566f
SN
1885 clip.width = grid.GetColSize(i) - 1;
1886 dc.DestroyClippingRegion();
1887 dc.SetClippingRegion(clip);
39b80349
SN
1888
1889 SetTextColoursAndFont(grid, attr, dc,
2b5f62a0 1890 grid.IsInSelection(row,i));
39b80349 1891
dc1f566f 1892 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
2b5f62a0 1893 rect, hAlign, vAlign);
39b80349 1894 clip.x += grid.GetColSize(i) - 1;
dc1f566f 1895 }
ab79958a 1896
39b80349 1897 rect = rectCell;
2b5f62a0 1898 rect.Inflate(-1);
dc1f566f 1899 rect.width++;
39b80349 1900 dc.DestroyClippingRegion();
dc1f566f 1901 }
39b80349 1902 }
ab79958a 1903
dc1f566f
SN
1904 // now we only have to draw the text
1905 SetTextColoursAndFont(grid, attr, dc, isSelected);
39b80349 1906
ab79958a
VZ
1907 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1908 rect, hAlign, vAlign);
1909}
1910
65e4e78e
VZ
1911// ----------------------------------------------------------------------------
1912// wxGridCellNumberRenderer
1913// ----------------------------------------------------------------------------
1914
fbfb8bcc 1915wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col)
65e4e78e
VZ
1916{
1917 wxGridTableBase *table = grid.GetTable();
1918 wxString text;
1919 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1920 {
1921 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
1922 }
9c4ba614
VZ
1923 else
1924 {
1925 text = table->GetValue(row, col);
1926 }
65e4e78e
VZ
1927
1928 return text;
1929}
1930
816be743
VZ
1931void wxGridCellNumberRenderer::Draw(wxGrid& grid,
1932 wxGridCellAttr& attr,
1933 wxDC& dc,
1934 const wxRect& rectCell,
1935 int row, int col,
1936 bool isSelected)
1937{
1938 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1939
1940 SetTextColoursAndFont(grid, attr, dc, isSelected);
1941
1942 // draw the text right aligned by default
1943 int hAlign, vAlign;
1944 attr.GetAlignment(&hAlign, &vAlign);
4c7277db 1945 hAlign = wxALIGN_RIGHT;
816be743
VZ
1946
1947 wxRect rect = rectCell;
1948 rect.Inflate(-1);
1949
65e4e78e
VZ
1950 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
1951}
816be743 1952
65e4e78e
VZ
1953wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
1954 wxGridCellAttr& attr,
1955 wxDC& dc,
1956 int row, int col)
1957{
1958 return DoGetBestSize(attr, dc, GetString(grid, row, col));
816be743
VZ
1959}
1960
1961// ----------------------------------------------------------------------------
1962// wxGridCellFloatRenderer
1963// ----------------------------------------------------------------------------
1964
1965wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
1966{
1967 SetWidth(width);
1968 SetPrecision(precision);
1969}
1970
e72b4213
VZ
1971wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
1972{
1973 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
1974 renderer->m_width = m_width;
1975 renderer->m_precision = m_precision;
1976 renderer->m_format = m_format;
1977
1978 return renderer;
1979}
1980
fbfb8bcc 1981wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col)
65e4e78e
VZ
1982{
1983 wxGridTableBase *table = grid.GetTable();
0b190b0f
VZ
1984
1985 bool hasDouble;
1986 double val;
65e4e78e
VZ
1987 wxString text;
1988 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1989 {
0b190b0f 1990 val = table->GetValueAsDouble(row, col);
ca65c044 1991 hasDouble = true;
65e4e78e 1992 }
9c4ba614
VZ
1993 else
1994 {
1995 text = table->GetValue(row, col);
0b190b0f 1996 hasDouble = text.ToDouble(&val);
9c4ba614 1997 }
65e4e78e 1998
0b190b0f
VZ
1999 if ( hasDouble )
2000 {
2001 if ( !m_format )
2002 {
2003 if ( m_width == -1 )
2004 {
19d7140e
VZ
2005 if ( m_precision == -1 )
2006 {
2b5f62a0
VZ
2007 // default width/precision
2008 m_format = _T("%f");
2009 }
19d7140e
VZ
2010 else
2011 {
2012 m_format.Printf(_T("%%.%df"), m_precision);
2013 }
0b190b0f
VZ
2014 }
2015 else if ( m_precision == -1 )
2016 {
2017 // default precision
2018 m_format.Printf(_T("%%%d.f"), m_width);
2019 }
2020 else
2021 {
2022 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
2023 }
2024 }
2025
2026 text.Printf(m_format, val);
19d7140e 2027
0b190b0f
VZ
2028 }
2029 //else: text already contains the string
2030
65e4e78e
VZ
2031 return text;
2032}
2033
816be743
VZ
2034void wxGridCellFloatRenderer::Draw(wxGrid& grid,
2035 wxGridCellAttr& attr,
2036 wxDC& dc,
2037 const wxRect& rectCell,
2038 int row, int col,
2039 bool isSelected)
2040{
2041 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
2042
2043 SetTextColoursAndFont(grid, attr, dc, isSelected);
2044
2045 // draw the text right aligned by default
2046 int hAlign, vAlign;
2047 attr.GetAlignment(&hAlign, &vAlign);
4c7277db 2048 hAlign = wxALIGN_RIGHT;
816be743
VZ
2049
2050 wxRect rect = rectCell;
2051 rect.Inflate(-1);
2052
65e4e78e
VZ
2053 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
2054}
816be743 2055
65e4e78e
VZ
2056wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
2057 wxGridCellAttr& attr,
2058 wxDC& dc,
2059 int row, int col)
2060{
2061 return DoGetBestSize(attr, dc, GetString(grid, row, col));
816be743
VZ
2062}
2063
0b190b0f
VZ
2064void wxGridCellFloatRenderer::SetParameters(const wxString& params)
2065{
0b190b0f
VZ
2066 if ( !params )
2067 {
2068 // reset to defaults
2069 SetWidth(-1);
2070 SetPrecision(-1);
2071 }
2072 else
2073 {
2074 wxString tmp = params.BeforeFirst(_T(','));
ec157c8f 2075 if ( !tmp.empty() )
0b190b0f
VZ
2076 {
2077 long width;
19d7140e 2078 if ( tmp.ToLong(&width) )
0b190b0f 2079 {
19d7140e 2080 SetWidth((int)width);
0b190b0f
VZ
2081 }
2082 else
2083 {
19d7140e
VZ
2084 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
2085 }
19d7140e 2086 }
2f024384 2087
7448de8d
WS
2088 tmp = params.AfterFirst(_T(','));
2089 if ( !tmp.empty() )
2090 {
2091 long precision;
19d7140e 2092 if ( tmp.ToLong(&precision) )
7448de8d 2093 {
19d7140e 2094 SetPrecision((int)precision);
7448de8d
WS
2095 }
2096 else
2097 {
19d7140e 2098 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
7448de8d 2099 }
0b190b0f
VZ
2100 }
2101 }
2102}
2103
508011ce
VZ
2104// ----------------------------------------------------------------------------
2105// wxGridCellBoolRenderer
2106// ----------------------------------------------------------------------------
2107
65e4e78e 2108wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
508011ce 2109
b94ae1ea
VZ
2110// FIXME these checkbox size calculations are really ugly...
2111
65e4e78e 2112// between checkmark and box
a95e38c0 2113static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
508011ce 2114
65e4e78e
VZ
2115wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
2116 wxGridCellAttr& WXUNUSED(attr),
2117 wxDC& WXUNUSED(dc),
2118 int WXUNUSED(row),
2119 int WXUNUSED(col))
2120{
2121 // compute it only once (no locks for MT safeness in GUI thread...)
2122 if ( !ms_sizeCheckMark.x )
297da4ba 2123 {
65e4e78e 2124 // get checkbox size
ca65c044 2125 wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString);
297da4ba 2126 wxSize size = checkbox->GetBestSize();
2f024384 2127 wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN;
297da4ba 2128
65e4e78e 2129 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
69d8f612 2130#if defined(__WXGTK__) || defined(__WXMOTIF__)
65e4e78e 2131 checkSize -= size.y / 2;
297da4ba
VZ
2132#endif
2133
2134 delete checkbox;
65e4e78e
VZ
2135
2136 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
297da4ba
VZ
2137 }
2138
65e4e78e
VZ
2139 return ms_sizeCheckMark;
2140}
2141
2142void wxGridCellBoolRenderer::Draw(wxGrid& grid,
2143 wxGridCellAttr& attr,
2144 wxDC& dc,
2145 const wxRect& rect,
2146 int row, int col,
2147 bool isSelected)
2148{
2149 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
2150
297da4ba 2151 // draw a check mark in the centre (ignoring alignment - TODO)
65e4e78e 2152 wxSize size = GetBestSize(grid, attr, dc, row, col);
b94ae1ea
VZ
2153
2154 // don't draw outside the cell
2155 wxCoord minSize = wxMin(rect.width, rect.height);
2156 if ( size.x >= minSize || size.y >= minSize )
2157 {
2158 // and even leave (at least) 1 pixel margin
2159 size.x = size.y = minSize - 2;
2160 }
2161
2162 // draw a border around checkmark
1bd71df9
JS
2163 int vAlign, hAlign;
2164 attr.GetAlignment(& hAlign, &vAlign);
52d6f640 2165
a95e38c0 2166 wxRect rectBorder;
1bd71df9
JS
2167 if (hAlign == wxALIGN_CENTRE)
2168 {
2f024384
DS
2169 rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
2170 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
1bd71df9
JS
2171 rectBorder.width = size.x;
2172 rectBorder.height = size.y;
2173 }
2174 else if (hAlign == wxALIGN_LEFT)
2175 {
2176 rectBorder.x = rect.x + 2;
2f024384 2177 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
1bd71df9 2178 rectBorder.width = size.x;
52d6f640 2179 rectBorder.height = size.y;
1bd71df9
JS
2180 }
2181 else if (hAlign == wxALIGN_RIGHT)
2182 {
2183 rectBorder.x = rect.x + rect.width - size.x - 2;
2f024384 2184 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
1bd71df9 2185 rectBorder.width = size.x;
52d6f640 2186 rectBorder.height = size.y;
1bd71df9 2187 }
b94ae1ea 2188
f2d76237 2189 bool value;
b94ae1ea 2190 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
f2d76237
RD
2191 value = grid.GetTable()->GetValueAsBool(row, col);
2192 else
695a3263
MB
2193 {
2194 wxString cellval( grid.GetTable()->GetValue(row, col) );
8dd8f875 2195 value = !( !cellval || (cellval == wxT("0")) );
695a3263 2196 }
f2d76237
RD
2197
2198 if ( value )
508011ce 2199 {
a95e38c0 2200 wxRect rectMark = rectBorder;
2f024384 2201
a95e38c0
VZ
2202#ifdef __WXMSW__
2203 // MSW DrawCheckMark() is weird (and should probably be changed...)
2f024384 2204 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN / 2);
a95e38c0
VZ
2205 rectMark.x++;
2206 rectMark.y++;
2f024384 2207#else
a95e38c0 2208 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
2f024384 2209#endif
a95e38c0 2210
508011ce
VZ
2211 dc.SetTextForeground(attr.GetTextColour());
2212 dc.DrawCheckMark(rectMark);
2213 }
a95e38c0
VZ
2214
2215 dc.SetBrush(*wxTRANSPARENT_BRUSH);
2216 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
2217 dc.DrawRectangle(rectBorder);
508011ce
VZ
2218}
2219
2796cce3
RD
2220// ----------------------------------------------------------------------------
2221// wxGridCellAttr
2222// ----------------------------------------------------------------------------
2223
1df4050d
VZ
2224void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
2225{
2226 m_nRef = 1;
2227
2228 m_isReadOnly = Unset;
2229
2230 m_renderer = NULL;
2231 m_editor = NULL;
2232
2233 m_attrkind = wxGridCellAttr::Cell;
2234
27f35b66 2235 m_sizeRows = m_sizeCols = 1;
b63fce94 2236 m_overflow = UnsetOverflow;
27f35b66 2237
1df4050d
VZ
2238 SetDefAttr(attrDefault);
2239}
2240
39bcce60 2241wxGridCellAttr *wxGridCellAttr::Clone() const
a68c1246 2242{
1df4050d
VZ
2243 wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr);
2244
a68c1246
VZ
2245 if ( HasTextColour() )
2246 attr->SetTextColour(GetTextColour());
2247 if ( HasBackgroundColour() )
2248 attr->SetBackgroundColour(GetBackgroundColour());
2249 if ( HasFont() )
2250 attr->SetFont(GetFont());
2251 if ( HasAlignment() )
2252 attr->SetAlignment(m_hAlign, m_vAlign);
2253
27f35b66
SN
2254 attr->SetSize( m_sizeRows, m_sizeCols );
2255
a68c1246
VZ
2256 if ( m_renderer )
2257 {
2258 attr->SetRenderer(m_renderer);
39bcce60 2259 m_renderer->IncRef();
a68c1246
VZ
2260 }
2261 if ( m_editor )
2262 {
2263 attr->SetEditor(m_editor);
39bcce60 2264 m_editor->IncRef();
a68c1246
VZ
2265 }
2266
2267 if ( IsReadOnly() )
2268 attr->SetReadOnly();
2269
19d7140e
VZ
2270 attr->SetKind( m_attrkind );
2271
a68c1246
VZ
2272 return attr;
2273}
2274
19d7140e
VZ
2275void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom)
2276{
2277 if ( !HasTextColour() && mergefrom->HasTextColour() )
2278 SetTextColour(mergefrom->GetTextColour());
2279 if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() )
2280 SetBackgroundColour(mergefrom->GetBackgroundColour());
2281 if ( !HasFont() && mergefrom->HasFont() )
2282 SetFont(mergefrom->GetFont());
4db6714b
KH
2283 if ( !HasAlignment() && mergefrom->HasAlignment() )
2284 {
19d7140e
VZ
2285 int hAlign, vAlign;
2286 mergefrom->GetAlignment( &hAlign, &vAlign);
2287 SetAlignment(hAlign, vAlign);
2288 }
3100c3db
RD
2289 if ( !HasSize() && mergefrom->HasSize() )
2290 mergefrom->GetSize( &m_sizeRows, &m_sizeCols );
27f35b66 2291
19d7140e
VZ
2292 // Directly access member functions as GetRender/Editor don't just return
2293 // m_renderer/m_editor
2294 //
2295 // Maybe add support for merge of Render and Editor?
2296 if (!HasRenderer() && mergefrom->HasRenderer() )
bf7945ce 2297 {
19d7140e
VZ
2298 m_renderer = mergefrom->m_renderer;
2299 m_renderer->IncRef();
2300 }
2301 if ( !HasEditor() && mergefrom->HasEditor() )
2302 {
2303 m_editor = mergefrom->m_editor;
2304 m_editor->IncRef();
2305 }
2f024384 2306 if ( !HasReadWriteMode() && mergefrom->HasReadWriteMode() )
19d7140e
VZ
2307 SetReadOnly(mergefrom->IsReadOnly());
2308
2f024384 2309 if (!HasOverflowMode() && mergefrom->HasOverflowMode() )
ff699386 2310 SetOverflow(mergefrom->GetOverflow());
ef5df12b 2311
19d7140e
VZ
2312 SetDefAttr(mergefrom->m_defGridAttr);
2313}
2314
27f35b66
SN
2315void wxGridCellAttr::SetSize(int num_rows, int num_cols)
2316{
2317 // The size of a cell is normally 1,1
2318
2319 // If this cell is larger (2,2) then this is the top left cell
2320 // the other cells that will be covered (lower right cells) must be
2321 // set to negative or zero values such that
2322 // row + num_rows of the covered cell points to the larger cell (this cell)
2323 // same goes for the col + num_cols.
2324
2325 // Size of 0,0 is NOT valid, neither is <=0 and any positive value
2326
2f024384
DS
2327 wxASSERT_MSG( (!((num_rows > 0) && (num_cols <= 0)) ||
2328 !((num_rows <= 0) && (num_cols > 0)) ||
2329 !((num_rows == 0) && (num_cols == 0))),
27f35b66
SN
2330 wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
2331
2332 m_sizeRows = num_rows;
2333 m_sizeCols = num_cols;
2334}
2335
2796cce3
RD
2336const wxColour& wxGridCellAttr::GetTextColour() const
2337{
2338 if (HasTextColour())
508011ce 2339 {
2796cce3 2340 return m_colText;
508011ce 2341 }
0926b2fc 2342 else if (m_defGridAttr && m_defGridAttr != this)
508011ce 2343 {
2796cce3 2344 return m_defGridAttr->GetTextColour();
508011ce
VZ
2345 }
2346 else
2347 {
2796cce3
RD
2348 wxFAIL_MSG(wxT("Missing default cell attribute"));
2349 return wxNullColour;
2350 }
2351}
2352
2796cce3
RD
2353const wxColour& wxGridCellAttr::GetBackgroundColour() const
2354{
2355 if (HasBackgroundColour())
2f024384 2356 {
2796cce3 2357 return m_colBack;
2f024384 2358 }
0926b2fc 2359 else if (m_defGridAttr && m_defGridAttr != this)
2f024384 2360 {
2796cce3 2361 return m_defGridAttr->GetBackgroundColour();
2f024384 2362 }
508011ce
VZ
2363 else
2364 {
2796cce3
RD
2365 wxFAIL_MSG(wxT("Missing default cell attribute"));
2366 return wxNullColour;
2367 }
2368}
2369
2796cce3
RD
2370const wxFont& wxGridCellAttr::GetFont() const
2371{
2372 if (HasFont())
2f024384 2373 {
2796cce3 2374 return m_font;
2f024384 2375 }
0926b2fc 2376 else if (m_defGridAttr && m_defGridAttr != this)
2f024384 2377 {
2796cce3 2378 return m_defGridAttr->GetFont();
2f024384 2379 }
508011ce
VZ
2380 else
2381 {
2796cce3
RD
2382 wxFAIL_MSG(wxT("Missing default cell attribute"));
2383 return wxNullFont;
2384 }
2385}
2386
2796cce3
RD
2387void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
2388{
508011ce
VZ
2389 if (HasAlignment())
2390 {
4db6714b
KH
2391 if ( hAlign )
2392 *hAlign = m_hAlign;
2393 if ( vAlign )
2394 *vAlign = m_vAlign;
2796cce3 2395 }
0926b2fc 2396 else if (m_defGridAttr && m_defGridAttr != this)
2796cce3 2397 m_defGridAttr->GetAlignment(hAlign, vAlign);
508011ce
VZ
2398 else
2399 {
2796cce3
RD
2400 wxFAIL_MSG(wxT("Missing default cell attribute"));
2401 }
2402}
2403
27f35b66
SN
2404void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const
2405{
4db6714b
KH
2406 if ( num_rows )
2407 *num_rows = m_sizeRows;
2408 if ( num_cols )
2409 *num_cols = m_sizeCols;
27f35b66 2410}
2796cce3 2411
f2d76237 2412// GetRenderer and GetEditor use a slightly different decision path about
28a77bc4
RD
2413// which attribute to use. If a non-default attr object has one then it is
2414// used, otherwise the default editor or renderer is fetched from the grid and
2415// used. It should be the default for the data type of the cell. If it is
2416// NULL (because the table has a type that the grid does not have in its
2417// registry,) then the grid's default editor or renderer is used.
2418
2419wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
2420{
3cf883a2 2421 wxGridCellRenderer *renderer;
28a77bc4 2422
3cf883a2 2423 if ( m_renderer && this != m_defGridAttr )
0b190b0f 2424 {
3cf883a2
VZ
2425 // use the cells renderer if it has one
2426 renderer = m_renderer;
2427 renderer->IncRef();
0b190b0f 2428 }
2f024384 2429 else // no non-default cell renderer
0b190b0f 2430 {
3cf883a2
VZ
2431 // get default renderer for the data type
2432 if ( grid )
2433 {
2434 // GetDefaultRendererForCell() will do IncRef() for us
2435 renderer = grid->GetDefaultRendererForCell(row, col);
2436 }
2437 else
2438 {
2439 renderer = NULL;
2440 }
0b190b0f 2441
3cf883a2
VZ
2442 if ( !renderer )
2443 {
0926b2fc 2444 if (m_defGridAttr && this != m_defGridAttr )
3cf883a2
VZ
2445 {
2446 // if we still don't have one then use the grid default
2447 // (no need for IncRef() here neither)
2448 renderer = m_defGridAttr->GetRenderer(NULL, 0, 0);
2449 }
2450 else // default grid attr
2451 {
2452 // use m_renderer which we had decided not to use initially
2453 renderer = m_renderer;
2454 if ( renderer )
2455 renderer->IncRef();
2456 }
2457 }
0b190b0f 2458 }
28a77bc4 2459
3cf883a2
VZ
2460 // we're supposed to always find something
2461 wxASSERT_MSG(renderer, wxT("Missing default cell renderer"));
28a77bc4
RD
2462
2463 return renderer;
2796cce3
RD
2464}
2465
3cf883a2 2466// same as above, except for s/renderer/editor/g
28a77bc4 2467wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
07296f0b 2468{
3cf883a2 2469 wxGridCellEditor *editor;
0b190b0f 2470
3cf883a2 2471 if ( m_editor && this != m_defGridAttr )
0b190b0f 2472 {
3cf883a2
VZ
2473 // use the cells editor if it has one
2474 editor = m_editor;
2475 editor->IncRef();
0b190b0f 2476 }
3cf883a2 2477 else // no non default cell editor
0b190b0f 2478 {
3cf883a2
VZ
2479 // get default editor for the data type
2480 if ( grid )
2481 {
2482 // GetDefaultEditorForCell() will do IncRef() for us
2483 editor = grid->GetDefaultEditorForCell(row, col);
2484 }
2485 else
2486 {
2487 editor = NULL;
2488 }
2489
2490 if ( !editor )
2491 {
0926b2fc 2492 if ( m_defGridAttr && this != m_defGridAttr )
3cf883a2
VZ
2493 {
2494 // if we still don't have one then use the grid default
2495 // (no need for IncRef() here neither)
2496 editor = m_defGridAttr->GetEditor(NULL, 0, 0);
2497 }
2498 else // default grid attr
2499 {
2500 // use m_editor which we had decided not to use initially
2501 editor = m_editor;
2502 if ( editor )
2503 editor->IncRef();
2504 }
2505 }
0b190b0f 2506 }
28a77bc4 2507
3cf883a2
VZ
2508 // we're supposed to always find something
2509 wxASSERT_MSG(editor, wxT("Missing default cell editor"));
2510
28a77bc4 2511 return editor;
07296f0b
RD
2512}
2513
b99be8fb 2514// ----------------------------------------------------------------------------
758cbedf 2515// wxGridCellAttrData
b99be8fb
VZ
2516// ----------------------------------------------------------------------------
2517
758cbedf 2518void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
b99be8fb
VZ
2519{
2520 int n = FindIndex(row, col);
2521 if ( n == wxNOT_FOUND )
2522 {
2523 // add the attribute
2524 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
2525 }
2526 else
2527 {
6f36917b
VZ
2528 // free the old attribute
2529 m_attrs[(size_t)n].attr->DecRef();
2530
b99be8fb
VZ
2531 if ( attr )
2532 {
2533 // change the attribute
2e9a6788 2534 m_attrs[(size_t)n].attr = attr;
b99be8fb
VZ
2535 }
2536 else
2537 {
2538 // remove this attribute
2539 m_attrs.RemoveAt((size_t)n);
2540 }
2541 }
b99be8fb
VZ
2542}
2543
758cbedf 2544wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
b99be8fb
VZ
2545{
2546 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2547
2548 int n = FindIndex(row, col);
2549 if ( n != wxNOT_FOUND )
2550 {
2e9a6788
VZ
2551 attr = m_attrs[(size_t)n].attr;
2552 attr->IncRef();
b99be8fb
VZ
2553 }
2554
2555 return attr;
2556}
2557
4d60017a
SN
2558void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
2559{
2560 size_t count = m_attrs.GetCount();
2561 for ( size_t n = 0; n < count; n++ )
2562 {
2563 wxGridCellCoords& coords = m_attrs[n].coords;
d1c0b4f9
VZ
2564 wxCoord row = coords.GetRow();
2565 if ((size_t)row >= pos)
2566 {
2567 if (numRows > 0)
2568 {
2569 // If rows inserted, include row counter where necessary
2570 coords.SetRow(row + numRows);
2571 }
2572 else if (numRows < 0)
2573 {
2574 // If rows deleted ...
2575 if ((size_t)row >= pos - numRows)
2576 {
2577 // ...either decrement row counter (if row still exists)...
2578 coords.SetRow(row + numRows);
2579 }
2580 else
2581 {
2582 // ...or remove the attribute
d3e9dd94
SN
2583 // No need to DecRef the attribute itself since this is
2584 // done be wxGridCellWithAttr's destructor!
01dd42b6 2585 m_attrs.RemoveAt(n);
4db6714b
KH
2586 n--;
2587 count--;
d1c0b4f9
VZ
2588 }
2589 }
4d60017a
SN
2590 }
2591 }
2592}
2593
2594void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
2595{
2596 size_t count = m_attrs.GetCount();
2597 for ( size_t n = 0; n < count; n++ )
2598 {
2599 wxGridCellCoords& coords = m_attrs[n].coords;
d1c0b4f9
VZ
2600 wxCoord col = coords.GetCol();
2601 if ( (size_t)col >= pos )
2602 {
2603 if ( numCols > 0 )
2604 {
2605 // If rows inserted, include row counter where necessary
2606 coords.SetCol(col + numCols);
2607 }
2608 else if (numCols < 0)
2609 {
2610 // If rows deleted ...
2611 if ((size_t)col >= pos - numCols)
2612 {
2613 // ...either decrement row counter (if row still exists)...
2614 coords.SetCol(col + numCols);
2615 }
2616 else
2617 {
2618 // ...or remove the attribute
d3e9dd94
SN
2619 // No need to DecRef the attribute itself since this is
2620 // done be wxGridCellWithAttr's destructor!
01dd42b6 2621 m_attrs.RemoveAt(n);
2f024384
DS
2622 n--;
2623 count--;
d1c0b4f9
VZ
2624 }
2625 }
4d60017a
SN
2626 }
2627 }
2628}
2629
758cbedf 2630int wxGridCellAttrData::FindIndex(int row, int col) const
b99be8fb
VZ
2631{
2632 size_t count = m_attrs.GetCount();
2633 for ( size_t n = 0; n < count; n++ )
2634 {
2635 const wxGridCellCoords& coords = m_attrs[n].coords;
2636 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
2637 {
2638 return n;
2639 }
2640 }
2641
2642 return wxNOT_FOUND;
2643}
2644
758cbedf
VZ
2645// ----------------------------------------------------------------------------
2646// wxGridRowOrColAttrData
2647// ----------------------------------------------------------------------------
2648
2649wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
2650{
2651 size_t count = m_attrs.Count();
2652 for ( size_t n = 0; n < count; n++ )
2653 {
2654 m_attrs[n]->DecRef();
2655 }
2656}
2657
2658wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
2659{
2660 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2661
2662 int n = m_rowsOrCols.Index(rowOrCol);
2663 if ( n != wxNOT_FOUND )
2664 {
2665 attr = m_attrs[(size_t)n];
2666 attr->IncRef();
2667 }
2668
2669 return attr;
2670}
2671
2672void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
2673{
a95e38c0
VZ
2674 int i = m_rowsOrCols.Index(rowOrCol);
2675 if ( i == wxNOT_FOUND )
758cbedf
VZ
2676 {
2677 // add the attribute
2678 m_rowsOrCols.Add(rowOrCol);
2679 m_attrs.Add(attr);
2680 }
2681 else
2682 {
a95e38c0 2683 size_t n = (size_t)i;
758cbedf
VZ
2684 if ( attr )
2685 {
2686 // change the attribute
a95e38c0
VZ
2687 m_attrs[n]->DecRef();
2688 m_attrs[n] = attr;
758cbedf
VZ
2689 }
2690 else
2691 {
2692 // remove this attribute
a95e38c0
VZ
2693 m_attrs[n]->DecRef();
2694 m_rowsOrCols.RemoveAt(n);
2695 m_attrs.RemoveAt(n);
758cbedf
VZ
2696 }
2697 }
2698}
2699
4d60017a
SN
2700void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
2701{
2702 size_t count = m_attrs.GetCount();
2703 for ( size_t n = 0; n < count; n++ )
2704 {
2705 int & rowOrCol = m_rowsOrCols[n];
d1c0b4f9
VZ
2706 if ( (size_t)rowOrCol >= pos )
2707 {
2708 if ( numRowsOrCols > 0 )
2709 {
2710 // If rows inserted, include row counter where necessary
2711 rowOrCol += numRowsOrCols;
2712 }
2713 else if ( numRowsOrCols < 0)
2714 {
2715 // If rows deleted, either decrement row counter (if row still exists)
2716 if ((size_t)rowOrCol >= pos - numRowsOrCols)
2717 rowOrCol += numRowsOrCols;
2718 else
2719 {
01dd42b6
VZ
2720 m_rowsOrCols.RemoveAt(n);
2721 m_attrs[n]->DecRef();
2722 m_attrs.RemoveAt(n);
4db6714b
KH
2723 n--;
2724 count--;
d1c0b4f9
VZ
2725 }
2726 }
4d60017a
SN
2727 }
2728 }
2729}
2730
b99be8fb
VZ
2731// ----------------------------------------------------------------------------
2732// wxGridCellAttrProvider
2733// ----------------------------------------------------------------------------
2734
2735wxGridCellAttrProvider::wxGridCellAttrProvider()
2736{
2737 m_data = (wxGridCellAttrProviderData *)NULL;
2738}
2739
2740wxGridCellAttrProvider::~wxGridCellAttrProvider()
2741{
2742 delete m_data;
2743}
2744
2745void wxGridCellAttrProvider::InitData()
2746{
2747 m_data = new wxGridCellAttrProviderData;
2748}
2749
19d7140e
VZ
2750wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col,
2751 wxGridCellAttr::wxAttrKind kind ) const
b99be8fb 2752{
758cbedf
VZ
2753 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2754 if ( m_data )
2755 {
962a48f6 2756 switch (kind)
758cbedf 2757 {
19d7140e 2758 case (wxGridCellAttr::Any):
962a48f6
DS
2759 // Get cached merge attributes.
2760 // Currently not used as no cache implemented as not mutable
19d7140e 2761 // attr = m_data->m_mergeAttr.GetAttr(row, col);
4db6714b 2762 if (!attr)
19d7140e 2763 {
962a48f6
DS
2764 // Basically implement old version.
2765 // Also check merge cache, so we don't have to re-merge every time..
999836aa
VZ
2766 wxGridCellAttr *attrcell = m_data->m_cellAttrs.GetAttr(row, col);
2767 wxGridCellAttr *attrrow = m_data->m_rowAttrs.GetAttr(row);
2768 wxGridCellAttr *attrcol = m_data->m_colAttrs.GetAttr(col);
19d7140e 2769
4db6714b
KH
2770 if ((attrcell != attrrow) && (attrrow != attrcol) && (attrcell != attrcol))
2771 {
2d0c2e79 2772 // Two or more are non NULL
19d7140e
VZ
2773 attr = new wxGridCellAttr;
2774 attr->SetKind(wxGridCellAttr::Merged);
2775
962a48f6 2776 // Order is important..
4db6714b
KH
2777 if (attrcell)
2778 {
19d7140e
VZ
2779 attr->MergeWith(attrcell);
2780 attrcell->DecRef();
2781 }
4db6714b
KH
2782 if (attrcol)
2783 {
19d7140e
VZ
2784 attr->MergeWith(attrcol);
2785 attrcol->DecRef();
2786 }
4db6714b
KH
2787 if (attrrow)
2788 {
19d7140e
VZ
2789 attr->MergeWith(attrrow);
2790 attrrow->DecRef();
2791 }
962a48f6
DS
2792
2793 // store merge attr if cache implemented
19d7140e
VZ
2794 //attr->IncRef();
2795 //m_data->m_mergeAttr.SetAttr(attr, row, col);
2796 }
2797 else
2d0c2e79 2798 {
19d7140e 2799 // one or none is non null return it or null.
4db6714b
KH
2800 if (attrrow)
2801 attr = attrrow;
2802 if (attrcol)
2d0c2e79 2803 {
962a48f6 2804 if (attr)
2d0c2e79
RD
2805 attr->DecRef();
2806 attr = attrcol;
2807 }
4db6714b 2808 if (attrcell)
2d0c2e79 2809 {
4db6714b 2810 if (attr)
2d0c2e79
RD
2811 attr->DecRef();
2812 attr = attrcell;
2813 }
19d7140e
VZ
2814 }
2815 }
2f024384 2816 break;
4db6714b 2817
19d7140e
VZ
2818 case (wxGridCellAttr::Cell):
2819 attr = m_data->m_cellAttrs.GetAttr(row, col);
2f024384 2820 break;
4db6714b 2821
19d7140e 2822 case (wxGridCellAttr::Col):
2d0c2e79 2823 attr = m_data->m_colAttrs.GetAttr(col);
2f024384 2824 break;
4db6714b 2825
19d7140e 2826 case (wxGridCellAttr::Row):
2d0c2e79 2827 attr = m_data->m_rowAttrs.GetAttr(row);
2f024384 2828 break;
4db6714b 2829
19d7140e
VZ
2830 default:
2831 // unused as yet...
2832 // (wxGridCellAttr::Default):
2833 // (wxGridCellAttr::Merged):
2f024384 2834 break;
758cbedf
VZ
2835 }
2836 }
2f024384 2837
758cbedf 2838 return attr;
b99be8fb
VZ
2839}
2840
2e9a6788 2841void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
b99be8fb
VZ
2842 int row, int col)
2843{
2844 if ( !m_data )
2845 InitData();
2846
758cbedf
VZ
2847 m_data->m_cellAttrs.SetAttr(attr, row, col);
2848}
2849
2850void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
2851{
2852 if ( !m_data )
2853 InitData();
2854
2855 m_data->m_rowAttrs.SetAttr(attr, row);
2856}
2857
2858void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
2859{
2860 if ( !m_data )
2861 InitData();
2862
2863 m_data->m_colAttrs.SetAttr(attr, col);
b99be8fb
VZ
2864}
2865
4d60017a
SN
2866void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
2867{
2868 if ( m_data )
2869 {
2870 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
2871
d1c0b4f9 2872 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
4d60017a
SN
2873 }
2874}
2875
2876void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
2877{
2878 if ( m_data )
2879 {
2880 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
2881
d1c0b4f9 2882 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
4d60017a
SN
2883 }
2884}
2885
f2d76237
RD
2886// ----------------------------------------------------------------------------
2887// wxGridTypeRegistry
2888// ----------------------------------------------------------------------------
2889
2890wxGridTypeRegistry::~wxGridTypeRegistry()
2891{
b94ae1ea
VZ
2892 size_t count = m_typeinfo.Count();
2893 for ( size_t i = 0; i < count; i++ )
f2d76237
RD
2894 delete m_typeinfo[i];
2895}
2896
f2d76237
RD
2897void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
2898 wxGridCellRenderer* renderer,
2899 wxGridCellEditor* editor)
2900{
f2d76237
RD
2901 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
2902
2903 // is it already registered?
c4608a8a 2904 int loc = FindRegisteredDataType(typeName);
39bcce60
VZ
2905 if ( loc != wxNOT_FOUND )
2906 {
f2d76237
RD
2907 delete m_typeinfo[loc];
2908 m_typeinfo[loc] = info;
2909 }
39bcce60
VZ
2910 else
2911 {
f2d76237
RD
2912 m_typeinfo.Add(info);
2913 }
2914}
2915
c4608a8a
VZ
2916int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
2917{
2918 size_t count = m_typeinfo.GetCount();
2919 for ( size_t i = 0; i < count; i++ )
2920 {
2921 if ( typeName == m_typeinfo[i]->m_typeName )
2922 {
2923 return i;
2924 }
2925 }
2926
2927 return wxNOT_FOUND;
2928}
2929
f2d76237
RD
2930int wxGridTypeRegistry::FindDataType(const wxString& typeName)
2931{
c4608a8a
VZ
2932 int index = FindRegisteredDataType(typeName);
2933 if ( index == wxNOT_FOUND )
2934 {
2935 // check whether this is one of the standard ones, in which case
2936 // register it "on the fly"
3a8c693a 2937#if wxUSE_TEXTCTRL
c4608a8a
VZ
2938 if ( typeName == wxGRID_VALUE_STRING )
2939 {
2940 RegisterDataType(wxGRID_VALUE_STRING,
2941 new wxGridCellStringRenderer,
2942 new wxGridCellTextEditor);
4db6714b
KH
2943 }
2944 else
3a8c693a
VZ
2945#endif // wxUSE_TEXTCTRL
2946#if wxUSE_CHECKBOX
2947 if ( typeName == wxGRID_VALUE_BOOL )
c4608a8a
VZ
2948 {
2949 RegisterDataType(wxGRID_VALUE_BOOL,
2950 new wxGridCellBoolRenderer,
2951 new wxGridCellBoolEditor);
4db6714b
KH
2952 }
2953 else
3a8c693a
VZ
2954#endif // wxUSE_CHECKBOX
2955#if wxUSE_TEXTCTRL
2956 if ( typeName == wxGRID_VALUE_NUMBER )
c4608a8a
VZ
2957 {
2958 RegisterDataType(wxGRID_VALUE_NUMBER,
2959 new wxGridCellNumberRenderer,
2960 new wxGridCellNumberEditor);
2961 }
2962 else if ( typeName == wxGRID_VALUE_FLOAT )
2963 {
2964 RegisterDataType(wxGRID_VALUE_FLOAT,
2965 new wxGridCellFloatRenderer,
2966 new wxGridCellFloatEditor);
4db6714b
KH
2967 }
2968 else
3a8c693a
VZ
2969#endif // wxUSE_TEXTCTRL
2970#if wxUSE_COMBOBOX
2971 if ( typeName == wxGRID_VALUE_CHOICE )
c4608a8a
VZ
2972 {
2973 RegisterDataType(wxGRID_VALUE_CHOICE,
2974 new wxGridCellStringRenderer,
2975 new wxGridCellChoiceEditor);
4db6714b
KH
2976 }
2977 else
3a8c693a 2978#endif // wxUSE_COMBOBOX
c4608a8a
VZ
2979 {
2980 return wxNOT_FOUND;
2981 }
f2d76237 2982
c4608a8a
VZ
2983 // we get here only if just added the entry for this type, so return
2984 // the last index
2985 index = m_typeinfo.GetCount() - 1;
2986 }
2987
2988 return index;
2989}
2990
2991int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
2992{
2993 int index = FindDataType(typeName);
2994 if ( index == wxNOT_FOUND )
2995 {
2996 // the first part of the typename is the "real" type, anything after ':'
2997 // are the parameters for the renderer
2998 index = FindDataType(typeName.BeforeFirst(_T(':')));
2999 if ( index == wxNOT_FOUND )
3000 {
3001 return wxNOT_FOUND;
f2d76237 3002 }
c4608a8a
VZ
3003
3004 wxGridCellRenderer *renderer = GetRenderer(index);
3005 wxGridCellRenderer *rendererOld = renderer;
3006 renderer = renderer->Clone();
3007 rendererOld->DecRef();
3008
3009 wxGridCellEditor *editor = GetEditor(index);
3010 wxGridCellEditor *editorOld = editor;
3011 editor = editor->Clone();
3012 editorOld->DecRef();
3013
3014 // do it even if there are no parameters to reset them to defaults
3015 wxString params = typeName.AfterFirst(_T(':'));
3016 renderer->SetParameters(params);
3017 editor->SetParameters(params);
3018
3019 // register the new typename
c4608a8a
VZ
3020 RegisterDataType(typeName, renderer, editor);
3021
3022 // we just registered it, it's the last one
3023 index = m_typeinfo.GetCount() - 1;
f2d76237
RD
3024 }
3025
c4608a8a 3026 return index;
f2d76237
RD
3027}
3028
3029wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
3030{
3031 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
faec5a43
SN
3032 if (renderer)
3033 renderer->IncRef();
2f024384 3034
f2d76237
RD
3035 return renderer;
3036}
3037
0b190b0f 3038wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
f2d76237
RD
3039{
3040 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
faec5a43
SN
3041 if (editor)
3042 editor->IncRef();
2f024384 3043
f2d76237
RD
3044 return editor;
3045}
3046
758cbedf
VZ
3047// ----------------------------------------------------------------------------
3048// wxGridTableBase
3049// ----------------------------------------------------------------------------
3050
f85afd4e
MB
3051IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
3052
f85afd4e 3053wxGridTableBase::wxGridTableBase()
f85afd4e
MB
3054{
3055 m_view = (wxGrid *) NULL;
b99be8fb 3056 m_attrProvider = (wxGridCellAttrProvider *) NULL;
f85afd4e
MB
3057}
3058
3059wxGridTableBase::~wxGridTableBase()
3060{
b99be8fb
VZ
3061 delete m_attrProvider;
3062}
3063
3064void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
3065{
3066 delete m_attrProvider;
3067 m_attrProvider = attrProvider;
f85afd4e
MB
3068}
3069
f2d76237
RD
3070bool wxGridTableBase::CanHaveAttributes()
3071{
3072 if ( ! GetAttrProvider() )
3073 {
3074 // use the default attr provider by default
3075 SetAttrProvider(new wxGridCellAttrProvider);
3076 }
2f024384 3077
ca65c044 3078 return true;
f2d76237
RD
3079}
3080
19d7140e 3081wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
b99be8fb
VZ
3082{
3083 if ( m_attrProvider )
19d7140e 3084 return m_attrProvider->GetAttr(row, col, kind);
b99be8fb
VZ
3085 else
3086 return (wxGridCellAttr *)NULL;
3087}
3088
758cbedf 3089void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
b99be8fb
VZ
3090{
3091 if ( m_attrProvider )
3092 {
19d7140e 3093 attr->SetKind(wxGridCellAttr::Cell);
b99be8fb
VZ
3094 m_attrProvider->SetAttr(attr, row, col);
3095 }
3096 else
3097 {
3098 // as we take ownership of the pointer and don't store it, we must
3099 // free it now
39bcce60 3100 wxSafeDecRef(attr);
b99be8fb
VZ
3101 }
3102}
3103
758cbedf
VZ
3104void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
3105{
3106 if ( m_attrProvider )
3107 {
19d7140e 3108 attr->SetKind(wxGridCellAttr::Row);
758cbedf
VZ
3109 m_attrProvider->SetRowAttr(attr, row);
3110 }
3111 else
3112 {
3113 // as we take ownership of the pointer and don't store it, we must
3114 // free it now
39bcce60 3115 wxSafeDecRef(attr);
758cbedf
VZ
3116 }
3117}
3118
3119void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
3120{
3121 if ( m_attrProvider )
3122 {
19d7140e 3123 attr->SetKind(wxGridCellAttr::Col);
758cbedf
VZ
3124 m_attrProvider->SetColAttr(attr, col);
3125 }
3126 else
3127 {
3128 // as we take ownership of the pointer and don't store it, we must
3129 // free it now
39bcce60 3130 wxSafeDecRef(attr);
758cbedf
VZ
3131 }
3132}
3133
aa5e1f75
SN
3134bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
3135 size_t WXUNUSED(numRows) )
f85afd4e 3136{
f6bcfd97 3137 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
8f177c8e 3138
ca65c044 3139 return false;
f85afd4e
MB
3140}
3141
aa5e1f75 3142bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
f85afd4e 3143{
f6bcfd97 3144 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
8f177c8e 3145
ca65c044 3146 return false;
f85afd4e
MB
3147}
3148
aa5e1f75
SN
3149bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
3150 size_t WXUNUSED(numRows) )
f85afd4e 3151{
f6bcfd97 3152 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
8f177c8e 3153
ca65c044 3154 return false;
f85afd4e
MB
3155}
3156
aa5e1f75
SN
3157bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
3158 size_t WXUNUSED(numCols) )
f85afd4e 3159{
f6bcfd97 3160 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
8f177c8e 3161
ca65c044 3162 return false;
f85afd4e
MB
3163}
3164
aa5e1f75 3165bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
f85afd4e 3166{
f6bcfd97 3167 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
8f177c8e 3168
ca65c044 3169 return false;
f85afd4e
MB
3170}
3171
aa5e1f75
SN
3172bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
3173 size_t WXUNUSED(numCols) )
f85afd4e 3174{
f6bcfd97 3175 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
8f177c8e 3176
ca65c044 3177 return false;
f85afd4e
MB
3178}
3179
f85afd4e
MB
3180wxString wxGridTableBase::GetRowLabelValue( int row )
3181{
3182 wxString s;
2f024384
DS
3183
3184 // RD: Starting the rows at zero confuses users,
3185 // no matter how much it makes sense to us geeks.
3186 s << row + 1;
3187
f85afd4e
MB
3188 return s;
3189}
3190
3191wxString wxGridTableBase::GetColLabelValue( int col )
3192{
3193 // default col labels are:
3194 // cols 0 to 25 : A-Z
3195 // cols 26 to 675 : AA-ZZ
3196 // etc.
3197
3198 wxString s;
3199 unsigned int i, n;
3200 for ( n = 1; ; n++ )
3201 {
2f024384
DS
3202 s += (wxChar) (_T('A') + (wxChar)(col % 26));
3203 col = col / 26 - 1;
4db6714b
KH
3204 if ( col < 0 )
3205 break;
f85afd4e
MB
3206 }
3207
3208 // reverse the string...
3209 wxString s2;
3210 for ( i = 0; i < n; i++ )
3211 {
2f024384 3212 s2 += s[n - i - 1];
f85afd4e
MB
3213 }
3214
3215 return s2;
3216}
3217
f2d76237
RD
3218wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
3219{
816be743 3220 return wxGRID_VALUE_STRING;
f2d76237
RD
3221}
3222
3223bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
3224 const wxString& typeName )
3225{
816be743 3226 return typeName == wxGRID_VALUE_STRING;
f2d76237
RD
3227}
3228
3229bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
3230{
3231 return CanGetValueAs(row, col, typeName);
3232}
3233
3234long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
3235{
3236 return 0;
3237}
3238
3239double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
3240{
3241 return 0.0;
3242}
3243
3244bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
3245{
ca65c044 3246 return false;
f2d76237
RD
3247}
3248
3249void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
3250 long WXUNUSED(value) )
3251{
3252}
3253
3254void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
3255 double WXUNUSED(value) )
3256{
3257}
3258
3259void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
3260 bool WXUNUSED(value) )
3261{
3262}
3263
f2d76237
RD
3264void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3265 const wxString& WXUNUSED(typeName) )
3266{
3267 return NULL;
3268}
3269
3270void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3271 const wxString& WXUNUSED(typeName),
3272 void* WXUNUSED(value) )
3273{
3274}
3275
f85afd4e
MB
3276//////////////////////////////////////////////////////////////////////
3277//
3278// Message class for the grid table to send requests and notifications
3279// to the grid view
3280//
3281
3282wxGridTableMessage::wxGridTableMessage()
3283{
3284 m_table = (wxGridTableBase *) NULL;
3285 m_id = -1;
3286 m_comInt1 = -1;
3287 m_comInt2 = -1;
3288}
3289
3290wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
3291 int commandInt1, int commandInt2 )
3292{
3293 m_table = table;
3294 m_id = id;
3295 m_comInt1 = commandInt1;
3296 m_comInt2 = commandInt2;
3297}
3298
f85afd4e
MB
3299//////////////////////////////////////////////////////////////////////
3300//
3301// A basic grid table for string data. An object of this class will
3302// created by wxGrid if you don't specify an alternative table class.
3303//
3304
223d09f6 3305WX_DEFINE_OBJARRAY(wxGridStringArray)
f85afd4e
MB
3306
3307IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
3308
3309wxGridStringTable::wxGridStringTable()
3310 : wxGridTableBase()
3311{
3312}
3313
3314wxGridStringTable::wxGridStringTable( int numRows, int numCols )
3315 : wxGridTableBase()
3316{
f85afd4e
MB
3317 m_data.Alloc( numRows );
3318
3319 wxArrayString sa;
3320 sa.Alloc( numCols );
27f35b66 3321 sa.Add( wxEmptyString, numCols );
8f177c8e 3322
27f35b66 3323 m_data.Add( sa, numRows );
f85afd4e
MB
3324}
3325
3326wxGridStringTable::~wxGridStringTable()
3327{
3328}
3329
e32352cf 3330int wxGridStringTable::GetNumberRows()
f85afd4e
MB
3331{
3332 return m_data.GetCount();
3333}
3334
e32352cf 3335int wxGridStringTable::GetNumberCols()
f85afd4e
MB
3336{
3337 if ( m_data.GetCount() > 0 )
3338 return m_data[0].GetCount();
3339 else
3340 return 0;
3341}
3342
3343wxString wxGridStringTable::GetValue( int row, int col )
3344{
3e13956a
RD
3345 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3346 wxEmptyString,
3347 _T("invalid row or column index in wxGridStringTable") );
af547d51 3348
f85afd4e
MB
3349 return m_data[row][col];
3350}
3351
f2d76237 3352void wxGridStringTable::SetValue( int row, int col, const wxString& value )
f85afd4e 3353{
3e13956a
RD
3354 wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()),
3355 _T("invalid row or column index in wxGridStringTable") );
af547d51 3356
f2d76237 3357 m_data[row][col] = value;
f85afd4e
MB
3358}
3359
3360bool wxGridStringTable::IsEmptyCell( int row, int col )
3361{
3e13956a
RD
3362 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3363 true,
af547d51
VZ
3364 _T("invalid row or column index in wxGridStringTable") );
3365
f85afd4e
MB
3366 return (m_data[row][col] == wxEmptyString);
3367}
3368
f85afd4e
MB
3369void wxGridStringTable::Clear()
3370{
3371 int row, col;
3372 int numRows, numCols;
8f177c8e 3373
f85afd4e
MB
3374 numRows = m_data.GetCount();
3375 if ( numRows > 0 )
3376 {
3377 numCols = m_data[0].GetCount();
3378
3379 for ( row = 0; row < numRows; row++ )
3380 {
3381 for ( col = 0; col < numCols; col++ )
3382 {
3383 m_data[row][col] = wxEmptyString;
3384 }
3385 }
3386 }
3387}
3388
f85afd4e
MB
3389bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
3390{
f85afd4e 3391 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
3392 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3393 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3394
f85afd4e
MB
3395 if ( pos >= curNumRows )
3396 {
3397 return AppendRows( numRows );
3398 }
8f177c8e 3399
f85afd4e
MB
3400 wxArrayString sa;
3401 sa.Alloc( curNumCols );
27f35b66
SN
3402 sa.Add( wxEmptyString, curNumCols );
3403 m_data.Insert( sa, pos, numRows );
2f024384 3404
f85afd4e
MB
3405 if ( GetView() )
3406 {
3407 wxGridTableMessage msg( this,
3408 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
3409 pos,
3410 numRows );
8f177c8e 3411
f85afd4e
MB
3412 GetView()->ProcessTableMessage( msg );
3413 }
3414
ca65c044 3415 return true;
f85afd4e
MB
3416}
3417
3418bool wxGridStringTable::AppendRows( size_t numRows )
3419{
f85afd4e 3420 size_t curNumRows = m_data.GetCount();
4db6714b
KH
3421 size_t curNumCols = ( curNumRows > 0
3422 ? m_data[0].GetCount()
3423 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3424
f85afd4e
MB
3425 wxArrayString sa;
3426 if ( curNumCols > 0 )
3427 {
3428 sa.Alloc( curNumCols );
27f35b66 3429 sa.Add( wxEmptyString, curNumCols );
f85afd4e 3430 }
8f177c8e 3431
27f35b66 3432 m_data.Add( sa, numRows );
f85afd4e
MB
3433
3434 if ( GetView() )
3435 {
3436 wxGridTableMessage msg( this,
3437 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
3438 numRows );
8f177c8e 3439
f85afd4e
MB
3440 GetView()->ProcessTableMessage( msg );
3441 }
3442
ca65c044 3443 return true;
f85afd4e
MB
3444}
3445
3446bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
3447{
f85afd4e 3448 size_t curNumRows = m_data.GetCount();
8f177c8e 3449
f85afd4e
MB
3450 if ( pos >= curNumRows )
3451 {
e91d2033
VZ
3452 wxFAIL_MSG( wxString::Format
3453 (
3454 wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
3455 (unsigned long)pos,
3456 (unsigned long)numRows,
3457 (unsigned long)curNumRows
3458 ) );
3459
ca65c044 3460 return false;
f85afd4e
MB
3461 }
3462
3463 if ( numRows > curNumRows - pos )
3464 {
3465 numRows = curNumRows - pos;
3466 }
8f177c8e 3467
f85afd4e
MB
3468 if ( numRows >= curNumRows )
3469 {
d57ad377 3470 m_data.Clear();
f85afd4e
MB
3471 }
3472 else
3473 {
27f35b66 3474 m_data.RemoveAt( pos, numRows );
f85afd4e 3475 }
4db6714b 3476
f85afd4e
MB
3477 if ( GetView() )
3478 {
3479 wxGridTableMessage msg( this,
3480 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
3481 pos,
3482 numRows );
8f177c8e 3483
f85afd4e
MB
3484 GetView()->ProcessTableMessage( msg );
3485 }
3486
ca65c044 3487 return true;
f85afd4e
MB
3488}
3489
3490bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
3491{
3492 size_t row, col;
3493
3494 size_t curNumRows = m_data.GetCount();
4db6714b
KH
3495 size_t curNumCols = ( curNumRows > 0
3496 ? m_data[0].GetCount()
3497 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3498
f85afd4e
MB
3499 if ( pos >= curNumCols )
3500 {
3501 return AppendCols( numCols );
3502 }
3503
3504 for ( row = 0; row < curNumRows; row++ )
3505 {
3506 for ( col = pos; col < pos + numCols; col++ )
3507 {
3508 m_data[row].Insert( wxEmptyString, col );
3509 }
3510 }
4db6714b 3511
f85afd4e
MB
3512 if ( GetView() )
3513 {
3514 wxGridTableMessage msg( this,
3515 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
3516 pos,
3517 numCols );
8f177c8e 3518
f85afd4e
MB
3519 GetView()->ProcessTableMessage( msg );
3520 }
3521
ca65c044 3522 return true;
f85afd4e
MB
3523}
3524
3525bool wxGridStringTable::AppendCols( size_t numCols )
3526{
27f35b66 3527 size_t row;
f85afd4e
MB
3528
3529 size_t curNumRows = m_data.GetCount();
2f024384 3530
f6bcfd97 3531#if 0
f85afd4e
MB
3532 if ( !curNumRows )
3533 {
3534 // TODO: something better than this ?
3535 //
f6bcfd97 3536 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
ca65c044 3537 return false;
f85afd4e 3538 }
f6bcfd97 3539#endif
8f177c8e 3540
f85afd4e
MB
3541 for ( row = 0; row < curNumRows; row++ )
3542 {
27f35b66 3543 m_data[row].Add( wxEmptyString, numCols );
f85afd4e
MB
3544 }
3545
3546 if ( GetView() )
3547 {
3548 wxGridTableMessage msg( this,
3549 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
3550 numCols );
8f177c8e 3551
f85afd4e
MB
3552 GetView()->ProcessTableMessage( msg );
3553 }
3554
ca65c044 3555 return true;
f85afd4e
MB
3556}
3557
3558bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
3559{
27f35b66 3560 size_t row;
f85afd4e
MB
3561
3562 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
3563 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3564 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3565
f85afd4e
MB
3566 if ( pos >= curNumCols )
3567 {
e91d2033
VZ
3568 wxFAIL_MSG( wxString::Format
3569 (
3570 wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
3571 (unsigned long)pos,
3572 (unsigned long)numCols,
3573 (unsigned long)curNumCols
3574 ) );
ca65c044 3575 return false;
f85afd4e
MB
3576 }
3577
3578 if ( numCols > curNumCols - pos )
3579 {
8f177c8e 3580 numCols = curNumCols - pos;
f85afd4e
MB
3581 }
3582
3583 for ( row = 0; row < curNumRows; row++ )
3584 {
3585 if ( numCols >= curNumCols )
3586 {
dcdce64e 3587 m_data[row].Clear();
f85afd4e
MB
3588 }
3589 else
3590 {
27f35b66 3591 m_data[row].RemoveAt( pos, numCols );
f85afd4e
MB
3592 }
3593 }
4db6714b 3594
f85afd4e
MB
3595 if ( GetView() )
3596 {
3597 wxGridTableMessage msg( this,
3598 wxGRIDTABLE_NOTIFY_COLS_DELETED,
3599 pos,
3600 numCols );
8f177c8e 3601
f85afd4e
MB
3602 GetView()->ProcessTableMessage( msg );
3603 }
3604
ca65c044 3605 return true;
f85afd4e
MB
3606}
3607
3608wxString wxGridStringTable::GetRowLabelValue( int row )
3609{
3610 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3611 {
3612 // using default label
3613 //
3614 return wxGridTableBase::GetRowLabelValue( row );
3615 }
3616 else
3617 {
2f024384 3618 return m_rowLabels[row];
f85afd4e
MB
3619 }
3620}
3621
3622wxString wxGridStringTable::GetColLabelValue( int col )
3623{
3624 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3625 {
3626 // using default label
3627 //
3628 return wxGridTableBase::GetColLabelValue( col );
3629 }
3630 else
3631 {
2f024384 3632 return m_colLabels[col];
f85afd4e
MB
3633 }
3634}
3635
3636void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
3637{
3638 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3639 {
3640 int n = m_rowLabels.GetCount();
3641 int i;
2f024384 3642
f85afd4e
MB
3643 for ( i = n; i <= row; i++ )
3644 {
3645 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
3646 }
3647 }
3648
3649 m_rowLabels[row] = value;
3650}
3651
3652void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
3653{
3654 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3655 {
3656 int n = m_colLabels.GetCount();
3657 int i;
2f024384 3658
f85afd4e
MB
3659 for ( i = n; i <= col; i++ )
3660 {
3661 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
3662 }
3663 }
3664
3665 m_colLabels[col] = value;
3666}
3667
3668
f85afd4e 3669//////////////////////////////////////////////////////////////////////
2d66e025
MB
3670//////////////////////////////////////////////////////////////////////
3671
3672IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
3673
3674BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
3675 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
b51c3f27 3676 EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel)
2d66e025
MB
3677 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
3678 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
f6bcfd97 3679 EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
63e2147c 3680 EVT_CHAR ( wxGridRowLabelWindow::OnChar )
2d66e025
MB
3681END_EVENT_TABLE()
3682
60ff3b99
VZ
3683wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
3684 wxWindowID id,
2d66e025 3685 const wxPoint &pos, const wxSize &size )
73bb6776 3686 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
2d66e025
MB
3687{
3688 m_owner = parent;
3689}
3690
aa5e1f75 3691void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2d66e025
MB
3692{
3693 wxPaintDC dc(this);
3694
3695 // NO - don't do this because it will set both the x and y origin
3696 // coords to match the parent scrolled window and we just want to
3697 // set the y coord - MB
3698 //
3699 // m_owner->PrepareDC( dc );
60ff3b99 3700
790ad94f 3701 int x, y;
2d66e025
MB
3702 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3703 dc.SetDeviceOrigin( 0, -y );
60ff3b99 3704
d10f4bf9
VZ
3705 wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
3706 m_owner->DrawRowLabels( dc , rows );
2d66e025
MB
3707}
3708
2d66e025
MB
3709void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
3710{
3711 m_owner->ProcessRowLabelMouseEvent( event );
3712}
3713
b51c3f27
RD
3714void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event )
3715{
3716 m_owner->GetEventHandler()->ProcessEvent(event);
3717}
3718
2d66e025
MB
3719// This seems to be required for wxMotif otherwise the mouse
3720// cursor must be in the cell edit control to get key events
3721//
3722void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
3723{
2f024384
DS
3724 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3725 event.Skip();
2d66e025
MB
3726}
3727
f6bcfd97
BP
3728void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
3729{
2f024384
DS
3730 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3731 event.Skip();
f6bcfd97
BP
3732}
3733
63e2147c
RD
3734void wxGridRowLabelWindow::OnChar( wxKeyEvent& event )
3735{
2f024384
DS
3736 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3737 event.Skip();
63e2147c
RD
3738}
3739
2d66e025
MB
3740//////////////////////////////////////////////////////////////////////
3741
3742IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
3743
3744BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
3745 EVT_PAINT( wxGridColLabelWindow::OnPaint )
b51c3f27 3746 EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel)
2d66e025
MB
3747 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
3748 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
f6bcfd97 3749 EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
63e2147c 3750 EVT_CHAR ( wxGridColLabelWindow::OnChar )
2d66e025
MB
3751END_EVENT_TABLE()
3752
60ff3b99
VZ
3753wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
3754 wxWindowID id,
2d66e025 3755 const wxPoint &pos, const wxSize &size )
73bb6776 3756 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
2d66e025
MB
3757{
3758 m_owner = parent;
3759}
3760
aa5e1f75 3761void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2d66e025
MB
3762{
3763 wxPaintDC dc(this);
3764
3765 // NO - don't do this because it will set both the x and y origin
3766 // coords to match the parent scrolled window and we just want to
3767 // set the x coord - MB
3768 //
3769 // m_owner->PrepareDC( dc );
60ff3b99 3770
790ad94f 3771 int x, y;
2d66e025
MB
3772 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
3773 dc.SetDeviceOrigin( -x, 0 );
3774
d10f4bf9
VZ
3775 wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() );
3776 m_owner->DrawColLabels( dc , cols );
2d66e025
MB
3777}
3778
2d66e025
MB
3779void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
3780{
3781 m_owner->ProcessColLabelMouseEvent( event );
3782}
3783
b51c3f27
RD
3784void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event )
3785{
3786 m_owner->GetEventHandler()->ProcessEvent(event);
3787}
3788
2d66e025
MB
3789// This seems to be required for wxMotif otherwise the mouse
3790// cursor must be in the cell edit control to get key events
3791//
3792void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
3793{
4db6714b
KH
3794 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3795 event.Skip();
2d66e025
MB
3796}
3797
f6bcfd97
BP
3798void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
3799{
4db6714b
KH
3800 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3801 event.Skip();
f6bcfd97
BP
3802}
3803
63e2147c
RD
3804void wxGridColLabelWindow::OnChar( wxKeyEvent& event )
3805{
4db6714b
KH
3806 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3807 event.Skip();
63e2147c 3808}
2d66e025 3809
2d66e025
MB
3810//////////////////////////////////////////////////////////////////////
3811
3812IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
3813
3814BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
b51c3f27 3815 EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel)
2d66e025 3816 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
d2fdd8d2 3817 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
2d66e025 3818 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
f6bcfd97 3819 EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
63e2147c 3820 EVT_CHAR ( wxGridCornerLabelWindow::OnChar )
2d66e025
MB
3821END_EVENT_TABLE()
3822
60ff3b99
VZ
3823wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
3824 wxWindowID id,
2d66e025 3825 const wxPoint &pos, const wxSize &size )
73bb6776 3826 : wxWindow( parent, id, pos, size, wxWANTS_CHARS|wxBORDER_NONE|wxFULL_REPAINT_ON_RESIZE )
2d66e025
MB
3827{
3828 m_owner = parent;
3829}
3830
d2fdd8d2
RR
3831void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3832{
3833 wxPaintDC dc(this);
b99be8fb 3834
d2fdd8d2
RR
3835 int client_height = 0;
3836 int client_width = 0;
3837 GetClientSize( &client_width, &client_height );
b99be8fb 3838
11850ff3
VZ
3839 // VZ: any reason for this ifdef? (FIXME)
3840#ifdef __WXGTK__
4d1bc39c
RR
3841 wxRect rect;
3842 rect.SetX( 1 );
3843 rect.SetY( 1 );
3844 rect.SetWidth( client_width - 2 );
3845 rect.SetHeight( client_height - 2 );
ec157c8f 3846
4d1bc39c 3847 wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 );
11850ff3 3848#else // !__WXGTK__
73145b0e 3849 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW),1, wxSOLID) );
d2fdd8d2
RR
3850 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
3851 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
d2fdd8d2
RR
3852 dc.DrawLine( 0, 0, client_width, 0 );
3853 dc.DrawLine( 0, 0, 0, client_height );
73145b0e
JS
3854
3855 dc.SetPen( *wxWHITE_PEN );
3856 dc.DrawLine( 1, 1, client_width-1, 1 );
3857 dc.DrawLine( 1, 1, 1, client_height-1 );
11850ff3 3858#endif // __WXGTK__/!__WXGTK__
d2fdd8d2
RR
3859}
3860
2d66e025
MB
3861void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
3862{
3863 m_owner->ProcessCornerLabelMouseEvent( event );
3864}
3865
b51c3f27
RD
3866void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event )
3867{
3868 m_owner->GetEventHandler()->ProcessEvent(event);
3869}
3870
2d66e025
MB
3871// This seems to be required for wxMotif otherwise the mouse
3872// cursor must be in the cell edit control to get key events
3873//
3874void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
3875{
2f024384
DS
3876 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3877 event.Skip();
2d66e025
MB
3878}
3879
f6bcfd97
BP
3880void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
3881{
2f024384
DS
3882 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3883 event.Skip();
f6bcfd97
BP
3884}
3885
63e2147c
RD
3886void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event )
3887{
2f024384
DS
3888 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3889 event.Skip();
63e2147c 3890}
2d66e025 3891
f85afd4e
MB
3892//////////////////////////////////////////////////////////////////////
3893
59ddac01 3894IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
2d66e025 3895
59ddac01 3896BEGIN_EVENT_TABLE( wxGridWindow, wxWindow )
2d66e025 3897 EVT_PAINT( wxGridWindow::OnPaint )
b51c3f27 3898 EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel)
2d66e025
MB
3899 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
3900 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
f6bcfd97 3901 EVT_KEY_UP( wxGridWindow::OnKeyUp )
63e2147c 3902 EVT_CHAR ( wxGridWindow::OnChar )
80acaf25
JS
3903 EVT_SET_FOCUS( wxGridWindow::OnFocus )
3904 EVT_KILL_FOCUS( wxGridWindow::OnFocus )
2796cce3 3905 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
2d66e025
MB
3906END_EVENT_TABLE()
3907
60ff3b99
VZ
3908wxGridWindow::wxGridWindow( wxGrid *parent,
3909 wxGridRowLabelWindow *rowLblWin,
2d66e025 3910 wxGridColLabelWindow *colLblWin,
04418332
VZ
3911 wxWindowID id,
3912 const wxPoint &pos,
3913 const wxSize &size )
73bb6776 3914 : wxWindow( parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE | wxCLIP_CHILDREN|wxFULL_REPAINT_ON_RESIZE,
04418332 3915 wxT("grid window") )
2d66e025
MB
3916{
3917 m_owner = parent;
3918 m_rowLabelWin = rowLblWin;
3919 m_colLabelWin = colLblWin;
2d66e025
MB
3920}
3921
2d66e025
MB
3922void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
3923{
3924 wxPaintDC dc( this );
3925 m_owner->PrepareDC( dc );
796df70a 3926 wxRegion reg = GetUpdateRegion();
d10f4bf9
VZ
3927 wxGridCellCoordsArray DirtyCells = m_owner->CalcCellsExposed( reg );
3928 m_owner->DrawGridCellArea( dc , DirtyCells);
2f024384 3929
9496deb5 3930#if WXGRID_DRAW_LINES
796df70a
SN
3931 m_owner->DrawAllGridLines( dc, reg );
3932#endif
2f024384 3933
a5777624 3934 m_owner->DrawGridSpace( dc );
d10f4bf9 3935 m_owner->DrawHighlight( dc , DirtyCells );
2d66e025
MB
3936}
3937
2d66e025
MB
3938void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
3939{
59ddac01 3940 wxWindow::ScrollWindow( dx, dy, rect );
2d66e025
MB
3941 m_rowLabelWin->ScrollWindow( 0, dy, rect );
3942 m_colLabelWin->ScrollWindow( dx, 0, rect );
3943}
3944
2d66e025
MB
3945void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
3946{
33e9fc54
RD
3947 if (event.ButtonDown(wxMOUSE_BTN_LEFT) && FindFocus() != this)
3948 SetFocus();
902725ee 3949
2d66e025
MB
3950 m_owner->ProcessGridCellMouseEvent( event );
3951}
3952
b51c3f27
RD
3953void wxGridWindow::OnMouseWheel( wxMouseEvent& event )
3954{
3955 m_owner->GetEventHandler()->ProcessEvent(event);
3956}
2d66e025 3957
f6bcfd97 3958// This seems to be required for wxMotif/wxGTK otherwise the mouse
2d66e025
MB
3959// cursor must be in the cell edit control to get key events
3960//
3961void wxGridWindow::OnKeyDown( wxKeyEvent& event )
3962{
4db6714b
KH
3963 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3964 event.Skip();
2d66e025 3965}
f85afd4e 3966
f6bcfd97
BP
3967void wxGridWindow::OnKeyUp( wxKeyEvent& event )
3968{
4db6714b
KH
3969 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3970 event.Skip();
f6bcfd97 3971}
7c8a8ad5 3972
63e2147c
RD
3973void wxGridWindow::OnChar( wxKeyEvent& event )
3974{
4db6714b
KH
3975 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3976 event.Skip();
63e2147c
RD
3977}
3978
aa5e1f75 3979void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
8dd4f536 3980{
8dd4f536 3981}
025562fe 3982
80acaf25
JS
3983void wxGridWindow::OnFocus(wxFocusEvent& event)
3984{
3985 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3986 event.Skip();
3987}
2d66e025
MB
3988
3989//////////////////////////////////////////////////////////////////////
3990
33188aa4
SN
3991// Internal Helper function for computing row or column from some
3992// (unscrolled) coordinate value, using either
70e8d961 3993// m_defaultRowHeight/m_defaultColWidth or binary search on array
33188aa4
SN
3994// of m_rowBottoms/m_ColRights to speed up the search!
3995
3996// Internal helper macros for simpler use of that function
3997
3998static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
64e15340 3999 const wxArrayInt& BorderArray, int nMax,
a967f048 4000 bool clipToMinMax);
33188aa4
SN
4001
4002#define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \
b8d24d4e 4003 m_minAcceptableColWidth, \
ca65c044 4004 m_colRights, m_numCols, true)
33188aa4 4005#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
b8d24d4e 4006 m_minAcceptableRowHeight, \
ca65c044 4007 m_rowBottoms, m_numRows, true)
33188aa4 4008/////////////////////////////////////////////////////////////////////
07296f0b 4009
b0a877ec 4010#if wxUSE_EXTENDED_RTTI
73c36334
JS
4011WX_DEFINE_FLAGS( wxGridStyle )
4012
3ff066a4 4013wxBEGIN_FLAGS( wxGridStyle )
73c36334
JS
4014 // new style border flags, we put them first to
4015 // use them for streaming out
3ff066a4
SC
4016 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
4017 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
4018 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
4019 wxFLAGS_MEMBER(wxBORDER_RAISED)
4020 wxFLAGS_MEMBER(wxBORDER_STATIC)
4021 wxFLAGS_MEMBER(wxBORDER_NONE)
ca65c044 4022
73c36334 4023 // old style border flags
3ff066a4
SC
4024 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
4025 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
4026 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
4027 wxFLAGS_MEMBER(wxRAISED_BORDER)
4028 wxFLAGS_MEMBER(wxSTATIC_BORDER)
cb0afb26 4029 wxFLAGS_MEMBER(wxBORDER)
73c36334
JS
4030
4031 // standard window styles
3ff066a4
SC
4032 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
4033 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
4034 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
4035 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 4036 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
4037 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
4038 wxFLAGS_MEMBER(wxVSCROLL)
4039 wxFLAGS_MEMBER(wxHSCROLL)
73c36334 4040
3ff066a4 4041wxEND_FLAGS( wxGridStyle )
73c36334 4042
b0a877ec
SC
4043IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid, wxScrolledWindow,"wx/grid.h")
4044
3ff066a4
SC
4045wxBEGIN_PROPERTIES_TABLE(wxGrid)
4046 wxHIDE_PROPERTY( Children )
af498247 4047 wxPROPERTY_FLAGS( WindowStyle , wxGridStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 4048wxEND_PROPERTIES_TABLE()
b0a877ec 4049
3ff066a4
SC
4050wxBEGIN_HANDLERS_TABLE(wxGrid)
4051wxEND_HANDLERS_TABLE()
b0a877ec 4052
ca65c044 4053wxCONSTRUCTOR_5( wxGrid , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
b0a877ec
SC
4054
4055/*
2d0c2e79 4056