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