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