]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp
include wx/thread.h in debug build which is needed after last change
[wxWidgets.git] / src / generic / grid.cpp
CommitLineData
2796cce3 1///////////////////////////////////////////////////////////////////////////
faa94f3e 2// Name: src/generic/grid.cpp
f85afd4e
MB
3// Purpose: wxGrid and related classes
4// Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
d4175745 5// Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios
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
95427194 12// For compilers that support precompilation, includes "wx/wx.h".
4d85bcd1
JS
13#include "wx/wxprec.h"
14
f85afd4e
MB
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
27b92ca4
VZ
19#if wxUSE_GRID
20
4c44eb66
PC
21#include "wx/grid.h"
22
f85afd4e
MB
23#ifndef WX_PRECOMP
24 #include "wx/utils.h"
25 #include "wx/dcclient.h"
26 #include "wx/settings.h"
27 #include "wx/log.h"
508011ce
VZ
28 #include "wx/textctrl.h"
29 #include "wx/checkbox.h"
4ee5fc9c 30 #include "wx/combobox.h"
816be743 31 #include "wx/valtext.h"
60d876f3 32 #include "wx/intl.h"
c77a6796 33 #include "wx/math.h"
2a673eb1 34 #include "wx/listbox.h"
f85afd4e
MB
35#endif
36
cb5df486 37#include "wx/textfile.h"
816be743 38#include "wx/spinctrl.h"
c4608a8a 39#include "wx/tokenzr.h"
4d1bc39c 40#include "wx/renderer.h"
6d004f67 41
b5808881 42#include "wx/generic/gridsel.h"
07296f0b 43
4c44eb66
PC
44const wxChar wxGridNameStr[] = wxT("grid");
45
0b7e6e7d
SN
46#if defined(__WXMOTIF__)
47 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
c78b3acd 48#else
0b7e6e7d 49 #define WXUNUSED_MOTIF(identifier) identifier
c78b3acd
SN
50#endif
51
52#if defined(__WXGTK__)
53 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
54#else
55 #define WXUNUSED_GTK(identifier) identifier
56#endif
57
3f8e5072
JS
58// Required for wxIs... functions
59#include <ctype.h>
60
b99be8fb 61// ----------------------------------------------------------------------------
758cbedf 62// array classes
b99be8fb
VZ
63// ----------------------------------------------------------------------------
64
d5d29b8a 65WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr *, wxArrayAttrs,
160ba750 66 class WXDLLIMPEXP_ADV);
758cbedf 67
b99be8fb
VZ
68struct wxGridCellWithAttr
69{
2e9a6788
VZ
70 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
71 : coords(row, col), attr(attr_)
b99be8fb
VZ
72 {
73 }
74
2e9a6788
VZ
75 ~wxGridCellWithAttr()
76 {
77 attr->DecRef();
78 }
79
b99be8fb 80 wxGridCellCoords coords;
2e9a6788 81 wxGridCellAttr *attr;
22f3361e
VZ
82
83// Cannot do this:
84// DECLARE_NO_COPY_CLASS(wxGridCellWithAttr)
85// without rewriting the macros, which require a public copy constructor.
b99be8fb
VZ
86};
87
160ba750
VS
88WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr, wxGridCellWithAttrArray,
89 class WXDLLIMPEXP_ADV);
b99be8fb
VZ
90
91#include "wx/arrimpl.cpp"
92
93WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
94WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
95
0f442030
RR
96// ----------------------------------------------------------------------------
97// events
98// ----------------------------------------------------------------------------
99
2e4df4bf
VZ
100DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK)
101DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK)
102DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK)
103DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK)
79dbea21 104DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG)
2e4df4bf
VZ
105DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK)
106DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK)
107DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK)
108DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK)
109DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE)
110DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE)
d4175745 111DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE)
2e4df4bf
VZ
112DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT)
113DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE)
114DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL)
115DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN)
116DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN)
bf7945ce 117DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED)
0f442030 118
b99be8fb
VZ
119// ----------------------------------------------------------------------------
120// private classes
121// ----------------------------------------------------------------------------
122
86033c4b
VZ
123// common base class for various grid subwindows
124class WXDLLIMPEXP_ADV wxGridSubwindow : public wxWindow
b99be8fb
VZ
125{
126public:
86033c4b
VZ
127 wxGridSubwindow() { m_owner = NULL; }
128 wxGridSubwindow(wxGrid *owner,
129 wxWindowID id,
130 const wxPoint& pos,
131 const wxSize& size,
132 int additionalStyle = 0,
133 const wxString& name = wxPanelNameStr)
134 : wxWindow(owner, id, pos, size,
135 wxWANTS_CHARS | wxBORDER_NONE | additionalStyle,
136 name)
137 {
138 m_owner = owner;
139 }
140
141 wxGrid *GetOwner() { return m_owner; }
142
143protected:
144 void OnMouseCaptureLost(wxMouseCaptureLostEvent& event);
145
146 wxGrid *m_owner;
147
148 DECLARE_EVENT_TABLE()
149 DECLARE_NO_COPY_CLASS(wxGridSubwindow)
150};
151
152class WXDLLIMPEXP_ADV wxGridRowLabelWindow : public wxGridSubwindow
153{
154public:
155 wxGridRowLabelWindow() { }
b99be8fb
VZ
156 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
157 const wxPoint &pos, const wxSize &size );
158
159private:
b99be8fb
VZ
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(wxGridRowLabelWindow)
168 DECLARE_EVENT_TABLE()
22f3361e 169 DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow)
b99be8fb
VZ
170};
171
172
86033c4b 173class WXDLLIMPEXP_ADV wxGridColLabelWindow : public wxGridSubwindow
b99be8fb
VZ
174{
175public:
86033c4b 176 wxGridColLabelWindow() { }
b99be8fb
VZ
177 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
178 const wxPoint &pos, const wxSize &size );
179
180private:
a9339fe2 181 void OnPaint( wxPaintEvent& event );
b99be8fb 182 void OnMouseEvent( wxMouseEvent& event );
b51c3f27 183 void OnMouseWheel( wxMouseEvent& event );
b99be8fb 184 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 185 void OnKeyUp( wxKeyEvent& );
63e2147c 186 void OnChar( wxKeyEvent& );
b99be8fb
VZ
187
188 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
189 DECLARE_EVENT_TABLE()
22f3361e 190 DECLARE_NO_COPY_CLASS(wxGridColLabelWindow)
b99be8fb
VZ
191};
192
193
86033c4b 194class WXDLLIMPEXP_ADV wxGridCornerLabelWindow : public wxGridSubwindow
b99be8fb
VZ
195{
196public:
86033c4b 197 wxGridCornerLabelWindow() { }
b99be8fb
VZ
198 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
199 const wxPoint &pos, const wxSize &size );
200
201private:
b99be8fb 202 void OnMouseEvent( wxMouseEvent& event );
b51c3f27 203 void OnMouseWheel( wxMouseEvent& event );
b99be8fb 204 void OnKeyDown( wxKeyEvent& event );
f6bcfd97 205 void OnKeyUp( wxKeyEvent& );
63e2147c 206 void OnChar( wxKeyEvent& );
b99be8fb
VZ
207 void OnPaint( wxPaintEvent& event );
208
209 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
210 DECLARE_EVENT_TABLE()
22f3361e 211 DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow)
b99be8fb
VZ
212};
213
86033c4b 214class WXDLLIMPEXP_ADV wxGridWindow : public wxGridSubwindow
b99be8fb
VZ
215{
216public:
217 wxGridWindow()
218 {
c2f5b920
DS
219 m_rowLabelWin = NULL;
220 m_colLabelWin = NULL;
b99be8fb
VZ
221 }
222
223 wxGridWindow( wxGrid *parent,
224 wxGridRowLabelWindow *rowLblWin,
225 wxGridColLabelWindow *colLblWin,
226 wxWindowID id, const wxPoint &pos, const wxSize &size );
b99be8fb
VZ
227
228 void ScrollWindow( int dx, int dy, const wxRect *rect );
229
230private:
b99be8fb
VZ
231 wxGridRowLabelWindow *m_rowLabelWin;
232 wxGridColLabelWindow *m_colLabelWin;
233
234 void OnPaint( wxPaintEvent &event );
b51c3f27 235 void OnMouseWheel( wxMouseEvent& event );
b99be8fb
VZ
236 void OnMouseEvent( wxMouseEvent& event );
237 void OnKeyDown( wxKeyEvent& );
f6bcfd97 238 void OnKeyUp( wxKeyEvent& );
63e2147c 239 void OnChar( wxKeyEvent& );
2796cce3 240 void OnEraseBackground( wxEraseEvent& );
80acaf25 241 void OnFocus( wxFocusEvent& );
b99be8fb
VZ
242
243 DECLARE_DYNAMIC_CLASS(wxGridWindow)
244 DECLARE_EVENT_TABLE()
22f3361e 245 DECLARE_NO_COPY_CLASS(wxGridWindow)
b99be8fb
VZ
246};
247
2796cce3 248
2796cce3
RD
249class wxGridCellEditorEvtHandler : public wxEvtHandler
250{
251public:
2796cce3 252 wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
140954fd 253 : m_grid(grid),
08dd04d0
JS
254 m_editor(editor),
255 m_inSetFocus(false)
140954fd
VZ
256 {
257 }
2796cce3 258
140954fd 259 void OnKillFocus(wxFocusEvent& event);
2796cce3 260 void OnKeyDown(wxKeyEvent& event);
fb0de762 261 void OnChar(wxKeyEvent& event);
2796cce3 262
08dd04d0
JS
263 void SetInSetFocus(bool inSetFocus) { m_inSetFocus = inSetFocus; }
264
2796cce3 265private:
2f024384
DS
266 wxGrid *m_grid;
267 wxGridCellEditor *m_editor;
140954fd 268
08dd04d0
JS
269 // Work around the fact that a focus kill event can be sent to
270 // a combobox within a set focus event.
271 bool m_inSetFocus;
7448de8d 272
2796cce3 273 DECLARE_EVENT_TABLE()
140954fd 274 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
22f3361e 275 DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler)
2796cce3
RD
276};
277
278
140954fd
VZ
279IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler, wxEvtHandler)
280
2796cce3 281BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
140954fd 282 EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus )
2796cce3 283 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
fb0de762 284 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
2796cce3
RD
285END_EVENT_TABLE()
286
287
758cbedf 288// ----------------------------------------------------------------------------
b99be8fb 289// the internal data representation used by wxGridCellAttrProvider
758cbedf
VZ
290// ----------------------------------------------------------------------------
291
292// this class stores attributes set for cells
12f190b0 293class WXDLLIMPEXP_ADV wxGridCellAttrData
b99be8fb
VZ
294{
295public:
2e9a6788 296 void SetAttr(wxGridCellAttr *attr, int row, int col);
b99be8fb 297 wxGridCellAttr *GetAttr(int row, int col) const;
4d60017a
SN
298 void UpdateAttrRows( size_t pos, int numRows );
299 void UpdateAttrCols( size_t pos, int numCols );
b99be8fb
VZ
300
301private:
302 // searches for the attr for given cell, returns wxNOT_FOUND if not found
303 int FindIndex(int row, int col) const;
304
305 wxGridCellWithAttrArray m_attrs;
306};
307
758cbedf 308// this class stores attributes set for rows or columns
12f190b0 309class WXDLLIMPEXP_ADV wxGridRowOrColAttrData
758cbedf
VZ
310{
311public:
ee6694a7 312 // empty ctor to suppress warnings
2f024384 313 wxGridRowOrColAttrData() {}
758cbedf
VZ
314 ~wxGridRowOrColAttrData();
315
316 void SetAttr(wxGridCellAttr *attr, int rowOrCol);
317 wxGridCellAttr *GetAttr(int rowOrCol) const;
4d60017a 318 void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
758cbedf
VZ
319
320private:
321 wxArrayInt m_rowsOrCols;
322 wxArrayAttrs m_attrs;
323};
324
325// NB: this is just a wrapper around 3 objects: one which stores cell
326// attributes, and 2 others for row/col ones
12f190b0 327class WXDLLIMPEXP_ADV wxGridCellAttrProviderData
758cbedf
VZ
328{
329public:
330 wxGridCellAttrData m_cellAttrs;
331 wxGridRowOrColAttrData m_rowAttrs,
332 m_colAttrs;
333};
334
f2d76237
RD
335
336// ----------------------------------------------------------------------------
337// data structures used for the data type registry
338// ----------------------------------------------------------------------------
339
b94ae1ea
VZ
340struct wxGridDataTypeInfo
341{
f2d76237
RD
342 wxGridDataTypeInfo(const wxString& typeName,
343 wxGridCellRenderer* renderer,
344 wxGridCellEditor* editor)
345 : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
2f024384 346 {}
f2d76237 347
39bcce60
VZ
348 ~wxGridDataTypeInfo()
349 {
350 wxSafeDecRef(m_renderer);
351 wxSafeDecRef(m_editor);
352 }
f2d76237
RD
353
354 wxString m_typeName;
355 wxGridCellRenderer* m_renderer;
356 wxGridCellEditor* m_editor;
22f3361e
VZ
357
358 DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo)
f2d76237
RD
359};
360
361
d5d29b8a 362WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo*, wxGridDataTypeInfoArray,
160ba750 363 class WXDLLIMPEXP_ADV);
f2d76237
RD
364
365
12f190b0 366class WXDLLIMPEXP_ADV wxGridTypeRegistry
b94ae1ea 367{
f2d76237 368public:
c78b3acd 369 wxGridTypeRegistry() {}
f2d76237 370 ~wxGridTypeRegistry();
b94ae1ea 371
f2d76237
RD
372 void RegisterDataType(const wxString& typeName,
373 wxGridCellRenderer* renderer,
374 wxGridCellEditor* editor);
c4608a8a
VZ
375
376 // find one of already registered data types
377 int FindRegisteredDataType(const wxString& typeName);
378
379 // try to FindRegisteredDataType(), if this fails and typeName is one of
380 // standard typenames, register it and return its index
f2d76237 381 int FindDataType(const wxString& typeName);
c4608a8a
VZ
382
383 // try to FindDataType(), if it fails see if it is not one of already
384 // registered data types with some params in which case clone the
385 // registered data type and set params for it
386 int FindOrCloneDataType(const wxString& typeName);
387
f2d76237
RD
388 wxGridCellRenderer* GetRenderer(int index);
389 wxGridCellEditor* GetEditor(int index);
390
391private:
392 wxGridDataTypeInfoArray m_typeinfo;
393};
394
a9339fe2 395
b99be8fb
VZ
396// ----------------------------------------------------------------------------
397// conditional compilation
398// ----------------------------------------------------------------------------
399
9496deb5
MB
400#ifndef WXGRID_DRAW_LINES
401#define WXGRID_DRAW_LINES 1
796df70a
SN
402#endif
403
0a976765
VZ
404// ----------------------------------------------------------------------------
405// globals
406// ----------------------------------------------------------------------------
407
408//#define DEBUG_ATTR_CACHE
409#ifdef DEBUG_ATTR_CACHE
410 static size_t gs_nAttrCacheHits = 0;
411 static size_t gs_nAttrCacheMisses = 0;
2f024384 412#endif
f85afd4e 413
43947979
VZ
414// ----------------------------------------------------------------------------
415// constants
416// ----------------------------------------------------------------------------
417
f85afd4e 418wxGridCellCoords wxGridNoCellCoords( -1, -1 );
2f024384 419wxRect wxGridNoCellRect( -1, -1, -1, -1 );
f85afd4e 420
f0102d2a 421// scroll line size
faec5a43
SN
422// TODO: this doesn't work at all, grid cells have different sizes and approx
423// calculations don't work as because of the size mismatch scrollbars
424// sometimes fail to be shown when they should be or vice versa
b51c3f27
RD
425//
426// The scroll bars may be a little flakey once in a while, but that is
427// surely much less horrible than having scroll lines of only 1!!!
428// -- Robin
97a9929e
VZ
429//
430// Well, it's still seriously broken so it might be better but needs
431// fixing anyhow
432// -- Vadim
433static const size_t GRID_SCROLL_LINE_X = 15; // 1;
434static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
f85afd4e 435
43947979
VZ
436// the size of hash tables used a bit everywhere (the max number of elements
437// in these hash tables is the number of rows/columns)
438static const int GRID_HASH_SIZE = 100;
439
608754c4 440#if 0
97a9929e
VZ
441// ----------------------------------------------------------------------------
442// private functions
443// ----------------------------------------------------------------------------
444
d0eb7e56 445static inline int GetScrollX(int x)
97a9929e
VZ
446{
447 return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X;
448}
449
d0eb7e56 450static inline int GetScrollY(int y)
97a9929e
VZ
451{
452 return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y;
453}
608754c4 454#endif
97a9929e 455
ab79958a
VZ
456// ============================================================================
457// implementation
458// ============================================================================
459
2796cce3
RD
460// ----------------------------------------------------------------------------
461// wxGridCellEditor
462// ----------------------------------------------------------------------------
463
464wxGridCellEditor::wxGridCellEditor()
465{
466 m_control = NULL;
1bd71df9 467 m_attr = NULL;
2796cce3
RD
468}
469
2796cce3
RD
470wxGridCellEditor::~wxGridCellEditor()
471{
472 Destroy();
473}
474
508011ce
VZ
475void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
476 wxWindowID WXUNUSED(id),
477 wxEvtHandler* evtHandler)
478{
189d0213 479 if ( evtHandler )
508011ce
VZ
480 m_control->PushEventHandler(evtHandler);
481}
2796cce3 482
189d0213
VZ
483void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
484 wxGridCellAttr *attr)
485{
486 // erase the background because we might not fill the cell
487 wxClientDC dc(m_control->GetParent());
b819b854
JS
488 wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
489 if (gridWindow)
490 gridWindow->GetOwner()->PrepareDC(dc);
ef5df12b 491
189d0213
VZ
492 dc.SetPen(*wxTRANSPARENT_PEN);
493 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
494 dc.DrawRectangle(rectCell);
495
496 // redraw the control we just painted over
497 m_control->Refresh();
498}
499
2796cce3
RD
500void wxGridCellEditor::Destroy()
501{
508011ce
VZ
502 if (m_control)
503 {
a9339fe2 504 m_control->PopEventHandler( true /* delete it*/ );
b94ae1ea 505
2796cce3
RD
506 m_control->Destroy();
507 m_control = NULL;
508 }
509}
510
3da93aae 511void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
2796cce3 512{
2f024384
DS
513 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
514
2796cce3 515 m_control->Show(show);
3da93aae
VZ
516
517 if ( show )
518 {
519 // set the colours/fonts if we have any
520 if ( attr )
521 {
f2d76237
RD
522 m_colFgOld = m_control->GetForegroundColour();
523 m_control->SetForegroundColour(attr->GetTextColour());
3da93aae 524
f2d76237
RD
525 m_colBgOld = m_control->GetBackgroundColour();
526 m_control->SetBackgroundColour(attr->GetBackgroundColour());
3da93aae 527
0e871ad0 528// Workaround for GTK+1 font setting problem on some platforms
ea2d542c 529#if !defined(__WXGTK__) || defined(__WXGTK20__)
f2d76237
RD
530 m_fontOld = m_control->GetFont();
531 m_control->SetFont(attr->GetFont());
ea2d542c 532#endif
a9339fe2 533
3da93aae
VZ
534 // can't do anything more in the base class version, the other
535 // attributes may only be used by the derived classes
536 }
537 }
538 else
539 {
540 // restore the standard colours fonts
541 if ( m_colFgOld.Ok() )
542 {
543 m_control->SetForegroundColour(m_colFgOld);
544 m_colFgOld = wxNullColour;
545 }
546
547 if ( m_colBgOld.Ok() )
548 {
549 m_control->SetBackgroundColour(m_colBgOld);
550 m_colBgOld = wxNullColour;
551 }
2f024384 552
0e871ad0 553// Workaround for GTK+1 font setting problem on some platforms
ea2d542c 554#if !defined(__WXGTK__) || defined(__WXGTK20__)
3da93aae
VZ
555 if ( m_fontOld.Ok() )
556 {
557 m_control->SetFont(m_fontOld);
558 m_fontOld = wxNullFont;
559 }
ea2d542c 560#endif
3da93aae 561 }
2796cce3
RD
562}
563
564void wxGridCellEditor::SetSize(const wxRect& rect)
565{
2f024384
DS
566 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
567
28a77bc4 568 m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
2796cce3
RD
569}
570
571void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
572{
573 event.Skip();
574}
575
f6bcfd97
BP
576bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
577{
63e2147c
RD
578 bool ctrl = event.ControlDown();
579 bool alt = event.AltDown();
2f024384 580
63e2147c
RD
581#ifdef __WXMAC__
582 // On the Mac the Alt key is more like shift and is used for entry of
583 // valid characters, so check for Ctrl and Meta instead.
584 alt = event.MetaDown();
585#endif
586
587 // Assume it's not a valid char if ctrl or alt is down, but if both are
588 // down then it may be because of an AltGr key combination, so let them
589 // through in that case.
590 if ((ctrl || alt) && !(ctrl && alt))
591 return false;
902725ee 592
2f024384 593 int key = 0;
63e2147c
RD
594 bool keyOk = true;
595
e1a66d9a
RD
596#ifdef __WXGTK20__
597 // If it's a F-Key or other special key then it shouldn't start the
598 // editor.
599 if (event.GetKeyCode() >= WXK_START)
600 return false;
601#endif
2f024384 602#if wxUSE_UNICODE
63e2147c
RD
603 // if the unicode key code is not really a unicode character (it may
604 // be a function key or etc., the platforms appear to always give us a
2f024384 605 // small value in this case) then fallback to the ASCII key code but
63e2147c 606 // don't do anything for function keys or etc.
2f024384 607 key = event.GetUnicodeKey();
63e2147c
RD
608 if (key <= 127)
609 {
610 key = event.GetKeyCode();
611 keyOk = (key <= 127);
612 }
2f024384
DS
613#else
614 key = event.GetKeyCode();
615 keyOk = (key <= 255);
616#endif
617
63e2147c 618 return keyOk;
f6bcfd97 619}
2796cce3 620
2c9a89e0
RD
621void wxGridCellEditor::StartingKey(wxKeyEvent& event)
622{
e195a54c
VZ
623 event.Skip();
624}
2c9a89e0 625
e195a54c
VZ
626void wxGridCellEditor::StartingClick()
627{
b54ba671 628}
2c9a89e0 629
3a8c693a
VZ
630#if wxUSE_TEXTCTRL
631
b54ba671
VZ
632// ----------------------------------------------------------------------------
633// wxGridCellTextEditor
634// ----------------------------------------------------------------------------
2c9a89e0 635
2796cce3
RD
636wxGridCellTextEditor::wxGridCellTextEditor()
637{
c4608a8a 638 m_maxChars = 0;
2796cce3
RD
639}
640
641void wxGridCellTextEditor::Create(wxWindow* parent,
642 wxWindowID id,
2796cce3
RD
643 wxEvtHandler* evtHandler)
644{
508011ce 645 m_control = new wxTextCtrl(parent, id, wxEmptyString,
2c9a89e0 646 wxDefaultPosition, wxDefaultSize
2796cce3 647#if defined(__WXMSW__)
b8508db8
VZ
648 ,
649 wxTE_PROCESS_ENTER |
650 wxTE_PROCESS_TAB |
651 wxTE_AUTO_SCROLL |
652 wxNO_BORDER
2796cce3 653#endif
508011ce 654 );
2796cce3 655
46a5010a
RD
656 // set max length allowed in the textctrl, if the parameter was set
657 if (m_maxChars != 0)
658 {
659 ((wxTextCtrl*)m_control)->SetMaxLength(m_maxChars);
660 }
c4608a8a 661
508011ce 662 wxGridCellEditor::Create(parent, id, evtHandler);
2796cce3
RD
663}
664
189d0213
VZ
665void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
666 wxGridCellAttr * WXUNUSED(attr))
667{
a9339fe2
DS
668 // as we fill the entire client area,
669 // don't do anything here to minimize flicker
189d0213 670}
2796cce3 671
99306db2
VZ
672void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
673{
674 wxRect rect(rectOrig);
675
2f024384 676 // Make the edit control large enough to allow for internal margins
99306db2 677 //
2f024384 678 // TODO: remove this if the text ctrl sizing is improved esp. for unix
99306db2
VZ
679 //
680#if defined(__WXGTK__)
b0e282b3
RR
681 if (rect.x != 0)
682 {
683 rect.x += 1;
684 rect.y += 1;
685 rect.width -= 1;
686 rect.height -= 1;
687 }
d4175745
VZ
688#elif defined(__WXMSW__)
689 if ( rect.x == 0 )
690 rect.x += 2;
691 else
692 rect.x += 3;
84912ef8 693
d4175745
VZ
694 if ( rect.y == 0 )
695 rect.y += 2;
696 else
697 rect.y += 3;
698
699 rect.width -= 2;
700 rect.height -= 2;
a0948e27 701#else
d4175745 702 int extra_x = ( rect.x > 2 ) ? 2 : 1;
2f024384 703 int extra_y = ( rect.y > 2 ) ? 2 : 1;
a0948e27 704
d4175745
VZ
705 #if defined(__WXMOTIF__)
706 extra_x *= 2;
707 extra_y *= 2;
708 #endif
2f024384 709
cb105ad4
SN
710 rect.SetLeft( wxMax(0, rect.x - extra_x) );
711 rect.SetTop( wxMax(0, rect.y - extra_y) );
2f024384
DS
712 rect.SetRight( rect.GetRight() + 2 * extra_x );
713 rect.SetBottom( rect.GetBottom() + 2 * extra_y );
d4175745 714#endif
99306db2
VZ
715
716 wxGridCellEditor::SetSize(rect);
717}
718
3da93aae 719void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
2796cce3 720{
2f024384 721 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
2796cce3
RD
722
723 m_startValue = grid->GetTable()->GetValue(row, col);
816be743
VZ
724
725 DoBeginEdit(m_startValue);
726}
727
728void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
729{
730 Text()->SetValue(startValue);
b54ba671 731 Text()->SetInsertionPointEnd();
2f024384 732 Text()->SetSelection(-1, -1);
b54ba671 733 Text()->SetFocus();
2796cce3
RD
734}
735
ccdee36f 736bool wxGridCellTextEditor::EndEdit(int row, int col, wxGrid* grid)
2796cce3 737{
2f024384 738 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
2796cce3 739
ca65c044 740 bool changed = false;
b54ba671 741 wxString value = Text()->GetValue();
2796cce3 742 if (value != m_startValue)
ca65c044 743 changed = true;
2796cce3
RD
744
745 if (changed)
746 grid->GetTable()->SetValue(row, col, value);
2c9a89e0 747
3da93aae 748 m_startValue = wxEmptyString;
a9339fe2 749
7b519e5e
JS
750 // No point in setting the text of the hidden control
751 //Text()->SetValue(m_startValue);
2796cce3
RD
752
753 return changed;
754}
755
2796cce3
RD
756void wxGridCellTextEditor::Reset()
757{
2f024384 758 wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!"));
2796cce3 759
816be743
VZ
760 DoReset(m_startValue);
761}
762
763void wxGridCellTextEditor::DoReset(const wxString& startValue)
764{
765 Text()->SetValue(startValue);
b54ba671 766 Text()->SetInsertionPointEnd();
2796cce3
RD
767}
768
f6bcfd97
BP
769bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
770{
63e2147c 771 return wxGridCellEditor::IsAcceptedKey(event);
f6bcfd97
BP
772}
773
2c9a89e0
RD
774void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
775{
63e2147c
RD
776 // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no
777 // longer an appropriate way to get the character into the text control.
778 // Do it ourselves instead. We know that if we get this far that we have
779 // a valid character, so not a whole lot of testing needs to be done.
780
781 wxTextCtrl* tc = Text();
782 wxChar ch;
783 long pos;
902725ee 784
63e2147c
RD
785#if wxUSE_UNICODE
786 ch = event.GetUnicodeKey();
787 if (ch <= 127)
6f0d2cee 788 ch = (wxChar)event.GetKeyCode();
63e2147c 789#else
6f0d2cee 790 ch = (wxChar)event.GetKeyCode();
63e2147c 791#endif
2f024384 792
63e2147c 793 switch (ch)
f6bcfd97 794 {
63e2147c
RD
795 case WXK_DELETE:
796 // delete the character at the cursor
797 pos = tc->GetInsertionPoint();
798 if (pos < tc->GetLastPosition())
2f024384 799 tc->Remove(pos, pos + 1);
63e2147c
RD
800 break;
801
802 case WXK_BACK:
803 // delete the character before the cursor
804 pos = tc->GetInsertionPoint();
805 if (pos > 0)
2f024384 806 tc->Remove(pos - 1, pos);
63e2147c
RD
807 break;
808
809 default:
810 tc->WriteText(ch);
811 break;
f6bcfd97 812 }
b54ba671 813}
2c9a89e0 814
c78b3acd 815void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
0b7e6e7d 816 WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
2796cce3
RD
817{
818#if defined(__WXMOTIF__) || defined(__WXGTK__)
819 // wxMotif needs a little extra help...
6fc0f38f 820 size_t pos = (size_t)( Text()->GetInsertionPoint() );
b54ba671 821 wxString s( Text()->GetValue() );
8dd8f875 822 s = s.Left(pos) + wxT("\n") + s.Mid(pos);
b54ba671
VZ
823 Text()->SetValue(s);
824 Text()->SetInsertionPoint( pos );
2796cce3
RD
825#else
826 // the other ports can handle a Return key press
827 //
828 event.Skip();
829#endif
830}
831
c4608a8a
VZ
832void wxGridCellTextEditor::SetParameters(const wxString& params)
833{
834 if ( !params )
835 {
836 // reset to default
837 m_maxChars = 0;
838 }
839 else
840 {
841 long tmp;
c2f5b920 842 if ( params.ToLong(&tmp) )
c4608a8a 843 {
c2f5b920 844 m_maxChars = (size_t)tmp;
c4608a8a
VZ
845 }
846 else
847 {
c2f5b920 848 wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() );
c4608a8a
VZ
849 }
850 }
851}
852
73145b0e
JS
853// return the value in the text control
854wxString wxGridCellTextEditor::GetValue() const
855{
2f024384 856 return Text()->GetValue();
73145b0e
JS
857}
858
816be743
VZ
859// ----------------------------------------------------------------------------
860// wxGridCellNumberEditor
861// ----------------------------------------------------------------------------
862
863wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
864{
865 m_min = min;
866 m_max = max;
867}
868
869void wxGridCellNumberEditor::Create(wxWindow* parent,
870 wxWindowID id,
871 wxEvtHandler* evtHandler)
872{
0e871ad0 873#if wxUSE_SPINCTRL
816be743
VZ
874 if ( HasRange() )
875 {
876 // create a spin ctrl
ca65c044 877 m_control = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString,
816be743
VZ
878 wxDefaultPosition, wxDefaultSize,
879 wxSP_ARROW_KEYS,
880 m_min, m_max);
881
882 wxGridCellEditor::Create(parent, id, evtHandler);
883 }
884 else
0e871ad0 885#endif
816be743
VZ
886 {
887 // just a text control
888 wxGridCellTextEditor::Create(parent, id, evtHandler);
889
890#if wxUSE_VALIDATORS
85bc0351 891 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
c2f5b920 892#endif
816be743
VZ
893 }
894}
895
896void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
897{
898 // first get the value
899 wxGridTableBase *table = grid->GetTable();
900 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
901 {
902 m_valueOld = table->GetValueAsLong(row, col);
903 }
904 else
905 {
8a60ff0a 906 m_valueOld = 0;
a5777624 907 wxString sValue = table->GetValue(row, col);
0e871ad0 908 if (! sValue.ToLong(&m_valueOld) && ! sValue.empty())
a5777624
RD
909 {
910 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
911 return;
912 }
816be743
VZ
913 }
914
0e871ad0 915#if wxUSE_SPINCTRL
816be743
VZ
916 if ( HasRange() )
917 {
4a64bee4 918 Spin()->SetValue((int)m_valueOld);
f6bcfd97 919 Spin()->SetFocus();
816be743
VZ
920 }
921 else
0e871ad0 922#endif
816be743
VZ
923 {
924 DoBeginEdit(GetString());
925 }
926}
927
3324d5f5 928bool wxGridCellNumberEditor::EndEdit(int row, int col,
816be743
VZ
929 wxGrid* grid)
930{
931 bool changed;
8a60ff0a
RD
932 long value = 0;
933 wxString text;
816be743 934
0e871ad0 935#if wxUSE_SPINCTRL
816be743
VZ
936 if ( HasRange() )
937 {
938 value = Spin()->GetValue();
939 changed = value != m_valueOld;
8a60ff0a
RD
940 if (changed)
941 text = wxString::Format(wxT("%ld"), value);
816be743
VZ
942 }
943 else
0e871ad0 944#endif
816be743 945 {
8a60ff0a 946 text = Text()->GetValue();
0e871ad0 947 changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld);
816be743
VZ
948 }
949
950 if ( changed )
951 {
a5777624
RD
952 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
953 grid->GetTable()->SetValueAsLong(row, col, value);
954 else
8a60ff0a 955 grid->GetTable()->SetValue(row, col, text);
816be743
VZ
956 }
957
958 return changed;
959}
960
961void wxGridCellNumberEditor::Reset()
962{
0e871ad0 963#if wxUSE_SPINCTRL
816be743
VZ
964 if ( HasRange() )
965 {
4a64bee4 966 Spin()->SetValue((int)m_valueOld);
816be743
VZ
967 }
968 else
0e871ad0 969#endif
816be743
VZ
970 {
971 DoReset(GetString());
972 }
973}
974
f6bcfd97
BP
975bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
976{
977 if ( wxGridCellEditor::IsAcceptedKey(event) )
978 {
979 int keycode = event.GetKeyCode();
63e2147c
RD
980 if ( (keycode < 128) &&
981 (wxIsdigit(keycode) || keycode == '+' || keycode == '-'))
f6bcfd97 982 {
63e2147c 983 return true;
f6bcfd97
BP
984 }
985 }
986
ca65c044 987 return false;
f6bcfd97
BP
988}
989
816be743
VZ
990void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
991{
eb5e42b6 992 int keycode = event.GetKeyCode();
816be743
VZ
993 if ( !HasRange() )
994 {
63e2147c 995 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-')
816be743
VZ
996 {
997 wxGridCellTextEditor::StartingKey(event);
998
999 // skip Skip() below
1000 return;
1001 }
1002 }
eb5e42b6
RD
1003#if wxUSE_SPINCTRL
1004 else
1005 {
1006 if ( wxIsdigit(keycode) )
1007 {
1008 wxSpinCtrl* spin = (wxSpinCtrl*)m_control;
1009 spin->SetValue(keycode - '0');
1010 spin->SetSelection(1,1);
1011 return;
1012 }
1013 }
1014#endif
2f024384 1015
816be743
VZ
1016 event.Skip();
1017}
9c4ba614 1018
c4608a8a
VZ
1019void wxGridCellNumberEditor::SetParameters(const wxString& params)
1020{
1021 if ( !params )
1022 {
1023 // reset to default
1024 m_min =
1025 m_max = -1;
1026 }
1027 else
1028 {
1029 long tmp;
1030 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1031 {
1032 m_min = (int)tmp;
1033
1034 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1035 {
1036 m_max = (int)tmp;
1037
1038 // skip the error message below
1039 return;
1040 }
1041 }
1042
f6bcfd97 1043 wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
c4608a8a
VZ
1044 }
1045}
1046
73145b0e
JS
1047// return the value in the spin control if it is there (the text control otherwise)
1048wxString wxGridCellNumberEditor::GetValue() const
1049{
0e871ad0
WS
1050 wxString s;
1051
1052#if wxUSE_SPINCTRL
4db6714b 1053 if ( HasRange() )
0e871ad0
WS
1054 {
1055 long value = Spin()->GetValue();
1056 s.Printf(wxT("%ld"), value);
1057 }
1058 else
1059#endif
1060 {
1061 s = Text()->GetValue();
1062 }
1063
1064 return s;
73145b0e
JS
1065}
1066
816be743
VZ
1067// ----------------------------------------------------------------------------
1068// wxGridCellFloatEditor
1069// ----------------------------------------------------------------------------
1070
f6bcfd97
BP
1071wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
1072{
1073 m_width = width;
1074 m_precision = precision;
1075}
1076
816be743
VZ
1077void wxGridCellFloatEditor::Create(wxWindow* parent,
1078 wxWindowID id,
1079 wxEvtHandler* evtHandler)
1080{
1081 wxGridCellTextEditor::Create(parent, id, evtHandler);
1082
1083#if wxUSE_VALIDATORS
85bc0351 1084 Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
c2f5b920 1085#endif
816be743
VZ
1086}
1087
1088void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
1089{
1090 // first get the value
1091 wxGridTableBase *table = grid->GetTable();
1092 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
1093 {
1094 m_valueOld = table->GetValueAsDouble(row, col);
1095 }
1096 else
1097 {
8a60ff0a 1098 m_valueOld = 0.0;
a5777624 1099 wxString sValue = table->GetValue(row, col);
0e871ad0 1100 if (! sValue.ToDouble(&m_valueOld) && ! sValue.empty())
a5777624
RD
1101 {
1102 wxFAIL_MSG( _T("this cell doesn't have float value") );
1103 return;
1104 }
816be743
VZ
1105 }
1106
1107 DoBeginEdit(GetString());
1108}
1109
3324d5f5 1110bool wxGridCellFloatEditor::EndEdit(int row, int col,
816be743
VZ
1111 wxGrid* grid)
1112{
8a60ff0a
RD
1113 double value = 0.0;
1114 wxString text(Text()->GetValue());
1115
c77a6796
VZ
1116 if ( (text.empty() || text.ToDouble(&value)) &&
1117 !wxIsSameDouble(value, m_valueOld) )
816be743 1118 {
a5777624
RD
1119 if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
1120 grid->GetTable()->SetValueAsDouble(row, col, value);
1121 else
8a60ff0a 1122 grid->GetTable()->SetValue(row, col, text);
816be743 1123
ca65c044 1124 return true;
816be743 1125 }
2f024384 1126
ca65c044 1127 return false;
816be743
VZ
1128}
1129
1130void wxGridCellFloatEditor::Reset()
1131{
1132 DoReset(GetString());
1133}
1134
1135void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
1136{
12a3f227 1137 int keycode = event.GetKeyCode();
3fe73755
SN
1138 char tmpbuf[2];
1139 tmpbuf[0] = (char) keycode;
1140 tmpbuf[1] = '\0';
42841dfc 1141 wxString strbuf(tmpbuf, *wxConvCurrent);
2f024384 1142
902725ee 1143#if wxUSE_INTL
42841dfc 1144 bool is_decimal_point = ( strbuf ==
63e2147c 1145 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) );
5335e9c4
MW
1146#else
1147 bool is_decimal_point = ( strbuf == _T(".") );
1148#endif
2f024384 1149
63e2147c
RD
1150 if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-'
1151 || is_decimal_point )
816be743
VZ
1152 {
1153 wxGridCellTextEditor::StartingKey(event);
1154
1155 // skip Skip() below
1156 return;
1157 }
1158
1159 event.Skip();
1160}
1161
f6bcfd97
BP
1162void wxGridCellFloatEditor::SetParameters(const wxString& params)
1163{
1164 if ( !params )
1165 {
1166 // reset to default
1167 m_width =
1168 m_precision = -1;
1169 }
1170 else
1171 {
1172 long tmp;
1173 if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
1174 {
1175 m_width = (int)tmp;
1176
1177 if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
1178 {
1179 m_precision = (int)tmp;
1180
1181 // skip the error message below
1182 return;
1183 }
1184 }
1185
1186 wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
1187 }
1188}
1189
1190wxString wxGridCellFloatEditor::GetString() const
1191{
1192 wxString fmt;
fe4cb4f5 1193 if ( m_precision == -1 && m_width != -1)
f6bcfd97
BP
1194 {
1195 // default precision
ec53826c 1196 fmt.Printf(_T("%%%d.f"), m_width);
f6bcfd97 1197 }
fe4cb4f5
JS
1198 else if ( m_precision != -1 && m_width == -1)
1199 {
1200 // default width
1201 fmt.Printf(_T("%%.%df"), m_precision);
1202 }
1203 else if ( m_precision != -1 && m_width != -1 )
f6bcfd97 1204 {
ec53826c 1205 fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
f6bcfd97 1206 }
fe4cb4f5
JS
1207 else
1208 {
1209 // default width/precision
1210 fmt = _T("%f");
1211 }
f6bcfd97
BP
1212
1213 return wxString::Format(fmt, m_valueOld);
1214}
1215
1216bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
1217{
1218 if ( wxGridCellEditor::IsAcceptedKey(event) )
1219 {
7b34da9b
VZ
1220 const int keycode = event.GetKeyCode();
1221 if ( isascii(keycode) )
1222 {
1223 char tmpbuf[2];
1224 tmpbuf[0] = (char) keycode;
1225 tmpbuf[1] = '\0';
1226 wxString strbuf(tmpbuf, *wxConvCurrent);
2f024384 1227
902725ee 1228#if wxUSE_INTL
7b34da9b
VZ
1229 const wxString decimalPoint =
1230 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
5335e9c4 1231#else
7b34da9b 1232 const wxString decimalPoint(_T('.'));
5335e9c4 1233#endif
2f024384 1234
7b34da9b
VZ
1235 // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
1236 if ( wxIsdigit(keycode) ||
1237 tolower(keycode) == 'e' ||
1238 keycode == decimalPoint ||
1239 keycode == '+' ||
1240 keycode == '-' )
1241 {
1242 return true;
1243 }
2f024384 1244 }
f6bcfd97
BP
1245 }
1246
ca65c044 1247 return false;
f6bcfd97
BP
1248}
1249
3a8c693a
VZ
1250#endif // wxUSE_TEXTCTRL
1251
1252#if wxUSE_CHECKBOX
1253
508011ce
VZ
1254// ----------------------------------------------------------------------------
1255// wxGridCellBoolEditor
1256// ----------------------------------------------------------------------------
1257
9c71a138 1258// the default values for GetValue()
dab61ed7 1259wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") };
9c71a138 1260
508011ce
VZ
1261void wxGridCellBoolEditor::Create(wxWindow* parent,
1262 wxWindowID id,
1263 wxEvtHandler* evtHandler)
1264{
1265 m_control = new wxCheckBox(parent, id, wxEmptyString,
1266 wxDefaultPosition, wxDefaultSize,
1267 wxNO_BORDER);
1268
1269 wxGridCellEditor::Create(parent, id, evtHandler);
1270}
1271
1272void wxGridCellBoolEditor::SetSize(const wxRect& r)
1273{
ca65c044 1274 bool resize = false;
b94ae1ea
VZ
1275 wxSize size = m_control->GetSize();
1276 wxCoord minSize = wxMin(r.width, r.height);
1277
1278 // check if the checkbox is not too big/small for this cell
1279 wxSize sizeBest = m_control->GetBestSize();
1280 if ( !(size == sizeBest) )
1281 {
1282 // reset to default size if it had been made smaller
1283 size = sizeBest;
1284
ca65c044 1285 resize = true;
b94ae1ea
VZ
1286 }
1287
1288 if ( size.x >= minSize || size.y >= minSize )
1289 {
1290 // leave 1 pixel margin
1291 size.x = size.y = minSize - 2;
1292
ca65c044 1293 resize = true;
b94ae1ea
VZ
1294 }
1295
1296 if ( resize )
1297 {
1298 m_control->SetSize(size);
1299 }
1300
508011ce 1301 // position it in the centre of the rectangle (TODO: support alignment?)
508011ce 1302
b94ae1ea 1303#if defined(__WXGTK__) || defined (__WXMOTIF__)
508011ce
VZ
1304 // the checkbox without label still has some space to the right in wxGTK,
1305 // so shift it to the right
b94ae1ea
VZ
1306 size.x -= 8;
1307#elif defined(__WXMSW__)
a95e38c0
VZ
1308 // here too, but in other way
1309 size.x += 1;
b94ae1ea
VZ
1310 size.y -= 2;
1311#endif
508011ce 1312
1bd71df9
JS
1313 int hAlign = wxALIGN_CENTRE;
1314 int vAlign = wxALIGN_CENTRE;
1315 if (GetCellAttr())
1316 GetCellAttr()->GetAlignment(& hAlign, & vAlign);
52d6f640 1317
1bd71df9
JS
1318 int x = 0, y = 0;
1319 if (hAlign == wxALIGN_LEFT)
1320 {
1321 x = r.x + 2;
2f024384 1322
1bd71df9
JS
1323#ifdef __WXMSW__
1324 x += 2;
52d6f640 1325#endif
2f024384
DS
1326
1327 y = r.y + r.height / 2 - size.y / 2;
1bd71df9
JS
1328 }
1329 else if (hAlign == wxALIGN_RIGHT)
1330 {
1331 x = r.x + r.width - size.x - 2;
2f024384 1332 y = r.y + r.height / 2 - size.y / 2;
1bd71df9
JS
1333 }
1334 else if (hAlign == wxALIGN_CENTRE)
1335 {
2f024384
DS
1336 x = r.x + r.width / 2 - size.x / 2;
1337 y = r.y + r.height / 2 - size.y / 2;
1bd71df9 1338 }
52d6f640 1339
1bd71df9 1340 m_control->Move(x, y);
508011ce
VZ
1341}
1342
1343void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
1344{
99306db2
VZ
1345 m_control->Show(show);
1346
189d0213 1347 if ( show )
508011ce 1348 {
189d0213
VZ
1349 wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
1350 CBox()->SetBackgroundColour(colBg);
508011ce 1351 }
508011ce
VZ
1352}
1353
1354void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
1355{
1356 wxASSERT_MSG(m_control,
c2f5b920 1357 wxT("The wxGridCellEditor must be created first!"));
508011ce 1358
28a77bc4 1359 if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
2f024384 1360 {
f2d76237 1361 m_startValue = grid->GetTable()->GetValueAsBool(row, col);
2f024384 1362 }
f2d76237 1363 else
695a3263
MB
1364 {
1365 wxString cellval( grid->GetTable()->GetValue(row, col) );
8497bbf5
VZ
1366
1367 if ( cellval == ms_stringValues[false] )
1368 m_startValue = false;
1369 else if ( cellval == ms_stringValues[true] )
1370 m_startValue = true;
1371 else
1372 {
1373 // do not try to be smart here and convert it to true or false
1374 // because we'll still overwrite it with something different and
1375 // this risks to be very surprising for the user code, let them
1376 // know about it
1377 wxFAIL_MSG( _T("invalid value for a cell with bool editor!") );
1378 }
695a3263 1379 }
2f024384 1380
508011ce
VZ
1381 CBox()->SetValue(m_startValue);
1382 CBox()->SetFocus();
1383}
1384
1385bool wxGridCellBoolEditor::EndEdit(int row, int col,
508011ce
VZ
1386 wxGrid* grid)
1387{
1388 wxASSERT_MSG(m_control,
c2f5b920 1389 wxT("The wxGridCellEditor must be created first!"));
508011ce 1390
ca65c044 1391 bool changed = false;
508011ce
VZ
1392 bool value = CBox()->GetValue();
1393 if ( value != m_startValue )
ca65c044 1394 changed = true;
508011ce
VZ
1395
1396 if ( changed )
1397 {
9c71a138
VZ
1398 wxGridTableBase * const table = grid->GetTable();
1399 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
1400 table->SetValueAsBool(row, col, value);
f2d76237 1401 else
9c71a138 1402 table->SetValue(row, col, GetValue());
508011ce
VZ
1403 }
1404
1405 return changed;
1406}
1407
1408void wxGridCellBoolEditor::Reset()
1409{
1410 wxASSERT_MSG(m_control,
c2f5b920 1411 wxT("The wxGridCellEditor must be created first!"));
508011ce
VZ
1412
1413 CBox()->SetValue(m_startValue);
1414}
1415
e195a54c 1416void wxGridCellBoolEditor::StartingClick()
508011ce 1417{
e195a54c 1418 CBox()->SetValue(!CBox()->GetValue());
508011ce
VZ
1419}
1420
f6bcfd97
BP
1421bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
1422{
1423 if ( wxGridCellEditor::IsAcceptedKey(event) )
1424 {
1425 int keycode = event.GetKeyCode();
1426 switch ( keycode )
1427 {
f6bcfd97
BP
1428 case WXK_SPACE:
1429 case '+':
1430 case '-':
ca65c044 1431 return true;
f6bcfd97
BP
1432 }
1433 }
1434
ca65c044 1435 return false;
f6bcfd97 1436}
04418332 1437
63e2147c
RD
1438void wxGridCellBoolEditor::StartingKey(wxKeyEvent& event)
1439{
1440 int keycode = event.GetKeyCode();
1441 switch ( keycode )
1442 {
1443 case WXK_SPACE:
1444 CBox()->SetValue(!CBox()->GetValue());
1445 break;
902725ee 1446
63e2147c
RD
1447 case '+':
1448 CBox()->SetValue(true);
1449 break;
902725ee 1450
63e2147c
RD
1451 case '-':
1452 CBox()->SetValue(false);
1453 break;
1454 }
1455}
1456
73145b0e
JS
1457wxString wxGridCellBoolEditor::GetValue() const
1458{
9c71a138
VZ
1459 return ms_stringValues[CBox()->GetValue()];
1460}
1461
1462/* static */ void
1463wxGridCellBoolEditor::UseStringValues(const wxString& valueTrue,
1464 const wxString& valueFalse)
1465{
1466 ms_stringValues[false] = valueFalse;
1467 ms_stringValues[true] = valueTrue;
1468}
1469
1470/* static */ bool
1471wxGridCellBoolEditor::IsTrueValue(const wxString& value)
1472{
1473 return value == ms_stringValues[true];
73145b0e 1474}
f6bcfd97 1475
3a8c693a
VZ
1476#endif // wxUSE_CHECKBOX
1477
1478#if wxUSE_COMBOBOX
1479
4ee5fc9c
VZ
1480// ----------------------------------------------------------------------------
1481// wxGridCellChoiceEditor
1482// ----------------------------------------------------------------------------
1483
7db33cc3
MB
1484wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString& choices,
1485 bool allowOthers)
1486 : m_choices(choices),
1487 m_allowOthers(allowOthers) { }
1488
4ee5fc9c 1489wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
f6bcfd97 1490 const wxString choices[],
4ee5fc9c
VZ
1491 bool allowOthers)
1492 : m_allowOthers(allowOthers)
1493{
c4608a8a 1494 if ( count )
4ee5fc9c 1495 {
c4608a8a
VZ
1496 m_choices.Alloc(count);
1497 for ( size_t n = 0; n < count; n++ )
1498 {
1499 m_choices.Add(choices[n]);
1500 }
4ee5fc9c
VZ
1501 }
1502}
1503
c4608a8a
VZ
1504wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
1505{
1506 wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
1507 editor->m_allowOthers = m_allowOthers;
1508 editor->m_choices = m_choices;
1509
1510 return editor;
1511}
1512
4ee5fc9c
VZ
1513void wxGridCellChoiceEditor::Create(wxWindow* parent,
1514 wxWindowID id,
1515 wxEvtHandler* evtHandler)
1516{
4ee5fc9c
VZ
1517 m_control = new wxComboBox(parent, id, wxEmptyString,
1518 wxDefaultPosition, wxDefaultSize,
584ad2a3 1519 m_choices,
4ee5fc9c
VZ
1520 m_allowOthers ? 0 : wxCB_READONLY);
1521
4ee5fc9c
VZ
1522 wxGridCellEditor::Create(parent, id, evtHandler);
1523}
1524
a5777624
RD
1525void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
1526 wxGridCellAttr * attr)
4ee5fc9c
VZ
1527{
1528 // as we fill the entire client area, don't do anything here to minimize
1529 // flicker
a5777624
RD
1530
1531 // TODO: It doesn't actually fill the client area since the height of a
c2f5b920
DS
1532 // combo always defaults to the standard. Until someone has time to
1533 // figure out the right rectangle to paint, just do it the normal way.
a5777624 1534 wxGridCellEditor::PaintBackground(rectCell, attr);
4ee5fc9c
VZ
1535}
1536
1537void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
1538{
1539 wxASSERT_MSG(m_control,
c2f5b920 1540 wxT("The wxGridCellEditor must be created first!"));
4ee5fc9c 1541
08dd04d0
JS
1542 wxGridCellEditorEvtHandler* evtHandler = NULL;
1543 if (m_control)
1544 evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
1545
1546 // Don't immediately end if we get a kill focus event within BeginEdit
1547 if (evtHandler)
1548 evtHandler->SetInSetFocus(true);
1549
4ee5fc9c
VZ
1550 m_startValue = grid->GetTable()->GetValue(row, col);
1551
2b5f62a0 1552 if (m_allowOthers)
2f024384 1553 {
2b5f62a0 1554 Combo()->SetValue(m_startValue);
2f024384 1555 }
2b5f62a0 1556 else
28a77bc4 1557 {
2b5f62a0
VZ
1558 // find the right position, or default to the first if not found
1559 int pos = Combo()->FindString(m_startValue);
902725ee 1560 if (pos == wxNOT_FOUND)
2b5f62a0
VZ
1561 pos = 0;
1562 Combo()->SetSelection(pos);
28a77bc4 1563 }
2f024384 1564
4ee5fc9c
VZ
1565 Combo()->SetInsertionPointEnd();
1566 Combo()->SetFocus();
08dd04d0
JS
1567
1568 if (evtHandler)
46cbb21e
JS
1569 {
1570 // When dropping down the menu, a kill focus event
1571 // happens after this point, so we can't reset the flag yet.
1572#if !defined(__WXGTK20__)
08dd04d0 1573 evtHandler->SetInSetFocus(false);
46cbb21e
JS
1574#endif
1575 }
4ee5fc9c
VZ
1576}
1577
28a77bc4 1578bool wxGridCellChoiceEditor::EndEdit(int row, int col,
4ee5fc9c
VZ
1579 wxGrid* grid)
1580{
1581 wxString value = Combo()->GetValue();
faffacec
VZ
1582 if ( value == m_startValue )
1583 return false;
4ee5fc9c 1584
faffacec 1585 grid->GetTable()->SetValue(row, col, value);
4ee5fc9c 1586
faffacec 1587 return true;
4ee5fc9c
VZ
1588}
1589
1590void wxGridCellChoiceEditor::Reset()
1591{
1592 Combo()->SetValue(m_startValue);
1593 Combo()->SetInsertionPointEnd();
1594}
1595
c4608a8a
VZ
1596void wxGridCellChoiceEditor::SetParameters(const wxString& params)
1597{
1598 if ( !params )
1599 {
1600 // what can we do?
1601 return;
1602 }
1603
1604 m_choices.Empty();
1605
1606 wxStringTokenizer tk(params, _T(','));
1607 while ( tk.HasMoreTokens() )
1608 {
1609 m_choices.Add(tk.GetNextToken());
1610 }
1611}
1612
73145b0e
JS
1613// return the value in the text control
1614wxString wxGridCellChoiceEditor::GetValue() const
1615{
1616 return Combo()->GetValue();
1617}
04418332 1618
3a8c693a
VZ
1619#endif // wxUSE_COMBOBOX
1620
508011ce
VZ
1621// ----------------------------------------------------------------------------
1622// wxGridCellEditorEvtHandler
1623// ----------------------------------------------------------------------------
2796cce3 1624
140954fd
VZ
1625void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent& event)
1626{
08dd04d0
JS
1627 // Don't disable the cell if we're just starting to edit it
1628 if (m_inSetFocus)
1629 return;
1630
140954fd
VZ
1631 // accept changes
1632 m_grid->DisableCellEditControl();
1633
1634 event.Skip();
1635}
1636
2796cce3
RD
1637void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
1638{
12a3f227 1639 switch ( event.GetKeyCode() )
2796cce3
RD
1640 {
1641 case WXK_ESCAPE:
1642 m_editor->Reset();
b54ba671 1643 m_grid->DisableCellEditControl();
2796cce3
RD
1644 break;
1645
2c9a89e0 1646 case WXK_TAB:
b51c3f27 1647 m_grid->GetEventHandler()->ProcessEvent( event );
9b4aede2
RD
1648 break;
1649
2796cce3 1650 case WXK_RETURN:
faec5a43
SN
1651 case WXK_NUMPAD_ENTER:
1652 if (!m_grid->GetEventHandler()->ProcessEvent(event))
2796cce3
RD
1653 m_editor->HandleReturn(event);
1654 break;
1655
2796cce3
RD
1656 default:
1657 event.Skip();
2f024384 1658 break;
2796cce3
RD
1659 }
1660}
1661
fb0de762
RD
1662void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
1663{
7db713ae
JS
1664 int row = m_grid->GetGridCursorRow();
1665 int col = m_grid->GetGridCursorCol();
1666 wxRect rect = m_grid->CellToRect( row, col );
1667 int cw, ch;
1668 m_grid->GetGridWindow()->GetClientSize( &cw, &ch );
2f024384 1669
7db713ae
JS
1670 // if cell width is smaller than grid client area, cell is wholly visible
1671 bool wholeCellVisible = (rect.GetWidth() < cw);
1672
12a3f227 1673 switch ( event.GetKeyCode() )
fb0de762
RD
1674 {
1675 case WXK_ESCAPE:
1676 case WXK_TAB:
1677 case WXK_RETURN:
a4f7bf58 1678 case WXK_NUMPAD_ENTER:
fb0de762
RD
1679 break;
1680
7db713ae
JS
1681 case WXK_HOME:
1682 {
2f024384 1683 if ( wholeCellVisible )
7db713ae
JS
1684 {
1685 // no special processing needed...
1686 event.Skip();
1687 break;
1688 }
1689
1690 // do special processing for partly visible cell...
1691
1692 // get the widths of all cells previous to this one
1693 int colXPos = 0;
faa94f3e 1694 for ( int i = 0; i < col; i++ )
7db713ae
JS
1695 {
1696 colXPos += m_grid->GetColSize(i);
1697 }
1698
1699 int xUnit = 1, yUnit = 1;
1700 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
1701 if (col != 0)
1702 {
2f024384 1703 m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL));
7db713ae
JS
1704 }
1705 else
1706 {
2f024384 1707 m_grid->Scroll(colXPos / xUnit, m_grid->GetScrollPos(wxVERTICAL));
7db713ae
JS
1708 }
1709 event.Skip();
1710 break;
1711 }
c2f5b920 1712
7db713ae
JS
1713 case WXK_END:
1714 {
2f024384 1715 if ( wholeCellVisible )
7db713ae
JS
1716 {
1717 // no special processing needed...
1718 event.Skip();
1719 break;
1720 }
1721
1722 // do special processing for partly visible cell...
1723
1724 int textWidth = 0;
1725 wxString value = m_grid->GetCellValue(row, col);
1726 if ( wxEmptyString != value )
1727 {
1728 // get width of cell CONTENTS (text)
1729 int y;
1730 wxFont font = m_grid->GetCellFont(row, col);
1731 m_grid->GetTextExtent(value, &textWidth, &y, NULL, NULL, &font);
2f024384 1732
7db713ae
JS
1733 // try to RIGHT align the text by scrolling
1734 int client_right = m_grid->GetGridWindow()->GetClientSize().GetWidth();
2f024384 1735
7db713ae
JS
1736 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far,
1737 // otherwise the last part of the cell content might be hidden below the scroll bar
1738 // FIXME: maybe there is a more suitable correction?
2f024384 1739 textWidth -= (client_right - (m_grid->GetScrollLineX() * 2));
7db713ae
JS
1740 if ( textWidth < 0 )
1741 {
1742 textWidth = 0;
1743 }
1744 }
1745
1746 // get the widths of all cells previous to this one
1747 int colXPos = 0;
faa94f3e 1748 for ( int i = 0; i < col; i++ )
7db713ae
JS
1749 {
1750 colXPos += m_grid->GetColSize(i);
1751 }
2f024384 1752
7db713ae
JS
1753 // and add the (modified) text width of the cell contents
1754 // as we'd like to see the last part of the cell contents
1755 colXPos += textWidth;
1756
1757 int xUnit = 1, yUnit = 1;
1758 m_grid->GetScrollPixelsPerUnit(&xUnit, &yUnit);
ccdee36f 1759 m_grid->Scroll(colXPos / xUnit - 1, m_grid->GetScrollPos(wxVERTICAL));
7db713ae
JS
1760 event.Skip();
1761 break;
1762 }
1763
fb0de762
RD
1764 default:
1765 event.Skip();
c2f5b920 1766 break;
fb0de762
RD
1767 }
1768}
1769
c4608a8a
VZ
1770// ----------------------------------------------------------------------------
1771// wxGridCellWorker is an (almost) empty common base class for
1772// wxGridCellRenderer and wxGridCellEditor managing ref counting
1773// ----------------------------------------------------------------------------
1774
1775void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
1776{
1777 // nothing to do
1778}
1779
1780wxGridCellWorker::~wxGridCellWorker()
1781{
1782}
1783
508011ce
VZ
1784// ============================================================================
1785// renderer classes
1786// ============================================================================
1787
ab79958a
VZ
1788// ----------------------------------------------------------------------------
1789// wxGridCellRenderer
1790// ----------------------------------------------------------------------------
1791
1792void wxGridCellRenderer::Draw(wxGrid& grid,
2796cce3 1793 wxGridCellAttr& attr,
ab79958a
VZ
1794 wxDC& dc,
1795 const wxRect& rect,
c78b3acd 1796 int WXUNUSED(row), int WXUNUSED(col),
ab79958a
VZ
1797 bool isSelected)
1798{
1799 dc.SetBackgroundMode( wxSOLID );
1800
04418332 1801 // grey out fields if the grid is disabled
4db6714b 1802 if ( grid.IsEnabled() )
ab79958a 1803 {
ec157c8f
WS
1804 if ( isSelected )
1805 {
1806 dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
1807 }
1808 else
1809 {
1810 dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
1811 }
52d6f640 1812 }
ab79958a
VZ
1813 else
1814 {
ec157c8f 1815 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxSOLID));
ab79958a
VZ
1816 }
1817
1818 dc.SetPen( *wxTRANSPARENT_PEN );
ab79958a
VZ
1819 dc.DrawRectangle(rect);
1820}
1821
508011ce
VZ
1822// ----------------------------------------------------------------------------
1823// wxGridCellStringRenderer
1824// ----------------------------------------------------------------------------
1825
fbfb8bcc
VZ
1826void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid& grid,
1827 const wxGridCellAttr& attr,
816be743
VZ
1828 wxDC& dc,
1829 bool isSelected)
ab79958a 1830{
ab79958a
VZ
1831 dc.SetBackgroundMode( wxTRANSPARENT );
1832
283b7808
VZ
1833 // TODO some special colours for attr.IsReadOnly() case?
1834
04418332 1835 // different coloured text when the grid is disabled
4db6714b 1836 if ( grid.IsEnabled() )
ab79958a 1837 {
c2f5b920
DS
1838 if ( isSelected )
1839 {
1840 dc.SetTextBackground( grid.GetSelectionBackground() );
1841 dc.SetTextForeground( grid.GetSelectionForeground() );
1842 }
1843 else
1844 {
1845 dc.SetTextBackground( attr.GetBackgroundColour() );
1846 dc.SetTextForeground( attr.GetTextColour() );
1847 }
ab79958a
VZ
1848 }
1849 else
1850 {
c2f5b920
DS
1851 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
1852 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
ab79958a 1853 }
816be743 1854
2796cce3 1855 dc.SetFont( attr.GetFont() );
816be743
VZ
1856}
1857
fbfb8bcc 1858wxSize wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr& attr,
65e4e78e
VZ
1859 wxDC& dc,
1860 const wxString& text)
1861{
f6bcfd97 1862 wxCoord x = 0, y = 0, max_x = 0;
65e4e78e 1863 dc.SetFont(attr.GetFont());
f6bcfd97
BP
1864 wxStringTokenizer tk(text, _T('\n'));
1865 while ( tk.HasMoreTokens() )
1866 {
1867 dc.GetTextExtent(tk.GetNextToken(), &x, &y);
1868 max_x = wxMax(max_x, x);
1869 }
1870
1871 y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
65e4e78e 1872
f6bcfd97 1873 return wxSize(max_x, y);
65e4e78e
VZ
1874}
1875
1876wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
1877 wxGridCellAttr& attr,
1878 wxDC& dc,
1879 int row, int col)
1880{
1881 return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
1882}
1883
816be743
VZ
1884void wxGridCellStringRenderer::Draw(wxGrid& grid,
1885 wxGridCellAttr& attr,
1886 wxDC& dc,
1887 const wxRect& rectCell,
1888 int row, int col,
1889 bool isSelected)
1890{
27f35b66 1891 wxRect rect = rectCell;
dc1f566f
SN
1892 rect.Inflate(-1);
1893
1894 // erase only this cells background, overflow cells should have been erased
1895 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
1896
1897 int hAlign, vAlign;
1898 attr.GetAlignment(&hAlign, &vAlign);
27f35b66 1899
39b80349
SN
1900 int overflowCols = 0;
1901
27f35b66
SN
1902 if (attr.GetOverflow())
1903 {
1904 int cols = grid.GetNumberCols();
1905 int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
1906 int cell_rows, cell_cols;
2f024384 1907 attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <= 0
27f35b66
SN
1908 if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
1909 {
1910 int i, c_cols, c_rows;
1911 for (i = col+cell_cols; i < cols; i++)
1912 {
ca65c044 1913 bool is_empty = true;
2f024384 1914 for (int j=row; j < row + cell_rows; j++)
27f35b66 1915 {
39b80349 1916 // check w/ anchor cell for multicell block
ef4d6ce8 1917 grid.GetCellSize(j, i, &c_rows, &c_cols);
2f024384
DS
1918 if (c_rows > 0)
1919 c_rows = 0;
1920 if (!grid.GetTable()->IsEmptyCell(j + c_rows, i))
39b80349 1921 {
ca65c044 1922 is_empty = false;
ef4d6ce8 1923 break;
39b80349 1924 }
27f35b66 1925 }
2f024384 1926
39b80349 1927 if (is_empty)
c2f5b920 1928 {
39b80349 1929 rect.width += grid.GetColSize(i);
c2f5b920 1930 }
dc1f566f
SN
1931 else
1932 {
1933 i--;
1934 break;
1935 }
2f024384 1936
4db6714b
KH
1937 if (rect.width >= best_width)
1938 break;
2b5f62a0 1939 }
2f024384 1940
39b80349 1941 overflowCols = i - col - cell_cols + 1;
4db6714b
KH
1942 if (overflowCols >= cols)
1943 overflowCols = cols - 1;
39b80349 1944 }
27f35b66 1945
dc1f566f
SN
1946 if (overflowCols > 0) // redraw overflow cells w/ proper hilight
1947 {
39b80349 1948 hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
2b5f62a0 1949 wxRect clip = rect;
39b80349 1950 clip.x += rectCell.width;
dc1f566f 1951 // draw each overflow cell individually
c2f5b920 1952 int col_end = col + cell_cols + overflowCols;
dc1f566f 1953 if (col_end >= grid.GetNumberCols())
2b5f62a0 1954 col_end = grid.GetNumberCols() - 1;
c2f5b920 1955 for (int i = col + cell_cols; i <= col_end; i++)
dc1f566f 1956 {
dc1f566f
SN
1957 clip.width = grid.GetColSize(i) - 1;
1958 dc.DestroyClippingRegion();
1959 dc.SetClippingRegion(clip);
39b80349
SN
1960
1961 SetTextColoursAndFont(grid, attr, dc,
2b5f62a0 1962 grid.IsInSelection(row,i));
39b80349 1963
dc1f566f 1964 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
2b5f62a0 1965 rect, hAlign, vAlign);
39b80349 1966 clip.x += grid.GetColSize(i) - 1;
dc1f566f 1967 }
ab79958a 1968
39b80349 1969 rect = rectCell;
2b5f62a0 1970 rect.Inflate(-1);
dc1f566f 1971 rect.width++;
39b80349 1972 dc.DestroyClippingRegion();
dc1f566f 1973 }
39b80349 1974 }
ab79958a 1975
dc1f566f
SN
1976 // now we only have to draw the text
1977 SetTextColoursAndFont(grid, attr, dc, isSelected);
39b80349 1978
ab79958a
VZ
1979 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
1980 rect, hAlign, vAlign);
1981}
1982
65e4e78e
VZ
1983// ----------------------------------------------------------------------------
1984// wxGridCellNumberRenderer
1985// ----------------------------------------------------------------------------
1986
fbfb8bcc 1987wxString wxGridCellNumberRenderer::GetString(const wxGrid& grid, int row, int col)
65e4e78e
VZ
1988{
1989 wxGridTableBase *table = grid.GetTable();
1990 wxString text;
1991 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
1992 {
1993 text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
1994 }
9c4ba614
VZ
1995 else
1996 {
1997 text = table->GetValue(row, col);
1998 }
65e4e78e
VZ
1999
2000 return text;
2001}
2002
816be743
VZ
2003void wxGridCellNumberRenderer::Draw(wxGrid& grid,
2004 wxGridCellAttr& attr,
2005 wxDC& dc,
2006 const wxRect& rectCell,
2007 int row, int col,
2008 bool isSelected)
2009{
2010 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
2011
2012 SetTextColoursAndFont(grid, attr, dc, isSelected);
2013
2014 // draw the text right aligned by default
2015 int hAlign, vAlign;
2016 attr.GetAlignment(&hAlign, &vAlign);
4c7277db 2017 hAlign = wxALIGN_RIGHT;
816be743
VZ
2018
2019 wxRect rect = rectCell;
2020 rect.Inflate(-1);
2021
65e4e78e
VZ
2022 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
2023}
816be743 2024
65e4e78e
VZ
2025wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
2026 wxGridCellAttr& attr,
2027 wxDC& dc,
2028 int row, int col)
2029{
2030 return DoGetBestSize(attr, dc, GetString(grid, row, col));
816be743
VZ
2031}
2032
2033// ----------------------------------------------------------------------------
2034// wxGridCellFloatRenderer
2035// ----------------------------------------------------------------------------
2036
2037wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
2038{
2039 SetWidth(width);
2040 SetPrecision(precision);
2041}
2042
e72b4213
VZ
2043wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
2044{
2045 wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
2046 renderer->m_width = m_width;
2047 renderer->m_precision = m_precision;
2048 renderer->m_format = m_format;
2049
2050 return renderer;
2051}
2052
fbfb8bcc 2053wxString wxGridCellFloatRenderer::GetString(const wxGrid& grid, int row, int col)
65e4e78e
VZ
2054{
2055 wxGridTableBase *table = grid.GetTable();
0b190b0f
VZ
2056
2057 bool hasDouble;
2058 double val;
65e4e78e
VZ
2059 wxString text;
2060 if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
2061 {
0b190b0f 2062 val = table->GetValueAsDouble(row, col);
ca65c044 2063 hasDouble = true;
65e4e78e 2064 }
9c4ba614
VZ
2065 else
2066 {
2067 text = table->GetValue(row, col);
0b190b0f 2068 hasDouble = text.ToDouble(&val);
9c4ba614 2069 }
65e4e78e 2070
0b190b0f
VZ
2071 if ( hasDouble )
2072 {
2073 if ( !m_format )
2074 {
2075 if ( m_width == -1 )
2076 {
19d7140e
VZ
2077 if ( m_precision == -1 )
2078 {
2b5f62a0
VZ
2079 // default width/precision
2080 m_format = _T("%f");
2081 }
19d7140e
VZ
2082 else
2083 {
2084 m_format.Printf(_T("%%.%df"), m_precision);
2085 }
0b190b0f
VZ
2086 }
2087 else if ( m_precision == -1 )
2088 {
2089 // default precision
2090 m_format.Printf(_T("%%%d.f"), m_width);
2091 }
2092 else
2093 {
2094 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
2095 }
2096 }
2097
2098 text.Printf(m_format, val);
19d7140e 2099
0b190b0f
VZ
2100 }
2101 //else: text already contains the string
2102
65e4e78e
VZ
2103 return text;
2104}
2105
816be743
VZ
2106void wxGridCellFloatRenderer::Draw(wxGrid& grid,
2107 wxGridCellAttr& attr,
2108 wxDC& dc,
2109 const wxRect& rectCell,
2110 int row, int col,
2111 bool isSelected)
2112{
2113 wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
2114
2115 SetTextColoursAndFont(grid, attr, dc, isSelected);
2116
2117 // draw the text right aligned by default
2118 int hAlign, vAlign;
2119 attr.GetAlignment(&hAlign, &vAlign);
4c7277db 2120 hAlign = wxALIGN_RIGHT;
816be743
VZ
2121
2122 wxRect rect = rectCell;
2123 rect.Inflate(-1);
2124
65e4e78e
VZ
2125 grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
2126}
816be743 2127
65e4e78e
VZ
2128wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
2129 wxGridCellAttr& attr,
2130 wxDC& dc,
2131 int row, int col)
2132{
2133 return DoGetBestSize(attr, dc, GetString(grid, row, col));
816be743
VZ
2134}
2135
0b190b0f
VZ
2136void wxGridCellFloatRenderer::SetParameters(const wxString& params)
2137{
0b190b0f
VZ
2138 if ( !params )
2139 {
2140 // reset to defaults
2141 SetWidth(-1);
2142 SetPrecision(-1);
2143 }
2144 else
2145 {
2146 wxString tmp = params.BeforeFirst(_T(','));
ec157c8f 2147 if ( !tmp.empty() )
0b190b0f
VZ
2148 {
2149 long width;
19d7140e 2150 if ( tmp.ToLong(&width) )
0b190b0f 2151 {
19d7140e 2152 SetWidth((int)width);
0b190b0f
VZ
2153 }
2154 else
2155 {
19d7140e
VZ
2156 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
2157 }
19d7140e 2158 }
2f024384 2159
7448de8d
WS
2160 tmp = params.AfterFirst(_T(','));
2161 if ( !tmp.empty() )
2162 {
2163 long precision;
19d7140e 2164 if ( tmp.ToLong(&precision) )
7448de8d 2165 {
19d7140e 2166 SetPrecision((int)precision);
7448de8d
WS
2167 }
2168 else
2169 {
19d7140e 2170 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
7448de8d 2171 }
0b190b0f
VZ
2172 }
2173 }
2174}
2175
508011ce
VZ
2176// ----------------------------------------------------------------------------
2177// wxGridCellBoolRenderer
2178// ----------------------------------------------------------------------------
2179
65e4e78e 2180wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
508011ce 2181
b94ae1ea
VZ
2182// FIXME these checkbox size calculations are really ugly...
2183
65e4e78e 2184// between checkmark and box
a95e38c0 2185static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
508011ce 2186
65e4e78e
VZ
2187wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
2188 wxGridCellAttr& WXUNUSED(attr),
2189 wxDC& WXUNUSED(dc),
2190 int WXUNUSED(row),
2191 int WXUNUSED(col))
2192{
2193 // compute it only once (no locks for MT safeness in GUI thread...)
2194 if ( !ms_sizeCheckMark.x )
297da4ba 2195 {
65e4e78e 2196 // get checkbox size
ca65c044 2197 wxCheckBox *checkbox = new wxCheckBox(&grid, wxID_ANY, wxEmptyString);
297da4ba 2198 wxSize size = checkbox->GetBestSize();
2f024384 2199 wxCoord checkSize = size.y + 2 * wxGRID_CHECKMARK_MARGIN;
297da4ba 2200
65e4e78e 2201 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
69d8f612 2202#if defined(__WXGTK__) || defined(__WXMOTIF__)
65e4e78e 2203 checkSize -= size.y / 2;
297da4ba
VZ
2204#endif
2205
2206 delete checkbox;
65e4e78e
VZ
2207
2208 ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
297da4ba
VZ
2209 }
2210
65e4e78e
VZ
2211 return ms_sizeCheckMark;
2212}
2213
2214void wxGridCellBoolRenderer::Draw(wxGrid& grid,
2215 wxGridCellAttr& attr,
2216 wxDC& dc,
2217 const wxRect& rect,
2218 int row, int col,
2219 bool isSelected)
2220{
2221 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
2222
297da4ba 2223 // draw a check mark in the centre (ignoring alignment - TODO)
65e4e78e 2224 wxSize size = GetBestSize(grid, attr, dc, row, col);
b94ae1ea
VZ
2225
2226 // don't draw outside the cell
2227 wxCoord minSize = wxMin(rect.width, rect.height);
2228 if ( size.x >= minSize || size.y >= minSize )
2229 {
2230 // and even leave (at least) 1 pixel margin
2231 size.x = size.y = minSize - 2;
2232 }
2233
2234 // draw a border around checkmark
1bd71df9 2235 int vAlign, hAlign;
c2f5b920 2236 attr.GetAlignment(&hAlign, &vAlign);
52d6f640 2237
a95e38c0 2238 wxRect rectBorder;
1bd71df9
JS
2239 if (hAlign == wxALIGN_CENTRE)
2240 {
2f024384
DS
2241 rectBorder.x = rect.x + rect.width / 2 - size.x / 2;
2242 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
1bd71df9
JS
2243 rectBorder.width = size.x;
2244 rectBorder.height = size.y;
2245 }
2246 else if (hAlign == wxALIGN_LEFT)
2247 {
2248 rectBorder.x = rect.x + 2;
2f024384 2249 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
1bd71df9 2250 rectBorder.width = size.x;
52d6f640 2251 rectBorder.height = size.y;
1bd71df9
JS
2252 }
2253 else if (hAlign == wxALIGN_RIGHT)
2254 {
2255 rectBorder.x = rect.x + rect.width - size.x - 2;
2f024384 2256 rectBorder.y = rect.y + rect.height / 2 - size.y / 2;
1bd71df9 2257 rectBorder.width = size.x;
52d6f640 2258 rectBorder.height = size.y;
1bd71df9 2259 }
b94ae1ea 2260
f2d76237 2261 bool value;
b94ae1ea 2262 if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
c2f5b920 2263 {
f2d76237 2264 value = grid.GetTable()->GetValueAsBool(row, col);
c2f5b920 2265 }
f2d76237 2266 else
695a3263
MB
2267 {
2268 wxString cellval( grid.GetTable()->GetValue(row, col) );
9c71a138 2269 value = wxGridCellBoolEditor::IsTrueValue(cellval);
695a3263 2270 }
f2d76237
RD
2271
2272 if ( value )
508011ce 2273 {
a95e38c0 2274 wxRect rectMark = rectBorder;
2f024384 2275
a95e38c0
VZ
2276#ifdef __WXMSW__
2277 // MSW DrawCheckMark() is weird (and should probably be changed...)
2f024384 2278 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN / 2);
a95e38c0
VZ
2279 rectMark.x++;
2280 rectMark.y++;
2f024384 2281#else
a95e38c0 2282 rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
2f024384 2283#endif
a95e38c0 2284
508011ce
VZ
2285 dc.SetTextForeground(attr.GetTextColour());
2286 dc.DrawCheckMark(rectMark);
2287 }
a95e38c0
VZ
2288
2289 dc.SetBrush(*wxTRANSPARENT_BRUSH);
2290 dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
2291 dc.DrawRectangle(rectBorder);
508011ce
VZ
2292}
2293
2796cce3
RD
2294// ----------------------------------------------------------------------------
2295// wxGridCellAttr
2296// ----------------------------------------------------------------------------
2297
1df4050d
VZ
2298void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
2299{
2300 m_nRef = 1;
2301
2302 m_isReadOnly = Unset;
2303
2304 m_renderer = NULL;
2305 m_editor = NULL;
2306
2307 m_attrkind = wxGridCellAttr::Cell;
2308
27f35b66 2309 m_sizeRows = m_sizeCols = 1;
b63fce94 2310 m_overflow = UnsetOverflow;
27f35b66 2311
1df4050d
VZ
2312 SetDefAttr(attrDefault);
2313}
2314
39bcce60 2315wxGridCellAttr *wxGridCellAttr::Clone() const
a68c1246 2316{
1df4050d
VZ
2317 wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr);
2318
a68c1246
VZ
2319 if ( HasTextColour() )
2320 attr->SetTextColour(GetTextColour());
2321 if ( HasBackgroundColour() )
2322 attr->SetBackgroundColour(GetBackgroundColour());
2323 if ( HasFont() )
2324 attr->SetFont(GetFont());
2325 if ( HasAlignment() )
2326 attr->SetAlignment(m_hAlign, m_vAlign);
2327
27f35b66
SN
2328 attr->SetSize( m_sizeRows, m_sizeCols );
2329
a68c1246
VZ
2330 if ( m_renderer )
2331 {
2332 attr->SetRenderer(m_renderer);
39bcce60 2333 m_renderer->IncRef();
a68c1246
VZ
2334 }
2335 if ( m_editor )
2336 {
2337 attr->SetEditor(m_editor);
39bcce60 2338 m_editor->IncRef();
a68c1246
VZ
2339 }
2340
2341 if ( IsReadOnly() )
2342 attr->SetReadOnly();
2343
dfd7c082 2344 attr->SetOverflow( m_overflow == Overflow );
19d7140e
VZ
2345 attr->SetKind( m_attrkind );
2346
a68c1246
VZ
2347 return attr;
2348}
2349
19d7140e
VZ
2350void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom)
2351{
2352 if ( !HasTextColour() && mergefrom->HasTextColour() )
2353 SetTextColour(mergefrom->GetTextColour());
2354 if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() )
2355 SetBackgroundColour(mergefrom->GetBackgroundColour());
2356 if ( !HasFont() && mergefrom->HasFont() )
2357 SetFont(mergefrom->GetFont());
4db6714b
KH
2358 if ( !HasAlignment() && mergefrom->HasAlignment() )
2359 {
19d7140e
VZ
2360 int hAlign, vAlign;
2361 mergefrom->GetAlignment( &hAlign, &vAlign);
2362 SetAlignment(hAlign, vAlign);
2363 }
3100c3db
RD
2364 if ( !HasSize() && mergefrom->HasSize() )
2365 mergefrom->GetSize( &m_sizeRows, &m_sizeCols );
27f35b66 2366
19d7140e
VZ
2367 // Directly access member functions as GetRender/Editor don't just return
2368 // m_renderer/m_editor
2369 //
2370 // Maybe add support for merge of Render and Editor?
2371 if (!HasRenderer() && mergefrom->HasRenderer() )
bf7945ce 2372 {
19d7140e
VZ
2373 m_renderer = mergefrom->m_renderer;
2374 m_renderer->IncRef();
2375 }
2376 if ( !HasEditor() && mergefrom->HasEditor() )
2377 {
2378 m_editor = mergefrom->m_editor;
2379 m_editor->IncRef();
2380 }
2f024384 2381 if ( !HasReadWriteMode() && mergefrom->HasReadWriteMode() )
19d7140e
VZ
2382 SetReadOnly(mergefrom->IsReadOnly());
2383
2f024384 2384 if (!HasOverflowMode() && mergefrom->HasOverflowMode() )
ff699386 2385 SetOverflow(mergefrom->GetOverflow());
ef5df12b 2386
19d7140e
VZ
2387 SetDefAttr(mergefrom->m_defGridAttr);
2388}
2389
27f35b66
SN
2390void wxGridCellAttr::SetSize(int num_rows, int num_cols)
2391{
2392 // The size of a cell is normally 1,1
2393
2394 // If this cell is larger (2,2) then this is the top left cell
2395 // the other cells that will be covered (lower right cells) must be
2396 // set to negative or zero values such that
2397 // row + num_rows of the covered cell points to the larger cell (this cell)
2398 // same goes for the col + num_cols.
2399
2400 // Size of 0,0 is NOT valid, neither is <=0 and any positive value
2401
2f024384
DS
2402 wxASSERT_MSG( (!((num_rows > 0) && (num_cols <= 0)) ||
2403 !((num_rows <= 0) && (num_cols > 0)) ||
2404 !((num_rows == 0) && (num_cols == 0))),
27f35b66
SN
2405 wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
2406
2407 m_sizeRows = num_rows;
2408 m_sizeCols = num_cols;
2409}
2410
2796cce3
RD
2411const wxColour& wxGridCellAttr::GetTextColour() const
2412{
2413 if (HasTextColour())
508011ce 2414 {
2796cce3 2415 return m_colText;
508011ce 2416 }
0926b2fc 2417 else if (m_defGridAttr && m_defGridAttr != this)
508011ce 2418 {
2796cce3 2419 return m_defGridAttr->GetTextColour();
508011ce
VZ
2420 }
2421 else
2422 {
2796cce3
RD
2423 wxFAIL_MSG(wxT("Missing default cell attribute"));
2424 return wxNullColour;
2425 }
2426}
2427
2796cce3
RD
2428const wxColour& wxGridCellAttr::GetBackgroundColour() const
2429{
2430 if (HasBackgroundColour())
2f024384 2431 {
2796cce3 2432 return m_colBack;
2f024384 2433 }
0926b2fc 2434 else if (m_defGridAttr && m_defGridAttr != this)
2f024384 2435 {
2796cce3 2436 return m_defGridAttr->GetBackgroundColour();
2f024384 2437 }
508011ce
VZ
2438 else
2439 {
2796cce3
RD
2440 wxFAIL_MSG(wxT("Missing default cell attribute"));
2441 return wxNullColour;
2442 }
2443}
2444
2796cce3
RD
2445const wxFont& wxGridCellAttr::GetFont() const
2446{
2447 if (HasFont())
2f024384 2448 {
2796cce3 2449 return m_font;
2f024384 2450 }
0926b2fc 2451 else if (m_defGridAttr && m_defGridAttr != this)
2f024384 2452 {
2796cce3 2453 return m_defGridAttr->GetFont();
2f024384 2454 }
508011ce
VZ
2455 else
2456 {
2796cce3
RD
2457 wxFAIL_MSG(wxT("Missing default cell attribute"));
2458 return wxNullFont;
2459 }
2460}
2461
2796cce3
RD
2462void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
2463{
508011ce
VZ
2464 if (HasAlignment())
2465 {
4db6714b
KH
2466 if ( hAlign )
2467 *hAlign = m_hAlign;
2468 if ( vAlign )
2469 *vAlign = m_vAlign;
2796cce3 2470 }
0926b2fc 2471 else if (m_defGridAttr && m_defGridAttr != this)
c2f5b920 2472 {
2796cce3 2473 m_defGridAttr->GetAlignment(hAlign, vAlign);
c2f5b920 2474 }
508011ce
VZ
2475 else
2476 {
2796cce3
RD
2477 wxFAIL_MSG(wxT("Missing default cell attribute"));
2478 }
2479}
2480
27f35b66
SN
2481void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const
2482{
4db6714b
KH
2483 if ( num_rows )
2484 *num_rows = m_sizeRows;
2485 if ( num_cols )
2486 *num_cols = m_sizeCols;
27f35b66 2487}
2796cce3 2488
f2d76237 2489// GetRenderer and GetEditor use a slightly different decision path about
28a77bc4
RD
2490// which attribute to use. If a non-default attr object has one then it is
2491// used, otherwise the default editor or renderer is fetched from the grid and
2492// used. It should be the default for the data type of the cell. If it is
2493// NULL (because the table has a type that the grid does not have in its
c2f5b920 2494// registry), then the grid's default editor or renderer is used.
28a77bc4 2495
ef316e23 2496wxGridCellRenderer* wxGridCellAttr::GetRenderer(const wxGrid* grid, int row, int col) const
28a77bc4 2497{
c2f5b920 2498 wxGridCellRenderer *renderer = NULL;
28a77bc4 2499
3cf883a2 2500 if ( m_renderer && this != m_defGridAttr )
0b190b0f 2501 {
3cf883a2
VZ
2502 // use the cells renderer if it has one
2503 renderer = m_renderer;
2504 renderer->IncRef();
0b190b0f 2505 }
2f024384 2506 else // no non-default cell renderer
0b190b0f 2507 {
3cf883a2
VZ
2508 // get default renderer for the data type
2509 if ( grid )
2510 {
2511 // GetDefaultRendererForCell() will do IncRef() for us
2512 renderer = grid->GetDefaultRendererForCell(row, col);
2513 }
0b190b0f 2514
c2f5b920 2515 if ( renderer == NULL )
3cf883a2 2516 {
c2f5b920 2517 if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) )
3cf883a2
VZ
2518 {
2519 // if we still don't have one then use the grid default
2520 // (no need for IncRef() here neither)
2521 renderer = m_defGridAttr->GetRenderer(NULL, 0, 0);
2522 }
2523 else // default grid attr
2524 {
2525 // use m_renderer which we had decided not to use initially
2526 renderer = m_renderer;
2527 if ( renderer )
2528 renderer->IncRef();
2529 }
2530 }
0b190b0f 2531 }
28a77bc4 2532
3cf883a2
VZ
2533 // we're supposed to always find something
2534 wxASSERT_MSG(renderer, wxT("Missing default cell renderer"));
28a77bc4
RD
2535
2536 return renderer;
2796cce3
RD
2537}
2538
3cf883a2 2539// same as above, except for s/renderer/editor/g
ef316e23 2540wxGridCellEditor* wxGridCellAttr::GetEditor(const wxGrid* grid, int row, int col) const
07296f0b 2541{
c2f5b920 2542 wxGridCellEditor *editor = NULL;
0b190b0f 2543
3cf883a2 2544 if ( m_editor && this != m_defGridAttr )
0b190b0f 2545 {
3cf883a2
VZ
2546 // use the cells editor if it has one
2547 editor = m_editor;
2548 editor->IncRef();
0b190b0f 2549 }
3cf883a2 2550 else // no non default cell editor
0b190b0f 2551 {
3cf883a2
VZ
2552 // get default editor for the data type
2553 if ( grid )
2554 {
2555 // GetDefaultEditorForCell() will do IncRef() for us
2556 editor = grid->GetDefaultEditorForCell(row, col);
2557 }
3cf883a2 2558
c2f5b920 2559 if ( editor == NULL )
3cf883a2 2560 {
c2f5b920 2561 if ( (m_defGridAttr != NULL) && (m_defGridAttr != this) )
3cf883a2
VZ
2562 {
2563 // if we still don't have one then use the grid default
2564 // (no need for IncRef() here neither)
2565 editor = m_defGridAttr->GetEditor(NULL, 0, 0);
2566 }
2567 else // default grid attr
2568 {
2569 // use m_editor which we had decided not to use initially
2570 editor = m_editor;
2571 if ( editor )
2572 editor->IncRef();
2573 }
2574 }
0b190b0f 2575 }
28a77bc4 2576
3cf883a2
VZ
2577 // we're supposed to always find something
2578 wxASSERT_MSG(editor, wxT("Missing default cell editor"));
2579
28a77bc4 2580 return editor;
07296f0b
RD
2581}
2582
b99be8fb 2583// ----------------------------------------------------------------------------
758cbedf 2584// wxGridCellAttrData
b99be8fb
VZ
2585// ----------------------------------------------------------------------------
2586
758cbedf 2587void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
b99be8fb
VZ
2588{
2589 int n = FindIndex(row, col);
2590 if ( n == wxNOT_FOUND )
2591 {
2592 // add the attribute
2593 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
2594 }
2595 else
2596 {
6f36917b
VZ
2597 // free the old attribute
2598 m_attrs[(size_t)n].attr->DecRef();
2599
b99be8fb
VZ
2600 if ( attr )
2601 {
2602 // change the attribute
2e9a6788 2603 m_attrs[(size_t)n].attr = attr;
b99be8fb
VZ
2604 }
2605 else
2606 {
2607 // remove this attribute
2608 m_attrs.RemoveAt((size_t)n);
2609 }
2610 }
b99be8fb
VZ
2611}
2612
758cbedf 2613wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
b99be8fb
VZ
2614{
2615 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2616
2617 int n = FindIndex(row, col);
2618 if ( n != wxNOT_FOUND )
2619 {
2e9a6788
VZ
2620 attr = m_attrs[(size_t)n].attr;
2621 attr->IncRef();
b99be8fb
VZ
2622 }
2623
2624 return attr;
2625}
2626
4d60017a
SN
2627void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
2628{
2629 size_t count = m_attrs.GetCount();
2630 for ( size_t n = 0; n < count; n++ )
2631 {
2632 wxGridCellCoords& coords = m_attrs[n].coords;
d1c0b4f9
VZ
2633 wxCoord row = coords.GetRow();
2634 if ((size_t)row >= pos)
2635 {
2636 if (numRows > 0)
2637 {
2638 // If rows inserted, include row counter where necessary
2639 coords.SetRow(row + numRows);
2640 }
2641 else if (numRows < 0)
2642 {
2643 // If rows deleted ...
2644 if ((size_t)row >= pos - numRows)
2645 {
2646 // ...either decrement row counter (if row still exists)...
2647 coords.SetRow(row + numRows);
2648 }
2649 else
2650 {
2651 // ...or remove the attribute
d3e9dd94
SN
2652 // No need to DecRef the attribute itself since this is
2653 // done be wxGridCellWithAttr's destructor!
01dd42b6 2654 m_attrs.RemoveAt(n);
4db6714b
KH
2655 n--;
2656 count--;
d1c0b4f9
VZ
2657 }
2658 }
4d60017a
SN
2659 }
2660 }
2661}
2662
2663void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
2664{
2665 size_t count = m_attrs.GetCount();
2666 for ( size_t n = 0; n < count; n++ )
2667 {
2668 wxGridCellCoords& coords = m_attrs[n].coords;
d1c0b4f9
VZ
2669 wxCoord col = coords.GetCol();
2670 if ( (size_t)col >= pos )
2671 {
2672 if ( numCols > 0 )
2673 {
2674 // If rows inserted, include row counter where necessary
2675 coords.SetCol(col + numCols);
2676 }
2677 else if (numCols < 0)
2678 {
2679 // If rows deleted ...
2680 if ((size_t)col >= pos - numCols)
2681 {
2682 // ...either decrement row counter (if row still exists)...
2683 coords.SetCol(col + numCols);
2684 }
2685 else
2686 {
2687 // ...or remove the attribute
d3e9dd94
SN
2688 // No need to DecRef the attribute itself since this is
2689 // done be wxGridCellWithAttr's destructor!
01dd42b6 2690 m_attrs.RemoveAt(n);
2f024384
DS
2691 n--;
2692 count--;
d1c0b4f9
VZ
2693 }
2694 }
4d60017a
SN
2695 }
2696 }
2697}
2698
758cbedf 2699int wxGridCellAttrData::FindIndex(int row, int col) const
b99be8fb
VZ
2700{
2701 size_t count = m_attrs.GetCount();
2702 for ( size_t n = 0; n < count; n++ )
2703 {
2704 const wxGridCellCoords& coords = m_attrs[n].coords;
2705 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
2706 {
2707 return n;
2708 }
2709 }
2710
2711 return wxNOT_FOUND;
2712}
2713
758cbedf
VZ
2714// ----------------------------------------------------------------------------
2715// wxGridRowOrColAttrData
2716// ----------------------------------------------------------------------------
2717
2718wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
2719{
2720 size_t count = m_attrs.Count();
2721 for ( size_t n = 0; n < count; n++ )
2722 {
2723 m_attrs[n]->DecRef();
2724 }
2725}
2726
2727wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
2728{
2729 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2730
2731 int n = m_rowsOrCols.Index(rowOrCol);
2732 if ( n != wxNOT_FOUND )
2733 {
2734 attr = m_attrs[(size_t)n];
2735 attr->IncRef();
2736 }
2737
2738 return attr;
2739}
2740
2741void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
2742{
a95e38c0
VZ
2743 int i = m_rowsOrCols.Index(rowOrCol);
2744 if ( i == wxNOT_FOUND )
758cbedf
VZ
2745 {
2746 // add the attribute
2747 m_rowsOrCols.Add(rowOrCol);
2748 m_attrs.Add(attr);
2749 }
2750 else
2751 {
a95e38c0 2752 size_t n = (size_t)i;
758cbedf
VZ
2753 if ( attr )
2754 {
2755 // change the attribute
a95e38c0
VZ
2756 m_attrs[n]->DecRef();
2757 m_attrs[n] = attr;
758cbedf
VZ
2758 }
2759 else
2760 {
2761 // remove this attribute
a95e38c0
VZ
2762 m_attrs[n]->DecRef();
2763 m_rowsOrCols.RemoveAt(n);
2764 m_attrs.RemoveAt(n);
758cbedf
VZ
2765 }
2766 }
2767}
2768
4d60017a
SN
2769void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
2770{
2771 size_t count = m_attrs.GetCount();
2772 for ( size_t n = 0; n < count; n++ )
2773 {
2774 int & rowOrCol = m_rowsOrCols[n];
d1c0b4f9
VZ
2775 if ( (size_t)rowOrCol >= pos )
2776 {
2777 if ( numRowsOrCols > 0 )
2778 {
2779 // If rows inserted, include row counter where necessary
2780 rowOrCol += numRowsOrCols;
2781 }
2782 else if ( numRowsOrCols < 0)
2783 {
2784 // If rows deleted, either decrement row counter (if row still exists)
2785 if ((size_t)rowOrCol >= pos - numRowsOrCols)
2786 rowOrCol += numRowsOrCols;
2787 else
2788 {
01dd42b6
VZ
2789 m_rowsOrCols.RemoveAt(n);
2790 m_attrs[n]->DecRef();
2791 m_attrs.RemoveAt(n);
4db6714b
KH
2792 n--;
2793 count--;
d1c0b4f9
VZ
2794 }
2795 }
4d60017a
SN
2796 }
2797 }
2798}
2799
b99be8fb
VZ
2800// ----------------------------------------------------------------------------
2801// wxGridCellAttrProvider
2802// ----------------------------------------------------------------------------
2803
2804wxGridCellAttrProvider::wxGridCellAttrProvider()
2805{
2806 m_data = (wxGridCellAttrProviderData *)NULL;
2807}
2808
2809wxGridCellAttrProvider::~wxGridCellAttrProvider()
2810{
2811 delete m_data;
2812}
2813
2814void wxGridCellAttrProvider::InitData()
2815{
2816 m_data = new wxGridCellAttrProviderData;
2817}
2818
19d7140e
VZ
2819wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col,
2820 wxGridCellAttr::wxAttrKind kind ) const
b99be8fb 2821{
758cbedf
VZ
2822 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
2823 if ( m_data )
2824 {
962a48f6 2825 switch (kind)
758cbedf 2826 {
19d7140e 2827 case (wxGridCellAttr::Any):
962a48f6
DS
2828 // Get cached merge attributes.
2829 // Currently not used as no cache implemented as not mutable
19d7140e 2830 // attr = m_data->m_mergeAttr.GetAttr(row, col);
4db6714b 2831 if (!attr)
19d7140e 2832 {
962a48f6
DS
2833 // Basically implement old version.
2834 // Also check merge cache, so we don't have to re-merge every time..
999836aa
VZ
2835 wxGridCellAttr *attrcell = m_data->m_cellAttrs.GetAttr(row, col);
2836 wxGridCellAttr *attrrow = m_data->m_rowAttrs.GetAttr(row);
2837 wxGridCellAttr *attrcol = m_data->m_colAttrs.GetAttr(col);
19d7140e 2838
4db6714b
KH
2839 if ((attrcell != attrrow) && (attrrow != attrcol) && (attrcell != attrcol))
2840 {
2d0c2e79 2841 // Two or more are non NULL
19d7140e
VZ
2842 attr = new wxGridCellAttr;
2843 attr->SetKind(wxGridCellAttr::Merged);
2844
962a48f6 2845 // Order is important..
4db6714b
KH
2846 if (attrcell)
2847 {
19d7140e
VZ
2848 attr->MergeWith(attrcell);
2849 attrcell->DecRef();
2850 }
4db6714b
KH
2851 if (attrcol)
2852 {
19d7140e
VZ
2853 attr->MergeWith(attrcol);
2854 attrcol->DecRef();
2855 }
4db6714b
KH
2856 if (attrrow)
2857 {
19d7140e
VZ
2858 attr->MergeWith(attrrow);
2859 attrrow->DecRef();
2860 }
962a48f6
DS
2861
2862 // store merge attr if cache implemented
19d7140e
VZ
2863 //attr->IncRef();
2864 //m_data->m_mergeAttr.SetAttr(attr, row, col);
2865 }
2866 else
2d0c2e79 2867 {
19d7140e 2868 // one or none is non null return it or null.
4db6714b
KH
2869 if (attrrow)
2870 attr = attrrow;
2871 if (attrcol)
2d0c2e79 2872 {
962a48f6 2873 if (attr)
2d0c2e79
RD
2874 attr->DecRef();
2875 attr = attrcol;
2876 }
4db6714b 2877 if (attrcell)
2d0c2e79 2878 {
4db6714b 2879 if (attr)
2d0c2e79
RD
2880 attr->DecRef();
2881 attr = attrcell;
2882 }
19d7140e
VZ
2883 }
2884 }
2f024384 2885 break;
4db6714b 2886
19d7140e
VZ
2887 case (wxGridCellAttr::Cell):
2888 attr = m_data->m_cellAttrs.GetAttr(row, col);
2f024384 2889 break;
4db6714b 2890
19d7140e 2891 case (wxGridCellAttr::Col):
2d0c2e79 2892 attr = m_data->m_colAttrs.GetAttr(col);
2f024384 2893 break;
4db6714b 2894
19d7140e 2895 case (wxGridCellAttr::Row):
2d0c2e79 2896 attr = m_data->m_rowAttrs.GetAttr(row);
2f024384 2897 break;
4db6714b 2898
19d7140e
VZ
2899 default:
2900 // unused as yet...
2901 // (wxGridCellAttr::Default):
2902 // (wxGridCellAttr::Merged):
2f024384 2903 break;
758cbedf
VZ
2904 }
2905 }
2f024384 2906
758cbedf 2907 return attr;
b99be8fb
VZ
2908}
2909
2e9a6788 2910void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
b99be8fb
VZ
2911 int row, int col)
2912{
2913 if ( !m_data )
2914 InitData();
2915
758cbedf
VZ
2916 m_data->m_cellAttrs.SetAttr(attr, row, col);
2917}
2918
2919void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
2920{
2921 if ( !m_data )
2922 InitData();
2923
2924 m_data->m_rowAttrs.SetAttr(attr, row);
2925}
2926
2927void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
2928{
2929 if ( !m_data )
2930 InitData();
2931
2932 m_data->m_colAttrs.SetAttr(attr, col);
b99be8fb
VZ
2933}
2934
4d60017a
SN
2935void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
2936{
2937 if ( m_data )
2938 {
2939 m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
2940
d1c0b4f9 2941 m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
4d60017a
SN
2942 }
2943}
2944
2945void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
2946{
2947 if ( m_data )
2948 {
2949 m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
2950
d1c0b4f9 2951 m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
4d60017a
SN
2952 }
2953}
2954
f2d76237
RD
2955// ----------------------------------------------------------------------------
2956// wxGridTypeRegistry
2957// ----------------------------------------------------------------------------
2958
2959wxGridTypeRegistry::~wxGridTypeRegistry()
2960{
b94ae1ea
VZ
2961 size_t count = m_typeinfo.Count();
2962 for ( size_t i = 0; i < count; i++ )
f2d76237
RD
2963 delete m_typeinfo[i];
2964}
2965
f2d76237
RD
2966void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
2967 wxGridCellRenderer* renderer,
2968 wxGridCellEditor* editor)
2969{
f2d76237
RD
2970 wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
2971
2972 // is it already registered?
c4608a8a 2973 int loc = FindRegisteredDataType(typeName);
39bcce60
VZ
2974 if ( loc != wxNOT_FOUND )
2975 {
f2d76237
RD
2976 delete m_typeinfo[loc];
2977 m_typeinfo[loc] = info;
2978 }
39bcce60
VZ
2979 else
2980 {
f2d76237
RD
2981 m_typeinfo.Add(info);
2982 }
2983}
2984
c4608a8a
VZ
2985int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
2986{
2987 size_t count = m_typeinfo.GetCount();
2988 for ( size_t i = 0; i < count; i++ )
2989 {
2990 if ( typeName == m_typeinfo[i]->m_typeName )
2991 {
2992 return i;
2993 }
2994 }
2995
2996 return wxNOT_FOUND;
2997}
2998
f2d76237
RD
2999int wxGridTypeRegistry::FindDataType(const wxString& typeName)
3000{
c4608a8a
VZ
3001 int index = FindRegisteredDataType(typeName);
3002 if ( index == wxNOT_FOUND )
3003 {
3004 // check whether this is one of the standard ones, in which case
3005 // register it "on the fly"
3a8c693a 3006#if wxUSE_TEXTCTRL
c4608a8a
VZ
3007 if ( typeName == wxGRID_VALUE_STRING )
3008 {
3009 RegisterDataType(wxGRID_VALUE_STRING,
3010 new wxGridCellStringRenderer,
3011 new wxGridCellTextEditor);
4db6714b
KH
3012 }
3013 else
3a8c693a
VZ
3014#endif // wxUSE_TEXTCTRL
3015#if wxUSE_CHECKBOX
3016 if ( typeName == wxGRID_VALUE_BOOL )
c4608a8a
VZ
3017 {
3018 RegisterDataType(wxGRID_VALUE_BOOL,
3019 new wxGridCellBoolRenderer,
3020 new wxGridCellBoolEditor);
4db6714b
KH
3021 }
3022 else
3a8c693a
VZ
3023#endif // wxUSE_CHECKBOX
3024#if wxUSE_TEXTCTRL
3025 if ( typeName == wxGRID_VALUE_NUMBER )
c4608a8a
VZ
3026 {
3027 RegisterDataType(wxGRID_VALUE_NUMBER,
3028 new wxGridCellNumberRenderer,
3029 new wxGridCellNumberEditor);
3030 }
3031 else if ( typeName == wxGRID_VALUE_FLOAT )
3032 {
3033 RegisterDataType(wxGRID_VALUE_FLOAT,
3034 new wxGridCellFloatRenderer,
3035 new wxGridCellFloatEditor);
4db6714b
KH
3036 }
3037 else
3a8c693a
VZ
3038#endif // wxUSE_TEXTCTRL
3039#if wxUSE_COMBOBOX
3040 if ( typeName == wxGRID_VALUE_CHOICE )
c4608a8a
VZ
3041 {
3042 RegisterDataType(wxGRID_VALUE_CHOICE,
3043 new wxGridCellStringRenderer,
3044 new wxGridCellChoiceEditor);
4db6714b
KH
3045 }
3046 else
3a8c693a 3047#endif // wxUSE_COMBOBOX
c4608a8a
VZ
3048 {
3049 return wxNOT_FOUND;
3050 }
f2d76237 3051
c4608a8a
VZ
3052 // we get here only if just added the entry for this type, so return
3053 // the last index
3054 index = m_typeinfo.GetCount() - 1;
3055 }
3056
3057 return index;
3058}
3059
3060int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
3061{
3062 int index = FindDataType(typeName);
3063 if ( index == wxNOT_FOUND )
3064 {
3065 // the first part of the typename is the "real" type, anything after ':'
3066 // are the parameters for the renderer
3067 index = FindDataType(typeName.BeforeFirst(_T(':')));
3068 if ( index == wxNOT_FOUND )
3069 {
3070 return wxNOT_FOUND;
f2d76237 3071 }
c4608a8a
VZ
3072
3073 wxGridCellRenderer *renderer = GetRenderer(index);
3074 wxGridCellRenderer *rendererOld = renderer;
3075 renderer = renderer->Clone();
3076 rendererOld->DecRef();
3077
3078 wxGridCellEditor *editor = GetEditor(index);
3079 wxGridCellEditor *editorOld = editor;
3080 editor = editor->Clone();
3081 editorOld->DecRef();
3082
3083 // do it even if there are no parameters to reset them to defaults
3084 wxString params = typeName.AfterFirst(_T(':'));
3085 renderer->SetParameters(params);
3086 editor->SetParameters(params);
3087
3088 // register the new typename
c4608a8a
VZ
3089 RegisterDataType(typeName, renderer, editor);
3090
3091 // we just registered it, it's the last one
3092 index = m_typeinfo.GetCount() - 1;
f2d76237
RD
3093 }
3094
c4608a8a 3095 return index;
f2d76237
RD
3096}
3097
3098wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
3099{
3100 wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
faec5a43
SN
3101 if (renderer)
3102 renderer->IncRef();
2f024384 3103
f2d76237
RD
3104 return renderer;
3105}
3106
0b190b0f 3107wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
f2d76237
RD
3108{
3109 wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
faec5a43
SN
3110 if (editor)
3111 editor->IncRef();
2f024384 3112
f2d76237
RD
3113 return editor;
3114}
3115
758cbedf
VZ
3116// ----------------------------------------------------------------------------
3117// wxGridTableBase
3118// ----------------------------------------------------------------------------
3119
f85afd4e
MB
3120IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
3121
f85afd4e 3122wxGridTableBase::wxGridTableBase()
f85afd4e
MB
3123{
3124 m_view = (wxGrid *) NULL;
b99be8fb 3125 m_attrProvider = (wxGridCellAttrProvider *) NULL;
f85afd4e
MB
3126}
3127
3128wxGridTableBase::~wxGridTableBase()
3129{
b99be8fb
VZ
3130 delete m_attrProvider;
3131}
3132
3133void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
3134{
3135 delete m_attrProvider;
3136 m_attrProvider = attrProvider;
f85afd4e
MB
3137}
3138
f2d76237
RD
3139bool wxGridTableBase::CanHaveAttributes()
3140{
3141 if ( ! GetAttrProvider() )
3142 {
3143 // use the default attr provider by default
3144 SetAttrProvider(new wxGridCellAttrProvider);
3145 }
2f024384 3146
ca65c044 3147 return true;
f2d76237
RD
3148}
3149
19d7140e 3150wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
b99be8fb
VZ
3151{
3152 if ( m_attrProvider )
19d7140e 3153 return m_attrProvider->GetAttr(row, col, kind);
b99be8fb
VZ
3154 else
3155 return (wxGridCellAttr *)NULL;
3156}
3157
758cbedf 3158void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
b99be8fb
VZ
3159{
3160 if ( m_attrProvider )
3161 {
19d7140e 3162 attr->SetKind(wxGridCellAttr::Cell);
b99be8fb
VZ
3163 m_attrProvider->SetAttr(attr, row, col);
3164 }
3165 else
3166 {
3167 // as we take ownership of the pointer and don't store it, we must
3168 // free it now
39bcce60 3169 wxSafeDecRef(attr);
b99be8fb
VZ
3170 }
3171}
3172
758cbedf
VZ
3173void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
3174{
3175 if ( m_attrProvider )
3176 {
19d7140e 3177 attr->SetKind(wxGridCellAttr::Row);
758cbedf
VZ
3178 m_attrProvider->SetRowAttr(attr, row);
3179 }
3180 else
3181 {
3182 // as we take ownership of the pointer and don't store it, we must
3183 // free it now
39bcce60 3184 wxSafeDecRef(attr);
758cbedf
VZ
3185 }
3186}
3187
3188void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
3189{
3190 if ( m_attrProvider )
3191 {
19d7140e 3192 attr->SetKind(wxGridCellAttr::Col);
758cbedf
VZ
3193 m_attrProvider->SetColAttr(attr, col);
3194 }
3195 else
3196 {
3197 // as we take ownership of the pointer and don't store it, we must
3198 // free it now
39bcce60 3199 wxSafeDecRef(attr);
758cbedf
VZ
3200 }
3201}
3202
aa5e1f75
SN
3203bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
3204 size_t WXUNUSED(numRows) )
f85afd4e 3205{
f6bcfd97 3206 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
8f177c8e 3207
ca65c044 3208 return false;
f85afd4e
MB
3209}
3210
aa5e1f75 3211bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
f85afd4e 3212{
f6bcfd97 3213 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
8f177c8e 3214
ca65c044 3215 return false;
f85afd4e
MB
3216}
3217
aa5e1f75
SN
3218bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
3219 size_t WXUNUSED(numRows) )
f85afd4e 3220{
f6bcfd97 3221 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
8f177c8e 3222
ca65c044 3223 return false;
f85afd4e
MB
3224}
3225
aa5e1f75
SN
3226bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
3227 size_t WXUNUSED(numCols) )
f85afd4e 3228{
f6bcfd97 3229 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
8f177c8e 3230
ca65c044 3231 return false;
f85afd4e
MB
3232}
3233
aa5e1f75 3234bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
f85afd4e 3235{
f6bcfd97 3236 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
8f177c8e 3237
ca65c044 3238 return false;
f85afd4e
MB
3239}
3240
aa5e1f75
SN
3241bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
3242 size_t WXUNUSED(numCols) )
f85afd4e 3243{
f6bcfd97 3244 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
8f177c8e 3245
ca65c044 3246 return false;
f85afd4e
MB
3247}
3248
f85afd4e
MB
3249wxString wxGridTableBase::GetRowLabelValue( int row )
3250{
3251 wxString s;
93763ad5 3252
2f024384
DS
3253 // RD: Starting the rows at zero confuses users,
3254 // no matter how much it makes sense to us geeks.
3255 s << row + 1;
3256
f85afd4e
MB
3257 return s;
3258}
3259
3260wxString wxGridTableBase::GetColLabelValue( int col )
3261{
3262 // default col labels are:
3263 // cols 0 to 25 : A-Z
3264 // cols 26 to 675 : AA-ZZ
3265 // etc.
3266
3267 wxString s;
3268 unsigned int i, n;
3269 for ( n = 1; ; n++ )
3270 {
2f024384
DS
3271 s += (wxChar) (_T('A') + (wxChar)(col % 26));
3272 col = col / 26 - 1;
4db6714b
KH
3273 if ( col < 0 )
3274 break;
f85afd4e
MB
3275 }
3276
3277 // reverse the string...
3278 wxString s2;
3d59537f 3279 for ( i = 0; i < n; i++ )
f85afd4e 3280 {
2f024384 3281 s2 += s[n - i - 1];
f85afd4e
MB
3282 }
3283
3284 return s2;
3285}
3286
f2d76237
RD
3287wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
3288{
816be743 3289 return wxGRID_VALUE_STRING;
f2d76237
RD
3290}
3291
3292bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
3293 const wxString& typeName )
3294{
816be743 3295 return typeName == wxGRID_VALUE_STRING;
f2d76237
RD
3296}
3297
3298bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
3299{
3300 return CanGetValueAs(row, col, typeName);
3301}
3302
3303long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
3304{
3305 return 0;
3306}
3307
3308double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
3309{
3310 return 0.0;
3311}
3312
3313bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
3314{
ca65c044 3315 return false;
f2d76237
RD
3316}
3317
3318void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
3319 long WXUNUSED(value) )
3320{
3321}
3322
3323void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
3324 double WXUNUSED(value) )
3325{
3326}
3327
3328void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
3329 bool WXUNUSED(value) )
3330{
3331}
3332
f2d76237
RD
3333void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3334 const wxString& WXUNUSED(typeName) )
3335{
3336 return NULL;
3337}
3338
3339void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
3340 const wxString& WXUNUSED(typeName),
3341 void* WXUNUSED(value) )
3342{
3343}
3344
f85afd4e
MB
3345//////////////////////////////////////////////////////////////////////
3346//
3347// Message class for the grid table to send requests and notifications
3348// to the grid view
3349//
3350
3351wxGridTableMessage::wxGridTableMessage()
3352{
3353 m_table = (wxGridTableBase *) NULL;
3354 m_id = -1;
3355 m_comInt1 = -1;
3356 m_comInt2 = -1;
3357}
3358
3359wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
3360 int commandInt1, int commandInt2 )
3361{
3362 m_table = table;
3363 m_id = id;
3364 m_comInt1 = commandInt1;
3365 m_comInt2 = commandInt2;
3366}
3367
f85afd4e
MB
3368//////////////////////////////////////////////////////////////////////
3369//
3370// A basic grid table for string data. An object of this class will
3371// created by wxGrid if you don't specify an alternative table class.
3372//
3373
223d09f6 3374WX_DEFINE_OBJARRAY(wxGridStringArray)
f85afd4e
MB
3375
3376IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
3377
3378wxGridStringTable::wxGridStringTable()
3379 : wxGridTableBase()
3380{
3381}
3382
3383wxGridStringTable::wxGridStringTable( int numRows, int numCols )
3384 : wxGridTableBase()
3385{
f85afd4e
MB
3386 m_data.Alloc( numRows );
3387
3388 wxArrayString sa;
3389 sa.Alloc( numCols );
27f35b66 3390 sa.Add( wxEmptyString, numCols );
8f177c8e 3391
27f35b66 3392 m_data.Add( sa, numRows );
f85afd4e
MB
3393}
3394
3395wxGridStringTable::~wxGridStringTable()
3396{
3397}
3398
e32352cf 3399int wxGridStringTable::GetNumberRows()
f85afd4e
MB
3400{
3401 return m_data.GetCount();
3402}
3403
e32352cf 3404int wxGridStringTable::GetNumberCols()
f85afd4e
MB
3405{
3406 if ( m_data.GetCount() > 0 )
3407 return m_data[0].GetCount();
3408 else
3409 return 0;
3410}
3411
3412wxString wxGridStringTable::GetValue( int row, int col )
3413{
3e13956a
RD
3414 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3415 wxEmptyString,
3416 _T("invalid row or column index in wxGridStringTable") );
af547d51 3417
f85afd4e
MB
3418 return m_data[row][col];
3419}
3420
f2d76237 3421void wxGridStringTable::SetValue( int row, int col, const wxString& value )
f85afd4e 3422{
3e13956a
RD
3423 wxCHECK_RET( (row < GetNumberRows()) && (col < GetNumberCols()),
3424 _T("invalid row or column index in wxGridStringTable") );
af547d51 3425
f2d76237 3426 m_data[row][col] = value;
f85afd4e
MB
3427}
3428
3429bool wxGridStringTable::IsEmptyCell( int row, int col )
3430{
3e13956a
RD
3431 wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
3432 true,
af547d51
VZ
3433 _T("invalid row or column index in wxGridStringTable") );
3434
f85afd4e
MB
3435 return (m_data[row][col] == wxEmptyString);
3436}
3437
f85afd4e
MB
3438void wxGridStringTable::Clear()
3439{
3440 int row, col;
3441 int numRows, numCols;
8f177c8e 3442
f85afd4e
MB
3443 numRows = m_data.GetCount();
3444 if ( numRows > 0 )
3445 {
3446 numCols = m_data[0].GetCount();
3447
3d59537f 3448 for ( row = 0; row < numRows; row++ )
f85afd4e 3449 {
3d59537f 3450 for ( col = 0; col < numCols; col++ )
f85afd4e
MB
3451 {
3452 m_data[row][col] = wxEmptyString;
3453 }
3454 }
3455 }
3456}
3457
f85afd4e
MB
3458bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
3459{
f85afd4e 3460 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
3461 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3462 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3463
f85afd4e
MB
3464 if ( pos >= curNumRows )
3465 {
3466 return AppendRows( numRows );
3467 }
8f177c8e 3468
f85afd4e
MB
3469 wxArrayString sa;
3470 sa.Alloc( curNumCols );
27f35b66
SN
3471 sa.Add( wxEmptyString, curNumCols );
3472 m_data.Insert( sa, pos, numRows );
2f024384 3473
f85afd4e
MB
3474 if ( GetView() )
3475 {
3476 wxGridTableMessage msg( this,
3477 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
3478 pos,
3479 numRows );
8f177c8e 3480
f85afd4e
MB
3481 GetView()->ProcessTableMessage( msg );
3482 }
3483
ca65c044 3484 return true;
f85afd4e
MB
3485}
3486
3487bool wxGridStringTable::AppendRows( size_t numRows )
3488{
f85afd4e 3489 size_t curNumRows = m_data.GetCount();
4db6714b
KH
3490 size_t curNumCols = ( curNumRows > 0
3491 ? m_data[0].GetCount()
3492 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3493
f85afd4e
MB
3494 wxArrayString sa;
3495 if ( curNumCols > 0 )
3496 {
3497 sa.Alloc( curNumCols );
27f35b66 3498 sa.Add( wxEmptyString, curNumCols );
f85afd4e 3499 }
8f177c8e 3500
27f35b66 3501 m_data.Add( sa, numRows );
f85afd4e
MB
3502
3503 if ( GetView() )
3504 {
3505 wxGridTableMessage msg( this,
3506 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
3507 numRows );
8f177c8e 3508
f85afd4e
MB
3509 GetView()->ProcessTableMessage( msg );
3510 }
3511
ca65c044 3512 return true;
f85afd4e
MB
3513}
3514
3515bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
3516{
f85afd4e 3517 size_t curNumRows = m_data.GetCount();
8f177c8e 3518
f85afd4e
MB
3519 if ( pos >= curNumRows )
3520 {
e91d2033
VZ
3521 wxFAIL_MSG( wxString::Format
3522 (
3523 wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
3524 (unsigned long)pos,
3525 (unsigned long)numRows,
3526 (unsigned long)curNumRows
3527 ) );
3528
ca65c044 3529 return false;
f85afd4e
MB
3530 }
3531
3532 if ( numRows > curNumRows - pos )
3533 {
3534 numRows = curNumRows - pos;
3535 }
8f177c8e 3536
f85afd4e
MB
3537 if ( numRows >= curNumRows )
3538 {
d57ad377 3539 m_data.Clear();
f85afd4e
MB
3540 }
3541 else
3542 {
27f35b66 3543 m_data.RemoveAt( pos, numRows );
f85afd4e 3544 }
4db6714b 3545
f85afd4e
MB
3546 if ( GetView() )
3547 {
3548 wxGridTableMessage msg( this,
3549 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
3550 pos,
3551 numRows );
8f177c8e 3552
f85afd4e
MB
3553 GetView()->ProcessTableMessage( msg );
3554 }
3555
ca65c044 3556 return true;
f85afd4e
MB
3557}
3558
3559bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
3560{
3561 size_t row, col;
3562
3563 size_t curNumRows = m_data.GetCount();
4db6714b
KH
3564 size_t curNumCols = ( curNumRows > 0
3565 ? m_data[0].GetCount()
3566 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3567
f85afd4e
MB
3568 if ( pos >= curNumCols )
3569 {
3570 return AppendCols( numCols );
3571 }
3572
d4175745
VZ
3573 if ( !m_colLabels.IsEmpty() )
3574 {
3575 m_colLabels.Insert( wxEmptyString, pos, numCols );
3576
3577 size_t i;
3578 for ( i = pos; i < pos + numCols; i++ )
3579 m_colLabels[i] = wxGridTableBase::GetColLabelValue( i );
3580 }
3581
3d59537f 3582 for ( row = 0; row < curNumRows; row++ )
f85afd4e 3583 {
3d59537f 3584 for ( col = pos; col < pos + numCols; col++ )
f85afd4e
MB
3585 {
3586 m_data[row].Insert( wxEmptyString, col );
3587 }
3588 }
4db6714b 3589
f85afd4e
MB
3590 if ( GetView() )
3591 {
3592 wxGridTableMessage msg( this,
3593 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
3594 pos,
3595 numCols );
8f177c8e 3596
f85afd4e
MB
3597 GetView()->ProcessTableMessage( msg );
3598 }
3599
ca65c044 3600 return true;
f85afd4e
MB
3601}
3602
3603bool wxGridStringTable::AppendCols( size_t numCols )
3604{
27f35b66 3605 size_t row;
f85afd4e
MB
3606
3607 size_t curNumRows = m_data.GetCount();
2f024384 3608
f6bcfd97 3609#if 0
f85afd4e
MB
3610 if ( !curNumRows )
3611 {
3612 // TODO: something better than this ?
3613 //
f6bcfd97 3614 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
ca65c044 3615 return false;
f85afd4e 3616 }
f6bcfd97 3617#endif
8f177c8e 3618
3d59537f 3619 for ( row = 0; row < curNumRows; row++ )
f85afd4e 3620 {
27f35b66 3621 m_data[row].Add( wxEmptyString, numCols );
f85afd4e
MB
3622 }
3623
3624 if ( GetView() )
3625 {
3626 wxGridTableMessage msg( this,
3627 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
3628 numCols );
8f177c8e 3629
f85afd4e
MB
3630 GetView()->ProcessTableMessage( msg );
3631 }
3632
ca65c044 3633 return true;
f85afd4e
MB
3634}
3635
3636bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
3637{
27f35b66 3638 size_t row;
f85afd4e
MB
3639
3640 size_t curNumRows = m_data.GetCount();
f6bcfd97
BP
3641 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
3642 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
8f177c8e 3643
f85afd4e
MB
3644 if ( pos >= curNumCols )
3645 {
e91d2033
VZ
3646 wxFAIL_MSG( wxString::Format
3647 (
3648 wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
3649 (unsigned long)pos,
3650 (unsigned long)numCols,
3651 (unsigned long)curNumCols
3652 ) );
ca65c044 3653 return false;
f85afd4e
MB
3654 }
3655
d4175745
VZ
3656 int colID;
3657 if ( GetView() )
3658 colID = GetView()->GetColAt( pos );
3659 else
3660 colID = pos;
3661
3662 if ( numCols > curNumCols - colID )
3663 {
3664 numCols = curNumCols - colID;
3665 }
3666
3667 if ( !m_colLabels.IsEmpty() )
f85afd4e 3668 {
b2df5ddf
VZ
3669 // m_colLabels stores just as many elements as it needs, e.g. if only
3670 // the label of the first column had been set it would have only one
3671 // element and not numCols, so account for it
3672 int nToRm = m_colLabels.size() - colID;
3673 if ( nToRm > 0 )
3674 m_colLabels.RemoveAt( colID, nToRm );
f85afd4e
MB
3675 }
3676
3d59537f 3677 for ( row = 0; row < curNumRows; row++ )
f85afd4e
MB
3678 {
3679 if ( numCols >= curNumCols )
3680 {
dcdce64e 3681 m_data[row].Clear();
f85afd4e
MB
3682 }
3683 else
3684 {
d4175745 3685 m_data[row].RemoveAt( colID, numCols );
f85afd4e
MB
3686 }
3687 }
4db6714b 3688
f85afd4e
MB
3689 if ( GetView() )
3690 {
3691 wxGridTableMessage msg( this,
3692 wxGRIDTABLE_NOTIFY_COLS_DELETED,
3693 pos,
3694 numCols );
8f177c8e 3695
f85afd4e
MB
3696 GetView()->ProcessTableMessage( msg );
3697 }
3698
ca65c044 3699 return true;
f85afd4e
MB
3700}
3701
3702wxString wxGridStringTable::GetRowLabelValue( int row )
3703{
3704 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3705 {
3706 // using default label
3707 //
3708 return wxGridTableBase::GetRowLabelValue( row );
3709 }
3710 else
3711 {
2f024384 3712 return m_rowLabels[row];
f85afd4e
MB
3713 }
3714}
3715
3716wxString wxGridStringTable::GetColLabelValue( int col )
3717{
3718 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3719 {
3720 // using default label
3721 //
3722 return wxGridTableBase::GetColLabelValue( col );
3723 }
3724 else
3725 {
2f024384 3726 return m_colLabels[col];
f85afd4e
MB
3727 }
3728}
3729
3730void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
3731{
3732 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
3733 {
3734 int n = m_rowLabels.GetCount();
3735 int i;
2f024384 3736
3d59537f 3737 for ( i = n; i <= row; i++ )
f85afd4e
MB
3738 {
3739 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
3740 }
3741 }
3742
3743 m_rowLabels[row] = value;
3744}
3745
3746void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
3747{
3748 if ( col > (int)(m_colLabels.GetCount()) - 1 )
3749 {
3750 int n = m_colLabels.GetCount();
3751 int i;
2f024384 3752
3d59537f 3753 for ( i = n; i <= col; i++ )
f85afd4e
MB
3754 {
3755 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
3756 }
3757 }
3758
3759 m_colLabels[col] = value;
3760}
3761
3762
f85afd4e 3763//////////////////////////////////////////////////////////////////////
2d66e025
MB
3764//////////////////////////////////////////////////////////////////////
3765
86033c4b
VZ
3766BEGIN_EVENT_TABLE(wxGridSubwindow, wxWindow)
3767 EVT_MOUSE_CAPTURE_LOST(wxGridSubwindow::OnMouseCaptureLost)
3768END_EVENT_TABLE()
3769
3770void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
3771{
3772 m_owner->CancelMouseCapture();
3773}
3774
2d66e025
MB
3775IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
3776
86033c4b 3777BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxGridSubwindow )
2d66e025 3778 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
a9339fe2 3779 EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel )
2d66e025
MB
3780 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
3781 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
f6bcfd97 3782 EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
a9339fe2 3783 EVT_CHAR( wxGridRowLabelWindow::OnChar )
2d66e025
MB
3784END_EVENT_TABLE()
3785
60ff3b99
VZ
3786wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
3787 wxWindowID id,
2d66e025 3788 const wxPoint &pos, const wxSize &size )
86033c4b 3789 : wxGridSubwindow(parent, id, pos, size)
2d66e025
MB
3790{
3791 m_owner = parent;
3792}
3793
aa5e1f75 3794void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2d66e025
MB
3795{
3796 wxPaintDC dc(this);
3797
3798 // NO - don't do this because it will set both the x and y origin
3799 // coords to match the parent scrolled window and we just want to
3800 // set the y coord - MB
3801 //
3802 // m_owner->PrepareDC( dc );
60ff3b99 3803
790ad94f 3804 int x, y;
2d66e025 3805 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
615b7e6a
RR
3806 wxPoint pt = dc.GetDeviceOrigin();
3807 dc.SetDeviceOrigin( pt.x, pt.y-y );
60ff3b99 3808
d10f4bf9 3809 wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
a9339fe2 3810 m_owner->DrawRowLabels( dc, rows );
2d66e025
MB
3811}
3812
2d66e025
MB
3813void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
3814{
3815 m_owner->ProcessRowLabelMouseEvent( event );
3816}
3817
b51c3f27
RD
3818void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event )
3819{
a9339fe2 3820 m_owner->GetEventHandler()->ProcessEvent( event );
b51c3f27
RD
3821}
3822
2d66e025
MB
3823// This seems to be required for wxMotif otherwise the mouse
3824// cursor must be in the cell edit control to get key events
3825//
3826void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
3827{
2f024384
DS
3828 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3829 event.Skip();
2d66e025
MB
3830}
3831
f6bcfd97
BP
3832void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
3833{
2f024384
DS
3834 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3835 event.Skip();
f6bcfd97
BP
3836}
3837
63e2147c
RD
3838void wxGridRowLabelWindow::OnChar( wxKeyEvent& event )
3839{
2f024384
DS
3840 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3841 event.Skip();
63e2147c
RD
3842}
3843
2d66e025
MB
3844//////////////////////////////////////////////////////////////////////
3845
3846IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
3847
86033c4b 3848BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxGridSubwindow )
2d66e025 3849 EVT_PAINT( wxGridColLabelWindow::OnPaint )
a9339fe2 3850 EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel )
2d66e025
MB
3851 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
3852 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
f6bcfd97 3853 EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
a9339fe2 3854 EVT_CHAR( wxGridColLabelWindow::OnChar )
2d66e025
MB
3855END_EVENT_TABLE()
3856
60ff3b99
VZ
3857wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
3858 wxWindowID id,
2d66e025 3859 const wxPoint &pos, const wxSize &size )
86033c4b 3860 : wxGridSubwindow(parent, id, pos, size)
2d66e025
MB
3861{
3862 m_owner = parent;
3863}
3864
aa5e1f75 3865void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
2d66e025
MB
3866{
3867 wxPaintDC dc(this);
3868
3869 // NO - don't do this because it will set both the x and y origin
3870 // coords to match the parent scrolled window and we just want to
3871 // set the x coord - MB
3872 //
3873 // m_owner->PrepareDC( dc );
60ff3b99 3874
790ad94f 3875 int x, y;
2d66e025 3876 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
615b7e6a
RR
3877 wxPoint pt = dc.GetDeviceOrigin();
3878 if (GetLayoutDirection() == wxLayout_RightToLeft)
3879 dc.SetDeviceOrigin( pt.x+x, pt.y );
3880 else
3881 dc.SetDeviceOrigin( pt.x-x, pt.y );
2d66e025 3882
d10f4bf9 3883 wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() );
a9339fe2 3884 m_owner->DrawColLabels( dc, cols );
2d66e025
MB
3885}
3886
2d66e025
MB
3887void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
3888{
3889 m_owner->ProcessColLabelMouseEvent( event );
3890}
3891
b51c3f27
RD
3892void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event )
3893{
a9339fe2 3894 m_owner->GetEventHandler()->ProcessEvent( event );
b51c3f27
RD
3895}
3896
2d66e025
MB
3897// This seems to be required for wxMotif otherwise the mouse
3898// cursor must be in the cell edit control to get key events
3899//
3900void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
3901{
4db6714b
KH
3902 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3903 event.Skip();
2d66e025
MB
3904}
3905
f6bcfd97
BP
3906void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
3907{
4db6714b
KH
3908 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3909 event.Skip();
f6bcfd97
BP
3910}
3911
63e2147c
RD
3912void wxGridColLabelWindow::OnChar( wxKeyEvent& event )
3913{
4db6714b
KH
3914 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3915 event.Skip();
63e2147c 3916}
2d66e025 3917
2d66e025
MB
3918//////////////////////////////////////////////////////////////////////
3919
3920IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
3921
86033c4b 3922BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxGridSubwindow )
a9339fe2 3923 EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel )
2d66e025 3924 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
a9339fe2 3925 EVT_PAINT( wxGridCornerLabelWindow::OnPaint )
2d66e025 3926 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
f6bcfd97 3927 EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
a9339fe2 3928 EVT_CHAR( wxGridCornerLabelWindow::OnChar )
2d66e025
MB
3929END_EVENT_TABLE()
3930
60ff3b99
VZ
3931wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
3932 wxWindowID id,
2d66e025 3933 const wxPoint &pos, const wxSize &size )
86033c4b 3934 : wxGridSubwindow(parent, id, pos, size)
2d66e025
MB
3935{
3936 m_owner = parent;
3937}
3938
d2fdd8d2
RR
3939void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
3940{
3941 wxPaintDC dc(this);
b99be8fb 3942
d2fdd8d2
RR
3943 int client_height = 0;
3944 int client_width = 0;
3945 GetClientSize( &client_width, &client_height );
b99be8fb 3946
11850ff3 3947 // VZ: any reason for this ifdef? (FIXME)
e6002250
RR
3948#if 0
3949def __WXGTK__
4d1bc39c
RR
3950 wxRect rect;
3951 rect.SetX( 1 );
3952 rect.SetY( 1 );
3953 rect.SetWidth( client_width - 2 );
3954 rect.SetHeight( client_height - 2 );
ec157c8f 3955
4d1bc39c 3956 wxRendererNative::Get().DrawHeaderButton( this, dc, rect, 0 );
11850ff3 3957#else // !__WXGTK__
d4175745 3958 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) );
ccdee36f
DS
3959 dc.DrawLine( client_width - 1, client_height - 1, client_width - 1, 0 );
3960 dc.DrawLine( client_width - 1, client_height - 1, 0, client_height - 1 );
d2fdd8d2
RR
3961 dc.DrawLine( 0, 0, client_width, 0 );
3962 dc.DrawLine( 0, 0, 0, client_height );
73145b0e
JS
3963
3964 dc.SetPen( *wxWHITE_PEN );
ccdee36f
DS
3965 dc.DrawLine( 1, 1, client_width - 1, 1 );
3966 dc.DrawLine( 1, 1, 1, client_height - 1 );
3967#endif
d2fdd8d2
RR
3968}
3969
2d66e025
MB
3970void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
3971{
3972 m_owner->ProcessCornerLabelMouseEvent( event );
3973}
3974
b51c3f27
RD
3975void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event )
3976{
3977 m_owner->GetEventHandler()->ProcessEvent(event);
3978}
3979
2d66e025
MB
3980// This seems to be required for wxMotif otherwise the mouse
3981// cursor must be in the cell edit control to get key events
3982//
3983void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
3984{
2f024384
DS
3985 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3986 event.Skip();
2d66e025
MB
3987}
3988
f6bcfd97
BP
3989void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
3990{
2f024384
DS
3991 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3992 event.Skip();
f6bcfd97
BP
3993}
3994
63e2147c
RD
3995void wxGridCornerLabelWindow::OnChar( wxKeyEvent& event )
3996{
2f024384
DS
3997 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
3998 event.Skip();
63e2147c 3999}
2d66e025 4000
f85afd4e
MB
4001//////////////////////////////////////////////////////////////////////
4002
59ddac01 4003IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
2d66e025 4004
86033c4b 4005BEGIN_EVENT_TABLE( wxGridWindow, wxGridSubwindow )
2d66e025 4006 EVT_PAINT( wxGridWindow::OnPaint )
a9339fe2 4007 EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel )
2d66e025
MB
4008 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
4009 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
f6bcfd97 4010 EVT_KEY_UP( wxGridWindow::OnKeyUp )
a9339fe2 4011 EVT_CHAR( wxGridWindow::OnChar )
80acaf25
JS
4012 EVT_SET_FOCUS( wxGridWindow::OnFocus )
4013 EVT_KILL_FOCUS( wxGridWindow::OnFocus )
2796cce3 4014 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
2d66e025
MB
4015END_EVENT_TABLE()
4016
60ff3b99
VZ
4017wxGridWindow::wxGridWindow( wxGrid *parent,
4018 wxGridRowLabelWindow *rowLblWin,
2d66e025 4019 wxGridColLabelWindow *colLblWin,
04418332
VZ
4020 wxWindowID id,
4021 const wxPoint &pos,
4022 const wxSize &size )
86033c4b
VZ
4023 : wxGridSubwindow(parent, id, pos, size,
4024 wxCLIP_CHILDREN, wxT("grid window") )
2d66e025
MB
4025{
4026 m_owner = parent;
4027 m_rowLabelWin = rowLblWin;
4028 m_colLabelWin = colLblWin;
2d66e025
MB
4029}
4030
2d66e025
MB
4031void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
4032{
4033 wxPaintDC dc( this );
4034 m_owner->PrepareDC( dc );
796df70a 4035 wxRegion reg = GetUpdateRegion();
ccdee36f
DS
4036 wxGridCellCoordsArray dirtyCells = m_owner->CalcCellsExposed( reg );
4037 m_owner->DrawGridCellArea( dc, dirtyCells );
2f024384 4038
9496deb5 4039#if WXGRID_DRAW_LINES
796df70a
SN
4040 m_owner->DrawAllGridLines( dc, reg );
4041#endif
2f024384 4042
a5777624 4043 m_owner->DrawGridSpace( dc );
ccdee36f 4044 m_owner->DrawHighlight( dc, dirtyCells );
2d66e025
MB
4045}
4046
2d66e025
MB
4047void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
4048{
59ddac01 4049 wxWindow::ScrollWindow( dx, dy, rect );
2d66e025
MB
4050 m_rowLabelWin->ScrollWindow( 0, dy, rect );
4051 m_colLabelWin->ScrollWindow( dx, 0, rect );
4052}
4053
2d66e025
MB
4054void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
4055{
33e9fc54
RD
4056 if (event.ButtonDown(wxMOUSE_BTN_LEFT) && FindFocus() != this)
4057 SetFocus();
902725ee 4058
2d66e025
MB
4059 m_owner->ProcessGridCellMouseEvent( event );
4060}
4061
b51c3f27
RD
4062void wxGridWindow::OnMouseWheel( wxMouseEvent& event )
4063{
a9339fe2 4064 m_owner->GetEventHandler()->ProcessEvent( event );
b51c3f27 4065}
2d66e025 4066
f6bcfd97 4067// This seems to be required for wxMotif/wxGTK otherwise the mouse
2d66e025
MB
4068// cursor must be in the cell edit control to get key events
4069//
4070void wxGridWindow::OnKeyDown( wxKeyEvent& event )
4071{
4db6714b
KH
4072 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
4073 event.Skip();
2d66e025 4074}
f85afd4e 4075
f6bcfd97
BP
4076void wxGridWindow::OnKeyUp( wxKeyEvent& event )
4077{
4db6714b
KH
4078 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
4079 event.Skip();
f6bcfd97 4080}
7c8a8ad5 4081
63e2147c
RD
4082void wxGridWindow::OnChar( wxKeyEvent& event )
4083{
4db6714b
KH
4084 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
4085 event.Skip();
63e2147c
RD
4086}
4087
aa5e1f75 4088void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
8dd4f536 4089{
8dd4f536 4090}
025562fe 4091
80acaf25
JS
4092void wxGridWindow::OnFocus(wxFocusEvent& event)
4093{
4094 if ( !m_owner->GetEventHandler()->ProcessEvent( event ) )
4095 event.Skip();
4096}
2d66e025
MB
4097
4098//////////////////////////////////////////////////////////////////////
4099
33188aa4
SN
4100// Internal Helper function for computing row or column from some
4101// (unscrolled) coordinate value, using either
70e8d961 4102// m_defaultRowHeight/m_defaultColWidth or binary search on array
33188aa4
SN
4103// of m_rowBottoms/m_ColRights to speed up the search!
4104
4105// Internal helper macros for simpler use of that function
4106
4107static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
64e15340 4108 const wxArrayInt& BorderArray, int nMax,
a967f048 4109 bool clipToMinMax);
33188aa4 4110
d4175745 4111#define internalXToCol(x) XToCol(x, true)
33188aa4 4112#define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
b8d24d4e 4113 m_minAcceptableRowHeight, \
ca65c044 4114 m_rowBottoms, m_numRows, true)
ccdee36f 4115
33188aa4 4116/////////////////////////////////////////////////////////////////////
07296f0b 4117
b0a877ec 4118#if wxUSE_EXTENDED_RTTI
73c36334
JS
4119WX_DEFINE_FLAGS( wxGridStyle )
4120
3ff066a4 4121wxBEGIN_FLAGS( wxGridStyle )
73c36334
JS
4122 // new style border flags, we put them first to
4123 // use them for streaming out
3ff066a4
SC
4124 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
4125 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
4126 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
4127 wxFLAGS_MEMBER(wxBORDER_RAISED)
4128 wxFLAGS_MEMBER(wxBORDER_STATIC)
4129 wxFLAGS_MEMBER(wxBORDER_NONE)
ca65c044 4130
73c36334 4131 // old style border flags
3ff066a4
SC
4132 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
4133 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
4134 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
4135 wxFLAGS_MEMBER(wxRAISED_BORDER)
4136 wxFLAGS_MEMBER(wxSTATIC_BORDER)
cb0afb26 4137 wxFLAGS_MEMBER(wxBORDER)
73c36334
JS
4138
4139 // standard window styles
3ff066a4
SC
4140 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
4141 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
4142 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
4143 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 4144 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
ccdee36f 4145 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB)
3ff066a4
SC
4146 wxFLAGS_MEMBER(wxVSCROLL)
4147 wxFLAGS_MEMBER(wxHSCROLL)
73c36334 4148
3ff066a4 4149wxEND_FLAGS( wxGridStyle )
73c36334 4150
b0a877ec
SC
4151IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid, wxScrolledWindow,"wx/grid.h")
4152
3ff066a4
SC
4153wxBEGIN_PROPERTIES_TABLE(wxGrid)
4154 wxHIDE_PROPERTY( Children )
af498247 4155 wxPROPERTY_FLAGS( WindowStyle , wxGridStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 4156wxEND_PROPERTIES_TABLE()
b0a877ec 4157
3ff066a4
SC
4158wxBEGIN_HANDLERS_TABLE(wxGrid)
4159wxEND_HANDLERS_TABLE()
b0a877ec 4160
ca65c044 4161wxCONSTRUCTOR_5( wxGrid , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
b0a877ec
SC
4162
4163/*
ccdee36f 4164 TODO : Expose more information of a list's layout, etc. via appropriate objects (e.g., NotebookPageInfo)
b0a877ec
SC
4165*/
4166#else
2d66e025 4167IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
b0a877ec 4168#endif
2d66e025
MB
4169
4170BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
f85afd4e
MB
4171 EVT_PAINT( wxGrid::OnPaint )
4172 EVT_SIZE( wxGrid::OnSize )
f85afd4e 4173 EVT_KEY_DOWN( wxGrid::OnKeyDown )
f6bcfd97 4174 EVT_KEY_UP( wxGrid::OnKeyUp )
63e2147c 4175 EVT_CHAR ( wxGrid::OnChar )
2796cce3 4176 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
f85afd4e 4177END_EVENT_TABLE()
8f177c8e 4178
b0a877ec
SC
4179wxGrid::wxGrid()
4180{
4181 // in order to make sure that a size event is not
4182 // trigerred in a unfinished state
2f024384
DS
4183 m_cornerLabelWin = NULL;
4184 m_rowLabelWin = NULL;
4185 m_colLabelWin = NULL;
4186 m_gridWin = NULL;
b0a877ec
SC
4187}
4188
2d66e025
MB
4189wxGrid::wxGrid( wxWindow *parent,
4190 wxWindowID id,
4191 const wxPoint& pos,
4192 const wxSize& size,
4193 long style,
4194 const wxString& name )
ebd773c6 4195 : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ),
af547d51
VZ
4196 m_colMinWidths(GRID_HASH_SIZE),
4197 m_rowMinHeights(GRID_HASH_SIZE)
2d66e025
MB
4198{
4199 Create();
170acdc9 4200 SetInitialSize(size);
58dd5b3b
MB
4201}
4202
b0a877ec
SC
4203bool wxGrid::Create(wxWindow *parent, wxWindowID id,
4204 const wxPoint& pos, const wxSize& size,
4205 long style, const wxString& name)
4206{
4207 if (!wxScrolledWindow::Create(parent, id, pos, size,
c2f5b920 4208 style | wxWANTS_CHARS, name))
ca65c044 4209 return false;
b0a877ec 4210
2f024384
DS
4211 m_colMinWidths = wxLongToLongHashMap(GRID_HASH_SIZE);
4212 m_rowMinHeights = wxLongToLongHashMap(GRID_HASH_SIZE);
b0a877ec 4213
2f024384 4214 Create();
170acdc9 4215 SetInitialSize(size);
b0a877ec 4216
ca65c044 4217 return true;
b0a877ec
SC
4218}
4219
58dd5b3b
MB
4220wxGrid::~wxGrid()
4221{
606b005f
JS
4222 // Must do this or ~wxScrollHelper will pop the wrong event handler
4223 SetTargetWindow(this);
0a976765 4224 ClearAttrCache();
39bcce60 4225 wxSafeDecRef(m_defaultCellAttr);
0a976765
VZ
4226
4227#ifdef DEBUG_ATTR_CACHE
4228 size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
4229 wxPrintf(_T("wxGrid attribute cache statistics: "
4230 "total: %u, hits: %u (%u%%)\n"),
4231 total, gs_nAttrCacheHits,
4232 total ? (gs_nAttrCacheHits*100) / total : 0);
4233#endif
4234
86020f7e
VZ
4235 // if we own the table, just delete it, otherwise at least don't leave it
4236 // with dangling view pointer
4237 if ( m_ownTable )
2796cce3 4238 delete m_table;
ecc7aa82 4239 else if ( m_table && m_table->GetView() == this )
86020f7e 4240 m_table->SetView(NULL);
f2d76237
RD
4241
4242 delete m_typeRegistry;
b5808881 4243 delete m_selection;
58dd5b3b
MB
4244}
4245
58dd5b3b
MB
4246//
4247// ----- internal init and update functions
4248//
4249
9950649c
RD
4250// NOTE: If using the default visual attributes works everywhere then this can
4251// be removed as well as the #else cases below.
4252#define _USE_VISATTR 0
4253
58dd5b3b 4254void wxGrid::Create()
f0102d2a 4255{
3d59537f
DS
4256 // set to true by CreateGrid
4257 m_created = false;
4634a5d6 4258
3d59537f
DS
4259 // create the type registry
4260 m_typeRegistry = new wxGridTypeRegistry;
4261 m_selection = NULL;
4262
4263 m_table = (wxGridTableBase *) NULL;
4264 m_ownTable = false;
2c9a89e0 4265
ca65c044 4266 m_cellEditCtrlEnabled = false;
4634a5d6 4267
ccd970b1 4268 m_defaultCellAttr = new wxGridCellAttr();
f2d76237
RD
4269
4270 // Set default cell attributes
ccd970b1 4271 m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
19d7140e 4272 m_defaultCellAttr->SetKind(wxGridCellAttr::Default);
f2d76237 4273 m_defaultCellAttr->SetFont(GetFont());
4c7277db 4274 m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP);
9950649c
RD
4275 m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
4276 m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
4277
4278#if _USE_VISATTR
4279 wxVisualAttributes gva = wxListBox::GetClassDefaultAttributes();
4280 wxVisualAttributes lva = wxPanel::GetClassDefaultAttributes();
4281
4282 m_defaultCellAttr->SetTextColour(gva.colFg);
4283 m_defaultCellAttr->SetBackgroundColour(gva.colBg);
ca65c044 4284
9950649c 4285#else
f2d76237 4286 m_defaultCellAttr->SetTextColour(
a756f210 4287 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
f2d76237 4288 m_defaultCellAttr->SetBackgroundColour(
a756f210 4289 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
9950649c 4290#endif
2796cce3 4291
4634a5d6
MB
4292 m_numRows = 0;
4293 m_numCols = 0;
4294 m_currentCellCoords = wxGridNoCellCoords;
b99be8fb 4295
18f9565d
MB
4296 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
4297 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
2d66e025 4298
f2d76237 4299 // subwindow components that make up the wxGrid
60ff3b99 4300 m_rowLabelWin = new wxGridRowLabelWindow( this,
ca65c044 4301 wxID_ANY,
18f9565d
MB
4302 wxDefaultPosition,
4303 wxDefaultSize );
2d66e025
MB
4304
4305 m_colLabelWin = new wxGridColLabelWindow( this,
ca65c044 4306 wxID_ANY,
18f9565d
MB
4307 wxDefaultPosition,
4308 wxDefaultSize );
60ff3b99 4309
3d59537f
DS
4310 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
4311 wxID_ANY,
4312 wxDefaultPosition,
4313 wxDefaultSize );
4314
60ff3b99
VZ
4315 m_gridWin = new wxGridWindow( this,
4316 m_rowLabelWin,
4317 m_colLabelWin,
ca65c044 4318 wxID_ANY,
18f9565d 4319 wxDefaultPosition,
2d66e025
MB
4320 wxDefaultSize );
4321
4322 SetTargetWindow( m_gridWin );
6f36917b 4323
9950649c
RD
4324#if _USE_VISATTR
4325 wxColour gfg = gva.colFg;
4326 wxColour gbg = gva.colBg;
4327 wxColour lfg = lva.colFg;
4328 wxColour lbg = lva.colBg;
4329#else
4330 wxColour gfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
4331 wxColour gbg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
4332 wxColour lfg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
4333 wxColour lbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
4334#endif
2f024384 4335
fa47d7a7
VS
4336 m_cornerLabelWin->SetOwnForegroundColour(lfg);
4337 m_cornerLabelWin->SetOwnBackgroundColour(lbg);
4338 m_rowLabelWin->SetOwnForegroundColour(lfg);
4339 m_rowLabelWin->SetOwnBackgroundColour(lbg);
4340 m_colLabelWin->SetOwnForegroundColour(lfg);
4341 m_colLabelWin->SetOwnBackgroundColour(lbg);
4342
4343 m_gridWin->SetOwnForegroundColour(gfg);
4344 m_gridWin->SetOwnBackgroundColour(gbg);
ca65c044 4345
6f36917b 4346 Init();
2d66e025 4347}
f85afd4e 4348
b5808881
SN
4349bool wxGrid::CreateGrid( int numRows, int numCols,
4350 wxGrid::wxGridSelectionModes selmode )
2d66e025 4351{
f6bcfd97 4352 wxCHECK_MSG( !m_created,
ca65c044 4353 false,
f6bcfd97
BP
4354 wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
4355
4356 m_numRows = numRows;
4357 m_numCols = numCols;
4358
4359 m_table = new wxGridStringTable( m_numRows, m_numCols );
4360 m_table->SetView( this );
ca65c044 4361 m_ownTable = true;
f6bcfd97 4362 m_selection = new wxGridSelection( this, selmode );
6f36917b
VZ
4363
4364 CalcDimensions();
4365
ca65c044 4366 m_created = true;
2d66e025 4367
2796cce3
RD
4368 return m_created;
4369}
4370
f1567cdd
SN
4371void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode)
4372{
6f36917b
VZ
4373 wxCHECK_RET( m_created,
4374 wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") );
4375
4376 m_selection->SetSelectionMode( selmode );
f1567cdd
SN
4377}
4378
aa5b8857
SN
4379wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const
4380{
4381 wxCHECK_MSG( m_created, wxGrid::wxGridSelectCells,
4382 wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") );
4383
4384 return m_selection->GetSelectionMode();
4385}
4386
043d16b2
SN
4387bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership,
4388 wxGrid::wxGridSelectionModes selmode )
2796cce3 4389{
a7dde52f 4390 bool checkSelection = false;
2796cce3
RD
4391 if ( m_created )
4392 {
3e13956a 4393 // stop all processing
ca65c044 4394 m_created = false;
86c7378f 4395
c71b2126 4396 if (m_table)
86c7378f 4397 {
a7dde52f
SN
4398 m_table->SetView(0);
4399 if( m_ownTable )
4400 delete m_table;
5b061713 4401 m_table = NULL;
86c7378f 4402 }
2f024384 4403
3e13956a 4404 delete m_selection;
5b061713 4405 m_selection = NULL;
a7dde52f
SN
4406
4407 m_ownTable = false;
2f024384
DS
4408 m_numRows = 0;
4409 m_numCols = 0;
a7dde52f
SN
4410 checkSelection = true;
4411
4412 // kill row and column size arrays
4413 m_colWidths.Empty();
4414 m_colRights.Empty();
4415 m_rowHeights.Empty();
4416 m_rowBottoms.Empty();
233a54f6 4417 }
2f024384 4418
233a54f6 4419 if (table)
2796cce3
RD
4420 {
4421 m_numRows = table->GetNumberRows();
4422 m_numCols = table->GetNumberCols();
4423
4424 m_table = table;
4425 m_table->SetView( this );
8fc856de 4426 m_ownTable = takeOwnership;
043d16b2 4427 m_selection = new wxGridSelection( this, selmode );
a7dde52f
SN
4428 if (checkSelection)
4429 {
4430 // If the newly set table is smaller than the
4431 // original one current cell and selection regions
4432 // might be invalid,
4433 m_selectingKeyboard = wxGridNoCellCoords;
c71b2126 4434 m_currentCellCoords =
a7dde52f
SN
4435 wxGridCellCoords(wxMin(m_numRows, m_currentCellCoords.GetRow()),
4436 wxMin(m_numCols, m_currentCellCoords.GetCol()));
4437 if (m_selectingTopLeft.GetRow() >= m_numRows ||
4438 m_selectingTopLeft.GetCol() >= m_numCols)
4439 {
4440 m_selectingTopLeft = wxGridNoCellCoords;
4441 m_selectingBottomRight = wxGridNoCellCoords;
4442 }
4443 else
4444 m_selectingBottomRight =
4445 wxGridCellCoords(wxMin(m_numRows,
4446 m_selectingBottomRight.GetRow()),
4447 wxMin(m_numCols,
4448 m_selectingBottomRight.GetCol()));
4449 }
6f36917b
VZ
4450 CalcDimensions();
4451
ca65c044 4452 m_created = true;
2d66e025 4453 }
f85afd4e 4454
2d66e025 4455 return m_created;
f85afd4e
MB
4456}
4457
4458void wxGrid::Init()
4459{
f85afd4e
MB
4460 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
4461 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
4462
60ff3b99
VZ
4463 if ( m_rowLabelWin )
4464 {
4465 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
4466 }
4467 else
4468 {
b0fa2187 4469 m_labelBackgroundColour = *wxWHITE;
60ff3b99
VZ
4470 }
4471
b0fa2187 4472 m_labelTextColour = *wxBLACK;
f85afd4e 4473
0a976765
VZ
4474 // init attr cache
4475 m_attrCache.row = -1;
2b5f62a0
VZ
4476 m_attrCache.col = -1;
4477 m_attrCache.attr = NULL;
0a976765 4478
f85afd4e
MB
4479 // TODO: something better than this ?
4480 //
4481 m_labelFont = this->GetFont();
52d6f640 4482 m_labelFont.SetWeight( wxBOLD );
8f177c8e 4483
73145b0e 4484 m_rowLabelHorizAlign = wxALIGN_CENTRE;
4c7277db 4485 m_rowLabelVertAlign = wxALIGN_CENTRE;
f85afd4e 4486
4c7277db 4487 m_colLabelHorizAlign = wxALIGN_CENTRE;
73145b0e 4488 m_colLabelVertAlign = wxALIGN_CENTRE;
d43851f7 4489 m_colLabelTextOrientation = wxHORIZONTAL;
f85afd4e 4490
f85afd4e 4491 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
1f1ce288
MB
4492 m_defaultRowHeight = m_gridWin->GetCharHeight();
4493
b8d24d4e
RG
4494 m_minAcceptableColWidth = WXGRID_MIN_COL_WIDTH;
4495 m_minAcceptableRowHeight = WXGRID_MIN_ROW_HEIGHT;
4496
d2fdd8d2 4497#if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1f1ce288
MB
4498 m_defaultRowHeight += 8;
4499#else
4500 m_defaultRowHeight += 4;
4501#endif
4502
73145b0e 4503 m_gridLineColour = wxColour( 192,192,192 );
ca65c044 4504 m_gridLinesEnabled = true;
73145b0e 4505 m_cellHighlightColour = *wxBLACK;
bf7945ce 4506 m_cellHighlightPenWidth = 2;
d2520c85 4507 m_cellHighlightROPenWidth = 1;
8f177c8e 4508
d4175745
VZ
4509 m_canDragColMove = false;
4510
58dd5b3b 4511 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
e2b42eeb 4512 m_winCapture = (wxWindow *)NULL;
ca65c044
WS
4513 m_canDragRowSize = true;
4514 m_canDragColSize = true;
4515 m_canDragGridSize = true;
79dbea21 4516 m_canDragCell = false;
f85afd4e
MB
4517 m_dragLastPos = -1;
4518 m_dragRowOrCol = -1;
ca65c044 4519 m_isDragging = false;
07296f0b 4520 m_startDragPos = wxDefaultPosition;
f85afd4e 4521
ca65c044 4522 m_waitForSlowClick = false;
025562fe 4523
f85afd4e
MB
4524 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
4525 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
4526
4527 m_currentCellCoords = wxGridNoCellCoords;
f85afd4e 4528
b524b5c6
VZ
4529 ClearSelection();
4530
d43851f7
JS
4531 m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
4532 m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
8f177c8e 4533
ca65c044 4534 m_editable = true; // default for whole grid
f85afd4e 4535
ca65c044 4536 m_inOnKeyDown = false;
2d66e025 4537 m_batchCount = 0;
3c79cf49 4538
266e8367 4539 m_extraWidth =
526dbb95 4540 m_extraHeight = 0;
608754c4
JS
4541
4542 m_scrollLineX = GRID_SCROLL_LINE_X;
4543 m_scrollLineY = GRID_SCROLL_LINE_Y;
7c1cb261
VZ
4544}
4545
4546// ----------------------------------------------------------------------------
4547// the idea is to call these functions only when necessary because they create
4548// quite big arrays which eat memory mostly unnecessary - in particular, if
4549// default widths/heights are used for all rows/columns, we may not use these
4550// arrays at all
4551//
0ed3b812
VZ
4552// with some extra code, it should be possible to only store the widths/heights
4553// different from default ones (resulting in space savings for huge grids) but
4554// this is not done currently
7c1cb261
VZ
4555// ----------------------------------------------------------------------------
4556
4557void wxGrid::InitRowHeights()
4558{
4559 m_rowHeights.Empty();
4560 m_rowBottoms.Empty();
4561
4562 m_rowHeights.Alloc( m_numRows );
4563 m_rowBottoms.Alloc( m_numRows );
4564
27f35b66
SN
4565 m_rowHeights.Add( m_defaultRowHeight, m_numRows );
4566
0ed3b812 4567 int rowBottom = 0;
3d59537f 4568 for ( int i = 0; i < m_numRows; i++ )
7c1cb261 4569 {
7c1cb261
VZ
4570 rowBottom += m_defaultRowHeight;
4571 m_rowBottoms.Add( rowBottom );
4572 }
4573}
4574
4575void wxGrid::InitColWidths()
4576{
4577 m_colWidths.Empty();
4578 m_colRights.Empty();
4579
4580 m_colWidths.Alloc( m_numCols );
4581 m_colRights.Alloc( m_numCols );
27f35b66
SN
4582
4583 m_colWidths.Add( m_defaultColWidth, m_numCols );
4584
0ed3b812 4585 int colRight = 0;
3d59537f 4586 for ( int i = 0; i < m_numCols; i++ )
7c1cb261 4587 {
d4175745 4588 colRight = ( GetColPos( i ) + 1 ) * m_defaultColWidth;
7c1cb261
VZ
4589 m_colRights.Add( colRight );
4590 }
4591}
4592
4593int wxGrid::GetColWidth(int col) const
4594{
4595 return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
4596}
4597
4598int wxGrid::GetColLeft(int col) const
4599{
d4175745 4600 return m_colRights.IsEmpty() ? GetColPos( col ) * m_defaultColWidth
7c1cb261
VZ
4601 : m_colRights[col] - m_colWidths[col];
4602}
4603
4604int wxGrid::GetColRight(int col) const
4605{
d4175745 4606 return m_colRights.IsEmpty() ? (GetColPos( col ) + 1) * m_defaultColWidth
7c1cb261
VZ
4607 : m_colRights[col];
4608}
4609
4610int wxGrid::GetRowHeight(int row) const
4611{
4612 return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
4613}
2d66e025 4614
7c1cb261
VZ
4615int wxGrid::GetRowTop(int row) const
4616{
4617 return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
4618 : m_rowBottoms[row] - m_rowHeights[row];
f85afd4e
MB
4619}
4620
7c1cb261
VZ
4621int wxGrid::GetRowBottom(int row) const
4622{
4623 return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
4624 : m_rowBottoms[row];
4625}
f85afd4e
MB
4626
4627void wxGrid::CalcDimensions()
4628{
0ed3b812
VZ
4629 // compute the size of the scrollable area
4630 int w = m_numCols > 0 ? GetColRight(GetColAt(m_numCols - 1)) : 0;
4631 int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0;
60ff3b99 4632
0ed3b812
VZ
4633 w += m_extraWidth;
4634 h += m_extraHeight;
faec5a43 4635
73145b0e 4636 // take into account editor if shown
4db6714b 4637 if ( IsCellEditControlShown() )
73145b0e 4638 {
3d59537f
DS
4639 int w2, h2;
4640 int r = m_currentCellCoords.GetRow();
4641 int c = m_currentCellCoords.GetCol();
4642 int x = GetColLeft(c);
4643 int y = GetRowTop(r);
4644
4645 // how big is the editor
4646 wxGridCellAttr* attr = GetCellAttr(r, c);
4647 wxGridCellEditor* editor = attr->GetEditor(this, r, c);
4648 editor->GetControl()->GetSize(&w2, &h2);
4649 w2 += x;
4650 h2 += y;
4651 if ( w2 > w )
4652 w = w2;
4653 if ( h2 > h )
4654 h = h2;
4655 editor->DecRef();
4656 attr->DecRef();
73145b0e
JS
4657 }
4658
faec5a43
SN
4659 // preserve (more or less) the previous position
4660 int x, y;
4661 GetViewStart( &x, &y );
97a9929e 4662
c92ed9f7 4663 // ensure the position is valid for the new scroll ranges
7b519e5e 4664 if ( x >= w )
c92ed9f7 4665 x = wxMax( w - 1, 0 );
7b519e5e 4666 if ( y >= h )
c92ed9f7 4667 y = wxMax( h - 1, 0 );
faec5a43
SN
4668
4669 // do set scrollbar parameters
675a9c0d 4670 SetScrollbars( m_scrollLineX, m_scrollLineY,
0ed3b812
VZ
4671 GetScrollX(w), GetScrollY(h),
4672 x, y,
97a9929e 4673 GetBatchCount() != 0);
12314291
VZ
4674
4675 // if our OnSize() hadn't been called (it would if we have scrollbars), we
4676 // still must reposition the children
4677 CalcWindowSizes();
f85afd4e
MB
4678}
4679
7807d81c
MB
4680void wxGrid::CalcWindowSizes()
4681{
b0a877ec
SC
4682 // escape if the window is has not been fully created yet
4683
4684 if ( m_cornerLabelWin == NULL )
2f024384 4685 return;
b0a877ec 4686
7807d81c
MB
4687 int cw, ch;
4688 GetClientSize( &cw, &ch );
b99be8fb 4689
388703a5
VZ
4690 // this block of code tries to work around the following problem: the grid
4691 // could have been just resized to have enough space to show the full grid
4692 // window contents without the scrollbars, but its client size could be
4693 // not big enough because the grid has the scrollbars right now and so the
4694 // scrollbars would remain even though we don't need them any more
4695 //
4696 // to prevent this from happening, check if we have enough space for
4697 // everything without the scrollbars and explicitly disable them then
4698 wxSize size = GetSize() - GetWindowBorderSize();
4699 if ( size != wxSize(cw, ch) )
4700 {
4701 // check if we have enough space for grid window after accounting for
4702 // the fixed size elements
4703 size.x -= m_rowLabelWidth;
4704 size.y -= m_colLabelHeight;
4705
4706 const wxSize vsize = m_gridWin->GetVirtualSize();
4707
4708 if ( size.x >= vsize.x && size.y >= vsize.y )
4709 {
4710 // yes, we do, so remove the scrollbars and use the new client size
4711 // (which should be the same as full window size - borders now)
4712 SetScrollbars(0, 0, 0, 0);
4713 GetClientSize(&cw, &ch);
4714 }
4715 }
4716
6d308072 4717 if ( m_cornerLabelWin && m_cornerLabelWin->IsShown() )
7807d81c
MB
4718 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
4719
c2f5b920
DS
4720 if ( m_colLabelWin && m_colLabelWin->IsShown() )
4721 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw - m_rowLabelWidth, m_colLabelHeight );
7807d81c 4722
6d308072 4723 if ( m_rowLabelWin && m_rowLabelWin->IsShown() )
c2f5b920 4724 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch - m_colLabelHeight );
7807d81c 4725
6d308072 4726 if ( m_gridWin && m_gridWin->IsShown() )
c2f5b920 4727 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw - m_rowLabelWidth, ch - m_colLabelHeight );
7807d81c
MB
4728}
4729
3d59537f
DS
4730// this is called when the grid table sends a message
4731// to indicate that it has been redimensioned
f85afd4e
MB
4732//
4733bool wxGrid::Redimension( wxGridTableMessage& msg )
4734{
4735 int i;
ca65c044 4736 bool result = false;
8f177c8e 4737
a6794685
SN
4738 // Clear the attribute cache as the attribute might refer to a different
4739 // cell than stored in the cache after adding/removing rows/columns.
4740 ClearAttrCache();
2f024384 4741
7e48d7d9
SN
4742 // By the same reasoning, the editor should be dismissed if columns are
4743 // added or removed. And for consistency, it should IMHO always be
4744 // removed, not only if the cell "underneath" it actually changes.
4745 // For now, I intentionally do not save the editor's content as the
4746 // cell it might want to save that stuff to might no longer exist.
bca7bfc8 4747 HideCellEditControl();
2f024384 4748
f6bcfd97 4749#if 0
7c1cb261
VZ
4750 // if we were using the default widths/heights so far, we must change them
4751 // now
4752 if ( m_colWidths.IsEmpty() )
4753 {
4754 InitColWidths();
4755 }
4756
4757 if ( m_rowHeights.IsEmpty() )
4758 {
4759 InitRowHeights();
4760 }
f6bcfd97 4761#endif
7c1cb261 4762
f85afd4e
MB
4763 switch ( msg.GetId() )
4764 {
4765 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
4766 {
4767 size_t pos = msg.GetCommandInt();
4768 int numRows = msg.GetCommandInt2();
f6bcfd97 4769
f85afd4e 4770 m_numRows += numRows;
2d66e025 4771
f6bcfd97
BP
4772 if ( !m_rowHeights.IsEmpty() )
4773 {
27f35b66
SN
4774 m_rowHeights.Insert( m_defaultRowHeight, pos, numRows );
4775 m_rowBottoms.Insert( 0, pos, numRows );
f6bcfd97
BP
4776
4777 int bottom = 0;
2f024384
DS
4778 if ( pos > 0 )
4779 bottom = m_rowBottoms[pos - 1];
60ff3b99 4780
3d59537f 4781 for ( i = pos; i < m_numRows; i++ )
f6bcfd97
BP
4782 {
4783 bottom += m_rowHeights[i];
4784 m_rowBottoms[i] = bottom;
4785 }
4786 }
2f024384 4787
f6bcfd97
BP
4788 if ( m_currentCellCoords == wxGridNoCellCoords )
4789 {
4790 // if we have just inserted cols into an empty grid the current
4791 // cell will be undefined...
4792 //
4793 SetCurrentCell( 0, 0 );
4794 }
3f3dc2ef
VZ
4795
4796 if ( m_selection )
4797 m_selection->UpdateRows( pos, numRows );
f6bcfd97
BP
4798 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
4799 if (attrProvider)
4800 attrProvider->UpdateAttrRows( pos, numRows );
4801
4802 if ( !GetBatchCount() )
2d66e025 4803 {
f6bcfd97
BP
4804 CalcDimensions();
4805 m_rowLabelWin->Refresh();
2d66e025 4806 }
f85afd4e 4807 }
ca65c044 4808 result = true;
f6bcfd97 4809 break;
f85afd4e
MB
4810
4811 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
4812 {
4813 int numRows = msg.GetCommandInt();
2d66e025 4814 int oldNumRows = m_numRows;
f85afd4e 4815 m_numRows += numRows;
2d66e025 4816
f6bcfd97
BP
4817 if ( !m_rowHeights.IsEmpty() )
4818 {
27f35b66
SN
4819 m_rowHeights.Add( m_defaultRowHeight, numRows );
4820 m_rowBottoms.Add( 0, numRows );
60ff3b99 4821
f6bcfd97 4822 int bottom = 0;
2f024384
DS
4823 if ( oldNumRows > 0 )
4824 bottom = m_rowBottoms[oldNumRows - 1];
f6bcfd97 4825
3d59537f 4826 for ( i = oldNumRows; i < m_numRows; i++ )
f6bcfd97
BP
4827 {
4828 bottom += m_rowHeights[i];
4829 m_rowBottoms[i] = bottom;
4830 }
4831 }
2f024384 4832
f6bcfd97
BP
4833 if ( m_currentCellCoords == wxGridNoCellCoords )
4834 {
4835 // if we have just inserted cols into an empty grid the current
4836 // cell will be undefined...
4837 //
4838 SetCurrentCell( 0, 0 );
4839 }
2f024384 4840
f6bcfd97 4841 if ( !GetBatchCount() )
2d66e025 4842 {
f6bcfd97
BP
4843 CalcDimensions();
4844 m_rowLabelWin->Refresh();
2d66e025 4845 }
f85afd4e 4846 }
ca65c044 4847 result = true;
f6bcfd97 4848 break;
f85afd4e
MB
4849
4850 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
4851 {
4852 size_t pos = msg.GetCommandInt();
4853 int numRows = msg.GetCommandInt2();
f85afd4e
MB
4854 m_numRows -= numRows;
4855
f6bcfd97 4856 if ( !m_rowHeights.IsEmpty() )
f85afd4e 4857 {
27f35b66
SN
4858 m_rowHeights.RemoveAt( pos, numRows );
4859 m_rowBottoms.RemoveAt( pos, numRows );
2d66e025
MB
4860
4861 int h = 0;
3d59537f 4862 for ( i = 0; i < m_numRows; i++ )
2d66e025
MB
4863 {
4864 h += m_rowHeights[i];
4865 m_rowBottoms[i] = h;
4866 }
f85afd4e 4867 }
3d59537f 4868
f6bcfd97
BP
4869 if ( !m_numRows )
4870 {
4871 m_currentCellCoords = wxGridNoCellCoords;
4872 }
4873 else
4874 {
4875 if ( m_currentCellCoords.GetRow() >= m_numRows )
4876 m_currentCellCoords.Set( 0, 0 );
4877 }
3f3dc2ef
VZ
4878
4879 if ( m_selection )
4880 m_selection->UpdateRows( pos, -((int)numRows) );
f6bcfd97 4881 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
4db6714b
KH
4882 if (attrProvider)
4883 {
f6bcfd97 4884 attrProvider->UpdateAttrRows( pos, -((int)numRows) );
3d59537f 4885
84912ef8
RD
4886// ifdef'd out following patch from Paul Gammans
4887#if 0
3ca6a5f0 4888 // No need to touch column attributes, unless we
f6bcfd97
BP
4889 // removed _all_ rows, in this case, we remove
4890 // all column attributes.
4891 // I hate to do this here, but the
4892 // needed data is not available inside UpdateAttrRows.
4893 if ( !GetNumberRows() )
4894 attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
84912ef8 4895#endif
f6bcfd97 4896 }
ccdee36f 4897
f6bcfd97
BP
4898 if ( !GetBatchCount() )
4899 {
4900 CalcDimensions();
4901 m_rowLabelWin->Refresh();
4902 }
f85afd4e 4903 }
ca65c044 4904 result = true;
f6bcfd97 4905 break;
f85afd4e
MB
4906
4907 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
4908 {
4909 size_t pos = msg.GetCommandInt();
4910 int numCols = msg.GetCommandInt2();
f85afd4e 4911 m_numCols += numCols;
2d66e025 4912
d4175745
VZ
4913 if ( !m_colAt.IsEmpty() )
4914 {
4915 //Shift the column IDs
4916 int i;
4917 for ( i = 0; i < m_numCols - numCols; i++ )
4918 {
4919 if ( m_colAt[i] >= (int)pos )
4920 m_colAt[i] += numCols;
4921 }
4922
4923 m_colAt.Insert( pos, pos, numCols );
4924
4925 //Set the new columns' positions
4926 for ( i = pos + 1; i < (int)pos + numCols; i++ )
4927 {
4928 m_colAt[i] = i;
4929 }
4930 }
4931
f6bcfd97
BP
4932 if ( !m_colWidths.IsEmpty() )
4933 {
27f35b66
SN
4934 m_colWidths.Insert( m_defaultColWidth, pos, numCols );
4935 m_colRights.Insert( 0, pos, numCols );
f6bcfd97
BP
4936
4937 int right = 0;
2f024384 4938 if ( pos > 0 )
d4175745 4939 right = m_colRights[GetColAt( pos - 1 )];
60ff3b99 4940
d4175745
VZ
4941 int colPos;
4942 for ( colPos = pos; colPos < m_numCols; colPos++ )
f6bcfd97 4943 {
d4175745
VZ
4944 i = GetColAt( colPos );
4945
f6bcfd97
BP
4946 right += m_colWidths[i];
4947 m_colRights[i] = right;
4948 }
4949 }
2f024384 4950
f6bcfd97 4951 if ( m_currentCellCoords == wxGridNoCellCoords )
2d66e025 4952 {
f6bcfd97
BP
4953 // if we have just inserted cols into an empty grid the current
4954 // cell will be undefined...
4955 //
4956 SetCurrentCell( 0, 0 );
2d66e025 4957 }
3f3dc2ef
VZ
4958
4959 if ( m_selection )
4960 m_selection->UpdateCols( pos, numCols );
f6bcfd97
BP
4961 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
4962 if (attrProvider)
4963 attrProvider->UpdateAttrCols( pos, numCols );
4964 if ( !GetBatchCount() )
4965 {
4966 CalcDimensions();
4967 m_colLabelWin->Refresh();
4968 }
f85afd4e 4969 }
ca65c044 4970 result = true;
f6bcfd97 4971 break;
f85afd4e
MB
4972
4973 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
4974 {
4975 int numCols = msg.GetCommandInt();
2d66e025 4976 int oldNumCols = m_numCols;
f85afd4e 4977 m_numCols += numCols;
d4175745
VZ
4978
4979 if ( !m_colAt.IsEmpty() )
4980 {
4981 m_colAt.Add( 0, numCols );
4982
4983 //Set the new columns' positions
4984 int i;
4985 for ( i = oldNumCols; i < m_numCols; i++ )
4986 {
4987 m_colAt[i] = i;
4988 }
4989 }
4990
f6bcfd97
BP
4991 if ( !m_colWidths.IsEmpty() )
4992 {
27f35b66
SN
4993 m_colWidths.Add( m_defaultColWidth, numCols );
4994 m_colRights.Add( 0, numCols );
2d66e025 4995
f6bcfd97 4996 int right = 0;
2f024384 4997 if ( oldNumCols > 0 )
d4175745 4998 right = m_colRights[GetColAt( oldNumCols - 1 )];
60ff3b99 4999
d4175745
VZ
5000 int colPos;
5001 for ( colPos = oldNumCols; colPos < m_numCols; colPos++ )
f6bcfd97 5002 {
d4175745
VZ
5003 i = GetColAt( colPos );
5004
f6bcfd97
BP
5005 right += m_colWidths[i];
5006 m_colRights[i] = right;
5007 }
5008 }
2f024384 5009
f6bcfd97 5010 if ( m_currentCellCoords == wxGridNoCellCoords )
2d66e025 5011 {
f6bcfd97
BP
5012 // if we have just inserted cols into an empty grid the current
5013 // cell will be undefined...
5014 //
5015 SetCurrentCell( 0, 0 );
5016 }
5017 if ( !GetBatchCount() )
5018 {
5019 CalcDimensions();
5020 m_colLabelWin->Refresh();
2d66e025 5021 }
f85afd4e 5022 }
ca65c044 5023 result = true;
f6bcfd97 5024 break;
f85afd4e
MB
5025
5026 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
5027 {
5028 size_t pos = msg.GetCommandInt();
5029 int numCols = msg.GetCommandInt2();
f85afd4e 5030 m_numCols -= numCols;
f85afd4e 5031
d4175745
VZ
5032 if ( !m_colAt.IsEmpty() )
5033 {
5034 int colID = GetColAt( pos );
5035
5036 m_colAt.RemoveAt( pos, numCols );
5037
5038 //Shift the column IDs
5039 int colPos;
5040 for ( colPos = 0; colPos < m_numCols; colPos++ )
5041 {
5042 if ( m_colAt[colPos] > colID )
5043 m_colAt[colPos] -= numCols;
5044 }
5045 }
5046
f6bcfd97 5047 if ( !m_colWidths.IsEmpty() )
f85afd4e 5048 {
27f35b66
SN
5049 m_colWidths.RemoveAt( pos, numCols );
5050 m_colRights.RemoveAt( pos, numCols );
2d66e025
MB
5051
5052 int w = 0;
d4175745
VZ
5053 int colPos;
5054 for ( colPos = 0; colPos < m_numCols; colPos++ )
2d66e025 5055 {
d4175745
VZ
5056 i = GetColAt( colPos );
5057
2d66e025
MB
5058 w += m_colWidths[i];
5059 m_colRights[i] = w;
5060 }
f85afd4e 5061 }
2f024384 5062
f6bcfd97
BP
5063 if ( !m_numCols )
5064 {
5065 m_currentCellCoords = wxGridNoCellCoords;
5066 }
5067 else
5068 {
5069 if ( m_currentCellCoords.GetCol() >= m_numCols )
5070 m_currentCellCoords.Set( 0, 0 );
5071 }
3f3dc2ef
VZ
5072
5073 if ( m_selection )
5074 m_selection->UpdateCols( pos, -((int)numCols) );
f6bcfd97 5075 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
4db6714b
KH
5076 if (attrProvider)
5077 {
f6bcfd97 5078 attrProvider->UpdateAttrCols( pos, -((int)numCols) );
ccdee36f 5079
84912ef8
RD
5080// ifdef'd out following patch from Paul Gammans
5081#if 0
f6bcfd97
BP
5082 // No need to touch row attributes, unless we
5083 // removed _all_ columns, in this case, we remove
5084 // all row attributes.
5085 // I hate to do this here, but the
5086 // needed data is not available inside UpdateAttrCols.
5087 if ( !GetNumberCols() )
5088 attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
84912ef8 5089#endif
f6bcfd97 5090 }
ccdee36f 5091
f6bcfd97
BP
5092 if ( !GetBatchCount() )
5093 {
5094 CalcDimensions();
5095 m_colLabelWin->Refresh();
5096 }
f85afd4e 5097 }
ca65c044 5098 result = true;
f6bcfd97 5099 break;
f85afd4e
MB
5100 }
5101
f6bcfd97
BP
5102 if (result && !GetBatchCount() )
5103 m_gridWin->Refresh();
2f024384 5104
f6bcfd97 5105 return result;
f85afd4e
MB
5106}
5107
ef316e23 5108wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg ) const
f85afd4e 5109{
2d66e025
MB
5110 wxRegionIterator iter( reg );
5111 wxRect r;
f85afd4e 5112
275c4ae4
RD
5113 wxArrayInt rowlabels;
5114
2d66e025
MB
5115 int top, bottom;
5116 while ( iter )
f85afd4e 5117 {
2d66e025 5118 r = iter.GetRect();
f85afd4e 5119
2d66e025
MB
5120 // TODO: remove this when we can...
5121 // There is a bug in wxMotif that gives garbage update
5122 // rectangles if you jump-scroll a long way by clicking the
5123 // scrollbar with middle button. This is a work-around
5124 //
5125#if defined(__WXMOTIF__)
5126 int cw, ch;
5127 m_gridWin->GetClientSize( &cw, &ch );
56b6cf26
DS
5128 if ( r.GetTop() > ch )
5129 r.SetTop( 0 );
2d66e025
MB
5130 r.SetBottom( wxMin( r.GetBottom(), ch ) );
5131#endif
f85afd4e 5132
2d66e025
MB
5133 // logical bounds of update region
5134 //
5135 int dummy;
5136 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
5137 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
5138
5139 // find the row labels within these bounds
5140 //
5141 int row;
3d59537f 5142 for ( row = internalYToRow(top); row < m_numRows; row++ )
2d66e025 5143 {
7c1cb261
VZ
5144 if ( GetRowBottom(row) < top )
5145 continue;
2d66e025 5146
6d55126d 5147 if ( GetRowTop(row) > bottom )
7c1cb261 5148 break;
60ff3b99 5149
d10f4bf9 5150 rowlabels.Add( row );
2d66e025 5151 }
60ff3b99 5152
60d8e886 5153 ++iter;
f85afd4e 5154 }
d10f4bf9
VZ
5155
5156 return rowlabels;
f85afd4e
MB
5157}
5158
ef316e23 5159wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg ) const
f85afd4e 5160{
2d66e025
MB
5161 wxRegionIterator iter( reg );
5162 wxRect r;
f85afd4e 5163
d10f4bf9 5164 wxArrayInt colLabels;
f85afd4e 5165
2d66e025
MB
5166 int left, right;
5167 while ( iter )
f85afd4e 5168 {
2d66e025 5169 r = iter.GetRect();
f85afd4e 5170
2d66e025
MB
5171 // TODO: remove this when we can...
5172 // There is a bug in wxMotif that gives garbage update
5173 // rectangles if you jump-scroll a long way by clicking the
5174 // scrollbar with middle button. This is a work-around
5175 //
5176#if defined(__WXMOTIF__)
5177 int cw, ch;
5178 m_gridWin->GetClientSize( &cw, &ch );
56b6cf26
DS
5179 if ( r.GetLeft() > cw )
5180 r.SetLeft( 0 );
2d66e025
MB
5181 r.SetRight( wxMin( r.GetRight(), cw ) );
5182#endif
5183
5184 // logical bounds of update region
5185 //
5186 int dummy;
5187 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
5188 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
5189
5190 // find the cells within these bounds
5191 //
5192 int col;
d4175745
VZ
5193 int colPos;
5194 for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ )
2d66e025 5195 {
d4175745
VZ
5196 col = GetColAt( colPos );
5197
7c1cb261
VZ
5198 if ( GetColRight(col) < left )
5199 continue;
60ff3b99 5200
7c1cb261
VZ
5201 if ( GetColLeft(col) > right )
5202 break;
2d66e025 5203
d10f4bf9 5204 colLabels.Add( col );
2d66e025 5205 }
60ff3b99 5206
60d8e886 5207 ++iter;
f85afd4e 5208 }
2f024384 5209
d10f4bf9 5210 return colLabels;
f85afd4e
MB
5211}
5212
ef316e23 5213wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg ) const
f85afd4e 5214{
2d66e025
MB
5215 wxRegionIterator iter( reg );
5216 wxRect r;
f85afd4e 5217
d10f4bf9 5218 wxGridCellCoordsArray cellsExposed;
f85afd4e 5219
2d66e025
MB
5220 int left, top, right, bottom;
5221 while ( iter )
5222 {
5223 r = iter.GetRect();
f85afd4e 5224
2d66e025
MB
5225 // TODO: remove this when we can...
5226 // There is a bug in wxMotif that gives garbage update
5227 // rectangles if you jump-scroll a long way by clicking the
5228 // scrollbar with middle button. This is a work-around
5229 //
5230#if defined(__WXMOTIF__)
f85afd4e 5231 int cw, ch;
2d66e025
MB
5232 m_gridWin->GetClientSize( &cw, &ch );
5233 if ( r.GetTop() > ch ) r.SetTop( 0 );
5234 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
5235 r.SetRight( wxMin( r.GetRight(), cw ) );
5236 r.SetBottom( wxMin( r.GetBottom(), ch ) );
5237#endif
8f177c8e 5238
2d66e025
MB
5239 // logical bounds of update region
5240 //
5241 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
5242 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
f85afd4e 5243
2d66e025 5244 // find the cells within these bounds
f85afd4e 5245 //
2d66e025 5246 int row, col;
3d59537f 5247 for ( row = internalYToRow(top); row < m_numRows; row++ )
f85afd4e 5248 {
7c1cb261
VZ
5249 if ( GetRowBottom(row) <= top )
5250 continue;
f85afd4e 5251
7c1cb261
VZ
5252 if ( GetRowTop(row) > bottom )
5253 break;
60ff3b99 5254
d4175745
VZ
5255 int colPos;
5256 for ( colPos = GetColPos( internalXToCol(left) ); colPos < m_numCols; colPos++ )
2d66e025 5257 {
d4175745
VZ
5258 col = GetColAt( colPos );
5259
7c1cb261
VZ
5260 if ( GetColRight(col) <= left )
5261 continue;
60ff3b99 5262
7c1cb261
VZ
5263 if ( GetColLeft(col) > right )
5264 break;
60ff3b99 5265
d10f4bf9 5266 cellsExposed.Add( wxGridCellCoords( row, col ) );
2d66e025
MB
5267 }
5268 }
60ff3b99 5269
60d8e886 5270 ++iter;
f85afd4e 5271 }
d10f4bf9
VZ
5272
5273 return cellsExposed;
f85afd4e
MB
5274}
5275
5276
2d66e025 5277void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
f85afd4e 5278{
2d66e025
MB
5279 int x, y, row;
5280 wxPoint pos( event.GetPosition() );
5281 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 5282
2d66e025 5283 if ( event.Dragging() )
f85afd4e 5284 {
426b2d87
JS
5285 if (!m_isDragging)
5286 {
ca65c044 5287 m_isDragging = true;
426b2d87
JS
5288 m_rowLabelWin->CaptureMouse();
5289 }
8f177c8e 5290
2d66e025 5291 if ( event.LeftIsDown() )
f85afd4e 5292 {
962a48f6 5293 switch ( m_cursorMode )
f85afd4e 5294 {
f85afd4e
MB
5295 case WXGRID_CURSOR_RESIZE_ROW:
5296 {
2d66e025
MB
5297 int cw, ch, left, dummy;
5298 m_gridWin->GetClientSize( &cw, &ch );
5299 CalcUnscrolledPosition( 0, 0, &left, &dummy );
60ff3b99 5300
2d66e025
MB
5301 wxClientDC dc( m_gridWin );
5302 PrepareDC( dc );
af547d51
VZ
5303 y = wxMax( y,
5304 GetRowTop(m_dragRowOrCol) +
5305 GetRowMinimalHeight(m_dragRowOrCol) );
d2fdd8d2 5306 dc.SetLogicalFunction(wxINVERT);
f85afd4e
MB
5307 if ( m_dragLastPos >= 0 )
5308 {
2d66e025 5309 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
f85afd4e 5310 }
2d66e025
MB
5311 dc.DrawLine( left, y, left+cw, y );
5312 m_dragLastPos = y;
f85afd4e
MB
5313 }
5314 break;
5315
5316 case WXGRID_CURSOR_SELECT_ROW:
902725ee 5317 {
e32352cf 5318 if ( (row = YToRow( y )) >= 0 )
aa5e1f75 5319 {
3f3dc2ef
VZ
5320 if ( m_selection )
5321 {
5322 m_selection->SelectRow( row,
5323 event.ControlDown(),
5324 event.ShiftDown(),
5325 event.AltDown(),
5326 event.MetaDown() );
5327 }
f85afd4e 5328 }
902725ee
WS
5329 }
5330 break;
e2b42eeb
VZ
5331
5332 // default label to suppress warnings about "enumeration value
5333 // 'xxx' not handled in switch
5334 default:
5335 break;
f85afd4e
MB
5336 }
5337 }
5338 return;
5339 }
5340
426b2d87
JS
5341 if ( m_isDragging && (event.Entering() || event.Leaving()) )
5342 return;
8f177c8e 5343
426b2d87
JS
5344 if (m_isDragging)
5345 {
ccdee36f
DS
5346 if (m_rowLabelWin->HasCapture())
5347 m_rowLabelWin->ReleaseMouse();
ca65c044 5348 m_isDragging = false;
426b2d87 5349 }
60ff3b99 5350
6d004f67
MB
5351 // ------------ Entering or leaving the window
5352 //
5353 if ( event.Entering() || event.Leaving() )
5354 {
e2b42eeb 5355 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
6d004f67
MB
5356 }
5357
2d66e025 5358 // ------------ Left button pressed
f85afd4e 5359 //
6d004f67 5360 else if ( event.LeftDown() )
f85afd4e 5361 {
2d66e025
MB
5362 // don't send a label click event for a hit on the
5363 // edge of the row label - this is probably the user
5364 // wanting to resize the row
5365 //
5366 if ( YToEdgeOfRow(y) < 0 )
f85afd4e 5367 {
2d66e025 5368 row = YToRow(y);
2f024384 5369 if ( row >= 0 &&
b54ba671 5370 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
f85afd4e 5371 {
2b01fd49 5372 if ( !event.ShiftDown() && !event.CmdDown() )
aa5e1f75 5373 ClearSelection();
64e15340 5374 if ( m_selection )
3f3dc2ef
VZ
5375 {
5376 if ( event.ShiftDown() )
5377 {
5378 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
5379 0,
5380 row,
5381 GetNumberCols() - 1,
5382 event.ControlDown(),
5383 event.ShiftDown(),
5384 event.AltDown(),
5385 event.MetaDown() );
5386 }
5387 else
5388 {
5389 m_selection->SelectRow( row,
5390 event.ControlDown(),
5391 event.ShiftDown(),
5392 event.AltDown(),
5393 event.MetaDown() );
5394 }
5395 }
5396
e2b42eeb 5397 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
f85afd4e 5398 }
2d66e025
MB
5399 }
5400 else
5401 {
5402 // starting to drag-resize a row
6e8524b1
MB
5403 if ( CanDragRowSize() )
5404 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
2d66e025
MB
5405 }
5406 }
f85afd4e 5407
2d66e025
MB
5408 // ------------ Left double click
5409 //
5410 else if (event.LeftDClick() )
5411 {
4e115ed2 5412 row = YToEdgeOfRow(y);
d43851f7 5413 if ( row < 0 )
2d66e025
MB
5414 {
5415 row = YToRow(y);
a967f048 5416 if ( row >=0 &&
ca65c044
WS
5417 !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event ) )
5418 {
a967f048 5419 // no default action at the moment
ca65c044 5420 }
f85afd4e 5421 }
d43851f7
JS
5422 else
5423 {
5424 // adjust row height depending on label text
5425 AutoSizeRowLabelSize( row );
5426
5427 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
ccdee36f 5428 m_dragLastPos = -1;
d43851f7 5429 }
f85afd4e 5430 }
60ff3b99 5431
2d66e025 5432 // ------------ Left button released
f85afd4e 5433 //
2d66e025 5434 else if ( event.LeftUp() )
f85afd4e 5435 {
2d66e025 5436 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
f85afd4e 5437 {
6d004f67 5438 DoEndDragResizeRow();
60ff3b99 5439
6d004f67
MB
5440 // Note: we are ending the event *after* doing
5441 // default processing in this case
5442 //
b54ba671 5443 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2d66e025 5444 }
f85afd4e 5445
e2b42eeb
VZ
5446 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
5447 m_dragLastPos = -1;
2d66e025 5448 }
f85afd4e 5449
2d66e025
MB
5450 // ------------ Right button down
5451 //
5452 else if ( event.RightDown() )
5453 {
5454 row = YToRow(y);
ef5df12b 5455 if ( row >=0 &&
ca65c044 5456 !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
2d66e025
MB
5457 {
5458 // no default action at the moment
f85afd4e
MB
5459 }
5460 }
60ff3b99 5461
2d66e025 5462 // ------------ Right double click
f85afd4e 5463 //
2d66e025
MB
5464 else if ( event.RightDClick() )
5465 {
5466 row = YToRow(y);
a967f048 5467 if ( row >= 0 &&
ca65c044 5468 !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
2d66e025
MB
5469 {
5470 // no default action at the moment
5471 }
5472 }
60ff3b99 5473
2d66e025 5474 // ------------ No buttons down and mouse moving
f85afd4e 5475 //
2d66e025 5476 else if ( event.Moving() )
f85afd4e 5477 {
2d66e025
MB
5478 m_dragRowOrCol = YToEdgeOfRow( y );
5479 if ( m_dragRowOrCol >= 0 )
8f177c8e 5480 {
2d66e025 5481 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
8f177c8e 5482 {
e2b42eeb 5483 // don't capture the mouse yet
6e8524b1 5484 if ( CanDragRowSize() )
ca65c044 5485 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, false);
8f177c8e 5486 }
2d66e025 5487 }
6d004f67 5488 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2d66e025 5489 {
ca65c044 5490 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, false);
8f177c8e 5491 }
f85afd4e 5492 }
2d66e025
MB
5493}
5494
2d66e025
MB
5495void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
5496{
5497 int x, y, col;
5498 wxPoint pos( event.GetPosition() );
5499 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 5500
2d66e025 5501 if ( event.Dragging() )
f85afd4e 5502 {
fe77cf60
JS
5503 if (!m_isDragging)
5504 {
ca65c044 5505 m_isDragging = true;
fe77cf60 5506 m_colLabelWin->CaptureMouse();
d4175745
VZ
5507
5508 if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL )
5509 m_dragRowOrCol = XToCol( x );
fe77cf60 5510 }
8f177c8e 5511
2d66e025 5512 if ( event.LeftIsDown() )
8f177c8e 5513 {
962a48f6 5514 switch ( m_cursorMode )
8f177c8e 5515 {
2d66e025 5516 case WXGRID_CURSOR_RESIZE_COL:
8f177c8e 5517 {
2d66e025
MB
5518 int cw, ch, dummy, top;
5519 m_gridWin->GetClientSize( &cw, &ch );
5520 CalcUnscrolledPosition( 0, 0, &dummy, &top );
60ff3b99 5521
2d66e025
MB
5522 wxClientDC dc( m_gridWin );
5523 PrepareDC( dc );
43947979
VZ
5524
5525 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
5526 GetColMinimalWidth(m_dragRowOrCol));
d2fdd8d2 5527 dc.SetLogicalFunction(wxINVERT);
2d66e025
MB
5528 if ( m_dragLastPos >= 0 )
5529 {
ccdee36f 5530 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch );
2d66e025 5531 }
ccdee36f 5532 dc.DrawLine( x, top, x, top + ch );
2d66e025 5533 m_dragLastPos = x;
f85afd4e 5534 }
2d66e025 5535 break;
f85afd4e 5536
2d66e025 5537 case WXGRID_CURSOR_SELECT_COL:
902725ee 5538 {
e32352cf 5539 if ( (col = XToCol( x )) >= 0 )
aa5e1f75 5540 {
3f3dc2ef
VZ
5541 if ( m_selection )
5542 {
5543 m_selection->SelectCol( col,
5544 event.ControlDown(),
5545 event.ShiftDown(),
5546 event.AltDown(),
5547 event.MetaDown() );
5548 }
2d66e025 5549 }
902725ee
WS
5550 }
5551 break;
e2b42eeb 5552
d4175745
VZ
5553 case WXGRID_CURSOR_MOVE_COL:
5554 {
5555 if ( x < 0 )
5556 m_moveToCol = GetColAt( 0 );
5557 else
5558 m_moveToCol = XToCol( x );
5559
5560 int markerX;
5561
5562 if ( m_moveToCol < 0 )
5563 markerX = GetColRight( GetColAt( m_numCols - 1 ) );
5564 else
5565 markerX = GetColLeft( m_moveToCol );
5566
5567 if ( markerX != m_dragLastPos )
5568 {
5569 wxClientDC dc( m_colLabelWin );
5570
5571 int cw, ch;
5572 m_colLabelWin->GetClientSize( &cw, &ch );
5573
5574 markerX++;
5575
5576 //Clean up the last indicator
5577 if ( m_dragLastPos >= 0 )
5578 {
5579 wxPen pen( m_colLabelWin->GetBackgroundColour(), 2 );
5580 dc.SetPen(pen);
5581 dc.DrawLine( m_dragLastPos + 1, 0, m_dragLastPos + 1, ch );
5582 dc.SetPen(wxNullPen);
5583
5584 if ( XToCol( m_dragLastPos ) != -1 )
5585 DrawColLabel( dc, XToCol( m_dragLastPos ) );
5586 }
5587
5588 //Moving to the same place? Don't draw a marker
5589 if ( (m_moveToCol == m_dragRowOrCol)
5590 || (GetColPos( m_moveToCol ) == GetColPos( m_dragRowOrCol ) + 1)
5591 || (m_moveToCol < 0 && m_dragRowOrCol == GetColAt( m_numCols - 1 )))
5592 {
5593 m_dragLastPos = -1;
5594 return;
5595 }
5596
5597 //Draw the marker
5598 wxPen pen( *wxBLUE, 2 );
5599 dc.SetPen(pen);
5600
5601 dc.DrawLine( markerX, 0, markerX, ch );
5602
5603 dc.SetPen(wxNullPen);
5604
5605 m_dragLastPos = markerX - 1;
5606 }
5607 }
5608 break;
5609
e2b42eeb
VZ
5610 // default label to suppress warnings about "enumeration value
5611 // 'xxx' not handled in switch
5612 default:
5613 break;
2d66e025 5614 }
f85afd4e 5615 }
2d66e025 5616 return;
f85afd4e 5617 }
2d66e025 5618
fe77cf60
JS
5619 if ( m_isDragging && (event.Entering() || event.Leaving()) )
5620 return;
2d66e025 5621
fe77cf60
JS
5622 if (m_isDragging)
5623 {
ccdee36f
DS
5624 if (m_colLabelWin->HasCapture())
5625 m_colLabelWin->ReleaseMouse();
ca65c044 5626 m_isDragging = false;
fe77cf60 5627 }
60ff3b99 5628
6d004f67
MB
5629 // ------------ Entering or leaving the window
5630 //
5631 if ( event.Entering() || event.Leaving() )
5632 {
e2b42eeb 5633 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
6d004f67
MB
5634 }
5635
2d66e025 5636 // ------------ Left button pressed
f85afd4e 5637 //
6d004f67 5638 else if ( event.LeftDown() )
f85afd4e 5639 {
2d66e025
MB
5640 // don't send a label click event for a hit on the
5641 // edge of the col label - this is probably the user
5642 // wanting to resize the col
5643 //
5644 if ( XToEdgeOfCol(x) < 0 )
8f177c8e 5645 {
2d66e025 5646 col = XToCol(x);
2f024384 5647 if ( col >= 0 &&
b54ba671 5648 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
8f177c8e 5649 {
d4175745 5650 if ( m_canDragColMove )
3f3dc2ef 5651 {
d4175745
VZ
5652 //Show button as pressed
5653 wxClientDC dc( m_colLabelWin );
5654 int colLeft = GetColLeft( col );
5655 int colRight = GetColRight( col ) - 1;
5656 dc.SetPen( wxPen( m_colLabelWin->GetBackgroundColour(), 1 ) );
5657 dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight-1 );
5658 dc.DrawLine( colLeft, 1, colRight, 1 );
5659
5660 ChangeCursorMode(WXGRID_CURSOR_MOVE_COL, m_colLabelWin);
5661 }
5662 else
5663 {
5664 if ( !event.ShiftDown() && !event.CmdDown() )
5665 ClearSelection();
5666 if ( m_selection )
3f3dc2ef 5667 {
d4175745
VZ
5668 if ( event.ShiftDown() )
5669 {
5670 m_selection->SelectBlock( 0,
5671 m_currentCellCoords.GetCol(),
5672 GetNumberRows() - 1, col,
5673 event.ControlDown(),
5674 event.ShiftDown(),
5675 event.AltDown(),
5676 event.MetaDown() );
5677 }
5678 else
5679 {
5680 m_selection->SelectCol( col,
5681 event.ControlDown(),
5682 event.ShiftDown(),
5683 event.AltDown(),
5684 event.MetaDown() );
5685 }
3f3dc2ef 5686 }
3f3dc2ef 5687
d4175745
VZ
5688 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
5689 }
f85afd4e 5690 }
2d66e025
MB
5691 }
5692 else
5693 {
5694 // starting to drag-resize a col
5695 //
6e8524b1
MB
5696 if ( CanDragColSize() )
5697 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
2d66e025
MB
5698 }
5699 }
f85afd4e 5700
2d66e025
MB
5701 // ------------ Left double click
5702 //
5703 if ( event.LeftDClick() )
5704 {
4e115ed2 5705 col = XToEdgeOfCol(x);
d43851f7 5706 if ( col < 0 )
2d66e025
MB
5707 {
5708 col = XToCol(x);
a967f048
RG
5709 if ( col >= 0 &&
5710 ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event ) )
5711 {
ca65c044 5712 // no default action at the moment
a967f048 5713 }
2d66e025 5714 }
d43851f7
JS
5715 else
5716 {
5717 // adjust column width depending on label text
5718 AutoSizeColLabelSize( col );
5719
5720 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
ccdee36f 5721 m_dragLastPos = -1;
d43851f7 5722 }
2d66e025 5723 }
60ff3b99 5724
2d66e025
MB
5725 // ------------ Left button released
5726 //
5727 else if ( event.LeftUp() )
5728 {
d4175745 5729 switch ( m_cursorMode )
2d66e025 5730 {
d4175745 5731 case WXGRID_CURSOR_RESIZE_COL:
d4175745 5732 DoEndDragResizeCol();
e2b42eeb 5733
d4175745
VZ
5734 // Note: we are ending the event *after* doing
5735 // default processing in this case
5736 //
5737 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
852b6c3c 5738 break;
d4175745
VZ
5739
5740 case WXGRID_CURSOR_MOVE_COL:
d4175745
VZ
5741 DoEndDragMoveCol();
5742
5743 SendEvent( wxEVT_GRID_COL_MOVE, -1, m_dragRowOrCol, event );
852b6c3c
VZ
5744 break;
5745
5746 case WXGRID_CURSOR_SELECT_COL:
5747 case WXGRID_CURSOR_SELECT_CELL:
5748 case WXGRID_CURSOR_RESIZE_ROW:
5749 case WXGRID_CURSOR_SELECT_ROW:
5750 // nothing to do (?)
5751 break;
2d66e025 5752 }
f85afd4e 5753
e2b42eeb 5754 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
ccdee36f 5755 m_dragLastPos = -1;
60ff3b99
VZ
5756 }
5757
2d66e025
MB
5758 // ------------ Right button down
5759 //
5760 else if ( event.RightDown() )
5761 {
5762 col = XToCol(x);
a967f048 5763 if ( col >= 0 &&
ca65c044 5764 !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
2d66e025
MB
5765 {
5766 // no default action at the moment
f85afd4e
MB
5767 }
5768 }
60ff3b99 5769
2d66e025 5770 // ------------ Right double click
f85afd4e 5771 //
2d66e025
MB
5772 else if ( event.RightDClick() )
5773 {
5774 col = XToCol(x);
a967f048 5775 if ( col >= 0 &&
ca65c044 5776 !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
2d66e025
MB
5777 {
5778 // no default action at the moment
5779 }
5780 }
60ff3b99 5781
2d66e025 5782 // ------------ No buttons down and mouse moving
f85afd4e 5783 //
2d66e025 5784 else if ( event.Moving() )
f85afd4e 5785 {
2d66e025
MB
5786 m_dragRowOrCol = XToEdgeOfCol( x );
5787 if ( m_dragRowOrCol >= 0 )
f85afd4e 5788 {
2d66e025 5789 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 5790 {
e2b42eeb 5791 // don't capture the cursor yet
6e8524b1 5792 if ( CanDragColSize() )
ca65c044 5793 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, false);
f85afd4e 5794 }
2d66e025 5795 }
6d004f67 5796 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2d66e025 5797 {
ca65c044 5798 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, false);
8f177c8e 5799 }
f85afd4e
MB
5800 }
5801}
5802
2d66e025 5803void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
f85afd4e 5804{
2d66e025 5805 if ( event.LeftDown() )
f85afd4e 5806 {
2d66e025
MB
5807 // indicate corner label by having both row and
5808 // col args == -1
f85afd4e 5809 //
b54ba671 5810 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
2d66e025
MB
5811 {
5812 SelectAll();
5813 }
f85afd4e 5814 }
2d66e025
MB
5815 else if ( event.LeftDClick() )
5816 {
b54ba671 5817 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
2d66e025 5818 }
2d66e025 5819 else if ( event.RightDown() )
f85afd4e 5820 {
b54ba671 5821 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
f85afd4e 5822 {
2d66e025
MB
5823 // no default action at the moment
5824 }
5825 }
2d66e025
MB
5826 else if ( event.RightDClick() )
5827 {
b54ba671 5828 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
2d66e025
MB
5829 {
5830 // no default action at the moment
5831 }
5832 }
5833}
f85afd4e 5834
86033c4b
VZ
5835void wxGrid::CancelMouseCapture()
5836{
5837 // cancel operation currently in progress, whatever it is
5838 if ( m_winCapture )
5839 {
5840 m_isDragging = false;
5841 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
5842 m_winCapture->SetCursor( *wxSTANDARD_CURSOR );
5843 m_winCapture = NULL;
5844
5845 // remove traces of whatever we drew on screen
5846 Refresh();
5847 }
5848}
5849
e2b42eeb
VZ
5850void wxGrid::ChangeCursorMode(CursorMode mode,
5851 wxWindow *win,
5852 bool captureMouse)
5853{
5854#ifdef __WXDEBUG__
5855 static const wxChar *cursorModes[] =
5856 {
5857 _T("SELECT_CELL"),
5858 _T("RESIZE_ROW"),
5859 _T("RESIZE_COL"),
5860 _T("SELECT_ROW"),
d4175745
VZ
5861 _T("SELECT_COL"),
5862 _T("MOVE_COL"),
e2b42eeb
VZ
5863 };
5864
181bfffd
VZ
5865 wxLogTrace(_T("grid"),
5866 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
e2b42eeb
VZ
5867 win == m_colLabelWin ? _T("colLabelWin")
5868 : win ? _T("rowLabelWin")
5869 : _T("gridWin"),
5870 cursorModes[m_cursorMode], cursorModes[mode]);
2f024384 5871#endif
e2b42eeb 5872
faec5a43
SN
5873 if ( mode == m_cursorMode &&
5874 win == m_winCapture &&
5875 captureMouse == (m_winCapture != NULL))
e2b42eeb
VZ
5876 return;
5877
5878 if ( !win )
5879 {
5880 // by default use the grid itself
5881 win = m_gridWin;
5882 }
5883
5884 if ( m_winCapture )
5885 {
2f024384
DS
5886 if (m_winCapture->HasCapture())
5887 m_winCapture->ReleaseMouse();
e2b42eeb
VZ
5888 m_winCapture = (wxWindow *)NULL;
5889 }
5890
5891 m_cursorMode = mode;
5892
5893 switch ( m_cursorMode )
5894 {
5895 case WXGRID_CURSOR_RESIZE_ROW:
5896 win->SetCursor( m_rowResizeCursor );
5897 break;
5898
5899 case WXGRID_CURSOR_RESIZE_COL:
5900 win->SetCursor( m_colResizeCursor );
5901 break;
5902
d4175745
VZ
5903 case WXGRID_CURSOR_MOVE_COL:
5904 win->SetCursor( wxCursor(wxCURSOR_HAND) );
5905 break;
5906
e2b42eeb
VZ
5907 default:
5908 win->SetCursor( *wxSTANDARD_CURSOR );
2f024384 5909 break;
e2b42eeb
VZ
5910 }
5911
5912 // we need to capture mouse when resizing
5913 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
5914 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
5915
5916 if ( captureMouse && resize )
5917 {
5918 win->CaptureMouse();
5919 m_winCapture = win;
5920 }
5921}
8f177c8e 5922
2d66e025
MB
5923void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
5924{
5925 int x, y;
5926 wxPoint pos( event.GetPosition() );
5927 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 5928
2d66e025
MB
5929 wxGridCellCoords coords;
5930 XYToCell( x, y, coords );
60ff3b99 5931
27f35b66 5932 int cell_rows, cell_cols;
79dbea21 5933 bool isFirstDrag = !m_isDragging;
27f35b66
SN
5934 GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols );
5935 if ((cell_rows < 0) || (cell_cols < 0))
5936 {
5937 coords.SetRow(coords.GetRow() + cell_rows);
5938 coords.SetCol(coords.GetCol() + cell_cols);
5939 }
5940
2d66e025
MB
5941 if ( event.Dragging() )
5942 {
07296f0b
RD
5943 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
5944
962a48f6 5945 // Don't start doing anything until the mouse has been dragged at
07296f0b 5946 // least 3 pixels in any direction...
508011ce
VZ
5947 if (! m_isDragging)
5948 {
5949 if (m_startDragPos == wxDefaultPosition)
5950 {
07296f0b
RD
5951 m_startDragPos = pos;
5952 return;
5953 }
5954 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
5955 return;
5956 }
5957
ca65c044 5958 m_isDragging = true;
2d66e025
MB
5959 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
5960 {
f0102d2a 5961 // Hide the edit control, so it
4db6714b 5962 // won't interfere with drag-shrinking.
f6bcfd97 5963 if ( IsCellEditControlShown() )
a5777624 5964 {
f0102d2a 5965 HideCellEditControl();
a5777624
RD
5966 SaveEditControlValue();
5967 }
07296f0b 5968
2d66e025
MB
5969 if ( coords != wxGridNoCellCoords )
5970 {
2b01fd49 5971 if ( event.CmdDown() )
aa5e1f75
SN
5972 {
5973 if ( m_selectingKeyboard == wxGridNoCellCoords)
5974 m_selectingKeyboard = coords;
a9339fe2 5975 HighlightBlock( m_selectingKeyboard, coords );
aa5e1f75 5976 }
79dbea21
RD
5977 else if ( CanDragCell() )
5978 {
5979 if ( isFirstDrag )
5980 {
5981 if ( m_selectingKeyboard == wxGridNoCellCoords)
5982 m_selectingKeyboard = coords;
5983
5984 SendEvent( wxEVT_GRID_CELL_BEGIN_DRAG,
5985 coords.GetRow(),
5986 coords.GetCol(),
5987 event );
25107357 5988 return;
79dbea21
RD
5989 }
5990 }
aa5e1f75
SN
5991 else
5992 {
5993 if ( !IsSelection() )
5994 {
c9097836 5995 HighlightBlock( coords, coords );
aa5e1f75
SN
5996 }
5997 else
5998 {
c9097836 5999 HighlightBlock( m_currentCellCoords, coords );
aa5e1f75 6000 }
f85afd4e 6001 }
07296f0b 6002
508011ce
VZ
6003 if (! IsVisible(coords))
6004 {
07296f0b
RD
6005 MakeCellVisible(coords);
6006 // TODO: need to introduce a delay or something here. The
e32352cf 6007 // scrolling is way to fast, at least on MSW - also on GTK.
07296f0b 6008 }
2d66e025 6009 }
25107357
RD
6010 // Have we captured the mouse yet?
6011 if (! m_winCapture)
6012 {
6013 m_winCapture = m_gridWin;
6014 m_winCapture->CaptureMouse();
6015 }
6016
c71b2126 6017
2d66e025 6018 }
6d004f67
MB
6019 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
6020 {
6021 int cw, ch, left, dummy;
6022 m_gridWin->GetClientSize( &cw, &ch );
6023 CalcUnscrolledPosition( 0, 0, &left, &dummy );
8f177c8e 6024
6d004f67
MB
6025 wxClientDC dc( m_gridWin );
6026 PrepareDC( dc );
a95e38c0
VZ
6027 y = wxMax( y, GetRowTop(m_dragRowOrCol) +
6028 GetRowMinimalHeight(m_dragRowOrCol) );
6d004f67
MB
6029 dc.SetLogicalFunction(wxINVERT);
6030 if ( m_dragLastPos >= 0 )
6031 {
6032 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
6033 }
6034 dc.DrawLine( left, y, left+cw, y );
6035 m_dragLastPos = y;
6036 }
6037 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
6038 {
6039 int cw, ch, dummy, top;
6040 m_gridWin->GetClientSize( &cw, &ch );
6041 CalcUnscrolledPosition( 0, 0, &dummy, &top );
e2b42eeb 6042
6d004f67
MB
6043 wxClientDC dc( m_gridWin );
6044 PrepareDC( dc );
43947979
VZ
6045 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
6046 GetColMinimalWidth(m_dragRowOrCol) );
6d004f67
MB
6047 dc.SetLogicalFunction(wxINVERT);
6048 if ( m_dragLastPos >= 0 )
6049 {
a9339fe2 6050 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch );
6d004f67 6051 }
a9339fe2 6052 dc.DrawLine( x, top, x, top + ch );
6d004f67
MB
6053 m_dragLastPos = x;
6054 }
e2b42eeb 6055
2d66e025
MB
6056 return;
6057 }
66242c80 6058
ca65c044 6059 m_isDragging = false;
07296f0b
RD
6060 m_startDragPos = wxDefaultPosition;
6061
a5777624
RD
6062 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
6063 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
6064 // wxGTK
e2b42eeb 6065#if 0
a5777624
RD
6066 if ( event.Entering() || event.Leaving() )
6067 {
6068 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
6069 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
6070 }
6071 else
e2b42eeb
VZ
6072#endif // 0
6073
a5777624
RD
6074 // ------------ Left button pressed
6075 //
6076 if ( event.LeftDown() && coords != wxGridNoCellCoords )
f6bcfd97
BP
6077 {
6078 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
6079 coords.GetRow(),
6080 coords.GetCol(),
6081 event ) )
a5777624 6082 {
2b01fd49 6083 if ( !event.CmdDown() )
f6bcfd97
BP
6084 ClearSelection();
6085 if ( event.ShiftDown() )
6086 {
3f3dc2ef
VZ
6087 if ( m_selection )
6088 {
6089 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
6090 m_currentCellCoords.GetCol(),
6091 coords.GetRow(),
6092 coords.GetCol(),
6093 event.ControlDown(),
6094 event.ShiftDown(),
6095 event.AltDown(),
6096 event.MetaDown() );
6097 }
f6bcfd97 6098 }
2f024384 6099 else if ( XToEdgeOfCol(x) < 0 &&
f6bcfd97 6100 YToEdgeOfRow(y) < 0 )
58dd5b3b 6101 {
a5777624
RD
6102 DisableCellEditControl();
6103 MakeCellVisible( coords );
6104
2b01fd49 6105 if ( event.CmdDown() )
58dd5b3b 6106 {
73145b0e
JS
6107 if ( m_selection )
6108 {
6109 m_selection->ToggleCellSelection( coords.GetRow(),
6110 coords.GetCol(),
6111 event.ControlDown(),
6112 event.ShiftDown(),
6113 event.AltDown(),
6114 event.MetaDown() );
6115 }
6116 m_selectingTopLeft = wxGridNoCellCoords;
6117 m_selectingBottomRight = wxGridNoCellCoords;
6118 m_selectingKeyboard = coords;
a5777624
RD
6119 }
6120 else
6121 {
73145b0e
JS
6122 m_waitForSlowClick = m_currentCellCoords == coords && coords != wxGridNoCellCoords;
6123 SetCurrentCell( coords );
6124 if ( m_selection )
aa5e1f75 6125 {
73145b0e
JS
6126 if ( m_selection->GetSelectionMode() !=
6127 wxGrid::wxGridSelectCells )
3f3dc2ef 6128 {
73145b0e 6129 HighlightBlock( coords, coords );
3f3dc2ef 6130 }
aa5e1f75 6131 }
58dd5b3b
MB
6132 }
6133 }
f85afd4e 6134 }
a5777624 6135 }
f85afd4e 6136
a5777624
RD
6137 // ------------ Left double click
6138 //
6139 else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
6140 {
6141 DisableCellEditControl();
6142
2f024384 6143 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
58dd5b3b 6144 {
1ef49ab5
VS
6145 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
6146 coords.GetRow(),
6147 coords.GetCol(),
6148 event ) )
6149 {
6150 // we want double click to select a cell and start editing
6151 // (i.e. to behave in same way as sequence of two slow clicks):
6152 m_waitForSlowClick = true;
6153 }
58dd5b3b 6154 }
a5777624 6155 }
f85afd4e 6156
a5777624
RD
6157 // ------------ Left button released
6158 //
6159 else if ( event.LeftUp() )
6160 {
6161 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 6162 {
f40f9976
JS
6163 if (m_winCapture)
6164 {
2f024384
DS
6165 if (m_winCapture->HasCapture())
6166 m_winCapture->ReleaseMouse();
f40f9976
JS
6167 m_winCapture = NULL;
6168 }
6169
bee19958 6170 if ( coords == m_currentCellCoords && m_waitForSlowClick && CanEnableCellControl() )
932b55d0
JS
6171 {
6172 ClearSelection();
6173 EnableCellEditControl();
6174
2f024384 6175 wxGridCellAttr *attr = GetCellAttr(coords);
932b55d0
JS
6176 wxGridCellEditor *editor = attr->GetEditor(this, coords.GetRow(), coords.GetCol());
6177 editor->StartingClick();
6178 editor->DecRef();
6179 attr->DecRef();
6180
ca65c044 6181 m_waitForSlowClick = false;
932b55d0
JS
6182 }
6183 else if ( m_selectingTopLeft != wxGridNoCellCoords &&
b5808881 6184 m_selectingBottomRight != wxGridNoCellCoords )
52068ea5 6185 {
3f3dc2ef
VZ
6186 if ( m_selection )
6187 {
6188 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
6189 m_selectingTopLeft.GetCol(),
6190 m_selectingBottomRight.GetRow(),
6191 m_selectingBottomRight.GetCol(),
6192 event.ControlDown(),
6193 event.ShiftDown(),
6194 event.AltDown(),
6195 event.MetaDown() );
6196 }
6197
5c8fc7c1
SN
6198 m_selectingTopLeft = wxGridNoCellCoords;
6199 m_selectingBottomRight = wxGridNoCellCoords;
2d66e025 6200
73145b0e
JS
6201 // Show the edit control, if it has been hidden for
6202 // drag-shrinking.
6203 ShowCellEditControl();
6204 }
a5777624
RD
6205 }
6206 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
6207 {
6208 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
6209 DoEndDragResizeRow();
e2b42eeb 6210
a5777624
RD
6211 // Note: we are ending the event *after* doing
6212 // default processing in this case
6213 //
6214 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
6215 }
6216 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
6217 {
6218 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
6219 DoEndDragResizeCol();
e2b42eeb 6220
a5777624
RD
6221 // Note: we are ending the event *after* doing
6222 // default processing in this case
6223 //
6224 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
58dd5b3b 6225 }
f85afd4e 6226
a5777624
RD
6227 m_dragLastPos = -1;
6228 }
6229
a5777624
RD
6230 // ------------ Right button down
6231 //
6232 else if ( event.RightDown() && coords != wxGridNoCellCoords )
6233 {
6234 DisableCellEditControl();
6235 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
6236 coords.GetRow(),
6237 coords.GetCol(),
6238 event ) )
f85afd4e 6239 {
a5777624 6240 // no default action at the moment
60ff3b99 6241 }
a5777624 6242 }
2d66e025 6243
a5777624
RD
6244 // ------------ Right double click
6245 //
6246 else if ( event.RightDClick() && coords != wxGridNoCellCoords )
6247 {
6248 DisableCellEditControl();
6249 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
6250 coords.GetRow(),
6251 coords.GetCol(),
6252 event ) )
f85afd4e 6253 {
a5777624 6254 // no default action at the moment
60ff3b99 6255 }
a5777624
RD
6256 }
6257
6258 // ------------ Moving and no button action
6259 //
6260 else if ( event.Moving() && !event.IsButton() )
6261 {
4db6714b 6262 if ( coords.GetRow() < 0 || coords.GetCol() < 0 )
d57ad377
SN
6263 {
6264 // out of grid cell area
6265 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
6266 return;
6267 }
6268
a5777624
RD
6269 int dragRow = YToEdgeOfRow( y );
6270 int dragCol = XToEdgeOfCol( x );
790cc417 6271
a5777624
RD
6272 // Dragging on the corner of a cell to resize in both
6273 // directions is not implemented yet...
790cc417 6274 //
91894db3 6275 if ( dragRow >= 0 && dragCol >= 0 )
790cc417 6276 {
a5777624
RD
6277 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
6278 return;
6279 }
6d004f67 6280
d57ad377 6281 if ( dragRow >= 0 )
a5777624
RD
6282 {
6283 m_dragRowOrCol = dragRow;
6d004f67 6284
a5777624 6285 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
6d004f67 6286 {
a5777624
RD
6287 if ( CanDragRowSize() && CanDragGridSize() )
6288 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
6d004f67 6289 }
a5777624 6290 }
91894db3 6291 else if ( dragCol >= 0 )
a5777624
RD
6292 {
6293 m_dragRowOrCol = dragCol;
e2b42eeb 6294
a5777624 6295 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
6d004f67 6296 {
a5777624
RD
6297 if ( CanDragColSize() && CanDragGridSize() )
6298 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
6d004f67
MB
6299 }
6300 }
91894db3 6301 else // Neither on a row or col edge
a5777624 6302 {
91894db3
VZ
6303 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
6304 {
6305 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
6306 }
a5777624
RD
6307 }
6308 }
6d004f67
MB
6309}
6310
6d004f67
MB
6311void wxGrid::DoEndDragResizeRow()
6312{
6313 if ( m_dragLastPos >= 0 )
6314 {
6315 // erase the last line and resize the row
6316 //
6317 int cw, ch, left, dummy;
6318 m_gridWin->GetClientSize( &cw, &ch );
6319 CalcUnscrolledPosition( 0, 0, &left, &dummy );
6320
6321 wxClientDC dc( m_gridWin );
6322 PrepareDC( dc );
6323 dc.SetLogicalFunction( wxINVERT );
a9339fe2 6324 dc.DrawLine( left, m_dragLastPos, left + cw, m_dragLastPos );
6d004f67 6325 HideCellEditControl();
a5777624 6326 SaveEditControlValue();
6d004f67 6327
7c1cb261 6328 int rowTop = GetRowTop(m_dragRowOrCol);
6d004f67 6329 SetRowSize( m_dragRowOrCol,
b8d24d4e 6330 wxMax( m_dragLastPos - rowTop, m_minAcceptableRowHeight ) );
e2b42eeb 6331
6d004f67
MB
6332 if ( !GetBatchCount() )
6333 {
6334 // Only needed to get the correct rect.y:
6335 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
6336 rect.x = 0;
6337 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
6338 rect.width = m_rowLabelWidth;
6339 rect.height = ch - rect.y;
ca65c044 6340 m_rowLabelWin->Refresh( true, &rect );
6d004f67 6341 rect.width = cw;
ccdee36f 6342
27f35b66
SN
6343 // if there is a multicell block, paint all of it
6344 if (m_table)
6345 {
6346 int i, cell_rows, cell_cols, subtract_rows = 0;
6347 int leftCol = XToCol(left);
a9339fe2 6348 int rightCol = internalXToCol(left + cw);
27f35b66
SN
6349 if (leftCol >= 0)
6350 {
27f35b66
SN
6351 for (i=leftCol; i<rightCol; i++)
6352 {
6353 GetCellSize(m_dragRowOrCol, i, &cell_rows, &cell_cols);
6354 if (cell_rows < subtract_rows)
6355 subtract_rows = cell_rows;
6356 }
6357 rect.y = GetRowTop(m_dragRowOrCol + subtract_rows);
6358 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
6359 rect.height = ch - rect.y;
6360 }
6361 }
ca65c044 6362 m_gridWin->Refresh( false, &rect );
6d004f67
MB
6363 }
6364
6365 ShowCellEditControl();
6366 }
6367}
6368
6369
6370void wxGrid::DoEndDragResizeCol()
6371{
6372 if ( m_dragLastPos >= 0 )
6373 {
6374 // erase the last line and resize the col
6375 //
6376 int cw, ch, dummy, top;
6377 m_gridWin->GetClientSize( &cw, &ch );
6378 CalcUnscrolledPosition( 0, 0, &dummy, &top );
6379
6380 wxClientDC dc( m_gridWin );
6381 PrepareDC( dc );
6382 dc.SetLogicalFunction( wxINVERT );
a9339fe2 6383 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch );
6d004f67 6384 HideCellEditControl();
a5777624 6385 SaveEditControlValue();
6d004f67 6386
7c1cb261 6387 int colLeft = GetColLeft(m_dragRowOrCol);
6d004f67 6388 SetColSize( m_dragRowOrCol,
43947979
VZ
6389 wxMax( m_dragLastPos - colLeft,
6390 GetColMinimalWidth(m_dragRowOrCol) ) );
6d004f67
MB
6391
6392 if ( !GetBatchCount() )
6393 {
6394 // Only needed to get the correct rect.x:
6395 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
6396 rect.y = 0;
6397 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
6398 rect.width = cw - rect.x;
6399 rect.height = m_colLabelHeight;
ca65c044 6400 m_colLabelWin->Refresh( true, &rect );
6d004f67 6401 rect.height = ch;
2f024384 6402
27f35b66
SN
6403 // if there is a multicell block, paint all of it
6404 if (m_table)
6405 {
6406 int i, cell_rows, cell_cols, subtract_cols = 0;
6407 int topRow = YToRow(top);
a9339fe2 6408 int bottomRow = internalYToRow(top + cw);
27f35b66
SN
6409 if (topRow >= 0)
6410 {
27f35b66
SN
6411 for (i=topRow; i<bottomRow; i++)
6412 {
6413 GetCellSize(i, m_dragRowOrCol, &cell_rows, &cell_cols);
6414 if (cell_cols < subtract_cols)
6415 subtract_cols = cell_cols;
6416 }
a9339fe2 6417
27f35b66
SN
6418 rect.x = GetColLeft(m_dragRowOrCol + subtract_cols);
6419 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
6420 rect.width = cw - rect.x;
6421 }
6422 }
2f024384 6423
ca65c044 6424 m_gridWin->Refresh( false, &rect );
790cc417 6425 }
e2b42eeb 6426
6d004f67 6427 ShowCellEditControl();
f85afd4e 6428 }
f85afd4e
MB
6429}
6430
d4175745
VZ
6431void wxGrid::DoEndDragMoveCol()
6432{
6433 //The user clicked on the column but didn't actually drag
6434 if ( m_dragLastPos < 0 )
6435 {
6436 m_colLabelWin->Refresh(); //Do this to "unpress" the column
6437 return;
6438 }
6439
6440 int newPos;
6441 if ( m_moveToCol == -1 )
6442 newPos = m_numCols - 1;
6443 else
6444 {
6445 newPos = GetColPos( m_moveToCol );
6446 if ( newPos > GetColPos( m_dragRowOrCol ) )
6447 newPos--;
6448 }
6449
6450 SetColPos( m_dragRowOrCol, newPos );
6451}
6452
6453void wxGrid::SetColPos( int colID, int newPos )
6454{
6455 if ( m_colAt.IsEmpty() )
6456 {
6457 m_colAt.Alloc( m_numCols );
6458
6459 int i;
6460 for ( i = 0; i < m_numCols; i++ )
6461 {
6462 m_colAt.Add( i );
6463 }
6464 }
6465
6466 int oldPos = GetColPos( colID );
6467
6468 //Reshuffle the m_colAt array
6469 if ( newPos > oldPos )
6470 {
6471 int i;
6472 for ( i = oldPos; i < newPos; i++ )
6473 {
6474 m_colAt[i] = m_colAt[i+1];
6475 }
6476 }
6477 else
6478 {
6479 int i;
6480 for ( i = oldPos; i > newPos; i-- )
6481 {
6482 m_colAt[i] = m_colAt[i-1];
6483 }
6484 }
6485
6486 m_colAt[newPos] = colID;
6487
6488 //Recalculate the column rights
6489 if ( !m_colWidths.IsEmpty() )
6490 {
6491 int colRight = 0;
6492 int colPos;
6493 for ( colPos = 0; colPos < m_numCols; colPos++ )
6494 {
6495 int colID = GetColAt( colPos );
6496
6497 colRight += m_colWidths[colID];
6498 m_colRights[colID] = colRight;
6499 }
6500 }
6501
6502 m_colLabelWin->Refresh();
6503 m_gridWin->Refresh();
6504}
6505
6506
6507
6508void wxGrid::EnableDragColMove( bool enable )
6509{
6510 if ( m_canDragColMove == enable )
6511 return;
6512
6513 m_canDragColMove = enable;
6514
6515 if ( !m_canDragColMove )
6516 {
6517 m_colAt.Clear();
6518
6519 //Recalculate the column rights
6520 if ( !m_colWidths.IsEmpty() )
6521 {
6522 int colRight = 0;
6523 int colPos;
6524 for ( colPos = 0; colPos < m_numCols; colPos++ )
6525 {
6526 colRight += m_colWidths[colPos];
6527 m_colRights[colPos] = colRight;
6528 }
6529 }
6530
6531 m_colLabelWin->Refresh();
6532 m_gridWin->Refresh();
6533 }
6534}
6535
6536
2d66e025
MB
6537//
6538// ------ interaction with data model
6539//
6540bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
f85afd4e 6541{
2d66e025 6542 switch ( msg.GetId() )
17732cec 6543 {
2d66e025
MB
6544 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
6545 return GetModelValues();
17732cec 6546
2d66e025
MB
6547 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
6548 return SetModelValues();
f85afd4e 6549
2d66e025
MB
6550 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
6551 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
6552 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
6553 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
6554 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
6555 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
6556 return Redimension( msg );
6557
6558 default:
ca65c044 6559 return false;
f85afd4e 6560 }
2d66e025 6561}
f85afd4e 6562
2d66e025 6563// The behaviour of this function depends on the grid table class
5b061713 6564// Clear() function. For the default wxGridStringTable class the
2d66e025
MB
6565// behavious is to replace all cell contents with wxEmptyString but
6566// not to change the number of rows or cols.
6567//
6568void wxGrid::ClearGrid()
6569{
6570 if ( m_table )
f85afd4e 6571 {
4cfa5de6
RD
6572 if (IsCellEditControlEnabled())
6573 DisableCellEditControl();
6574
2d66e025 6575 m_table->Clear();
5b061713 6576 if (!GetBatchCount())
a9339fe2 6577 m_gridWin->Refresh();
f85afd4e
MB
6578 }
6579}
6580
2d66e025 6581bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 6582{
2d66e025 6583 // TODO: something with updateLabels flag
8f177c8e 6584
2d66e025 6585 if ( !m_created )
f85afd4e 6586 {
bd3c6758 6587 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
ca65c044 6588 return false;
2d66e025 6589 }
8f177c8e 6590
2d66e025
MB
6591 if ( m_table )
6592 {
b7fff980 6593 if (IsCellEditControlEnabled())
b54ba671 6594 DisableCellEditControl();
b7fff980 6595
4ea3479c 6596 bool done = m_table->InsertRows( pos, numRows );
4ea3479c 6597 return done;
f85afd4e 6598
2d66e025
MB
6599 // the table will have sent the results of the insert row
6600 // operation to this view object as a grid table message
f85afd4e 6601 }
a9339fe2 6602
ca65c044 6603 return false;
f85afd4e
MB
6604}
6605
2d66e025 6606bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 6607{
2d66e025
MB
6608 // TODO: something with updateLabels flag
6609
6610 if ( !m_created )
f85afd4e 6611 {
bd3c6758 6612 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
ca65c044 6613 return false;
2d66e025
MB
6614 }
6615
4ea3479c
JS
6616 if ( m_table )
6617 {
6618 bool done = m_table && m_table->AppendRows( numRows );
4ea3479c 6619 return done;
a9339fe2 6620
4ea3479c
JS
6621 // the table will have sent the results of the append row
6622 // operation to this view object as a grid table message
6623 }
a9339fe2 6624
ca65c044 6625 return false;
f85afd4e
MB
6626}
6627
2d66e025 6628bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 6629{
2d66e025
MB
6630 // TODO: something with updateLabels flag
6631
6632 if ( !m_created )
f85afd4e 6633 {
bd3c6758 6634 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
ca65c044 6635 return false;
2d66e025
MB
6636 }
6637
b7fff980 6638 if ( m_table )
2d66e025 6639 {
b7fff980 6640 if (IsCellEditControlEnabled())
b54ba671 6641 DisableCellEditControl();
f85afd4e 6642
4ea3479c 6643 bool done = m_table->DeleteRows( pos, numRows );
4ea3479c 6644 return done;
f6bcfd97
BP
6645 // the table will have sent the results of the delete row
6646 // operation to this view object as a grid table message
2d66e025 6647 }
a9339fe2 6648
ca65c044 6649 return false;
2d66e025 6650}
f85afd4e 6651
2d66e025
MB
6652bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
6653{
6654 // TODO: something with updateLabels flag
8f177c8e 6655
2d66e025
MB
6656 if ( !m_created )
6657 {
bd3c6758 6658 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
ca65c044 6659 return false;
2d66e025 6660 }
f85afd4e 6661
2d66e025
MB
6662 if ( m_table )
6663 {
b7fff980 6664 if (IsCellEditControlEnabled())
b54ba671 6665 DisableCellEditControl();
b7fff980 6666
4ea3479c 6667 bool done = m_table->InsertCols( pos, numCols );
4ea3479c 6668 return done;
2d66e025
MB
6669 // the table will have sent the results of the insert col
6670 // operation to this view object as a grid table message
f85afd4e 6671 }
2f024384 6672
ca65c044 6673 return false;
f85afd4e
MB
6674}
6675
2d66e025 6676bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 6677{
2d66e025
MB
6678 // TODO: something with updateLabels flag
6679
6680 if ( !m_created )
f85afd4e 6681 {
bd3c6758 6682 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
ca65c044 6683 return false;
2d66e025 6684 }
f85afd4e 6685
4ea3479c
JS
6686 if ( m_table )
6687 {
6688 bool done = m_table->AppendCols( numCols );
4ea3479c
JS
6689 return done;
6690 // the table will have sent the results of the append col
6691 // operation to this view object as a grid table message
6692 }
2f024384 6693
ca65c044 6694 return false;
f85afd4e
MB
6695}
6696
2d66e025 6697bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 6698{
2d66e025 6699 // TODO: something with updateLabels flag
8f177c8e 6700
2d66e025 6701 if ( !m_created )
f85afd4e 6702 {
bd3c6758 6703 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
ca65c044 6704 return false;
f85afd4e
MB
6705 }
6706
b7fff980 6707 if ( m_table )
2d66e025 6708 {
b7fff980 6709 if (IsCellEditControlEnabled())
b54ba671 6710 DisableCellEditControl();
8f177c8e 6711
4ea3479c 6712 bool done = m_table->DeleteCols( pos, numCols );
4ea3479c 6713 return done;
f6bcfd97
BP
6714 // the table will have sent the results of the delete col
6715 // operation to this view object as a grid table message
f85afd4e 6716 }
2f024384 6717
ca65c044 6718 return false;
f85afd4e
MB
6719}
6720
2d66e025
MB
6721//
6722// ----- event handlers
f85afd4e 6723//
8f177c8e 6724
2d66e025
MB
6725// Generate a grid event based on a mouse event and
6726// return the result of ProcessEvent()
6727//
fe7b9ed6 6728int wxGrid::SendEvent( const wxEventType type,
2d66e025
MB
6729 int row, int col,
6730 wxMouseEvent& mouseEv )
6731{
2f024384 6732 bool claimed, vetoed;
fe7b9ed6 6733
97a9929e
VZ
6734 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
6735 {
6736 int rowOrCol = (row == -1 ? col : row);
6737
6738 wxGridSizeEvent gridEvt( GetId(),
6739 type,
6740 this,
6741 rowOrCol,
6742 mouseEv.GetX() + GetRowLabelSize(),
6743 mouseEv.GetY() + GetColLabelSize(),
6744 mouseEv.ControlDown(),
6745 mouseEv.ShiftDown(),
6746 mouseEv.AltDown(),
6747 mouseEv.MetaDown() );
6748
6749 claimed = GetEventHandler()->ProcessEvent(gridEvt);
6750 vetoed = !gridEvt.IsAllowed();
6751 }
fe7b9ed6 6752 else if ( type == wxEVT_GRID_RANGE_SELECT )
97a9929e
VZ
6753 {
6754 // Right now, it should _never_ end up here!
6755 wxGridRangeSelectEvent gridEvt( GetId(),
6756 type,
6757 this,
6758 m_selectingTopLeft,
6759 m_selectingBottomRight,
ca65c044 6760 true,
97a9929e
VZ
6761 mouseEv.ControlDown(),
6762 mouseEv.ShiftDown(),
6763 mouseEv.AltDown(),
6764 mouseEv.MetaDown() );
6765
6766 claimed = GetEventHandler()->ProcessEvent(gridEvt);
6767 vetoed = !gridEvt.IsAllowed();
6768 }
2b73a34e
RD
6769 else if ( type == wxEVT_GRID_LABEL_LEFT_CLICK ||
6770 type == wxEVT_GRID_LABEL_LEFT_DCLICK ||
6771 type == wxEVT_GRID_LABEL_RIGHT_CLICK ||
6772 type == wxEVT_GRID_LABEL_RIGHT_DCLICK )
6773 {
6774 wxPoint pos = mouseEv.GetPosition();
6775
6776 if ( mouseEv.GetEventObject() == GetGridRowLabelWindow() )
6777 pos.y += GetColLabelSize();
6778 if ( mouseEv.GetEventObject() == GetGridColLabelWindow() )
6779 pos.x += GetRowLabelSize();
c71b2126 6780
2b73a34e
RD
6781 wxGridEvent gridEvt( GetId(),
6782 type,
6783 this,
6784 row, col,
6785 pos.x,
6786 pos.y,
6787 false,
6788 mouseEv.ControlDown(),
6789 mouseEv.ShiftDown(),
6790 mouseEv.AltDown(),
6791 mouseEv.MetaDown() );
6792 claimed = GetEventHandler()->ProcessEvent(gridEvt);
6793 vetoed = !gridEvt.IsAllowed();
6794 }
fe7b9ed6 6795 else
97a9929e
VZ
6796 {
6797 wxGridEvent gridEvt( GetId(),
6798 type,
6799 this,
6800 row, col,
6801 mouseEv.GetX() + GetRowLabelSize(),
6802 mouseEv.GetY() + GetColLabelSize(),
ca65c044 6803 false,
97a9929e
VZ
6804 mouseEv.ControlDown(),
6805 mouseEv.ShiftDown(),
6806 mouseEv.AltDown(),
6807 mouseEv.MetaDown() );
6808 claimed = GetEventHandler()->ProcessEvent(gridEvt);
6809 vetoed = !gridEvt.IsAllowed();
6810 }
6811
6812 // A Veto'd event may not be `claimed' so test this first
4db6714b
KH
6813 if (vetoed)
6814 return -1;
6815
97a9929e 6816 return claimed ? 1 : 0;
f85afd4e
MB
6817}
6818
2d66e025
MB
6819// Generate a grid event of specified type and return the result
6820// of ProcessEvent().
f85afd4e 6821//
fe7b9ed6 6822int wxGrid::SendEvent( const wxEventType type,
2d66e025 6823 int row, int col )
f85afd4e 6824{
a9339fe2 6825 bool claimed, vetoed;
fe7b9ed6 6826
b54ba671 6827 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
f85afd4e 6828 {
2d66e025 6829 int rowOrCol = (row == -1 ? col : row);
f85afd4e 6830
a9339fe2 6831 wxGridSizeEvent gridEvt( GetId(), type, this, rowOrCol );
2d66e025 6832
fe7b9ed6
VZ
6833 claimed = GetEventHandler()->ProcessEvent(gridEvt);
6834 vetoed = !gridEvt.IsAllowed();
2d66e025
MB
6835 }
6836 else
6837 {
a9339fe2 6838 wxGridEvent gridEvt( GetId(), type, this, row, col );
8f177c8e 6839
fe7b9ed6
VZ
6840 claimed = GetEventHandler()->ProcessEvent(gridEvt);
6841 vetoed = !gridEvt.IsAllowed();
6842 }
6843
97a9929e 6844 // A Veto'd event may not be `claimed' so test this first
4db6714b
KH
6845 if (vetoed)
6846 return -1;
6847
97a9929e 6848 return claimed ? 1 : 0;
f85afd4e
MB
6849}
6850
2d66e025 6851void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
f85afd4e 6852{
3d59537f
DS
6853 // needed to prevent zillions of paint events on MSW
6854 wxPaintDC dc(this);
8f177c8e 6855}
f85afd4e 6856
bca7bfc8 6857void wxGrid::Refresh(bool eraseb, const wxRect* rect)
27f35b66 6858{
ad603bf7
VZ
6859 // Don't do anything if between Begin/EndBatch...
6860 // EndBatch() will do all this on the last nested one anyway.
27f35b66
SN
6861 if (! GetBatchCount())
6862 {
bca7bfc8 6863 // Refresh to get correct scrolled position:
4db6714b 6864 wxScrolledWindow::Refresh(eraseb, rect);
27f35b66 6865
27f35b66
SN
6866 if (rect)
6867 {
bca7bfc8
SN
6868 int rect_x, rect_y, rectWidth, rectHeight;
6869 int width_label, width_cell, height_label, height_cell;
6870 int x, y;
6871
2f024384 6872 // Copy rectangle can get scroll offsets..
bca7bfc8
SN
6873 rect_x = rect->GetX();
6874 rect_y = rect->GetY();
6875 rectWidth = rect->GetWidth();
6876 rectHeight = rect->GetHeight();
27f35b66 6877
bca7bfc8 6878 width_label = m_rowLabelWidth - rect_x;
4db6714b
KH
6879 if (width_label > rectWidth)
6880 width_label = rectWidth;
27f35b66 6881
bca7bfc8 6882 height_label = m_colLabelHeight - rect_y;
a9339fe2
DS
6883 if (height_label > rectHeight)
6884 height_label = rectHeight;
27f35b66 6885
bca7bfc8
SN
6886 if (rect_x > m_rowLabelWidth)
6887 {
6888 x = rect_x - m_rowLabelWidth;
6889 width_cell = rectWidth;
6890 }
6891 else
6892 {
6893 x = 0;
6894 width_cell = rectWidth - (m_rowLabelWidth - rect_x);
6895 }
6896
6897 if (rect_y > m_colLabelHeight)
6898 {
6899 y = rect_y - m_colLabelHeight;
6900 height_cell = rectHeight;
6901 }
6902 else
6903 {
6904 y = 0;
6905 height_cell = rectHeight - (m_colLabelHeight - rect_y);
6906 }
6907
6908 // Paint corner label part intersecting rect.
6909 if ( width_label > 0 && height_label > 0 )
6910 {
6911 wxRect anotherrect(rect_x, rect_y, width_label, height_label);
6912 m_cornerLabelWin->Refresh(eraseb, &anotherrect);
6913 }
6914
6915 // Paint col labels part intersecting rect.
6916 if ( width_cell > 0 && height_label > 0 )
6917 {
6918 wxRect anotherrect(x, rect_y, width_cell, height_label);
6919 m_colLabelWin->Refresh(eraseb, &anotherrect);
6920 }
6921
6922 // Paint row labels part intersecting rect.
6923 if ( width_label > 0 && height_cell > 0 )
6924 {
6925 wxRect anotherrect(rect_x, y, width_label, height_cell);
6926 m_rowLabelWin->Refresh(eraseb, &anotherrect);
6927 }
6928
6929 // Paint cell area part intersecting rect.
6930 if ( width_cell > 0 && height_cell > 0 )
6931 {
6932 wxRect anotherrect(x, y, width_cell, height_cell);
6933 m_gridWin->Refresh(eraseb, &anotherrect);
6934 }
6935 }
6936 else
6937 {
6938 m_cornerLabelWin->Refresh(eraseb, NULL);
2b5f62a0 6939 m_colLabelWin->Refresh(eraseb, NULL);
bca7bfc8
SN
6940 m_rowLabelWin->Refresh(eraseb, NULL);
6941 m_gridWin->Refresh(eraseb, NULL);
6942 }
27f35b66
SN
6943 }
6944}
f85afd4e 6945
c71b2126 6946void wxGrid::OnSize(wxSizeEvent& WXUNUSED(event))
f85afd4e 6947{
c71b2126
VZ
6948 // update our children window positions and scrollbars
6949 CalcDimensions();
f85afd4e
MB
6950}
6951
2d66e025 6952void wxGrid::OnKeyDown( wxKeyEvent& event )
f85afd4e 6953{
2d66e025 6954 if ( m_inOnKeyDown )
f85afd4e 6955 {
2d66e025
MB
6956 // shouldn't be here - we are going round in circles...
6957 //
07296f0b 6958 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
f85afd4e
MB
6959 }
6960
ca65c044 6961 m_inOnKeyDown = true;
f85afd4e 6962
2d66e025 6963 // propagate the event up and see if it gets processed
2d66e025
MB
6964 wxWindow *parent = GetParent();
6965 wxKeyEvent keyEvt( event );
6966 keyEvt.SetEventObject( parent );
6967
6968 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
f85afd4e 6969 {
bcb614b3
RR
6970 if (GetLayoutDirection() == wxLayout_RightToLeft)
6971 {
6972 if (event.GetKeyCode() == WXK_RIGHT)
6973 event.m_keyCode = WXK_LEFT;
6974 else if (event.GetKeyCode() == WXK_LEFT)
6975 event.m_keyCode = WXK_RIGHT;
6976 }
c71b2126 6977
2d66e025 6978 // try local handlers
12a3f227 6979 switch ( event.GetKeyCode() )
2d66e025
MB
6980 {
6981 case WXK_UP:
6982 if ( event.ControlDown() )
5c8fc7c1 6983 MoveCursorUpBlock( event.ShiftDown() );
2d66e025 6984 else
5c8fc7c1 6985 MoveCursorUp( event.ShiftDown() );
2d66e025 6986 break;
f85afd4e 6987
2d66e025
MB
6988 case WXK_DOWN:
6989 if ( event.ControlDown() )
5c8fc7c1 6990 MoveCursorDownBlock( event.ShiftDown() );
2d66e025 6991 else
5c8fc7c1 6992 MoveCursorDown( event.ShiftDown() );
2d66e025 6993 break;
8f177c8e 6994
2d66e025
MB
6995 case WXK_LEFT:
6996 if ( event.ControlDown() )
5c8fc7c1 6997 MoveCursorLeftBlock( event.ShiftDown() );
2d66e025 6998 else
5c8fc7c1 6999 MoveCursorLeft( event.ShiftDown() );
2d66e025
MB
7000 break;
7001
7002 case WXK_RIGHT:
7003 if ( event.ControlDown() )
5c8fc7c1 7004 MoveCursorRightBlock( event.ShiftDown() );
2d66e025 7005 else
5c8fc7c1 7006 MoveCursorRight( event.ShiftDown() );
2d66e025 7007 break;
b99be8fb 7008
2d66e025 7009 case WXK_RETURN:
a4f7bf58 7010 case WXK_NUMPAD_ENTER:
58dd5b3b
MB
7011 if ( event.ControlDown() )
7012 {
7013 event.Skip(); // to let the edit control have the return
7014 }
7015 else
7016 {
f6bcfd97
BP
7017 if ( GetGridCursorRow() < GetNumberRows()-1 )
7018 {
7019 MoveCursorDown( event.ShiftDown() );
7020 }
7021 else
7022 {
7023 // at the bottom of a column
13f6e9e8 7024 DisableCellEditControl();
f6bcfd97 7025 }
58dd5b3b 7026 }
2d66e025
MB
7027 break;
7028
5c8fc7c1 7029 case WXK_ESCAPE:
e32352cf 7030 ClearSelection();
5c8fc7c1
SN
7031 break;
7032
2c9a89e0
RD
7033 case WXK_TAB:
7034 if (event.ShiftDown())
f6bcfd97
BP
7035 {
7036 if ( GetGridCursorCol() > 0 )
7037 {
ca65c044 7038 MoveCursorLeft( false );
f6bcfd97
BP
7039 }
7040 else
7041 {
7042 // at left of grid
13f6e9e8 7043 DisableCellEditControl();
f6bcfd97
BP
7044 }
7045 }
2c9a89e0 7046 else
f6bcfd97 7047 {
ccdee36f 7048 if ( GetGridCursorCol() < GetNumberCols() - 1 )
f6bcfd97 7049 {
ca65c044 7050 MoveCursorRight( false );
f6bcfd97
BP
7051 }
7052 else
7053 {
7054 // at right of grid
13f6e9e8 7055 DisableCellEditControl();
f6bcfd97
BP
7056 }
7057 }
2c9a89e0
RD
7058 break;
7059
2d66e025
MB
7060 case WXK_HOME:
7061 if ( event.ControlDown() )
7062 {
7063 MakeCellVisible( 0, 0 );
7064 SetCurrentCell( 0, 0 );
7065 }
7066 else
7067 {
7068 event.Skip();
7069 }
7070 break;
7071
7072 case WXK_END:
7073 if ( event.ControlDown() )
7074 {
a9339fe2
DS
7075 MakeCellVisible( m_numRows - 1, m_numCols - 1 );
7076 SetCurrentCell( m_numRows - 1, m_numCols - 1 );
2d66e025
MB
7077 }
7078 else
7079 {
7080 event.Skip();
7081 }
7082 break;
7083
faa94f3e 7084 case WXK_PAGEUP:
2d66e025
MB
7085 MovePageUp();
7086 break;
7087
faa94f3e 7088 case WXK_PAGEDOWN:
2d66e025
MB
7089 MovePageDown();
7090 break;
7091
07296f0b 7092 case WXK_SPACE:
aa5e1f75
SN
7093 if ( event.ControlDown() )
7094 {
3f3dc2ef
VZ
7095 if ( m_selection )
7096 {
a9339fe2
DS
7097 m_selection->ToggleCellSelection(
7098 m_currentCellCoords.GetRow(),
7099 m_currentCellCoords.GetCol(),
7100 event.ControlDown(),
7101 event.ShiftDown(),
7102 event.AltDown(),
7103 event.MetaDown() );
3f3dc2ef 7104 }
aa5e1f75
SN
7105 break;
7106 }
ccdee36f 7107
07296f0b 7108 if ( !IsEditable() )
ca65c044 7109 MoveCursorRight( false );
ccdee36f
DS
7110 else
7111 event.Skip();
7112 break;
07296f0b 7113
2d66e025 7114 default:
63e2147c 7115 event.Skip();
025562fe 7116 break;
2d66e025 7117 }
f85afd4e
MB
7118 }
7119
ca65c044 7120 m_inOnKeyDown = false;
f85afd4e
MB
7121}
7122
f6bcfd97
BP
7123void wxGrid::OnKeyUp( wxKeyEvent& event )
7124{
7125 // try local handlers
7126 //
12a3f227 7127 if ( event.GetKeyCode() == WXK_SHIFT )
f6bcfd97
BP
7128 {
7129 if ( m_selectingTopLeft != wxGridNoCellCoords &&
7130 m_selectingBottomRight != wxGridNoCellCoords )
3f3dc2ef
VZ
7131 {
7132 if ( m_selection )
7133 {
a9339fe2
DS
7134 m_selection->SelectBlock(
7135 m_selectingTopLeft.GetRow(),
7136 m_selectingTopLeft.GetCol(),
7137 m_selectingBottomRight.GetRow(),
7138 m_selectingBottomRight.GetCol(),
7139 event.ControlDown(),
7140 true,
7141 event.AltDown(),
7142 event.MetaDown() );
3f3dc2ef
VZ
7143 }
7144 }
7145
f6bcfd97
BP
7146 m_selectingTopLeft = wxGridNoCellCoords;
7147 m_selectingBottomRight = wxGridNoCellCoords;
7148 m_selectingKeyboard = wxGridNoCellCoords;
7149 }
7150}
7151
63e2147c
RD
7152void wxGrid::OnChar( wxKeyEvent& event )
7153{
7154 // is it possible to edit the current cell at all?
7155 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
7156 {
7157 // yes, now check whether the cells editor accepts the key
7158 int row = m_currentCellCoords.GetRow();
7159 int col = m_currentCellCoords.GetCol();
2f024384 7160 wxGridCellAttr *attr = GetCellAttr(row, col);
63e2147c
RD
7161 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
7162
7163 // <F2> is special and will always start editing, for
7164 // other keys - ask the editor itself
7165 if ( (event.GetKeyCode() == WXK_F2 && !event.HasModifiers())
7166 || editor->IsAcceptedKey(event) )
7167 {
7168 // ensure cell is visble
7169 MakeCellVisible(row, col);
7170 EnableCellEditControl();
7171
7172 // a problem can arise if the cell is not completely
7173 // visible (even after calling MakeCellVisible the
7174 // control is not created and calling StartingKey will
7175 // crash the app
046d682f 7176 if ( event.GetKeyCode() != WXK_F2 && editor->IsCreated() && m_cellEditCtrlEnabled )
63e2147c
RD
7177 editor->StartingKey(event);
7178 }
7179 else
7180 {
7181 event.Skip();
7182 }
7183
7184 editor->DecRef();
7185 attr->DecRef();
7186 }
7187 else
7188 {
7189 event.Skip();
7190 }
7191}
7192
2796cce3 7193void wxGrid::OnEraseBackground(wxEraseEvent&)
508011ce
VZ
7194{
7195}
07296f0b 7196
2d66e025 7197void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
66242c80 7198{
f6bcfd97
BP
7199 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
7200 {
7201 // the event has been intercepted - do nothing
7202 return;
7203 }
7204
5d38a5f3 7205#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS)
bee19958
DS
7206 wxClientDC dc( m_gridWin );
7207 PrepareDC( dc );
5d38a5f3 7208#endif
f6bcfd97 7209
2a7750d9 7210 if ( m_currentCellCoords != wxGridNoCellCoords )
2d66e025 7211 {
b54ba671 7212 DisableCellEditControl();
07296f0b 7213
ca65c044 7214 if ( IsVisible( m_currentCellCoords, false ) )
f6bcfd97
BP
7215 {
7216 wxRect r;
bee19958 7217 r = BlockToDeviceRect( m_currentCellCoords, m_currentCellCoords );
f6bcfd97
BP
7218 if ( !m_gridLinesEnabled )
7219 {
7220 r.x--;
7221 r.y--;
7222 r.width++;
7223 r.height++;
7224 }
d1c0b4f9 7225
3ed884a0 7226 wxGridCellCoordsArray cells = CalcCellsExposed( r );
84912ef8 7227
f6bcfd97
BP
7228 // Otherwise refresh redraws the highlight!
7229 m_currentCellCoords = coords;
275c4ae4 7230
5d38a5f3
JS
7231#if defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS
7232 m_gridWin->Refresh(true /*, & r */);
7233#else
bee19958 7234 DrawGridCellArea( dc, cells );
f6bcfd97 7235 DrawAllGridLines( dc, r );
5d38a5f3 7236#endif
f6bcfd97 7237 }
66242c80 7238 }
8f177c8e 7239
2d66e025
MB
7240 m_currentCellCoords = coords;
7241
bee19958 7242 wxGridCellAttr *attr = GetCellAttr( coords );
5d38a5f3 7243#if !(defined(__WXMAC__) && wxMAC_USE_CORE_GRAPHICS)
bee19958 7244 DrawCellHighlight( dc, attr );
5d38a5f3 7245#endif
2a7750d9 7246 attr->DecRef();
66242c80
MB
7247}
7248
c9097836
MB
7249void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol )
7250{
7251 int temp;
7252 wxGridCellCoords updateTopLeft, updateBottomRight;
7253
3f3dc2ef 7254 if ( m_selection )
c9097836 7255 {
3f3dc2ef
VZ
7256 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
7257 {
7258 leftCol = 0;
7259 rightCol = GetNumberCols() - 1;
7260 }
7261 else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
7262 {
7263 topRow = 0;
7264 bottomRow = GetNumberRows() - 1;
7265 }
c9097836 7266 }
3f3dc2ef 7267
c9097836
MB
7268 if ( topRow > bottomRow )
7269 {
7270 temp = topRow;
7271 topRow = bottomRow;
7272 bottomRow = temp;
7273 }
7274
7275 if ( leftCol > rightCol )
7276 {
7277 temp = leftCol;
7278 leftCol = rightCol;
7279 rightCol = temp;
7280 }
7281
7282 updateTopLeft = wxGridCellCoords( topRow, leftCol );
7283 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
7284
3ed884a0
SN
7285 // First the case that we selected a completely new area
7286 if ( m_selectingTopLeft == wxGridNoCellCoords ||
7287 m_selectingBottomRight == wxGridNoCellCoords )
7288 {
7289 wxRect rect;
7290 rect = BlockToDeviceRect( wxGridCellCoords ( topRow, leftCol ),
7291 wxGridCellCoords ( bottomRow, rightCol ) );
ca65c044 7292 m_gridWin->Refresh( false, &rect );
3ed884a0 7293 }
2f024384 7294
3ed884a0
SN
7295 // Now handle changing an existing selection area.
7296 else if ( m_selectingTopLeft != updateTopLeft ||
7297 m_selectingBottomRight != updateBottomRight )
c9097836
MB
7298 {
7299 // Compute two optimal update rectangles:
7300 // Either one rectangle is a real subset of the
7301 // other, or they are (almost) disjoint!
7302 wxRect rect[4];
7303 bool need_refresh[4];
7304 need_refresh[0] =
7305 need_refresh[1] =
7306 need_refresh[2] =
ca65c044 7307 need_refresh[3] = false;
c9097836
MB
7308 int i;
7309
7310 // Store intermediate values
a9339fe2
DS
7311 wxCoord oldLeft = m_selectingTopLeft.GetCol();
7312 wxCoord oldTop = m_selectingTopLeft.GetRow();
7313 wxCoord oldRight = m_selectingBottomRight.GetCol();
c9097836
MB
7314 wxCoord oldBottom = m_selectingBottomRight.GetRow();
7315
7316 // Determine the outer/inner coordinates.
7317 if (oldLeft > leftCol)
7318 {
7319 temp = oldLeft;
7320 oldLeft = leftCol;
7321 leftCol = temp;
7322 }
7323 if (oldTop > topRow )
7324 {
7325 temp = oldTop;
7326 oldTop = topRow;
7327 topRow = temp;
7328 }
7329 if (oldRight < rightCol )
7330 {
7331 temp = oldRight;
7332 oldRight = rightCol;
7333 rightCol = temp;
7334 }
7335 if (oldBottom < bottomRow)
7336 {
7337 temp = oldBottom;
7338 oldBottom = bottomRow;
7339 bottomRow = temp;
7340 }
7341
7342 // Now, either the stuff marked old is the outer
7343 // rectangle or we don't have a situation where one
7344 // is contained in the other.
7345
7346 if ( oldLeft < leftCol )
7347 {
3ed884a0
SN
7348 // Refresh the newly selected or deselected
7349 // area to the left of the old or new selection.
ca65c044 7350 need_refresh[0] = true;
a9339fe2
DS
7351 rect[0] = BlockToDeviceRect(
7352 wxGridCellCoords( oldTop, oldLeft ),
7353 wxGridCellCoords( oldBottom, leftCol - 1 ) );
c9097836
MB
7354 }
7355
2f024384 7356 if ( oldTop < topRow )
c9097836 7357 {
3ed884a0
SN
7358 // Refresh the newly selected or deselected
7359 // area above the old or new selection.
ca65c044 7360 need_refresh[1] = true;
2f024384
DS
7361 rect[1] = BlockToDeviceRect(
7362 wxGridCellCoords( oldTop, leftCol ),
7363 wxGridCellCoords( topRow - 1, rightCol ) );
c9097836
MB
7364 }
7365
7366 if ( oldRight > rightCol )
7367 {
3ed884a0
SN
7368 // Refresh the newly selected or deselected
7369 // area to the right of the old or new selection.
ca65c044 7370 need_refresh[2] = true;
2f024384 7371 rect[2] = BlockToDeviceRect(
a9339fe2
DS
7372 wxGridCellCoords( oldTop, rightCol + 1 ),
7373 wxGridCellCoords( oldBottom, oldRight ) );
c9097836
MB
7374 }
7375
7376 if ( oldBottom > bottomRow )
7377 {
3ed884a0
SN
7378 // Refresh the newly selected or deselected
7379 // area below the old or new selection.
ca65c044 7380 need_refresh[3] = true;
2f024384 7381 rect[3] = BlockToDeviceRect(
a9339fe2
DS
7382 wxGridCellCoords( bottomRow + 1, leftCol ),
7383 wxGridCellCoords( oldBottom, rightCol ) );
c9097836
MB
7384 }
7385
c9097836
MB
7386 // various Refresh() calls
7387 for (i = 0; i < 4; i++ )
7388 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
ca65c044 7389 m_gridWin->Refresh( false, &(rect[i]) );
c9097836 7390 }
2f024384
DS
7391
7392 // change selection
3ed884a0
SN
7393 m_selectingTopLeft = updateTopLeft;
7394 m_selectingBottomRight = updateBottomRight;
c9097836
MB
7395}
7396
2d66e025
MB
7397//
7398// ------ functions to get/send data (see also public functions)
7399//
7400
7401bool wxGrid::GetModelValues()
66242c80 7402{
bca7bfc8
SN
7403 // Hide the editor, so it won't hide a changed value.
7404 HideCellEditControl();
c6707d16 7405
2d66e025 7406 if ( m_table )
66242c80 7407 {
2d66e025 7408 // all we need to do is repaint the grid
66242c80 7409 //
2d66e025 7410 m_gridWin->Refresh();
ca65c044 7411 return true;
66242c80 7412 }
8f177c8e 7413
ca65c044 7414 return false;
66242c80
MB
7415}
7416
2d66e025 7417bool wxGrid::SetModelValues()
f85afd4e 7418{
2d66e025 7419 int row, col;
8f177c8e 7420
c6707d16
SN
7421 // Disable the editor, so it won't hide a changed value.
7422 // Do we also want to save the current value of the editor first?
7423 // I think so ...
c6707d16
SN
7424 DisableCellEditControl();
7425
2d66e025
MB
7426 if ( m_table )
7427 {
56b6cf26 7428 for ( row = 0; row < m_numRows; row++ )
f85afd4e 7429 {
56b6cf26 7430 for ( col = 0; col < m_numCols; col++ )
f85afd4e 7431 {
2d66e025 7432 m_table->SetValue( row, col, GetCellValue(row, col) );
f85afd4e
MB
7433 }
7434 }
8f177c8e 7435
ca65c044 7436 return true;
f85afd4e
MB
7437 }
7438
ca65c044 7439 return false;
f85afd4e
MB
7440}
7441
2d66e025
MB
7442// Note - this function only draws cells that are in the list of
7443// exposed cells (usually set from the update region by
7444// CalcExposedCells)
7445//
d10f4bf9 7446void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells )
f85afd4e 7447{
4db6714b
KH
7448 if ( !m_numRows || !m_numCols )
7449 return;
60ff3b99 7450
dc1f566f 7451 int i, numCells = cells.GetCount();
27f35b66
SN
7452 int row, col, cell_rows, cell_cols;
7453 wxGridCellCoordsArray redrawCells;
60ff3b99 7454
a9339fe2 7455 for ( i = numCells - 1; i >= 0; i-- )
f85afd4e 7456 {
27f35b66
SN
7457 row = cells[i].GetRow();
7458 col = cells[i].GetCol();
7459 GetCellSize( row, col, &cell_rows, &cell_cols );
7460
7461 // If this cell is part of a multicell block, find owner for repaint
7462 if ( cell_rows <= 0 || cell_cols <= 0 )
7463 {
a9339fe2 7464 wxGridCellCoords cell( row + cell_rows, col + cell_cols );
ca65c044 7465 bool marked = false;
56b6cf26 7466 for ( int j = 0; j < numCells; j++ )
27f35b66
SN
7467 {
7468 if ( cell == cells[j] )
7469 {
ca65c044 7470 marked = true;
3ed884a0 7471 break;
27f35b66
SN
7472 }
7473 }
2f024384 7474
27f35b66
SN
7475 if (!marked)
7476 {
7477 int count = redrawCells.GetCount();
dc1f566f 7478 for (int j = 0; j < count; j++)
27f35b66
SN
7479 {
7480 if ( cell == redrawCells[j] )
7481 {
ca65c044 7482 marked = true;
27f35b66
SN
7483 break;
7484 }
7485 }
2f024384 7486
4db6714b
KH
7487 if (!marked)
7488 redrawCells.Add( cell );
27f35b66 7489 }
2f024384
DS
7490
7491 // don't bother drawing this cell
7492 continue;
27f35b66
SN
7493 }
7494
7495 // If this cell is empty, find cell to left that might want to overflow
7496 if (m_table && m_table->IsEmptyCell(row, col))
7497 {
dc1f566f 7498 for ( int l = 0; l < cell_rows; l++ )
27f35b66 7499 {
56b6cf26 7500 // find a cell in this row to leave already marked for repaint
dc1f566f
SN
7501 int left = col;
7502 for (int k = 0; k < int(redrawCells.GetCount()); k++)
7503 if ((redrawCells[k].GetCol() < left) &&
7504 (redrawCells[k].GetRow() == row))
2f024384 7505 {
4db6714b 7506 left = redrawCells[k].GetCol();
2f024384 7507 }
dc1f566f 7508
4db6714b
KH
7509 if (left == col)
7510 left = 0; // oh well
dc1f566f 7511
2f024384 7512 for (int j = col - 1; j >= left; j--)
27f35b66 7513 {
2f024384 7514 if (!m_table->IsEmptyCell(row + l, j))
27f35b66 7515 {
2f024384 7516 if (GetCellOverflow(row + l, j))
27f35b66 7517 {
2f024384 7518 wxGridCellCoords cell(row + l, j);
ca65c044 7519 bool marked = false;
27f35b66 7520
dc1f566f 7521 for (int k = 0; k < numCells; k++)
27f35b66
SN
7522 {
7523 if ( cell == cells[k] )
7524 {
ca65c044 7525 marked = true;
27f35b66
SN
7526 break;
7527 }
7528 }
4db6714b 7529
27f35b66
SN
7530 if (!marked)
7531 {
7532 int count = redrawCells.GetCount();
dc1f566f 7533 for (int k = 0; k < count; k++)
27f35b66
SN
7534 {
7535 if ( cell == redrawCells[k] )
7536 {
ca65c044 7537 marked = true;
27f35b66
SN
7538 break;
7539 }
7540 }
4db6714b
KH
7541 if (!marked)
7542 redrawCells.Add( cell );
27f35b66
SN
7543 }
7544 }
7545 break;
7546 }
7547 }
7548 }
7549 }
4db6714b 7550
d10f4bf9 7551 DrawCell( dc, cells[i] );
2d66e025 7552 }
27f35b66
SN
7553
7554 numCells = redrawCells.GetCount();
7555
56b6cf26 7556 for ( i = numCells - 1; i >= 0; i-- )
27f35b66
SN
7557 {
7558 DrawCell( dc, redrawCells[i] );
7559 }
2d66e025 7560}
8f177c8e 7561
7c8a8ad5
MB
7562void wxGrid::DrawGridSpace( wxDC& dc )
7563{
f6bcfd97
BP
7564 int cw, ch;
7565 m_gridWin->GetClientSize( &cw, &ch );
7c8a8ad5 7566
f6bcfd97
BP
7567 int right, bottom;
7568 CalcUnscrolledPosition( cw, ch, &right, &bottom );
7c8a8ad5 7569
d4175745 7570 int rightCol = m_numCols > 0 ? GetColRight(GetColAt( m_numCols - 1 )) : 0;
2f024384 7571 int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0;
7c8a8ad5 7572
f6bcfd97
BP
7573 if ( right > rightCol || bottom > bottomRow )
7574 {
7575 int left, top;
7576 CalcUnscrolledPosition( 0, 0, &left, &top );
7c8a8ad5 7577
f6bcfd97
BP
7578 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
7579 dc.SetPen( *wxTRANSPARENT_PEN );
7c8a8ad5 7580
f6bcfd97
BP
7581 if ( right > rightCol )
7582 {
a9339fe2 7583 dc.DrawRectangle( rightCol, top, right - rightCol, ch );
f6bcfd97
BP
7584 }
7585
7586 if ( bottom > bottomRow )
7587 {
a9339fe2 7588 dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow );
f6bcfd97
BP
7589 }
7590 }
7c8a8ad5
MB
7591}
7592
2d66e025
MB
7593void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
7594{
ab79958a
VZ
7595 int row = coords.GetRow();
7596 int col = coords.GetCol();
60ff3b99 7597
7c1cb261 7598 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
ab79958a
VZ
7599 return;
7600
7601 // we draw the cell border ourselves
9496deb5 7602#if !WXGRID_DRAW_LINES
2d66e025
MB
7603 if ( m_gridLinesEnabled )
7604 DrawCellBorder( dc, coords );
796df70a 7605#endif
f85afd4e 7606
189d0213
VZ
7607 wxGridCellAttr* attr = GetCellAttr(row, col);
7608
7609 bool isCurrent = coords == m_currentCellCoords;
508011ce 7610
f6bcfd97 7611 wxRect rect = CellToRect( row, col );
f85afd4e 7612
189d0213 7613 // if the editor is shown, we should use it and not the renderer
f6bcfd97
BP
7614 // Note: However, only if it is really _shown_, i.e. not hidden!
7615 if ( isCurrent && IsCellEditControlShown() )
189d0213 7616 {
a9339fe2 7617 // NB: this "#if..." is temporary and fixes a problem where the
962a48f6
DS
7618 // edit control is erased by this code after being rendered.
7619 // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered
7620 // implicitly, causing this out-of order render.
5d38a5f3 7621#if !defined(__WXMAC__)
0b190b0f
VZ
7622 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
7623 editor->PaintBackground(rect, attr);
7624 editor->DecRef();
962a48f6 7625#endif
189d0213
VZ
7626 }
7627 else
7628 {
a9339fe2 7629 // but all the rest is drawn by the cell renderer and hence may be customized
0b190b0f
VZ
7630 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
7631 renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
7632 renderer->DecRef();
189d0213 7633 }
07296f0b 7634
283b7808
VZ
7635 attr->DecRef();
7636}
07296f0b 7637
283b7808 7638void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
07296f0b
RD
7639{
7640 int row = m_currentCellCoords.GetRow();
7641 int col = m_currentCellCoords.GetCol();
7642
7c1cb261 7643 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
07296f0b
RD
7644 return;
7645
f6bcfd97 7646 wxRect rect = CellToRect(row, col);
07296f0b 7647
b3a7510d
VZ
7648 // hmmm... what could we do here to show that the cell is disabled?
7649 // for now, I just draw a thinner border than for the other ones, but
7650 // it doesn't look really good
b3a7510d 7651
d2520c85
RD
7652 int penWidth = attr->IsReadOnly() ? m_cellHighlightROPenWidth : m_cellHighlightPenWidth;
7653
27f35b66
SN
7654 if (penWidth > 0)
7655 {
56b6cf26
DS
7656 // The center of the drawn line is where the position/width/height of
7657 // the rectangle is actually at (on wxMSW at least), so the
7658 // size of the rectangle is reduced to compensate for the thickness of
7659 // the line. If this is too strange on non-wxMSW platforms then
d2520c85 7660 // please #ifdef this appropriately.
4db6714b
KH
7661 rect.x += penWidth / 2;
7662 rect.y += penWidth / 2;
7663 rect.width -= penWidth - 1;
7664 rect.height -= penWidth - 1;
d2520c85 7665
d2520c85 7666 // Now draw the rectangle
73145b0e
JS
7667 // use the cellHighlightColour if the cell is inside a selection, this
7668 // will ensure the cell is always visible.
4db6714b 7669 dc.SetPen(wxPen(IsInSelection(row,col) ? m_selectionForeground : m_cellHighlightColour, penWidth, wxSOLID));
d2520c85
RD
7670 dc.SetBrush(*wxTRANSPARENT_BRUSH);
7671 dc.DrawRectangle(rect);
7672 }
07296f0b 7673
283b7808 7674#if 0
2f024384 7675 // VZ: my experiments with 3D borders...
283b7808 7676
b3a7510d 7677 // how to properly set colours for arbitrary bg?
283b7808
VZ
7678 wxCoord x1 = rect.x,
7679 y1 = rect.y,
4db6714b
KH
7680 x2 = rect.x + rect.width - 1,
7681 y2 = rect.y + rect.height - 1;
283b7808
VZ
7682
7683 dc.SetPen(*wxWHITE_PEN);
00cf1208
RR
7684 dc.DrawLine(x1, y1, x2, y1);
7685 dc.DrawLine(x1, y1, x1, y2);
283b7808 7686
283b7808 7687 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
2f024384 7688 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2);
283b7808
VZ
7689
7690 dc.SetPen(*wxBLACK_PEN);
7691 dc.DrawLine(x1, y2, x2, y2);
2f024384 7692 dc.DrawLine(x2, y1, x2, y2 + 1);
a9339fe2 7693#endif
2d66e025 7694}
f85afd4e 7695
3d3f3e37
VZ
7696wxPen wxGrid::GetDefaultGridLinePen()
7697{
7698 return wxPen(GetGridLineColour(), 1, wxSOLID);
7699}
7700
7701wxPen wxGrid::GetRowGridLinePen(int WXUNUSED(row))
7702{
7703 return GetDefaultGridLinePen();
7704}
7705
7706wxPen wxGrid::GetColGridLinePen(int WXUNUSED(col))
7707{
7708 return GetDefaultGridLinePen();
7709}
7710
2d66e025
MB
7711void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
7712{
2d66e025
MB
7713 int row = coords.GetRow();
7714 int col = coords.GetCol();
7c1cb261
VZ
7715 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
7716 return;
7717
60ff3b99 7718
27f35b66
SN
7719 wxRect rect = CellToRect( row, col );
7720
2d66e025 7721 // right hand border
3d3f3e37 7722 dc.SetPen( GetColGridLinePen(col) );
27f35b66
SN
7723 dc.DrawLine( rect.x + rect.width, rect.y,
7724 rect.x + rect.width, rect.y + rect.height + 1 );
2d66e025
MB
7725
7726 // bottom border
3d3f3e37 7727 dc.SetPen( GetRowGridLinePen(row) );
2f024384 7728 dc.DrawLine( rect.x, rect.y + rect.height,
27f35b66 7729 rect.x + rect.width, rect.y + rect.height);
f85afd4e
MB
7730}
7731
2f024384 7732void wxGrid::DrawHighlight(wxDC& dc, const wxGridCellCoordsArray& cells)
b3a7510d 7733{
2a7750d9
MB
7734 // This if block was previously in wxGrid::OnPaint but that doesn't
7735 // seem to get called under wxGTK - MB
7736 //
2f024384 7737 if ( m_currentCellCoords == wxGridNoCellCoords &&
2a7750d9
MB
7738 m_numRows && m_numCols )
7739 {
7740 m_currentCellCoords.Set(0, 0);
7741 }
7742
f6bcfd97 7743 if ( IsCellEditControlShown() )
99306db2
VZ
7744 {
7745 // don't show highlight when the edit control is shown
7746 return;
7747 }
7748
b3a7510d
VZ
7749 // if the active cell was repainted, repaint its highlight too because it
7750 // might have been damaged by the grid lines
d10f4bf9 7751 size_t count = cells.GetCount();
b3a7510d
VZ
7752 for ( size_t n = 0; n < count; n++ )
7753 {
d10f4bf9 7754 if ( cells[n] == m_currentCellCoords )
b3a7510d
VZ
7755 {
7756 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
7757 DrawCellHighlight(dc, attr);
7758 attr->DecRef();
7759
7760 break;
7761 }
7762 }
7763}
2d66e025 7764
2d66e025
MB
7765// TODO: remove this ???
7766// This is used to redraw all grid lines e.g. when the grid line colour
7767// has been changed
7768//
33ac7e6f 7769void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) )
f85afd4e 7770{
27f35b66
SN
7771#if !WXGRID_DRAW_LINES
7772 return;
7773#endif
7774
afd0f084 7775 if ( !m_gridLinesEnabled || !m_numRows || !m_numCols )
4db6714b 7776 return;
f85afd4e 7777
2d66e025 7778 int top, bottom, left, right;
796df70a 7779
f6bcfd97 7780#if 0 //#ifndef __WXGTK__
508011ce
VZ
7781 if (reg.IsEmpty())
7782 {
796df70a
SN
7783 int cw, ch;
7784 m_gridWin->GetClientSize(&cw, &ch);
7785
7786 // virtual coords of visible area
7787 //
7788 CalcUnscrolledPosition( 0, 0, &left, &top );
7789 CalcUnscrolledPosition( cw, ch, &right, &bottom );
7790 }
508011ce
VZ
7791 else
7792 {
796df70a
SN
7793 wxCoord x, y, w, h;
7794 reg.GetBox(x, y, w, h);
7795 CalcUnscrolledPosition( x, y, &left, &top );
7796 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
7797 }
8e217128
RR
7798#else
7799 int cw, ch;
7800 m_gridWin->GetClientSize(&cw, &ch);
7801 CalcUnscrolledPosition( 0, 0, &left, &top );
7802 CalcUnscrolledPosition( cw, ch, &right, &bottom );
7803#endif
f85afd4e 7804
9496deb5
MB
7805 // avoid drawing grid lines past the last row and col
7806 //
d4175745 7807 right = wxMin( right, GetColRight(GetColAt( m_numCols - 1 )) );
7c1cb261 7808 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
9496deb5 7809
27f35b66 7810 // no gridlines inside multicells, clip them out
d4175745 7811 int leftCol = GetColPos( internalXToCol(left) );
a9339fe2 7812 int topRow = internalYToRow(top);
d4175745 7813 int rightCol = GetColPos( internalXToCol(right) );
a967f048 7814 int bottomRow = internalYToRow(bottom);
27f35b66 7815
f4f9074f 7816#if !defined(__WXMAC__) || wxMAC_USE_CORE_GRAPHICS
c03bf0c7 7817 wxRegion clippedcells(0, 0, cw, ch);
27f35b66 7818
a967f048
RG
7819 int i, j, cell_rows, cell_cols;
7820 wxRect rect;
27f35b66 7821
7c3f33a9 7822 for (j=topRow; j<=bottomRow; j++)
a967f048 7823 {
d4175745 7824 int colPos;
7c3f33a9 7825 for (colPos=leftCol; colPos<=rightCol; colPos++)
27f35b66 7826 {
d4175745
VZ
7827 i = GetColAt( colPos );
7828
a967f048
RG
7829 GetCellSize( j, i, &cell_rows, &cell_cols );
7830 if ((cell_rows > 1) || (cell_cols > 1))
27f35b66 7831 {
a967f048
RG
7832 rect = CellToRect(j,i);
7833 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
7834 clippedcells.Subtract(rect);
7835 }
7836 else if ((cell_rows < 0) || (cell_cols < 0))
7837 {
a9339fe2 7838 rect = CellToRect(j + cell_rows, i + cell_cols);
a967f048
RG
7839 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
7840 clippedcells.Subtract(rect);
27f35b66
SN
7841 }
7842 }
7843 }
c03bf0c7 7844#else
c2f5b920 7845 wxRegion clippedcells( left, top, right - left, bottom - top );
c03bf0c7
SC
7846
7847 int i, j, cell_rows, cell_cols;
7848 wxRect rect;
7849
7c3f33a9 7850 for (j=topRow; j<=bottomRow; j++)
c03bf0c7 7851 {
7c3f33a9 7852 for (i=leftCol; i<=rightCol; i++)
c03bf0c7
SC
7853 {
7854 GetCellSize( j, i, &cell_rows, &cell_cols );
7855 if ((cell_rows > 1) || (cell_cols > 1))
7856 {
2f024384 7857 rect = CellToRect(j, i);
c03bf0c7
SC
7858 clippedcells.Subtract(rect);
7859 }
7860 else if ((cell_rows < 0) || (cell_cols < 0))
7861 {
2f024384 7862 rect = CellToRect(j + cell_rows, i + cell_cols);
c03bf0c7
SC
7863 clippedcells.Subtract(rect);
7864 }
7865 }
7866 }
7867#endif
a9339fe2 7868
27f35b66
SN
7869 dc.SetClippingRegion( clippedcells );
7870
f85afd4e 7871
2d66e025 7872 // horizontal grid lines
f85afd4e 7873 //
a967f048 7874 // already declared above - int i;
33188aa4 7875 for ( i = internalYToRow(top); i < m_numRows; i++ )
f85afd4e 7876 {
6d55126d 7877 int bot = GetRowBottom(i) - 1;
7c1cb261 7878
6d55126d 7879 if ( bot > bottom )
2d66e025
MB
7880 {
7881 break;
7882 }
7c1cb261 7883
6d55126d 7884 if ( bot >= top )
2d66e025 7885 {
3d3f3e37 7886 dc.SetPen( GetRowGridLinePen(i) );
6d55126d 7887 dc.DrawLine( left, bot, right, bot );
2d66e025 7888 }
f85afd4e
MB
7889 }
7890
2d66e025
MB
7891 // vertical grid lines
7892 //
d4175745
VZ
7893 int colPos;
7894 for ( colPos = leftCol; colPos < m_numCols; colPos++ )
f85afd4e 7895 {
d4175745
VZ
7896 i = GetColAt( colPos );
7897
2121eb69
RR
7898 int colRight = GetColRight(i);
7899#ifdef __WXGTK__
7900 if (GetLayoutDirection() != wxLayout_RightToLeft)
7901#endif
7902 colRight--;
7903
7c1cb261 7904 if ( colRight > right )
2d66e025
MB
7905 {
7906 break;
7907 }
7c1cb261
VZ
7908
7909 if ( colRight >= left )
2d66e025 7910 {
3d3f3e37 7911 dc.SetPen( GetColGridLinePen(i) );
7c1cb261 7912 dc.DrawLine( colRight, top, colRight, bottom );
2d66e025
MB
7913 }
7914 }
a9339fe2 7915
27f35b66 7916 dc.DestroyClippingRegion();
2d66e025 7917}
f85afd4e 7918
c2f5b920 7919void wxGrid::DrawRowLabels( wxDC& dc, const wxArrayInt& rows)
2d66e025 7920{
4db6714b
KH
7921 if ( !m_numRows )
7922 return;
60ff3b99 7923
2d66e025 7924 size_t i;
d10f4bf9 7925 size_t numLabels = rows.GetCount();
60ff3b99 7926
2f024384 7927 for ( i = 0; i < numLabels; i++ )
2d66e025 7928 {
d10f4bf9 7929 DrawRowLabel( dc, rows[i] );
60ff3b99 7930 }
f85afd4e
MB
7931}
7932
2d66e025 7933void wxGrid::DrawRowLabel( wxDC& dc, int row )
f85afd4e 7934{
659af826 7935 if ( GetRowHeight(row) <= 0 || m_rowLabelWidth <= 0 )
7c1cb261 7936 return;
60ff3b99 7937
4d1bc39c 7938 wxRect rect;
2f024384 7939
e6002250
RR
7940#if 0
7941def __WXGTK20__
4d1bc39c
RR
7942 rect.SetX( 1 );
7943 rect.SetY( GetRowTop(row) + 1 );
7944 rect.SetWidth( m_rowLabelWidth - 2 );
7945 rect.SetHeight( GetRowHeight(row) - 2 );
ec157c8f 7946
4d1bc39c 7947 CalcScrolledPosition( 0, rect.y, NULL, &rect.y );
ec157c8f 7948
4d1bc39c
RR
7949 wxWindowDC *win_dc = (wxWindowDC*) &dc;
7950
7951 wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 );
7952#else
7c1cb261
VZ
7953 int rowTop = GetRowTop(row),
7954 rowBottom = GetRowBottom(row) - 1;
b99be8fb 7955
d4175745 7956 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) );
a9339fe2 7957 dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom );
73145b0e 7958 dc.DrawLine( 0, rowTop, 0, rowBottom );
73145b0e 7959 dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom );
b99be8fb 7960
2d66e025 7961 dc.SetPen( *wxWHITE_PEN );
73145b0e 7962 dc.DrawLine( 1, rowTop, 1, rowBottom );
a9339fe2 7963 dc.DrawLine( 1, rowTop, m_rowLabelWidth - 1, rowTop );
4d1bc39c 7964#endif
2f024384 7965
f85afd4e 7966 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
7967 dc.SetTextForeground( GetLabelTextColour() );
7968 dc.SetFont( GetLabelFont() );
8f177c8e 7969
f85afd4e 7970 int hAlign, vAlign;
2d66e025 7971 GetRowLabelAlignment( &hAlign, &vAlign );
60ff3b99 7972
2d66e025 7973 rect.SetX( 2 );
7c1cb261 7974 rect.SetY( GetRowTop(row) + 2 );
2d66e025 7975 rect.SetWidth( m_rowLabelWidth - 4 );
7c1cb261 7976 rect.SetHeight( GetRowHeight(row) - 4 );
60ff3b99 7977 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
f85afd4e
MB
7978}
7979
d10f4bf9 7980void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols )
f85afd4e 7981{
4db6714b
KH
7982 if ( !m_numCols )
7983 return;
60ff3b99 7984
2d66e025 7985 size_t i;
d10f4bf9 7986 size_t numLabels = cols.GetCount();
60ff3b99 7987
56b6cf26 7988 for ( i = 0; i < numLabels; i++ )
f85afd4e 7989 {
d10f4bf9 7990 DrawColLabel( dc, cols[i] );
60ff3b99 7991 }
f85afd4e
MB
7992}
7993
2d66e025 7994void wxGrid::DrawColLabel( wxDC& dc, int col )
f85afd4e 7995{
659af826 7996 if ( GetColWidth(col) <= 0 || m_colLabelHeight <= 0 )
7c1cb261 7997 return;
60ff3b99 7998
4d1bc39c 7999 int colLeft = GetColLeft(col);
ec157c8f 8000
4d1bc39c 8001 wxRect rect;
2f024384 8002
e6002250
RR
8003#if 0
8004def __WXGTK20__
4d1bc39c
RR
8005 rect.SetX( colLeft + 1 );
8006 rect.SetY( 1 );
8007 rect.SetWidth( GetColWidth(col) - 2 );
8008 rect.SetHeight( m_colLabelHeight - 2 );
ec157c8f 8009
4d1bc39c
RR
8010 wxWindowDC *win_dc = (wxWindowDC*) &dc;
8011
8012 wxRendererNative::Get().DrawHeaderButton( win_dc->m_owner, dc, rect, 0 );
8013#else
8014 int colRight = GetColRight(col) - 1;
b99be8fb 8015
d4175745 8016 dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID) );
ccdee36f 8017 dc.DrawLine( colRight, 0, colRight, m_colLabelHeight - 1 );
73145b0e 8018 dc.DrawLine( colLeft, 0, colRight, 0 );
ccdee36f
DS
8019 dc.DrawLine( colLeft, m_colLabelHeight - 1,
8020 colRight + 1, m_colLabelHeight - 1 );
b99be8fb 8021
f85afd4e 8022 dc.SetPen( *wxWHITE_PEN );
ccdee36f 8023 dc.DrawLine( colLeft, 1, colLeft, m_colLabelHeight - 1 );
73145b0e 8024 dc.DrawLine( colLeft, 1, colRight, 1 );
4d1bc39c 8025#endif
2f024384 8026
b0d6ff2f
MB
8027 dc.SetBackgroundMode( wxTRANSPARENT );
8028 dc.SetTextForeground( GetLabelTextColour() );
8029 dc.SetFont( GetLabelFont() );
8f177c8e 8030
d43851f7 8031 int hAlign, vAlign, orient;
2d66e025 8032 GetColLabelAlignment( &hAlign, &vAlign );
d43851f7 8033 orient = GetColLabelTextOrientation();
60ff3b99 8034
7c1cb261 8035 rect.SetX( colLeft + 2 );
2d66e025 8036 rect.SetY( 2 );
7c1cb261 8037 rect.SetWidth( GetColWidth(col) - 4 );
2d66e025 8038 rect.SetHeight( m_colLabelHeight - 4 );
d43851f7 8039 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign, orient );
f85afd4e
MB
8040}
8041
2d66e025
MB
8042void wxGrid::DrawTextRectangle( wxDC& dc,
8043 const wxString& value,
8044 const wxRect& rect,
8045 int horizAlign,
d43851f7
JS
8046 int vertAlign,
8047 int textOrientation )
f85afd4e 8048{
2d66e025 8049 wxArrayString lines;
ef5df12b 8050
2d66e025 8051 StringToLines( value, lines );
ef5df12b 8052
2f024384 8053 // Forward to new API.
a9339fe2 8054 DrawTextRectangle( dc,
038a5591
JS
8055 lines,
8056 rect,
8057 horizAlign,
8058 vertAlign,
8059 textOrientation );
d10f4bf9
VZ
8060}
8061
4330c974
VZ
8062// VZ: this should be replaced with wxDC::DrawLabel() to which we just have to
8063// add textOrientation support
8064void wxGrid::DrawTextRectangle(wxDC& dc,
038a5591
JS
8065 const wxArrayString& lines,
8066 const wxRect& rect,
8067 int horizAlign,
8068 int vertAlign,
4330c974 8069 int textOrientation)
d10f4bf9 8070{
4330c974
VZ
8071 if ( lines.empty() )
8072 return;
ef5df12b 8073
4330c974 8074 wxDCClipper clip(dc, rect);
ef5df12b 8075
4330c974
VZ
8076 long textWidth,
8077 textHeight;
ef5df12b 8078
4330c974
VZ
8079 if ( textOrientation == wxHORIZONTAL )
8080 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
8081 else
8082 GetTextBoxSize( dc, lines, &textHeight, &textWidth );
ef5df12b 8083
4330c974
VZ
8084 int x = 0,
8085 y = 0;
8086 switch ( vertAlign )
8087 {
73145b0e 8088 case wxALIGN_BOTTOM:
4db6714b 8089 if ( textOrientation == wxHORIZONTAL )
038a5591 8090 y = rect.y + (rect.height - textHeight - 1);
d43851f7 8091 else
038a5591
JS
8092 x = rect.x + rect.width - textWidth;
8093 break;
ef5df12b 8094
73145b0e 8095 case wxALIGN_CENTRE:
4db6714b 8096 if ( textOrientation == wxHORIZONTAL )
a9339fe2 8097 y = rect.y + ((rect.height - textHeight) / 2);
d43851f7 8098 else
a9339fe2 8099 x = rect.x + ((rect.width - textWidth) / 2);
038a5591 8100 break;
ef5df12b 8101
73145b0e
JS
8102 case wxALIGN_TOP:
8103 default:
4db6714b 8104 if ( textOrientation == wxHORIZONTAL )
038a5591 8105 y = rect.y + 1;
d43851f7 8106 else
038a5591 8107 x = rect.x + 1;
73145b0e 8108 break;
4330c974 8109 }
ef5df12b 8110
4330c974
VZ
8111 // Align each line of a multi-line label
8112 size_t nLines = lines.GetCount();
8113 for ( size_t l = 0; l < nLines; l++ )
8114 {
8115 const wxString& line = lines[l];
ef5df12b 8116
9b7d3c09
VZ
8117 if ( line.empty() )
8118 {
8119 *(textOrientation == wxHORIZONTAL ? &y : &x) += dc.GetCharHeight();
8120 continue;
8121 }
8122
c2b2c10e
MW
8123 long lineWidth = 0,
8124 lineHeight = 0;
4330c974
VZ
8125 dc.GetTextExtent(line, &lineWidth, &lineHeight);
8126
8127 switch ( horizAlign )
8128 {
038a5591 8129 case wxALIGN_RIGHT:
4db6714b 8130 if ( textOrientation == wxHORIZONTAL )
038a5591
JS
8131 x = rect.x + (rect.width - lineWidth - 1);
8132 else
8133 y = rect.y + lineWidth + 1;
8134 break;
ef5df12b 8135
038a5591 8136 case wxALIGN_CENTRE:
4db6714b 8137 if ( textOrientation == wxHORIZONTAL )
2f024384 8138 x = rect.x + ((rect.width - lineWidth) / 2);
038a5591 8139 else
2f024384 8140 y = rect.y + rect.height - ((rect.height - lineWidth) / 2);
038a5591 8141 break;
ef5df12b 8142
038a5591
JS
8143 case wxALIGN_LEFT:
8144 default:
4db6714b 8145 if ( textOrientation == wxHORIZONTAL )
038a5591
JS
8146 x = rect.x + 1;
8147 else
8148 y = rect.y + rect.height - 1;
8149 break;
4330c974 8150 }
ef5df12b 8151
4330c974
VZ
8152 if ( textOrientation == wxHORIZONTAL )
8153 {
8154 dc.DrawText( line, x, y );
8155 y += lineHeight;
8156 }
8157 else
8158 {
8159 dc.DrawRotatedText( line, x, y, 90.0 );
8160 x += lineHeight;
038a5591 8161 }
f85afd4e 8162 }
f85afd4e
MB
8163}
8164
2f024384
DS
8165// Split multi-line text up into an array of strings.
8166// Any existing contents of the string array are preserved.
f85afd4e 8167//
ef316e23 8168void wxGrid::StringToLines( const wxString& value, wxArrayString& lines ) const
f85afd4e 8169{
f85afd4e
MB
8170 int startPos = 0;
8171 int pos;
6d004f67 8172 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
2433bb2e 8173 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
e2b42eeb 8174
faa94f3e 8175 while ( startPos < (int)tVal.length() )
f85afd4e 8176 {
2433bb2e 8177 pos = tVal.Mid(startPos).Find( eol );
f85afd4e
MB
8178 if ( pos < 0 )
8179 {
8180 break;
8181 }
8182 else if ( pos == 0 )
8183 {
8184 lines.Add( wxEmptyString );
8185 }
8186 else
8187 {
2433bb2e 8188 lines.Add( value.Mid(startPos, pos) );
f85afd4e 8189 }
a9339fe2 8190
4db6714b 8191 startPos += pos + 1;
f85afd4e 8192 }
4db6714b 8193
faa94f3e 8194 if ( startPos < (int)value.length() )
f85afd4e
MB
8195 {
8196 lines.Add( value.Mid( startPos ) );
8197 }
8198}
8199
fbfb8bcc 8200void wxGrid::GetTextBoxSize( const wxDC& dc,
d10f4bf9 8201 const wxArrayString& lines,
ef316e23 8202 long *width, long *height ) const
f85afd4e
MB
8203{
8204 long w = 0;
8205 long h = 0;
8d7eaf91 8206 long lineW = 0, lineH = 0;
f85afd4e 8207
b540eb2b 8208 size_t i;
56b6cf26 8209 for ( i = 0; i < lines.GetCount(); i++ )
f85afd4e
MB
8210 {
8211 dc.GetTextExtent( lines[i], &lineW, &lineH );
8212 w = wxMax( w, lineW );
8213 h += lineH;
8214 }
8215
8216 *width = w;
8217 *height = h;
8218}
8219
f6bcfd97
BP
8220//
8221// ------ Batch processing.
8222//
8223void wxGrid::EndBatch()
8224{
8225 if ( m_batchCount > 0 )
8226 {
8227 m_batchCount--;
8228 if ( !m_batchCount )
8229 {
8230 CalcDimensions();
8231 m_rowLabelWin->Refresh();
8232 m_colLabelWin->Refresh();
8233 m_cornerLabelWin->Refresh();
8234 m_gridWin->Refresh();
8235 }
8236 }
8237}
f85afd4e 8238
d8232393
MB
8239// Use this, rather than wxWindow::Refresh(), to force an immediate
8240// repainting of the grid. Has no effect if you are already inside a
8241// BeginBatch / EndBatch block.
8242//
8243void wxGrid::ForceRefresh()
8244{
8245 BeginBatch();
8246 EndBatch();
8247}
8248
bf646121
VZ
8249bool wxGrid::Enable(bool enable)
8250{
8251 if ( !wxScrolledWindow::Enable(enable) )
8252 return false;
8253
8254 // redraw in the new state
8255 m_gridWin->Refresh();
8256
8257 return true;
8258}
d8232393 8259
f85afd4e 8260//
2d66e025 8261// ------ Edit control functions
f85afd4e
MB
8262//
8263
2d66e025 8264void wxGrid::EnableEditing( bool edit )
f85afd4e 8265{
2d66e025
MB
8266 // TODO: improve this ?
8267 //
8268 if ( edit != m_editable )
f85afd4e 8269 {
4db6714b
KH
8270 if (!edit)
8271 EnableCellEditControl(edit);
2d66e025 8272 m_editable = edit;
f85afd4e 8273 }
f85afd4e
MB
8274}
8275
2d66e025 8276void wxGrid::EnableCellEditControl( bool enable )
f85afd4e 8277{
2c9a89e0
RD
8278 if (! m_editable)
8279 return;
8280
2c9a89e0
RD
8281 if ( enable != m_cellEditCtrlEnabled )
8282 {
dcfe4c3d 8283 if ( enable )
f85afd4e 8284 {
97a9929e
VZ
8285 if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0)
8286 return;
fe7b9ed6 8287
97a9929e 8288 // this should be checked by the caller!
a9339fe2 8289 wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") );
b54ba671
VZ
8290
8291 // do it before ShowCellEditControl()
dcfe4c3d 8292 m_cellEditCtrlEnabled = enable;
b54ba671 8293
2d66e025 8294 ShowCellEditControl();
2d66e025
MB
8295 }
8296 else
8297 {
97a9929e 8298 //FIXME:add veto support
a9339fe2 8299 SendEvent( wxEVT_GRID_EDITOR_HIDDEN );
fe7b9ed6 8300
97a9929e 8301 HideCellEditControl();
2d66e025 8302 SaveEditControlValue();
b54ba671
VZ
8303
8304 // do it after HideCellEditControl()
dcfe4c3d 8305 m_cellEditCtrlEnabled = enable;
f85afd4e 8306 }
f85afd4e 8307 }
f85afd4e 8308}
f85afd4e 8309
b54ba671 8310bool wxGrid::IsCurrentCellReadOnly() const
283b7808 8311{
b54ba671
VZ
8312 // const_cast
8313 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
8314 bool readonly = attr->IsReadOnly();
8315 attr->DecRef();
283b7808 8316
b54ba671
VZ
8317 return readonly;
8318}
283b7808 8319
b54ba671
VZ
8320bool wxGrid::CanEnableCellControl() const
8321{
20c84410
SN
8322 return m_editable && (m_currentCellCoords != wxGridNoCellCoords) &&
8323 !IsCurrentCellReadOnly();
b54ba671
VZ
8324}
8325
8326bool wxGrid::IsCellEditControlEnabled() const
8327{
8328 // the cell edit control might be disable for all cells or just for the
8329 // current one if it's read only
ca65c044 8330 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : false;
283b7808
VZ
8331}
8332
f6bcfd97
BP
8333bool wxGrid::IsCellEditControlShown() const
8334{
ca65c044 8335 bool isShown = false;
f6bcfd97
BP
8336
8337 if ( m_cellEditCtrlEnabled )
8338 {
8339 int row = m_currentCellCoords.GetRow();
8340 int col = m_currentCellCoords.GetCol();
8341 wxGridCellAttr* attr = GetCellAttr(row, col);
8342 wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
8343 attr->DecRef();
8344
8345 if ( editor )
8346 {
8347 if ( editor->IsCreated() )
8348 {
8349 isShown = editor->GetControl()->IsShown();
8350 }
8351
8352 editor->DecRef();
8353 }
8354 }
8355
8356 return isShown;
8357}
8358
2d66e025 8359void wxGrid::ShowCellEditControl()
f85afd4e 8360{
2d66e025 8361 if ( IsCellEditControlEnabled() )
f85afd4e 8362 {
7db713ae 8363 if ( !IsVisible( m_currentCellCoords, false ) )
2d66e025 8364 {
ca65c044 8365 m_cellEditCtrlEnabled = false;
2d66e025
MB
8366 return;
8367 }
8368 else
8369 {
2c9a89e0
RD
8370 wxRect rect = CellToRect( m_currentCellCoords );
8371 int row = m_currentCellCoords.GetRow();
8372 int col = m_currentCellCoords.GetCol();
2d66e025 8373
27f35b66
SN
8374 // if this is part of a multicell, find owner (topleft)
8375 int cell_rows, cell_cols;
8376 GetCellSize( row, col, &cell_rows, &cell_cols );
8377 if ( cell_rows <= 0 || cell_cols <= 0 )
8378 {
8379 row += cell_rows;
8380 col += cell_cols;
8381 m_currentCellCoords.SetRow( row );
8382 m_currentCellCoords.SetCol( col );
8383 }
8384
99306db2
VZ
8385 // erase the highlight and the cell contents because the editor
8386 // might not cover the entire cell
8387 wxClientDC dc( m_gridWin );
8388 PrepareDC( dc );
2c03d771
VZ
8389 wxGridCellAttr* attr = GetCellAttr(row, col);
8390 dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
99306db2
VZ
8391 dc.SetPen(*wxTRANSPARENT_PEN);
8392 dc.DrawRectangle(rect);
d2fdd8d2 8393
6f706ee0
VZ
8394 // convert to scrolled coords
8395 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
8396
8397 int nXMove = 0;
8398 if (rect.x < 0)
8399 nXMove = rect.x;
8400
99306db2 8401 // cell is shifted by one pixel
68c5a31c 8402 // However, don't allow x or y to become negative
70e8d961 8403 // since the SetSize() method interprets that as
68c5a31c
SN
8404 // "don't change."
8405 if (rect.x > 0)
8406 rect.x--;
8407 if (rect.y > 0)
8408 rect.y--;
f0102d2a 8409
28a77bc4 8410 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
3da93aae
VZ
8411 if ( !editor->IsCreated() )
8412 {
ca65c044 8413 editor->Create(m_gridWin, wxID_ANY,
2c9a89e0 8414 new wxGridCellEditorEvtHandler(this, editor));
bf7945ce
RD
8415
8416 wxGridEditorCreatedEvent evt(GetId(),
8417 wxEVT_GRID_EDITOR_CREATED,
8418 this,
8419 row,
8420 col,
8421 editor->GetControl());
8422 GetEventHandler()->ProcessEvent(evt);
2d66e025
MB
8423 }
8424
27f35b66 8425 // resize editor to overflow into righthand cells if allowed
39b80349 8426 int maxWidth = rect.width;
27f35b66
SN
8427 wxString value = GetCellValue(row, col);
8428 if ( (value != wxEmptyString) && (attr->GetOverflow()) )
8429 {
39b80349 8430 int y;
2f024384
DS
8431 GetTextExtent(value, &maxWidth, &y, NULL, NULL, &attr->GetFont());
8432 if (maxWidth < rect.width)
8433 maxWidth = rect.width;
39b80349 8434 }
4db6714b 8435
39b80349 8436 int client_right = m_gridWin->GetClientSize().GetWidth();
2f024384 8437 if (rect.x + maxWidth > client_right)
2b5f62a0 8438 maxWidth = client_right - rect.x;
39b80349 8439
2b5f62a0
VZ
8440 if ((maxWidth > rect.width) && (col < m_numCols) && m_table)
8441 {
39b80349 8442 GetCellSize( row, col, &cell_rows, &cell_cols );
2b5f62a0 8443 // may have changed earlier
2f024384 8444 for (int i = col + cell_cols; i < m_numCols; i++)
2b5f62a0 8445 {
39b80349
SN
8446 int c_rows, c_cols;
8447 GetCellSize( row, i, &c_rows, &c_cols );
2f024384 8448
2b5f62a0 8449 // looks weird going over a multicell
bee19958 8450 if (m_table->IsEmptyCell( row, i ) &&
2b5f62a0 8451 (rect.width < maxWidth) && (c_rows == 1))
2f024384 8452 {
bee19958 8453 rect.width += GetColWidth( i );
2f024384 8454 }
2b5f62a0
VZ
8455 else
8456 break;
8457 }
4db6714b 8458
39b80349 8459 if (rect.GetRight() > client_right)
bee19958 8460 rect.SetRight( client_right - 1 );
27f35b66 8461 }
73145b0e 8462
bee19958 8463 editor->SetCellAttr( attr );
2c9a89e0 8464 editor->SetSize( rect );
e1a66d9a
RD
8465 if (nXMove != 0)
8466 editor->GetControl()->Move(
8467 editor->GetControl()->GetPosition().x + nXMove,
8468 editor->GetControl()->GetPosition().y );
ca65c044 8469 editor->Show( true, attr );
04418332
VZ
8470
8471 // recalc dimensions in case we need to
8472 // expand the scrolled window to account for editor
73145b0e 8473 CalcDimensions();
99306db2 8474
3da93aae 8475 editor->BeginEdit(row, col, this);
1bd71df9 8476 editor->SetCellAttr(NULL);
0b190b0f
VZ
8477
8478 editor->DecRef();
2c9a89e0 8479 attr->DecRef();
2b5f62a0 8480 }
f85afd4e
MB
8481 }
8482}
8483
2d66e025 8484void wxGrid::HideCellEditControl()
f85afd4e 8485{
2d66e025 8486 if ( IsCellEditControlEnabled() )
f85afd4e 8487 {
2c9a89e0
RD
8488 int row = m_currentCellCoords.GetRow();
8489 int col = m_currentCellCoords.GetCol();
8490
bee19958 8491 wxGridCellAttr *attr = GetCellAttr(row, col);
0b190b0f 8492 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
ca65c044 8493 editor->Show( false );
0b190b0f 8494 editor->DecRef();
2c9a89e0 8495 attr->DecRef();
2fb3e528 8496
48962b9f 8497 m_gridWin->SetFocus();
2fb3e528 8498
27f35b66
SN
8499 // refresh whole row to the right
8500 wxRect rect( CellToRect(row, col) );
8501 CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y );
8502 rect.width = m_gridWin->GetClientSize().GetWidth() - rect.x;
2f024384 8503
7d75e6c6
RD
8504#ifdef __WXMAC__
8505 // ensure that the pixels under the focus ring get refreshed as well
4db6714b 8506 rect.Inflate(10, 10);
7d75e6c6 8507#endif
2f024384 8508
ca65c044 8509 m_gridWin->Refresh( false, &rect );
f85afd4e 8510 }
2d66e025 8511}
8f177c8e 8512
2d66e025
MB
8513void wxGrid::SaveEditControlValue()
8514{
3da93aae
VZ
8515 if ( IsCellEditControlEnabled() )
8516 {
2c9a89e0
RD
8517 int row = m_currentCellCoords.GetRow();
8518 int col = m_currentCellCoords.GetCol();
8f177c8e 8519
4db6714b 8520 wxString oldval = GetCellValue(row, col);
fe7b9ed6 8521
3da93aae 8522 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 8523 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
3324d5f5 8524 bool changed = editor->EndEdit(row, col, this);
2d66e025 8525
0b190b0f 8526 editor->DecRef();
2c9a89e0 8527 attr->DecRef();
2d66e025 8528
3da93aae
VZ
8529 if (changed)
8530 {
fe7b9ed6 8531 if ( SendEvent( wxEVT_GRID_CELL_CHANGE,
2d66e025 8532 m_currentCellCoords.GetRow(),
4db6714b
KH
8533 m_currentCellCoords.GetCol() ) < 0 )
8534 {
97a9929e 8535 // Event has been vetoed, set the data back.
4db6714b 8536 SetCellValue(row, col, oldval);
97a9929e 8537 }
2d66e025 8538 }
f85afd4e
MB
8539 }
8540}
8541
2d66e025 8542//
60ff3b99
VZ
8543// ------ Grid location functions
8544// Note that all of these functions work with the logical coordinates of
2d66e025
MB
8545// grid cells and labels so you will need to convert from device
8546// coordinates for mouse events etc.
8547//
8548
ef316e23 8549void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) const
f85afd4e 8550{
58dd5b3b
MB
8551 int row = YToRow(y);
8552 int col = XToCol(x);
8553
a9339fe2 8554 if ( row == -1 || col == -1 )
58dd5b3b
MB
8555 {
8556 coords = wxGridNoCellCoords;
8557 }
8558 else
8559 {
8560 coords.Set( row, col );
8561 }
2d66e025 8562}
f85afd4e 8563
b1da8107
SN
8564// Internal Helper function for computing row or column from some
8565// (unscrolled) coordinate value, using either
70e8d961 8566// m_defaultRowHeight/m_defaultColWidth or binary search on array
b1da8107
SN
8567// of m_rowBottoms/m_ColRights to speed up the search!
8568
8569static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
64e15340 8570 const wxArrayInt& BorderArray, int nMax,
a967f048 8571 bool clipToMinMax)
2d66e025 8572{
a967f048
RG
8573 if (coord < 0)
8574 return clipToMinMax && (nMax > 0) ? 0 : -1;
8575
b1da8107
SN
8576 if (!defaultDist)
8577 defaultDist = 1;
a967f048 8578
1af546bf
VZ
8579 size_t i_max = coord / defaultDist,
8580 i_min = 0;
d57ad377 8581
b1da8107
SN
8582 if (BorderArray.IsEmpty())
8583 {
4db6714b 8584 if ((int) i_max < nMax)
64e15340 8585 return i_max;
a967f048 8586 return clipToMinMax ? nMax - 1 : -1;
b1da8107 8587 }
8f177c8e 8588
b1da8107 8589 if ( i_max >= BorderArray.GetCount())
2f024384 8590 {
b1da8107 8591 i_max = BorderArray.GetCount() - 1;
2f024384 8592 }
70e8d961 8593 else
f85afd4e 8594 {
b1da8107
SN
8595 if ( coord >= BorderArray[i_max])
8596 {
8597 i_min = i_max;
20c84410
SN
8598 if (minDist)
8599 i_max = coord / minDist;
8600 else
8601 i_max = BorderArray.GetCount() - 1;
b1da8107 8602 }
4db6714b 8603
b1da8107
SN
8604 if ( i_max >= BorderArray.GetCount())
8605 i_max = BorderArray.GetCount() - 1;
f85afd4e 8606 }
4db6714b 8607
33188aa4 8608 if ( coord >= BorderArray[i_max])
a967f048 8609 return clipToMinMax ? (int)i_max : -1;
68c5a31c
SN
8610 if ( coord < BorderArray[0] )
8611 return 0;
2d66e025 8612
68c5a31c 8613 while ( i_max - i_min > 0 )
b1da8107
SN
8614 {
8615 wxCHECK_MSG(BorderArray[i_min] <= coord && coord < BorderArray[i_max],
33188aa4 8616 0, _T("wxGrid: internal error in CoordToRowOrCol"));
b1da8107 8617 if (coord >= BorderArray[ i_max - 1])
b1da8107 8618 return i_max;
b1da8107
SN
8619 else
8620 i_max--;
8621 int median = i_min + (i_max - i_min + 1) / 2;
8622 if (coord < BorderArray[median])
8623 i_max = median;
8624 else
8625 i_min = median;
8626 }
4db6714b 8627
b1da8107 8628 return i_max;
f85afd4e
MB
8629}
8630
ef316e23 8631int wxGrid::YToRow( int y ) const
f85afd4e 8632{
b1da8107 8633 return CoordToRowOrCol(y, m_defaultRowHeight,
ca65c044 8634 m_minAcceptableRowHeight, m_rowBottoms, m_numRows, false);
b1da8107 8635}
8f177c8e 8636
ef316e23 8637int wxGrid::XToCol( int x, bool clipToMinMax ) const
b1da8107 8638{
d4175745
VZ
8639 if (x < 0)
8640 return clipToMinMax && (m_numCols > 0) ? GetColAt( 0 ) : -1;
8641
ef316e23 8642 wxASSERT_MSG(m_defaultColWidth > 0, wxT("Default column width can not be zero"));
d4175745
VZ
8643
8644 int maxPos = x / m_defaultColWidth;
8645 int minPos = 0;
8646
8647 if (m_colRights.IsEmpty())
8648 {
8649 if(maxPos < m_numCols)
8650 return GetColAt( maxPos );
8651 return clipToMinMax ? GetColAt( m_numCols - 1 ) : -1;
8652 }
8653
8654 if ( maxPos >= m_numCols)
8655 maxPos = m_numCols - 1;
8656 else
8657 {
8658 if ( x >= m_colRights[GetColAt( maxPos )])
8659 {
8660 minPos = maxPos;
8661 if (m_minAcceptableColWidth)
8662 maxPos = x / m_minAcceptableColWidth;
8663 else
8664 maxPos = m_numCols - 1;
8665 }
8666 if ( maxPos >= m_numCols)
8667 maxPos = m_numCols - 1;
8668 }
8669
8670 //X is beyond the last column
8671 if ( x >= m_colRights[GetColAt( maxPos )])
8672 return clipToMinMax ? GetColAt( maxPos ) : -1;
8673
8674 //X is before the first column
8675 if ( x < m_colRights[GetColAt( 0 )] )
8676 return GetColAt( 0 );
8677
8678 //Perform a binary search
8679 while ( maxPos - minPos > 0 )
8680 {
8681 wxCHECK_MSG(m_colRights[GetColAt( minPos )] <= x && x < m_colRights[GetColAt( maxPos )],
8682 0, _T("wxGrid: internal error in XToCol"));
8683
8684 if (x >= m_colRights[GetColAt( maxPos - 1 )])
8685 return GetColAt( maxPos );
8686 else
8687 maxPos--;
8688 int median = minPos + (maxPos - minPos + 1) / 2;
8689 if (x < m_colRights[GetColAt( median )])
8690 maxPos = median;
8691 else
8692 minPos = median;
8693 }
8694 return GetColAt( maxPos );
2d66e025 8695}
8f177c8e 8696
be2e4015
SN
8697// return the row number that that the y coord is near
8698// the edge of, or -1 if not near an edge.
8699// coords can only possibly be near an edge if
8700// (a) the row/column is large enough to still allow for an "inner" area
8701// that is _not_ nead the edge (i.e., if the height/width is smaller
8702// than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be
8703// near the edge).
8704// and
8705// (b) resizing rows/columns (the thing for which edge detection is
8706// relevant at all) is enabled.
2d66e025 8707//
ef316e23 8708int wxGrid::YToEdgeOfRow( int y ) const
2d66e025 8709{
33188aa4
SN
8710 int i;
8711 i = internalYToRow(y);
8712
be2e4015 8713 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE && CanDragRowSize() )
2d66e025 8714 {
33188aa4
SN
8715 // We know that we are in row i, test whether we are
8716 // close enough to lower or upper border, respectively.
8717 if ( abs(GetRowBottom(i) - y) < WXGRID_LABEL_EDGE_ZONE )
8718 return i;
4db6714b 8719 else if ( i > 0 && y - GetRowTop(i) < WXGRID_LABEL_EDGE_ZONE )
33188aa4 8720 return i - 1;
f85afd4e 8721 }
2d66e025
MB
8722
8723 return -1;
8724}
8725
2d66e025
MB
8726// return the col number that that the x coord is near the edge of, or
8727// -1 if not near an edge
be2e4015 8728// See comment at YToEdgeOfRow for conditions on edge detection.
2d66e025 8729//
ef316e23 8730int wxGrid::XToEdgeOfCol( int x ) const
2d66e025 8731{
33188aa4
SN
8732 int i;
8733 i = internalXToCol(x);
8734
be2e4015 8735 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE && CanDragColSize() )
f85afd4e 8736 {
a9339fe2 8737 // We know that we are in column i; test whether we are
33188aa4
SN
8738 // close enough to right or left border, respectively.
8739 if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE )
8740 return i;
4db6714b 8741 else if ( i > 0 && x - GetColLeft(i) < WXGRID_LABEL_EDGE_ZONE )
33188aa4 8742 return i - 1;
f85afd4e 8743 }
2d66e025
MB
8744
8745 return -1;
f85afd4e
MB
8746}
8747
ef316e23 8748wxRect wxGrid::CellToRect( int row, int col ) const
f85afd4e 8749{
2d66e025 8750 wxRect rect( -1, -1, -1, -1 );
f85afd4e 8751
2f024384
DS
8752 if ( row >= 0 && row < m_numRows &&
8753 col >= 0 && col < m_numCols )
f85afd4e 8754 {
27f35b66
SN
8755 int i, cell_rows, cell_cols;
8756 rect.width = rect.height = 0;
8757 GetCellSize( row, col, &cell_rows, &cell_cols );
8758 // if negative then find multicell owner
2f024384
DS
8759 if (cell_rows < 0)
8760 row += cell_rows;
8761 if (cell_cols < 0)
8762 col += cell_cols;
27f35b66
SN
8763 GetCellSize( row, col, &cell_rows, &cell_cols );
8764
7c1cb261
VZ
8765 rect.x = GetColLeft(col);
8766 rect.y = GetRowTop(row);
2f024384
DS
8767 for (i=col; i < col + cell_cols; i++)
8768 rect.width += GetColWidth(i);
8769 for (i=row; i < row + cell_rows; i++)
27f35b66 8770 rect.height += GetRowHeight(i);
f85afd4e
MB
8771 }
8772
f6bcfd97 8773 // if grid lines are enabled, then the area of the cell is a bit smaller
4db6714b
KH
8774 if (m_gridLinesEnabled)
8775 {
f6bcfd97
BP
8776 rect.width -= 1;
8777 rect.height -= 1;
8778 }
4db6714b 8779
2d66e025
MB
8780 return rect;
8781}
8782
ef316e23 8783bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) const
2d66e025
MB
8784{
8785 // get the cell rectangle in logical coords
8786 //
8787 wxRect r( CellToRect( row, col ) );
60ff3b99 8788
2d66e025
MB
8789 // convert to device coords
8790 //
8791 int left, top, right, bottom;
8792 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
8793 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 8794
2d66e025 8795 // check against the client area of the grid window
2d66e025
MB
8796 int cw, ch;
8797 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 8798
2d66e025 8799 if ( wholeCellVisible )
f85afd4e 8800 {
2d66e025 8801 // is the cell wholly visible ?
2f024384
DS
8802 return ( left >= 0 && right <= cw &&
8803 top >= 0 && bottom <= ch );
2d66e025
MB
8804 }
8805 else
8806 {
8807 // is the cell partly visible ?
8808 //
2f024384
DS
8809 return ( ((left >= 0 && left < cw) || (right > 0 && right <= cw)) &&
8810 ((top >= 0 && top < ch) || (bottom > 0 && bottom <= ch)) );
2d66e025
MB
8811 }
8812}
8813
2d66e025
MB
8814// make the specified cell location visible by doing a minimal amount
8815// of scrolling
8816//
8817void wxGrid::MakeCellVisible( int row, int col )
8818{
8819 int i;
60ff3b99 8820 int xpos = -1, ypos = -1;
2d66e025 8821
2f024384
DS
8822 if ( row >= 0 && row < m_numRows &&
8823 col >= 0 && col < m_numCols )
2d66e025
MB
8824 {
8825 // get the cell rectangle in logical coords
2d66e025 8826 wxRect r( CellToRect( row, col ) );
60ff3b99 8827
2d66e025 8828 // convert to device coords
2d66e025
MB
8829 int left, top, right, bottom;
8830 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
8831 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 8832
2d66e025
MB
8833 int cw, ch;
8834 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 8835
2d66e025 8836 if ( top < 0 )
3f296516 8837 {
2d66e025 8838 ypos = r.GetTop();
3f296516 8839 }
2d66e025
MB
8840 else if ( bottom > ch )
8841 {
8842 int h = r.GetHeight();
8843 ypos = r.GetTop();
56b6cf26 8844 for ( i = row - 1; i >= 0; i-- )
2d66e025 8845 {
7c1cb261
VZ
8846 int rowHeight = GetRowHeight(i);
8847 if ( h + rowHeight > ch )
8848 break;
2d66e025 8849
7c1cb261
VZ
8850 h += rowHeight;
8851 ypos -= rowHeight;
2d66e025 8852 }
f0102d2a
VZ
8853
8854 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
56b6cf26
DS
8855 // have rounding errors (this is important, because if we do,
8856 // we might not scroll at all and some cells won't be redrawn)
275c4ae4 8857 //
56b6cf26
DS
8858 // Sometimes GRID_SCROLL_LINE / 2 is not enough,
8859 // so just add a full scroll unit...
675a9c0d 8860 ypos += m_scrollLineY;
2d66e025
MB
8861 }
8862
7db713ae 8863 // special handling for wide cells - show always left part of the cell!
faa94f3e 8864 // Otherwise, e.g. when stepping from row to row, it would jump between
7db713ae
JS
8865 // left and right part of the cell on every step!
8866// if ( left < 0 )
ccdee36f 8867 if ( left < 0 || (right - left) >= cw )
2d66e025
MB
8868 {
8869 xpos = r.GetLeft();
8870 }
8871 else if ( right > cw )
8872 {
73145b0e
JS
8873 // position the view so that the cell is on the right
8874 int x0, y0;
8875 CalcUnscrolledPosition(0, 0, &x0, &y0);
8876 xpos = x0 + (right - cw);
f0102d2a
VZ
8877
8878 // see comment for ypos above
675a9c0d 8879 xpos += m_scrollLineX;
2d66e025
MB
8880 }
8881
ccdee36f 8882 if ( xpos != -1 || ypos != -1 )
2d66e025 8883 {
97a9929e 8884 if ( xpos != -1 )
675a9c0d 8885 xpos /= m_scrollLineX;
97a9929e 8886 if ( ypos != -1 )
675a9c0d 8887 ypos /= m_scrollLineY;
2d66e025
MB
8888 Scroll( xpos, ypos );
8889 AdjustScrollbars();
8890 }
8891 }
8892}
8893
2d66e025
MB
8894//
8895// ------ Grid cursor movement functions
8896//
8897
5c8fc7c1 8898bool wxGrid::MoveCursorUp( bool expandSelection )
2d66e025 8899{
2f024384 8900 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 8901 m_currentCellCoords.GetRow() >= 0 )
2d66e025 8902 {
bee19958 8903 if ( expandSelection )
d95b0c2b
SN
8904 {
8905 if ( m_selectingKeyboard == wxGridNoCellCoords )
8906 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
8907 if ( m_selectingKeyboard.GetRow() > 0 )
8908 {
8909 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
8910 MakeCellVisible( m_selectingKeyboard.GetRow(),
8911 m_selectingKeyboard.GetCol() );
c9097836 8912 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 8913 }
d95b0c2b 8914 }
f6bcfd97 8915 else if ( m_currentCellCoords.GetRow() > 0 )
aa5e1f75 8916 {
962a48f6
DS
8917 int row = m_currentCellCoords.GetRow() - 1;
8918 int col = m_currentCellCoords.GetCol();
aa5e1f75 8919 ClearSelection();
962a48f6
DS
8920 MakeCellVisible( row, col );
8921 SetCurrentCell( row, col );
aa5e1f75 8922 }
f6bcfd97 8923 else
ca65c044 8924 return false;
4db6714b 8925
ca65c044 8926 return true;
f85afd4e 8927 }
2d66e025 8928
ca65c044 8929 return false;
2d66e025
MB
8930}
8931
5c8fc7c1 8932bool wxGrid::MoveCursorDown( bool expandSelection )
2d66e025 8933{
2f024384 8934 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 8935 m_currentCellCoords.GetRow() < m_numRows )
f85afd4e 8936 {
5c8fc7c1 8937 if ( expandSelection )
d95b0c2b
SN
8938 {
8939 if ( m_selectingKeyboard == wxGridNoCellCoords )
8940 m_selectingKeyboard = m_currentCellCoords;
ccdee36f 8941 if ( m_selectingKeyboard.GetRow() < m_numRows - 1 )
f6bcfd97
BP
8942 {
8943 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
8944 MakeCellVisible( m_selectingKeyboard.GetRow(),
8945 m_selectingKeyboard.GetCol() );
c9097836 8946 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 8947 }
d95b0c2b 8948 }
f6bcfd97 8949 else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
aa5e1f75 8950 {
962a48f6
DS
8951 int row = m_currentCellCoords.GetRow() + 1;
8952 int col = m_currentCellCoords.GetCol();
aa5e1f75 8953 ClearSelection();
962a48f6
DS
8954 MakeCellVisible( row, col );
8955 SetCurrentCell( row, col );
aa5e1f75 8956 }
f6bcfd97 8957 else
ca65c044 8958 return false;
4db6714b 8959
ca65c044 8960 return true;
f85afd4e 8961 }
2d66e025 8962
ca65c044 8963 return false;
f85afd4e
MB
8964}
8965
5c8fc7c1 8966bool wxGrid::MoveCursorLeft( bool expandSelection )
f85afd4e 8967{
2f024384 8968 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 8969 m_currentCellCoords.GetCol() >= 0 )
2d66e025 8970 {
5c8fc7c1 8971 if ( expandSelection )
d95b0c2b
SN
8972 {
8973 if ( m_selectingKeyboard == wxGridNoCellCoords )
8974 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
8975 if ( m_selectingKeyboard.GetCol() > 0 )
8976 {
8977 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
8978 MakeCellVisible( m_selectingKeyboard.GetRow(),
8979 m_selectingKeyboard.GetCol() );
c9097836 8980 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 8981 }
d95b0c2b 8982 }
d4175745 8983 else if ( GetColPos( m_currentCellCoords.GetCol() ) > 0 )
aa5e1f75 8984 {
962a48f6 8985 int row = m_currentCellCoords.GetRow();
d4175745 8986 int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) - 1 );
aa5e1f75 8987 ClearSelection();
d4175745 8988
962a48f6
DS
8989 MakeCellVisible( row, col );
8990 SetCurrentCell( row, col );
aa5e1f75 8991 }
f6bcfd97 8992 else
ca65c044 8993 return false;
4db6714b 8994
ca65c044 8995 return true;
2d66e025
MB
8996 }
8997
ca65c044 8998 return false;
2d66e025
MB
8999}
9000
5c8fc7c1 9001bool wxGrid::MoveCursorRight( bool expandSelection )
2d66e025 9002{
2f024384 9003 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 9004 m_currentCellCoords.GetCol() < m_numCols )
f85afd4e 9005 {
5c8fc7c1 9006 if ( expandSelection )
d95b0c2b
SN
9007 {
9008 if ( m_selectingKeyboard == wxGridNoCellCoords )
9009 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
9010 if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
9011 {
9012 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
9013 MakeCellVisible( m_selectingKeyboard.GetRow(),
9014 m_selectingKeyboard.GetCol() );
c9097836 9015 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 9016 }
d95b0c2b 9017 }
d4175745 9018 else if ( GetColPos( m_currentCellCoords.GetCol() ) < m_numCols - 1 )
aa5e1f75 9019 {
962a48f6 9020 int row = m_currentCellCoords.GetRow();
d4175745 9021 int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) + 1 );
aa5e1f75 9022 ClearSelection();
d4175745 9023
962a48f6
DS
9024 MakeCellVisible( row, col );
9025 SetCurrentCell( row, col );
aa5e1f75 9026 }
f6bcfd97 9027 else
ca65c044 9028 return false;
4db6714b 9029
ca65c044 9030 return true;
f85afd4e 9031 }
8f177c8e 9032
ca65c044 9033 return false;
2d66e025
MB
9034}
9035
2d66e025
MB
9036bool wxGrid::MovePageUp()
9037{
4db6714b
KH
9038 if ( m_currentCellCoords == wxGridNoCellCoords )
9039 return false;
60ff3b99 9040
2d66e025
MB
9041 int row = m_currentCellCoords.GetRow();
9042 if ( row > 0 )
f85afd4e 9043 {
2d66e025
MB
9044 int cw, ch;
9045 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 9046
7c1cb261 9047 int y = GetRowTop(row);
a967f048 9048 int newRow = internalYToRow( y - ch + 1 );
ef5df12b 9049
a967f048 9050 if ( newRow == row )
2d66e025 9051 {
c2f5b920 9052 // row > 0, so newRow can never be less than 0 here.
2d66e025
MB
9053 newRow = row - 1;
9054 }
8f177c8e 9055
2d66e025
MB
9056 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
9057 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 9058
ca65c044 9059 return true;
f85afd4e 9060 }
2d66e025 9061
ca65c044 9062 return false;
2d66e025
MB
9063}
9064
9065bool wxGrid::MovePageDown()
9066{
4db6714b
KH
9067 if ( m_currentCellCoords == wxGridNoCellCoords )
9068 return false;
60ff3b99 9069
2d66e025 9070 int row = m_currentCellCoords.GetRow();
ccdee36f 9071 if ( (row + 1) < m_numRows )
f85afd4e 9072 {
2d66e025
MB
9073 int cw, ch;
9074 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 9075
7c1cb261 9076 int y = GetRowTop(row);
a967f048
RG
9077 int newRow = internalYToRow( y + ch );
9078 if ( newRow == row )
2d66e025 9079 {
c2f5b920 9080 // row < m_numRows, so newRow can't overflow here.
ca65c044 9081 newRow = row + 1;
2d66e025
MB
9082 }
9083
9084 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
9085 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 9086
ca65c044 9087 return true;
f85afd4e 9088 }
2d66e025 9089
ca65c044 9090 return false;
f85afd4e 9091}
8f177c8e 9092
5c8fc7c1 9093bool wxGrid::MoveCursorUpBlock( bool expandSelection )
2d66e025
MB
9094{
9095 if ( m_table &&
2f024384 9096 m_currentCellCoords != wxGridNoCellCoords &&
2d66e025
MB
9097 m_currentCellCoords.GetRow() > 0 )
9098 {
9099 int row = m_currentCellCoords.GetRow();
9100 int col = m_currentCellCoords.GetCol();
9101
9102 if ( m_table->IsEmptyCell(row, col) )
9103 {
9104 // starting in an empty cell: find the next block of
9105 // non-empty cells
9106 //
9107 while ( row > 0 )
9108 {
2f024384 9109 row--;
4db6714b
KH
9110 if ( !(m_table->IsEmptyCell(row, col)) )
9111 break;
2d66e025
MB
9112 }
9113 }
2f024384 9114 else if ( m_table->IsEmptyCell(row - 1, col) )
2d66e025
MB
9115 {
9116 // starting at the top of a block: find the next block
9117 //
9118 row--;
9119 while ( row > 0 )
9120 {
2f024384 9121 row--;
4db6714b
KH
9122 if ( !(m_table->IsEmptyCell(row, col)) )
9123 break;
2d66e025
MB
9124 }
9125 }
9126 else
9127 {
9128 // starting within a block: find the top of the block
9129 //
9130 while ( row > 0 )
9131 {
2f024384 9132 row--;
2d66e025
MB
9133 if ( m_table->IsEmptyCell(row, col) )
9134 {
2f024384 9135 row++;
2d66e025
MB
9136 break;
9137 }
9138 }
9139 }
f85afd4e 9140
2d66e025 9141 MakeCellVisible( row, col );
5c8fc7c1 9142 if ( expandSelection )
d95b0c2b
SN
9143 {
9144 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 9145 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
9146 }
9147 else
aa5e1f75
SN
9148 {
9149 ClearSelection();
9150 SetCurrentCell( row, col );
9151 }
4db6714b 9152
ca65c044 9153 return true;
2d66e025 9154 }
f85afd4e 9155
ca65c044 9156 return false;
2d66e025 9157}
f85afd4e 9158
5c8fc7c1 9159bool wxGrid::MoveCursorDownBlock( bool expandSelection )
f85afd4e 9160{
2d66e025 9161 if ( m_table &&
2f024384
DS
9162 m_currentCellCoords != wxGridNoCellCoords &&
9163 m_currentCellCoords.GetRow() < m_numRows - 1 )
f85afd4e 9164 {
2d66e025
MB
9165 int row = m_currentCellCoords.GetRow();
9166 int col = m_currentCellCoords.GetCol();
9167
9168 if ( m_table->IsEmptyCell(row, col) )
9169 {
9170 // starting in an empty cell: find the next block of
9171 // non-empty cells
9172 //
2f024384 9173 while ( row < m_numRows - 1 )
2d66e025 9174 {
2f024384 9175 row++;
4db6714b
KH
9176 if ( !(m_table->IsEmptyCell(row, col)) )
9177 break;
2d66e025
MB
9178 }
9179 }
2f024384 9180 else if ( m_table->IsEmptyCell(row + 1, col) )
2d66e025
MB
9181 {
9182 // starting at the bottom of a block: find the next block
9183 //
9184 row++;
2f024384 9185 while ( row < m_numRows - 1 )
2d66e025 9186 {
2f024384 9187 row++;
4db6714b
KH
9188 if ( !(m_table->IsEmptyCell(row, col)) )
9189 break;
2d66e025
MB
9190 }
9191 }
9192 else
9193 {
9194 // starting within a block: find the bottom of the block
9195 //
2f024384 9196 while ( row < m_numRows - 1 )
2d66e025 9197 {
2f024384 9198 row++;
2d66e025
MB
9199 if ( m_table->IsEmptyCell(row, col) )
9200 {
2f024384 9201 row--;
2d66e025
MB
9202 break;
9203 }
9204 }
9205 }
9206
9207 MakeCellVisible( row, col );
5c8fc7c1 9208 if ( expandSelection )
d95b0c2b
SN
9209 {
9210 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 9211 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
9212 }
9213 else
aa5e1f75
SN
9214 {
9215 ClearSelection();
9216 SetCurrentCell( row, col );
9217 }
2d66e025 9218
ca65c044 9219 return true;
f85afd4e 9220 }
f85afd4e 9221
ca65c044 9222 return false;
2d66e025 9223}
f85afd4e 9224
5c8fc7c1 9225bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
f85afd4e 9226{
2d66e025 9227 if ( m_table &&
2f024384 9228 m_currentCellCoords != wxGridNoCellCoords &&
2d66e025 9229 m_currentCellCoords.GetCol() > 0 )
f85afd4e 9230 {
2d66e025
MB
9231 int row = m_currentCellCoords.GetRow();
9232 int col = m_currentCellCoords.GetCol();
9233
9234 if ( m_table->IsEmptyCell(row, col) )
9235 {
9236 // starting in an empty cell: find the next block of
9237 // non-empty cells
9238 //
9239 while ( col > 0 )
9240 {
2f024384 9241 col--;
4db6714b
KH
9242 if ( !(m_table->IsEmptyCell(row, col)) )
9243 break;
2d66e025
MB
9244 }
9245 }
2f024384 9246 else if ( m_table->IsEmptyCell(row, col - 1) )
2d66e025
MB
9247 {
9248 // starting at the left of a block: find the next block
9249 //
9250 col--;
9251 while ( col > 0 )
9252 {
2f024384 9253 col--;
4db6714b
KH
9254 if ( !(m_table->IsEmptyCell(row, col)) )
9255 break;
2d66e025
MB
9256 }
9257 }
9258 else
9259 {
9260 // starting within a block: find the left of the block
9261 //
9262 while ( col > 0 )
9263 {
2f024384 9264 col--;
2d66e025
MB
9265 if ( m_table->IsEmptyCell(row, col) )
9266 {
2f024384 9267 col++;
2d66e025
MB
9268 break;
9269 }
9270 }
9271 }
f85afd4e 9272
2d66e025 9273 MakeCellVisible( row, col );
5c8fc7c1 9274 if ( expandSelection )
d95b0c2b
SN
9275 {
9276 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 9277 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
9278 }
9279 else
aa5e1f75
SN
9280 {
9281 ClearSelection();
9282 SetCurrentCell( row, col );
9283 }
8f177c8e 9284
ca65c044 9285 return true;
f85afd4e 9286 }
2d66e025 9287
ca65c044 9288 return false;
f85afd4e
MB
9289}
9290
5c8fc7c1 9291bool wxGrid::MoveCursorRightBlock( bool expandSelection )
f85afd4e 9292{
2d66e025 9293 if ( m_table &&
2f024384
DS
9294 m_currentCellCoords != wxGridNoCellCoords &&
9295 m_currentCellCoords.GetCol() < m_numCols - 1 )
f85afd4e 9296 {
2d66e025
MB
9297 int row = m_currentCellCoords.GetRow();
9298 int col = m_currentCellCoords.GetCol();
8f177c8e 9299
2d66e025
MB
9300 if ( m_table->IsEmptyCell(row, col) )
9301 {
9302 // starting in an empty cell: find the next block of
9303 // non-empty cells
9304 //
2f024384 9305 while ( col < m_numCols - 1 )
2d66e025 9306 {
2f024384 9307 col++;
4db6714b
KH
9308 if ( !(m_table->IsEmptyCell(row, col)) )
9309 break;
2d66e025
MB
9310 }
9311 }
2f024384 9312 else if ( m_table->IsEmptyCell(row, col + 1) )
2d66e025
MB
9313 {
9314 // starting at the right of a block: find the next block
9315 //
9316 col++;
2f024384 9317 while ( col < m_numCols - 1 )
2d66e025 9318 {
2f024384 9319 col++;
4db6714b
KH
9320 if ( !(m_table->IsEmptyCell(row, col)) )
9321 break;
2d66e025
MB
9322 }
9323 }
9324 else
9325 {
9326 // starting within a block: find the right of the block
9327 //
2f024384 9328 while ( col < m_numCols - 1 )
2d66e025 9329 {
2f024384 9330 col++;
2d66e025
MB
9331 if ( m_table->IsEmptyCell(row, col) )
9332 {
2f024384 9333 col--;
2d66e025
MB
9334 break;
9335 }
9336 }
9337 }
8f177c8e 9338
2d66e025 9339 MakeCellVisible( row, col );
5c8fc7c1 9340 if ( expandSelection )
d95b0c2b
SN
9341 {
9342 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 9343 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
9344 }
9345 else
aa5e1f75
SN
9346 {
9347 ClearSelection();
9348 SetCurrentCell( row, col );
9349 }
f85afd4e 9350
ca65c044 9351 return true;
f85afd4e 9352 }
2d66e025 9353
ca65c044 9354 return false;
f85afd4e
MB
9355}
9356
f85afd4e 9357//
2d66e025 9358// ------ Label values and formatting
f85afd4e
MB
9359//
9360
ef316e23 9361void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) const
f85afd4e 9362{
2f024384
DS
9363 if ( horiz )
9364 *horiz = m_rowLabelHorizAlign;
9365 if ( vert )
9366 *vert = m_rowLabelVertAlign;
f85afd4e
MB
9367}
9368
ef316e23 9369void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) const
f85afd4e 9370{
2f024384
DS
9371 if ( horiz )
9372 *horiz = m_colLabelHorizAlign;
9373 if ( vert )
9374 *vert = m_colLabelVertAlign;
f85afd4e
MB
9375}
9376
ef316e23 9377int wxGrid::GetColLabelTextOrientation() const
d43851f7
JS
9378{
9379 return m_colLabelTextOrientation;
9380}
9381
ef316e23 9382wxString wxGrid::GetRowLabelValue( int row ) const
f85afd4e
MB
9383{
9384 if ( m_table )
9385 {
9386 return m_table->GetRowLabelValue( row );
9387 }
9388 else
9389 {
9390 wxString s;
9391 s << row;
9392 return s;
9393 }
9394}
9395
ef316e23 9396wxString wxGrid::GetColLabelValue( int col ) const
f85afd4e
MB
9397{
9398 if ( m_table )
9399 {
9400 return m_table->GetColLabelValue( col );
9401 }
9402 else
9403 {
9404 wxString s;
9405 s << col;
9406 return s;
9407 }
9408}
9409
9410void wxGrid::SetRowLabelSize( int width )
9411{
2e8cd977
MB
9412 width = wxMax( width, 0 );
9413 if ( width != m_rowLabelWidth )
9414 {
2e8cd977
MB
9415 if ( width == 0 )
9416 {
ca65c044
WS
9417 m_rowLabelWin->Show( false );
9418 m_cornerLabelWin->Show( false );
2e8cd977 9419 }
7807d81c 9420 else if ( m_rowLabelWidth == 0 )
2e8cd977 9421 {
ca65c044 9422 m_rowLabelWin->Show( true );
2f024384
DS
9423 if ( m_colLabelHeight > 0 )
9424 m_cornerLabelWin->Show( true );
2e8cd977 9425 }
b99be8fb 9426
2e8cd977 9427 m_rowLabelWidth = width;
7807d81c 9428 CalcWindowSizes();
ca65c044 9429 wxScrolledWindow::Refresh( true );
2e8cd977 9430 }
f85afd4e
MB
9431}
9432
9433void wxGrid::SetColLabelSize( int height )
9434{
7807d81c 9435 height = wxMax( height, 0 );
2e8cd977
MB
9436 if ( height != m_colLabelHeight )
9437 {
2e8cd977
MB
9438 if ( height == 0 )
9439 {
ca65c044
WS
9440 m_colLabelWin->Show( false );
9441 m_cornerLabelWin->Show( false );
2e8cd977 9442 }
7807d81c 9443 else if ( m_colLabelHeight == 0 )
2e8cd977 9444 {
ca65c044 9445 m_colLabelWin->Show( true );
a9339fe2
DS
9446 if ( m_rowLabelWidth > 0 )
9447 m_cornerLabelWin->Show( true );
2e8cd977 9448 }
7807d81c 9449
2e8cd977 9450 m_colLabelHeight = height;
7807d81c 9451 CalcWindowSizes();
ca65c044 9452 wxScrolledWindow::Refresh( true );
2e8cd977 9453 }
f85afd4e
MB
9454}
9455
9456void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
9457{
2d66e025
MB
9458 if ( m_labelBackgroundColour != colour )
9459 {
9460 m_labelBackgroundColour = colour;
9461 m_rowLabelWin->SetBackgroundColour( colour );
9462 m_colLabelWin->SetBackgroundColour( colour );
9463 m_cornerLabelWin->SetBackgroundColour( colour );
9464
9465 if ( !GetBatchCount() )
9466 {
9467 m_rowLabelWin->Refresh();
9468 m_colLabelWin->Refresh();
9469 m_cornerLabelWin->Refresh();
9470 }
9471 }
f85afd4e
MB
9472}
9473
9474void wxGrid::SetLabelTextColour( const wxColour& colour )
9475{
2d66e025
MB
9476 if ( m_labelTextColour != colour )
9477 {
9478 m_labelTextColour = colour;
9479 if ( !GetBatchCount() )
9480 {
9481 m_rowLabelWin->Refresh();
9482 m_colLabelWin->Refresh();
9483 }
9484 }
f85afd4e
MB
9485}
9486
9487void wxGrid::SetLabelFont( const wxFont& font )
9488{
9489 m_labelFont = font;
2d66e025
MB
9490 if ( !GetBatchCount() )
9491 {
9492 m_rowLabelWin->Refresh();
9493 m_colLabelWin->Refresh();
9494 }
f85afd4e
MB
9495}
9496
9497void wxGrid::SetRowLabelAlignment( int horiz, int vert )
9498{
4c7277db
MB
9499 // allow old (incorrect) defs to be used
9500 switch ( horiz )
9501 {
9502 case wxLEFT: horiz = wxALIGN_LEFT; break;
9503 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
9504 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
9505 }
84912ef8 9506
4c7277db
MB
9507 switch ( vert )
9508 {
9509 case wxTOP: vert = wxALIGN_TOP; break;
9510 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
9511 case wxCENTRE: vert = wxALIGN_CENTRE; break;
9512 }
84912ef8 9513
4c7277db 9514 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
f85afd4e
MB
9515 {
9516 m_rowLabelHorizAlign = horiz;
9517 }
8f177c8e 9518
4c7277db 9519 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
f85afd4e
MB
9520 {
9521 m_rowLabelVertAlign = vert;
9522 }
9523
2d66e025
MB
9524 if ( !GetBatchCount() )
9525 {
9526 m_rowLabelWin->Refresh();
60ff3b99 9527 }
f85afd4e
MB
9528}
9529
9530void wxGrid::SetColLabelAlignment( int horiz, int vert )
9531{
4c7277db
MB
9532 // allow old (incorrect) defs to be used
9533 switch ( horiz )
9534 {
9535 case wxLEFT: horiz = wxALIGN_LEFT; break;
9536 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
9537 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
9538 }
84912ef8 9539
4c7277db
MB
9540 switch ( vert )
9541 {
9542 case wxTOP: vert = wxALIGN_TOP; break;
9543 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
9544 case wxCENTRE: vert = wxALIGN_CENTRE; break;
9545 }
84912ef8 9546
4c7277db 9547 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
f85afd4e
MB
9548 {
9549 m_colLabelHorizAlign = horiz;
9550 }
8f177c8e 9551
4c7277db 9552 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
f85afd4e
MB
9553 {
9554 m_colLabelVertAlign = vert;
9555 }
9556
2d66e025
MB
9557 if ( !GetBatchCount() )
9558 {
2d66e025 9559 m_colLabelWin->Refresh();
60ff3b99 9560 }
f85afd4e
MB
9561}
9562
ca65c044
WS
9563// Note: under MSW, the default column label font must be changed because it
9564// does not support vertical printing
d43851f7
JS
9565//
9566// Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD);
ca65c044
WS
9567// pGrid->SetLabelFont(font);
9568// pGrid->SetColLabelTextOrientation(wxVERTICAL);
d43851f7
JS
9569//
9570void wxGrid::SetColLabelTextOrientation( int textOrientation )
9571{
4db6714b 9572 if ( textOrientation == wxHORIZONTAL || textOrientation == wxVERTICAL )
d43851f7 9573 m_colLabelTextOrientation = textOrientation;
d43851f7
JS
9574
9575 if ( !GetBatchCount() )
d43851f7 9576 m_colLabelWin->Refresh();
d43851f7
JS
9577}
9578
f85afd4e
MB
9579void wxGrid::SetRowLabelValue( int row, const wxString& s )
9580{
9581 if ( m_table )
9582 {
9583 m_table->SetRowLabelValue( row, s );
2d66e025
MB
9584 if ( !GetBatchCount() )
9585 {
ccdee36f 9586 wxRect rect = CellToRect( row, 0 );
70c7a608
SN
9587 if ( rect.height > 0 )
9588 {
cb309039 9589 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
b1944ebc 9590 rect.x = 0;
70c7a608 9591 rect.width = m_rowLabelWidth;
ca65c044 9592 m_rowLabelWin->Refresh( true, &rect );
70c7a608 9593 }
2d66e025 9594 }
f85afd4e
MB
9595 }
9596}
9597
9598void wxGrid::SetColLabelValue( int col, const wxString& s )
9599{
9600 if ( m_table )
9601 {
9602 m_table->SetColLabelValue( col, s );
2d66e025
MB
9603 if ( !GetBatchCount() )
9604 {
70c7a608
SN
9605 wxRect rect = CellToRect( 0, col );
9606 if ( rect.width > 0 )
9607 {
cb309039 9608 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
b1944ebc 9609 rect.y = 0;
70c7a608 9610 rect.height = m_colLabelHeight;
ca65c044 9611 m_colLabelWin->Refresh( true, &rect );
70c7a608 9612 }
2d66e025 9613 }
f85afd4e
MB
9614 }
9615}
9616
9617void wxGrid::SetGridLineColour( const wxColour& colour )
9618{
2d66e025
MB
9619 if ( m_gridLineColour != colour )
9620 {
9621 m_gridLineColour = colour;
60ff3b99 9622
2d66e025
MB
9623 wxClientDC dc( m_gridWin );
9624 PrepareDC( dc );
c6a51dcd 9625 DrawAllGridLines( dc, wxRegion() );
2d66e025 9626 }
f85afd4e
MB
9627}
9628
f6bcfd97
BP
9629void wxGrid::SetCellHighlightColour( const wxColour& colour )
9630{
9631 if ( m_cellHighlightColour != colour )
9632 {
9633 m_cellHighlightColour = colour;
9634
9635 wxClientDC dc( m_gridWin );
9636 PrepareDC( dc );
9637 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
9638 DrawCellHighlight(dc, attr);
9639 attr->DecRef();
9640 }
9641}
9642
d2520c85
RD
9643void wxGrid::SetCellHighlightPenWidth(int width)
9644{
4db6714b
KH
9645 if (m_cellHighlightPenWidth != width)
9646 {
d2520c85
RD
9647 m_cellHighlightPenWidth = width;
9648
9649 // Just redrawing the cell highlight is not enough since that won't
9650 // make any visible change if the the thickness is getting smaller.
9651 int row = m_currentCellCoords.GetRow();
9652 int col = m_currentCellCoords.GetCol();
9653 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
9654 return;
2f024384 9655
d2520c85 9656 wxRect rect = CellToRect(row, col);
ca65c044 9657 m_gridWin->Refresh(true, &rect);
d2520c85
RD
9658 }
9659}
9660
9661void wxGrid::SetCellHighlightROPenWidth(int width)
9662{
4db6714b
KH
9663 if (m_cellHighlightROPenWidth != width)
9664 {
d2520c85
RD
9665 m_cellHighlightROPenWidth = width;
9666
9667 // Just redrawing the cell highlight is not enough since that won't
9668 // make any visible change if the the thickness is getting smaller.
9669 int row = m_currentCellCoords.GetRow();
9670 int col = m_currentCellCoords.GetCol();
9671 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
9672 return;
ccdee36f 9673
d2520c85 9674 wxRect rect = CellToRect(row, col);
ca65c044 9675 m_gridWin->Refresh(true, &rect);
d2520c85
RD
9676 }
9677}
9678
f85afd4e
MB
9679void wxGrid::EnableGridLines( bool enable )
9680{
9681 if ( enable != m_gridLinesEnabled )
9682 {
9683 m_gridLinesEnabled = enable;
2d66e025
MB
9684
9685 if ( !GetBatchCount() )
9686 {
9687 if ( enable )
9688 {
9689 wxClientDC dc( m_gridWin );
9690 PrepareDC( dc );
c6a51dcd 9691 DrawAllGridLines( dc, wxRegion() );
2d66e025
MB
9692 }
9693 else
9694 {
9695 m_gridWin->Refresh();
9696 }
9697 }
f85afd4e
MB
9698 }
9699}
9700
ef316e23 9701int wxGrid::GetDefaultRowSize() const
f85afd4e
MB
9702{
9703 return m_defaultRowHeight;
9704}
9705
ef316e23 9706int wxGrid::GetRowSize( int row ) const
f85afd4e 9707{
b99be8fb
VZ
9708 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
9709
7c1cb261 9710 return GetRowHeight(row);
f85afd4e
MB
9711}
9712
ef316e23 9713int wxGrid::GetDefaultColSize() const
f85afd4e
MB
9714{
9715 return m_defaultColWidth;
9716}
9717
ef316e23 9718int wxGrid::GetColSize( int col ) const
f85afd4e 9719{
b99be8fb
VZ
9720 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
9721
7c1cb261 9722 return GetColWidth(col);
f85afd4e
MB
9723}
9724
2e9a6788
VZ
9725// ============================================================================
9726// access to the grid attributes: each of them has a default value in the grid
9727// itself and may be overidden on a per-cell basis
9728// ============================================================================
9729
9730// ----------------------------------------------------------------------------
9731// setting default attributes
9732// ----------------------------------------------------------------------------
9733
9734void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
9735{
2796cce3 9736 m_defaultCellAttr->SetBackgroundColour(col);
c916e13b
RR
9737#ifdef __WXGTK__
9738 m_gridWin->SetBackgroundColour(col);
9739#endif
2e9a6788
VZ
9740}
9741
9742void wxGrid::SetDefaultCellTextColour( const wxColour& col )
9743{
2796cce3 9744 m_defaultCellAttr->SetTextColour(col);
2e9a6788
VZ
9745}
9746
9747void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
9748{
2796cce3 9749 m_defaultCellAttr->SetAlignment(horiz, vert);
2e9a6788
VZ
9750}
9751
27f35b66
SN
9752void wxGrid::SetDefaultCellOverflow( bool allow )
9753{
9754 m_defaultCellAttr->SetOverflow(allow);
9755}
9756
2e9a6788
VZ
9757void wxGrid::SetDefaultCellFont( const wxFont& font )
9758{
2796cce3
RD
9759 m_defaultCellAttr->SetFont(font);
9760}
9761
ca63e8e9
RD
9762// For editors and renderers the type registry takes precedence over the
9763// default attr, so we need to register the new editor/renderer for the string
9764// data type in order to make setting a default editor/renderer appear to
9765// work correctly.
9766
0ba143c9
RD
9767void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
9768{
ca63e8e9
RD
9769 RegisterDataType(wxGRID_VALUE_STRING,
9770 renderer,
9771 GetDefaultEditorForType(wxGRID_VALUE_STRING));
0ba143c9 9772}
2e9a6788 9773
0ba143c9
RD
9774void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
9775{
ca63e8e9
RD
9776 RegisterDataType(wxGRID_VALUE_STRING,
9777 GetDefaultRendererForType(wxGRID_VALUE_STRING),
42841dfc 9778 editor);
0ba143c9 9779}
9b4aede2 9780
2e9a6788 9781// ----------------------------------------------------------------------------
ef316e23 9782// access to the default attributes
2e9a6788
VZ
9783// ----------------------------------------------------------------------------
9784
ef316e23 9785wxColour wxGrid::GetDefaultCellBackgroundColour() const
f85afd4e 9786{
2796cce3 9787 return m_defaultCellAttr->GetBackgroundColour();
f85afd4e
MB
9788}
9789
ef316e23 9790wxColour wxGrid::GetDefaultCellTextColour() const
2e9a6788 9791{
2796cce3 9792 return m_defaultCellAttr->GetTextColour();
2e9a6788
VZ
9793}
9794
ef316e23 9795wxFont wxGrid::GetDefaultCellFont() const
2e9a6788 9796{
2796cce3 9797 return m_defaultCellAttr->GetFont();
2e9a6788
VZ
9798}
9799
ef316e23 9800void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) const
2e9a6788 9801{
2796cce3 9802 m_defaultCellAttr->GetAlignment(horiz, vert);
2e9a6788
VZ
9803}
9804
ef316e23 9805bool wxGrid::GetDefaultCellOverflow() const
27f35b66
SN
9806{
9807 return m_defaultCellAttr->GetOverflow();
9808}
9809
0ba143c9
RD
9810wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
9811{
0b190b0f 9812 return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
0ba143c9 9813}
ab79958a 9814
0ba143c9
RD
9815wxGridCellEditor *wxGrid::GetDefaultEditor() const
9816{
4db6714b 9817 return m_defaultCellAttr->GetEditor(NULL, 0, 0);
0ba143c9 9818}
9b4aede2 9819
2e9a6788
VZ
9820// ----------------------------------------------------------------------------
9821// access to cell attributes
9822// ----------------------------------------------------------------------------
9823
ef316e23 9824wxColour wxGrid::GetCellBackgroundColour(int row, int col) const
f85afd4e 9825{
0a976765 9826 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 9827 wxColour colour = attr->GetBackgroundColour();
39bcce60 9828 attr->DecRef();
2f024384 9829
b99be8fb 9830 return colour;
f85afd4e
MB
9831}
9832
ef316e23 9833wxColour wxGrid::GetCellTextColour( int row, int col ) const
f85afd4e 9834{
0a976765 9835 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 9836 wxColour colour = attr->GetTextColour();
39bcce60 9837 attr->DecRef();
2f024384 9838
b99be8fb 9839 return colour;
f85afd4e
MB
9840}
9841
ef316e23 9842wxFont wxGrid::GetCellFont( int row, int col ) const
f85afd4e 9843{
0a976765 9844 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 9845 wxFont font = attr->GetFont();
39bcce60 9846 attr->DecRef();
2f024384 9847
b99be8fb 9848 return font;
f85afd4e
MB
9849}
9850
ef316e23 9851void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) const
f85afd4e 9852{
0a976765 9853 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 9854 attr->GetAlignment(horiz, vert);
39bcce60 9855 attr->DecRef();
2e9a6788
VZ
9856}
9857
ef316e23 9858bool wxGrid::GetCellOverflow( int row, int col ) const
27f35b66
SN
9859{
9860 wxGridCellAttr *attr = GetCellAttr(row, col);
9861 bool allow = attr->GetOverflow();
9862 attr->DecRef();
4db6714b 9863
27f35b66
SN
9864 return allow;
9865}
9866
ef316e23 9867void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) const
27f35b66
SN
9868{
9869 wxGridCellAttr *attr = GetCellAttr(row, col);
9870 attr->GetSize( num_rows, num_cols );
9871 attr->DecRef();
9872}
9873
ef316e23 9874wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) const
2796cce3
RD
9875{
9876 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 9877 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
2796cce3 9878 attr->DecRef();
0b190b0f 9879
2796cce3
RD
9880 return renderer;
9881}
9882
ef316e23 9883wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) const
9b4aede2
RD
9884{
9885 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 9886 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
9b4aede2 9887 attr->DecRef();
0b190b0f 9888
9b4aede2
RD
9889 return editor;
9890}
9891
283b7808
VZ
9892bool wxGrid::IsReadOnly(int row, int col) const
9893{
9894 wxGridCellAttr* attr = GetCellAttr(row, col);
9895 bool isReadOnly = attr->IsReadOnly();
9896 attr->DecRef();
4db6714b 9897
283b7808
VZ
9898 return isReadOnly;
9899}
9900
2e9a6788 9901// ----------------------------------------------------------------------------
758cbedf 9902// attribute support: cache, automatic provider creation, ...
2e9a6788
VZ
9903// ----------------------------------------------------------------------------
9904
ef316e23 9905bool wxGrid::CanHaveAttributes() const
2e9a6788
VZ
9906{
9907 if ( !m_table )
9908 {
ca65c044 9909 return false;
2e9a6788
VZ
9910 }
9911
f2d76237 9912 return m_table->CanHaveAttributes();
2e9a6788
VZ
9913}
9914
0a976765
VZ
9915void wxGrid::ClearAttrCache()
9916{
9917 if ( m_attrCache.row != -1 )
9918 {
39bcce60 9919 wxSafeDecRef(m_attrCache.attr);
19d7140e 9920 m_attrCache.attr = NULL;
0a976765
VZ
9921 m_attrCache.row = -1;
9922 }
9923}
9924
9925void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
9926{
2b5f62a0
VZ
9927 if ( attr != NULL )
9928 {
9929 wxGrid *self = (wxGrid *)this; // const_cast
0a976765 9930
2b5f62a0
VZ
9931 self->ClearAttrCache();
9932 self->m_attrCache.row = row;
9933 self->m_attrCache.col = col;
9934 self->m_attrCache.attr = attr;
9935 wxSafeIncRef(attr);
9936 }
0a976765
VZ
9937}
9938
9939bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
9940{
9941 if ( row == m_attrCache.row && col == m_attrCache.col )
9942 {
9943 *attr = m_attrCache.attr;
39bcce60 9944 wxSafeIncRef(m_attrCache.attr);
0a976765
VZ
9945
9946#ifdef DEBUG_ATTR_CACHE
9947 gs_nAttrCacheHits++;
9948#endif
9949
ca65c044 9950 return true;
0a976765
VZ
9951 }
9952 else
9953 {
9954#ifdef DEBUG_ATTR_CACHE
9955 gs_nAttrCacheMisses++;
9956#endif
4db6714b 9957
ca65c044 9958 return false;
0a976765
VZ
9959 }
9960}
9961
2e9a6788
VZ
9962wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
9963{
a373d23b
SN
9964 wxGridCellAttr *attr = NULL;
9965 // Additional test to avoid looking at the cache e.g. for
9966 // wxNoCellCoords, as this will confuse memory management.
9967 if ( row >= 0 )
9968 {
3ed884a0
SN
9969 if ( !LookupAttr(row, col, &attr) )
9970 {
c2f5b920 9971 attr = m_table ? m_table->GetAttr(row, col, wxGridCellAttr::Any)
3ed884a0
SN
9972 : (wxGridCellAttr *)NULL;
9973 CacheAttr(row, col, attr);
9974 }
0a976765 9975 }
4db6714b 9976
508011ce
VZ
9977 if (attr)
9978 {
2796cce3 9979 attr->SetDefAttr(m_defaultCellAttr);
508011ce
VZ
9980 }
9981 else
9982 {
2796cce3
RD
9983 attr = m_defaultCellAttr;
9984 attr->IncRef();
9985 }
2e9a6788 9986
0a976765
VZ
9987 return attr;
9988}
9989
9990wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
9991{
19d7140e 9992 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
71e60f70 9993 bool canHave = ((wxGrid*)this)->CanHaveAttributes();
0a976765 9994
71e60f70
RD
9995 wxCHECK_MSG( canHave, attr, _T("Cell attributes not allowed"));
9996 wxCHECK_MSG( m_table, attr, _T("must have a table") );
1df4050d
VZ
9997
9998 attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell);
9999 if ( !attr )
10000 {
10001 attr = new wxGridCellAttr(m_defaultCellAttr);
10002
10003 // artificially inc the ref count to match DecRef() in caller
10004 attr->IncRef();
10005 m_table->SetAttr(attr, row, col);
10006 }
0a976765 10007
2e9a6788
VZ
10008 return attr;
10009}
10010
0b190b0f
VZ
10011// ----------------------------------------------------------------------------
10012// setting column attributes (wrappers around SetColAttr)
10013// ----------------------------------------------------------------------------
10014
10015void wxGrid::SetColFormatBool(int col)
10016{
10017 SetColFormatCustom(col, wxGRID_VALUE_BOOL);
10018}
10019
10020void wxGrid::SetColFormatNumber(int col)
10021{
10022 SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
10023}
10024
10025void wxGrid::SetColFormatFloat(int col, int width, int precision)
10026{
10027 wxString typeName = wxGRID_VALUE_FLOAT;
10028 if ( (width != -1) || (precision != -1) )
10029 {
10030 typeName << _T(':') << width << _T(',') << precision;
10031 }
10032
10033 SetColFormatCustom(col, typeName);
10034}
10035
10036void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
10037{
999836aa 10038 wxGridCellAttr *attr = m_table->GetAttr(-1, col, wxGridCellAttr::Col );
4db6714b 10039 if (!attr)
19d7140e 10040 attr = new wxGridCellAttr;
0b190b0f
VZ
10041 wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
10042 attr->SetRenderer(renderer);
10043
10044 SetColAttr(col, attr);
19d7140e 10045
0b190b0f
VZ
10046}
10047
758cbedf
VZ
10048// ----------------------------------------------------------------------------
10049// setting cell attributes: this is forwarded to the table
10050// ----------------------------------------------------------------------------
10051
27f35b66
SN
10052void wxGrid::SetAttr(int row, int col, wxGridCellAttr *attr)
10053{
10054 if ( CanHaveAttributes() )
10055 {
10056 m_table->SetAttr(attr, row, col);
10057 ClearAttrCache();
10058 }
10059 else
10060 {
10061 wxSafeDecRef(attr);
10062 }
10063}
10064
758cbedf
VZ
10065void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
10066{
10067 if ( CanHaveAttributes() )
10068 {
10069 m_table->SetRowAttr(attr, row);
19d7140e 10070 ClearAttrCache();
758cbedf
VZ
10071 }
10072 else
10073 {
39bcce60 10074 wxSafeDecRef(attr);
758cbedf
VZ
10075 }
10076}
10077
10078void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
10079{
10080 if ( CanHaveAttributes() )
10081 {
10082 m_table->SetColAttr(attr, col);
19d7140e 10083 ClearAttrCache();
758cbedf
VZ
10084 }
10085 else
10086 {
39bcce60 10087 wxSafeDecRef(attr);
758cbedf
VZ
10088 }
10089}
10090
2e9a6788
VZ
10091void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
10092{
10093 if ( CanHaveAttributes() )
10094 {
0a976765 10095 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
10096 attr->SetBackgroundColour(colour);
10097 attr->DecRef();
10098 }
10099}
10100
10101void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
10102{
10103 if ( CanHaveAttributes() )
10104 {
0a976765 10105 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
10106 attr->SetTextColour(colour);
10107 attr->DecRef();
10108 }
10109}
10110
10111void wxGrid::SetCellFont( int row, int col, const wxFont& font )
10112{
10113 if ( CanHaveAttributes() )
10114 {
0a976765 10115 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
10116 attr->SetFont(font);
10117 attr->DecRef();
10118 }
10119}
10120
10121void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
10122{
10123 if ( CanHaveAttributes() )
10124 {
0a976765 10125 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
10126 attr->SetAlignment(horiz, vert);
10127 attr->DecRef();
ab79958a
VZ
10128 }
10129}
10130
27f35b66
SN
10131void wxGrid::SetCellOverflow( int row, int col, bool allow )
10132{
10133 if ( CanHaveAttributes() )
10134 {
10135 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
10136 attr->SetOverflow(allow);
10137 attr->DecRef();
10138 }
10139}
10140
10141void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols )
10142{
10143 if ( CanHaveAttributes() )
10144 {
10145 int cell_rows, cell_cols;
10146
10147 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
10148 attr->GetSize(&cell_rows, &cell_cols);
10149 attr->SetSize(num_rows, num_cols);
10150 attr->DecRef();
10151
10152 // Cannot set the size of a cell to 0 or negative values
10153 // While it is perfectly legal to do that, this function cannot
10154 // handle all the possibilies, do it by hand by getting the CellAttr.
10155 // You can only set the size of a cell to 1,1 or greater with this fn
10156 wxASSERT_MSG( !((cell_rows < 1) || (cell_cols < 1)),
10157 wxT("wxGrid::SetCellSize setting cell size that is already part of another cell"));
10158 wxASSERT_MSG( !((num_rows < 1) || (num_cols < 1)),
10159 wxT("wxGrid::SetCellSize setting cell size to < 1"));
10160
10161 // if this was already a multicell then "turn off" the other cells first
10162 if ((cell_rows > 1) || (cell_rows > 1))
10163 {
10164 int i, j;
2f024384 10165 for (j=row; j < row + cell_rows; j++)
27f35b66 10166 {
2f024384 10167 for (i=col; i < col + cell_cols; i++)
27f35b66
SN
10168 {
10169 if ((i != col) || (j != row))
10170 {
10171 wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
10172 attr_stub->SetSize( 1, 1 );
10173 attr_stub->DecRef();
10174 }
10175 }
10176 }
10177 }
10178
10179 // mark the cells that will be covered by this cell to
10180 // negative or zero values to point back at this cell
10181 if (((num_rows > 1) || (num_cols > 1)) && (num_rows >= 1) && (num_cols >= 1))
10182 {
10183 int i, j;
2f024384 10184 for (j=row; j < row + num_rows; j++)
27f35b66 10185 {
2f024384 10186 for (i=col; i < col + num_cols; i++)
27f35b66
SN
10187 {
10188 if ((i != col) || (j != row))
10189 {
10190 wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
2f024384 10191 attr_stub->SetSize( row - j, col - i );
27f35b66
SN
10192 attr_stub->DecRef();
10193 }
10194 }
10195 }
10196 }
10197 }
10198}
10199
ab79958a
VZ
10200void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
10201{
10202 if ( CanHaveAttributes() )
10203 {
0a976765 10204 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
ab79958a
VZ
10205 attr->SetRenderer(renderer);
10206 attr->DecRef();
9b4aede2
RD
10207 }
10208}
10209
10210void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
10211{
10212 if ( CanHaveAttributes() )
10213 {
10214 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
10215 attr->SetEditor(editor);
10216 attr->DecRef();
283b7808
VZ
10217 }
10218}
10219
10220void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
10221{
10222 if ( CanHaveAttributes() )
10223 {
10224 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
10225 attr->SetReadOnly(isReadOnly);
10226 attr->DecRef();
2e9a6788 10227 }
f85afd4e
MB
10228}
10229
f2d76237
RD
10230// ----------------------------------------------------------------------------
10231// Data type registration
10232// ----------------------------------------------------------------------------
10233
10234void wxGrid::RegisterDataType(const wxString& typeName,
10235 wxGridCellRenderer* renderer,
10236 wxGridCellEditor* editor)
10237{
10238 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
10239}
10240
10241
a9339fe2 10242wxGridCellEditor * wxGrid::GetDefaultEditorForCell(int row, int col) const
f2d76237
RD
10243{
10244 wxString typeName = m_table->GetTypeName(row, col);
10245 return GetDefaultEditorForType(typeName);
10246}
10247
a9339fe2 10248wxGridCellRenderer * wxGrid::GetDefaultRendererForCell(int row, int col) const
f2d76237
RD
10249{
10250 wxString typeName = m_table->GetTypeName(row, col);
10251 return GetDefaultRendererForType(typeName);
10252}
10253
a9339fe2 10254wxGridCellEditor * wxGrid::GetDefaultEditorForType(const wxString& typeName) const
f2d76237 10255{
c4608a8a 10256 int index = m_typeRegistry->FindOrCloneDataType(typeName);
0b190b0f
VZ
10257 if ( index == wxNOT_FOUND )
10258 {
f87ab3cc 10259 wxString errStr;
4db6714b
KH
10260
10261 errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str());
10262 wxFAIL_MSG(errStr.c_str());
0b190b0f 10263
f2d76237
RD
10264 return NULL;
10265 }
0b190b0f 10266
f2d76237
RD
10267 return m_typeRegistry->GetEditor(index);
10268}
10269
a9339fe2 10270wxGridCellRenderer * wxGrid::GetDefaultRendererForType(const wxString& typeName) const
f2d76237 10271{
c4608a8a 10272 int index = m_typeRegistry->FindOrCloneDataType(typeName);
0b190b0f
VZ
10273 if ( index == wxNOT_FOUND )
10274 {
2f024384 10275 wxString errStr;
4db6714b
KH
10276
10277 errStr.Printf(wxT("Unknown data type name [%s]"), typeName.c_str());
10278 wxFAIL_MSG(errStr.c_str());
0b190b0f 10279
c4608a8a 10280 return NULL;
e72b4213 10281 }
0b190b0f 10282
c4608a8a 10283 return m_typeRegistry->GetRenderer(index);
f2d76237
RD
10284}
10285
2e9a6788
VZ
10286// ----------------------------------------------------------------------------
10287// row/col size
10288// ----------------------------------------------------------------------------
10289
6e8524b1
MB
10290void wxGrid::EnableDragRowSize( bool enable )
10291{
10292 m_canDragRowSize = enable;
10293}
10294
6e8524b1
MB
10295void wxGrid::EnableDragColSize( bool enable )
10296{
10297 m_canDragColSize = enable;
10298}
10299
4cfa5de6
RD
10300void wxGrid::EnableDragGridSize( bool enable )
10301{
10302 m_canDragGridSize = enable;
10303}
10304
79dbea21
RD
10305void wxGrid::EnableDragCell( bool enable )
10306{
10307 m_canDragCell = enable;
10308}
6e8524b1 10309
f85afd4e
MB
10310void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
10311{
b8d24d4e 10312 m_defaultRowHeight = wxMax( height, m_minAcceptableRowHeight );
f85afd4e
MB
10313
10314 if ( resizeExistingRows )
10315 {
b1da8107
SN
10316 // since we are resizing all rows to the default row size,
10317 // we can simply clear the row heights and row bottoms
10318 // arrays (which also allows us to take advantage of
10319 // some speed optimisations)
10320 m_rowHeights.Empty();
10321 m_rowBottoms.Empty();
edb89f7e
VZ
10322 if ( !GetBatchCount() )
10323 CalcDimensions();
f85afd4e
MB
10324 }
10325}
10326
10327void wxGrid::SetRowSize( int row, int height )
10328{
b99be8fb 10329 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
60ff3b99 10330
b4bfd0fa 10331 // See comment in SetColSize
4db6714b
KH
10332 if ( height < GetRowMinimalAcceptableHeight())
10333 return;
b8d24d4e 10334
7c1cb261
VZ
10335 if ( m_rowHeights.IsEmpty() )
10336 {
10337 // need to really create the array
10338 InitRowHeights();
10339 }
60ff3b99 10340
b99be8fb
VZ
10341 int h = wxMax( 0, height );
10342 int diff = h - m_rowHeights[row];
60ff3b99 10343
b99be8fb 10344 m_rowHeights[row] = h;
0ed3b812 10345 for ( int i = row; i < m_numRows; i++ )
f85afd4e 10346 {
b99be8fb 10347 m_rowBottoms[i] += diff;
f85afd4e 10348 }
2f024384 10349
faec5a43
SN
10350 if ( !GetBatchCount() )
10351 CalcDimensions();
f85afd4e
MB
10352}
10353
10354void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
10355{
ef316e23
VZ
10356 // we dont allow zero default column width
10357 m_defaultColWidth = wxMax( wxMax( width, m_minAcceptableColWidth ), 1 );
f85afd4e
MB
10358
10359 if ( resizeExistingCols )
10360 {
b1da8107
SN
10361 // since we are resizing all columns to the default column size,
10362 // we can simply clear the col widths and col rights
10363 // arrays (which also allows us to take advantage of
10364 // some speed optimisations)
10365 m_colWidths.Empty();
10366 m_colRights.Empty();
edb89f7e
VZ
10367 if ( !GetBatchCount() )
10368 CalcDimensions();
f85afd4e
MB
10369 }
10370}
10371
10372void wxGrid::SetColSize( int col, int width )
10373{
b99be8fb 10374 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
60ff3b99 10375
43947979 10376 // should we check that it's bigger than GetColMinimalWidth(col) here?
b4bfd0fa
RG
10377 // (VZ)
10378 // No, because it is reasonable to assume the library user know's
d4175745 10379 // what he is doing. However we should test against the weaker
ccdee36f 10380 // constraint of minimalAcceptableWidth, as this breaks rendering
3e13956a 10381 //
b4bfd0fa 10382 // This test then fixes sf.net bug #645734
3e13956a 10383
962a48f6 10384 if ( width < GetColMinimalAcceptableWidth() )
4db6714b 10385 return;
3e13956a 10386
7c1cb261
VZ
10387 if ( m_colWidths.IsEmpty() )
10388 {
10389 // need to really create the array
10390 InitColWidths();
10391 }
f85afd4e 10392
56b6cf26 10393 // if < 0 then calculate new width from label
4db6714b 10394 if ( width < 0 )
73145b0e 10395 {
56b6cf26
DS
10396 long w, h;
10397 wxArrayString lines;
10398 wxClientDC dc(m_colLabelWin);
10399 dc.SetFont(GetLabelFont());
10400 StringToLines(GetColLabelValue(col), lines);
10401 GetTextBoxSize(dc, lines, &w, &h);
10402 width = w + 6;
73145b0e 10403 }
962a48f6 10404
b99be8fb
VZ
10405 int w = wxMax( 0, width );
10406 int diff = w - m_colWidths[col];
10407 m_colWidths[col] = w;
60ff3b99 10408
0ed3b812 10409 for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ )
f85afd4e 10410 {
0ed3b812 10411 m_colRights[GetColAt(colPos)] += diff;
f85afd4e 10412 }
962a48f6 10413
faec5a43
SN
10414 if ( !GetBatchCount() )
10415 CalcDimensions();
f85afd4e
MB
10416}
10417
43947979
VZ
10418void wxGrid::SetColMinimalWidth( int col, int width )
10419{
4db6714b
KH
10420 if (width > GetColMinimalAcceptableWidth())
10421 {
c6fbe2f0 10422 wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)col;
8253f2e0 10423 m_colMinWidths[key] = width;
b8d24d4e 10424 }
af547d51
VZ
10425}
10426
10427void wxGrid::SetRowMinimalHeight( int row, int width )
10428{
4db6714b
KH
10429 if (width > GetRowMinimalAcceptableHeight())
10430 {
c6fbe2f0 10431 wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)row;
8253f2e0 10432 m_rowMinHeights[key] = width;
b8d24d4e 10433 }
43947979
VZ
10434}
10435
10436int wxGrid::GetColMinimalWidth(int col) const
10437{
c6fbe2f0 10438 wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)col;
8253f2e0 10439 wxLongToLongHashMap::const_iterator it = m_colMinWidths.find(key);
962a48f6 10440
ba8c1601 10441 return it != m_colMinWidths.end() ? (int)it->second : m_minAcceptableColWidth;
af547d51
VZ
10442}
10443
10444int wxGrid::GetRowMinimalHeight(int row) const
10445{
c6fbe2f0 10446 wxLongToLongHashMap::key_type key = (wxLongToLongHashMap::key_type)row;
8253f2e0 10447 wxLongToLongHashMap::const_iterator it = m_rowMinHeights.find(key);
962a48f6 10448
ba8c1601 10449 return it != m_rowMinHeights.end() ? (int)it->second : m_minAcceptableRowHeight;
b8d24d4e
RG
10450}
10451
10452void wxGrid::SetColMinimalAcceptableWidth( int width )
10453{
20c84410 10454 // We do allow a width of 0 since this gives us
962a48f6
DS
10455 // an easy way to temporarily hiding columns.
10456 if ( width >= 0 )
10457 m_minAcceptableColWidth = width;
b8d24d4e
RG
10458}
10459
10460void wxGrid::SetRowMinimalAcceptableHeight( int height )
10461{
20c84410 10462 // We do allow a height of 0 since this gives us
962a48f6
DS
10463 // an easy way to temporarily hiding rows.
10464 if ( height >= 0 )
10465 m_minAcceptableRowHeight = height;
17a1ebd1 10466}
b8d24d4e
RG
10467
10468int wxGrid::GetColMinimalAcceptableWidth() const
10469{
10470 return m_minAcceptableColWidth;
10471}
10472
10473int wxGrid::GetRowMinimalAcceptableHeight() const
10474{
10475 return m_minAcceptableRowHeight;
43947979
VZ
10476}
10477
57c086ef
VZ
10478// ----------------------------------------------------------------------------
10479// auto sizing
10480// ----------------------------------------------------------------------------
10481
af547d51 10482void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
65e4e78e
VZ
10483{
10484 wxClientDC dc(m_gridWin);
10485
962a48f6 10486 // cancel editing of cell
13f6e9e8
RG
10487 HideCellEditControl();
10488 SaveEditControlValue();
10489
962a48f6 10490 // init both of them to avoid compiler warnings, even if we only need one
a95e38c0
VZ
10491 int row = -1,
10492 col = -1;
af547d51
VZ
10493 if ( column )
10494 col = colOrRow;
10495 else
10496 row = colOrRow;
10497
10498 wxCoord extent, extentMax = 0;
10499 int max = column ? m_numRows : m_numCols;
39bcce60 10500 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
65e4e78e 10501 {
af547d51
VZ
10502 if ( column )
10503 row = rowOrCol;
10504 else
10505 col = rowOrCol;
10506
2f024384
DS
10507 wxGridCellAttr *attr = GetCellAttr(row, col);
10508 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
65e4e78e
VZ
10509 if ( renderer )
10510 {
af547d51
VZ
10511 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
10512 extent = column ? size.x : size.y;
10513 if ( extent > extentMax )
af547d51 10514 extentMax = extent;
0b190b0f
VZ
10515
10516 renderer->DecRef();
65e4e78e
VZ
10517 }
10518
10519 attr->DecRef();
10520 }
10521
af547d51
VZ
10522 // now also compare with the column label extent
10523 wxCoord w, h;
65e4e78e 10524 dc.SetFont( GetLabelFont() );
294d195c
MB
10525
10526 if ( column )
d43851f7 10527 {
9d4b8a5d 10528 dc.GetMultiLineTextExtent( GetColLabelValue(col), &w, &h );
4db6714b 10529 if ( GetColLabelTextOrientation() == wxVERTICAL )
d43851f7
JS
10530 w = h;
10531 }
294d195c 10532 else
9d4b8a5d 10533 dc.GetMultiLineTextExtent( GetRowLabelValue(row), &w, &h );
294d195c 10534
af547d51
VZ
10535 extent = column ? w : h;
10536 if ( extent > extentMax )
af547d51 10537 extentMax = extent;
65e4e78e 10538
af547d51 10539 if ( !extentMax )
65e4e78e 10540 {
af547d51 10541 // empty column - give default extent (notice that if extentMax is less
2f024384 10542 // than default extent but != 0, it's OK)
af547d51 10543 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
65e4e78e
VZ
10544 }
10545 else
10546 {
a95e38c0 10547 if ( column )
a95e38c0
VZ
10548 // leave some space around text
10549 extentMax += 10;
f6bcfd97 10550 else
f6bcfd97 10551 extentMax += 6;
65e4e78e
VZ
10552 }
10553
edb89f7e
VZ
10554 if ( column )
10555 {
962a48f6 10556 SetColSize( col, extentMax );
faec5a43
SN
10557 if ( !GetBatchCount() )
10558 {
edb89f7e
VZ
10559 int cw, ch, dummy;
10560 m_gridWin->GetClientSize( &cw, &ch );
10561 wxRect rect ( CellToRect( 0, col ) );
10562 rect.y = 0;
10563 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
10564 rect.width = cw - rect.x;
10565 rect.height = m_colLabelHeight;
ca65c044 10566 m_colLabelWin->Refresh( true, &rect );
edb89f7e
VZ
10567 }
10568 }
10569 else
10570 {
39bcce60 10571 SetRowSize(row, extentMax);
faec5a43
SN
10572 if ( !GetBatchCount() )
10573 {
edb89f7e
VZ
10574 int cw, ch, dummy;
10575 m_gridWin->GetClientSize( &cw, &ch );
ccdee36f 10576 wxRect rect( CellToRect( row, 0 ) );
edb89f7e
VZ
10577 rect.x = 0;
10578 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
10579 rect.width = m_rowLabelWidth;
faec5a43 10580 rect.height = ch - rect.y;
ca65c044 10581 m_rowLabelWin->Refresh( true, &rect );
edb89f7e 10582 }
faec5a43 10583 }
2f024384 10584
65e4e78e
VZ
10585 if ( setAsMin )
10586 {
af547d51
VZ
10587 if ( column )
10588 SetColMinimalWidth(col, extentMax);
10589 else
39bcce60 10590 SetRowMinimalHeight(row, extentMax);
65e4e78e
VZ
10591 }
10592}
10593
266e8367 10594int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
65e4e78e 10595{
57c086ef
VZ
10596 int width = m_rowLabelWidth;
10597
faec5a43
SN
10598 if ( !calcOnly )
10599 BeginBatch();
97a9929e 10600
65e4e78e
VZ
10601 for ( int col = 0; col < m_numCols; col++ )
10602 {
266e8367 10603 if ( !calcOnly )
266e8367 10604 AutoSizeColumn(col, setAsMin);
57c086ef
VZ
10605
10606 width += GetColWidth(col);
65e4e78e 10607 }
97a9929e 10608
faec5a43
SN
10609 if ( !calcOnly )
10610 EndBatch();
97a9929e 10611
266e8367 10612 return width;
65e4e78e
VZ
10613}
10614
266e8367 10615int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
57c086ef
VZ
10616{
10617 int height = m_colLabelHeight;
10618
faec5a43
SN
10619 if ( !calcOnly )
10620 BeginBatch();
97a9929e 10621
57c086ef
VZ
10622 for ( int row = 0; row < m_numRows; row++ )
10623 {
af547d51 10624 if ( !calcOnly )
af547d51 10625 AutoSizeRow(row, setAsMin);
57c086ef
VZ
10626
10627 height += GetRowHeight(row);
10628 }
97a9929e 10629
faec5a43
SN
10630 if ( !calcOnly )
10631 EndBatch();
97a9929e 10632
266e8367 10633 return height;
57c086ef
VZ
10634}
10635
10636void wxGrid::AutoSize()
10637{
97a9929e
VZ
10638 BeginBatch();
10639
0ed3b812
VZ
10640 // we need to round up the size of the scrollable area to a multiple of
10641 // scroll step to ensure that we don't get the scrollbars when we're sized
10642 // exactly to fit our contents
10643 wxSize size(SetOrCalcColumnSizes(false) - m_rowLabelWidth + m_extraWidth,
10644 SetOrCalcRowSizes(false) - m_colLabelHeight + m_extraHeight);
10645 wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(),
10646 GetScrollY(size.y) * GetScrollLineY());
97a9929e 10647
2b5f62a0 10648 // distribute the extra space between the columns/rows to avoid having
97a9929e 10649 // extra white space
0ed3b812 10650 wxCoord diff = sizeFit.x - size.x;
2b5f62a0 10651 if ( diff && m_numCols )
97a9929e
VZ
10652 {
10653 // try to resize the columns uniformly
10654 wxCoord diffPerCol = diff / m_numCols;
10655 if ( diffPerCol )
10656 {
10657 for ( int col = 0; col < m_numCols; col++ )
10658 {
10659 SetColSize(col, GetColWidth(col) + diffPerCol);
10660 }
10661 }
10662
10663 // add remaining amount to the last columns
10664 diff -= diffPerCol * m_numCols;
10665 if ( diff )
10666 {
10667 for ( int col = m_numCols - 1; col >= m_numCols - diff; col-- )
10668 {
10669 SetColSize(col, GetColWidth(col) + 1);
10670 }
10671 }
10672 }
10673
10674 // same for rows
0ed3b812 10675 diff = sizeFit.y - size.y;
2b5f62a0 10676 if ( diff && m_numRows )
97a9929e
VZ
10677 {
10678 // try to resize the columns uniformly
10679 wxCoord diffPerRow = diff / m_numRows;
10680 if ( diffPerRow )
10681 {
10682 for ( int row = 0; row < m_numRows; row++ )
10683 {
10684 SetRowSize(row, GetRowHeight(row) + diffPerRow);
10685 }
10686 }
10687
10688 // add remaining amount to the last rows
10689 diff -= diffPerRow * m_numRows;
10690 if ( diff )
10691 {
10692 for ( int row = m_numRows - 1; row >= m_numRows - diff; row-- )
10693 {
10694 SetRowSize(row, GetRowHeight(row) + 1);
10695 }
10696 }
10697 }
10698
0ed3b812
VZ
10699 // we know that we're not going to have scrollbars so disable them now to
10700 // avoid trouble in SetClientSize() which can otherwise set the correct
10701 // client size but also leave space for (not needed any more) scrollbars
39621ee0 10702 SetScrollbars(0, 0, 0, 0, 0, 0, true);
0ed3b812 10703 SetClientSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight);
97a9929e 10704
0ed3b812 10705 EndBatch();
266e8367
VZ
10706}
10707
d43851f7
JS
10708void wxGrid::AutoSizeRowLabelSize( int row )
10709{
10710 wxArrayString lines;
10711 long w, h;
10712
10713 // Hide the edit control, so it
4db6714b
KH
10714 // won't interfere with drag-shrinking.
10715 if ( IsCellEditControlShown() )
d43851f7
JS
10716 {
10717 HideCellEditControl();
10718 SaveEditControlValue();
10719 }
10720
10721 // autosize row height depending on label text
10722 StringToLines( GetRowLabelValue( row ), lines );
10723 wxClientDC dc( m_rowLabelWin );
ccdee36f 10724 GetTextBoxSize( dc, lines, &w, &h );
4db6714b 10725 if ( h < m_defaultRowHeight )
d43851f7
JS
10726 h = m_defaultRowHeight;
10727 SetRowSize(row, h);
10728 ForceRefresh();
10729}
10730
10731void wxGrid::AutoSizeColLabelSize( int col )
10732{
10733 wxArrayString lines;
10734 long w, h;
10735
10736 // Hide the edit control, so it
c2f5b920 10737 // won't interfere with drag-shrinking.
4db6714b 10738 if ( IsCellEditControlShown() )
d43851f7
JS
10739 {
10740 HideCellEditControl();
10741 SaveEditControlValue();
10742 }
10743
10744 // autosize column width depending on label text
10745 StringToLines( GetColLabelValue( col ), lines );
10746 wxClientDC dc( m_colLabelWin );
4db6714b 10747 if ( GetColLabelTextOrientation() == wxHORIZONTAL )
2f024384 10748 GetTextBoxSize( dc, lines, &w, &h );
d43851f7 10749 else
2f024384 10750 GetTextBoxSize( dc, lines, &h, &w );
4db6714b 10751 if ( w < m_defaultColWidth )
d43851f7
JS
10752 w = m_defaultColWidth;
10753 SetColSize(col, w);
10754 ForceRefresh();
10755}
10756
266e8367
VZ
10757wxSize wxGrid::DoGetBestSize() const
10758{
266e8367
VZ
10759 wxGrid *self = (wxGrid *)this; // const_cast
10760
dc4689ef
VZ
10761 // we do the same as in AutoSize() here with the exception that we don't
10762 // change the column/row sizes, only calculate them
10763 wxSize size(self->SetOrCalcColumnSizes(true) - m_rowLabelWidth + m_extraWidth,
10764 self->SetOrCalcRowSizes(true) - m_colLabelHeight + m_extraHeight);
10765 wxSize sizeFit(GetScrollX(size.x) * GetScrollLineX(),
10766 GetScrollY(size.y) * GetScrollLineY());
962a48f6 10767
6d308072
RD
10768 // NOTE: This size should be cached, but first we need to add calls to
10769 // InvalidateBestSize everywhere that could change the results of this
10770 // calculation.
10771 // CacheBestSize(size);
962a48f6 10772
dc4689ef
VZ
10773 return wxSize(sizeFit.x + m_rowLabelWidth, sizeFit.y + m_colLabelHeight)
10774 + GetWindowBorderSize();
266e8367
VZ
10775}
10776
10777void wxGrid::Fit()
10778{
10779 AutoSize();
57c086ef
VZ
10780}
10781
6fc0f38f
SN
10782wxPen& wxGrid::GetDividerPen() const
10783{
10784 return wxNullPen;
10785}
10786
57c086ef
VZ
10787// ----------------------------------------------------------------------------
10788// cell value accessor functions
10789// ----------------------------------------------------------------------------
f85afd4e
MB
10790
10791void wxGrid::SetCellValue( int row, int col, const wxString& s )
10792{
10793 if ( m_table )
10794 {
f6bcfd97 10795 m_table->SetValue( row, col, s );
2d66e025
MB
10796 if ( !GetBatchCount() )
10797 {
27f35b66
SN
10798 int dummy;
10799 wxRect rect( CellToRect( row, col ) );
10800 rect.x = 0;
10801 rect.width = m_gridWin->GetClientSize().GetWidth();
10802 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
ca65c044 10803 m_gridWin->Refresh( false, &rect );
2d66e025 10804 }
60ff3b99 10805
f85afd4e 10806 if ( m_currentCellCoords.GetRow() == row &&
4cfa5de6 10807 m_currentCellCoords.GetCol() == col &&
f6bcfd97
BP
10808 IsCellEditControlShown())
10809 // Note: If we are using IsCellEditControlEnabled,
10810 // this interacts badly with calling SetCellValue from
10811 // an EVT_GRID_CELL_CHANGE handler.
f85afd4e 10812 {
4cfa5de6
RD
10813 HideCellEditControl();
10814 ShowCellEditControl(); // will reread data from table
f85afd4e 10815 }
f85afd4e
MB
10816 }
10817}
10818
962a48f6 10819// ----------------------------------------------------------------------------
2f024384 10820// block, row and column selection
962a48f6 10821// ----------------------------------------------------------------------------
f85afd4e
MB
10822
10823void wxGrid::SelectRow( int row, bool addToSelected )
10824{
b5808881 10825 if ( IsSelection() && !addToSelected )
e32352cf 10826 ClearSelection();
70c7a608 10827
3f3dc2ef 10828 if ( m_selection )
ca65c044 10829 m_selection->SelectRow( row, false, addToSelected );
f85afd4e
MB
10830}
10831
f85afd4e
MB
10832void wxGrid::SelectCol( int col, bool addToSelected )
10833{
b5808881 10834 if ( IsSelection() && !addToSelected )
e32352cf 10835 ClearSelection();
f85afd4e 10836
3f3dc2ef 10837 if ( m_selection )
ca65c044 10838 m_selection->SelectCol( col, false, addToSelected );
f85afd4e
MB
10839}
10840
84912ef8 10841void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol,
c9097836 10842 bool addToSelected )
f85afd4e 10843{
c9097836
MB
10844 if ( IsSelection() && !addToSelected )
10845 ClearSelection();
f85afd4e 10846
3f3dc2ef
VZ
10847 if ( m_selection )
10848 m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol,
ca65c044 10849 false, addToSelected );
f85afd4e
MB
10850}
10851
10852void wxGrid::SelectAll()
10853{
f74d0b57 10854 if ( m_numRows > 0 && m_numCols > 0 )
3f3dc2ef
VZ
10855 {
10856 if ( m_selection )
ccdee36f 10857 m_selection->SelectBlock( 0, 0, m_numRows - 1, m_numCols - 1 );
3f3dc2ef 10858 }
b5808881 10859}
f85afd4e 10860
962a48f6
DS
10861// ----------------------------------------------------------------------------
10862// cell, row and col deselection
10863// ----------------------------------------------------------------------------
f7b4b343
VZ
10864
10865void wxGrid::DeselectRow( int row )
10866{
3f3dc2ef
VZ
10867 if ( !m_selection )
10868 return;
10869
f7b4b343
VZ
10870 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
10871 {
10872 if ( m_selection->IsInSelection(row, 0 ) )
2f024384 10873 m_selection->ToggleCellSelection(row, 0);
ffdd3c98 10874 }
f7b4b343
VZ
10875 else
10876 {
10877 int nCols = GetNumberCols();
2f024384 10878 for ( int i = 0; i < nCols; i++ )
f7b4b343
VZ
10879 {
10880 if ( m_selection->IsInSelection(row, i ) )
2f024384 10881 m_selection->ToggleCellSelection(row, i);
f7b4b343
VZ
10882 }
10883 }
10884}
10885
10886void wxGrid::DeselectCol( int col )
10887{
3f3dc2ef
VZ
10888 if ( !m_selection )
10889 return;
10890
f7b4b343
VZ
10891 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
10892 {
10893 if ( m_selection->IsInSelection(0, col ) )
2f024384 10894 m_selection->ToggleCellSelection(0, col);
f7b4b343
VZ
10895 }
10896 else
10897 {
10898 int nRows = GetNumberRows();
2f024384 10899 for ( int i = 0; i < nRows; i++ )
f7b4b343
VZ
10900 {
10901 if ( m_selection->IsInSelection(i, col ) )
10902 m_selection->ToggleCellSelection(i, col);
10903 }
10904 }
10905}
10906
10907void wxGrid::DeselectCell( int row, int col )
10908{
3f3dc2ef 10909 if ( m_selection && m_selection->IsInSelection(row, col) )
f7b4b343
VZ
10910 m_selection->ToggleCellSelection(row, col);
10911}
10912
ef316e23 10913bool wxGrid::IsSelection() const
b5808881 10914{
3f3dc2ef 10915 return ( m_selection && (m_selection->IsSelection() ||
b5808881 10916 ( m_selectingTopLeft != wxGridNoCellCoords &&
3f3dc2ef 10917 m_selectingBottomRight != wxGridNoCellCoords) ) );
f85afd4e
MB
10918}
10919
84035150 10920bool wxGrid::IsInSelection( int row, int col ) const
b5808881 10921{
3f3dc2ef 10922 return ( m_selection && (m_selection->IsInSelection( row, col ) ||
b5808881
SN
10923 ( row >= m_selectingTopLeft.GetRow() &&
10924 col >= m_selectingTopLeft.GetCol() &&
10925 row <= m_selectingBottomRight.GetRow() &&
3f3dc2ef 10926 col <= m_selectingBottomRight.GetCol() )) );
b5808881 10927}
f85afd4e 10928
aa5b8857
SN
10929wxGridCellCoordsArray wxGrid::GetSelectedCells() const
10930{
4db6714b
KH
10931 if (!m_selection)
10932 {
10933 wxGridCellCoordsArray a;
10934 return a;
10935 }
10936
aa5b8857
SN
10937 return m_selection->m_cellSelection;
10938}
4db6714b 10939
aa5b8857
SN
10940wxGridCellCoordsArray wxGrid::GetSelectionBlockTopLeft() const
10941{
4db6714b
KH
10942 if (!m_selection)
10943 {
10944 wxGridCellCoordsArray a;
10945 return a;
10946 }
10947
aa5b8857
SN
10948 return m_selection->m_blockSelectionTopLeft;
10949}
4db6714b 10950
aa5b8857
SN
10951wxGridCellCoordsArray wxGrid::GetSelectionBlockBottomRight() const
10952{
4db6714b
KH
10953 if (!m_selection)
10954 {
10955 wxGridCellCoordsArray a;
10956 return a;
10957 }
10958
a8de8190 10959 return m_selection->m_blockSelectionBottomRight;
aa5b8857 10960}
4db6714b 10961
aa5b8857
SN
10962wxArrayInt wxGrid::GetSelectedRows() const
10963{
4db6714b
KH
10964 if (!m_selection)
10965 {
10966 wxArrayInt a;
10967 return a;
10968 }
10969
aa5b8857
SN
10970 return m_selection->m_rowSelection;
10971}
4db6714b 10972
aa5b8857
SN
10973wxArrayInt wxGrid::GetSelectedCols() const
10974{
4db6714b
KH
10975 if (!m_selection)
10976 {
10977 wxArrayInt a;
10978 return a;
10979 }
10980
aa5b8857
SN
10981 return m_selection->m_colSelection;
10982}
10983
f85afd4e
MB
10984void wxGrid::ClearSelection()
10985{
b524b5c6
VZ
10986 m_selectingTopLeft =
10987 m_selectingBottomRight =
10988 m_selectingKeyboard = wxGridNoCellCoords;
3f3dc2ef
VZ
10989 if ( m_selection )
10990 m_selection->ClearSelection();
8f177c8e 10991}
f85afd4e 10992
da6af900 10993// This function returns the rectangle that encloses the given block
2d66e025
MB
10994// in device coords clipped to the client size of the grid window.
10995//
58dd5b3b 10996wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
ef316e23 10997 const wxGridCellCoords &bottomRight ) const
f85afd4e 10998{
58dd5b3b 10999 wxRect rect( wxGridNoCellRect );
f85afd4e
MB
11000 wxRect cellRect;
11001
58dd5b3b
MB
11002 cellRect = CellToRect( topLeft );
11003 if ( cellRect != wxGridNoCellRect )
f85afd4e 11004 {
58dd5b3b
MB
11005 rect = cellRect;
11006 }
11007 else
11008 {
962a48f6 11009 rect = wxRect(0, 0, 0, 0);
58dd5b3b 11010 }
60ff3b99 11011
58dd5b3b
MB
11012 cellRect = CellToRect( bottomRight );
11013 if ( cellRect != wxGridNoCellRect )
11014 {
11015 rect += cellRect;
2d66e025
MB
11016 }
11017 else
11018 {
11019 return wxGridNoCellRect;
f85afd4e
MB
11020 }
11021
27f35b66
SN
11022 int i, j;
11023 int left = rect.GetLeft();
11024 int top = rect.GetTop();
11025 int right = rect.GetRight();
11026 int bottom = rect.GetBottom();
11027
11028 int leftCol = topLeft.GetCol();
11029 int topRow = topLeft.GetRow();
11030 int rightCol = bottomRight.GetCol();
11031 int bottomRow = bottomRight.GetRow();
11032
3ed884a0
SN
11033 if (left > right)
11034 {
11035 i = left;
11036 left = right;
11037 right = i;
11038 i = leftCol;
4db6714b 11039 leftCol = rightCol;
3ed884a0
SN
11040 rightCol = i;
11041 }
11042
11043 if (top > bottom)
11044 {
11045 i = top;
11046 top = bottom;
11047 bottom = i;
11048 i = topRow;
11049 topRow = bottomRow;
11050 bottomRow = i;
11051 }
11052
27f35b66
SN
11053 for ( j = topRow; j <= bottomRow; j++ )
11054 {
11055 for ( i = leftCol; i <= rightCol; i++ )
11056 {
4db6714b 11057 if ((j == topRow) || (j == bottomRow) || (i == leftCol) || (i == rightCol))
27f35b66
SN
11058 {
11059 cellRect = CellToRect( j, i );
11060
11061 if (cellRect.x < left)
11062 left = cellRect.x;
11063 if (cellRect.y < top)
11064 top = cellRect.y;
11065 if (cellRect.x + cellRect.width > right)
11066 right = cellRect.x + cellRect.width;
11067 if (cellRect.y + cellRect.height > bottom)
11068 bottom = cellRect.y + cellRect.height;
11069 }
4db6714b
KH
11070 else
11071 {
11072 i = rightCol; // jump over inner cells.
11073 }
27f35b66
SN
11074 }
11075 }
11076
58dd5b3b
MB
11077 // convert to scrolled coords
11078 //
27f35b66
SN
11079 CalcScrolledPosition( left, top, &left, &top );
11080 CalcScrolledPosition( right, bottom, &right, &bottom );
58dd5b3b
MB
11081
11082 int cw, ch;
11083 m_gridWin->GetClientSize( &cw, &ch );
11084
f6bcfd97 11085 if (right < 0 || bottom < 0 || left > cw || top > ch)
c47addef 11086 return wxRect(0,0,0,0);
f6bcfd97 11087
58dd5b3b
MB
11088 rect.SetLeft( wxMax(0, left) );
11089 rect.SetTop( wxMax(0, top) );
11090 rect.SetRight( wxMin(cw, right) );
11091 rect.SetBottom( wxMin(ch, bottom) );
11092
f85afd4e
MB
11093 return rect;
11094}
11095
962a48f6
DS
11096// ----------------------------------------------------------------------------
11097// grid event classes
11098// ----------------------------------------------------------------------------
f85afd4e 11099
bf7945ce 11100IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxNotifyEvent )
f85afd4e
MB
11101
11102wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5c8fc7c1 11103 int row, int col, int x, int y, bool sel,
f85afd4e
MB
11104 bool control, bool shift, bool alt, bool meta )
11105 : wxNotifyEvent( type, id )
11106{
11107 m_row = row;
11108 m_col = col;
11109 m_x = x;
11110 m_y = y;
5c8fc7c1 11111 m_selecting = sel;
f85afd4e
MB
11112 m_control = control;
11113 m_shift = shift;
11114 m_alt = alt;
11115 m_meta = meta;
8f177c8e 11116
f85afd4e
MB
11117 SetEventObject(obj);
11118}
11119
11120
bf7945ce 11121IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxNotifyEvent )
f85afd4e
MB
11122
11123wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
11124 int rowOrCol, int x, int y,
11125 bool control, bool shift, bool alt, bool meta )
11126 : wxNotifyEvent( type, id )
11127{
11128 m_rowOrCol = rowOrCol;
11129 m_x = x;
11130 m_y = y;
11131 m_control = control;
11132 m_shift = shift;
11133 m_alt = alt;
11134 m_meta = meta;
8f177c8e 11135
f85afd4e
MB
11136 SetEventObject(obj);
11137}
11138
11139
bf7945ce 11140IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxNotifyEvent )
f85afd4e
MB
11141
11142wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8f177c8e
VZ
11143 const wxGridCellCoords& topLeft,
11144 const wxGridCellCoords& bottomRight,
5c8fc7c1
SN
11145 bool sel, bool control,
11146 bool shift, bool alt, bool meta )
8f177c8e 11147 : wxNotifyEvent( type, id )
f85afd4e 11148{
2f024384 11149 m_topLeft = topLeft;
f85afd4e 11150 m_bottomRight = bottomRight;
2f024384
DS
11151 m_selecting = sel;
11152 m_control = control;
11153 m_shift = shift;
11154 m_alt = alt;
11155 m_meta = meta;
f85afd4e
MB
11156
11157 SetEventObject(obj);
11158}
11159
11160
bf7945ce
RD
11161IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent, wxCommandEvent)
11162
11163wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id, wxEventType type,
11164 wxObject* obj, int row,
11165 int col, wxControl* ctrl)
11166 : wxCommandEvent(type, id)
11167{
11168 SetEventObject(obj);
11169 m_row = row;
11170 m_col = col;
11171 m_ctrl = ctrl;
11172}
11173
27b92ca4 11174#endif // wxUSE_GRID