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