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