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