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