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