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