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