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