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