]> git.saurik.com Git - wxWidgets.git/blame - src/generic/grid.cpp
conditional compilation for Universal Interfaces (3.4 or later)
[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;
d2520c85
RD
3601 m_cellHighlightPenWidth = 3;
3602 m_cellHighlightROPenWidth = 1;
8f177c8e 3603
58dd5b3b 3604 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
e2b42eeb 3605 m_winCapture = (wxWindow *)NULL;
6e8524b1
MB
3606 m_canDragRowSize = TRUE;
3607 m_canDragColSize = TRUE;
4cfa5de6 3608 m_canDragGridSize = TRUE;
f85afd4e
MB
3609 m_dragLastPos = -1;
3610 m_dragRowOrCol = -1;
3611 m_isDragging = FALSE;
07296f0b 3612 m_startDragPos = wxDefaultPosition;
f85afd4e 3613
07296f0b 3614 m_waitForSlowClick = FALSE;
025562fe 3615
f85afd4e
MB
3616 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
3617 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
3618
3619 m_currentCellCoords = wxGridNoCellCoords;
f85afd4e 3620
b5808881
SN
3621 m_selectingTopLeft = wxGridNoCellCoords;
3622 m_selectingBottomRight = wxGridNoCellCoords;
2796cce3
RD
3623 m_selectionBackground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT);
3624 m_selectionForeground = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
8f177c8e 3625
f85afd4e
MB
3626 m_editable = TRUE; // default for whole grid
3627
2d66e025
MB
3628 m_inOnKeyDown = FALSE;
3629 m_batchCount = 0;
3c79cf49 3630
266e8367
VZ
3631 m_extraWidth =
3632 m_extraHeight = 50;
3633
3c79cf49 3634 CalcDimensions();
7c1cb261
VZ
3635}
3636
3637// ----------------------------------------------------------------------------
3638// the idea is to call these functions only when necessary because they create
3639// quite big arrays which eat memory mostly unnecessary - in particular, if
3640// default widths/heights are used for all rows/columns, we may not use these
3641// arrays at all
3642//
3643// with some extra code, it should be possible to only store the
3644// widths/heights different from default ones but this will be done later...
3645// ----------------------------------------------------------------------------
3646
3647void wxGrid::InitRowHeights()
3648{
3649 m_rowHeights.Empty();
3650 m_rowBottoms.Empty();
3651
3652 m_rowHeights.Alloc( m_numRows );
3653 m_rowBottoms.Alloc( m_numRows );
3654
3655 int rowBottom = 0;
3656 for ( int i = 0; i < m_numRows; i++ )
3657 {
3658 m_rowHeights.Add( m_defaultRowHeight );
3659 rowBottom += m_defaultRowHeight;
3660 m_rowBottoms.Add( rowBottom );
3661 }
3662}
3663
3664void wxGrid::InitColWidths()
3665{
3666 m_colWidths.Empty();
3667 m_colRights.Empty();
3668
3669 m_colWidths.Alloc( m_numCols );
3670 m_colRights.Alloc( m_numCols );
3671 int colRight = 0;
3672 for ( int i = 0; i < m_numCols; i++ )
3673 {
3674 m_colWidths.Add( m_defaultColWidth );
3675 colRight += m_defaultColWidth;
3676 m_colRights.Add( colRight );
3677 }
3678}
3679
3680int wxGrid::GetColWidth(int col) const
3681{
3682 return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
3683}
3684
3685int wxGrid::GetColLeft(int col) const
3686{
3687 return m_colRights.IsEmpty() ? col * m_defaultColWidth
3688 : m_colRights[col] - m_colWidths[col];
3689}
3690
3691int wxGrid::GetColRight(int col) const
3692{
3693 return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth
3694 : m_colRights[col];
3695}
3696
3697int wxGrid::GetRowHeight(int row) const
3698{
3699 return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
3700}
2d66e025 3701
7c1cb261
VZ
3702int wxGrid::GetRowTop(int row) const
3703{
3704 return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
3705 : m_rowBottoms[row] - m_rowHeights[row];
f85afd4e
MB
3706}
3707
7c1cb261
VZ
3708int wxGrid::GetRowBottom(int row) const
3709{
3710 return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
3711 : m_rowBottoms[row];
3712}
f85afd4e
MB
3713
3714void wxGrid::CalcDimensions()
3715{
f85afd4e 3716 int cw, ch;
2d66e025 3717 GetClientSize( &cw, &ch );
f85afd4e 3718
faec5a43
SN
3719 if ( m_colLabelWin->IsShown() )
3720 cw -= m_rowLabelWidth;
3721 if ( m_rowLabelWin->IsShown() )
3722 ch -= m_colLabelHeight;
60ff3b99 3723
faec5a43
SN
3724 // grid total size
3725 int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0;
3726 int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0;
3727
3728 // preserve (more or less) the previous position
3729 int x, y;
3730 GetViewStart( &x, &y );
3731 // maybe we don't need scrollbars at all? and if we do, transform w and h
3732 // from pixels into logical units
3733 if ( w <= cw )
3734 {
3735 w = 0; x= 0;
3736 }
3737 else
3738 {
3739 w = (w + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE;
3740 if ( x >= w )
3741 x = w - 1;
f85afd4e 3742 }
faec5a43
SN
3743 if ( h <= ch )
3744 {
3745 h = 0; y = 0;
3746 }
3747 else
3748 {
3749 h = (h + GRID_SCROLL_LINE - 1)/GRID_SCROLL_LINE;
3750 if ( y >= h )
3751 y = h - 1;
3752 }
3753
3754 // do set scrollbar parameters
3755 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
389b961e 3756 w, h, x, y, (GetBatchCount() != 0));
f85afd4e
MB
3757}
3758
3759
7807d81c
MB
3760void wxGrid::CalcWindowSizes()
3761{
3762 int cw, ch;
3763 GetClientSize( &cw, &ch );
b99be8fb 3764
7807d81c
MB
3765 if ( m_cornerLabelWin->IsShown() )
3766 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
3767
3768 if ( m_colLabelWin->IsShown() )
3769 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
3770
3771 if ( m_rowLabelWin->IsShown() )
3772 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
3773
3774 if ( m_gridWin->IsShown() )
3775 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
3776}
3777
3778
f85afd4e
MB
3779// this is called when the grid table sends a message to say that it
3780// has been redimensioned
3781//
3782bool wxGrid::Redimension( wxGridTableMessage& msg )
3783{
3784 int i;
f6bcfd97 3785 bool result = FALSE;
8f177c8e 3786
f6bcfd97 3787#if 0
7c1cb261
VZ
3788 // if we were using the default widths/heights so far, we must change them
3789 // now
3790 if ( m_colWidths.IsEmpty() )
3791 {
3792 InitColWidths();
3793 }
3794
3795 if ( m_rowHeights.IsEmpty() )
3796 {
3797 InitRowHeights();
3798 }
f6bcfd97 3799#endif
7c1cb261 3800
f85afd4e
MB
3801 switch ( msg.GetId() )
3802 {
3803 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
3804 {
3805 size_t pos = msg.GetCommandInt();
3806 int numRows = msg.GetCommandInt2();
f6bcfd97 3807
f85afd4e 3808 m_numRows += numRows;
2d66e025 3809
f6bcfd97
BP
3810 if ( !m_rowHeights.IsEmpty() )
3811 {
3812 for ( i = 0; i < numRows; i++ )
3813 {
3814 m_rowHeights.Insert( m_defaultRowHeight, pos );
3815 m_rowBottoms.Insert( 0, pos );
3816 }
3817
3818 int bottom = 0;
3819 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
60ff3b99 3820
f6bcfd97
BP
3821 for ( i = pos; i < m_numRows; i++ )
3822 {
3823 bottom += m_rowHeights[i];
3824 m_rowBottoms[i] = bottom;
3825 }
3826 }
3827 if ( m_currentCellCoords == wxGridNoCellCoords )
3828 {
3829 // if we have just inserted cols into an empty grid the current
3830 // cell will be undefined...
3831 //
3832 SetCurrentCell( 0, 0 );
3833 }
3834 m_selection->UpdateRows( pos, numRows );
3835 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3836 if (attrProvider)
3837 attrProvider->UpdateAttrRows( pos, numRows );
3838
3839 if ( !GetBatchCount() )
2d66e025 3840 {
f6bcfd97
BP
3841 CalcDimensions();
3842 m_rowLabelWin->Refresh();
2d66e025 3843 }
f85afd4e 3844 }
f6bcfd97
BP
3845 result = TRUE;
3846 break;
f85afd4e
MB
3847
3848 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
3849 {
3850 int numRows = msg.GetCommandInt();
2d66e025 3851 int oldNumRows = m_numRows;
f85afd4e 3852 m_numRows += numRows;
2d66e025 3853
f6bcfd97
BP
3854 if ( !m_rowHeights.IsEmpty() )
3855 {
3856 for ( i = 0; i < numRows; i++ )
3857 {
3858 m_rowHeights.Add( m_defaultRowHeight );
3859 m_rowBottoms.Add( 0 );
3860 }
60ff3b99 3861
f6bcfd97
BP
3862 int bottom = 0;
3863 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
3864
3865 for ( i = oldNumRows; i < m_numRows; i++ )
3866 {
3867 bottom += m_rowHeights[i];
3868 m_rowBottoms[i] = bottom;
3869 }
3870 }
3871 if ( m_currentCellCoords == wxGridNoCellCoords )
3872 {
3873 // if we have just inserted cols into an empty grid the current
3874 // cell will be undefined...
3875 //
3876 SetCurrentCell( 0, 0 );
3877 }
3878 if ( !GetBatchCount() )
2d66e025 3879 {
f6bcfd97
BP
3880 CalcDimensions();
3881 m_rowLabelWin->Refresh();
2d66e025 3882 }
f85afd4e 3883 }
f6bcfd97
BP
3884 result = TRUE;
3885 break;
f85afd4e
MB
3886
3887 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
3888 {
3889 size_t pos = msg.GetCommandInt();
3890 int numRows = msg.GetCommandInt2();
f85afd4e
MB
3891 m_numRows -= numRows;
3892
f6bcfd97 3893 if ( !m_rowHeights.IsEmpty() )
f85afd4e 3894 {
f6bcfd97
BP
3895 for ( i = 0; i < numRows; i++ )
3896 {
3897 m_rowHeights.Remove( pos );
3898 m_rowBottoms.Remove( pos );
3899 }
2d66e025
MB
3900
3901 int h = 0;
3902 for ( i = 0; i < m_numRows; i++ )
3903 {
3904 h += m_rowHeights[i];
3905 m_rowBottoms[i] = h;
3906 }
f85afd4e 3907 }
f6bcfd97
BP
3908 if ( !m_numRows )
3909 {
3910 m_currentCellCoords = wxGridNoCellCoords;
3911 }
3912 else
3913 {
3914 if ( m_currentCellCoords.GetRow() >= m_numRows )
3915 m_currentCellCoords.Set( 0, 0 );
3916 }
3917 m_selection->UpdateRows( pos, -((int)numRows) );
3918 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3919 if (attrProvider) {
3920 attrProvider->UpdateAttrRows( pos, -((int)numRows) );
84912ef8
RD
3921// ifdef'd out following patch from Paul Gammans
3922#if 0
3ca6a5f0 3923 // No need to touch column attributes, unless we
f6bcfd97
BP
3924 // removed _all_ rows, in this case, we remove
3925 // all column attributes.
3926 // I hate to do this here, but the
3927 // needed data is not available inside UpdateAttrRows.
3928 if ( !GetNumberRows() )
3929 attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
84912ef8 3930#endif
f6bcfd97
BP
3931 }
3932 if ( !GetBatchCount() )
3933 {
3934 CalcDimensions();
3935 m_rowLabelWin->Refresh();
3936 }
f85afd4e 3937 }
f6bcfd97
BP
3938 result = TRUE;
3939 break;
f85afd4e
MB
3940
3941 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
3942 {
3943 size_t pos = msg.GetCommandInt();
3944 int numCols = msg.GetCommandInt2();
f85afd4e 3945 m_numCols += numCols;
2d66e025 3946
f6bcfd97
BP
3947 if ( !m_colWidths.IsEmpty() )
3948 {
3949 for ( i = 0; i < numCols; i++ )
3950 {
3951 m_colWidths.Insert( m_defaultColWidth, pos );
3952 m_colRights.Insert( 0, pos );
3953 }
3954
3955 int right = 0;
3956 if ( pos > 0 ) right = m_colRights[pos-1];
60ff3b99 3957
f6bcfd97
BP
3958 for ( i = pos; i < m_numCols; i++ )
3959 {
3960 right += m_colWidths[i];
3961 m_colRights[i] = right;
3962 }
3963 }
3964 if ( m_currentCellCoords == wxGridNoCellCoords )
2d66e025 3965 {
f6bcfd97
BP
3966 // if we have just inserted cols into an empty grid the current
3967 // cell will be undefined...
3968 //
3969 SetCurrentCell( 0, 0 );
2d66e025 3970 }
f6bcfd97
BP
3971 m_selection->UpdateCols( pos, numCols );
3972 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
3973 if (attrProvider)
3974 attrProvider->UpdateAttrCols( pos, numCols );
3975 if ( !GetBatchCount() )
3976 {
3977 CalcDimensions();
3978 m_colLabelWin->Refresh();
3979 }
3980
f85afd4e 3981 }
f6bcfd97
BP
3982 result = TRUE;
3983 break;
f85afd4e
MB
3984
3985 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
3986 {
3987 int numCols = msg.GetCommandInt();
2d66e025 3988 int oldNumCols = m_numCols;
f85afd4e 3989 m_numCols += numCols;
f6bcfd97
BP
3990 if ( !m_colWidths.IsEmpty() )
3991 {
3992 for ( i = 0; i < numCols; i++ )
3993 {
3994 m_colWidths.Add( m_defaultColWidth );
3995 m_colRights.Add( 0 );
3996 }
2d66e025 3997
f6bcfd97
BP
3998 int right = 0;
3999 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
60ff3b99 4000
f6bcfd97
BP
4001 for ( i = oldNumCols; i < m_numCols; i++ )
4002 {
4003 right += m_colWidths[i];
4004 m_colRights[i] = right;
4005 }
4006 }
4007 if ( m_currentCellCoords == wxGridNoCellCoords )
2d66e025 4008 {
f6bcfd97
BP
4009 // if we have just inserted cols into an empty grid the current
4010 // cell will be undefined...
4011 //
4012 SetCurrentCell( 0, 0 );
4013 }
4014 if ( !GetBatchCount() )
4015 {
4016 CalcDimensions();
4017 m_colLabelWin->Refresh();
2d66e025 4018 }
f85afd4e 4019 }
f6bcfd97
BP
4020 result = TRUE;
4021 break;
f85afd4e
MB
4022
4023 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
4024 {
4025 size_t pos = msg.GetCommandInt();
4026 int numCols = msg.GetCommandInt2();
f85afd4e 4027 m_numCols -= numCols;
f85afd4e 4028
f6bcfd97 4029 if ( !m_colWidths.IsEmpty() )
f85afd4e 4030 {
f6bcfd97
BP
4031 for ( i = 0; i < numCols; i++ )
4032 {
4033 m_colWidths.Remove( pos );
4034 m_colRights.Remove( pos );
4035 }
2d66e025
MB
4036
4037 int w = 0;
4038 for ( i = 0; i < m_numCols; i++ )
4039 {
4040 w += m_colWidths[i];
4041 m_colRights[i] = w;
4042 }
f85afd4e 4043 }
f6bcfd97
BP
4044 if ( !m_numCols )
4045 {
4046 m_currentCellCoords = wxGridNoCellCoords;
4047 }
4048 else
4049 {
4050 if ( m_currentCellCoords.GetCol() >= m_numCols )
4051 m_currentCellCoords.Set( 0, 0 );
4052 }
4053 m_selection->UpdateCols( pos, -((int)numCols) );
4054 wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
4055 if (attrProvider) {
4056 attrProvider->UpdateAttrCols( pos, -((int)numCols) );
84912ef8
RD
4057// ifdef'd out following patch from Paul Gammans
4058#if 0
f6bcfd97
BP
4059 // No need to touch row attributes, unless we
4060 // removed _all_ columns, in this case, we remove
4061 // all row attributes.
4062 // I hate to do this here, but the
4063 // needed data is not available inside UpdateAttrCols.
4064 if ( !GetNumberCols() )
4065 attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
84912ef8 4066#endif
f6bcfd97
BP
4067 }
4068 if ( !GetBatchCount() )
4069 {
4070 CalcDimensions();
4071 m_colLabelWin->Refresh();
4072 }
f85afd4e 4073 }
faec5a43 4074 result = TRUE;
f6bcfd97 4075 break;
f85afd4e
MB
4076 }
4077
f6bcfd97
BP
4078 if (result && !GetBatchCount() )
4079 m_gridWin->Refresh();
4080 return result;
f85afd4e
MB
4081}
4082
4083
f6bcfd97 4084void wxGrid::CalcRowLabelsExposed( const wxRegion& reg )
f85afd4e 4085{
2d66e025
MB
4086 wxRegionIterator iter( reg );
4087 wxRect r;
f85afd4e 4088
2d66e025 4089 m_rowLabelsExposed.Empty();
f85afd4e 4090
2d66e025
MB
4091 int top, bottom;
4092 while ( iter )
f85afd4e 4093 {
2d66e025 4094 r = iter.GetRect();
f85afd4e 4095
2d66e025
MB
4096 // TODO: remove this when we can...
4097 // There is a bug in wxMotif that gives garbage update
4098 // rectangles if you jump-scroll a long way by clicking the
4099 // scrollbar with middle button. This is a work-around
4100 //
4101#if defined(__WXMOTIF__)
4102 int cw, ch;
4103 m_gridWin->GetClientSize( &cw, &ch );
4104 if ( r.GetTop() > ch ) r.SetTop( 0 );
4105 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4106#endif
f85afd4e 4107
2d66e025
MB
4108 // logical bounds of update region
4109 //
4110 int dummy;
4111 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
4112 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
4113
4114 // find the row labels within these bounds
4115 //
4116 int row;
2d66e025
MB
4117 for ( row = 0; row < m_numRows; row++ )
4118 {
7c1cb261
VZ
4119 if ( GetRowBottom(row) < top )
4120 continue;
2d66e025 4121
6d55126d 4122 if ( GetRowTop(row) > bottom )
7c1cb261 4123 break;
60ff3b99 4124
2d66e025
MB
4125 m_rowLabelsExposed.Add( row );
4126 }
60ff3b99 4127
2d66e025 4128 iter++ ;
f85afd4e
MB
4129 }
4130}
4131
4132
f6bcfd97 4133void wxGrid::CalcColLabelsExposed( const wxRegion& reg )
f85afd4e 4134{
2d66e025
MB
4135 wxRegionIterator iter( reg );
4136 wxRect r;
f85afd4e 4137
2d66e025 4138 m_colLabelsExposed.Empty();
f85afd4e 4139
2d66e025
MB
4140 int left, right;
4141 while ( iter )
f85afd4e 4142 {
2d66e025 4143 r = iter.GetRect();
f85afd4e 4144
2d66e025
MB
4145 // TODO: remove this when we can...
4146 // There is a bug in wxMotif that gives garbage update
4147 // rectangles if you jump-scroll a long way by clicking the
4148 // scrollbar with middle button. This is a work-around
4149 //
4150#if defined(__WXMOTIF__)
4151 int cw, ch;
4152 m_gridWin->GetClientSize( &cw, &ch );
4153 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4154 r.SetRight( wxMin( r.GetRight(), cw ) );
4155#endif
4156
4157 // logical bounds of update region
4158 //
4159 int dummy;
4160 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
4161 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
4162
4163 // find the cells within these bounds
4164 //
4165 int col;
2d66e025
MB
4166 for ( col = 0; col < m_numCols; col++ )
4167 {
7c1cb261
VZ
4168 if ( GetColRight(col) < left )
4169 continue;
60ff3b99 4170
7c1cb261
VZ
4171 if ( GetColLeft(col) > right )
4172 break;
2d66e025
MB
4173
4174 m_colLabelsExposed.Add( col );
4175 }
60ff3b99 4176
2d66e025 4177 iter++ ;
f85afd4e
MB
4178 }
4179}
4180
4181
f6bcfd97 4182void wxGrid::CalcCellsExposed( const wxRegion& reg )
f85afd4e 4183{
2d66e025
MB
4184 wxRegionIterator iter( reg );
4185 wxRect r;
f85afd4e 4186
2d66e025
MB
4187 m_cellsExposed.Empty();
4188 m_rowsExposed.Empty();
4189 m_colsExposed.Empty();
f85afd4e 4190
2d66e025
MB
4191 int left, top, right, bottom;
4192 while ( iter )
4193 {
4194 r = iter.GetRect();
f85afd4e 4195
2d66e025
MB
4196 // TODO: remove this when we can...
4197 // There is a bug in wxMotif that gives garbage update
4198 // rectangles if you jump-scroll a long way by clicking the
4199 // scrollbar with middle button. This is a work-around
4200 //
4201#if defined(__WXMOTIF__)
f85afd4e 4202 int cw, ch;
2d66e025
MB
4203 m_gridWin->GetClientSize( &cw, &ch );
4204 if ( r.GetTop() > ch ) r.SetTop( 0 );
4205 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
4206 r.SetRight( wxMin( r.GetRight(), cw ) );
4207 r.SetBottom( wxMin( r.GetBottom(), ch ) );
4208#endif
8f177c8e 4209
2d66e025
MB
4210 // logical bounds of update region
4211 //
4212 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
4213 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
f85afd4e 4214
2d66e025 4215 // find the cells within these bounds
f85afd4e 4216 //
2d66e025 4217 int row, col;
2d66e025 4218 for ( row = 0; row < m_numRows; row++ )
f85afd4e 4219 {
7c1cb261
VZ
4220 if ( GetRowBottom(row) <= top )
4221 continue;
f85afd4e 4222
7c1cb261
VZ
4223 if ( GetRowTop(row) > bottom )
4224 break;
60ff3b99 4225
2d66e025 4226 m_rowsExposed.Add( row );
f85afd4e 4227
2d66e025
MB
4228 for ( col = 0; col < m_numCols; col++ )
4229 {
7c1cb261
VZ
4230 if ( GetColRight(col) <= left )
4231 continue;
60ff3b99 4232
7c1cb261
VZ
4233 if ( GetColLeft(col) > right )
4234 break;
60ff3b99 4235
7c1cb261
VZ
4236 if ( m_colsExposed.Index( col ) == wxNOT_FOUND )
4237 m_colsExposed.Add( col );
2d66e025
MB
4238 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
4239 }
4240 }
60ff3b99 4241
7c1cb261 4242 iter++;
f85afd4e
MB
4243 }
4244}
4245
4246
2d66e025 4247void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
f85afd4e 4248{
2d66e025
MB
4249 int x, y, row;
4250 wxPoint pos( event.GetPosition() );
4251 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 4252
2d66e025 4253 if ( event.Dragging() )
f85afd4e
MB
4254 {
4255 m_isDragging = TRUE;
8f177c8e 4256
2d66e025 4257 if ( event.LeftIsDown() )
f85afd4e
MB
4258 {
4259 switch( m_cursorMode )
4260 {
f85afd4e
MB
4261 case WXGRID_CURSOR_RESIZE_ROW:
4262 {
2d66e025
MB
4263 int cw, ch, left, dummy;
4264 m_gridWin->GetClientSize( &cw, &ch );
4265 CalcUnscrolledPosition( 0, 0, &left, &dummy );
60ff3b99 4266
2d66e025
MB
4267 wxClientDC dc( m_gridWin );
4268 PrepareDC( dc );
af547d51
VZ
4269 y = wxMax( y,
4270 GetRowTop(m_dragRowOrCol) +
4271 GetRowMinimalHeight(m_dragRowOrCol) );
d2fdd8d2 4272 dc.SetLogicalFunction(wxINVERT);
f85afd4e
MB
4273 if ( m_dragLastPos >= 0 )
4274 {
2d66e025 4275 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
f85afd4e 4276 }
2d66e025
MB
4277 dc.DrawLine( left, y, left+cw, y );
4278 m_dragLastPos = y;
f85afd4e
MB
4279 }
4280 break;
4281
4282 case WXGRID_CURSOR_SELECT_ROW:
e32352cf 4283 if ( (row = YToRow( y )) >= 0 )
aa5e1f75
SN
4284 {
4285 m_selection->SelectRow( row,
4286 event.ControlDown(),
4287 event.ShiftDown(),
4288 event.AltDown(),
4289 event.MetaDown() );
f85afd4e 4290 }
e2b42eeb
VZ
4291
4292 // default label to suppress warnings about "enumeration value
4293 // 'xxx' not handled in switch
4294 default:
4295 break;
f85afd4e
MB
4296 }
4297 }
4298 return;
4299 }
4300
4301 m_isDragging = FALSE;
8f177c8e 4302
60ff3b99 4303
6d004f67
MB
4304 // ------------ Entering or leaving the window
4305 //
4306 if ( event.Entering() || event.Leaving() )
4307 {
e2b42eeb 4308 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
6d004f67
MB
4309 }
4310
e2b42eeb 4311
2d66e025 4312 // ------------ Left button pressed
f85afd4e 4313 //
6d004f67 4314 else if ( event.LeftDown() )
f85afd4e 4315 {
2d66e025
MB
4316 // don't send a label click event for a hit on the
4317 // edge of the row label - this is probably the user
4318 // wanting to resize the row
4319 //
4320 if ( YToEdgeOfRow(y) < 0 )
f85afd4e 4321 {
2d66e025 4322 row = YToRow(y);
58dd5b3b 4323 if ( row >= 0 &&
b54ba671 4324 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
f85afd4e 4325 {
aa5e1f75
SN
4326 if ( !event.ShiftDown() && !event.ControlDown() )
4327 ClearSelection();
4328 if ( event.ShiftDown() )
4329 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4330 0,
4331 row,
4332 GetNumberCols() - 1,
4333 event.ControlDown(),
4334 event.ShiftDown(),
4335 event.AltDown(),
4336 event.MetaDown() );
4337 else
4338 m_selection->SelectRow( row,
4339 event.ControlDown(),
4340 event.ShiftDown(),
4341 event.AltDown(),
4342 event.MetaDown() );
e2b42eeb 4343 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
f85afd4e 4344 }
2d66e025
MB
4345 }
4346 else
4347 {
4348 // starting to drag-resize a row
4349 //
6e8524b1
MB
4350 if ( CanDragRowSize() )
4351 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
2d66e025
MB
4352 }
4353 }
f85afd4e 4354
f85afd4e 4355
2d66e025
MB
4356 // ------------ Left double click
4357 //
4358 else if (event.LeftDClick() )
4359 {
4360 if ( YToEdgeOfRow(y) < 0 )
4361 {
4362 row = YToRow(y);
b54ba671 4363 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
f85afd4e
MB
4364 }
4365 }
60ff3b99
VZ
4366
4367
2d66e025 4368 // ------------ Left button released
f85afd4e 4369 //
2d66e025 4370 else if ( event.LeftUp() )
f85afd4e 4371 {
2d66e025 4372 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
f85afd4e 4373 {
6d004f67 4374 DoEndDragResizeRow();
60ff3b99 4375
6d004f67
MB
4376 // Note: we are ending the event *after* doing
4377 // default processing in this case
4378 //
b54ba671 4379 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2d66e025 4380 }
f85afd4e 4381
e2b42eeb
VZ
4382 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
4383 m_dragLastPos = -1;
2d66e025 4384 }
f85afd4e 4385
f85afd4e 4386
2d66e025
MB
4387 // ------------ Right button down
4388 //
4389 else if ( event.RightDown() )
4390 {
4391 row = YToRow(y);
b54ba671 4392 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
2d66e025
MB
4393 {
4394 // no default action at the moment
f85afd4e
MB
4395 }
4396 }
60ff3b99
VZ
4397
4398
2d66e025 4399 // ------------ Right double click
f85afd4e 4400 //
2d66e025
MB
4401 else if ( event.RightDClick() )
4402 {
4403 row = YToRow(y);
b54ba671 4404 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
2d66e025
MB
4405 {
4406 // no default action at the moment
4407 }
4408 }
60ff3b99
VZ
4409
4410
2d66e025 4411 // ------------ No buttons down and mouse moving
f85afd4e 4412 //
2d66e025 4413 else if ( event.Moving() )
f85afd4e 4414 {
2d66e025
MB
4415 m_dragRowOrCol = YToEdgeOfRow( y );
4416 if ( m_dragRowOrCol >= 0 )
8f177c8e 4417 {
2d66e025 4418 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
8f177c8e 4419 {
e2b42eeb 4420 // don't capture the mouse yet
6e8524b1
MB
4421 if ( CanDragRowSize() )
4422 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
8f177c8e 4423 }
2d66e025 4424 }
6d004f67 4425 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2d66e025 4426 {
e2b42eeb 4427 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
8f177c8e 4428 }
f85afd4e 4429 }
2d66e025
MB
4430}
4431
4432
4433void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
4434{
4435 int x, y, col;
4436 wxPoint pos( event.GetPosition() );
4437 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 4438
2d66e025 4439 if ( event.Dragging() )
f85afd4e 4440 {
2d66e025 4441 m_isDragging = TRUE;
8f177c8e 4442
2d66e025 4443 if ( event.LeftIsDown() )
8f177c8e 4444 {
2d66e025 4445 switch( m_cursorMode )
8f177c8e 4446 {
2d66e025 4447 case WXGRID_CURSOR_RESIZE_COL:
8f177c8e 4448 {
2d66e025
MB
4449 int cw, ch, dummy, top;
4450 m_gridWin->GetClientSize( &cw, &ch );
4451 CalcUnscrolledPosition( 0, 0, &dummy, &top );
60ff3b99 4452
2d66e025
MB
4453 wxClientDC dc( m_gridWin );
4454 PrepareDC( dc );
43947979
VZ
4455
4456 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4457 GetColMinimalWidth(m_dragRowOrCol));
d2fdd8d2 4458 dc.SetLogicalFunction(wxINVERT);
2d66e025
MB
4459 if ( m_dragLastPos >= 0 )
4460 {
4461 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4462 }
4463 dc.DrawLine( x, top, x, top+ch );
4464 m_dragLastPos = x;
f85afd4e 4465 }
2d66e025 4466 break;
f85afd4e 4467
2d66e025 4468 case WXGRID_CURSOR_SELECT_COL:
e32352cf 4469 if ( (col = XToCol( x )) >= 0 )
aa5e1f75
SN
4470 {
4471 m_selection->SelectCol( col,
4472 event.ControlDown(),
4473 event.ShiftDown(),
4474 event.AltDown(),
4475 event.MetaDown() );
2d66e025 4476 }
e2b42eeb
VZ
4477
4478 // default label to suppress warnings about "enumeration value
4479 // 'xxx' not handled in switch
4480 default:
4481 break;
2d66e025 4482 }
f85afd4e 4483 }
2d66e025 4484 return;
f85afd4e 4485 }
2d66e025
MB
4486
4487 m_isDragging = FALSE;
4488
60ff3b99 4489
6d004f67
MB
4490 // ------------ Entering or leaving the window
4491 //
4492 if ( event.Entering() || event.Leaving() )
4493 {
e2b42eeb 4494 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
6d004f67
MB
4495 }
4496
e2b42eeb 4497
2d66e025 4498 // ------------ Left button pressed
f85afd4e 4499 //
6d004f67 4500 else if ( event.LeftDown() )
f85afd4e 4501 {
2d66e025
MB
4502 // don't send a label click event for a hit on the
4503 // edge of the col label - this is probably the user
4504 // wanting to resize the col
4505 //
4506 if ( XToEdgeOfCol(x) < 0 )
8f177c8e 4507 {
2d66e025 4508 col = XToCol(x);
58dd5b3b 4509 if ( col >= 0 &&
b54ba671 4510 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
8f177c8e 4511 {
aa5e1f75
SN
4512 if ( !event.ShiftDown() && !event.ControlDown() )
4513 ClearSelection();
4514 if ( event.ShiftDown() )
4515 m_selection->SelectBlock( 0,
4516 m_currentCellCoords.GetCol(),
4517 GetNumberRows() - 1, col,
4518 event.ControlDown(),
4519 event.ShiftDown(),
4520 event.AltDown(),
4521 event.MetaDown() );
4522 else
4523 m_selection->SelectCol( col,
4524 event.ControlDown(),
4525 event.ShiftDown(),
4526 event.AltDown(),
4527 event.MetaDown() );
e2b42eeb 4528 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
f85afd4e 4529 }
2d66e025
MB
4530 }
4531 else
4532 {
4533 // starting to drag-resize a col
4534 //
6e8524b1
MB
4535 if ( CanDragColSize() )
4536 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
2d66e025
MB
4537 }
4538 }
f85afd4e 4539
f85afd4e 4540
2d66e025
MB
4541 // ------------ Left double click
4542 //
4543 if ( event.LeftDClick() )
4544 {
4545 if ( XToEdgeOfCol(x) < 0 )
4546 {
4547 col = XToCol(x);
b54ba671 4548 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
2d66e025
MB
4549 }
4550 }
60ff3b99
VZ
4551
4552
2d66e025
MB
4553 // ------------ Left button released
4554 //
4555 else if ( event.LeftUp() )
4556 {
4557 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4558 {
6d004f67 4559 DoEndDragResizeCol();
e2b42eeb 4560
6d004f67
MB
4561 // Note: we are ending the event *after* doing
4562 // default processing in this case
4563 //
b54ba671 4564 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2d66e025 4565 }
f85afd4e 4566
e2b42eeb 4567 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
2d66e025 4568 m_dragLastPos = -1;
60ff3b99
VZ
4569 }
4570
4571
2d66e025
MB
4572 // ------------ Right button down
4573 //
4574 else if ( event.RightDown() )
4575 {
4576 col = XToCol(x);
b54ba671 4577 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
2d66e025
MB
4578 {
4579 // no default action at the moment
f85afd4e
MB
4580 }
4581 }
60ff3b99
VZ
4582
4583
2d66e025 4584 // ------------ Right double click
f85afd4e 4585 //
2d66e025
MB
4586 else if ( event.RightDClick() )
4587 {
4588 col = XToCol(x);
b54ba671 4589 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
2d66e025
MB
4590 {
4591 // no default action at the moment
4592 }
4593 }
60ff3b99
VZ
4594
4595
2d66e025 4596 // ------------ No buttons down and mouse moving
f85afd4e 4597 //
2d66e025 4598 else if ( event.Moving() )
f85afd4e 4599 {
2d66e025
MB
4600 m_dragRowOrCol = XToEdgeOfCol( x );
4601 if ( m_dragRowOrCol >= 0 )
f85afd4e 4602 {
2d66e025 4603 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 4604 {
e2b42eeb 4605 // don't capture the cursor yet
6e8524b1
MB
4606 if ( CanDragColSize() )
4607 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
f85afd4e 4608 }
2d66e025 4609 }
6d004f67 4610 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2d66e025 4611 {
e2b42eeb 4612 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
8f177c8e 4613 }
f85afd4e
MB
4614 }
4615}
4616
4617
2d66e025 4618void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
f85afd4e 4619{
2d66e025 4620 if ( event.LeftDown() )
f85afd4e 4621 {
2d66e025
MB
4622 // indicate corner label by having both row and
4623 // col args == -1
f85afd4e 4624 //
b54ba671 4625 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
2d66e025
MB
4626 {
4627 SelectAll();
4628 }
f85afd4e
MB
4629 }
4630
2d66e025
MB
4631 else if ( event.LeftDClick() )
4632 {
b54ba671 4633 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
2d66e025 4634 }
8f177c8e 4635
2d66e025 4636 else if ( event.RightDown() )
f85afd4e 4637 {
b54ba671 4638 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
f85afd4e 4639 {
2d66e025
MB
4640 // no default action at the moment
4641 }
4642 }
f85afd4e 4643
2d66e025
MB
4644 else if ( event.RightDClick() )
4645 {
b54ba671 4646 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
2d66e025
MB
4647 {
4648 // no default action at the moment
4649 }
4650 }
4651}
f85afd4e 4652
e2b42eeb
VZ
4653void wxGrid::ChangeCursorMode(CursorMode mode,
4654 wxWindow *win,
4655 bool captureMouse)
4656{
4657#ifdef __WXDEBUG__
4658 static const wxChar *cursorModes[] =
4659 {
4660 _T("SELECT_CELL"),
4661 _T("RESIZE_ROW"),
4662 _T("RESIZE_COL"),
4663 _T("SELECT_ROW"),
4664 _T("SELECT_COL")
4665 };
4666
181bfffd
VZ
4667 wxLogTrace(_T("grid"),
4668 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
e2b42eeb
VZ
4669 win == m_colLabelWin ? _T("colLabelWin")
4670 : win ? _T("rowLabelWin")
4671 : _T("gridWin"),
4672 cursorModes[m_cursorMode], cursorModes[mode]);
4673#endif // __WXDEBUG__
4674
faec5a43
SN
4675 if ( mode == m_cursorMode &&
4676 win == m_winCapture &&
4677 captureMouse == (m_winCapture != NULL))
e2b42eeb
VZ
4678 return;
4679
4680 if ( !win )
4681 {
4682 // by default use the grid itself
4683 win = m_gridWin;
4684 }
4685
4686 if ( m_winCapture )
4687 {
4688 m_winCapture->ReleaseMouse();
4689 m_winCapture = (wxWindow *)NULL;
4690 }
4691
4692 m_cursorMode = mode;
4693
4694 switch ( m_cursorMode )
4695 {
4696 case WXGRID_CURSOR_RESIZE_ROW:
4697 win->SetCursor( m_rowResizeCursor );
4698 break;
4699
4700 case WXGRID_CURSOR_RESIZE_COL:
4701 win->SetCursor( m_colResizeCursor );
4702 break;
4703
4704 default:
4705 win->SetCursor( *wxSTANDARD_CURSOR );
4706 }
4707
4708 // we need to capture mouse when resizing
4709 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
4710 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
4711
4712 if ( captureMouse && resize )
4713 {
4714 win->CaptureMouse();
4715 m_winCapture = win;
4716 }
4717}
8f177c8e 4718
2d66e025
MB
4719void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
4720{
4721 int x, y;
4722 wxPoint pos( event.GetPosition() );
4723 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
60ff3b99 4724
2d66e025
MB
4725 wxGridCellCoords coords;
4726 XYToCell( x, y, coords );
60ff3b99 4727
2d66e025
MB
4728 if ( event.Dragging() )
4729 {
07296f0b
RD
4730 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
4731
4732 // Don't start doing anything until the mouse has been drug at
4733 // least 3 pixels in any direction...
508011ce
VZ
4734 if (! m_isDragging)
4735 {
4736 if (m_startDragPos == wxDefaultPosition)
4737 {
07296f0b
RD
4738 m_startDragPos = pos;
4739 return;
4740 }
4741 if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
4742 return;
4743 }
4744
2d66e025 4745 m_isDragging = TRUE;
2d66e025
MB
4746 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
4747 {
f0102d2a
VZ
4748 // Hide the edit control, so it
4749 // won't interfer with drag-shrinking.
f6bcfd97 4750 if ( IsCellEditControlShown() )
a5777624 4751 {
f0102d2a 4752 HideCellEditControl();
a5777624
RD
4753 SaveEditControlValue();
4754 }
07296f0b
RD
4755
4756 // Have we captured the mouse yet?
508011ce
VZ
4757 if (! m_winCapture)
4758 {
07296f0b
RD
4759 m_winCapture = m_gridWin;
4760 m_winCapture->CaptureMouse();
4761 }
4762
2d66e025
MB
4763 if ( coords != wxGridNoCellCoords )
4764 {
aa5e1f75
SN
4765 if ( event.ControlDown() )
4766 {
4767 if ( m_selectingKeyboard == wxGridNoCellCoords)
4768 m_selectingKeyboard = coords;
c9097836 4769 HighlightBlock ( m_selectingKeyboard, coords );
aa5e1f75
SN
4770 }
4771 else
4772 {
4773 if ( !IsSelection() )
4774 {
c9097836 4775 HighlightBlock( coords, coords );
aa5e1f75
SN
4776 }
4777 else
4778 {
c9097836 4779 HighlightBlock( m_currentCellCoords, coords );
aa5e1f75 4780 }
f85afd4e 4781 }
07296f0b 4782
508011ce
VZ
4783 if (! IsVisible(coords))
4784 {
07296f0b
RD
4785 MakeCellVisible(coords);
4786 // TODO: need to introduce a delay or something here. The
e32352cf 4787 // scrolling is way to fast, at least on MSW - also on GTK.
07296f0b 4788 }
2d66e025
MB
4789 }
4790 }
6d004f67
MB
4791 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4792 {
4793 int cw, ch, left, dummy;
4794 m_gridWin->GetClientSize( &cw, &ch );
4795 CalcUnscrolledPosition( 0, 0, &left, &dummy );
8f177c8e 4796
6d004f67
MB
4797 wxClientDC dc( m_gridWin );
4798 PrepareDC( dc );
a95e38c0
VZ
4799 y = wxMax( y, GetRowTop(m_dragRowOrCol) +
4800 GetRowMinimalHeight(m_dragRowOrCol) );
6d004f67
MB
4801 dc.SetLogicalFunction(wxINVERT);
4802 if ( m_dragLastPos >= 0 )
4803 {
4804 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
4805 }
4806 dc.DrawLine( left, y, left+cw, y );
4807 m_dragLastPos = y;
4808 }
4809 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4810 {
4811 int cw, ch, dummy, top;
4812 m_gridWin->GetClientSize( &cw, &ch );
4813 CalcUnscrolledPosition( 0, 0, &dummy, &top );
e2b42eeb 4814
6d004f67
MB
4815 wxClientDC dc( m_gridWin );
4816 PrepareDC( dc );
43947979
VZ
4817 x = wxMax( x, GetColLeft(m_dragRowOrCol) +
4818 GetColMinimalWidth(m_dragRowOrCol) );
6d004f67
MB
4819 dc.SetLogicalFunction(wxINVERT);
4820 if ( m_dragLastPos >= 0 )
4821 {
4822 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
4823 }
4824 dc.DrawLine( x, top, x, top+ch );
4825 m_dragLastPos = x;
4826 }
e2b42eeb 4827
2d66e025
MB
4828 return;
4829 }
66242c80 4830
2d66e025 4831 m_isDragging = FALSE;
07296f0b
RD
4832 m_startDragPos = wxDefaultPosition;
4833
a5777624
RD
4834 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
4835 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
4836 // wxGTK
e2b42eeb 4837#if 0
a5777624
RD
4838 if ( event.Entering() || event.Leaving() )
4839 {
4840 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4841 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
4842 }
4843 else
e2b42eeb
VZ
4844#endif // 0
4845
a5777624
RD
4846 // ------------ Left button pressed
4847 //
4848 if ( event.LeftDown() && coords != wxGridNoCellCoords )
f6bcfd97
BP
4849 {
4850 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
4851 coords.GetRow(),
4852 coords.GetCol(),
4853 event ) )
a5777624 4854 {
f6bcfd97
BP
4855 if ( !event.ControlDown() )
4856 ClearSelection();
4857 if ( event.ShiftDown() )
4858 {
4859 m_selection->SelectBlock( m_currentCellCoords.GetRow(),
4860 m_currentCellCoords.GetCol(),
4861 coords.GetRow(),
4862 coords.GetCol(),
4863 event.ControlDown(),
4864 event.ShiftDown(),
4865 event.AltDown(),
4866 event.MetaDown() );
4867 }
4868 else if ( XToEdgeOfCol(x) < 0 &&
4869 YToEdgeOfRow(y) < 0 )
58dd5b3b 4870 {
a5777624
RD
4871 DisableCellEditControl();
4872 MakeCellVisible( coords );
4873
4874 // if this is the second click on this cell then start
4875 // the edit control
4876 if ( m_waitForSlowClick &&
4877 (coords == m_currentCellCoords) &&
4878 CanEnableCellControl())
58dd5b3b 4879 {
a5777624 4880 EnableCellEditControl();
e195a54c 4881
a5777624 4882 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
0b190b0f
VZ
4883 wxGridCellEditor *editor = attr->GetEditor(this,
4884 coords.GetRow(),
4885 coords.GetCol());
4886 editor->StartingClick();
4887 editor->DecRef();
a5777624 4888 attr->DecRef();
e195a54c 4889
a5777624
RD
4890 m_waitForSlowClick = FALSE;
4891 }
4892 else
4893 {
aa5e1f75
SN
4894 if ( event.ControlDown() )
4895 {
4896 m_selection->ToggleCellSelection( coords.GetRow(),
4897 coords.GetCol(),
4898 event.ControlDown(),
4899 event.ShiftDown(),
4900 event.AltDown(),
4901 event.MetaDown() );
4902 m_selectingTopLeft = wxGridNoCellCoords;
4903 m_selectingBottomRight = wxGridNoCellCoords;
4904 m_selectingKeyboard = coords;
4905 }
4906 else
f6bcfd97 4907 {
aa5e1f75 4908 SetCurrentCell( coords );
f6bcfd97
BP
4909 if ( m_selection->GetSelectionMode()
4910 != wxGrid::wxGridSelectCells)
c9097836 4911 HighlightBlock( coords, coords );
f6bcfd97 4912 }
a5777624 4913 m_waitForSlowClick = TRUE;
58dd5b3b
MB
4914 }
4915 }
f85afd4e 4916 }
a5777624 4917 }
f85afd4e 4918
f85afd4e 4919
a5777624
RD
4920 // ------------ Left double click
4921 //
4922 else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
4923 {
4924 DisableCellEditControl();
4925
4926 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
58dd5b3b 4927 {
a5777624
RD
4928 SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
4929 coords.GetRow(),
4930 coords.GetCol(),
4931 event );
58dd5b3b 4932 }
a5777624 4933 }
f85afd4e 4934
8f177c8e 4935
a5777624
RD
4936 // ------------ Left button released
4937 //
4938 else if ( event.LeftUp() )
4939 {
4940 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
f85afd4e 4941 {
b5808881
SN
4942 if ( m_selectingTopLeft != wxGridNoCellCoords &&
4943 m_selectingBottomRight != wxGridNoCellCoords )
52068ea5 4944 {
a5777624 4945 if (m_winCapture)
58dd5b3b 4946 {
a5777624
RD
4947 m_winCapture->ReleaseMouse();
4948 m_winCapture = NULL;
58dd5b3b 4949 }
5c8fc7c1
SN
4950 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
4951 m_selectingTopLeft.GetCol(),
4952 m_selectingBottomRight.GetRow(),
4953 m_selectingBottomRight.GetCol(),
d95b0c2b
SN
4954 event.ControlDown(),
4955 event.ShiftDown(),
4956 event.AltDown(),
4957 event.MetaDown() );
5c8fc7c1
SN
4958 m_selectingTopLeft = wxGridNoCellCoords;
4959 m_selectingBottomRight = wxGridNoCellCoords;
6d004f67 4960 }
2d66e025 4961
a5777624
RD
4962 // Show the edit control, if it has been hidden for
4963 // drag-shrinking.
4964 ShowCellEditControl();
4965 }
4966 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
4967 {
4968 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4969 DoEndDragResizeRow();
e2b42eeb 4970
a5777624
RD
4971 // Note: we are ending the event *after* doing
4972 // default processing in this case
4973 //
4974 SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
4975 }
4976 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
4977 {
4978 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
4979 DoEndDragResizeCol();
e2b42eeb 4980
a5777624
RD
4981 // Note: we are ending the event *after* doing
4982 // default processing in this case
4983 //
4984 SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
58dd5b3b 4985 }
f85afd4e 4986
a5777624
RD
4987 m_dragLastPos = -1;
4988 }
4989
f85afd4e 4990
a5777624
RD
4991 // ------------ Right button down
4992 //
4993 else if ( event.RightDown() && coords != wxGridNoCellCoords )
4994 {
4995 DisableCellEditControl();
4996 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
4997 coords.GetRow(),
4998 coords.GetCol(),
4999 event ) )
f85afd4e 5000 {
a5777624 5001 // no default action at the moment
60ff3b99 5002 }
a5777624 5003 }
2d66e025 5004
60ff3b99 5005
a5777624
RD
5006 // ------------ Right double click
5007 //
5008 else if ( event.RightDClick() && coords != wxGridNoCellCoords )
5009 {
5010 DisableCellEditControl();
5011 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
5012 coords.GetRow(),
5013 coords.GetCol(),
5014 event ) )
f85afd4e 5015 {
a5777624 5016 // no default action at the moment
60ff3b99 5017 }
a5777624
RD
5018 }
5019
5020 // ------------ Moving and no button action
5021 //
5022 else if ( event.Moving() && !event.IsButton() )
5023 {
5024 int dragRow = YToEdgeOfRow( y );
5025 int dragCol = XToEdgeOfCol( x );
790cc417 5026
a5777624
RD
5027 // Dragging on the corner of a cell to resize in both
5028 // directions is not implemented yet...
790cc417 5029 //
a5777624 5030 if ( dragRow >= 0 && dragCol >= 0 )
790cc417 5031 {
a5777624
RD
5032 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
5033 return;
5034 }
6d004f67 5035
a5777624
RD
5036 if ( dragRow >= 0 )
5037 {
5038 m_dragRowOrCol = dragRow;
6d004f67 5039
a5777624 5040 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
6d004f67 5041 {
a5777624
RD
5042 if ( CanDragRowSize() && CanDragGridSize() )
5043 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
6d004f67 5044 }
e2b42eeb 5045
b94ae1ea
VZ
5046 if ( dragCol >= 0 )
5047 {
5048 m_dragRowOrCol = dragCol;
122603f1 5049 }
b94ae1ea 5050
a5777624
RD
5051 return;
5052 }
e2b42eeb 5053
a5777624
RD
5054 if ( dragCol >= 0 )
5055 {
5056 m_dragRowOrCol = dragCol;
e2b42eeb 5057
a5777624 5058 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
6d004f67 5059 {
a5777624
RD
5060 if ( CanDragColSize() && CanDragGridSize() )
5061 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
6d004f67 5062 }
a5777624
RD
5063
5064 return;
6d004f67 5065 }
a5777624
RD
5066
5067 // Neither on a row or col edge
5068 //
5069 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
5070 {
5071 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
5072 }
5073 }
6d004f67
MB
5074}
5075
5076
5077void wxGrid::DoEndDragResizeRow()
5078{
5079 if ( m_dragLastPos >= 0 )
5080 {
5081 // erase the last line and resize the row
5082 //
5083 int cw, ch, left, dummy;
5084 m_gridWin->GetClientSize( &cw, &ch );
5085 CalcUnscrolledPosition( 0, 0, &left, &dummy );
5086
5087 wxClientDC dc( m_gridWin );
5088 PrepareDC( dc );
5089 dc.SetLogicalFunction( wxINVERT );
5090 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
5091 HideCellEditControl();
a5777624 5092 SaveEditControlValue();
6d004f67 5093
7c1cb261 5094 int rowTop = GetRowTop(m_dragRowOrCol);
6d004f67
MB
5095 SetRowSize( m_dragRowOrCol,
5096 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
e2b42eeb 5097
6d004f67
MB
5098 if ( !GetBatchCount() )
5099 {
5100 // Only needed to get the correct rect.y:
5101 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
5102 rect.x = 0;
5103 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
5104 rect.width = m_rowLabelWidth;
5105 rect.height = ch - rect.y;
5106 m_rowLabelWin->Refresh( TRUE, &rect );
5107 rect.width = cw;
5108 m_gridWin->Refresh( FALSE, &rect );
5109 }
5110
5111 ShowCellEditControl();
5112 }
5113}
5114
5115
5116void wxGrid::DoEndDragResizeCol()
5117{
5118 if ( m_dragLastPos >= 0 )
5119 {
5120 // erase the last line and resize the col
5121 //
5122 int cw, ch, dummy, top;
5123 m_gridWin->GetClientSize( &cw, &ch );
5124 CalcUnscrolledPosition( 0, 0, &dummy, &top );
5125
5126 wxClientDC dc( m_gridWin );
5127 PrepareDC( dc );
5128 dc.SetLogicalFunction( wxINVERT );
5129 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
5130 HideCellEditControl();
a5777624 5131 SaveEditControlValue();
6d004f67 5132
7c1cb261 5133 int colLeft = GetColLeft(m_dragRowOrCol);
6d004f67 5134 SetColSize( m_dragRowOrCol,
43947979
VZ
5135 wxMax( m_dragLastPos - colLeft,
5136 GetColMinimalWidth(m_dragRowOrCol) ) );
6d004f67
MB
5137
5138 if ( !GetBatchCount() )
5139 {
5140 // Only needed to get the correct rect.x:
5141 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
5142 rect.y = 0;
5143 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
5144 rect.width = cw - rect.x;
5145 rect.height = m_colLabelHeight;
5146 m_colLabelWin->Refresh( TRUE, &rect );
5147 rect.height = ch;
5148 m_gridWin->Refresh( FALSE, &rect );
790cc417 5149 }
e2b42eeb 5150
6d004f67 5151 ShowCellEditControl();
f85afd4e 5152 }
f85afd4e
MB
5153}
5154
5155
6d004f67 5156
2d66e025
MB
5157//
5158// ------ interaction with data model
5159//
5160bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
f85afd4e 5161{
2d66e025 5162 switch ( msg.GetId() )
17732cec 5163 {
2d66e025
MB
5164 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
5165 return GetModelValues();
17732cec 5166
2d66e025
MB
5167 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
5168 return SetModelValues();
f85afd4e 5169
2d66e025
MB
5170 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
5171 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
5172 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
5173 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
5174 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
5175 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
5176 return Redimension( msg );
5177
5178 default:
5179 return FALSE;
f85afd4e 5180 }
2d66e025 5181}
f85afd4e 5182
f85afd4e 5183
f85afd4e 5184
2d66e025
MB
5185// The behaviour of this function depends on the grid table class
5186// Clear() function. For the default wxGridStringTable class the
5187// behavious is to replace all cell contents with wxEmptyString but
5188// not to change the number of rows or cols.
5189//
5190void wxGrid::ClearGrid()
5191{
5192 if ( m_table )
f85afd4e 5193 {
4cfa5de6
RD
5194 if (IsCellEditControlEnabled())
5195 DisableCellEditControl();
5196
2d66e025 5197 m_table->Clear();
1f1ce288 5198 if ( !GetBatchCount() ) m_gridWin->Refresh();
f85afd4e
MB
5199 }
5200}
5201
5202
2d66e025 5203bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 5204{
2d66e025 5205 // TODO: something with updateLabels flag
8f177c8e 5206
2d66e025 5207 if ( !m_created )
f85afd4e 5208 {
bd3c6758 5209 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2d66e025
MB
5210 return FALSE;
5211 }
8f177c8e 5212
2d66e025
MB
5213 if ( m_table )
5214 {
b7fff980 5215 if (IsCellEditControlEnabled())
b54ba671 5216 DisableCellEditControl();
b7fff980 5217
f6bcfd97 5218 return m_table->InsertRows( pos, numRows );
f85afd4e 5219
2d66e025
MB
5220 // the table will have sent the results of the insert row
5221 // operation to this view object as a grid table message
f85afd4e 5222 }
f6bcfd97 5223 return FALSE;
f85afd4e
MB
5224}
5225
5226
2d66e025 5227bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 5228{
2d66e025
MB
5229 // TODO: something with updateLabels flag
5230
5231 if ( !m_created )
f85afd4e 5232 {
bd3c6758 5233 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2d66e025
MB
5234 return FALSE;
5235 }
5236
f6bcfd97
BP
5237 return ( m_table && m_table->AppendRows( numRows ) );
5238 // the table will have sent the results of the append row
5239 // operation to this view object as a grid table message
f85afd4e
MB
5240}
5241
2d66e025
MB
5242
5243bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
f85afd4e 5244{
2d66e025
MB
5245 // TODO: something with updateLabels flag
5246
5247 if ( !m_created )
f85afd4e 5248 {
bd3c6758 5249 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2d66e025
MB
5250 return FALSE;
5251 }
5252
b7fff980 5253 if ( m_table )
2d66e025 5254 {
b7fff980 5255 if (IsCellEditControlEnabled())
b54ba671 5256 DisableCellEditControl();
f85afd4e 5257
f6bcfd97
BP
5258 return (m_table->DeleteRows( pos, numRows ));
5259 // the table will have sent the results of the delete row
5260 // operation to this view object as a grid table message
2d66e025 5261 }
b7fff980 5262 return FALSE;
2d66e025 5263}
f85afd4e 5264
f85afd4e 5265
2d66e025
MB
5266bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
5267{
5268 // TODO: something with updateLabels flag
8f177c8e 5269
2d66e025
MB
5270 if ( !m_created )
5271 {
bd3c6758 5272 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2d66e025
MB
5273 return FALSE;
5274 }
f85afd4e 5275
2d66e025
MB
5276 if ( m_table )
5277 {
b7fff980 5278 if (IsCellEditControlEnabled())
b54ba671 5279 DisableCellEditControl();
b7fff980 5280
f6bcfd97 5281 return m_table->InsertCols( pos, numCols );
2d66e025
MB
5282 // the table will have sent the results of the insert col
5283 // operation to this view object as a grid table message
f85afd4e 5284 }
f6bcfd97 5285 return FALSE;
f85afd4e
MB
5286}
5287
2d66e025
MB
5288
5289bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 5290{
2d66e025
MB
5291 // TODO: something with updateLabels flag
5292
5293 if ( !m_created )
f85afd4e 5294 {
bd3c6758 5295 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2d66e025
MB
5296 return FALSE;
5297 }
f85afd4e 5298
f6bcfd97
BP
5299 return ( m_table && m_table->AppendCols( numCols ) );
5300 // the table will have sent the results of the append col
5301 // operation to this view object as a grid table message
f85afd4e
MB
5302}
5303
5304
2d66e025 5305bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
f85afd4e 5306{
2d66e025 5307 // TODO: something with updateLabels flag
8f177c8e 5308
2d66e025 5309 if ( !m_created )
f85afd4e 5310 {
bd3c6758 5311 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2d66e025 5312 return FALSE;
f85afd4e
MB
5313 }
5314
b7fff980 5315 if ( m_table )
2d66e025 5316 {
b7fff980 5317 if (IsCellEditControlEnabled())
b54ba671 5318 DisableCellEditControl();
8f177c8e 5319
f6bcfd97
BP
5320 return ( m_table->DeleteCols( pos, numCols ) );
5321 // the table will have sent the results of the delete col
5322 // operation to this view object as a grid table message
f85afd4e 5323 }
b7fff980 5324 return FALSE;
f85afd4e
MB
5325}
5326
5327
2d66e025
MB
5328
5329//
5330// ----- event handlers
f85afd4e 5331//
8f177c8e 5332
2d66e025
MB
5333// Generate a grid event based on a mouse event and
5334// return the result of ProcessEvent()
5335//
5336bool wxGrid::SendEvent( const wxEventType type,
5337 int row, int col,
5338 wxMouseEvent& mouseEv )
5339{
b54ba671 5340 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
f85afd4e 5341 {
2d66e025
MB
5342 int rowOrCol = (row == -1 ? col : row);
5343
5344 wxGridSizeEvent gridEvt( GetId(),
5345 type,
5346 this,
5347 rowOrCol,
faec5a43
SN
5348 mouseEv.GetX() + GetRowLabelSize(),
5349 mouseEv.GetY() + GetColLabelSize(),
2d66e025
MB
5350 mouseEv.ControlDown(),
5351 mouseEv.ShiftDown(),
5352 mouseEv.AltDown(),
5353 mouseEv.MetaDown() );
2d66e025 5354 return GetEventHandler()->ProcessEvent(gridEvt);
f85afd4e 5355 }
b54ba671 5356 else if ( type == wxEVT_GRID_RANGE_SELECT )
2d66e025 5357 {
f6bcfd97 5358 // Right now, it should _never_ end up here!
2d66e025
MB
5359 wxGridRangeSelectEvent gridEvt( GetId(),
5360 type,
5361 this,
b5808881
SN
5362 m_selectingTopLeft,
5363 m_selectingBottomRight,
5c8fc7c1 5364 TRUE,
2d66e025
MB
5365 mouseEv.ControlDown(),
5366 mouseEv.ShiftDown(),
5367 mouseEv.AltDown(),
5368 mouseEv.MetaDown() );
f85afd4e 5369
2d66e025
MB
5370 return GetEventHandler()->ProcessEvent(gridEvt);
5371 }
5372 else
5373 {
5374 wxGridEvent gridEvt( GetId(),
5375 type,
5376 this,
5377 row, col,
faec5a43
SN
5378 mouseEv.GetX() + GetRowLabelSize(),
5379 mouseEv.GetY() + GetColLabelSize(),
d7da9756 5380 FALSE,
2d66e025
MB
5381 mouseEv.ControlDown(),
5382 mouseEv.ShiftDown(),
5383 mouseEv.AltDown(),
5384 mouseEv.MetaDown() );
2d66e025
MB
5385 return GetEventHandler()->ProcessEvent(gridEvt);
5386 }
f85afd4e
MB
5387}
5388
5389
2d66e025
MB
5390// Generate a grid event of specified type and return the result
5391// of ProcessEvent().
f85afd4e 5392//
2d66e025
MB
5393bool wxGrid::SendEvent( const wxEventType type,
5394 int row, int col )
f85afd4e 5395{
b54ba671 5396 if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
f85afd4e 5397 {
2d66e025 5398 int rowOrCol = (row == -1 ? col : row);
f85afd4e 5399
2d66e025
MB
5400 wxGridSizeEvent gridEvt( GetId(),
5401 type,
5402 this,
5403 rowOrCol );
5404
5405 return GetEventHandler()->ProcessEvent(gridEvt);
5406 }
5407 else
5408 {
5409 wxGridEvent gridEvt( GetId(),
5410 type,
5411 this,
5412 row, col );
8f177c8e 5413
2d66e025
MB
5414 return GetEventHandler()->ProcessEvent(gridEvt);
5415 }
f85afd4e
MB
5416}
5417
5418
2d66e025 5419void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
f85afd4e 5420{
f6bcfd97 5421 wxPaintDC dc(this); // needed to prevent zillions of paint events on MSW
8f177c8e 5422}
f85afd4e
MB
5423
5424
18f9565d
MB
5425// This is just here to make sure that CalcDimensions gets called when
5426// the grid view is resized... then the size event is skipped to allow
5427// the box sizers to handle everything
5428//
aa5e1f75 5429void wxGrid::OnSize( wxSizeEvent& WXUNUSED(event) )
f85afd4e 5430{
7807d81c 5431 CalcWindowSizes();
2d66e025 5432 CalcDimensions();
f85afd4e
MB
5433}
5434
f85afd4e 5435
2d66e025 5436void wxGrid::OnKeyDown( wxKeyEvent& event )
f85afd4e 5437{
2d66e025 5438 if ( m_inOnKeyDown )
f85afd4e 5439 {
2d66e025
MB
5440 // shouldn't be here - we are going round in circles...
5441 //
07296f0b 5442 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
f85afd4e
MB
5443 }
5444
2d66e025 5445 m_inOnKeyDown = TRUE;
f85afd4e 5446
2d66e025
MB
5447 // propagate the event up and see if it gets processed
5448 //
5449 wxWindow *parent = GetParent();
5450 wxKeyEvent keyEvt( event );
5451 keyEvt.SetEventObject( parent );
5452
5453 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
f85afd4e 5454 {
9b4aede2 5455
2d66e025
MB
5456 // try local handlers
5457 //
5458 switch ( event.KeyCode() )
5459 {
5460 case WXK_UP:
5461 if ( event.ControlDown() )
5462 {
5c8fc7c1 5463 MoveCursorUpBlock( event.ShiftDown() );
2d66e025
MB
5464 }
5465 else
5466 {
5c8fc7c1 5467 MoveCursorUp( event.ShiftDown() );
2d66e025
MB
5468 }
5469 break;
f85afd4e 5470
2d66e025
MB
5471 case WXK_DOWN:
5472 if ( event.ControlDown() )
5473 {
5c8fc7c1 5474 MoveCursorDownBlock( event.ShiftDown() );
2d66e025
MB
5475 }
5476 else
5477 {
5c8fc7c1 5478 MoveCursorDown( event.ShiftDown() );
2d66e025
MB
5479 }
5480 break;
8f177c8e 5481
2d66e025
MB
5482 case WXK_LEFT:
5483 if ( event.ControlDown() )
5484 {
5c8fc7c1 5485 MoveCursorLeftBlock( event.ShiftDown() );
2d66e025
MB
5486 }
5487 else
5488 {
5c8fc7c1 5489 MoveCursorLeft( event.ShiftDown() );
2d66e025
MB
5490 }
5491 break;
5492
5493 case WXK_RIGHT:
5494 if ( event.ControlDown() )
5495 {
5c8fc7c1 5496 MoveCursorRightBlock( event.ShiftDown() );
2d66e025
MB
5497 }
5498 else
5499 {
5c8fc7c1 5500 MoveCursorRight( event.ShiftDown() );
2d66e025
MB
5501 }
5502 break;
b99be8fb 5503
2d66e025 5504 case WXK_RETURN:
a4f7bf58 5505 case WXK_NUMPAD_ENTER:
58dd5b3b
MB
5506 if ( event.ControlDown() )
5507 {
5508 event.Skip(); // to let the edit control have the return
5509 }
5510 else
5511 {
f6bcfd97
BP
5512 if ( GetGridCursorRow() < GetNumberRows()-1 )
5513 {
5514 MoveCursorDown( event.ShiftDown() );
5515 }
5516 else
5517 {
5518 // at the bottom of a column
5519 HideCellEditControl();
5520 SaveEditControlValue();
5521 }
58dd5b3b 5522 }
2d66e025
MB
5523 break;
5524
5c8fc7c1 5525 case WXK_ESCAPE:
e32352cf 5526 ClearSelection();
5c8fc7c1
SN
5527 break;
5528
2c9a89e0
RD
5529 case WXK_TAB:
5530 if (event.ShiftDown())
f6bcfd97
BP
5531 {
5532 if ( GetGridCursorCol() > 0 )
5533 {
5534 MoveCursorLeft( FALSE );
5535 }
5536 else
5537 {
5538 // at left of grid
5539 HideCellEditControl();
5540 SaveEditControlValue();
5541 }
5542 }
2c9a89e0 5543 else
f6bcfd97
BP
5544 {
5545 if ( GetGridCursorCol() < GetNumberCols()-1 )
5546 {
5547 MoveCursorRight( FALSE );
5548 }
5549 else
5550 {
5551 // at right of grid
5552 HideCellEditControl();
5553 SaveEditControlValue();
5554 }
5555 }
2c9a89e0
RD
5556 break;
5557
2d66e025
MB
5558 case WXK_HOME:
5559 if ( event.ControlDown() )
5560 {
5561 MakeCellVisible( 0, 0 );
5562 SetCurrentCell( 0, 0 );
5563 }
5564 else
5565 {
5566 event.Skip();
5567 }
5568 break;
5569
5570 case WXK_END:
5571 if ( event.ControlDown() )
5572 {
5573 MakeCellVisible( m_numRows-1, m_numCols-1 );
5574 SetCurrentCell( m_numRows-1, m_numCols-1 );
5575 }
5576 else
5577 {
5578 event.Skip();
5579 }
5580 break;
5581
5582 case WXK_PRIOR:
5583 MovePageUp();
5584 break;
5585
5586 case WXK_NEXT:
5587 MovePageDown();
5588 break;
5589
07296f0b 5590 case WXK_SPACE:
aa5e1f75
SN
5591 if ( event.ControlDown() )
5592 {
5593 m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
5594 m_currentCellCoords.GetCol(),
5595 event.ControlDown(),
5596 event.ShiftDown(),
5597 event.AltDown(),
5598 event.MetaDown() );
5599 break;
5600 }
07296f0b
RD
5601 if ( !IsEditable() )
5602 {
5c8fc7c1 5603 MoveCursorRight( FALSE );
07296f0b
RD
5604 break;
5605 }
5606 // Otherwise fall through to default
5607
2d66e025 5608 default:
f6bcfd97
BP
5609 // is it possible to edit the current cell at all?
5610 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
b54ba671 5611 {
f6bcfd97 5612 // yes, now check whether the cells editor accepts the key
f2d76237
RD
5613 int row = m_currentCellCoords.GetRow();
5614 int col = m_currentCellCoords.GetCol();
5615 wxGridCellAttr* attr = GetCellAttr(row, col);
0b190b0f 5616 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
f6bcfd97
BP
5617
5618 // <F2> is special and will always start editing, for
5619 // other keys - ask the editor itself
5620 if ( (event.KeyCode() == WXK_F2 && !event.HasModifiers())
5621 || editor->IsAcceptedKey(event) )
5622 {
5623 EnableCellEditControl();
5624 editor->StartingKey(event);
5625 }
5626 else
5627 {
5628 event.Skip();
5629 }
5630
0b190b0f 5631 editor->DecRef();
2c9a89e0
RD
5632 attr->DecRef();
5633 }
b3a7510d
VZ
5634 else
5635 {
b94ae1ea
VZ
5636 // let others process char events with modifiers or all
5637 // char events for readonly cells
b3a7510d
VZ
5638 event.Skip();
5639 }
025562fe 5640 break;
2d66e025 5641 }
f85afd4e
MB
5642 }
5643
2d66e025 5644 m_inOnKeyDown = FALSE;
f85afd4e
MB
5645}
5646
f6bcfd97
BP
5647void wxGrid::OnKeyUp( wxKeyEvent& event )
5648{
5649 // try local handlers
5650 //
5651 if ( event.KeyCode() == WXK_SHIFT )
5652 {
5653 if ( m_selectingTopLeft != wxGridNoCellCoords &&
5654 m_selectingBottomRight != wxGridNoCellCoords )
5655 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
5656 m_selectingTopLeft.GetCol(),
5657 m_selectingBottomRight.GetRow(),
5658 m_selectingBottomRight.GetCol(),
5659 event.ControlDown(),
5660 TRUE,
5661 event.AltDown(),
5662 event.MetaDown() );
5663 m_selectingTopLeft = wxGridNoCellCoords;
5664 m_selectingBottomRight = wxGridNoCellCoords;
5665 m_selectingKeyboard = wxGridNoCellCoords;
5666 }
5667}
5668
2796cce3 5669void wxGrid::OnEraseBackground(wxEraseEvent&)
508011ce
VZ
5670{
5671}
07296f0b 5672
2d66e025 5673void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
66242c80 5674{
f6bcfd97
BP
5675 if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
5676 {
5677 // the event has been intercepted - do nothing
5678 return;
5679 }
5680
5681 wxClientDC dc(m_gridWin);
5682 PrepareDC(dc);
5683
2a7750d9 5684 if ( m_currentCellCoords != wxGridNoCellCoords )
2d66e025 5685 {
2d66e025 5686 HideCellEditControl();
b54ba671 5687 DisableCellEditControl();
07296f0b 5688
3ca6a5f0 5689 if ( IsVisible( m_currentCellCoords, FALSE ) )
f6bcfd97
BP
5690 {
5691 wxRect r;
5692 r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
5693 if ( !m_gridLinesEnabled )
5694 {
5695 r.x--;
5696 r.y--;
5697 r.width++;
5698 r.height++;
5699 }
d1c0b4f9 5700
f6bcfd97 5701 CalcCellsExposed( r );
84912ef8 5702
f6bcfd97
BP
5703 // Otherwise refresh redraws the highlight!
5704 m_currentCellCoords = coords;
d1c0b4f9 5705
f6bcfd97
BP
5706 DrawGridCellArea(dc);
5707 DrawAllGridLines( dc, r );
5708 }
66242c80 5709 }
8f177c8e 5710
2d66e025
MB
5711 m_currentCellCoords = coords;
5712
2a7750d9
MB
5713 wxGridCellAttr* attr = GetCellAttr(coords);
5714 DrawCellHighlight(dc, attr);
5715 attr->DecRef();
66242c80
MB
5716}
5717
2d66e025 5718
c9097836
MB
5719void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol )
5720{
5721 int temp;
5722 wxGridCellCoords updateTopLeft, updateBottomRight;
5723
5724 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
5725 {
5726 leftCol = 0;
5727 rightCol = GetNumberCols() - 1;
5728 }
5729 else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
5730 {
5731 topRow = 0;
5732 bottomRow = GetNumberRows() - 1;
5733 }
5734 if ( topRow > bottomRow )
5735 {
5736 temp = topRow;
5737 topRow = bottomRow;
5738 bottomRow = temp;
5739 }
5740
5741 if ( leftCol > rightCol )
5742 {
5743 temp = leftCol;
5744 leftCol = rightCol;
5745 rightCol = temp;
5746 }
5747
5748 updateTopLeft = wxGridCellCoords( topRow, leftCol );
5749 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
5750
5751 if ( m_selectingTopLeft != updateTopLeft ||
5752 m_selectingBottomRight != updateBottomRight )
5753 {
5754 // Compute two optimal update rectangles:
5755 // Either one rectangle is a real subset of the
5756 // other, or they are (almost) disjoint!
5757 wxRect rect[4];
5758 bool need_refresh[4];
5759 need_refresh[0] =
5760 need_refresh[1] =
5761 need_refresh[2] =
5762 need_refresh[3] = FALSE;
5763 int i;
5764
5765 // Store intermediate values
5766 wxCoord oldLeft = m_selectingTopLeft.GetCol();
5767 wxCoord oldTop = m_selectingTopLeft.GetRow();
5768 wxCoord oldRight = m_selectingBottomRight.GetCol();
5769 wxCoord oldBottom = m_selectingBottomRight.GetRow();
5770
5771 // Determine the outer/inner coordinates.
5772 if (oldLeft > leftCol)
5773 {
5774 temp = oldLeft;
5775 oldLeft = leftCol;
5776 leftCol = temp;
5777 }
5778 if (oldTop > topRow )
5779 {
5780 temp = oldTop;
5781 oldTop = topRow;
5782 topRow = temp;
5783 }
5784 if (oldRight < rightCol )
5785 {
5786 temp = oldRight;
5787 oldRight = rightCol;
5788 rightCol = temp;
5789 }
5790 if (oldBottom < bottomRow)
5791 {
5792 temp = oldBottom;
5793 oldBottom = bottomRow;
5794 bottomRow = temp;
5795 }
5796
5797 // Now, either the stuff marked old is the outer
5798 // rectangle or we don't have a situation where one
5799 // is contained in the other.
5800
5801 if ( oldLeft < leftCol )
5802 {
5803 need_refresh[0] = TRUE;
5804 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5805 oldLeft ),
5806 wxGridCellCoords ( oldBottom,
5807 leftCol - 1 ) );
5808 }
5809
5810 if ( oldTop < topRow )
5811 {
5812 need_refresh[1] = TRUE;
5813 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5814 leftCol ),
5815 wxGridCellCoords ( topRow - 1,
5816 rightCol ) );
5817 }
5818
5819 if ( oldRight > rightCol )
5820 {
5821 need_refresh[2] = TRUE;
5822 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5823 rightCol + 1 ),
5824 wxGridCellCoords ( oldBottom,
5825 oldRight ) );
5826 }
5827
5828 if ( oldBottom > bottomRow )
5829 {
5830 need_refresh[3] = TRUE;
5831 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
5832 leftCol ),
5833 wxGridCellCoords ( oldBottom,
5834 rightCol ) );
5835 }
5836
5837
5838 // Change Selection
5839 m_selectingTopLeft = updateTopLeft;
5840 m_selectingBottomRight = updateBottomRight;
5841
5842 // various Refresh() calls
5843 for (i = 0; i < 4; i++ )
5844 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5845 m_gridWin->Refresh( FALSE, &(rect[i]) );
5846 }
5847
5848 // never generate an event as it will be generated from
5849 // wxGridSelection::SelectBlock!
5850 // (old comment from when this was the body of SelectBlock)
5851}
5852
2d66e025
MB
5853//
5854// ------ functions to get/send data (see also public functions)
5855//
5856
5857bool wxGrid::GetModelValues()
66242c80 5858{
2d66e025 5859 if ( m_table )
66242c80 5860 {
2d66e025 5861 // all we need to do is repaint the grid
66242c80 5862 //
2d66e025 5863 m_gridWin->Refresh();
66242c80
MB
5864 return TRUE;
5865 }
8f177c8e 5866
66242c80
MB
5867 return FALSE;
5868}
5869
2d66e025
MB
5870
5871bool wxGrid::SetModelValues()
f85afd4e 5872{
2d66e025 5873 int row, col;
8f177c8e 5874
2d66e025
MB
5875 if ( m_table )
5876 {
5877 for ( row = 0; row < m_numRows; row++ )
f85afd4e 5878 {
2d66e025 5879 for ( col = 0; col < m_numCols; col++ )
f85afd4e 5880 {
2d66e025 5881 m_table->SetValue( row, col, GetCellValue(row, col) );
f85afd4e
MB
5882 }
5883 }
8f177c8e 5884
f85afd4e
MB
5885 return TRUE;
5886 }
5887
5888 return FALSE;
5889}
5890
2d66e025
MB
5891
5892
5893// Note - this function only draws cells that are in the list of
5894// exposed cells (usually set from the update region by
5895// CalcExposedCells)
5896//
5897void wxGrid::DrawGridCellArea( wxDC& dc )
f85afd4e 5898{
2d66e025 5899 if ( !m_numRows || !m_numCols ) return;
60ff3b99 5900
2d66e025
MB
5901 size_t i;
5902 size_t numCells = m_cellsExposed.GetCount();
60ff3b99 5903
2d66e025 5904 for ( i = 0; i < numCells; i++ )
f85afd4e 5905 {
2d66e025
MB
5906 DrawCell( dc, m_cellsExposed[i] );
5907 }
5908}
8f177c8e 5909
8f177c8e 5910
7c8a8ad5
MB
5911void wxGrid::DrawGridSpace( wxDC& dc )
5912{
f6bcfd97
BP
5913 int cw, ch;
5914 m_gridWin->GetClientSize( &cw, &ch );
7c8a8ad5 5915
f6bcfd97
BP
5916 int right, bottom;
5917 CalcUnscrolledPosition( cw, ch, &right, &bottom );
7c8a8ad5 5918
f6bcfd97
BP
5919 int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0;
5920 int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0 ;
7c8a8ad5 5921
f6bcfd97
BP
5922 if ( right > rightCol || bottom > bottomRow )
5923 {
5924 int left, top;
5925 CalcUnscrolledPosition( 0, 0, &left, &top );
7c8a8ad5 5926
f6bcfd97
BP
5927 dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
5928 dc.SetPen( *wxTRANSPARENT_PEN );
7c8a8ad5 5929
f6bcfd97
BP
5930 if ( right > rightCol )
5931 {
5932 dc.DrawRectangle( rightCol, top, right - rightCol, ch);
5933 }
5934
5935 if ( bottom > bottomRow )
5936 {
5937 dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow);
5938 }
5939 }
7c8a8ad5
MB
5940}
5941
5942
2d66e025
MB
5943void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
5944{
ab79958a
VZ
5945 int row = coords.GetRow();
5946 int col = coords.GetCol();
60ff3b99 5947
7c1cb261 5948 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
ab79958a
VZ
5949 return;
5950
5951 // we draw the cell border ourselves
9496deb5 5952#if !WXGRID_DRAW_LINES
2d66e025
MB
5953 if ( m_gridLinesEnabled )
5954 DrawCellBorder( dc, coords );
796df70a 5955#endif
f85afd4e 5956
189d0213
VZ
5957 wxGridCellAttr* attr = GetCellAttr(row, col);
5958
5959 bool isCurrent = coords == m_currentCellCoords;
508011ce 5960
f6bcfd97 5961 wxRect rect = CellToRect( row, col );
f85afd4e 5962
189d0213 5963 // if the editor is shown, we should use it and not the renderer
f6bcfd97
BP
5964 // Note: However, only if it is really _shown_, i.e. not hidden!
5965 if ( isCurrent && IsCellEditControlShown() )
189d0213 5966 {
0b190b0f
VZ
5967 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
5968 editor->PaintBackground(rect, attr);
5969 editor->DecRef();
189d0213
VZ
5970 }
5971 else
5972 {
5973 // but all the rest is drawn by the cell renderer and hence may be
5974 // customized
0b190b0f
VZ
5975 wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
5976 renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
5977 renderer->DecRef();
189d0213 5978 }
07296f0b 5979
283b7808
VZ
5980 attr->DecRef();
5981}
07296f0b 5982
283b7808 5983void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
07296f0b
RD
5984{
5985 int row = m_currentCellCoords.GetRow();
5986 int col = m_currentCellCoords.GetCol();
5987
7c1cb261 5988 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
07296f0b
RD
5989 return;
5990
f6bcfd97 5991 wxRect rect = CellToRect(row, col);
07296f0b 5992
b3a7510d
VZ
5993 // hmmm... what could we do here to show that the cell is disabled?
5994 // for now, I just draw a thinner border than for the other ones, but
5995 // it doesn't look really good
b3a7510d 5996
d2520c85
RD
5997 int penWidth = attr->IsReadOnly() ? m_cellHighlightROPenWidth : m_cellHighlightPenWidth;
5998
5999 if (penWidth > 0) {
6000
6001 // The center of th drawn line is where the position/width/height of
6002 // the rectangle is actually at, (on wxMSW atr least,) so we will
6003 // reduce the size of the rectangle to compensate for the thickness of
6004 // the line. If this is too strange on non wxMSW platforms then
6005 // please #ifdef this appropriately.
6006 rect.x += penWidth/2;
6007 rect.y += penWidth/2;
6008 rect.width -= penWidth-1;
6009 rect.height -= penWidth-1;
6010
6011
6012 // Now draw the rectangle
6013 dc.SetPen(wxPen(m_cellHighlightColour, penWidth, wxSOLID));
6014 dc.SetBrush(*wxTRANSPARENT_BRUSH);
6015 dc.DrawRectangle(rect);
6016 }
07296f0b 6017
283b7808 6018#if 0
b3a7510d 6019 // VZ: my experiments with 3d borders...
283b7808 6020
b3a7510d 6021 // how to properly set colours for arbitrary bg?
283b7808
VZ
6022 wxCoord x1 = rect.x,
6023 y1 = rect.y,
00cf1208
RR
6024 x2 = rect.x + rect.width -1,
6025 y2 = rect.y + rect.height -1;
283b7808
VZ
6026
6027 dc.SetPen(*wxWHITE_PEN);
00cf1208
RR
6028 dc.DrawLine(x1, y1, x2, y1);
6029 dc.DrawLine(x1, y1, x1, y2);
283b7808 6030
283b7808 6031 dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
00cf1208 6032 dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
283b7808
VZ
6033
6034 dc.SetPen(*wxBLACK_PEN);
6035 dc.DrawLine(x1, y2, x2, y2);
00cf1208 6036 dc.DrawLine(x2, y1, x2, y2+1);
b3a7510d 6037#endif // 0
2d66e025 6038}
f85afd4e 6039
f2d76237 6040
2d66e025
MB
6041void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
6042{
2d66e025
MB
6043 int row = coords.GetRow();
6044 int col = coords.GetCol();
7c1cb261
VZ
6045 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
6046 return;
6047
6048 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
60ff3b99 6049
2d66e025
MB
6050 // right hand border
6051 //
7c1cb261
VZ
6052 dc.DrawLine( GetColRight(col), GetRowTop(row),
6053 GetColRight(col), GetRowBottom(row) );
2d66e025
MB
6054
6055 // bottom border
6056 //
7c1cb261
VZ
6057 dc.DrawLine( GetColLeft(col), GetRowBottom(row),
6058 GetColRight(col), GetRowBottom(row) );
f85afd4e
MB
6059}
6060
b3a7510d
VZ
6061void wxGrid::DrawHighlight(wxDC& dc)
6062{
2a7750d9
MB
6063 // This if block was previously in wxGrid::OnPaint but that doesn't
6064 // seem to get called under wxGTK - MB
6065 //
6066 if ( m_currentCellCoords == wxGridNoCellCoords &&
6067 m_numRows && m_numCols )
6068 {
6069 m_currentCellCoords.Set(0, 0);
6070 }
6071
f6bcfd97 6072 if ( IsCellEditControlShown() )
99306db2
VZ
6073 {
6074 // don't show highlight when the edit control is shown
6075 return;
6076 }
6077
b3a7510d
VZ
6078 // if the active cell was repainted, repaint its highlight too because it
6079 // might have been damaged by the grid lines
6080 size_t count = m_cellsExposed.GetCount();
6081 for ( size_t n = 0; n < count; n++ )
6082 {
6083 if ( m_cellsExposed[n] == m_currentCellCoords )
6084 {
6085 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
6086 DrawCellHighlight(dc, attr);
6087 attr->DecRef();
6088
6089 break;
6090 }
6091 }
6092}
2d66e025 6093
2d66e025
MB
6094// TODO: remove this ???
6095// This is used to redraw all grid lines e.g. when the grid line colour
6096// has been changed
6097//
33ac7e6f 6098void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) )
f85afd4e 6099{
60ff3b99
VZ
6100 if ( !m_gridLinesEnabled ||
6101 !m_numRows ||
2d66e025 6102 !m_numCols ) return;
f85afd4e 6103
2d66e025 6104 int top, bottom, left, right;
796df70a 6105
f6bcfd97 6106#if 0 //#ifndef __WXGTK__
508011ce
VZ
6107 if (reg.IsEmpty())
6108 {
796df70a
SN
6109 int cw, ch;
6110 m_gridWin->GetClientSize(&cw, &ch);
6111
6112 // virtual coords of visible area
6113 //
6114 CalcUnscrolledPosition( 0, 0, &left, &top );
6115 CalcUnscrolledPosition( cw, ch, &right, &bottom );
6116 }
508011ce
VZ
6117 else
6118 {
796df70a
SN
6119 wxCoord x, y, w, h;
6120 reg.GetBox(x, y, w, h);
6121 CalcUnscrolledPosition( x, y, &left, &top );
6122 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
6123 }
8e217128
RR
6124#else
6125 int cw, ch;
6126 m_gridWin->GetClientSize(&cw, &ch);
6127 CalcUnscrolledPosition( 0, 0, &left, &top );
6128 CalcUnscrolledPosition( cw, ch, &right, &bottom );
6129#endif
f85afd4e 6130
9496deb5
MB
6131 // avoid drawing grid lines past the last row and col
6132 //
7c1cb261
VZ
6133 right = wxMin( right, GetColRight(m_numCols - 1) );
6134 bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
9496deb5 6135
2d66e025 6136 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
f85afd4e 6137
2d66e025 6138 // horizontal grid lines
f85afd4e 6139 //
60ff3b99 6140 int i;
9496deb5 6141 for ( i = 0; i < m_numRows; i++ )
f85afd4e 6142 {
6d55126d 6143 int bot = GetRowBottom(i) - 1;
7c1cb261 6144
6d55126d 6145 if ( bot > bottom )
2d66e025
MB
6146 {
6147 break;
6148 }
7c1cb261 6149
6d55126d 6150 if ( bot >= top )
2d66e025 6151 {
6d55126d 6152 dc.DrawLine( left, bot, right, bot );
2d66e025 6153 }
f85afd4e
MB
6154 }
6155
f85afd4e 6156
2d66e025
MB
6157 // vertical grid lines
6158 //
9496deb5 6159 for ( i = 0; i < m_numCols; i++ )
f85afd4e 6160 {
7c1cb261
VZ
6161 int colRight = GetColRight(i) - 1;
6162 if ( colRight > right )
2d66e025
MB
6163 {
6164 break;
6165 }
7c1cb261
VZ
6166
6167 if ( colRight >= left )
2d66e025 6168 {
7c1cb261 6169 dc.DrawLine( colRight, top, colRight, bottom );
2d66e025
MB
6170 }
6171 }
6172}
f85afd4e 6173
8f177c8e 6174
2d66e025
MB
6175void wxGrid::DrawRowLabels( wxDC& dc )
6176{
f6bcfd97 6177 if ( !m_numRows ) return;
60ff3b99 6178
2d66e025
MB
6179 size_t i;
6180 size_t numLabels = m_rowLabelsExposed.GetCount();
60ff3b99 6181
2d66e025
MB
6182 for ( i = 0; i < numLabels; i++ )
6183 {
6184 DrawRowLabel( dc, m_rowLabelsExposed[i] );
60ff3b99 6185 }
f85afd4e
MB
6186}
6187
6188
2d66e025 6189void wxGrid::DrawRowLabel( wxDC& dc, int row )
f85afd4e 6190{
7c1cb261
VZ
6191 if ( GetRowHeight(row) <= 0 )
6192 return;
60ff3b99 6193
7c1cb261
VZ
6194 int rowTop = GetRowTop(row),
6195 rowBottom = GetRowBottom(row) - 1;
b99be8fb 6196
2d66e025 6197 dc.SetPen( *wxBLACK_PEN );
b0d6ff2f 6198 dc.DrawLine( m_rowLabelWidth-1, rowTop,
7c1cb261 6199 m_rowLabelWidth-1, rowBottom );
b99be8fb 6200
7c1cb261 6201 dc.DrawLine( 0, rowBottom, m_rowLabelWidth-1, rowBottom );
b99be8fb 6202
2d66e025 6203 dc.SetPen( *wxWHITE_PEN );
7c1cb261 6204 dc.DrawLine( 0, rowTop, 0, rowBottom );
b0d6ff2f 6205 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
60ff3b99 6206
f85afd4e 6207 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
6208 dc.SetTextForeground( GetLabelTextColour() );
6209 dc.SetFont( GetLabelFont() );
8f177c8e 6210
f85afd4e 6211 int hAlign, vAlign;
2d66e025 6212 GetRowLabelAlignment( &hAlign, &vAlign );
60ff3b99 6213
2d66e025
MB
6214 wxRect rect;
6215 rect.SetX( 2 );
7c1cb261 6216 rect.SetY( GetRowTop(row) + 2 );
2d66e025 6217 rect.SetWidth( m_rowLabelWidth - 4 );
7c1cb261 6218 rect.SetHeight( GetRowHeight(row) - 4 );
60ff3b99 6219 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
f85afd4e
MB
6220}
6221
6222
2d66e025 6223void wxGrid::DrawColLabels( wxDC& dc )
f85afd4e 6224{
f6bcfd97 6225 if ( !m_numCols ) return;
60ff3b99 6226
2d66e025
MB
6227 size_t i;
6228 size_t numLabels = m_colLabelsExposed.GetCount();
60ff3b99 6229
2d66e025 6230 for ( i = 0; i < numLabels; i++ )
f85afd4e 6231 {
2d66e025 6232 DrawColLabel( dc, m_colLabelsExposed[i] );
60ff3b99 6233 }
f85afd4e
MB
6234}
6235
6236
2d66e025 6237void wxGrid::DrawColLabel( wxDC& dc, int col )
f85afd4e 6238{
7c1cb261
VZ
6239 if ( GetColWidth(col) <= 0 )
6240 return;
60ff3b99 6241
7c1cb261
VZ
6242 int colLeft = GetColLeft(col),
6243 colRight = GetColRight(col) - 1;
b99be8fb 6244
2d66e025 6245 dc.SetPen( *wxBLACK_PEN );
7c1cb261
VZ
6246 dc.DrawLine( colRight, 0,
6247 colRight, m_colLabelHeight-1 );
b99be8fb 6248
b0d6ff2f 6249 dc.DrawLine( colLeft, m_colLabelHeight-1,
7c1cb261 6250 colRight, m_colLabelHeight-1 );
b99be8fb 6251
f85afd4e 6252 dc.SetPen( *wxWHITE_PEN );
b0d6ff2f 6253 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
7c1cb261 6254 dc.DrawLine( colLeft, 0, colRight, 0 );
f85afd4e 6255
b0d6ff2f
MB
6256 dc.SetBackgroundMode( wxTRANSPARENT );
6257 dc.SetTextForeground( GetLabelTextColour() );
6258 dc.SetFont( GetLabelFont() );
8f177c8e 6259
f85afd4e 6260 dc.SetBackgroundMode( wxTRANSPARENT );
f85afd4e
MB
6261 dc.SetTextForeground( GetLabelTextColour() );
6262 dc.SetFont( GetLabelFont() );
8f177c8e 6263
f85afd4e 6264 int hAlign, vAlign;
2d66e025 6265 GetColLabelAlignment( &hAlign, &vAlign );
60ff3b99 6266
2d66e025 6267 wxRect rect;
7c1cb261 6268 rect.SetX( colLeft + 2 );
2d66e025 6269 rect.SetY( 2 );
7c1cb261 6270 rect.SetWidth( GetColWidth(col) - 4 );
2d66e025 6271 rect.SetHeight( m_colLabelHeight - 4 );
60ff3b99 6272 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
f85afd4e
MB
6273}
6274
6275
2d66e025
MB
6276void wxGrid::DrawTextRectangle( wxDC& dc,
6277 const wxString& value,
6278 const wxRect& rect,
6279 int horizAlign,
6280 int vertAlign )
f85afd4e 6281{
2d66e025
MB
6282 long textWidth, textHeight;
6283 long lineWidth, lineHeight;
6284 wxArrayString lines;
f85afd4e 6285
2d66e025
MB
6286 dc.SetClippingRegion( rect );
6287 StringToLines( value, lines );
6288 if ( lines.GetCount() )
6289 {
6290 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
6291 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
f85afd4e 6292
2d66e025
MB
6293 float x, y;
6294 switch ( horizAlign )
6295 {
4c7277db 6296 case wxALIGN_RIGHT:
2d66e025
MB
6297 x = rect.x + (rect.width - textWidth - 1);
6298 break;
f85afd4e 6299
4c7277db 6300 case wxALIGN_CENTRE:
2d66e025
MB
6301 x = rect.x + ((rect.width - textWidth)/2);
6302 break;
f85afd4e 6303
4c7277db 6304 case wxALIGN_LEFT:
2d66e025
MB
6305 default:
6306 x = rect.x + 1;
6307 break;
6308 }
f85afd4e 6309
2d66e025
MB
6310 switch ( vertAlign )
6311 {
4c7277db 6312 case wxALIGN_BOTTOM:
2d66e025
MB
6313 y = rect.y + (rect.height - textHeight - 1);
6314 break;
f85afd4e 6315
4c7277db 6316 case wxALIGN_CENTRE:
8f177c8e 6317 y = rect.y + ((rect.height - textHeight)/2);
f85afd4e
MB
6318 break;
6319
4c7277db 6320 case wxALIGN_TOP:
f85afd4e 6321 default:
8f177c8e 6322 y = rect.y + 1;
f85afd4e
MB
6323 break;
6324 }
6325
b540eb2b 6326 for ( size_t i = 0; i < lines.GetCount(); i++ )
f85afd4e 6327 {
4a64bee4 6328 dc.DrawText( lines[i], (int)x, (int)y );
f85afd4e
MB
6329 y += lineHeight;
6330 }
6331 }
8f177c8e 6332
f85afd4e 6333 dc.DestroyClippingRegion();
f85afd4e
MB
6334}
6335
6336
6337// Split multi line text up into an array of strings. Any existing
6338// contents of the string array are preserved.
6339//
6340void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
6341{
f85afd4e
MB
6342 int startPos = 0;
6343 int pos;
6d004f67 6344 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
2433bb2e 6345 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
e2b42eeb 6346
2433bb2e 6347 while ( startPos < (int)tVal.Length() )
f85afd4e 6348 {
2433bb2e 6349 pos = tVal.Mid(startPos).Find( eol );
f85afd4e
MB
6350 if ( pos < 0 )
6351 {
6352 break;
6353 }
6354 else if ( pos == 0 )
6355 {
6356 lines.Add( wxEmptyString );
6357 }
6358 else
6359 {
2433bb2e 6360 lines.Add( value.Mid(startPos, pos) );
f85afd4e
MB
6361 }
6362 startPos += pos+1;
6363 }
b540eb2b 6364 if ( startPos < (int)value.Length() )
f85afd4e
MB
6365 {
6366 lines.Add( value.Mid( startPos ) );
6367 }
6368}
6369
6370
6371void wxGrid::GetTextBoxSize( wxDC& dc,
6372 wxArrayString& lines,
6373 long *width, long *height )
6374{
6375 long w = 0;
6376 long h = 0;
6377 long lineW, lineH;
6378
b540eb2b 6379 size_t i;
f85afd4e
MB
6380 for ( i = 0; i < lines.GetCount(); i++ )
6381 {
6382 dc.GetTextExtent( lines[i], &lineW, &lineH );
6383 w = wxMax( w, lineW );
6384 h += lineH;
6385 }
6386
6387 *width = w;
6388 *height = h;
6389}
6390
f6bcfd97
BP
6391//
6392// ------ Batch processing.
6393//
6394void wxGrid::EndBatch()
6395{
6396 if ( m_batchCount > 0 )
6397 {
6398 m_batchCount--;
6399 if ( !m_batchCount )
6400 {
6401 CalcDimensions();
6402 m_rowLabelWin->Refresh();
6403 m_colLabelWin->Refresh();
6404 m_cornerLabelWin->Refresh();
6405 m_gridWin->Refresh();
6406 }
6407 }
6408}
f85afd4e 6409
d8232393
MB
6410// Use this, rather than wxWindow::Refresh(), to force an immediate
6411// repainting of the grid. Has no effect if you are already inside a
6412// BeginBatch / EndBatch block.
6413//
6414void wxGrid::ForceRefresh()
6415{
6416 BeginBatch();
6417 EndBatch();
6418}
6419
6420
f85afd4e 6421//
2d66e025 6422// ------ Edit control functions
f85afd4e
MB
6423//
6424
2d66e025
MB
6425
6426void wxGrid::EnableEditing( bool edit )
f85afd4e 6427{
2d66e025
MB
6428 // TODO: improve this ?
6429 //
6430 if ( edit != m_editable )
f85afd4e 6431 {
632efa47 6432 if(!edit) EnableCellEditControl(edit);
2d66e025 6433 m_editable = edit;
f85afd4e 6434 }
f85afd4e
MB
6435}
6436
6437
2d66e025 6438void wxGrid::EnableCellEditControl( bool enable )
f85afd4e 6439{
2c9a89e0
RD
6440 if (! m_editable)
6441 return;
6442
dcfe4c3d
SN
6443 if ( m_currentCellCoords == wxGridNoCellCoords )
6444 SetCurrentCell( 0, 0 );
60ff3b99 6445
2c9a89e0
RD
6446 if ( enable != m_cellEditCtrlEnabled )
6447 {
b54ba671
VZ
6448 // TODO allow the app to Veto() this event?
6449 SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN : wxEVT_GRID_EDITOR_HIDDEN);
6450
dcfe4c3d 6451 if ( enable )
f85afd4e 6452 {
b54ba671
VZ
6453 // this should be checked by the caller!
6454 wxASSERT_MSG( CanEnableCellControl(),
6455 _T("can't enable editing for this cell!") );
6456
6457 // do it before ShowCellEditControl()
dcfe4c3d 6458 m_cellEditCtrlEnabled = enable;
b54ba671 6459
2d66e025 6460 ShowCellEditControl();
2d66e025
MB
6461 }
6462 else
6463 {
2d66e025
MB
6464 HideCellEditControl();
6465 SaveEditControlValue();
b54ba671
VZ
6466
6467 // do it after HideCellEditControl()
dcfe4c3d 6468 m_cellEditCtrlEnabled = enable;
f85afd4e 6469 }
f85afd4e 6470 }
f85afd4e 6471}
f85afd4e 6472
b54ba671 6473bool wxGrid::IsCurrentCellReadOnly() const
283b7808 6474{
b54ba671
VZ
6475 // const_cast
6476 wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
6477 bool readonly = attr->IsReadOnly();
6478 attr->DecRef();
283b7808 6479
b54ba671
VZ
6480 return readonly;
6481}
283b7808 6482
b54ba671
VZ
6483bool wxGrid::CanEnableCellControl() const
6484{
6485 return m_editable && !IsCurrentCellReadOnly();
6486}
6487
6488bool wxGrid::IsCellEditControlEnabled() const
6489{
6490 // the cell edit control might be disable for all cells or just for the
6491 // current one if it's read only
6492 return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
283b7808
VZ
6493}
6494
f6bcfd97
BP
6495bool wxGrid::IsCellEditControlShown() const
6496{
6497 bool isShown = FALSE;
6498
6499 if ( m_cellEditCtrlEnabled )
6500 {
6501 int row = m_currentCellCoords.GetRow();
6502 int col = m_currentCellCoords.GetCol();
6503 wxGridCellAttr* attr = GetCellAttr(row, col);
6504 wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
6505 attr->DecRef();
6506
6507 if ( editor )
6508 {
6509 if ( editor->IsCreated() )
6510 {
6511 isShown = editor->GetControl()->IsShown();
6512 }
6513
6514 editor->DecRef();
6515 }
6516 }
6517
6518 return isShown;
6519}
6520
2d66e025 6521void wxGrid::ShowCellEditControl()
f85afd4e 6522{
2d66e025 6523 if ( IsCellEditControlEnabled() )
f85afd4e 6524 {
2d66e025
MB
6525 if ( !IsVisible( m_currentCellCoords ) )
6526 {
3ca6a5f0 6527 m_cellEditCtrlEnabled = FALSE;
2d66e025
MB
6528 return;
6529 }
6530 else
6531 {
2c9a89e0
RD
6532 wxRect rect = CellToRect( m_currentCellCoords );
6533 int row = m_currentCellCoords.GetRow();
6534 int col = m_currentCellCoords.GetCol();
2d66e025
MB
6535
6536 // convert to scrolled coords
6537 //
99306db2 6538 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
508011ce 6539
99306db2
VZ
6540 // done in PaintBackground()
6541#if 0
6542 // erase the highlight and the cell contents because the editor
6543 // might not cover the entire cell
6544 wxClientDC dc( m_gridWin );
6545 PrepareDC( dc );
6546 dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
6547 dc.SetPen(*wxTRANSPARENT_PEN);
6548 dc.DrawRectangle(rect);
6549#endif // 0
d2fdd8d2 6550
99306db2
VZ
6551 // cell is shifted by one pixel
6552 rect.x--;
6553 rect.y--;
f0102d2a 6554
508011ce 6555 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 6556 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
3da93aae
VZ
6557 if ( !editor->IsCreated() )
6558 {
2c9a89e0
RD
6559 editor->Create(m_gridWin, -1,
6560 new wxGridCellEditorEvtHandler(this, editor));
2d66e025
MB
6561 }
6562
b0e282b3 6563 editor->Show( TRUE, attr );
0b190b0f 6564
2c9a89e0 6565 editor->SetSize( rect );
99306db2 6566
3da93aae 6567 editor->BeginEdit(row, col, this);
0b190b0f
VZ
6568
6569 editor->DecRef();
2c9a89e0
RD
6570 attr->DecRef();
6571 }
f85afd4e
MB
6572 }
6573}
6574
6575
2d66e025 6576void wxGrid::HideCellEditControl()
f85afd4e 6577{
2d66e025 6578 if ( IsCellEditControlEnabled() )
f85afd4e 6579 {
2c9a89e0
RD
6580 int row = m_currentCellCoords.GetRow();
6581 int col = m_currentCellCoords.GetCol();
6582
3da93aae 6583 wxGridCellAttr* attr = GetCellAttr(row, col);
0b190b0f
VZ
6584 wxGridCellEditor *editor = attr->GetEditor(this, row, col);
6585 editor->Show( FALSE );
6586 editor->DecRef();
2c9a89e0
RD
6587 attr->DecRef();
6588 m_gridWin->SetFocus();
f6bcfd97
BP
6589 wxRect rect( CellToRect( row, col ) );
6590 m_gridWin->Refresh( FALSE, &rect );
f85afd4e 6591 }
2d66e025 6592}
8f177c8e 6593
2d66e025 6594
2d66e025
MB
6595void wxGrid::SaveEditControlValue()
6596{
3da93aae
VZ
6597 if ( IsCellEditControlEnabled() )
6598 {
2c9a89e0
RD
6599 int row = m_currentCellCoords.GetRow();
6600 int col = m_currentCellCoords.GetCol();
8f177c8e 6601
3da93aae 6602 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 6603 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
3324d5f5 6604 bool changed = editor->EndEdit(row, col, this);
2d66e025 6605
0b190b0f 6606 editor->DecRef();
2c9a89e0 6607 attr->DecRef();
2d66e025 6608
3da93aae
VZ
6609 if (changed)
6610 {
b54ba671 6611 SendEvent( wxEVT_GRID_CELL_CHANGE,
2d66e025
MB
6612 m_currentCellCoords.GetRow(),
6613 m_currentCellCoords.GetCol() );
6614 }
f85afd4e
MB
6615 }
6616}
6617
2d66e025
MB
6618
6619//
60ff3b99
VZ
6620// ------ Grid location functions
6621// Note that all of these functions work with the logical coordinates of
2d66e025
MB
6622// grid cells and labels so you will need to convert from device
6623// coordinates for mouse events etc.
6624//
6625
6626void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
f85afd4e 6627{
58dd5b3b
MB
6628 int row = YToRow(y);
6629 int col = XToCol(x);
6630
6631 if ( row == -1 || col == -1 )
6632 {
6633 coords = wxGridNoCellCoords;
6634 }
6635 else
6636 {
6637 coords.Set( row, col );
6638 }
2d66e025 6639}
f85afd4e 6640
8f177c8e 6641
2d66e025
MB
6642int wxGrid::YToRow( int y )
6643{
6644 int i;
8f177c8e 6645
2d66e025 6646 for ( i = 0; i < m_numRows; i++ )
f85afd4e 6647 {
7c1cb261
VZ
6648 if ( y < GetRowBottom(i) )
6649 return i;
f85afd4e 6650 }
2d66e025 6651
4ee5fc9c 6652 return -1;
f85afd4e
MB
6653}
6654
2d66e025
MB
6655
6656int wxGrid::XToCol( int x )
f85afd4e 6657{
2d66e025 6658 int i;
8f177c8e 6659
2d66e025 6660 for ( i = 0; i < m_numCols; i++ )
f85afd4e 6661 {
7c1cb261
VZ
6662 if ( x < GetColRight(i) )
6663 return i;
f85afd4e
MB
6664 }
6665
4ee5fc9c 6666 return -1;
2d66e025 6667}
8f177c8e 6668
2d66e025
MB
6669
6670// return the row number that that the y coord is near the edge of, or
6671// -1 if not near an edge
6672//
6673int wxGrid::YToEdgeOfRow( int y )
6674{
6675 int i, d;
6676
6677 for ( i = 0; i < m_numRows; i++ )
6678 {
7c1cb261 6679 if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
f85afd4e 6680 {
7c1cb261
VZ
6681 d = abs( y - GetRowBottom(i) );
6682 if ( d < WXGRID_LABEL_EDGE_ZONE )
6683 return i;
f85afd4e 6684 }
f85afd4e 6685 }
2d66e025
MB
6686
6687 return -1;
6688}
6689
6690
6691// return the col number that that the x coord is near the edge of, or
6692// -1 if not near an edge
6693//
6694int wxGrid::XToEdgeOfCol( int x )
6695{
6696 int i, d;
6697
6698 for ( i = 0; i < m_numCols; i++ )
f85afd4e 6699 {
7c1cb261 6700 if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
2d66e025 6701 {
7c1cb261
VZ
6702 d = abs( x - GetColRight(i) );
6703 if ( d < WXGRID_LABEL_EDGE_ZONE )
6704 return i;
2d66e025 6705 }
f85afd4e 6706 }
2d66e025
MB
6707
6708 return -1;
f85afd4e
MB
6709}
6710
2d66e025
MB
6711
6712wxRect wxGrid::CellToRect( int row, int col )
f85afd4e 6713{
2d66e025 6714 wxRect rect( -1, -1, -1, -1 );
f85afd4e 6715
2d66e025
MB
6716 if ( row >= 0 && row < m_numRows &&
6717 col >= 0 && col < m_numCols )
f85afd4e 6718 {
7c1cb261
VZ
6719 rect.x = GetColLeft(col);
6720 rect.y = GetRowTop(row);
6721 rect.width = GetColWidth(col);
6722 rect.height = GetRowHeight(row);
f85afd4e
MB
6723 }
6724
f6bcfd97
BP
6725 // if grid lines are enabled, then the area of the cell is a bit smaller
6726 if (m_gridLinesEnabled) {
6727 rect.width -= 1;
6728 rect.height -= 1;
6729 }
2d66e025
MB
6730 return rect;
6731}
6732
6733
6734bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
6735{
6736 // get the cell rectangle in logical coords
6737 //
6738 wxRect r( CellToRect( row, col ) );
60ff3b99 6739
2d66e025
MB
6740 // convert to device coords
6741 //
6742 int left, top, right, bottom;
6743 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6744 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 6745
2d66e025
MB
6746 // check against the client area of the grid window
6747 //
6748 int cw, ch;
6749 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 6750
2d66e025 6751 if ( wholeCellVisible )
f85afd4e 6752 {
2d66e025 6753 // is the cell wholly visible ?
8f177c8e 6754 //
2d66e025
MB
6755 return ( left >= 0 && right <= cw &&
6756 top >= 0 && bottom <= ch );
6757 }
6758 else
6759 {
6760 // is the cell partly visible ?
6761 //
6762 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
6763 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
6764 }
6765}
6766
6767
6768// make the specified cell location visible by doing a minimal amount
6769// of scrolling
6770//
6771void wxGrid::MakeCellVisible( int row, int col )
6772{
6773 int i;
60ff3b99 6774 int xpos = -1, ypos = -1;
2d66e025
MB
6775
6776 if ( row >= 0 && row < m_numRows &&
6777 col >= 0 && col < m_numCols )
6778 {
6779 // get the cell rectangle in logical coords
6780 //
6781 wxRect r( CellToRect( row, col ) );
60ff3b99 6782
2d66e025
MB
6783 // convert to device coords
6784 //
6785 int left, top, right, bottom;
6786 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
6787 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
60ff3b99 6788
2d66e025
MB
6789 int cw, ch;
6790 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 6791
2d66e025 6792 if ( top < 0 )
3f296516 6793 {
2d66e025 6794 ypos = r.GetTop();
3f296516 6795 }
2d66e025
MB
6796 else if ( bottom > ch )
6797 {
6798 int h = r.GetHeight();
6799 ypos = r.GetTop();
6800 for ( i = row-1; i >= 0; i-- )
6801 {
7c1cb261
VZ
6802 int rowHeight = GetRowHeight(i);
6803 if ( h + rowHeight > ch )
6804 break;
2d66e025 6805
7c1cb261
VZ
6806 h += rowHeight;
6807 ypos -= rowHeight;
2d66e025 6808 }
f0102d2a
VZ
6809
6810 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
6811 // have rounding errors (this is important, because if we do, we
6812 // might not scroll at all and some cells won't be redrawn)
6813 ypos += GRID_SCROLL_LINE / 2;
2d66e025
MB
6814 }
6815
6816 if ( left < 0 )
6817 {
6818 xpos = r.GetLeft();
6819 }
6820 else if ( right > cw )
6821 {
6822 int w = r.GetWidth();
6823 xpos = r.GetLeft();
6824 for ( i = col-1; i >= 0; i-- )
6825 {
7c1cb261
VZ
6826 int colWidth = GetColWidth(i);
6827 if ( w + colWidth > cw )
6828 break;
2d66e025 6829
7c1cb261
VZ
6830 w += colWidth;
6831 xpos -= colWidth;
2d66e025 6832 }
f0102d2a
VZ
6833
6834 // see comment for ypos above
6835 xpos += GRID_SCROLL_LINE / 2;
2d66e025
MB
6836 }
6837
6838 if ( xpos != -1 || ypos != -1 )
6839 {
f0102d2a
VZ
6840 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
6841 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
2d66e025
MB
6842 Scroll( xpos, ypos );
6843 AdjustScrollbars();
6844 }
6845 }
6846}
6847
6848
6849//
6850// ------ Grid cursor movement functions
6851//
6852
5c8fc7c1 6853bool wxGrid::MoveCursorUp( bool expandSelection )
2d66e025
MB
6854{
6855 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6856 m_currentCellCoords.GetRow() >= 0 )
2d66e025 6857 {
f6bcfd97 6858 if ( expandSelection)
d95b0c2b
SN
6859 {
6860 if ( m_selectingKeyboard == wxGridNoCellCoords )
6861 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6862 if ( m_selectingKeyboard.GetRow() > 0 )
6863 {
6864 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
6865 MakeCellVisible( m_selectingKeyboard.GetRow(),
6866 m_selectingKeyboard.GetCol() );
c9097836 6867 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6868 }
d95b0c2b 6869 }
f6bcfd97 6870 else if ( m_currentCellCoords.GetRow() > 0 )
aa5e1f75
SN
6871 {
6872 ClearSelection();
6873 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
6874 m_currentCellCoords.GetCol() );
d95b0c2b
SN
6875 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
6876 m_currentCellCoords.GetCol() );
aa5e1f75 6877 }
f6bcfd97
BP
6878 else
6879 return FALSE;
8f177c8e 6880 return TRUE;
f85afd4e 6881 }
2d66e025
MB
6882
6883 return FALSE;
6884}
6885
6886
5c8fc7c1 6887bool wxGrid::MoveCursorDown( bool expandSelection )
2d66e025 6888{
2d66e025 6889 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6890 m_currentCellCoords.GetRow() < m_numRows )
f85afd4e 6891 {
5c8fc7c1 6892 if ( expandSelection )
d95b0c2b
SN
6893 {
6894 if ( m_selectingKeyboard == wxGridNoCellCoords )
6895 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6896 if ( m_selectingKeyboard.GetRow() < m_numRows-1 )
6897 {
6898 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
6899 MakeCellVisible( m_selectingKeyboard.GetRow(),
6900 m_selectingKeyboard.GetCol() );
c9097836 6901 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6902 }
d95b0c2b 6903 }
f6bcfd97 6904 else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
aa5e1f75
SN
6905 {
6906 ClearSelection();
6907 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
6908 m_currentCellCoords.GetCol() );
d95b0c2b
SN
6909 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
6910 m_currentCellCoords.GetCol() );
aa5e1f75 6911 }
f6bcfd97
BP
6912 else
6913 return FALSE;
2d66e025 6914 return TRUE;
f85afd4e 6915 }
2d66e025
MB
6916
6917 return FALSE;
f85afd4e
MB
6918}
6919
2d66e025 6920
5c8fc7c1 6921bool wxGrid::MoveCursorLeft( bool expandSelection )
f85afd4e 6922{
2d66e025 6923 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6924 m_currentCellCoords.GetCol() >= 0 )
2d66e025 6925 {
5c8fc7c1 6926 if ( expandSelection )
d95b0c2b
SN
6927 {
6928 if ( m_selectingKeyboard == wxGridNoCellCoords )
6929 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6930 if ( m_selectingKeyboard.GetCol() > 0 )
6931 {
6932 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
6933 MakeCellVisible( m_selectingKeyboard.GetRow(),
6934 m_selectingKeyboard.GetCol() );
c9097836 6935 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6936 }
d95b0c2b 6937 }
f6bcfd97 6938 else if ( m_currentCellCoords.GetCol() > 0 )
aa5e1f75
SN
6939 {
6940 ClearSelection();
6941 MakeCellVisible( m_currentCellCoords.GetRow(),
6942 m_currentCellCoords.GetCol() - 1 );
d95b0c2b
SN
6943 SetCurrentCell( m_currentCellCoords.GetRow(),
6944 m_currentCellCoords.GetCol() - 1 );
aa5e1f75 6945 }
f6bcfd97
BP
6946 else
6947 return FALSE;
2d66e025
MB
6948 return TRUE;
6949 }
6950
6951 return FALSE;
6952}
6953
6954
5c8fc7c1 6955bool wxGrid::MoveCursorRight( bool expandSelection )
2d66e025
MB
6956{
6957 if ( m_currentCellCoords != wxGridNoCellCoords &&
f6bcfd97 6958 m_currentCellCoords.GetCol() < m_numCols )
f85afd4e 6959 {
5c8fc7c1 6960 if ( expandSelection )
d95b0c2b
SN
6961 {
6962 if ( m_selectingKeyboard == wxGridNoCellCoords )
6963 m_selectingKeyboard = m_currentCellCoords;
f6bcfd97
BP
6964 if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
6965 {
6966 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
6967 MakeCellVisible( m_selectingKeyboard.GetRow(),
6968 m_selectingKeyboard.GetCol() );
c9097836 6969 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
f6bcfd97 6970 }
d95b0c2b 6971 }
f6bcfd97 6972 else if ( m_currentCellCoords.GetCol() < m_numCols - 1 )
aa5e1f75
SN
6973 {
6974 ClearSelection();
6975 MakeCellVisible( m_currentCellCoords.GetRow(),
6976 m_currentCellCoords.GetCol() + 1 );
6977 SetCurrentCell( m_currentCellCoords.GetRow(),
d95b0c2b 6978 m_currentCellCoords.GetCol() + 1 );
aa5e1f75 6979 }
f6bcfd97
BP
6980 else
6981 return FALSE;
2d66e025 6982 return TRUE;
f85afd4e 6983 }
8f177c8e 6984
2d66e025
MB
6985 return FALSE;
6986}
6987
6988
6989bool wxGrid::MovePageUp()
6990{
6991 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 6992
2d66e025
MB
6993 int row = m_currentCellCoords.GetRow();
6994 if ( row > 0 )
f85afd4e 6995 {
2d66e025
MB
6996 int cw, ch;
6997 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 6998
7c1cb261 6999 int y = GetRowTop(row);
2d66e025
MB
7000 int newRow = YToRow( y - ch + 1 );
7001 if ( newRow == -1 )
7002 {
7003 newRow = 0;
7004 }
60ff3b99 7005 else if ( newRow == row )
2d66e025
MB
7006 {
7007 newRow = row - 1;
7008 }
8f177c8e 7009
2d66e025
MB
7010 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
7011 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 7012
f85afd4e
MB
7013 return TRUE;
7014 }
2d66e025
MB
7015
7016 return FALSE;
7017}
7018
7019bool wxGrid::MovePageDown()
7020{
7021 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
60ff3b99 7022
2d66e025
MB
7023 int row = m_currentCellCoords.GetRow();
7024 if ( row < m_numRows )
f85afd4e 7025 {
2d66e025
MB
7026 int cw, ch;
7027 m_gridWin->GetClientSize( &cw, &ch );
60ff3b99 7028
7c1cb261 7029 int y = GetRowTop(row);
2d66e025
MB
7030 int newRow = YToRow( y + ch );
7031 if ( newRow == -1 )
7032 {
7033 newRow = m_numRows - 1;
7034 }
60ff3b99 7035 else if ( newRow == row )
2d66e025
MB
7036 {
7037 newRow = row + 1;
7038 }
7039
7040 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
7041 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
60ff3b99 7042
2d66e025 7043 return TRUE;
f85afd4e 7044 }
2d66e025
MB
7045
7046 return FALSE;
f85afd4e 7047}
8f177c8e 7048
5c8fc7c1 7049bool wxGrid::MoveCursorUpBlock( bool expandSelection )
2d66e025
MB
7050{
7051 if ( m_table &&
7052 m_currentCellCoords != wxGridNoCellCoords &&
7053 m_currentCellCoords.GetRow() > 0 )
7054 {
7055 int row = m_currentCellCoords.GetRow();
7056 int col = m_currentCellCoords.GetCol();
7057
7058 if ( m_table->IsEmptyCell(row, col) )
7059 {
7060 // starting in an empty cell: find the next block of
7061 // non-empty cells
7062 //
7063 while ( row > 0 )
7064 {
7065 row-- ;
7066 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7067 }
7068 }
7069 else if ( m_table->IsEmptyCell(row-1, col) )
7070 {
7071 // starting at the top of a block: find the next block
7072 //
7073 row--;
7074 while ( row > 0 )
7075 {
7076 row-- ;
7077 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7078 }
7079 }
7080 else
7081 {
7082 // starting within a block: find the top of the block
7083 //
7084 while ( row > 0 )
7085 {
7086 row-- ;
7087 if ( m_table->IsEmptyCell(row, col) )
7088 {
7089 row++ ;
7090 break;
7091 }
7092 }
7093 }
f85afd4e 7094
2d66e025 7095 MakeCellVisible( row, col );
5c8fc7c1 7096 if ( expandSelection )
d95b0c2b
SN
7097 {
7098 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7099 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7100 }
7101 else
aa5e1f75
SN
7102 {
7103 ClearSelection();
7104 SetCurrentCell( row, col );
7105 }
2d66e025
MB
7106 return TRUE;
7107 }
f85afd4e 7108
2d66e025
MB
7109 return FALSE;
7110}
f85afd4e 7111
5c8fc7c1 7112bool wxGrid::MoveCursorDownBlock( bool expandSelection )
f85afd4e 7113{
2d66e025
MB
7114 if ( m_table &&
7115 m_currentCellCoords != wxGridNoCellCoords &&
7116 m_currentCellCoords.GetRow() < m_numRows-1 )
f85afd4e 7117 {
2d66e025
MB
7118 int row = m_currentCellCoords.GetRow();
7119 int col = m_currentCellCoords.GetCol();
7120
7121 if ( m_table->IsEmptyCell(row, col) )
7122 {
7123 // starting in an empty cell: find the next block of
7124 // non-empty cells
7125 //
7126 while ( row < m_numRows-1 )
7127 {
7128 row++ ;
7129 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7130 }
7131 }
7132 else if ( m_table->IsEmptyCell(row+1, col) )
7133 {
7134 // starting at the bottom of a block: find the next block
7135 //
7136 row++;
7137 while ( row < m_numRows-1 )
7138 {
7139 row++ ;
7140 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7141 }
7142 }
7143 else
7144 {
7145 // starting within a block: find the bottom of the block
7146 //
7147 while ( row < m_numRows-1 )
7148 {
7149 row++ ;
7150 if ( m_table->IsEmptyCell(row, col) )
7151 {
7152 row-- ;
7153 break;
7154 }
7155 }
7156 }
7157
7158 MakeCellVisible( row, col );
5c8fc7c1 7159 if ( expandSelection )
d95b0c2b
SN
7160 {
7161 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7162 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7163 }
7164 else
aa5e1f75
SN
7165 {
7166 ClearSelection();
7167 SetCurrentCell( row, col );
7168 }
2d66e025
MB
7169
7170 return TRUE;
f85afd4e 7171 }
f85afd4e 7172
2d66e025
MB
7173 return FALSE;
7174}
f85afd4e 7175
5c8fc7c1 7176bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
f85afd4e 7177{
2d66e025
MB
7178 if ( m_table &&
7179 m_currentCellCoords != wxGridNoCellCoords &&
7180 m_currentCellCoords.GetCol() > 0 )
f85afd4e 7181 {
2d66e025
MB
7182 int row = m_currentCellCoords.GetRow();
7183 int col = m_currentCellCoords.GetCol();
7184
7185 if ( m_table->IsEmptyCell(row, col) )
7186 {
7187 // starting in an empty cell: find the next block of
7188 // non-empty cells
7189 //
7190 while ( col > 0 )
7191 {
7192 col-- ;
7193 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7194 }
7195 }
7196 else if ( m_table->IsEmptyCell(row, col-1) )
7197 {
7198 // starting at the left of a block: find the next block
7199 //
7200 col--;
7201 while ( col > 0 )
7202 {
7203 col-- ;
7204 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7205 }
7206 }
7207 else
7208 {
7209 // starting within a block: find the left of the block
7210 //
7211 while ( col > 0 )
7212 {
7213 col-- ;
7214 if ( m_table->IsEmptyCell(row, col) )
7215 {
7216 col++ ;
7217 break;
7218 }
7219 }
7220 }
f85afd4e 7221
2d66e025 7222 MakeCellVisible( row, col );
5c8fc7c1 7223 if ( expandSelection )
d95b0c2b
SN
7224 {
7225 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7226 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7227 }
7228 else
aa5e1f75
SN
7229 {
7230 ClearSelection();
7231 SetCurrentCell( row, col );
7232 }
8f177c8e 7233
2d66e025 7234 return TRUE;
f85afd4e 7235 }
2d66e025
MB
7236
7237 return FALSE;
f85afd4e
MB
7238}
7239
5c8fc7c1 7240bool wxGrid::MoveCursorRightBlock( bool expandSelection )
f85afd4e 7241{
2d66e025
MB
7242 if ( m_table &&
7243 m_currentCellCoords != wxGridNoCellCoords &&
7244 m_currentCellCoords.GetCol() < m_numCols-1 )
f85afd4e 7245 {
2d66e025
MB
7246 int row = m_currentCellCoords.GetRow();
7247 int col = m_currentCellCoords.GetCol();
8f177c8e 7248
2d66e025
MB
7249 if ( m_table->IsEmptyCell(row, col) )
7250 {
7251 // starting in an empty cell: find the next block of
7252 // non-empty cells
7253 //
7254 while ( col < m_numCols-1 )
7255 {
7256 col++ ;
7257 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7258 }
7259 }
7260 else if ( m_table->IsEmptyCell(row, col+1) )
7261 {
7262 // starting at the right of a block: find the next block
7263 //
7264 col++;
7265 while ( col < m_numCols-1 )
7266 {
7267 col++ ;
7268 if ( !(m_table->IsEmptyCell(row, col)) ) break;
7269 }
7270 }
7271 else
7272 {
7273 // starting within a block: find the right of the block
7274 //
7275 while ( col < m_numCols-1 )
7276 {
7277 col++ ;
7278 if ( m_table->IsEmptyCell(row, col) )
7279 {
7280 col-- ;
7281 break;
7282 }
7283 }
7284 }
8f177c8e 7285
2d66e025 7286 MakeCellVisible( row, col );
5c8fc7c1 7287 if ( expandSelection )
d95b0c2b
SN
7288 {
7289 m_selectingKeyboard = wxGridCellCoords( row, col );
c9097836 7290 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
d95b0c2b
SN
7291 }
7292 else
aa5e1f75
SN
7293 {
7294 ClearSelection();
7295 SetCurrentCell( row, col );
7296 }
f85afd4e 7297
2d66e025 7298 return TRUE;
f85afd4e 7299 }
2d66e025
MB
7300
7301 return FALSE;
f85afd4e
MB
7302}
7303
7304
2d66e025 7305
f85afd4e 7306//
2d66e025 7307// ------ Label values and formatting
f85afd4e
MB
7308//
7309
7310void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
7311{
7312 *horiz = m_rowLabelHorizAlign;
7313 *vert = m_rowLabelVertAlign;
7314}
7315
7316void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
7317{
7318 *horiz = m_colLabelHorizAlign;
7319 *vert = m_colLabelVertAlign;
7320}
7321
7322wxString wxGrid::GetRowLabelValue( int row )
7323{
7324 if ( m_table )
7325 {
7326 return m_table->GetRowLabelValue( row );
7327 }
7328 else
7329 {
7330 wxString s;
7331 s << row;
7332 return s;
7333 }
7334}
7335
7336wxString wxGrid::GetColLabelValue( int col )
7337{
7338 if ( m_table )
7339 {
7340 return m_table->GetColLabelValue( col );
7341 }
7342 else
7343 {
7344 wxString s;
7345 s << col;
7346 return s;
7347 }
7348}
7349
2e8cd977 7350
f85afd4e
MB
7351void wxGrid::SetRowLabelSize( int width )
7352{
2e8cd977
MB
7353 width = wxMax( width, 0 );
7354 if ( width != m_rowLabelWidth )
7355 {
2e8cd977
MB
7356 if ( width == 0 )
7357 {
7358 m_rowLabelWin->Show( FALSE );
7807d81c 7359 m_cornerLabelWin->Show( FALSE );
2e8cd977 7360 }
7807d81c 7361 else if ( m_rowLabelWidth == 0 )
2e8cd977 7362 {
7807d81c
MB
7363 m_rowLabelWin->Show( TRUE );
7364 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
2e8cd977 7365 }
b99be8fb 7366
2e8cd977 7367 m_rowLabelWidth = width;
7807d81c
MB
7368 CalcWindowSizes();
7369 Refresh( TRUE );
2e8cd977 7370 }
f85afd4e
MB
7371}
7372
2e8cd977 7373
f85afd4e
MB
7374void wxGrid::SetColLabelSize( int height )
7375{
7807d81c 7376 height = wxMax( height, 0 );
2e8cd977
MB
7377 if ( height != m_colLabelHeight )
7378 {
2e8cd977
MB
7379 if ( height == 0 )
7380 {
2e8cd977 7381 m_colLabelWin->Show( FALSE );
7807d81c 7382 m_cornerLabelWin->Show( FALSE );
2e8cd977 7383 }
7807d81c 7384 else if ( m_colLabelHeight == 0 )
2e8cd977 7385 {
7807d81c
MB
7386 m_colLabelWin->Show( TRUE );
7387 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
2e8cd977 7388 }
7807d81c 7389
2e8cd977 7390 m_colLabelHeight = height;
7807d81c
MB
7391 CalcWindowSizes();
7392 Refresh( TRUE );
2e8cd977 7393 }
f85afd4e
MB
7394}
7395
2e8cd977 7396
f85afd4e
MB
7397void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
7398{
2d66e025
MB
7399 if ( m_labelBackgroundColour != colour )
7400 {
7401 m_labelBackgroundColour = colour;
7402 m_rowLabelWin->SetBackgroundColour( colour );
7403 m_colLabelWin->SetBackgroundColour( colour );
7404 m_cornerLabelWin->SetBackgroundColour( colour );
7405
7406 if ( !GetBatchCount() )
7407 {
7408 m_rowLabelWin->Refresh();
7409 m_colLabelWin->Refresh();
7410 m_cornerLabelWin->Refresh();
7411 }
7412 }
f85afd4e
MB
7413}
7414
7415void wxGrid::SetLabelTextColour( const wxColour& colour )
7416{
2d66e025
MB
7417 if ( m_labelTextColour != colour )
7418 {
7419 m_labelTextColour = colour;
7420 if ( !GetBatchCount() )
7421 {
7422 m_rowLabelWin->Refresh();
7423 m_colLabelWin->Refresh();
7424 }
7425 }
f85afd4e
MB
7426}
7427
7428void wxGrid::SetLabelFont( const wxFont& font )
7429{
7430 m_labelFont = font;
2d66e025
MB
7431 if ( !GetBatchCount() )
7432 {
7433 m_rowLabelWin->Refresh();
7434 m_colLabelWin->Refresh();
7435 }
f85afd4e
MB
7436}
7437
7438void wxGrid::SetRowLabelAlignment( int horiz, int vert )
7439{
4c7277db
MB
7440 // allow old (incorrect) defs to be used
7441 switch ( horiz )
7442 {
7443 case wxLEFT: horiz = wxALIGN_LEFT; break;
7444 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
7445 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
7446 }
84912ef8 7447
4c7277db
MB
7448 switch ( vert )
7449 {
7450 case wxTOP: vert = wxALIGN_TOP; break;
7451 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
7452 case wxCENTRE: vert = wxALIGN_CENTRE; break;
7453 }
84912ef8 7454
4c7277db 7455 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
f85afd4e
MB
7456 {
7457 m_rowLabelHorizAlign = horiz;
7458 }
8f177c8e 7459
4c7277db 7460 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
f85afd4e
MB
7461 {
7462 m_rowLabelVertAlign = vert;
7463 }
7464
2d66e025
MB
7465 if ( !GetBatchCount() )
7466 {
7467 m_rowLabelWin->Refresh();
60ff3b99 7468 }
f85afd4e
MB
7469}
7470
7471void wxGrid::SetColLabelAlignment( int horiz, int vert )
7472{
4c7277db
MB
7473 // allow old (incorrect) defs to be used
7474 switch ( horiz )
7475 {
7476 case wxLEFT: horiz = wxALIGN_LEFT; break;
7477 case wxRIGHT: horiz = wxALIGN_RIGHT; break;
7478 case wxCENTRE: horiz = wxALIGN_CENTRE; break;
7479 }
84912ef8 7480
4c7277db
MB
7481 switch ( vert )
7482 {
7483 case wxTOP: vert = wxALIGN_TOP; break;
7484 case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
7485 case wxCENTRE: vert = wxALIGN_CENTRE; break;
7486 }
84912ef8 7487
4c7277db 7488 if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
f85afd4e
MB
7489 {
7490 m_colLabelHorizAlign = horiz;
7491 }
8f177c8e 7492
4c7277db 7493 if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
f85afd4e
MB
7494 {
7495 m_colLabelVertAlign = vert;
7496 }
7497
2d66e025
MB
7498 if ( !GetBatchCount() )
7499 {
2d66e025 7500 m_colLabelWin->Refresh();
60ff3b99 7501 }
f85afd4e
MB
7502}
7503
7504void wxGrid::SetRowLabelValue( int row, const wxString& s )
7505{
7506 if ( m_table )
7507 {
7508 m_table->SetRowLabelValue( row, s );
2d66e025
MB
7509 if ( !GetBatchCount() )
7510 {
70c7a608
SN
7511 wxRect rect = CellToRect( row, 0);
7512 if ( rect.height > 0 )
7513 {
cb309039 7514 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
b1944ebc 7515 rect.x = 0;
70c7a608
SN
7516 rect.width = m_rowLabelWidth;
7517 m_rowLabelWin->Refresh( TRUE, &rect );
7518 }
2d66e025 7519 }
f85afd4e
MB
7520 }
7521}
7522
7523void wxGrid::SetColLabelValue( int col, const wxString& s )
7524{
7525 if ( m_table )
7526 {
7527 m_table->SetColLabelValue( col, s );
2d66e025
MB
7528 if ( !GetBatchCount() )
7529 {
70c7a608
SN
7530 wxRect rect = CellToRect( 0, col );
7531 if ( rect.width > 0 )
7532 {
cb309039 7533 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
b1944ebc 7534 rect.y = 0;
70c7a608
SN
7535 rect.height = m_colLabelHeight;
7536 m_colLabelWin->Refresh( TRUE, &rect );
7537 }
2d66e025 7538 }
f85afd4e
MB
7539 }
7540}
7541
7542void wxGrid::SetGridLineColour( const wxColour& colour )
7543{
2d66e025
MB
7544 if ( m_gridLineColour != colour )
7545 {
7546 m_gridLineColour = colour;
60ff3b99 7547
2d66e025
MB
7548 wxClientDC dc( m_gridWin );
7549 PrepareDC( dc );
c6a51dcd 7550 DrawAllGridLines( dc, wxRegion() );
2d66e025 7551 }
f85afd4e
MB
7552}
7553
f6bcfd97
BP
7554
7555void wxGrid::SetCellHighlightColour( const wxColour& colour )
7556{
7557 if ( m_cellHighlightColour != colour )
7558 {
7559 m_cellHighlightColour = colour;
7560
7561 wxClientDC dc( m_gridWin );
7562 PrepareDC( dc );
7563 wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
7564 DrawCellHighlight(dc, attr);
7565 attr->DecRef();
7566 }
7567}
7568
d2520c85
RD
7569void wxGrid::SetCellHighlightPenWidth(int width)
7570{
7571 if (m_cellHighlightPenWidth != width) {
7572 m_cellHighlightPenWidth = width;
7573
7574 // Just redrawing the cell highlight is not enough since that won't
7575 // make any visible change if the the thickness is getting smaller.
7576 int row = m_currentCellCoords.GetRow();
7577 int col = m_currentCellCoords.GetCol();
7578 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
7579 return;
7580 wxRect rect = CellToRect(row, col);
7581 m_gridWin->Refresh(TRUE, &rect);
7582 }
7583}
7584
7585void wxGrid::SetCellHighlightROPenWidth(int width)
7586{
7587 if (m_cellHighlightROPenWidth != width) {
7588 m_cellHighlightROPenWidth = width;
7589
7590 // Just redrawing the cell highlight is not enough since that won't
7591 // make any visible change if the the thickness is getting smaller.
7592 int row = m_currentCellCoords.GetRow();
7593 int col = m_currentCellCoords.GetCol();
7594 if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
7595 return;
7596 wxRect rect = CellToRect(row, col);
7597 m_gridWin->Refresh(TRUE, &rect);
7598 }
7599}
7600
f85afd4e
MB
7601void wxGrid::EnableGridLines( bool enable )
7602{
7603 if ( enable != m_gridLinesEnabled )
7604 {
7605 m_gridLinesEnabled = enable;
2d66e025
MB
7606
7607 if ( !GetBatchCount() )
7608 {
7609 if ( enable )
7610 {
7611 wxClientDC dc( m_gridWin );
7612 PrepareDC( dc );
c6a51dcd 7613 DrawAllGridLines( dc, wxRegion() );
2d66e025
MB
7614 }
7615 else
7616 {
7617 m_gridWin->Refresh();
7618 }
7619 }
f85afd4e
MB
7620 }
7621}
7622
7623
7624int wxGrid::GetDefaultRowSize()
7625{
7626 return m_defaultRowHeight;
7627}
7628
7629int wxGrid::GetRowSize( int row )
7630{
b99be8fb
VZ
7631 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
7632
7c1cb261 7633 return GetRowHeight(row);
f85afd4e
MB
7634}
7635
7636int wxGrid::GetDefaultColSize()
7637{
7638 return m_defaultColWidth;
7639}
7640
7641int wxGrid::GetColSize( int col )
7642{
b99be8fb
VZ
7643 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
7644
7c1cb261 7645 return GetColWidth(col);
f85afd4e
MB
7646}
7647
2e9a6788
VZ
7648// ============================================================================
7649// access to the grid attributes: each of them has a default value in the grid
7650// itself and may be overidden on a per-cell basis
7651// ============================================================================
7652
7653// ----------------------------------------------------------------------------
7654// setting default attributes
7655// ----------------------------------------------------------------------------
7656
7657void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
7658{
2796cce3 7659 m_defaultCellAttr->SetBackgroundColour(col);
c916e13b
RR
7660#ifdef __WXGTK__
7661 m_gridWin->SetBackgroundColour(col);
7662#endif
2e9a6788
VZ
7663}
7664
7665void wxGrid::SetDefaultCellTextColour( const wxColour& col )
7666{
2796cce3 7667 m_defaultCellAttr->SetTextColour(col);
2e9a6788
VZ
7668}
7669
7670void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
7671{
2796cce3 7672 m_defaultCellAttr->SetAlignment(horiz, vert);
2e9a6788
VZ
7673}
7674
7675void wxGrid::SetDefaultCellFont( const wxFont& font )
7676{
2796cce3
RD
7677 m_defaultCellAttr->SetFont(font);
7678}
7679
0ba143c9
RD
7680void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
7681{
7682 m_defaultCellAttr->SetRenderer(renderer);
7683}
2e9a6788 7684
0ba143c9
RD
7685void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
7686{
7687 m_defaultCellAttr->SetEditor(editor);
7688}
9b4aede2 7689
2e9a6788
VZ
7690// ----------------------------------------------------------------------------
7691// access to the default attrbiutes
7692// ----------------------------------------------------------------------------
7693
f85afd4e
MB
7694wxColour wxGrid::GetDefaultCellBackgroundColour()
7695{
2796cce3 7696 return m_defaultCellAttr->GetBackgroundColour();
f85afd4e
MB
7697}
7698
2e9a6788
VZ
7699wxColour wxGrid::GetDefaultCellTextColour()
7700{
2796cce3 7701 return m_defaultCellAttr->GetTextColour();
2e9a6788
VZ
7702}
7703
7704wxFont wxGrid::GetDefaultCellFont()
7705{
2796cce3 7706 return m_defaultCellAttr->GetFont();
2e9a6788
VZ
7707}
7708
7709void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
7710{
2796cce3 7711 m_defaultCellAttr->GetAlignment(horiz, vert);
2e9a6788
VZ
7712}
7713
0ba143c9
RD
7714wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
7715{
0b190b0f 7716 return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
0ba143c9 7717}
ab79958a 7718
0ba143c9
RD
7719wxGridCellEditor *wxGrid::GetDefaultEditor() const
7720{
28a77bc4 7721 return m_defaultCellAttr->GetEditor(NULL,0,0);
0ba143c9 7722}
9b4aede2 7723
2e9a6788
VZ
7724// ----------------------------------------------------------------------------
7725// access to cell attributes
7726// ----------------------------------------------------------------------------
7727
b99be8fb 7728wxColour wxGrid::GetCellBackgroundColour(int row, int col)
f85afd4e 7729{
0a976765 7730 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7731 wxColour colour = attr->GetBackgroundColour();
39bcce60 7732 attr->DecRef();
b99be8fb 7733 return colour;
f85afd4e
MB
7734}
7735
b99be8fb 7736wxColour wxGrid::GetCellTextColour( int row, int col )
f85afd4e 7737{
0a976765 7738 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7739 wxColour colour = attr->GetTextColour();
39bcce60 7740 attr->DecRef();
b99be8fb 7741 return colour;
f85afd4e
MB
7742}
7743
b99be8fb 7744wxFont wxGrid::GetCellFont( int row, int col )
f85afd4e 7745{
0a976765 7746 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7747 wxFont font = attr->GetFont();
39bcce60 7748 attr->DecRef();
b99be8fb 7749 return font;
f85afd4e
MB
7750}
7751
b99be8fb 7752void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
f85afd4e 7753{
0a976765 7754 wxGridCellAttr *attr = GetCellAttr(row, col);
2796cce3 7755 attr->GetAlignment(horiz, vert);
39bcce60 7756 attr->DecRef();
2e9a6788
VZ
7757}
7758
2796cce3
RD
7759wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
7760{
7761 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 7762 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
2796cce3 7763 attr->DecRef();
0b190b0f 7764
2796cce3
RD
7765 return renderer;
7766}
7767
9b4aede2
RD
7768wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
7769{
7770 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 7771 wxGridCellEditor* editor = attr->GetEditor(this, row, col);
9b4aede2 7772 attr->DecRef();
0b190b0f 7773
9b4aede2
RD
7774 return editor;
7775}
7776
283b7808
VZ
7777bool wxGrid::IsReadOnly(int row, int col) const
7778{
7779 wxGridCellAttr* attr = GetCellAttr(row, col);
7780 bool isReadOnly = attr->IsReadOnly();
7781 attr->DecRef();
7782 return isReadOnly;
7783}
7784
2e9a6788 7785// ----------------------------------------------------------------------------
758cbedf 7786// attribute support: cache, automatic provider creation, ...
2e9a6788
VZ
7787// ----------------------------------------------------------------------------
7788
7789bool wxGrid::CanHaveAttributes()
7790{
7791 if ( !m_table )
7792 {
7793 return FALSE;
7794 }
7795
f2d76237 7796 return m_table->CanHaveAttributes();
2e9a6788
VZ
7797}
7798
0a976765
VZ
7799void wxGrid::ClearAttrCache()
7800{
7801 if ( m_attrCache.row != -1 )
7802 {
39bcce60 7803 wxSafeDecRef(m_attrCache.attr);
0a976765
VZ
7804 m_attrCache.row = -1;
7805 }
7806}
7807
7808void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
7809{
7810 wxGrid *self = (wxGrid *)this; // const_cast
7811
7812 self->ClearAttrCache();
7813 self->m_attrCache.row = row;
7814 self->m_attrCache.col = col;
7815 self->m_attrCache.attr = attr;
39bcce60 7816 wxSafeIncRef(attr);
0a976765
VZ
7817}
7818
7819bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
7820{
7821 if ( row == m_attrCache.row && col == m_attrCache.col )
7822 {
7823 *attr = m_attrCache.attr;
39bcce60 7824 wxSafeIncRef(m_attrCache.attr);
0a976765
VZ
7825
7826#ifdef DEBUG_ATTR_CACHE
7827 gs_nAttrCacheHits++;
7828#endif
7829
7830 return TRUE;
7831 }
7832 else
7833 {
7834#ifdef DEBUG_ATTR_CACHE
7835 gs_nAttrCacheMisses++;
7836#endif
7837 return FALSE;
7838 }
7839}
7840
2e9a6788
VZ
7841wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
7842{
0a976765
VZ
7843 wxGridCellAttr *attr;
7844 if ( !LookupAttr(row, col, &attr) )
2e9a6788 7845 {
0a976765
VZ
7846 attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
7847 CacheAttr(row, col, attr);
7848 }
508011ce
VZ
7849 if (attr)
7850 {
2796cce3 7851 attr->SetDefAttr(m_defaultCellAttr);
508011ce
VZ
7852 }
7853 else
7854 {
2796cce3
RD
7855 attr = m_defaultCellAttr;
7856 attr->IncRef();
7857 }
2e9a6788 7858
0a976765
VZ
7859 return attr;
7860}
7861
7862wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
7863{
7864 wxGridCellAttr *attr;
7865 if ( !LookupAttr(row, col, &attr) || !attr )
7866 {
7867 wxASSERT_MSG( m_table,
f6bcfd97 7868 _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
0a976765
VZ
7869
7870 attr = m_table->GetAttr(row, col);
7871 if ( !attr )
7872 {
7873 attr = new wxGridCellAttr;
7874
7875 // artificially inc the ref count to match DecRef() in caller
7876 attr->IncRef();
7877
7878 m_table->SetAttr(attr, row, col);
7879 }
2e9a6788 7880
0a976765 7881 CacheAttr(row, col, attr);
2e9a6788 7882 }
2796cce3 7883 attr->SetDefAttr(m_defaultCellAttr);
2e9a6788
VZ
7884 return attr;
7885}
7886
0b190b0f
VZ
7887// ----------------------------------------------------------------------------
7888// setting column attributes (wrappers around SetColAttr)
7889// ----------------------------------------------------------------------------
7890
7891void wxGrid::SetColFormatBool(int col)
7892{
7893 SetColFormatCustom(col, wxGRID_VALUE_BOOL);
7894}
7895
7896void wxGrid::SetColFormatNumber(int col)
7897{
7898 SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
7899}
7900
7901void wxGrid::SetColFormatFloat(int col, int width, int precision)
7902{
7903 wxString typeName = wxGRID_VALUE_FLOAT;
7904 if ( (width != -1) || (precision != -1) )
7905 {
7906 typeName << _T(':') << width << _T(',') << precision;
7907 }
7908
7909 SetColFormatCustom(col, typeName);
7910}
7911
7912void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
7913{
7914 wxGridCellAttr *attr = new wxGridCellAttr;
7915 wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
7916 attr->SetRenderer(renderer);
7917
7918 SetColAttr(col, attr);
7919}
7920
758cbedf
VZ
7921// ----------------------------------------------------------------------------
7922// setting cell attributes: this is forwarded to the table
7923// ----------------------------------------------------------------------------
7924
7925void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
7926{
7927 if ( CanHaveAttributes() )
7928 {
7929 m_table->SetRowAttr(attr, row);
7930 }
7931 else
7932 {
39bcce60 7933 wxSafeDecRef(attr);
758cbedf
VZ
7934 }
7935}
7936
7937void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
7938{
7939 if ( CanHaveAttributes() )
7940 {
7941 m_table->SetColAttr(attr, col);
7942 }
7943 else
7944 {
39bcce60 7945 wxSafeDecRef(attr);
758cbedf
VZ
7946 }
7947}
7948
2e9a6788
VZ
7949void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
7950{
7951 if ( CanHaveAttributes() )
7952 {
0a976765 7953 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7954 attr->SetBackgroundColour(colour);
7955 attr->DecRef();
7956 }
7957}
7958
7959void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
7960{
7961 if ( CanHaveAttributes() )
7962 {
0a976765 7963 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7964 attr->SetTextColour(colour);
7965 attr->DecRef();
7966 }
7967}
7968
7969void wxGrid::SetCellFont( int row, int col, const wxFont& font )
7970{
7971 if ( CanHaveAttributes() )
7972 {
0a976765 7973 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7974 attr->SetFont(font);
7975 attr->DecRef();
7976 }
7977}
7978
7979void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
7980{
7981 if ( CanHaveAttributes() )
7982 {
0a976765 7983 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
2e9a6788
VZ
7984 attr->SetAlignment(horiz, vert);
7985 attr->DecRef();
ab79958a
VZ
7986 }
7987}
7988
7989void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
7990{
7991 if ( CanHaveAttributes() )
7992 {
0a976765 7993 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
ab79958a
VZ
7994 attr->SetRenderer(renderer);
7995 attr->DecRef();
9b4aede2
RD
7996 }
7997}
7998
7999void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
8000{
8001 if ( CanHaveAttributes() )
8002 {
8003 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
8004 attr->SetEditor(editor);
8005 attr->DecRef();
283b7808
VZ
8006 }
8007}
8008
8009void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
8010{
8011 if ( CanHaveAttributes() )
8012 {
8013 wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
8014 attr->SetReadOnly(isReadOnly);
8015 attr->DecRef();
2e9a6788 8016 }
f85afd4e
MB
8017}
8018
f2d76237
RD
8019// ----------------------------------------------------------------------------
8020// Data type registration
8021// ----------------------------------------------------------------------------
8022
8023void wxGrid::RegisterDataType(const wxString& typeName,
8024 wxGridCellRenderer* renderer,
8025 wxGridCellEditor* editor)
8026{
8027 m_typeRegistry->RegisterDataType(typeName, renderer, editor);
8028}
8029
8030
99306db2 8031wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
f2d76237
RD
8032{
8033 wxString typeName = m_table->GetTypeName(row, col);
8034 return GetDefaultEditorForType(typeName);
8035}
8036
99306db2 8037wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
f2d76237
RD
8038{
8039 wxString typeName = m_table->GetTypeName(row, col);
8040 return GetDefaultRendererForType(typeName);
8041}
8042
99306db2
VZ
8043wxGridCellEditor*
8044wxGrid::GetDefaultEditorForType(const wxString& typeName) const
f2d76237 8045{
c4608a8a 8046 int index = m_typeRegistry->FindOrCloneDataType(typeName);
0b190b0f
VZ
8047 if ( index == wxNOT_FOUND )
8048 {
8049 wxFAIL_MSG(wxT("Unknown data type name"));
8050
f2d76237
RD
8051 return NULL;
8052 }
0b190b0f 8053
f2d76237
RD
8054 return m_typeRegistry->GetEditor(index);
8055}
8056
99306db2
VZ
8057wxGridCellRenderer*
8058wxGrid::GetDefaultRendererForType(const wxString& typeName) const
f2d76237 8059{
c4608a8a 8060 int index = m_typeRegistry->FindOrCloneDataType(typeName);
0b190b0f
VZ
8061 if ( index == wxNOT_FOUND )
8062 {
c4608a8a 8063 wxFAIL_MSG(wxT("Unknown data type name"));
0b190b0f 8064
c4608a8a 8065 return NULL;
e72b4213 8066 }
0b190b0f 8067
c4608a8a 8068 return m_typeRegistry->GetRenderer(index);
f2d76237
RD
8069}
8070
8071
2e9a6788
VZ
8072// ----------------------------------------------------------------------------
8073// row/col size
8074// ----------------------------------------------------------------------------
8075
6e8524b1
MB
8076void wxGrid::EnableDragRowSize( bool enable )
8077{
8078 m_canDragRowSize = enable;
8079}
8080
8081
8082void wxGrid::EnableDragColSize( bool enable )
8083{
8084 m_canDragColSize = enable;
8085}
8086
4cfa5de6
RD
8087void wxGrid::EnableDragGridSize( bool enable )
8088{
8089 m_canDragGridSize = enable;
8090}
8091
6e8524b1 8092
f85afd4e
MB
8093void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
8094{
8095 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
8096
8097 if ( resizeExistingRows )
8098 {
7c1cb261 8099 InitRowHeights();
faec5a43
SN
8100 if ( !GetBatchCount() )
8101 CalcDimensions();
f85afd4e
MB
8102 }
8103}
8104
8105void wxGrid::SetRowSize( int row, int height )
8106{
b99be8fb 8107 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
60ff3b99 8108
7c1cb261
VZ
8109 if ( m_rowHeights.IsEmpty() )
8110 {
8111 // need to really create the array
8112 InitRowHeights();
8113 }
60ff3b99 8114
b99be8fb
VZ
8115 int h = wxMax( 0, height );
8116 int diff = h - m_rowHeights[row];
60ff3b99 8117
b99be8fb 8118 m_rowHeights[row] = h;
7c1cb261 8119 int i;
b99be8fb 8120 for ( i = row; i < m_numRows; i++ )
f85afd4e 8121 {
b99be8fb 8122 m_rowBottoms[i] += diff;
f85afd4e 8123 }
faec5a43
SN
8124 if ( !GetBatchCount() )
8125 CalcDimensions();
f85afd4e
MB
8126}
8127
8128void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
8129{
8130 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
8131
8132 if ( resizeExistingCols )
8133 {
7c1cb261 8134 InitColWidths();
faec5a43
SN
8135 if ( !GetBatchCount() )
8136 CalcDimensions();
f85afd4e
MB
8137 }
8138}
8139
8140void wxGrid::SetColSize( int col, int width )
8141{
b99be8fb 8142 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
60ff3b99 8143
43947979
VZ
8144 // should we check that it's bigger than GetColMinimalWidth(col) here?
8145
7c1cb261
VZ
8146 if ( m_colWidths.IsEmpty() )
8147 {
8148 // need to really create the array
8149 InitColWidths();
8150 }
f85afd4e 8151
b99be8fb
VZ
8152 int w = wxMax( 0, width );
8153 int diff = w - m_colWidths[col];
8154 m_colWidths[col] = w;
60ff3b99 8155
7c1cb261 8156 int i;
b99be8fb 8157 for ( i = col; i < m_numCols; i++ )
f85afd4e 8158 {
b99be8fb 8159 m_colRights[i] += diff;
f85afd4e 8160 }
faec5a43
SN
8161 if ( !GetBatchCount() )
8162 CalcDimensions();
f85afd4e
MB
8163}
8164
2d66e025 8165
43947979
VZ
8166void wxGrid::SetColMinimalWidth( int col, int width )
8167{
af547d51
VZ
8168 m_colMinWidths.Put(col, width);
8169}
8170
8171void wxGrid::SetRowMinimalHeight( int row, int width )
8172{
8173 m_rowMinHeights.Put(row, width);
43947979
VZ
8174}
8175
8176int wxGrid::GetColMinimalWidth(int col) const
8177{
af547d51
VZ
8178 long value = m_colMinWidths.Get(col);
8179 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_COL_WIDTH;
8180}
8181
8182int wxGrid::GetRowMinimalHeight(int row) const
8183{
8184 long value = m_rowMinHeights.Get(row);
8185 return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_ROW_HEIGHT;
43947979
VZ
8186}
8187
57c086ef
VZ
8188// ----------------------------------------------------------------------------
8189// auto sizing
8190// ----------------------------------------------------------------------------
8191
af547d51 8192void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
65e4e78e
VZ
8193{
8194 wxClientDC dc(m_gridWin);
8195
a95e38c0
VZ
8196 // init both of them to avoid compiler warnings, even if weo nly need one
8197 int row = -1,
8198 col = -1;
af547d51
VZ
8199 if ( column )
8200 col = colOrRow;
8201 else
8202 row = colOrRow;
8203
8204 wxCoord extent, extentMax = 0;
8205 int max = column ? m_numRows : m_numCols;
39bcce60 8206 for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
65e4e78e 8207 {
af547d51
VZ
8208 if ( column )
8209 row = rowOrCol;
8210 else
8211 col = rowOrCol;
8212
65e4e78e 8213 wxGridCellAttr* attr = GetCellAttr(row, col);
28a77bc4 8214 wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
65e4e78e
VZ
8215 if ( renderer )
8216 {
af547d51
VZ
8217 wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
8218 extent = column ? size.x : size.y;
8219 if ( extent > extentMax )
65e4e78e 8220 {
af547d51 8221 extentMax = extent;
65e4e78e 8222 }
0b190b0f
VZ
8223
8224 renderer->DecRef();
65e4e78e
VZ
8225 }
8226
8227 attr->DecRef();
8228 }
8229
af547d51
VZ
8230 // now also compare with the column label extent
8231 wxCoord w, h;
65e4e78e 8232 dc.SetFont( GetLabelFont() );
294d195c
MB
8233
8234 if ( column )
8235 dc.GetTextExtent( GetColLabelValue(col), &w, &h );
8236 else
ee495e4c 8237 dc.GetTextExtent( GetRowLabelValue(row), &w, &h );
294d195c 8238
af547d51
VZ
8239 extent = column ? w : h;
8240 if ( extent > extentMax )
65e4e78e 8241 {
af547d51 8242 extentMax = extent;
65e4e78e
VZ
8243 }
8244
af547d51 8245 if ( !extentMax )
65e4e78e 8246 {
af547d51
VZ
8247 // empty column - give default extent (notice that if extentMax is less
8248 // than default extent but != 0, it's ok)
8249 extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
65e4e78e
VZ
8250 }
8251 else
8252 {
a95e38c0
VZ
8253 if ( column )
8254 {
8255 // leave some space around text
8256 extentMax += 10;
8257 }
f6bcfd97
BP
8258 else
8259 {
8260 extentMax += 6;
8261 }
65e4e78e
VZ
8262 }
8263
faec5a43 8264 if ( column ){
af547d51 8265 SetColSize(col, extentMax);
faec5a43
SN
8266 if ( !GetBatchCount() )
8267 {
8268 int cw, ch, dummy;
8269 m_gridWin->GetClientSize( &cw, &ch );
8270 wxRect rect ( CellToRect( 0, col ) );
8271 rect.y = 0;
8272 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
8273 rect.width = cw - rect.x;
8274 rect.height = m_colLabelHeight;
8275 m_colLabelWin->Refresh( TRUE, &rect );
8276 }
8277 }
8278 else{
39bcce60 8279 SetRowSize(row, extentMax);
faec5a43
SN
8280 if ( !GetBatchCount() )
8281 {
8282 int cw, ch, dummy;
8283 m_gridWin->GetClientSize( &cw, &ch );
8284 wxRect rect ( CellToRect( row, 0 ) );
8285 rect.x = 0;
8286 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
8287 rect.width = m_rowLabelWidth;
8288 rect.height = ch - rect.y;
8289 m_rowLabelWin->Refresh( TRUE, &rect );
8290 }
8291 }
65e4e78e
VZ
8292 if ( setAsMin )
8293 {
af547d51
VZ
8294 if ( column )
8295 SetColMinimalWidth(col, extentMax);
8296 else
39bcce60 8297 SetRowMinimalHeight(row, extentMax);
65e4e78e
VZ
8298 }
8299}
8300
266e8367 8301int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
65e4e78e 8302{
57c086ef
VZ
8303 int width = m_rowLabelWidth;
8304
faec5a43
SN
8305 if ( !calcOnly )
8306 BeginBatch();
65e4e78e
VZ
8307 for ( int col = 0; col < m_numCols; col++ )
8308 {
266e8367
VZ
8309 if ( !calcOnly )
8310 {
8311 AutoSizeColumn(col, setAsMin);
8312 }
57c086ef
VZ
8313
8314 width += GetColWidth(col);
65e4e78e 8315 }
faec5a43
SN
8316 if ( !calcOnly )
8317 EndBatch();
266e8367 8318 return width;
65e4e78e
VZ
8319}
8320
266e8367 8321int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
57c086ef
VZ
8322{
8323 int height = m_colLabelHeight;
8324
faec5a43
SN
8325 if ( !calcOnly )
8326 BeginBatch();
57c086ef
VZ
8327 for ( int row = 0; row < m_numRows; row++ )
8328 {
af547d51
VZ
8329 if ( !calcOnly )
8330 {
8331 AutoSizeRow(row, setAsMin);
8332 }
57c086ef
VZ
8333
8334 height += GetRowHeight(row);
8335 }
faec5a43
SN
8336 if ( !calcOnly )
8337 EndBatch();
266e8367 8338 return height;
57c086ef
VZ
8339}
8340
8341void wxGrid::AutoSize()
8342{
266e8367 8343 // set the size too
faec5a43 8344 SetClientSize(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
266e8367
VZ
8345}
8346
8347wxSize wxGrid::DoGetBestSize() const
8348{
8349 // don't set sizes, only calculate them
8350 wxGrid *self = (wxGrid *)this; // const_cast
8351
8352 return wxSize(self->SetOrCalcColumnSizes(TRUE),
8353 self->SetOrCalcRowSizes(TRUE));
8354}
8355
8356void wxGrid::Fit()
8357{
8358 AutoSize();
57c086ef
VZ
8359}
8360
6fc0f38f
SN
8361
8362wxPen& wxGrid::GetDividerPen() const
8363{
8364 return wxNullPen;
8365}
8366
57c086ef
VZ
8367// ----------------------------------------------------------------------------
8368// cell value accessor functions
8369// ----------------------------------------------------------------------------
f85afd4e
MB
8370
8371void wxGrid::SetCellValue( int row, int col, const wxString& s )
8372{
8373 if ( m_table )
8374 {
f6bcfd97 8375 m_table->SetValue( row, col, s );
2d66e025
MB
8376 if ( !GetBatchCount() )
8377 {
8378 wxClientDC dc( m_gridWin );
8379 PrepareDC( dc );
8380 DrawCell( dc, wxGridCellCoords(row, col) );
8381 }
60ff3b99 8382
f85afd4e 8383 if ( m_currentCellCoords.GetRow() == row &&
4cfa5de6 8384 m_currentCellCoords.GetCol() == col &&
f6bcfd97
BP
8385 IsCellEditControlShown())
8386 // Note: If we are using IsCellEditControlEnabled,
8387 // this interacts badly with calling SetCellValue from
8388 // an EVT_GRID_CELL_CHANGE handler.
f85afd4e 8389 {
4cfa5de6
RD
8390 HideCellEditControl();
8391 ShowCellEditControl(); // will reread data from table
f85afd4e 8392 }
f85afd4e
MB
8393 }
8394}
8395
8396
8397//
2d66e025 8398// ------ Block, row and col selection
f85afd4e
MB
8399//
8400
8401void wxGrid::SelectRow( int row, bool addToSelected )
8402{
b5808881 8403 if ( IsSelection() && !addToSelected )
e32352cf 8404 ClearSelection();
70c7a608 8405
f6bcfd97 8406 m_selection->SelectRow( row, FALSE, addToSelected );
f85afd4e
MB
8407}
8408
8409
8410void wxGrid::SelectCol( int col, bool addToSelected )
8411{
b5808881 8412 if ( IsSelection() && !addToSelected )
e32352cf 8413 ClearSelection();
f85afd4e 8414
f6bcfd97 8415 m_selection->SelectCol( col, FALSE, addToSelected );
f85afd4e
MB
8416}
8417
8418
84912ef8 8419void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol,
c9097836 8420 bool addToSelected )
f85afd4e 8421{
c9097836
MB
8422 if ( IsSelection() && !addToSelected )
8423 ClearSelection();
f85afd4e 8424
84912ef8
RD
8425 m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol,
8426 FALSE, addToSelected );
f85afd4e
MB
8427}
8428
c9097836 8429
f85afd4e
MB
8430void wxGrid::SelectAll()
8431{
f74d0b57
SN
8432 if ( m_numRows > 0 && m_numCols > 0 )
8433 m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
b5808881 8434}
f85afd4e 8435
f7b4b343
VZ
8436//
8437// ------ Cell, row and col deselection
8438//
8439
8440void wxGrid::DeselectRow( int row )
8441{
8442 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
8443 {
8444 if ( m_selection->IsInSelection(row, 0 ) )
8445 m_selection->ToggleCellSelection( row, 0);
ffdd3c98 8446 }
f7b4b343
VZ
8447 else
8448 {
8449 int nCols = GetNumberCols();
8450 for ( int i = 0; i < nCols ; i++ )
8451 {
8452 if ( m_selection->IsInSelection(row, i ) )
8453 m_selection->ToggleCellSelection( row, i);
8454 }
8455 }
8456}
8457
8458void wxGrid::DeselectCol( int col )
8459{
8460 if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
8461 {
8462 if ( m_selection->IsInSelection(0, col ) )
8463 m_selection->ToggleCellSelection( 0, col);
8464 }
8465 else
8466 {
8467 int nRows = GetNumberRows();
8468 for ( int i = 0; i < nRows ; i++ )
8469 {
8470 if ( m_selection->IsInSelection(i, col ) )
8471 m_selection->ToggleCellSelection(i, col);
8472 }
8473 }
8474}
8475
8476void wxGrid::DeselectCell( int row, int col )
8477{
8478 if ( m_selection->IsInSelection(row, col) )
8479 m_selection->ToggleCellSelection(row, col);
8480}
8481
b5808881
SN
8482bool wxGrid::IsSelection()
8483{
8484 return ( m_selection->IsSelection() ||
8485 ( m_selectingTopLeft != wxGridNoCellCoords &&
8486 m_selectingBottomRight != wxGridNoCellCoords ) );
f85afd4e
MB
8487}
8488
b5808881
SN
8489bool wxGrid::IsInSelection( int row, int col )
8490{
8491 return ( m_selection->IsInSelection( row, col ) ||
8492 ( row >= m_selectingTopLeft.GetRow() &&
8493 col >= m_selectingTopLeft.GetCol() &&
8494 row <= m_selectingBottomRight.GetRow() &&
8495 col <= m_selectingBottomRight.GetCol() ) );
8496}
f85afd4e
MB
8497
8498void wxGrid::ClearSelection()
8499{
b5808881
SN
8500 m_selectingTopLeft = wxGridNoCellCoords;
8501 m_selectingBottomRight = wxGridNoCellCoords;
8502 m_selection->ClearSelection();
8f177c8e 8503}
f85afd4e
MB
8504
8505
da6af900 8506// This function returns the rectangle that encloses the given block
2d66e025
MB
8507// in device coords clipped to the client size of the grid window.
8508//
58dd5b3b
MB
8509wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
8510 const wxGridCellCoords &bottomRight )
f85afd4e 8511{
58dd5b3b 8512 wxRect rect( wxGridNoCellRect );
f85afd4e
MB
8513 wxRect cellRect;
8514
58dd5b3b
MB
8515 cellRect = CellToRect( topLeft );
8516 if ( cellRect != wxGridNoCellRect )
f85afd4e 8517 {
58dd5b3b
MB
8518 rect = cellRect;
8519 }
8520 else
8521 {
8522 rect = wxRect( 0, 0, 0, 0 );
8523 }
60ff3b99 8524
58dd5b3b
MB
8525 cellRect = CellToRect( bottomRight );
8526 if ( cellRect != wxGridNoCellRect )
8527 {
8528 rect += cellRect;
2d66e025
MB
8529 }
8530 else
8531 {
8532 return wxGridNoCellRect;
f85afd4e
MB
8533 }
8534
58dd5b3b
MB
8535 // convert to scrolled coords
8536 //
8537 int left, top, right, bottom;
8538 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
8539 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
8540
8541 int cw, ch;
8542 m_gridWin->GetClientSize( &cw, &ch );
8543
f6bcfd97
BP
8544 if (right < 0 || bottom < 0 || left > cw || top > ch)
8545 return wxRect( 0, 0, 0, 0);
8546
58dd5b3b
MB
8547 rect.SetLeft( wxMax(0, left) );
8548 rect.SetTop( wxMax(0, top) );
8549 rect.SetRight( wxMin(cw, right) );
8550 rect.SetBottom( wxMin(ch, bottom) );
8551
f85afd4e
MB
8552 return rect;
8553}
8554
8555
58dd5b3b 8556
f85afd4e
MB
8557//
8558// ------ Grid event classes
8559//
8560
8561IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
8562
8563wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5c8fc7c1 8564 int row, int col, int x, int y, bool sel,
f85afd4e
MB
8565 bool control, bool shift, bool alt, bool meta )
8566 : wxNotifyEvent( type, id )
8567{
8568 m_row = row;
8569 m_col = col;
8570 m_x = x;
8571 m_y = y;
5c8fc7c1 8572 m_selecting = sel;
f85afd4e
MB
8573 m_control = control;
8574 m_shift = shift;
8575 m_alt = alt;
8576 m_meta = meta;
8f177c8e 8577
f85afd4e
MB
8578 SetEventObject(obj);
8579}
8580
8581
8582IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
8583
8584wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
8585 int rowOrCol, int x, int y,
8586 bool control, bool shift, bool alt, bool meta )
8587 : wxNotifyEvent( type, id )
8588{
8589 m_rowOrCol = rowOrCol;
8590 m_x = x;
8591 m_y = y;
8592 m_control = control;
8593 m_shift = shift;
8594 m_alt = alt;
8595 m_meta = meta;
8f177c8e 8596
f85afd4e
MB
8597 SetEventObject(obj);
8598}
8599
8600
8601IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
8602
8603wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
8f177c8e
VZ
8604 const wxGridCellCoords& topLeft,
8605 const wxGridCellCoords& bottomRight,
5c8fc7c1
SN
8606 bool sel, bool control,
8607 bool shift, bool alt, bool meta )
8f177c8e 8608 : wxNotifyEvent( type, id )
f85afd4e
MB
8609{
8610 m_topLeft = topLeft;
8611 m_bottomRight = bottomRight;
5c8fc7c1 8612 m_selecting = sel;
f85afd4e
MB
8613 m_control = control;
8614 m_shift = shift;
8615 m_alt = alt;
8616 m_meta = meta;
8617
8618 SetEventObject(obj);
8619}
8620
8621
8622#endif // ifndef wxUSE_NEW_GRID