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