1 ///////////////////////////////////////////////////////////////////////////
2 // Name: generic/grid.cpp
3 // Purpose: wxGrid and related classes
4 // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "grid.h"
24 // For compilers that support precompilation, includes "wx/wx.h".
25 #include "wx/wxprec.h"
33 #if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
39 #include "wx/dcclient.h"
40 #include "wx/settings.h"
42 #include "wx/textctrl.h"
43 #include "wx/checkbox.h"
44 #include "wx/valtext.h"
47 #include "wx/textfile.h"
48 #include "wx/spinctrl.h"
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 WX_DEFINE_ARRAY(wxGridCellAttr
*, wxArrayAttrs
);
58 struct wxGridCellWithAttr
60 wxGridCellWithAttr(int row
, int col
, wxGridCellAttr
*attr_
)
61 : coords(row
, col
), attr(attr_
)
70 wxGridCellCoords coords
;
74 WX_DECLARE_OBJARRAY(wxGridCellWithAttr
, wxGridCellWithAttrArray
);
76 #include "wx/arrimpl.cpp"
78 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
)
79 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray
)
81 // ----------------------------------------------------------------------------
83 // ----------------------------------------------------------------------------
85 class WXDLLEXPORT wxGridRowLabelWindow
: public wxWindow
88 wxGridRowLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
89 wxGridRowLabelWindow( wxGrid
*parent
, wxWindowID id
,
90 const wxPoint
&pos
, const wxSize
&size
);
95 void OnPaint( wxPaintEvent
& event
);
96 void OnMouseEvent( wxMouseEvent
& event
);
97 void OnKeyDown( wxKeyEvent
& event
);
99 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow
)
100 DECLARE_EVENT_TABLE()
104 class WXDLLEXPORT wxGridColLabelWindow
: public wxWindow
107 wxGridColLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
108 wxGridColLabelWindow( wxGrid
*parent
, wxWindowID id
,
109 const wxPoint
&pos
, const wxSize
&size
);
114 void OnPaint( wxPaintEvent
&event
);
115 void OnMouseEvent( wxMouseEvent
& event
);
116 void OnKeyDown( wxKeyEvent
& event
);
118 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow
)
119 DECLARE_EVENT_TABLE()
123 class WXDLLEXPORT wxGridCornerLabelWindow
: public wxWindow
126 wxGridCornerLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
127 wxGridCornerLabelWindow( wxGrid
*parent
, wxWindowID id
,
128 const wxPoint
&pos
, const wxSize
&size
);
133 void OnMouseEvent( wxMouseEvent
& event
);
134 void OnKeyDown( wxKeyEvent
& event
);
135 void OnPaint( wxPaintEvent
& event
);
137 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow
)
138 DECLARE_EVENT_TABLE()
141 class WXDLLEXPORT wxGridWindow
: public wxPanel
146 m_owner
= (wxGrid
*)NULL
;
147 m_rowLabelWin
= (wxGridRowLabelWindow
*)NULL
;
148 m_colLabelWin
= (wxGridColLabelWindow
*)NULL
;
151 wxGridWindow( wxGrid
*parent
,
152 wxGridRowLabelWindow
*rowLblWin
,
153 wxGridColLabelWindow
*colLblWin
,
154 wxWindowID id
, const wxPoint
&pos
, const wxSize
&size
);
157 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
);
161 wxGridRowLabelWindow
*m_rowLabelWin
;
162 wxGridColLabelWindow
*m_colLabelWin
;
164 void OnPaint( wxPaintEvent
&event
);
165 void OnMouseEvent( wxMouseEvent
& event
);
166 void OnKeyDown( wxKeyEvent
& );
167 void OnEraseBackground( wxEraseEvent
& );
170 DECLARE_DYNAMIC_CLASS(wxGridWindow
)
171 DECLARE_EVENT_TABLE()
176 class wxGridCellEditorEvtHandler
: public wxEvtHandler
179 wxGridCellEditorEvtHandler()
180 : m_grid(0), m_editor(0)
182 wxGridCellEditorEvtHandler(wxGrid
* grid
, wxGridCellEditor
* editor
)
183 : m_grid(grid
), m_editor(editor
)
186 void OnKeyDown(wxKeyEvent
& event
);
187 void OnChar(wxKeyEvent
& event
);
191 wxGridCellEditor
* m_editor
;
192 DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler
)
193 DECLARE_EVENT_TABLE()
197 IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler
, wxEvtHandler
)
198 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler
, wxEvtHandler
)
199 EVT_KEY_DOWN( wxGridCellEditorEvtHandler
::OnKeyDown
)
200 EVT_CHAR( wxGridCellEditorEvtHandler
::OnChar
)
205 // ----------------------------------------------------------------------------
206 // the internal data representation used by wxGridCellAttrProvider
207 // ----------------------------------------------------------------------------
209 // this class stores attributes set for cells
210 class WXDLLEXPORT wxGridCellAttrData
213 void SetAttr(wxGridCellAttr
*attr
, int row
, int col
);
214 wxGridCellAttr
*GetAttr(int row
, int col
) const;
215 void UpdateAttrRows( size_t pos
, int numRows
);
216 void UpdateAttrCols( size_t pos
, int numCols
);
219 // searches for the attr for given cell, returns wxNOT_FOUND if not found
220 int FindIndex(int row
, int col
) const;
222 wxGridCellWithAttrArray m_attrs
;
225 // this class stores attributes set for rows or columns
226 class WXDLLEXPORT wxGridRowOrColAttrData
229 // empty ctor to suppress warnings
230 wxGridRowOrColAttrData() { }
231 ~wxGridRowOrColAttrData();
233 void SetAttr(wxGridCellAttr
*attr
, int rowOrCol
);
234 wxGridCellAttr
*GetAttr(int rowOrCol
) const;
235 void UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols
);
238 wxArrayInt m_rowsOrCols
;
239 wxArrayAttrs m_attrs
;
242 // NB: this is just a wrapper around 3 objects: one which stores cell
243 // attributes, and 2 others for row/col ones
244 class WXDLLEXPORT wxGridCellAttrProviderData
247 wxGridCellAttrData m_cellAttrs
;
248 wxGridRowOrColAttrData m_rowAttrs
,
253 // ----------------------------------------------------------------------------
254 // data structures used for the data type registry
255 // ----------------------------------------------------------------------------
257 struct wxGridDataTypeInfo
{
258 wxGridDataTypeInfo(const wxString
& typeName
,
259 wxGridCellRenderer
* renderer
,
260 wxGridCellEditor
* editor
)
261 : m_typeName(typeName
), m_renderer(renderer
), m_editor(editor
)
264 ~wxGridDataTypeInfo() { delete m_renderer
; delete m_editor
; }
267 wxGridCellRenderer
* m_renderer
;
268 wxGridCellEditor
* m_editor
;
272 WX_DEFINE_ARRAY(wxGridDataTypeInfo
*, wxGridDataTypeInfoArray
);
275 class WXDLLEXPORT wxGridTypeRegistry
{
277 ~wxGridTypeRegistry();
278 void RegisterDataType(const wxString
& typeName
,
279 wxGridCellRenderer
* renderer
,
280 wxGridCellEditor
* editor
);
281 int FindDataType(const wxString
& typeName
);
282 wxGridCellRenderer
* GetRenderer(int index
);
283 wxGridCellEditor
* GetEditor(int index
);
286 wxGridDataTypeInfoArray m_typeinfo
;
292 // ----------------------------------------------------------------------------
293 // conditional compilation
294 // ----------------------------------------------------------------------------
296 #ifndef WXGRID_DRAW_LINES
297 #define WXGRID_DRAW_LINES 1
300 // ----------------------------------------------------------------------------
302 // ----------------------------------------------------------------------------
304 //#define DEBUG_ATTR_CACHE
305 #ifdef DEBUG_ATTR_CACHE
306 static size_t gs_nAttrCacheHits
= 0;
307 static size_t gs_nAttrCacheMisses
= 0;
308 #endif // DEBUG_ATTR_CACHE
310 // ----------------------------------------------------------------------------
312 // ----------------------------------------------------------------------------
314 wxGridCellCoords
wxGridNoCellCoords( -1, -1 );
315 wxRect
wxGridNoCellRect( -1, -1, -1, -1 );
318 // TODO: fixed so far - make configurable later (and also different for x/y)
319 static const size_t GRID_SCROLL_LINE
= 10;
321 // the size of hash tables used a bit everywhere (the max number of elements
322 // in these hash tables is the number of rows/columns)
323 static const int GRID_HASH_SIZE
= 100;
325 // ============================================================================
327 // ============================================================================
329 // ----------------------------------------------------------------------------
331 // ----------------------------------------------------------------------------
333 wxGridCellEditor
::wxGridCellEditor()
339 wxGridCellEditor
::~wxGridCellEditor()
344 void wxGridCellEditor
::Create(wxWindow
* WXUNUSED(parent
),
345 wxWindowID
WXUNUSED(id
),
346 wxEvtHandler
* evtHandler
)
349 m_control
->PushEventHandler(evtHandler
);
352 void wxGridCellEditor
::PaintBackground(const wxRect
& rectCell
,
353 wxGridCellAttr
*attr
)
355 // erase the background because we might not fill the cell
356 wxClientDC
dc(m_control
->GetParent());
357 dc
.SetPen(*wxTRANSPARENT_PEN
);
358 dc
.SetBrush(wxBrush(attr
->GetBackgroundColour(), wxSOLID
));
359 dc
.DrawRectangle(rectCell
);
361 // redraw the control we just painted over
362 m_control
->Refresh();
365 void wxGridCellEditor
::Destroy()
369 m_control
->Destroy();
374 void wxGridCellEditor
::Show(bool show
, wxGridCellAttr
*attr
)
376 wxASSERT_MSG(m_control
,
377 wxT("The wxGridCellEditor must be Created first!"));
378 m_control
->Show(show
);
382 // set the colours/fonts if we have any
385 m_colFgOld
= m_control
->GetForegroundColour();
386 m_control
->SetForegroundColour(attr
->GetTextColour());
388 m_colBgOld
= m_control
->GetBackgroundColour();
389 m_control
->SetBackgroundColour(attr
->GetBackgroundColour());
391 m_fontOld
= m_control
->GetFont();
392 m_control
->SetFont(attr
->GetFont());
394 // can't do anything more in the base class version, the other
395 // attributes may only be used by the derived classes
400 // restore the standard colours fonts
401 if ( m_colFgOld
.Ok() )
403 m_control
->SetForegroundColour(m_colFgOld
);
404 m_colFgOld
= wxNullColour
;
407 if ( m_colBgOld
.Ok() )
409 m_control
->SetBackgroundColour(m_colBgOld
);
410 m_colBgOld
= wxNullColour
;
413 if ( m_fontOld
.Ok() )
415 m_control
->SetFont(m_fontOld
);
416 m_fontOld
= wxNullFont
;
421 void wxGridCellEditor
::SetSize(const wxRect
& rect
)
423 wxASSERT_MSG(m_control
,
424 wxT("The wxGridCellEditor must be Created first!"));
425 m_control
->SetSize(rect
);
428 void wxGridCellEditor
::HandleReturn(wxKeyEvent
& event
)
434 void wxGridCellEditor
::StartingKey(wxKeyEvent
& event
)
439 void wxGridCellEditor
::StartingClick()
443 // ----------------------------------------------------------------------------
444 // wxGridCellTextEditor
445 // ----------------------------------------------------------------------------
447 wxGridCellTextEditor
::wxGridCellTextEditor()
451 void wxGridCellTextEditor
::Create(wxWindow
* parent
,
453 wxEvtHandler
* evtHandler
)
455 m_control
= new wxTextCtrl(parent
, id
, wxEmptyString
,
456 wxDefaultPosition
, wxDefaultSize
457 #if defined(__WXMSW__)
458 , wxTE_MULTILINE
| wxTE_NO_VSCROLL
// necessary ???
462 wxGridCellEditor
::Create(parent
, id
, evtHandler
);
465 void wxGridCellTextEditor
::PaintBackground(const wxRect
& WXUNUSED(rectCell
),
466 wxGridCellAttr
* WXUNUSED(attr
))
468 // as we fill the entire client area, don't do anything here to minimize
472 void wxGridCellTextEditor
::SetSize(const wxRect
& rectOrig
)
474 wxRect
rect(rectOrig
);
476 // Make the edit control large enough to allow for internal
479 // TODO: remove this if the text ctrl sizing is improved esp. for
482 #if defined(__WXGTK__)
483 rect
.Inflate(rect
.x ?
1 : 0, rect
.y ?
1 : 0);
485 int extra
= row
&& col ?
2 : 1;
486 #if defined(__WXMOTIF__)
489 rect
.SetLeft( wxMax(0, rect
.x
- extra
) );
490 rect
.SetTop( wxMax(0, rect
.y
- extra
) );
491 rect
.SetRight( rect
.GetRight() + 2*extra
);
492 rect
.SetBottom( rect
.GetBottom() + 2*extra
);
495 wxGridCellEditor
::SetSize(rect
);
498 void wxGridCellTextEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
500 wxASSERT_MSG(m_control
,
501 wxT("The wxGridCellEditor must be Created first!"));
503 m_startValue
= grid
->GetTable()->GetValue(row
, col
);
505 DoBeginEdit(m_startValue
);
508 void wxGridCellTextEditor
::DoBeginEdit(const wxString
& startValue
)
510 Text()->SetValue(startValue
);
511 Text()->SetInsertionPointEnd();
515 bool wxGridCellTextEditor
::EndEdit(int row
, int col
, bool saveValue
,
518 wxASSERT_MSG(m_control
,
519 wxT("The wxGridCellEditor must be Created first!"));
521 bool changed
= FALSE
;
522 wxString value
= Text()->GetValue();
523 if (value
!= m_startValue
)
527 grid
->GetTable()->SetValue(row
, col
, value
);
529 m_startValue
= wxEmptyString
;
530 Text()->SetValue(m_startValue
);
536 void wxGridCellTextEditor
::Reset()
538 wxASSERT_MSG(m_control
,
539 wxT("The wxGridCellEditor must be Created first!"));
541 DoReset(m_startValue
);
544 void wxGridCellTextEditor
::DoReset(const wxString
& startValue
)
546 Text()->SetValue(startValue
);
547 Text()->SetInsertionPointEnd();
550 void wxGridCellTextEditor
::StartingKey(wxKeyEvent
& event
)
552 if ( !event
.AltDown() && !event
.MetaDown() && !event
.ControlDown() )
554 // insert the key in the control
555 long keycode
= event
.KeyCode();
556 if ( isprint(keycode
) )
558 // FIXME this is not going to work for non letters...
559 if ( !event
.ShiftDown() )
561 keycode
= tolower(keycode
);
564 Text()->AppendText((wxChar
)keycode
);
574 void wxGridCellTextEditor
::HandleReturn(wxKeyEvent
& event
)
576 #if defined(__WXMOTIF__) || defined(__WXGTK__)
577 // wxMotif needs a little extra help...
578 int pos
= Text()->GetInsertionPoint();
579 wxString
s( Text()->GetValue() );
580 s
= s
.Left(pos
) + "\n" + s
.Mid(pos
);
582 Text()->SetInsertionPoint( pos
);
584 // the other ports can handle a Return key press
590 // ----------------------------------------------------------------------------
591 // wxGridCellNumberEditor
592 // ----------------------------------------------------------------------------
594 wxGridCellNumberEditor
::wxGridCellNumberEditor(int min
, int max
)
600 void wxGridCellNumberEditor
::Create(wxWindow
* parent
,
602 wxEvtHandler
* evtHandler
)
606 // create a spin ctrl
607 m_control
= new wxSpinCtrl(parent
, -1, wxEmptyString
,
608 wxDefaultPosition
, wxDefaultSize
,
612 wxGridCellEditor
::Create(parent
, id
, evtHandler
);
616 // just a text control
617 wxGridCellTextEditor
::Create(parent
, id
, evtHandler
);
620 Text()->SetValidator(new wxTextValidator(wxFILTER_NUMERIC
));
621 #endif // wxUSE_VALIDATORS
625 void wxGridCellNumberEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
627 // first get the value
628 wxGridTableBase
*table
= grid
->GetTable();
629 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
631 m_valueOld
= table
->GetValueAsLong(row
, col
);
635 wxFAIL_MSG( _T("this cell doesn't have numeric value") );
642 Spin()->SetValue(m_valueOld
);
646 DoBeginEdit(GetString());
650 bool wxGridCellNumberEditor
::EndEdit(int row
, int col
, bool saveValue
,
658 value
= Spin()->GetValue();
659 changed
= value
!= m_valueOld
;
663 changed
= Text()->GetValue().ToLong(&value
) && (value
!= m_valueOld
);
668 grid
->GetTable()->SetValueAsLong(row
, col
, value
);
674 void wxGridCellNumberEditor
::Reset()
678 Spin()->SetValue(m_valueOld
);
682 DoReset(GetString());
686 void wxGridCellNumberEditor
::StartingKey(wxKeyEvent
& event
)
690 long keycode
= event
.KeyCode();
691 if ( isdigit(keycode
) || keycode
== '+' || keycode
== '-' )
693 wxGridCellTextEditor
::StartingKey(event
);
702 // ----------------------------------------------------------------------------
703 // wxGridCellFloatEditor
704 // ----------------------------------------------------------------------------
706 void wxGridCellFloatEditor
::Create(wxWindow
* parent
,
708 wxEvtHandler
* evtHandler
)
710 wxGridCellTextEditor
::Create(parent
, id
, evtHandler
);
713 Text()->SetValidator(new wxTextValidator(wxFILTER_NUMERIC
));
714 #endif // wxUSE_VALIDATORS
717 void wxGridCellFloatEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
719 // first get the value
720 wxGridTableBase
*table
= grid
->GetTable();
721 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
723 m_valueOld
= table
->GetValueAsDouble(row
, col
);
727 wxFAIL_MSG( _T("this cell doesn't have float value") );
732 DoBeginEdit(GetString());
735 bool wxGridCellFloatEditor
::EndEdit(int row
, int col
, bool saveValue
,
739 if ( Text()->GetValue().ToDouble(&value
) && (value
!= m_valueOld
) )
741 grid
->GetTable()->SetValueAsDouble(row
, col
, value
);
751 void wxGridCellFloatEditor
::Reset()
753 DoReset(GetString());
756 void wxGridCellFloatEditor
::StartingKey(wxKeyEvent
& event
)
758 long keycode
= event
.KeyCode();
759 if ( isdigit(keycode
) ||
760 keycode
== '+' || keycode
== '-' || keycode
== '.' )
762 wxGridCellTextEditor
::StartingKey(event
);
771 // ----------------------------------------------------------------------------
772 // wxGridCellBoolEditor
773 // ----------------------------------------------------------------------------
775 void wxGridCellBoolEditor
::Create(wxWindow
* parent
,
777 wxEvtHandler
* evtHandler
)
779 m_control
= new wxCheckBox(parent
, id
, wxEmptyString
,
780 wxDefaultPosition
, wxDefaultSize
,
783 wxGridCellEditor
::Create(parent
, id
, evtHandler
);
786 void wxGridCellBoolEditor
::SetSize(const wxRect
& r
)
788 // position it in the centre of the rectangle (TODO: support alignment?)
790 m_control
->GetSize(&w
, &h
);
792 // the checkbox without label still has some space to the right in wxGTK,
793 // so shift it to the right
798 m_control
->Move(r
.x
+ r
.width
/2 - w
/2, r
.y
+ r
.height
/2 - h
/2);
801 void wxGridCellBoolEditor
::Show(bool show
, wxGridCellAttr
*attr
)
803 m_control
->Show(show
);
807 wxColour colBg
= attr ? attr
->GetBackgroundColour() : *wxLIGHT_GREY
;
808 CBox()->SetBackgroundColour(colBg
);
812 void wxGridCellBoolEditor
::BeginEdit(int row
, int col
, wxGrid
* grid
)
814 wxASSERT_MSG(m_control
,
815 wxT("The wxGridCellEditor must be Created first!"));
817 if (grid
->GetTable()->CanGetValueAs(row
, col
, wxT("bool")))
818 m_startValue
= grid
->GetTable()->GetValueAsBool(row
, col
);
820 m_startValue
= !!grid
->GetTable()->GetValue(row
, col
);
821 CBox()->SetValue(m_startValue
);
825 bool wxGridCellBoolEditor
::EndEdit(int row
, int col
,
829 wxASSERT_MSG(m_control
,
830 wxT("The wxGridCellEditor must be Created first!"));
832 bool changed
= FALSE
;
833 bool value
= CBox()->GetValue();
834 if ( value
!= m_startValue
)
839 if (grid
->GetTable()->CanGetValueAs(row
, col
, wxT("bool")))
840 grid
->GetTable()->SetValueAsBool(row
, col
, value
);
842 grid
->GetTable()->SetValue(row
, col
, value ?
_T("1") : wxEmptyString
);
848 void wxGridCellBoolEditor
::Reset()
850 wxASSERT_MSG(m_control
,
851 wxT("The wxGridCellEditor must be Created first!"));
853 CBox()->SetValue(m_startValue
);
856 void wxGridCellBoolEditor
::StartingClick()
858 CBox()->SetValue(!CBox()->GetValue());
861 // ----------------------------------------------------------------------------
862 // wxGridCellEditorEvtHandler
863 // ----------------------------------------------------------------------------
865 void wxGridCellEditorEvtHandler
::OnKeyDown(wxKeyEvent
& event
)
867 switch ( event
.KeyCode() )
871 m_grid
->DisableCellEditControl();
875 event
.Skip( m_grid
->ProcessEvent( event
) );
879 if (!m_grid
->ProcessEvent(event
))
880 m_editor
->HandleReturn(event
);
889 void wxGridCellEditorEvtHandler
::OnChar(wxKeyEvent
& event
)
891 switch ( event
.KeyCode() )
903 // ============================================================================
905 // ============================================================================
907 // ----------------------------------------------------------------------------
908 // wxGridCellRenderer
909 // ----------------------------------------------------------------------------
911 void wxGridCellRenderer
::Draw(wxGrid
& grid
,
912 wxGridCellAttr
& attr
,
918 dc
.SetBackgroundMode( wxSOLID
);
922 dc
.SetBrush( wxBrush(grid
.GetSelectionBackground(), wxSOLID
) );
926 dc
.SetBrush( wxBrush(attr
.GetBackgroundColour(), wxSOLID
) );
929 dc
.SetPen( *wxTRANSPARENT_PEN
);
930 dc
.DrawRectangle(rect
);
933 wxGridCellRenderer
::~wxGridCellRenderer()
937 // ----------------------------------------------------------------------------
938 // wxGridCellStringRenderer
939 // ----------------------------------------------------------------------------
941 void wxGridCellStringRenderer
::SetTextColoursAndFont(wxGrid
& grid
,
942 wxGridCellAttr
& attr
,
946 dc
.SetBackgroundMode( wxTRANSPARENT
);
948 // TODO some special colours for attr.IsReadOnly() case?
952 dc
.SetTextBackground( grid
.GetSelectionBackground() );
953 dc
.SetTextForeground( grid
.GetSelectionForeground() );
957 dc
.SetTextBackground( attr
.GetBackgroundColour() );
958 dc
.SetTextForeground( attr
.GetTextColour() );
961 dc
.SetFont( attr
.GetFont() );
964 wxSize wxGridCellStringRenderer
::DoGetBestSize(wxGridCellAttr
& attr
,
966 const wxString
& text
)
969 dc
.SetFont(attr
.GetFont());
970 dc
.GetTextExtent(text
, &x
, &y
);
975 wxSize wxGridCellStringRenderer
::GetBestSize(wxGrid
& grid
,
976 wxGridCellAttr
& attr
,
980 return DoGetBestSize(attr
, dc
, grid
.GetCellValue(row
, col
));
983 void wxGridCellStringRenderer
::Draw(wxGrid
& grid
,
984 wxGridCellAttr
& attr
,
986 const wxRect
& rectCell
,
990 wxGridCellRenderer
::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
);
992 // now we only have to draw the text
993 SetTextColoursAndFont(grid
, attr
, dc
, isSelected
);
996 attr
.GetAlignment(&hAlign
, &vAlign
);
998 wxRect rect
= rectCell
;
1001 grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
),
1002 rect
, hAlign
, vAlign
);
1005 // ----------------------------------------------------------------------------
1006 // wxGridCellNumberRenderer
1007 // ----------------------------------------------------------------------------
1009 wxString wxGridCellNumberRenderer
::GetString(wxGrid
& grid
, int row
, int col
)
1011 wxGridTableBase
*table
= grid
.GetTable();
1013 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) )
1015 text
.Printf(_T("%ld"), table
->GetValueAsLong(row
, col
));
1017 //else: leave the string empty or put 0 into it?
1022 void wxGridCellNumberRenderer
::Draw(wxGrid
& grid
,
1023 wxGridCellAttr
& attr
,
1025 const wxRect
& rectCell
,
1029 wxGridCellRenderer
::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
);
1031 SetTextColoursAndFont(grid
, attr
, dc
, isSelected
);
1033 // draw the text right aligned by default
1035 attr
.GetAlignment(&hAlign
, &vAlign
);
1038 wxRect rect
= rectCell
;
1041 grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
);
1044 wxSize wxGridCellNumberRenderer
::GetBestSize(wxGrid
& grid
,
1045 wxGridCellAttr
& attr
,
1049 return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
));
1052 // ----------------------------------------------------------------------------
1053 // wxGridCellFloatRenderer
1054 // ----------------------------------------------------------------------------
1056 wxGridCellFloatRenderer
::wxGridCellFloatRenderer(int width
, int precision
)
1059 SetPrecision(precision
);
1062 wxString wxGridCellFloatRenderer
::GetString(wxGrid
& grid
, int row
, int col
)
1064 wxGridTableBase
*table
= grid
.GetTable();
1066 if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) )
1070 m_format
.Printf(_T("%%%d.%d%%f"), m_width
, m_precision
);
1073 text
.Printf(m_format
, table
->GetValueAsDouble(row
, col
));
1075 //else: leave the string empty or put 0 into it?
1080 void wxGridCellFloatRenderer
::Draw(wxGrid
& grid
,
1081 wxGridCellAttr
& attr
,
1083 const wxRect
& rectCell
,
1087 wxGridCellRenderer
::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
);
1089 SetTextColoursAndFont(grid
, attr
, dc
, isSelected
);
1091 // draw the text right aligned by default
1093 attr
.GetAlignment(&hAlign
, &vAlign
);
1096 wxRect rect
= rectCell
;
1099 grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
);
1102 wxSize wxGridCellFloatRenderer
::GetBestSize(wxGrid
& grid
,
1103 wxGridCellAttr
& attr
,
1107 return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
));
1110 // ----------------------------------------------------------------------------
1111 // wxGridCellBoolRenderer
1112 // ----------------------------------------------------------------------------
1114 wxSize wxGridCellBoolRenderer
::ms_sizeCheckMark
;
1116 // between checkmark and box
1117 static const wxCoord wxGRID_CHECKMARK_MARGIN
= 4;
1119 wxSize wxGridCellBoolRenderer
::GetBestSize(wxGrid
& grid
,
1120 wxGridCellAttr
& WXUNUSED(attr
),
1125 // compute it only once (no locks for MT safeness in GUI thread...)
1126 if ( !ms_sizeCheckMark
.x
)
1128 // get checkbox size
1129 wxCoord checkSize
= 0;
1130 wxCheckBox
*checkbox
= new wxCheckBox(&grid
, -1, wxEmptyString
);
1131 wxSize size
= checkbox
->GetBestSize();
1132 checkSize
= size
.y
+ wxGRID_CHECKMARK_MARGIN
;
1134 // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
1136 checkSize
-= size
.y
/ 2;
1141 ms_sizeCheckMark
.x
= ms_sizeCheckMark
.y
= checkSize
;
1144 return ms_sizeCheckMark
;
1147 void wxGridCellBoolRenderer
::Draw(wxGrid
& grid
,
1148 wxGridCellAttr
& attr
,
1154 wxGridCellRenderer
::Draw(grid
, attr
, dc
, rect
, row
, col
, isSelected
);
1156 // draw a check mark in the centre (ignoring alignment - TODO)
1157 wxSize size
= GetBestSize(grid
, attr
, dc
, row
, col
);
1159 rectMark
.x
= rect
.x
+ rect
.width
/2 - size
.x
/2;
1160 rectMark
.y
= rect
.y
+ rect
.height
/2 - size
.y
/2;
1161 rectMark
.width
= size
.x
;
1162 rectMark
.height
= size
.y
;
1164 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1165 dc
.SetPen(wxPen(attr
.GetTextColour(), 1, wxSOLID
));
1166 dc
.DrawRectangle(rectMark
);
1168 rectMark
.Inflate(-wxGRID_CHECKMARK_MARGIN
);
1171 if (grid
.GetTable()->CanGetValueAs(row
, col
, wxT("bool")))
1172 value
= grid
.GetTable()->GetValueAsBool(row
, col
);
1174 value
= !!grid
.GetTable()->GetValue(row
, col
);
1178 dc
.SetTextForeground(attr
.GetTextColour());
1179 dc
.DrawCheckMark(rectMark
);
1183 // ----------------------------------------------------------------------------
1185 // ----------------------------------------------------------------------------
1187 const wxColour
& wxGridCellAttr
::GetTextColour() const
1189 if (HasTextColour())
1193 else if (m_defGridAttr
!= this)
1195 return m_defGridAttr
->GetTextColour();
1199 wxFAIL_MSG(wxT("Missing default cell attribute"));
1200 return wxNullColour
;
1205 const wxColour
& wxGridCellAttr
::GetBackgroundColour() const
1207 if (HasBackgroundColour())
1209 else if (m_defGridAttr
!= this)
1210 return m_defGridAttr
->GetBackgroundColour();
1213 wxFAIL_MSG(wxT("Missing default cell attribute"));
1214 return wxNullColour
;
1219 const wxFont
& wxGridCellAttr
::GetFont() const
1223 else if (m_defGridAttr
!= this)
1224 return m_defGridAttr
->GetFont();
1227 wxFAIL_MSG(wxT("Missing default cell attribute"));
1233 void wxGridCellAttr
::GetAlignment(int *hAlign
, int *vAlign
) const
1237 if ( hAlign
) *hAlign
= m_hAlign
;
1238 if ( vAlign
) *vAlign
= m_vAlign
;
1240 else if (m_defGridAttr
!= this)
1241 m_defGridAttr
->GetAlignment(hAlign
, vAlign
);
1244 wxFAIL_MSG(wxT("Missing default cell attribute"));
1249 // GetRenderer and GetEditor use a slightly different decision path about
1250 // which to use. If a non-default attr object has one then it is used,
1251 // otherwise the default editor or renderer passed in is used. It should be
1252 // the default for the data type of the cell. If it is NULL (because the
1253 // table has a type that the grid does not have in its registry,) then the
1254 // grid's default editor or renderer is used.
1256 wxGridCellRenderer
* wxGridCellAttr
::GetRenderer(wxGridCellRenderer
* def
) const
1258 if ((m_defGridAttr
!= this || def
== NULL
) && HasRenderer())
1262 else if (m_defGridAttr
!= this)
1263 return m_defGridAttr
->GetRenderer(NULL
);
1266 wxFAIL_MSG(wxT("Missing default cell attribute"));
1271 wxGridCellEditor
* wxGridCellAttr
::GetEditor(wxGridCellEditor
* def
) const
1273 if ((m_defGridAttr
!= this || def
== NULL
) && HasEditor())
1277 else if (m_defGridAttr
!= this)
1278 return m_defGridAttr
->GetEditor(NULL
);
1281 wxFAIL_MSG(wxT("Missing default cell attribute"));
1286 // ----------------------------------------------------------------------------
1287 // wxGridCellAttrData
1288 // ----------------------------------------------------------------------------
1290 void wxGridCellAttrData
::SetAttr(wxGridCellAttr
*attr
, int row
, int col
)
1292 int n
= FindIndex(row
, col
);
1293 if ( n
== wxNOT_FOUND
)
1295 // add the attribute
1296 m_attrs
.Add(new wxGridCellWithAttr(row
, col
, attr
));
1302 // change the attribute
1303 m_attrs
[(size_t)n
].attr
= attr
;
1307 // remove this attribute
1308 m_attrs
.RemoveAt((size_t)n
);
1313 wxGridCellAttr
*wxGridCellAttrData
::GetAttr(int row
, int col
) const
1315 wxGridCellAttr
*attr
= (wxGridCellAttr
*)NULL
;
1317 int n
= FindIndex(row
, col
);
1318 if ( n
!= wxNOT_FOUND
)
1320 attr
= m_attrs
[(size_t)n
].attr
;
1327 void wxGridCellAttrData
::UpdateAttrRows( size_t pos
, int numRows
)
1329 size_t count
= m_attrs
.GetCount();
1330 for ( size_t n
= 0; n
< count
; n
++ )
1332 wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
1333 wxCoord row
= coords
.GetRow();
1334 if ((size_t)row
>= pos
)
1338 // If rows inserted, include row counter where necessary
1339 coords
.SetRow(row
+ numRows
);
1341 else if (numRows
< 0)
1343 // If rows deleted ...
1344 if ((size_t)row
>= pos
- numRows
)
1346 // ...either decrement row counter (if row still exists)...
1347 coords
.SetRow(row
+ numRows
);
1351 // ...or remove the attribute
1352 m_attrs
.RemoveAt((size_t)n
);
1360 void wxGridCellAttrData
::UpdateAttrCols( size_t pos
, int numCols
)
1362 size_t count
= m_attrs
.GetCount();
1363 for ( size_t n
= 0; n
< count
; n
++ )
1365 wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
1366 wxCoord col
= coords
.GetCol();
1367 if ( (size_t)col
>= pos
)
1371 // If rows inserted, include row counter where necessary
1372 coords
.SetCol(col
+ numCols
);
1374 else if (numCols
< 0)
1376 // If rows deleted ...
1377 if ((size_t)col
>= pos
- numCols
)
1379 // ...either decrement row counter (if row still exists)...
1380 coords
.SetCol(col
+ numCols
);
1384 // ...or remove the attribute
1385 m_attrs
.RemoveAt((size_t)n
);
1393 int wxGridCellAttrData
::FindIndex(int row
, int col
) const
1395 size_t count
= m_attrs
.GetCount();
1396 for ( size_t n
= 0; n
< count
; n
++ )
1398 const wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
1399 if ( (coords
.GetRow() == row
) && (coords
.GetCol() == col
) )
1408 // ----------------------------------------------------------------------------
1409 // wxGridRowOrColAttrData
1410 // ----------------------------------------------------------------------------
1412 wxGridRowOrColAttrData
::~wxGridRowOrColAttrData()
1414 size_t count
= m_attrs
.Count();
1415 for ( size_t n
= 0; n
< count
; n
++ )
1417 m_attrs
[n
]->DecRef();
1421 wxGridCellAttr
*wxGridRowOrColAttrData
::GetAttr(int rowOrCol
) const
1423 wxGridCellAttr
*attr
= (wxGridCellAttr
*)NULL
;
1425 int n
= m_rowsOrCols
.Index(rowOrCol
);
1426 if ( n
!= wxNOT_FOUND
)
1428 attr
= m_attrs
[(size_t)n
];
1435 void wxGridRowOrColAttrData
::SetAttr(wxGridCellAttr
*attr
, int rowOrCol
)
1437 int n
= m_rowsOrCols
.Index(rowOrCol
);
1438 if ( n
== wxNOT_FOUND
)
1440 // add the attribute
1441 m_rowsOrCols
.Add(rowOrCol
);
1448 // change the attribute
1449 m_attrs
[(size_t)n
] = attr
;
1453 // remove this attribute
1454 m_attrs
[(size_t)n
]->DecRef();
1455 m_rowsOrCols
.RemoveAt((size_t)n
);
1456 m_attrs
.RemoveAt((size_t)n
);
1461 void wxGridRowOrColAttrData
::UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols
)
1463 size_t count
= m_attrs
.GetCount();
1464 for ( size_t n
= 0; n
< count
; n
++ )
1466 int & rowOrCol
= m_rowsOrCols
[n
];
1467 if ( (size_t)rowOrCol
>= pos
)
1469 if ( numRowsOrCols
> 0 )
1471 // If rows inserted, include row counter where necessary
1472 rowOrCol
+= numRowsOrCols
;
1474 else if ( numRowsOrCols
< 0)
1476 // If rows deleted, either decrement row counter (if row still exists)
1477 if ((size_t)rowOrCol
>= pos
- numRowsOrCols
)
1478 rowOrCol
+= numRowsOrCols
;
1481 m_rowsOrCols
.RemoveAt((size_t)n
);
1482 m_attrs
.RemoveAt((size_t)n
);
1490 // ----------------------------------------------------------------------------
1491 // wxGridCellAttrProvider
1492 // ----------------------------------------------------------------------------
1494 wxGridCellAttrProvider
::wxGridCellAttrProvider()
1496 m_data
= (wxGridCellAttrProviderData
*)NULL
;
1499 wxGridCellAttrProvider
::~wxGridCellAttrProvider()
1504 void wxGridCellAttrProvider
::InitData()
1506 m_data
= new wxGridCellAttrProviderData
;
1509 wxGridCellAttr
*wxGridCellAttrProvider
::GetAttr(int row
, int col
) const
1511 wxGridCellAttr
*attr
= (wxGridCellAttr
*)NULL
;
1514 // first look for the attribute of this specific cell
1515 attr
= m_data
->m_cellAttrs
.GetAttr(row
, col
);
1519 // then look for the col attr (col attributes are more common than
1520 // the row ones, hence they have priority)
1521 attr
= m_data
->m_colAttrs
.GetAttr(col
);
1526 // finally try the row attributes
1527 attr
= m_data
->m_rowAttrs
.GetAttr(row
);
1534 void wxGridCellAttrProvider
::SetAttr(wxGridCellAttr
*attr
,
1540 m_data
->m_cellAttrs
.SetAttr(attr
, row
, col
);
1543 void wxGridCellAttrProvider
::SetRowAttr(wxGridCellAttr
*attr
, int row
)
1548 m_data
->m_rowAttrs
.SetAttr(attr
, row
);
1551 void wxGridCellAttrProvider
::SetColAttr(wxGridCellAttr
*attr
, int col
)
1556 m_data
->m_colAttrs
.SetAttr(attr
, col
);
1559 void wxGridCellAttrProvider
::UpdateAttrRows( size_t pos
, int numRows
)
1563 m_data
->m_cellAttrs
.UpdateAttrRows( pos
, numRows
);
1565 m_data
->m_rowAttrs
.UpdateAttrRowsOrCols( pos
, numRows
);
1569 void wxGridCellAttrProvider
::UpdateAttrCols( size_t pos
, int numCols
)
1573 m_data
->m_cellAttrs
.UpdateAttrCols( pos
, numCols
);
1575 m_data
->m_colAttrs
.UpdateAttrRowsOrCols( pos
, numCols
);
1579 // ----------------------------------------------------------------------------
1580 // wxGridTypeRegistry
1581 // ----------------------------------------------------------------------------
1583 wxGridTypeRegistry
::~wxGridTypeRegistry()
1585 for (size_t i
=0; i
<m_typeinfo
.Count(); i
++)
1586 delete m_typeinfo
[i
];
1590 void wxGridTypeRegistry
::RegisterDataType(const wxString
& typeName
,
1591 wxGridCellRenderer
* renderer
,
1592 wxGridCellEditor
* editor
)
1595 wxGridDataTypeInfo
* info
= new wxGridDataTypeInfo(typeName
, renderer
, editor
);
1597 // is it already registered?
1598 if ((loc
= FindDataType(typeName
)) != -1) {
1599 delete m_typeinfo
[loc
];
1600 m_typeinfo
[loc
] = info
;
1603 m_typeinfo
.Add(info
);
1607 int wxGridTypeRegistry
::FindDataType(const wxString
& typeName
)
1611 for (size_t i
=0; i
<m_typeinfo
.Count(); i
++) {
1612 if (typeName
== m_typeinfo
[i
]->m_typeName
) {
1621 wxGridCellRenderer
* wxGridTypeRegistry
::GetRenderer(int index
)
1623 wxGridCellRenderer
* renderer
= m_typeinfo
[index
]->m_renderer
;
1627 wxGridCellEditor
* wxGridTypeRegistry
::GetEditor(int index
)
1629 wxGridCellEditor
* editor
= m_typeinfo
[index
]->m_editor
;
1633 // ----------------------------------------------------------------------------
1635 // ----------------------------------------------------------------------------
1637 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject
)
1640 wxGridTableBase
::wxGridTableBase()
1642 m_view
= (wxGrid
*) NULL
;
1643 m_attrProvider
= (wxGridCellAttrProvider
*) NULL
;
1646 wxGridTableBase
::~wxGridTableBase()
1648 delete m_attrProvider
;
1651 void wxGridTableBase
::SetAttrProvider(wxGridCellAttrProvider
*attrProvider
)
1653 delete m_attrProvider
;
1654 m_attrProvider
= attrProvider
;
1657 bool wxGridTableBase
::CanHaveAttributes()
1659 if ( ! GetAttrProvider() )
1661 // use the default attr provider by default
1662 SetAttrProvider(new wxGridCellAttrProvider
);
1667 wxGridCellAttr
*wxGridTableBase
::GetAttr(int row
, int col
)
1669 if ( m_attrProvider
)
1670 return m_attrProvider
->GetAttr(row
, col
);
1672 return (wxGridCellAttr
*)NULL
;
1675 void wxGridTableBase
::SetAttr(wxGridCellAttr
* attr
, int row
, int col
)
1677 if ( m_attrProvider
)
1679 m_attrProvider
->SetAttr(attr
, row
, col
);
1683 // as we take ownership of the pointer and don't store it, we must
1689 void wxGridTableBase
::SetRowAttr(wxGridCellAttr
*attr
, int row
)
1691 if ( m_attrProvider
)
1693 m_attrProvider
->SetRowAttr(attr
, row
);
1697 // as we take ownership of the pointer and don't store it, we must
1703 void wxGridTableBase
::SetColAttr(wxGridCellAttr
*attr
, int col
)
1705 if ( m_attrProvider
)
1707 m_attrProvider
->SetColAttr(attr
, col
);
1711 // as we take ownership of the pointer and don't store it, we must
1717 void wxGridTableBase
::UpdateAttrRows( size_t pos
, int numRows
)
1719 if ( m_attrProvider
)
1721 m_attrProvider
->UpdateAttrRows( pos
, numRows
);
1725 void wxGridTableBase
::UpdateAttrCols( size_t pos
, int numCols
)
1727 if ( m_attrProvider
)
1729 m_attrProvider
->UpdateAttrCols( pos
, numCols
);
1733 bool wxGridTableBase
::InsertRows( size_t pos
, size_t numRows
)
1735 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
1736 "but your derived table class does not override this function") );
1741 bool wxGridTableBase
::AppendRows( size_t numRows
)
1743 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
1744 "but your derived table class does not override this function"));
1749 bool wxGridTableBase
::DeleteRows( size_t pos
, size_t numRows
)
1751 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
1752 "but your derived table class does not override this function"));
1757 bool wxGridTableBase
::InsertCols( size_t pos
, size_t numCols
)
1759 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
1760 "but your derived table class does not override this function"));
1765 bool wxGridTableBase
::AppendCols( size_t numCols
)
1767 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
1768 "but your derived table class does not override this function"));
1773 bool wxGridTableBase
::DeleteCols( size_t pos
, size_t numCols
)
1775 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
1776 "but your derived table class does not override this function"));
1782 wxString wxGridTableBase
::GetRowLabelValue( int row
)
1785 s
<< row
+ 1; // RD: Starting the rows at zero confuses users, no matter
1786 // how much it makes sense to us geeks.
1790 wxString wxGridTableBase
::GetColLabelValue( int col
)
1792 // default col labels are:
1793 // cols 0 to 25 : A-Z
1794 // cols 26 to 675 : AA-ZZ
1799 for ( n
= 1; ; n
++ )
1801 s
+= (_T('A') + (wxChar
)( col
%26 ));
1803 if ( col
< 0 ) break;
1806 // reverse the string...
1808 for ( i
= 0; i
< n
; i
++ )
1817 wxString wxGridTableBase
::GetTypeName( int WXUNUSED(row
), int WXUNUSED(col
) )
1819 return wxGRID_VALUE_STRING
;
1822 bool wxGridTableBase
::CanGetValueAs( int WXUNUSED(row
), int WXUNUSED(col
),
1823 const wxString
& typeName
)
1825 return typeName
== wxGRID_VALUE_STRING
;
1828 bool wxGridTableBase
::CanSetValueAs( int row
, int col
, const wxString
& typeName
)
1830 return CanGetValueAs(row
, col
, typeName
);
1833 long wxGridTableBase
::GetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
) )
1838 double wxGridTableBase
::GetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
) )
1843 bool wxGridTableBase
::GetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
) )
1848 void wxGridTableBase
::SetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
),
1849 long WXUNUSED(value
) )
1853 void wxGridTableBase
::SetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
),
1854 double WXUNUSED(value
) )
1858 void wxGridTableBase
::SetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
),
1859 bool WXUNUSED(value
) )
1864 void* wxGridTableBase
::GetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
),
1865 const wxString
& WXUNUSED(typeName
) )
1870 void wxGridTableBase
::SetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
),
1871 const wxString
& WXUNUSED(typeName
),
1872 void* WXUNUSED(value
) )
1877 //////////////////////////////////////////////////////////////////////
1879 // Message class for the grid table to send requests and notifications
1883 wxGridTableMessage
::wxGridTableMessage()
1885 m_table
= (wxGridTableBase
*) NULL
;
1891 wxGridTableMessage
::wxGridTableMessage( wxGridTableBase
*table
, int id
,
1892 int commandInt1
, int commandInt2
)
1896 m_comInt1
= commandInt1
;
1897 m_comInt2
= commandInt2
;
1902 //////////////////////////////////////////////////////////////////////
1904 // A basic grid table for string data. An object of this class will
1905 // created by wxGrid if you don't specify an alternative table class.
1908 WX_DEFINE_OBJARRAY(wxGridStringArray
)
1910 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase
)
1912 wxGridStringTable
::wxGridStringTable()
1917 wxGridStringTable
::wxGridStringTable( int numRows
, int numCols
)
1922 m_data
.Alloc( numRows
);
1925 sa
.Alloc( numCols
);
1926 for ( col
= 0; col
< numCols
; col
++ )
1928 sa
.Add( wxEmptyString
);
1931 for ( row
= 0; row
< numRows
; row
++ )
1937 wxGridStringTable
::~wxGridStringTable()
1941 long wxGridStringTable
::GetNumberRows()
1943 return m_data
.GetCount();
1946 long wxGridStringTable
::GetNumberCols()
1948 if ( m_data
.GetCount() > 0 )
1949 return m_data
[0].GetCount();
1954 wxString wxGridStringTable
::GetValue( int row
, int col
)
1956 // TODO: bounds checking
1958 return m_data
[row
][col
];
1961 void wxGridStringTable
::SetValue( int row
, int col
, const wxString
& value
)
1963 // TODO: bounds checking
1965 m_data
[row
][col
] = value
;
1968 bool wxGridStringTable
::IsEmptyCell( int row
, int col
)
1970 // TODO: bounds checking
1972 return (m_data
[row
][col
] == wxEmptyString
);
1976 void wxGridStringTable
::Clear()
1979 int numRows
, numCols
;
1981 numRows
= m_data
.GetCount();
1984 numCols
= m_data
[0].GetCount();
1986 for ( row
= 0; row
< numRows
; row
++ )
1988 for ( col
= 0; col
< numCols
; col
++ )
1990 m_data
[row
][col
] = wxEmptyString
;
1997 bool wxGridStringTable
::InsertRows( size_t pos
, size_t numRows
)
2001 size_t curNumRows
= m_data
.GetCount();
2002 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
2004 if ( pos
>= curNumRows
)
2006 return AppendRows( numRows
);
2010 sa
.Alloc( curNumCols
);
2011 for ( col
= 0; col
< curNumCols
; col
++ )
2013 sa
.Add( wxEmptyString
);
2016 for ( row
= pos
; row
< pos
+ numRows
; row
++ )
2018 m_data
.Insert( sa
, row
);
2020 UpdateAttrRows( pos
, numRows
);
2023 wxGridTableMessage
msg( this,
2024 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
,
2028 GetView()->ProcessTableMessage( msg
);
2034 bool wxGridStringTable
::AppendRows( size_t numRows
)
2038 size_t curNumRows
= m_data
.GetCount();
2039 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
2042 if ( curNumCols
> 0 )
2044 sa
.Alloc( curNumCols
);
2045 for ( col
= 0; col
< curNumCols
; col
++ )
2047 sa
.Add( wxEmptyString
);
2051 for ( row
= 0; row
< numRows
; row
++ )
2058 wxGridTableMessage
msg( this,
2059 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
,
2062 GetView()->ProcessTableMessage( msg
);
2068 bool wxGridStringTable
::DeleteRows( size_t pos
, size_t numRows
)
2072 size_t curNumRows
= m_data
.GetCount();
2074 if ( pos
>= curNumRows
)
2077 errmsg
.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
2078 "Pos value is invalid for present table with %d rows",
2079 pos
, numRows
, curNumRows
);
2080 wxFAIL_MSG( wxT(errmsg
) );
2084 if ( numRows
> curNumRows
- pos
)
2086 numRows
= curNumRows
- pos
;
2089 if ( numRows
>= curNumRows
)
2091 m_data
.Empty(); // don't release memory just yet
2095 for ( n
= 0; n
< numRows
; n
++ )
2097 m_data
.Remove( pos
);
2100 UpdateAttrRows( pos
, -((int)numRows
) );
2103 wxGridTableMessage
msg( this,
2104 wxGRIDTABLE_NOTIFY_ROWS_DELETED
,
2108 GetView()->ProcessTableMessage( msg
);
2114 bool wxGridStringTable
::InsertCols( size_t pos
, size_t numCols
)
2118 size_t curNumRows
= m_data
.GetCount();
2119 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
2121 if ( pos
>= curNumCols
)
2123 return AppendCols( numCols
);
2126 for ( row
= 0; row
< curNumRows
; row
++ )
2128 for ( col
= pos
; col
< pos
+ numCols
; col
++ )
2130 m_data
[row
].Insert( wxEmptyString
, col
);
2133 UpdateAttrCols( pos
, numCols
);
2136 wxGridTableMessage
msg( this,
2137 wxGRIDTABLE_NOTIFY_COLS_INSERTED
,
2141 GetView()->ProcessTableMessage( msg
);
2147 bool wxGridStringTable
::AppendCols( size_t numCols
)
2151 size_t curNumRows
= m_data
.GetCount();
2154 // TODO: something better than this ?
2156 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
2157 "Call AppendRows() first") );
2161 for ( row
= 0; row
< curNumRows
; row
++ )
2163 for ( n
= 0; n
< numCols
; n
++ )
2165 m_data
[row
].Add( wxEmptyString
);
2171 wxGridTableMessage
msg( this,
2172 wxGRIDTABLE_NOTIFY_COLS_APPENDED
,
2175 GetView()->ProcessTableMessage( msg
);
2181 bool wxGridStringTable
::DeleteCols( size_t pos
, size_t numCols
)
2185 size_t curNumRows
= m_data
.GetCount();
2186 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
2188 if ( pos
>= curNumCols
)
2191 errmsg
.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
2192 "Pos value is invalid for present table with %d cols",
2193 pos
, numCols
, curNumCols
);
2194 wxFAIL_MSG( wxT( errmsg
) );
2198 if ( numCols
> curNumCols
- pos
)
2200 numCols
= curNumCols
- pos
;
2203 for ( row
= 0; row
< curNumRows
; row
++ )
2205 if ( numCols
>= curNumCols
)
2207 m_data
[row
].Clear();
2211 for ( n
= 0; n
< numCols
; n
++ )
2213 m_data
[row
].Remove( pos
);
2217 UpdateAttrCols( pos
, -((int)numCols
) );
2220 wxGridTableMessage
msg( this,
2221 wxGRIDTABLE_NOTIFY_COLS_DELETED
,
2225 GetView()->ProcessTableMessage( msg
);
2231 wxString wxGridStringTable
::GetRowLabelValue( int row
)
2233 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
2235 // using default label
2237 return wxGridTableBase
::GetRowLabelValue( row
);
2241 return m_rowLabels
[ row
];
2245 wxString wxGridStringTable
::GetColLabelValue( int col
)
2247 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
2249 // using default label
2251 return wxGridTableBase
::GetColLabelValue( col
);
2255 return m_colLabels
[ col
];
2259 void wxGridStringTable
::SetRowLabelValue( int row
, const wxString
& value
)
2261 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
2263 int n
= m_rowLabels
.GetCount();
2265 for ( i
= n
; i
<= row
; i
++ )
2267 m_rowLabels
.Add( wxGridTableBase
::GetRowLabelValue(i
) );
2271 m_rowLabels
[row
] = value
;
2274 void wxGridStringTable
::SetColLabelValue( int col
, const wxString
& value
)
2276 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
2278 int n
= m_colLabels
.GetCount();
2280 for ( i
= n
; i
<= col
; i
++ )
2282 m_colLabels
.Add( wxGridTableBase
::GetColLabelValue(i
) );
2286 m_colLabels
[col
] = value
;
2291 //////////////////////////////////////////////////////////////////////
2292 //////////////////////////////////////////////////////////////////////
2294 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow
, wxWindow
)
2296 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxWindow
)
2297 EVT_PAINT( wxGridRowLabelWindow
::OnPaint
)
2298 EVT_MOUSE_EVENTS( wxGridRowLabelWindow
::OnMouseEvent
)
2299 EVT_KEY_DOWN( wxGridRowLabelWindow
::OnKeyDown
)
2302 wxGridRowLabelWindow
::wxGridRowLabelWindow( wxGrid
*parent
,
2304 const wxPoint
&pos
, const wxSize
&size
)
2305 : wxWindow( parent
, id
, pos
, size
)
2310 void wxGridRowLabelWindow
::OnPaint( wxPaintEvent
&event
)
2314 // NO - don't do this because it will set both the x and y origin
2315 // coords to match the parent scrolled window and we just want to
2316 // set the y coord - MB
2318 // m_owner->PrepareDC( dc );
2321 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
2322 dc
.SetDeviceOrigin( 0, -y
);
2324 m_owner
->CalcRowLabelsExposed( GetUpdateRegion() );
2325 m_owner
->DrawRowLabels( dc
);
2329 void wxGridRowLabelWindow
::OnMouseEvent( wxMouseEvent
& event
)
2331 m_owner
->ProcessRowLabelMouseEvent( event
);
2335 // This seems to be required for wxMotif otherwise the mouse
2336 // cursor must be in the cell edit control to get key events
2338 void wxGridRowLabelWindow
::OnKeyDown( wxKeyEvent
& event
)
2340 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
2345 //////////////////////////////////////////////////////////////////////
2347 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow
, wxWindow
)
2349 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxWindow
)
2350 EVT_PAINT( wxGridColLabelWindow
::OnPaint
)
2351 EVT_MOUSE_EVENTS( wxGridColLabelWindow
::OnMouseEvent
)
2352 EVT_KEY_DOWN( wxGridColLabelWindow
::OnKeyDown
)
2355 wxGridColLabelWindow
::wxGridColLabelWindow( wxGrid
*parent
,
2357 const wxPoint
&pos
, const wxSize
&size
)
2358 : wxWindow( parent
, id
, pos
, size
)
2363 void wxGridColLabelWindow
::OnPaint( wxPaintEvent
&event
)
2367 // NO - don't do this because it will set both the x and y origin
2368 // coords to match the parent scrolled window and we just want to
2369 // set the x coord - MB
2371 // m_owner->PrepareDC( dc );
2374 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
2375 dc
.SetDeviceOrigin( -x
, 0 );
2377 m_owner
->CalcColLabelsExposed( GetUpdateRegion() );
2378 m_owner
->DrawColLabels( dc
);
2382 void wxGridColLabelWindow
::OnMouseEvent( wxMouseEvent
& event
)
2384 m_owner
->ProcessColLabelMouseEvent( event
);
2388 // This seems to be required for wxMotif otherwise the mouse
2389 // cursor must be in the cell edit control to get key events
2391 void wxGridColLabelWindow
::OnKeyDown( wxKeyEvent
& event
)
2393 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
2398 //////////////////////////////////////////////////////////////////////
2400 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow
, wxWindow
)
2402 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxWindow
)
2403 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow
::OnMouseEvent
)
2404 EVT_PAINT( wxGridCornerLabelWindow
::OnPaint
)
2405 EVT_KEY_DOWN( wxGridCornerLabelWindow
::OnKeyDown
)
2408 wxGridCornerLabelWindow
::wxGridCornerLabelWindow( wxGrid
*parent
,
2410 const wxPoint
&pos
, const wxSize
&size
)
2411 : wxWindow( parent
, id
, pos
, size
)
2416 void wxGridCornerLabelWindow
::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
2420 int client_height
= 0;
2421 int client_width
= 0;
2422 GetClientSize( &client_width
, &client_height
);
2424 dc
.SetPen( *wxBLACK_PEN
);
2425 dc
.DrawLine( client_width
-1, client_height
-1, client_width
-1, 0 );
2426 dc
.DrawLine( client_width
-1, client_height
-1, 0, client_height
-1 );
2428 dc
.SetPen( *wxWHITE_PEN
);
2429 dc
.DrawLine( 0, 0, client_width
, 0 );
2430 dc
.DrawLine( 0, 0, 0, client_height
);
2434 void wxGridCornerLabelWindow
::OnMouseEvent( wxMouseEvent
& event
)
2436 m_owner
->ProcessCornerLabelMouseEvent( event
);
2440 // This seems to be required for wxMotif otherwise the mouse
2441 // cursor must be in the cell edit control to get key events
2443 void wxGridCornerLabelWindow
::OnKeyDown( wxKeyEvent
& event
)
2445 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
2450 //////////////////////////////////////////////////////////////////////
2452 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow
, wxPanel
)
2454 BEGIN_EVENT_TABLE( wxGridWindow
, wxPanel
)
2455 EVT_PAINT( wxGridWindow
::OnPaint
)
2456 EVT_MOUSE_EVENTS( wxGridWindow
::OnMouseEvent
)
2457 EVT_KEY_DOWN( wxGridWindow
::OnKeyDown
)
2458 EVT_ERASE_BACKGROUND( wxGridWindow
::OnEraseBackground
)
2461 wxGridWindow
::wxGridWindow( wxGrid
*parent
,
2462 wxGridRowLabelWindow
*rowLblWin
,
2463 wxGridColLabelWindow
*colLblWin
,
2464 wxWindowID id
, const wxPoint
&pos
, const wxSize
&size
)
2465 : wxPanel( parent
, id
, pos
, size
, 0, "grid window" )
2468 m_rowLabelWin
= rowLblWin
;
2469 m_colLabelWin
= colLblWin
;
2470 SetBackgroundColour( "WHITE" );
2474 wxGridWindow
::~wxGridWindow()
2479 void wxGridWindow
::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
2481 wxPaintDC
dc( this );
2482 m_owner
->PrepareDC( dc
);
2483 wxRegion reg
= GetUpdateRegion();
2484 m_owner
->CalcCellsExposed( reg
);
2485 m_owner
->DrawGridCellArea( dc
);
2486 #if WXGRID_DRAW_LINES
2487 m_owner
->DrawAllGridLines( dc
, reg
);
2489 m_owner
->DrawHighlight( dc
);
2493 void wxGridWindow
::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
2495 wxPanel
::ScrollWindow( dx
, dy
, rect
);
2496 m_rowLabelWin
->ScrollWindow( 0, dy
, rect
);
2497 m_colLabelWin
->ScrollWindow( dx
, 0, rect
);
2501 void wxGridWindow
::OnMouseEvent( wxMouseEvent
& event
)
2503 m_owner
->ProcessGridCellMouseEvent( event
);
2507 // This seems to be required for wxMotif otherwise the mouse
2508 // cursor must be in the cell edit control to get key events
2510 void wxGridWindow
::OnKeyDown( wxKeyEvent
& event
)
2512 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
2515 // We are trapping erase background events to reduce flicker under MSW
2516 // and GTK but this can leave junk in the space beyond the last row and
2517 // col. So here we paint these spaces if they are visible.
2519 void wxGridWindow
::OnEraseBackground(wxEraseEvent
& event
)
2522 GetClientSize( &cw
, &ch
);
2525 m_owner
->CalcUnscrolledPosition( cw
, ch
, &right
, &bottom
);
2528 rightRect
= m_owner
->CellToRect( 0, m_owner
->GetNumberCols()-1 );
2531 bottomRect
= m_owner
->CellToRect( m_owner
->GetNumberRows()-1, 0 );
2533 if ( right
> rightRect
.GetRight() || bottom
> bottomRect
.GetBottom() )
2536 m_owner
->CalcUnscrolledPosition( 0, 0, &left
, &top
);
2538 wxClientDC
dc( this );
2539 m_owner
->PrepareDC( dc
);
2540 dc
.SetBrush( wxBrush(m_owner
->GetDefaultCellBackgroundColour(), wxSOLID
) );
2541 dc
.SetPen( *wxTRANSPARENT_PEN
);
2543 if ( right
> rightRect
.GetRight() )
2544 dc
.DrawRectangle( rightRect
.GetRight()+1, top
, right
- rightRect
.GetRight(), ch
);
2546 if ( bottom
> bottomRect
.GetBottom() )
2547 dc
.DrawRectangle( left
, bottomRect
.GetBottom()+1, cw
, bottom
- bottomRect
.GetBottom() );
2552 //////////////////////////////////////////////////////////////////////
2555 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow
)
2557 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow
)
2558 EVT_PAINT( wxGrid
::OnPaint
)
2559 EVT_SIZE( wxGrid
::OnSize
)
2560 EVT_KEY_DOWN( wxGrid
::OnKeyDown
)
2561 EVT_ERASE_BACKGROUND( wxGrid
::OnEraseBackground
)
2564 wxGrid
::wxGrid( wxWindow
*parent
,
2569 const wxString
& name
)
2570 : wxScrolledWindow( parent
, id
, pos
, size
, style
, name
),
2571 m_colMinWidths(wxKEY_INTEGER
, GRID_HASH_SIZE
)
2580 m_defaultCellAttr
->SafeDecRef();
2582 #ifdef DEBUG_ATTR_CACHE
2583 size_t total
= gs_nAttrCacheHits
+ gs_nAttrCacheMisses
;
2584 wxPrintf(_T("wxGrid attribute cache statistics: "
2585 "total: %u, hits: %u (%u%%)\n"),
2586 total
, gs_nAttrCacheHits
,
2587 total ?
(gs_nAttrCacheHits
*100) / total
: 0);
2593 delete m_typeRegistry
;
2598 // ----- internal init and update functions
2601 void wxGrid
::Create()
2603 m_created
= FALSE
; // set to TRUE by CreateGrid
2604 m_displayed
= TRUE
; // FALSE; // set to TRUE by OnPaint
2606 m_table
= (wxGridTableBase
*) NULL
;
2609 m_cellEditCtrlEnabled
= FALSE
;
2611 m_defaultCellAttr
= new wxGridCellAttr
;
2612 m_defaultCellAttr
->SetDefAttr(m_defaultCellAttr
);
2614 // Set default cell attributes
2615 m_defaultCellAttr
->SetFont(GetFont());
2616 m_defaultCellAttr
->SetAlignment(wxLEFT
, wxTOP
);
2617 m_defaultCellAttr
->SetTextColour(
2618 wxSystemSettings
::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT
));
2619 m_defaultCellAttr
->SetBackgroundColour(
2620 wxSystemSettings
::GetSystemColour(wxSYS_COLOUR_WINDOW
));
2621 m_defaultCellAttr
->SetRenderer(new wxGridCellStringRenderer
);
2622 m_defaultCellAttr
->SetEditor(new wxGridCellTextEditor
);
2627 m_currentCellCoords
= wxGridNoCellCoords
;
2629 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
2630 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
2632 // data type registration: register all standard data types
2633 // TODO: may be allow the app to selectively disable some of them?
2634 m_typeRegistry
= new wxGridTypeRegistry
;
2635 RegisterDataType(wxGRID_VALUE_STRING
,
2636 new wxGridCellStringRenderer
,
2637 new wxGridCellTextEditor
);
2638 RegisterDataType(wxGRID_VALUE_BOOL
,
2639 new wxGridCellBoolRenderer
,
2640 new wxGridCellBoolEditor
);
2641 RegisterDataType(wxGRID_VALUE_NUMBER
,
2642 new wxGridCellNumberRenderer
,
2643 new wxGridCellNumberEditor
);
2645 // subwindow components that make up the wxGrid
2646 m_cornerLabelWin
= new wxGridCornerLabelWindow( this,
2651 m_rowLabelWin
= new wxGridRowLabelWindow( this,
2656 m_colLabelWin
= new wxGridColLabelWindow( this,
2661 m_gridWin
= new wxGridWindow( this,
2668 SetTargetWindow( m_gridWin
);
2672 bool wxGrid
::CreateGrid( int numRows
, int numCols
)
2676 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
2681 m_numRows
= numRows
;
2682 m_numCols
= numCols
;
2684 m_table
= new wxGridStringTable( m_numRows
, m_numCols
);
2685 m_table
->SetView( this );
2694 bool wxGrid
::SetTable( wxGridTableBase
*table
, bool takeOwnership
)
2698 // RD: Actually, this should probably be allowed. I think it would be
2699 // nice to be able to switch multiple Tables in and out of a single
2700 // View at runtime. Is there anything in the implmentation that would
2703 wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
2708 m_numRows
= table
->GetNumberRows();
2709 m_numCols
= table
->GetNumberCols();
2712 m_table
->SetView( this );
2725 if ( m_numRows
<= 0 )
2726 m_numRows
= WXGRID_DEFAULT_NUMBER_ROWS
;
2728 if ( m_numCols
<= 0 )
2729 m_numCols
= WXGRID_DEFAULT_NUMBER_COLS
;
2731 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
2732 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
2734 if ( m_rowLabelWin
)
2736 m_labelBackgroundColour
= m_rowLabelWin
->GetBackgroundColour();
2740 m_labelBackgroundColour
= wxColour( _T("WHITE") );
2743 m_labelTextColour
= wxColour( _T("BLACK") );
2746 m_attrCache
.row
= -1;
2748 // TODO: something better than this ?
2750 m_labelFont
= this->GetFont();
2751 m_labelFont
.SetWeight( m_labelFont
.GetWeight() + 2 );
2753 m_rowLabelHorizAlign
= wxLEFT
;
2754 m_rowLabelVertAlign
= wxCENTRE
;
2756 m_colLabelHorizAlign
= wxCENTRE
;
2757 m_colLabelVertAlign
= wxTOP
;
2759 m_defaultColWidth
= WXGRID_DEFAULT_COL_WIDTH
;
2760 m_defaultRowHeight
= m_gridWin
->GetCharHeight();
2762 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
2763 m_defaultRowHeight
+= 8;
2765 m_defaultRowHeight
+= 4;
2768 m_gridLineColour
= wxColour( 128, 128, 255 );
2769 m_gridLinesEnabled
= TRUE
;
2771 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
2772 m_winCapture
= (wxWindow
*)NULL
;
2773 m_canDragRowSize
= TRUE
;
2774 m_canDragColSize
= TRUE
;
2776 m_dragRowOrCol
= -1;
2777 m_isDragging
= FALSE
;
2778 m_startDragPos
= wxDefaultPosition
;
2780 m_waitForSlowClick
= FALSE
;
2782 m_rowResizeCursor
= wxCursor( wxCURSOR_SIZENS
);
2783 m_colResizeCursor
= wxCursor( wxCURSOR_SIZEWE
);
2785 m_currentCellCoords
= wxGridNoCellCoords
;
2787 m_selectedTopLeft
= wxGridNoCellCoords
;
2788 m_selectedBottomRight
= wxGridNoCellCoords
;
2789 m_selectionBackground
= wxSystemSettings
::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT
);
2790 m_selectionForeground
= wxSystemSettings
::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
2792 m_editable
= TRUE
; // default for whole grid
2794 m_inOnKeyDown
= FALSE
;
2798 // ----------------------------------------------------------------------------
2799 // the idea is to call these functions only when necessary because they create
2800 // quite big arrays which eat memory mostly unnecessary - in particular, if
2801 // default widths/heights are used for all rows/columns, we may not use these
2804 // with some extra code, it should be possible to only store the
2805 // widths/heights different from default ones but this will be done later...
2806 // ----------------------------------------------------------------------------
2808 void wxGrid
::InitRowHeights()
2810 m_rowHeights
.Empty();
2811 m_rowBottoms
.Empty();
2813 m_rowHeights
.Alloc( m_numRows
);
2814 m_rowBottoms
.Alloc( m_numRows
);
2817 for ( int i
= 0; i
< m_numRows
; i
++ )
2819 m_rowHeights
.Add( m_defaultRowHeight
);
2820 rowBottom
+= m_defaultRowHeight
;
2821 m_rowBottoms
.Add( rowBottom
);
2825 void wxGrid
::InitColWidths()
2827 m_colWidths
.Empty();
2828 m_colRights
.Empty();
2830 m_colWidths
.Alloc( m_numCols
);
2831 m_colRights
.Alloc( m_numCols
);
2833 for ( int i
= 0; i
< m_numCols
; i
++ )
2835 m_colWidths
.Add( m_defaultColWidth
);
2836 colRight
+= m_defaultColWidth
;
2837 m_colRights
.Add( colRight
);
2841 int wxGrid
::GetColWidth(int col
) const
2843 return m_colWidths
.IsEmpty() ? m_defaultColWidth
: m_colWidths
[col
];
2846 int wxGrid
::GetColLeft(int col
) const
2848 return m_colRights
.IsEmpty() ? col
* m_defaultColWidth
2849 : m_colRights
[col
] - m_colWidths
[col
];
2852 int wxGrid
::GetColRight(int col
) const
2854 return m_colRights
.IsEmpty() ?
(col
+ 1) * m_defaultColWidth
2858 int wxGrid
::GetRowHeight(int row
) const
2860 return m_rowHeights
.IsEmpty() ? m_defaultRowHeight
: m_rowHeights
[row
];
2863 int wxGrid
::GetRowTop(int row
) const
2865 return m_rowBottoms
.IsEmpty() ? row
* m_defaultRowHeight
2866 : m_rowBottoms
[row
] - m_rowHeights
[row
];
2869 int wxGrid
::GetRowBottom(int row
) const
2871 return m_rowBottoms
.IsEmpty() ?
(row
+ 1) * m_defaultRowHeight
2872 : m_rowBottoms
[row
];
2875 void wxGrid
::CalcDimensions()
2878 GetClientSize( &cw
, &ch
);
2880 if ( m_numRows
> 0 && m_numCols
> 0 )
2882 int right
= GetColRight( m_numCols
-1 ) + 50;
2883 int bottom
= GetRowBottom( m_numRows
-1 ) + 50;
2885 // TODO: restore the scroll position that we had before sizing
2888 GetViewStart( &x
, &y
);
2889 SetScrollbars( GRID_SCROLL_LINE
, GRID_SCROLL_LINE
,
2890 right
/GRID_SCROLL_LINE
, bottom
/GRID_SCROLL_LINE
,
2896 void wxGrid
::CalcWindowSizes()
2899 GetClientSize( &cw
, &ch
);
2901 if ( m_cornerLabelWin
->IsShown() )
2902 m_cornerLabelWin
->SetSize( 0, 0, m_rowLabelWidth
, m_colLabelHeight
);
2904 if ( m_colLabelWin
->IsShown() )
2905 m_colLabelWin
->SetSize( m_rowLabelWidth
, 0, cw
-m_rowLabelWidth
, m_colLabelHeight
);
2907 if ( m_rowLabelWin
->IsShown() )
2908 m_rowLabelWin
->SetSize( 0, m_colLabelHeight
, m_rowLabelWidth
, ch
-m_colLabelHeight
);
2910 if ( m_gridWin
->IsShown() )
2911 m_gridWin
->SetSize( m_rowLabelWidth
, m_colLabelHeight
, cw
-m_rowLabelWidth
, ch
-m_colLabelHeight
);
2915 // this is called when the grid table sends a message to say that it
2916 // has been redimensioned
2918 bool wxGrid
::Redimension( wxGridTableMessage
& msg
)
2922 // if we were using the default widths/heights so far, we must change them
2924 if ( m_colWidths
.IsEmpty() )
2929 if ( m_rowHeights
.IsEmpty() )
2934 switch ( msg
.GetId() )
2936 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
2938 size_t pos
= msg
.GetCommandInt();
2939 int numRows
= msg
.GetCommandInt2();
2940 for ( i
= 0; i
< numRows
; i
++ )
2942 m_rowHeights
.Insert( m_defaultRowHeight
, pos
);
2943 m_rowBottoms
.Insert( 0, pos
);
2945 m_numRows
+= numRows
;
2948 if ( pos
> 0 ) bottom
= m_rowBottoms
[pos
-1];
2950 for ( i
= pos
; i
< m_numRows
; i
++ )
2952 bottom
+= m_rowHeights
[i
];
2953 m_rowBottoms
[i
] = bottom
;
2959 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
2961 int numRows
= msg
.GetCommandInt();
2962 for ( i
= 0; i
< numRows
; i
++ )
2964 m_rowHeights
.Add( m_defaultRowHeight
);
2965 m_rowBottoms
.Add( 0 );
2968 int oldNumRows
= m_numRows
;
2969 m_numRows
+= numRows
;
2972 if ( oldNumRows
> 0 ) bottom
= m_rowBottoms
[oldNumRows
-1];
2974 for ( i
= oldNumRows
; i
< m_numRows
; i
++ )
2976 bottom
+= m_rowHeights
[i
];
2977 m_rowBottoms
[i
] = bottom
;
2983 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
2985 size_t pos
= msg
.GetCommandInt();
2986 int numRows
= msg
.GetCommandInt2();
2987 for ( i
= 0; i
< numRows
; i
++ )
2989 m_rowHeights
.Remove( pos
);
2990 m_rowBottoms
.Remove( pos
);
2992 m_numRows
-= numRows
;
2997 m_colWidths
.Clear();
2998 m_colRights
.Clear();
2999 m_currentCellCoords
= wxGridNoCellCoords
;
3003 if ( m_currentCellCoords
.GetRow() >= m_numRows
)
3004 m_currentCellCoords
.Set( 0, 0 );
3007 for ( i
= 0; i
< m_numRows
; i
++ )
3009 h
+= m_rowHeights
[i
];
3010 m_rowBottoms
[i
] = h
;
3018 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
3020 size_t pos
= msg
.GetCommandInt();
3021 int numCols
= msg
.GetCommandInt2();
3022 for ( i
= 0; i
< numCols
; i
++ )
3024 m_colWidths
.Insert( m_defaultColWidth
, pos
);
3025 m_colRights
.Insert( 0, pos
);
3027 m_numCols
+= numCols
;
3030 if ( pos
> 0 ) right
= m_colRights
[pos
-1];
3032 for ( i
= pos
; i
< m_numCols
; i
++ )
3034 right
+= m_colWidths
[i
];
3035 m_colRights
[i
] = right
;
3041 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
3043 int numCols
= msg
.GetCommandInt();
3044 for ( i
= 0; i
< numCols
; i
++ )
3046 m_colWidths
.Add( m_defaultColWidth
);
3047 m_colRights
.Add( 0 );
3050 int oldNumCols
= m_numCols
;
3051 m_numCols
+= numCols
;
3054 if ( oldNumCols
> 0 ) right
= m_colRights
[oldNumCols
-1];
3056 for ( i
= oldNumCols
; i
< m_numCols
; i
++ )
3058 right
+= m_colWidths
[i
];
3059 m_colRights
[i
] = right
;
3065 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
3067 size_t pos
= msg
.GetCommandInt();
3068 int numCols
= msg
.GetCommandInt2();
3069 for ( i
= 0; i
< numCols
; i
++ )
3071 m_colWidths
.Remove( pos
);
3072 m_colRights
.Remove( pos
);
3074 m_numCols
-= numCols
;
3078 #if 0 // leave the row alone here so that AppendCols will work subsequently
3080 m_rowHeights
.Clear();
3081 m_rowBottoms
.Clear();
3083 m_currentCellCoords
= wxGridNoCellCoords
;
3087 if ( m_currentCellCoords
.GetCol() >= m_numCols
)
3088 m_currentCellCoords
.Set( 0, 0 );
3091 for ( i
= 0; i
< m_numCols
; i
++ )
3093 w
+= m_colWidths
[i
];
3106 void wxGrid
::CalcRowLabelsExposed( wxRegion
& reg
)
3108 wxRegionIterator
iter( reg
);
3111 m_rowLabelsExposed
.Empty();
3118 // TODO: remove this when we can...
3119 // There is a bug in wxMotif that gives garbage update
3120 // rectangles if you jump-scroll a long way by clicking the
3121 // scrollbar with middle button. This is a work-around
3123 #if defined(__WXMOTIF__)
3125 m_gridWin
->GetClientSize( &cw
, &ch
);
3126 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
3127 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
3130 // logical bounds of update region
3133 CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top
);
3134 CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom
);
3136 // find the row labels within these bounds
3139 for ( row
= 0; row
< m_numRows
; row
++ )
3141 if ( GetRowBottom(row
) < top
)
3144 if ( GetRowTop(row
) > bottom
)
3147 m_rowLabelsExposed
.Add( row
);
3155 void wxGrid
::CalcColLabelsExposed( wxRegion
& reg
)
3157 wxRegionIterator
iter( reg
);
3160 m_colLabelsExposed
.Empty();
3167 // TODO: remove this when we can...
3168 // There is a bug in wxMotif that gives garbage update
3169 // rectangles if you jump-scroll a long way by clicking the
3170 // scrollbar with middle button. This is a work-around
3172 #if defined(__WXMOTIF__)
3174 m_gridWin
->GetClientSize( &cw
, &ch
);
3175 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
3176 r
.SetRight( wxMin( r
.GetRight(), cw
) );
3179 // logical bounds of update region
3182 CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy
);
3183 CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy
);
3185 // find the cells within these bounds
3188 for ( col
= 0; col
< m_numCols
; col
++ )
3190 if ( GetColRight(col
) < left
)
3193 if ( GetColLeft(col
) > right
)
3196 m_colLabelsExposed
.Add( col
);
3204 void wxGrid
::CalcCellsExposed( wxRegion
& reg
)
3206 wxRegionIterator
iter( reg
);
3209 m_cellsExposed
.Empty();
3210 m_rowsExposed
.Empty();
3211 m_colsExposed
.Empty();
3213 int left
, top
, right
, bottom
;
3218 // TODO: remove this when we can...
3219 // There is a bug in wxMotif that gives garbage update
3220 // rectangles if you jump-scroll a long way by clicking the
3221 // scrollbar with middle button. This is a work-around
3223 #if defined(__WXMOTIF__)
3225 m_gridWin
->GetClientSize( &cw
, &ch
);
3226 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
3227 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
3228 r
.SetRight( wxMin( r
.GetRight(), cw
) );
3229 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
3232 // logical bounds of update region
3234 CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
3235 CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
3237 // find the cells within these bounds
3240 for ( row
= 0; row
< m_numRows
; row
++ )
3242 if ( GetRowBottom(row
) <= top
)
3245 if ( GetRowTop(row
) > bottom
)
3248 m_rowsExposed
.Add( row
);
3250 for ( col
= 0; col
< m_numCols
; col
++ )
3252 if ( GetColRight(col
) <= left
)
3255 if ( GetColLeft(col
) > right
)
3258 if ( m_colsExposed
.Index( col
) == wxNOT_FOUND
)
3259 m_colsExposed
.Add( col
);
3260 m_cellsExposed
.Add( wxGridCellCoords( row
, col
) );
3269 void wxGrid
::ProcessRowLabelMouseEvent( wxMouseEvent
& event
)
3272 wxPoint
pos( event
.GetPosition() );
3273 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
3275 if ( event
.Dragging() )
3277 m_isDragging
= TRUE
;
3279 if ( event
.LeftIsDown() )
3281 switch( m_cursorMode
)
3283 case WXGRID_CURSOR_RESIZE_ROW
:
3285 int cw
, ch
, left
, dummy
;
3286 m_gridWin
->GetClientSize( &cw
, &ch
);
3287 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
3289 wxClientDC
dc( m_gridWin
);
3291 y
= wxMax( y
, GetRowTop(m_dragRowOrCol
) + WXGRID_MIN_ROW_HEIGHT
);
3292 dc
.SetLogicalFunction(wxINVERT
);
3293 if ( m_dragLastPos
>= 0 )
3295 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
3297 dc
.DrawLine( left
, y
, left
+cw
, y
);
3302 case WXGRID_CURSOR_SELECT_ROW
:
3303 if ( (row
= YToRow( y
)) >= 0 &&
3304 !IsInSelection( row
, 0 ) )
3306 SelectRow( row
, TRUE
);
3309 // default label to suppress warnings about "enumeration value
3310 // 'xxx' not handled in switch
3318 m_isDragging
= FALSE
;
3321 // ------------ Entering or leaving the window
3323 if ( event
.Entering() || event
.Leaving() )
3325 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
);
3329 // ------------ Left button pressed
3331 else if ( event
.LeftDown() )
3333 // don't send a label click event for a hit on the
3334 // edge of the row label - this is probably the user
3335 // wanting to resize the row
3337 if ( YToEdgeOfRow(y
) < 0 )
3341 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event
) )
3343 SelectRow( row
, event
.ShiftDown() );
3344 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW
, m_rowLabelWin
);
3349 // starting to drag-resize a row
3351 if ( CanDragRowSize() )
3352 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
);
3357 // ------------ Left double click
3359 else if (event
.LeftDClick() )
3361 if ( YToEdgeOfRow(y
) < 0 )
3364 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event
);
3369 // ------------ Left button released
3371 else if ( event
.LeftUp() )
3373 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
3375 DoEndDragResizeRow();
3377 // Note: we are ending the event *after* doing
3378 // default processing in this case
3380 SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
3383 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
);
3388 // ------------ Right button down
3390 else if ( event
.RightDown() )
3393 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event
) )
3395 // no default action at the moment
3400 // ------------ Right double click
3402 else if ( event
.RightDClick() )
3405 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event
) )
3407 // no default action at the moment
3412 // ------------ No buttons down and mouse moving
3414 else if ( event
.Moving() )
3416 m_dragRowOrCol
= YToEdgeOfRow( y
);
3417 if ( m_dragRowOrCol
>= 0 )
3419 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3421 // don't capture the mouse yet
3422 if ( CanDragRowSize() )
3423 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
, FALSE
);
3426 else if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
3428 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
, FALSE
);
3434 void wxGrid
::ProcessColLabelMouseEvent( wxMouseEvent
& event
)
3437 wxPoint
pos( event
.GetPosition() );
3438 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
3440 if ( event
.Dragging() )
3442 m_isDragging
= TRUE
;
3444 if ( event
.LeftIsDown() )
3446 switch( m_cursorMode
)
3448 case WXGRID_CURSOR_RESIZE_COL
:
3450 int cw
, ch
, dummy
, top
;
3451 m_gridWin
->GetClientSize( &cw
, &ch
);
3452 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
3454 wxClientDC
dc( m_gridWin
);
3457 x
= wxMax( x
, GetColLeft(m_dragRowOrCol
) +
3458 GetColMinimalWidth(m_dragRowOrCol
));
3459 dc
.SetLogicalFunction(wxINVERT
);
3460 if ( m_dragLastPos
>= 0 )
3462 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
3464 dc
.DrawLine( x
, top
, x
, top
+ch
);
3469 case WXGRID_CURSOR_SELECT_COL
:
3470 if ( (col
= XToCol( x
)) >= 0 &&
3471 !IsInSelection( 0, col
) )
3473 SelectCol( col
, TRUE
);
3476 // default label to suppress warnings about "enumeration value
3477 // 'xxx' not handled in switch
3485 m_isDragging
= FALSE
;
3488 // ------------ Entering or leaving the window
3490 if ( event
.Entering() || event
.Leaving() )
3492 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
);
3496 // ------------ Left button pressed
3498 else if ( event
.LeftDown() )
3500 // don't send a label click event for a hit on the
3501 // edge of the col label - this is probably the user
3502 // wanting to resize the col
3504 if ( XToEdgeOfCol(x
) < 0 )
3508 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event
) )
3510 SelectCol( col
, event
.ShiftDown() );
3511 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL
, m_colLabelWin
);
3516 // starting to drag-resize a col
3518 if ( CanDragColSize() )
3519 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, m_colLabelWin
);
3524 // ------------ Left double click
3526 if ( event
.LeftDClick() )
3528 if ( XToEdgeOfCol(x
) < 0 )
3531 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event
);
3536 // ------------ Left button released
3538 else if ( event
.LeftUp() )
3540 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
3542 DoEndDragResizeCol();
3544 // Note: we are ending the event *after* doing
3545 // default processing in this case
3547 SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event
);
3550 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
);
3555 // ------------ Right button down
3557 else if ( event
.RightDown() )
3560 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event
) )
3562 // no default action at the moment
3567 // ------------ Right double click
3569 else if ( event
.RightDClick() )
3572 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event
) )
3574 // no default action at the moment
3579 // ------------ No buttons down and mouse moving
3581 else if ( event
.Moving() )
3583 m_dragRowOrCol
= XToEdgeOfCol( x
);
3584 if ( m_dragRowOrCol
>= 0 )
3586 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3588 // don't capture the cursor yet
3589 if ( CanDragColSize() )
3590 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, m_colLabelWin
, FALSE
);
3593 else if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
3595 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
, FALSE
);
3601 void wxGrid
::ProcessCornerLabelMouseEvent( wxMouseEvent
& event
)
3603 if ( event
.LeftDown() )
3605 // indicate corner label by having both row and
3608 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event
) )
3614 else if ( event
.LeftDClick() )
3616 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event
);
3619 else if ( event
.RightDown() )
3621 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event
) )
3623 // no default action at the moment
3627 else if ( event
.RightDClick() )
3629 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event
) )
3631 // no default action at the moment
3636 void wxGrid
::ChangeCursorMode(CursorMode mode
,
3641 static const wxChar
*cursorModes
[] =
3650 wxLogTrace(_T("grid"),
3651 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
3652 win
== m_colLabelWin ?
_T("colLabelWin")
3653 : win ?
_T("rowLabelWin")
3655 cursorModes
[m_cursorMode
], cursorModes
[mode
]);
3656 #endif // __WXDEBUG__
3658 if ( mode
== m_cursorMode
)
3663 // by default use the grid itself
3669 m_winCapture
->ReleaseMouse();
3670 m_winCapture
= (wxWindow
*)NULL
;
3673 m_cursorMode
= mode
;
3675 switch ( m_cursorMode
)
3677 case WXGRID_CURSOR_RESIZE_ROW
:
3678 win
->SetCursor( m_rowResizeCursor
);
3681 case WXGRID_CURSOR_RESIZE_COL
:
3682 win
->SetCursor( m_colResizeCursor
);
3686 win
->SetCursor( *wxSTANDARD_CURSOR
);
3689 // we need to capture mouse when resizing
3690 bool resize
= m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
||
3691 m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
;
3693 if ( captureMouse
&& resize
)
3695 win
->CaptureMouse();
3700 void wxGrid
::ProcessGridCellMouseEvent( wxMouseEvent
& event
)
3703 wxPoint
pos( event
.GetPosition() );
3704 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
3706 wxGridCellCoords coords
;
3707 XYToCell( x
, y
, coords
);
3709 if ( event
.Dragging() )
3711 //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
3713 // Don't start doing anything until the mouse has been drug at
3714 // least 3 pixels in any direction...
3717 if (m_startDragPos
== wxDefaultPosition
)
3719 m_startDragPos
= pos
;
3722 if (abs(m_startDragPos
.x
- pos
.x
) < 4 && abs(m_startDragPos
.y
- pos
.y
) < 4)
3726 m_isDragging
= TRUE
;
3727 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3729 // Hide the edit control, so it
3730 // won't interfer with drag-shrinking.
3731 if ( IsCellEditControlEnabled() )
3732 HideCellEditControl();
3734 // Have we captured the mouse yet?
3737 m_winCapture
= m_gridWin
;
3738 m_winCapture
->CaptureMouse();
3741 if ( coords
!= wxGridNoCellCoords
)
3743 if ( !IsSelection() )
3745 SelectBlock( coords
, coords
);
3749 SelectBlock( m_currentCellCoords
, coords
);
3752 if (! IsVisible(coords
))
3754 MakeCellVisible(coords
);
3755 // TODO: need to introduce a delay or something here. The
3756 // scrolling is way to fast, at least on MSW.
3760 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
3762 int cw
, ch
, left
, dummy
;
3763 m_gridWin
->GetClientSize( &cw
, &ch
);
3764 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
3766 wxClientDC
dc( m_gridWin
);
3768 y
= wxMax( y
, GetRowTop(m_dragRowOrCol
) + WXGRID_MIN_ROW_HEIGHT
);
3769 dc
.SetLogicalFunction(wxINVERT
);
3770 if ( m_dragLastPos
>= 0 )
3772 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
3774 dc
.DrawLine( left
, y
, left
+cw
, y
);
3777 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
3779 int cw
, ch
, dummy
, top
;
3780 m_gridWin
->GetClientSize( &cw
, &ch
);
3781 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
3783 wxClientDC
dc( m_gridWin
);
3785 x
= wxMax( x
, GetColLeft(m_dragRowOrCol
) +
3786 GetColMinimalWidth(m_dragRowOrCol
) );
3787 dc
.SetLogicalFunction(wxINVERT
);
3788 if ( m_dragLastPos
>= 0 )
3790 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
3792 dc
.DrawLine( x
, top
, x
, top
+ch
);
3799 m_isDragging
= FALSE
;
3800 m_startDragPos
= wxDefaultPosition
;
3803 if ( coords
!= wxGridNoCellCoords
)
3805 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
3806 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
3809 if ( event
.Entering() || event
.Leaving() )
3811 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3812 m_gridWin
->SetCursor( *wxSTANDARD_CURSOR
);
3817 // ------------ Left button pressed
3819 if ( event
.LeftDown() )
3821 DisableCellEditControl();
3822 if ( event
.ShiftDown() )
3824 SelectBlock( m_currentCellCoords
, coords
);
3826 else if ( XToEdgeOfCol(x
) < 0 &&
3827 YToEdgeOfRow(y
) < 0 )
3829 if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK
,
3834 MakeCellVisible( coords
);
3836 // if this is the second click on this cell then start
3838 if ( m_waitForSlowClick
&&
3839 (coords
== m_currentCellCoords
) &&
3840 CanEnableCellControl())
3842 EnableCellEditControl();
3844 wxGridCellAttr
* attr
= GetCellAttr(m_currentCellCoords
);
3845 attr
->GetEditor(GetDefaultEditorForCell(coords
.GetRow(), coords
.GetCol()))->StartingClick();
3848 m_waitForSlowClick
= FALSE
;
3852 SetCurrentCell( coords
);
3853 m_waitForSlowClick
= TRUE
;
3860 // ------------ Left double click
3862 else if ( event
.LeftDClick() )
3864 DisableCellEditControl();
3865 if ( XToEdgeOfCol(x
) < 0 && YToEdgeOfRow(y
) < 0 )
3867 SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK
,
3875 // ------------ Left button released
3877 else if ( event
.LeftUp() )
3879 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3881 if ( IsSelection() )
3885 m_winCapture
->ReleaseMouse();
3886 m_winCapture
= NULL
;
3888 SendEvent( wxEVT_GRID_RANGE_SELECT
, -1, -1, event
);
3891 // Show the edit control, if it has been hidden for
3893 ShowCellEditControl();
3895 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
3897 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3898 DoEndDragResizeRow();
3900 // Note: we are ending the event *after* doing
3901 // default processing in this case
3903 SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
3905 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
3907 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3908 DoEndDragResizeCol();
3910 // Note: we are ending the event *after* doing
3911 // default processing in this case
3913 SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event
);
3920 // ------------ Right button down
3922 else if ( event
.RightDown() )
3924 DisableCellEditControl();
3925 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK
,
3930 // no default action at the moment
3935 // ------------ Right double click
3937 else if ( event
.RightDClick() )
3939 DisableCellEditControl();
3940 if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK
,
3945 // no default action at the moment
3949 // ------------ Moving and no button action
3951 else if ( event
.Moving() && !event
.IsButton() )
3953 int dragRow
= YToEdgeOfRow( y
);
3954 int dragCol
= XToEdgeOfCol( x
);
3956 // Dragging on the corner of a cell to resize in both
3957 // directions is not implemented yet...
3959 if ( dragRow
>= 0 && dragCol
>= 0 )
3961 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3967 m_dragRowOrCol
= dragRow
;
3969 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3971 if ( CanDragRowSize() )
3972 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
);
3980 m_dragRowOrCol
= dragCol
;
3982 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3984 if ( CanDragColSize() )
3985 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
);
3991 // Neither on a row or col edge
3993 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
3995 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
4002 void wxGrid
::DoEndDragResizeRow()
4004 if ( m_dragLastPos
>= 0 )
4006 // erase the last line and resize the row
4008 int cw
, ch
, left
, dummy
;
4009 m_gridWin
->GetClientSize( &cw
, &ch
);
4010 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
4012 wxClientDC
dc( m_gridWin
);
4014 dc
.SetLogicalFunction( wxINVERT
);
4015 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
4016 HideCellEditControl();
4018 int rowTop
= GetRowTop(m_dragRowOrCol
);
4019 SetRowSize( m_dragRowOrCol
,
4020 wxMax( m_dragLastPos
- rowTop
, WXGRID_MIN_ROW_HEIGHT
) );
4022 if ( !GetBatchCount() )
4024 // Only needed to get the correct rect.y:
4025 wxRect
rect ( CellToRect( m_dragRowOrCol
, 0 ) );
4027 CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
);
4028 rect
.width
= m_rowLabelWidth
;
4029 rect
.height
= ch
- rect
.y
;
4030 m_rowLabelWin
->Refresh( TRUE
, &rect
);
4032 m_gridWin
->Refresh( FALSE
, &rect
);
4035 ShowCellEditControl();
4040 void wxGrid
::DoEndDragResizeCol()
4042 if ( m_dragLastPos
>= 0 )
4044 // erase the last line and resize the col
4046 int cw
, ch
, dummy
, top
;
4047 m_gridWin
->GetClientSize( &cw
, &ch
);
4048 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
4050 wxClientDC
dc( m_gridWin
);
4052 dc
.SetLogicalFunction( wxINVERT
);
4053 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
4054 HideCellEditControl();
4056 int colLeft
= GetColLeft(m_dragRowOrCol
);
4057 SetColSize( m_dragRowOrCol
,
4058 wxMax( m_dragLastPos
- colLeft
,
4059 GetColMinimalWidth(m_dragRowOrCol
) ) );
4061 if ( !GetBatchCount() )
4063 // Only needed to get the correct rect.x:
4064 wxRect
rect ( CellToRect( 0, m_dragRowOrCol
) );
4066 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
);
4067 rect
.width
= cw
- rect
.x
;
4068 rect
.height
= m_colLabelHeight
;
4069 m_colLabelWin
->Refresh( TRUE
, &rect
);
4071 m_gridWin
->Refresh( FALSE
, &rect
);
4074 ShowCellEditControl();
4081 // ------ interaction with data model
4083 bool wxGrid
::ProcessTableMessage( wxGridTableMessage
& msg
)
4085 switch ( msg
.GetId() )
4087 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
:
4088 return GetModelValues();
4090 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
:
4091 return SetModelValues();
4093 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
4094 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
4095 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
4096 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
4097 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
4098 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
4099 return Redimension( msg
);
4108 // The behaviour of this function depends on the grid table class
4109 // Clear() function. For the default wxGridStringTable class the
4110 // behavious is to replace all cell contents with wxEmptyString but
4111 // not to change the number of rows or cols.
4113 void wxGrid
::ClearGrid()
4118 SetEditControlValue();
4119 if ( !GetBatchCount() ) m_gridWin
->Refresh();
4124 bool wxGrid
::InsertRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
4126 // TODO: something with updateLabels flag
4130 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
4136 if (IsCellEditControlEnabled())
4137 DisableCellEditControl();
4139 bool ok
= m_table
->InsertRows( pos
, numRows
);
4141 // the table will have sent the results of the insert row
4142 // operation to this view object as a grid table message
4146 if ( m_numCols
== 0 )
4148 m_table
->AppendCols( WXGRID_DEFAULT_NUMBER_COLS
);
4150 // TODO: perhaps instead of appending the default number of cols
4151 // we should remember what the last non-zero number of cols was ?
4155 if ( m_currentCellCoords
== wxGridNoCellCoords
)
4157 // if we have just inserted cols into an empty grid the current
4158 // cell will be undefined...
4160 SetCurrentCell( 0, 0 );
4164 if ( !GetBatchCount() ) Refresh();
4167 SetEditControlValue();
4177 bool wxGrid
::AppendRows( int numRows
, bool WXUNUSED(updateLabels
) )
4179 // TODO: something with updateLabels flag
4183 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
4187 if ( m_table
&& m_table
->AppendRows( numRows
) )
4189 if ( m_currentCellCoords
== wxGridNoCellCoords
)
4191 // if we have just inserted cols into an empty grid the current
4192 // cell will be undefined...
4194 SetCurrentCell( 0, 0 );
4197 // the table will have sent the results of the append row
4198 // operation to this view object as a grid table message
4201 if ( !GetBatchCount() ) Refresh();
4211 bool wxGrid
::DeleteRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
4213 // TODO: something with updateLabels flag
4217 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
4223 if (IsCellEditControlEnabled())
4224 DisableCellEditControl();
4226 if (m_table
->DeleteRows( pos
, numRows
))
4229 // the table will have sent the results of the delete row
4230 // operation to this view object as a grid table message
4233 if ( !GetBatchCount() ) Refresh();
4241 bool wxGrid
::InsertCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
4243 // TODO: something with updateLabels flag
4247 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
4253 if (IsCellEditControlEnabled())
4254 DisableCellEditControl();
4256 bool ok
= m_table
->InsertCols( pos
, numCols
);
4258 // the table will have sent the results of the insert col
4259 // operation to this view object as a grid table message
4263 if ( m_currentCellCoords
== wxGridNoCellCoords
)
4265 // if we have just inserted cols into an empty grid the current
4266 // cell will be undefined...
4268 SetCurrentCell( 0, 0 );
4272 if ( !GetBatchCount() ) Refresh();
4275 SetEditControlValue();
4285 bool wxGrid
::AppendCols( int numCols
, bool WXUNUSED(updateLabels
) )
4287 // TODO: something with updateLabels flag
4291 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
4295 if ( m_table
&& m_table
->AppendCols( numCols
) )
4297 // the table will have sent the results of the append col
4298 // operation to this view object as a grid table message
4300 if ( m_currentCellCoords
== wxGridNoCellCoords
)
4302 // if we have just inserted cols into an empty grid the current
4303 // cell will be undefined...
4305 SetCurrentCell( 0, 0 );
4309 if ( !GetBatchCount() ) Refresh();
4319 bool wxGrid
::DeleteCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
4321 // TODO: something with updateLabels flag
4325 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
4331 if (IsCellEditControlEnabled())
4332 DisableCellEditControl();
4334 if ( m_table
->DeleteCols( pos
, numCols
) )
4336 // the table will have sent the results of the delete col
4337 // operation to this view object as a grid table message
4340 if ( !GetBatchCount() ) Refresh();
4350 // ----- event handlers
4353 // Generate a grid event based on a mouse event and
4354 // return the result of ProcessEvent()
4356 bool wxGrid
::SendEvent( const wxEventType type
,
4358 wxMouseEvent
& mouseEv
)
4360 if ( type
== wxEVT_GRID_ROW_SIZE
|| type
== wxEVT_GRID_COL_SIZE
)
4362 int rowOrCol
= (row
== -1 ? col
: row
);
4364 wxGridSizeEvent
gridEvt( GetId(),
4368 mouseEv
.GetX(), mouseEv
.GetY(),
4369 mouseEv
.ControlDown(),
4370 mouseEv
.ShiftDown(),
4372 mouseEv
.MetaDown() );
4374 return GetEventHandler()->ProcessEvent(gridEvt
);
4376 else if ( type
== wxEVT_GRID_RANGE_SELECT
)
4378 wxGridRangeSelectEvent
gridEvt( GetId(),
4382 m_selectedBottomRight
,
4383 mouseEv
.ControlDown(),
4384 mouseEv
.ShiftDown(),
4386 mouseEv
.MetaDown() );
4388 return GetEventHandler()->ProcessEvent(gridEvt
);
4392 wxGridEvent
gridEvt( GetId(),
4396 mouseEv
.GetX(), mouseEv
.GetY(),
4397 mouseEv
.ControlDown(),
4398 mouseEv
.ShiftDown(),
4400 mouseEv
.MetaDown() );
4402 return GetEventHandler()->ProcessEvent(gridEvt
);
4407 // Generate a grid event of specified type and return the result
4408 // of ProcessEvent().
4410 bool wxGrid
::SendEvent( const wxEventType type
,
4413 if ( type
== wxEVT_GRID_ROW_SIZE
|| type
== wxEVT_GRID_COL_SIZE
)
4415 int rowOrCol
= (row
== -1 ? col
: row
);
4417 wxGridSizeEvent
gridEvt( GetId(),
4422 return GetEventHandler()->ProcessEvent(gridEvt
);
4426 wxGridEvent
gridEvt( GetId(),
4431 return GetEventHandler()->ProcessEvent(gridEvt
);
4436 void wxGrid
::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
4438 wxPaintDC
dc( this );
4440 if ( m_currentCellCoords
== wxGridNoCellCoords
&&
4441 m_numRows
&& m_numCols
)
4443 m_currentCellCoords
.Set(0, 0);
4444 SetEditControlValue();
4445 ShowCellEditControl();
4452 // This is just here to make sure that CalcDimensions gets called when
4453 // the grid view is resized... then the size event is skipped to allow
4454 // the box sizers to handle everything
4456 void wxGrid
::OnSize( wxSizeEvent
& event
)
4463 void wxGrid
::OnKeyDown( wxKeyEvent
& event
)
4465 if ( m_inOnKeyDown
)
4467 // shouldn't be here - we are going round in circles...
4469 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
4472 m_inOnKeyDown
= TRUE
;
4474 // propagate the event up and see if it gets processed
4476 wxWindow
*parent
= GetParent();
4477 wxKeyEvent
keyEvt( event
);
4478 keyEvt
.SetEventObject( parent
);
4480 if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt
) )
4483 // TODO: Should also support Shift-cursor keys for
4484 // extending the selection. Maybe add a flag to
4485 // MoveCursorXXX() and MoveCursorXXXBlock() and
4486 // just send event.ShiftDown().
4488 // try local handlers
4490 switch ( event
.KeyCode() )
4493 if ( event
.ControlDown() )
4495 MoveCursorUpBlock();
4504 if ( event
.ControlDown() )
4506 MoveCursorDownBlock();
4515 if ( event
.ControlDown() )
4517 MoveCursorLeftBlock();
4526 if ( event
.ControlDown() )
4528 MoveCursorRightBlock();
4537 if ( event
.ControlDown() )
4539 event
.Skip(); // to let the edit control have the return
4548 if (event
.ShiftDown())
4555 if ( event
.ControlDown() )
4557 MakeCellVisible( 0, 0 );
4558 SetCurrentCell( 0, 0 );
4567 if ( event
.ControlDown() )
4569 MakeCellVisible( m_numRows
-1, m_numCols
-1 );
4570 SetCurrentCell( m_numRows
-1, m_numCols
-1 );
4586 // We don't want these keys to trigger the edit control, any others?
4595 if ( !IsEditable() )
4600 // Otherwise fall through to default
4603 // now try the cell edit control
4605 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
4607 EnableCellEditControl();
4608 int row
= m_currentCellCoords
.GetRow();
4609 int col
= m_currentCellCoords
.GetCol();
4610 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
4611 attr
->GetEditor(GetDefaultEditorForCell(row
, col
))->StartingKey(event
);
4616 // let others process char events for readonly cells
4623 m_inOnKeyDown
= FALSE
;
4627 void wxGrid
::OnEraseBackground(wxEraseEvent
&)
4631 void wxGrid
::SetCurrentCell( const wxGridCellCoords
& coords
)
4633 if ( SendEvent( wxEVT_GRID_SELECT_CELL
, coords
.GetRow(), coords
.GetCol() ) )
4635 // the event has been intercepted - do nothing
4640 m_currentCellCoords
!= wxGridNoCellCoords
)
4642 HideCellEditControl();
4643 SaveEditControlValue();
4644 DisableCellEditControl();
4646 // Clear the old current cell highlight
4647 wxRect r
= BlockToDeviceRect(m_currentCellCoords
, m_currentCellCoords
);
4649 // Otherwise refresh redraws the highlight!
4650 m_currentCellCoords
= coords
;
4652 m_gridWin
->Refresh( FALSE
, &r
);
4655 m_currentCellCoords
= coords
;
4657 SetEditControlValue();
4661 wxClientDC
dc(m_gridWin
);
4664 wxGridCellAttr
* attr
= GetCellAttr(coords
);
4665 DrawCellHighlight(dc
, attr
);
4668 if ( IsSelection() )
4670 wxRect
r( SelectionToDeviceRect() );
4672 if ( !GetBatchCount() ) m_gridWin
->Refresh( FALSE
, &r
);
4679 // ------ functions to get/send data (see also public functions)
4682 bool wxGrid
::GetModelValues()
4686 // all we need to do is repaint the grid
4688 m_gridWin
->Refresh();
4696 bool wxGrid
::SetModelValues()
4702 for ( row
= 0; row
< m_numRows
; row
++ )
4704 for ( col
= 0; col
< m_numCols
; col
++ )
4706 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) );
4718 // Note - this function only draws cells that are in the list of
4719 // exposed cells (usually set from the update region by
4720 // CalcExposedCells)
4722 void wxGrid
::DrawGridCellArea( wxDC
& dc
)
4724 if ( !m_numRows
|| !m_numCols
) return;
4727 size_t numCells
= m_cellsExposed
.GetCount();
4729 for ( i
= 0; i
< numCells
; i
++ )
4731 DrawCell( dc
, m_cellsExposed
[i
] );
4736 void wxGrid
::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords
)
4738 int row
= coords
.GetRow();
4739 int col
= coords
.GetCol();
4741 if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
4744 // we draw the cell border ourselves
4745 #if !WXGRID_DRAW_LINES
4746 if ( m_gridLinesEnabled
)
4747 DrawCellBorder( dc
, coords
);
4750 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
4752 bool isCurrent
= coords
== m_currentCellCoords
;
4755 rect
.x
= GetColLeft(col
);
4756 rect
.y
= GetRowTop(row
);
4757 rect
.width
= GetColWidth(col
) - 1;
4758 rect
.height
= GetRowHeight(row
) - 1;
4760 // if the editor is shown, we should use it and not the renderer
4761 if ( isCurrent
&& IsCellEditControlEnabled() )
4763 attr
->GetEditor(GetDefaultEditorForCell(row
, col
))->
4764 PaintBackground(rect
, attr
);
4768 // but all the rest is drawn by the cell renderer and hence may be
4770 attr
->GetRenderer(GetDefaultRendererForCell(row
,col
))->
4771 Draw(*this, *attr
, dc
, rect
, row
, col
, IsInSelection(coords
));
4778 void wxGrid
::DrawCellHighlight( wxDC
& dc
, const wxGridCellAttr
*attr
)
4780 int row
= m_currentCellCoords
.GetRow();
4781 int col
= m_currentCellCoords
.GetCol();
4783 if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
4787 rect
.x
= GetColLeft(col
);
4788 rect
.y
= GetRowTop(row
);
4789 rect
.width
= GetColWidth(col
) - 1;
4790 rect
.height
= GetRowHeight(row
) - 1;
4792 // hmmm... what could we do here to show that the cell is disabled?
4793 // for now, I just draw a thinner border than for the other ones, but
4794 // it doesn't look really good
4795 dc
.SetPen(wxPen(m_gridLineColour
, attr
->IsReadOnly() ?
1 : 3, wxSOLID
));
4796 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
4798 dc
.DrawRectangle(rect
);
4801 // VZ: my experiments with 3d borders...
4803 // how to properly set colours for arbitrary bg?
4804 wxCoord x1
= rect
.x
,
4806 x2
= rect
.x
+ rect
.width
-1,
4807 y2
= rect
.y
+ rect
.height
-1;
4809 dc
.SetPen(*wxWHITE_PEN
);
4810 dc
.DrawLine(x1
, y1
, x2
, y1
);
4811 dc
.DrawLine(x1
, y1
, x1
, y2
);
4813 dc
.DrawLine(x1
+ 1, y2
- 1, x2
- 1, y2
- 1);
4814 dc
.DrawLine(x2
- 1, y1
+ 1, x2
- 1, y2
);
4816 dc
.SetPen(*wxBLACK_PEN
);
4817 dc
.DrawLine(x1
, y2
, x2
, y2
);
4818 dc
.DrawLine(x2
, y1
, x2
, y2
+1);
4823 void wxGrid
::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords
)
4825 int row
= coords
.GetRow();
4826 int col
= coords
.GetCol();
4827 if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
4830 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
4832 // right hand border
4834 dc
.DrawLine( GetColRight(col
), GetRowTop(row
),
4835 GetColRight(col
), GetRowBottom(row
) );
4839 dc
.DrawLine( GetColLeft(col
), GetRowBottom(row
),
4840 GetColRight(col
), GetRowBottom(row
) );
4843 void wxGrid
::DrawHighlight(wxDC
& dc
)
4845 if ( IsCellEditControlEnabled() )
4847 // don't show highlight when the edit control is shown
4851 // if the active cell was repainted, repaint its highlight too because it
4852 // might have been damaged by the grid lines
4853 size_t count
= m_cellsExposed
.GetCount();
4854 for ( size_t n
= 0; n
< count
; n
++ )
4856 if ( m_cellsExposed
[n
] == m_currentCellCoords
)
4858 wxGridCellAttr
* attr
= GetCellAttr(m_currentCellCoords
);
4859 DrawCellHighlight(dc
, attr
);
4867 // TODO: remove this ???
4868 // This is used to redraw all grid lines e.g. when the grid line colour
4871 void wxGrid
::DrawAllGridLines( wxDC
& dc
, const wxRegion
& reg
)
4873 if ( !m_gridLinesEnabled
||
4875 !m_numCols
) return;
4877 int top
, bottom
, left
, right
;
4882 m_gridWin
->GetClientSize(&cw
, &ch
);
4884 // virtual coords of visible area
4886 CalcUnscrolledPosition( 0, 0, &left
, &top
);
4887 CalcUnscrolledPosition( cw
, ch
, &right
, &bottom
);
4892 reg
.GetBox(x
, y
, w
, h
);
4893 CalcUnscrolledPosition( x
, y
, &left
, &top
);
4894 CalcUnscrolledPosition( x
+ w
, y
+ h
, &right
, &bottom
);
4897 // avoid drawing grid lines past the last row and col
4899 right
= wxMin( right
, GetColRight(m_numCols
- 1) );
4900 bottom
= wxMin( bottom
, GetRowBottom(m_numRows
- 1) );
4902 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
4904 // horizontal grid lines
4907 for ( i
= 0; i
< m_numRows
; i
++ )
4909 int bot
= GetRowBottom(i
) - 1;
4918 dc
.DrawLine( left
, bot
, right
, bot
);
4923 // vertical grid lines
4925 for ( i
= 0; i
< m_numCols
; i
++ )
4927 int colRight
= GetColRight(i
) - 1;
4928 if ( colRight
> right
)
4933 if ( colRight
>= left
)
4935 dc
.DrawLine( colRight
, top
, colRight
, bottom
);
4941 void wxGrid
::DrawRowLabels( wxDC
& dc
)
4943 if ( !m_numRows
|| !m_numCols
) return;
4946 size_t numLabels
= m_rowLabelsExposed
.GetCount();
4948 for ( i
= 0; i
< numLabels
; i
++ )
4950 DrawRowLabel( dc
, m_rowLabelsExposed
[i
] );
4955 void wxGrid
::DrawRowLabel( wxDC
& dc
, int row
)
4957 if ( GetRowHeight(row
) <= 0 )
4960 int rowTop
= GetRowTop(row
),
4961 rowBottom
= GetRowBottom(row
) - 1;
4963 dc
.SetPen( *wxBLACK_PEN
);
4964 dc
.DrawLine( m_rowLabelWidth
-1, rowTop
,
4965 m_rowLabelWidth
-1, rowBottom
);
4967 dc
.DrawLine( 0, rowBottom
, m_rowLabelWidth
-1, rowBottom
);
4969 dc
.SetPen( *wxWHITE_PEN
);
4970 dc
.DrawLine( 0, rowTop
, 0, rowBottom
);
4971 dc
.DrawLine( 0, rowTop
, m_rowLabelWidth
-1, rowTop
);
4973 dc
.SetBackgroundMode( wxTRANSPARENT
);
4974 dc
.SetTextForeground( GetLabelTextColour() );
4975 dc
.SetFont( GetLabelFont() );
4978 GetRowLabelAlignment( &hAlign
, &vAlign
);
4982 rect
.SetY( GetRowTop(row
) + 2 );
4983 rect
.SetWidth( m_rowLabelWidth
- 4 );
4984 rect
.SetHeight( GetRowHeight(row
) - 4 );
4985 DrawTextRectangle( dc
, GetRowLabelValue( row
), rect
, hAlign
, vAlign
);
4989 void wxGrid
::DrawColLabels( wxDC
& dc
)
4991 if ( !m_numRows
|| !m_numCols
) return;
4994 size_t numLabels
= m_colLabelsExposed
.GetCount();
4996 for ( i
= 0; i
< numLabels
; i
++ )
4998 DrawColLabel( dc
, m_colLabelsExposed
[i
] );
5003 void wxGrid
::DrawColLabel( wxDC
& dc
, int col
)
5005 if ( GetColWidth(col
) <= 0 )
5008 int colLeft
= GetColLeft(col
),
5009 colRight
= GetColRight(col
) - 1;
5011 dc
.SetPen( *wxBLACK_PEN
);
5012 dc
.DrawLine( colRight
, 0,
5013 colRight
, m_colLabelHeight
-1 );
5015 dc
.DrawLine( colLeft
, m_colLabelHeight
-1,
5016 colRight
, m_colLabelHeight
-1 );
5018 dc
.SetPen( *wxWHITE_PEN
);
5019 dc
.DrawLine( colLeft
, 0, colLeft
, m_colLabelHeight
-1 );
5020 dc
.DrawLine( colLeft
, 0, colRight
, 0 );
5022 dc
.SetBackgroundMode( wxTRANSPARENT
);
5023 dc
.SetTextForeground( GetLabelTextColour() );
5024 dc
.SetFont( GetLabelFont() );
5026 dc
.SetBackgroundMode( wxTRANSPARENT
);
5027 dc
.SetTextForeground( GetLabelTextColour() );
5028 dc
.SetFont( GetLabelFont() );
5031 GetColLabelAlignment( &hAlign
, &vAlign
);
5034 rect
.SetX( colLeft
+ 2 );
5036 rect
.SetWidth( GetColWidth(col
) - 4 );
5037 rect
.SetHeight( m_colLabelHeight
- 4 );
5038 DrawTextRectangle( dc
, GetColLabelValue( col
), rect
, hAlign
, vAlign
);
5042 void wxGrid
::DrawTextRectangle( wxDC
& dc
,
5043 const wxString
& value
,
5048 long textWidth
, textHeight
;
5049 long lineWidth
, lineHeight
;
5050 wxArrayString lines
;
5052 dc
.SetClippingRegion( rect
);
5053 StringToLines( value
, lines
);
5054 if ( lines
.GetCount() )
5056 GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight
);
5057 dc
.GetTextExtent( lines
[0], &lineWidth
, &lineHeight
);
5060 switch ( horizAlign
)
5063 x
= rect
.x
+ (rect
.width
- textWidth
- 1);
5067 x
= rect
.x
+ ((rect
.width
- textWidth
)/2);
5076 switch ( vertAlign
)
5079 y
= rect
.y
+ (rect
.height
- textHeight
- 1);
5083 y
= rect
.y
+ ((rect
.height
- textHeight
)/2);
5092 for ( size_t i
= 0; i
< lines
.GetCount(); i
++ )
5094 dc
.DrawText( lines
[i
], (long)x
, (long)y
);
5099 dc
.DestroyClippingRegion();
5103 // Split multi line text up into an array of strings. Any existing
5104 // contents of the string array are preserved.
5106 void wxGrid
::StringToLines( const wxString
& value
, wxArrayString
& lines
)
5110 wxString eol
= wxTextFile
::GetEOL( wxTextFileType_Unix
);
5111 wxString tVal
= wxTextFile
::Translate( value
, wxTextFileType_Unix
);
5113 while ( startPos
< (int)tVal
.Length() )
5115 pos
= tVal
.Mid(startPos
).Find( eol
);
5120 else if ( pos
== 0 )
5122 lines
.Add( wxEmptyString
);
5126 lines
.Add( value
.Mid(startPos
, pos
) );
5130 if ( startPos
< (int)value
.Length() )
5132 lines
.Add( value
.Mid( startPos
) );
5137 void wxGrid
::GetTextBoxSize( wxDC
& dc
,
5138 wxArrayString
& lines
,
5139 long *width
, long *height
)
5146 for ( i
= 0; i
< lines
.GetCount(); i
++ )
5148 dc
.GetTextExtent( lines
[i
], &lineW
, &lineH
);
5149 w
= wxMax( w
, lineW
);
5159 // ------ Edit control functions
5163 void wxGrid
::EnableEditing( bool edit
)
5165 // TODO: improve this ?
5167 if ( edit
!= m_editable
)
5171 // FIXME IMHO this won't disable the edit control if edit == FALSE
5172 // because of the check in the beginning of
5173 // EnableCellEditControl() just below (VZ)
5174 EnableCellEditControl(m_editable
);
5179 void wxGrid
::EnableCellEditControl( bool enable
)
5184 if ( m_currentCellCoords
== wxGridNoCellCoords
)
5185 SetCurrentCell( 0, 0 );
5187 if ( enable
!= m_cellEditCtrlEnabled
)
5189 // TODO allow the app to Veto() this event?
5190 SendEvent(enable ? wxEVT_GRID_EDITOR_SHOWN
: wxEVT_GRID_EDITOR_HIDDEN
);
5194 // this should be checked by the caller!
5195 wxASSERT_MSG( CanEnableCellControl(),
5196 _T("can't enable editing for this cell!") );
5198 // do it before ShowCellEditControl()
5199 m_cellEditCtrlEnabled
= enable
;
5201 SetEditControlValue();
5202 ShowCellEditControl();
5206 HideCellEditControl();
5207 SaveEditControlValue();
5209 // do it after HideCellEditControl()
5210 m_cellEditCtrlEnabled
= enable
;
5215 bool wxGrid
::IsCurrentCellReadOnly() const
5218 wxGridCellAttr
* attr
= ((wxGrid
*)this)->GetCellAttr(m_currentCellCoords
);
5219 bool readonly
= attr
->IsReadOnly();
5225 bool wxGrid
::CanEnableCellControl() const
5227 return m_editable
&& !IsCurrentCellReadOnly();
5230 bool wxGrid
::IsCellEditControlEnabled() const
5232 // the cell edit control might be disable for all cells or just for the
5233 // current one if it's read only
5234 return m_cellEditCtrlEnabled ?
!IsCurrentCellReadOnly() : FALSE
;
5237 void wxGrid
::ShowCellEditControl()
5239 if ( IsCellEditControlEnabled() )
5241 if ( !IsVisible( m_currentCellCoords
) )
5247 wxRect rect
= CellToRect( m_currentCellCoords
);
5248 int row
= m_currentCellCoords
.GetRow();
5249 int col
= m_currentCellCoords
.GetCol();
5251 // convert to scrolled coords
5253 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
5255 // done in PaintBackground()
5257 // erase the highlight and the cell contents because the editor
5258 // might not cover the entire cell
5259 wxClientDC
dc( m_gridWin
);
5261 dc
.SetBrush(*wxLIGHT_GREY_BRUSH
); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
5262 dc
.SetPen(*wxTRANSPARENT_PEN
);
5263 dc
.DrawRectangle(rect
);
5266 // cell is shifted by one pixel
5270 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
5271 wxGridCellEditor
* editor
= attr
->GetEditor(GetDefaultEditorForCell(row
, col
));
5272 if ( !editor
->IsCreated() )
5274 editor
->Create(m_gridWin
, -1,
5275 new wxGridCellEditorEvtHandler(this, editor
));
5278 editor
->SetSize( rect
);
5280 editor
->Show( TRUE
, attr
);
5281 editor
->BeginEdit(row
, col
, this);
5288 void wxGrid
::HideCellEditControl()
5290 if ( IsCellEditControlEnabled() )
5292 int row
= m_currentCellCoords
.GetRow();
5293 int col
= m_currentCellCoords
.GetCol();
5295 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
5296 attr
->GetEditor(GetDefaultEditorForCell(row
, col
))->Show( FALSE
);
5298 m_gridWin
->SetFocus();
5303 void wxGrid
::SetEditControlValue( const wxString
& value
)
5305 // RD: The new Editors get the value from the table themselves now. This
5306 // method can probably be removed...
5310 void wxGrid
::SaveEditControlValue()
5312 if ( IsCellEditControlEnabled() )
5314 int row
= m_currentCellCoords
.GetRow();
5315 int col
= m_currentCellCoords
.GetCol();
5317 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
5318 wxGridCellEditor
* editor
= attr
->GetEditor(GetDefaultEditorForCell(row
, col
));
5319 bool changed
= editor
->EndEdit(row
, col
, TRUE
, this);
5325 SendEvent( wxEVT_GRID_CELL_CHANGE
,
5326 m_currentCellCoords
.GetRow(),
5327 m_currentCellCoords
.GetCol() );
5334 // ------ Grid location functions
5335 // Note that all of these functions work with the logical coordinates of
5336 // grid cells and labels so you will need to convert from device
5337 // coordinates for mouse events etc.
5340 void wxGrid
::XYToCell( int x
, int y
, wxGridCellCoords
& coords
)
5342 int row
= YToRow(y
);
5343 int col
= XToCol(x
);
5345 if ( row
== -1 || col
== -1 )
5347 coords
= wxGridNoCellCoords
;
5351 coords
.Set( row
, col
);
5356 int wxGrid
::YToRow( int y
)
5360 for ( i
= 0; i
< m_numRows
; i
++ )
5362 if ( y
< GetRowBottom(i
) )
5366 return m_numRows
; //-1;
5370 int wxGrid
::XToCol( int x
)
5374 for ( i
= 0; i
< m_numCols
; i
++ )
5376 if ( x
< GetColRight(i
) )
5380 return m_numCols
; //-1;
5384 // return the row number that that the y coord is near the edge of, or
5385 // -1 if not near an edge
5387 int wxGrid
::YToEdgeOfRow( int y
)
5391 for ( i
= 0; i
< m_numRows
; i
++ )
5393 if ( GetRowHeight(i
) > WXGRID_LABEL_EDGE_ZONE
)
5395 d
= abs( y
- GetRowBottom(i
) );
5396 if ( d
< WXGRID_LABEL_EDGE_ZONE
)
5405 // return the col number that that the x coord is near the edge of, or
5406 // -1 if not near an edge
5408 int wxGrid
::XToEdgeOfCol( int x
)
5412 for ( i
= 0; i
< m_numCols
; i
++ )
5414 if ( GetColWidth(i
) > WXGRID_LABEL_EDGE_ZONE
)
5416 d
= abs( x
- GetColRight(i
) );
5417 if ( d
< WXGRID_LABEL_EDGE_ZONE
)
5426 wxRect wxGrid
::CellToRect( int row
, int col
)
5428 wxRect
rect( -1, -1, -1, -1 );
5430 if ( row
>= 0 && row
< m_numRows
&&
5431 col
>= 0 && col
< m_numCols
)
5433 rect
.x
= GetColLeft(col
);
5434 rect
.y
= GetRowTop(row
);
5435 rect
.width
= GetColWidth(col
);
5436 rect
.height
= GetRowHeight(row
);
5443 bool wxGrid
::IsVisible( int row
, int col
, bool wholeCellVisible
)
5445 // get the cell rectangle in logical coords
5447 wxRect
r( CellToRect( row
, col
) );
5449 // convert to device coords
5451 int left
, top
, right
, bottom
;
5452 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
5453 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
5455 // check against the client area of the grid window
5458 m_gridWin
->GetClientSize( &cw
, &ch
);
5460 if ( wholeCellVisible
)
5462 // is the cell wholly visible ?
5464 return ( left
>= 0 && right
<= cw
&&
5465 top
>= 0 && bottom
<= ch
);
5469 // is the cell partly visible ?
5471 return ( ((left
>=0 && left
< cw
) || (right
> 0 && right
<= cw
)) &&
5472 ((top
>=0 && top
< ch
) || (bottom
> 0 && bottom
<= ch
)) );
5477 // make the specified cell location visible by doing a minimal amount
5480 void wxGrid
::MakeCellVisible( int row
, int col
)
5483 int xpos
= -1, ypos
= -1;
5485 if ( row
>= 0 && row
< m_numRows
&&
5486 col
>= 0 && col
< m_numCols
)
5488 // get the cell rectangle in logical coords
5490 wxRect
r( CellToRect( row
, col
) );
5492 // convert to device coords
5494 int left
, top
, right
, bottom
;
5495 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
5496 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
5499 m_gridWin
->GetClientSize( &cw
, &ch
);
5505 else if ( bottom
> ch
)
5507 int h
= r
.GetHeight();
5509 for ( i
= row
-1; i
>= 0; i
-- )
5511 int rowHeight
= GetRowHeight(i
);
5512 if ( h
+ rowHeight
> ch
)
5519 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
5520 // have rounding errors (this is important, because if we do, we
5521 // might not scroll at all and some cells won't be redrawn)
5522 ypos
+= GRID_SCROLL_LINE
/ 2;
5529 else if ( right
> cw
)
5531 int w
= r
.GetWidth();
5533 for ( i
= col
-1; i
>= 0; i
-- )
5535 int colWidth
= GetColWidth(i
);
5536 if ( w
+ colWidth
> cw
)
5543 // see comment for ypos above
5544 xpos
+= GRID_SCROLL_LINE
/ 2;
5547 if ( xpos
!= -1 || ypos
!= -1 )
5549 if ( xpos
!= -1 ) xpos
/= GRID_SCROLL_LINE
;
5550 if ( ypos
!= -1 ) ypos
/= GRID_SCROLL_LINE
;
5551 Scroll( xpos
, ypos
);
5559 // ------ Grid cursor movement functions
5562 bool wxGrid
::MoveCursorUp()
5564 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
5565 m_currentCellCoords
.GetRow() > 0 )
5567 MakeCellVisible( m_currentCellCoords
.GetRow() - 1,
5568 m_currentCellCoords
.GetCol() );
5570 SetCurrentCell( m_currentCellCoords
.GetRow() - 1,
5571 m_currentCellCoords
.GetCol() );
5580 bool wxGrid
::MoveCursorDown()
5582 // TODO: allow for scrolling
5584 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
5585 m_currentCellCoords
.GetRow() < m_numRows
-1 )
5587 MakeCellVisible( m_currentCellCoords
.GetRow() + 1,
5588 m_currentCellCoords
.GetCol() );
5590 SetCurrentCell( m_currentCellCoords
.GetRow() + 1,
5591 m_currentCellCoords
.GetCol() );
5600 bool wxGrid
::MoveCursorLeft()
5602 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
5603 m_currentCellCoords
.GetCol() > 0 )
5605 MakeCellVisible( m_currentCellCoords
.GetRow(),
5606 m_currentCellCoords
.GetCol() - 1 );
5608 SetCurrentCell( m_currentCellCoords
.GetRow(),
5609 m_currentCellCoords
.GetCol() - 1 );
5618 bool wxGrid
::MoveCursorRight()
5620 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
5621 m_currentCellCoords
.GetCol() < m_numCols
- 1 )
5623 MakeCellVisible( m_currentCellCoords
.GetRow(),
5624 m_currentCellCoords
.GetCol() + 1 );
5626 SetCurrentCell( m_currentCellCoords
.GetRow(),
5627 m_currentCellCoords
.GetCol() + 1 );
5636 bool wxGrid
::MovePageUp()
5638 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
5640 int row
= m_currentCellCoords
.GetRow();
5644 m_gridWin
->GetClientSize( &cw
, &ch
);
5646 int y
= GetRowTop(row
);
5647 int newRow
= YToRow( y
- ch
+ 1 );
5652 else if ( newRow
== row
)
5657 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
5658 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
5666 bool wxGrid
::MovePageDown()
5668 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
5670 int row
= m_currentCellCoords
.GetRow();
5671 if ( row
< m_numRows
)
5674 m_gridWin
->GetClientSize( &cw
, &ch
);
5676 int y
= GetRowTop(row
);
5677 int newRow
= YToRow( y
+ ch
);
5680 newRow
= m_numRows
- 1;
5682 else if ( newRow
== row
)
5687 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
5688 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
5696 bool wxGrid
::MoveCursorUpBlock()
5699 m_currentCellCoords
!= wxGridNoCellCoords
&&
5700 m_currentCellCoords
.GetRow() > 0 )
5702 int row
= m_currentCellCoords
.GetRow();
5703 int col
= m_currentCellCoords
.GetCol();
5705 if ( m_table
->IsEmptyCell(row
, col
) )
5707 // starting in an empty cell: find the next block of
5713 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5716 else if ( m_table
->IsEmptyCell(row
-1, col
) )
5718 // starting at the top of a block: find the next block
5724 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5729 // starting within a block: find the top of the block
5734 if ( m_table
->IsEmptyCell(row
, col
) )
5742 MakeCellVisible( row
, col
);
5743 SetCurrentCell( row
, col
);
5751 bool wxGrid
::MoveCursorDownBlock()
5754 m_currentCellCoords
!= wxGridNoCellCoords
&&
5755 m_currentCellCoords
.GetRow() < m_numRows
-1 )
5757 int row
= m_currentCellCoords
.GetRow();
5758 int col
= m_currentCellCoords
.GetCol();
5760 if ( m_table
->IsEmptyCell(row
, col
) )
5762 // starting in an empty cell: find the next block of
5765 while ( row
< m_numRows
-1 )
5768 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5771 else if ( m_table
->IsEmptyCell(row
+1, col
) )
5773 // starting at the bottom of a block: find the next block
5776 while ( row
< m_numRows
-1 )
5779 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5784 // starting within a block: find the bottom of the block
5786 while ( row
< m_numRows
-1 )
5789 if ( m_table
->IsEmptyCell(row
, col
) )
5797 MakeCellVisible( row
, col
);
5798 SetCurrentCell( row
, col
);
5806 bool wxGrid
::MoveCursorLeftBlock()
5809 m_currentCellCoords
!= wxGridNoCellCoords
&&
5810 m_currentCellCoords
.GetCol() > 0 )
5812 int row
= m_currentCellCoords
.GetRow();
5813 int col
= m_currentCellCoords
.GetCol();
5815 if ( m_table
->IsEmptyCell(row
, col
) )
5817 // starting in an empty cell: find the next block of
5823 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5826 else if ( m_table
->IsEmptyCell(row
, col
-1) )
5828 // starting at the left of a block: find the next block
5834 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5839 // starting within a block: find the left of the block
5844 if ( m_table
->IsEmptyCell(row
, col
) )
5852 MakeCellVisible( row
, col
);
5853 SetCurrentCell( row
, col
);
5861 bool wxGrid
::MoveCursorRightBlock()
5864 m_currentCellCoords
!= wxGridNoCellCoords
&&
5865 m_currentCellCoords
.GetCol() < m_numCols
-1 )
5867 int row
= m_currentCellCoords
.GetRow();
5868 int col
= m_currentCellCoords
.GetCol();
5870 if ( m_table
->IsEmptyCell(row
, col
) )
5872 // starting in an empty cell: find the next block of
5875 while ( col
< m_numCols
-1 )
5878 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5881 else if ( m_table
->IsEmptyCell(row
, col
+1) )
5883 // starting at the right of a block: find the next block
5886 while ( col
< m_numCols
-1 )
5889 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
5894 // starting within a block: find the right of the block
5896 while ( col
< m_numCols
-1 )
5899 if ( m_table
->IsEmptyCell(row
, col
) )
5907 MakeCellVisible( row
, col
);
5908 SetCurrentCell( row
, col
);
5919 // ------ Label values and formatting
5922 void wxGrid
::GetRowLabelAlignment( int *horiz
, int *vert
)
5924 *horiz
= m_rowLabelHorizAlign
;
5925 *vert
= m_rowLabelVertAlign
;
5928 void wxGrid
::GetColLabelAlignment( int *horiz
, int *vert
)
5930 *horiz
= m_colLabelHorizAlign
;
5931 *vert
= m_colLabelVertAlign
;
5934 wxString wxGrid
::GetRowLabelValue( int row
)
5938 return m_table
->GetRowLabelValue( row
);
5948 wxString wxGrid
::GetColLabelValue( int col
)
5952 return m_table
->GetColLabelValue( col
);
5963 void wxGrid
::SetRowLabelSize( int width
)
5965 width
= wxMax( width
, 0 );
5966 if ( width
!= m_rowLabelWidth
)
5970 m_rowLabelWin
->Show( FALSE
);
5971 m_cornerLabelWin
->Show( FALSE
);
5973 else if ( m_rowLabelWidth
== 0 )
5975 m_rowLabelWin
->Show( TRUE
);
5976 if ( m_colLabelHeight
> 0 ) m_cornerLabelWin
->Show( TRUE
);
5979 m_rowLabelWidth
= width
;
5986 void wxGrid
::SetColLabelSize( int height
)
5988 height
= wxMax( height
, 0 );
5989 if ( height
!= m_colLabelHeight
)
5993 m_colLabelWin
->Show( FALSE
);
5994 m_cornerLabelWin
->Show( FALSE
);
5996 else if ( m_colLabelHeight
== 0 )
5998 m_colLabelWin
->Show( TRUE
);
5999 if ( m_rowLabelWidth
> 0 ) m_cornerLabelWin
->Show( TRUE
);
6002 m_colLabelHeight
= height
;
6009 void wxGrid
::SetLabelBackgroundColour( const wxColour
& colour
)
6011 if ( m_labelBackgroundColour
!= colour
)
6013 m_labelBackgroundColour
= colour
;
6014 m_rowLabelWin
->SetBackgroundColour( colour
);
6015 m_colLabelWin
->SetBackgroundColour( colour
);
6016 m_cornerLabelWin
->SetBackgroundColour( colour
);
6018 if ( !GetBatchCount() )
6020 m_rowLabelWin
->Refresh();
6021 m_colLabelWin
->Refresh();
6022 m_cornerLabelWin
->Refresh();
6027 void wxGrid
::SetLabelTextColour( const wxColour
& colour
)
6029 if ( m_labelTextColour
!= colour
)
6031 m_labelTextColour
= colour
;
6032 if ( !GetBatchCount() )
6034 m_rowLabelWin
->Refresh();
6035 m_colLabelWin
->Refresh();
6040 void wxGrid
::SetLabelFont( const wxFont
& font
)
6043 if ( !GetBatchCount() )
6045 m_rowLabelWin
->Refresh();
6046 m_colLabelWin
->Refresh();
6050 void wxGrid
::SetRowLabelAlignment( int horiz
, int vert
)
6052 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
6054 m_rowLabelHorizAlign
= horiz
;
6057 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
6059 m_rowLabelVertAlign
= vert
;
6062 if ( !GetBatchCount() )
6064 m_rowLabelWin
->Refresh();
6068 void wxGrid
::SetColLabelAlignment( int horiz
, int vert
)
6070 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
6072 m_colLabelHorizAlign
= horiz
;
6075 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
6077 m_colLabelVertAlign
= vert
;
6080 if ( !GetBatchCount() )
6082 m_colLabelWin
->Refresh();
6086 void wxGrid
::SetRowLabelValue( int row
, const wxString
& s
)
6090 m_table
->SetRowLabelValue( row
, s
);
6091 if ( !GetBatchCount() )
6093 wxRect rect
= CellToRect( row
, 0);
6094 if ( rect
.height
> 0 )
6096 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
);
6098 rect
.width
= m_rowLabelWidth
;
6099 m_rowLabelWin
->Refresh( TRUE
, &rect
);
6105 void wxGrid
::SetColLabelValue( int col
, const wxString
& s
)
6109 m_table
->SetColLabelValue( col
, s
);
6110 if ( !GetBatchCount() )
6112 wxRect rect
= CellToRect( 0, col
);
6113 if ( rect
.width
> 0 )
6115 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
);
6117 rect
.height
= m_colLabelHeight
;
6118 m_colLabelWin
->Refresh( TRUE
, &rect
);
6124 void wxGrid
::SetGridLineColour( const wxColour
& colour
)
6126 if ( m_gridLineColour
!= colour
)
6128 m_gridLineColour
= colour
;
6130 wxClientDC
dc( m_gridWin
);
6132 DrawAllGridLines( dc
, wxRegion() );
6136 void wxGrid
::EnableGridLines( bool enable
)
6138 if ( enable
!= m_gridLinesEnabled
)
6140 m_gridLinesEnabled
= enable
;
6142 if ( !GetBatchCount() )
6146 wxClientDC
dc( m_gridWin
);
6148 DrawAllGridLines( dc
, wxRegion() );
6152 m_gridWin
->Refresh();
6159 int wxGrid
::GetDefaultRowSize()
6161 return m_defaultRowHeight
;
6164 int wxGrid
::GetRowSize( int row
)
6166 wxCHECK_MSG( row
>= 0 && row
< m_numRows
, 0, _T("invalid row index") );
6168 return GetRowHeight(row
);
6171 int wxGrid
::GetDefaultColSize()
6173 return m_defaultColWidth
;
6176 int wxGrid
::GetColSize( int col
)
6178 wxCHECK_MSG( col
>= 0 && col
< m_numCols
, 0, _T("invalid column index") );
6180 return GetColWidth(col
);
6183 // ============================================================================
6184 // access to the grid attributes: each of them has a default value in the grid
6185 // itself and may be overidden on a per-cell basis
6186 // ============================================================================
6188 // ----------------------------------------------------------------------------
6189 // setting default attributes
6190 // ----------------------------------------------------------------------------
6192 void wxGrid
::SetDefaultCellBackgroundColour( const wxColour
& col
)
6194 m_defaultCellAttr
->SetBackgroundColour(col
);
6196 m_gridWin
->SetBackgroundColour(col
);
6200 void wxGrid
::SetDefaultCellTextColour( const wxColour
& col
)
6202 m_defaultCellAttr
->SetTextColour(col
);
6205 void wxGrid
::SetDefaultCellAlignment( int horiz
, int vert
)
6207 m_defaultCellAttr
->SetAlignment(horiz
, vert
);
6210 void wxGrid
::SetDefaultCellFont( const wxFont
& font
)
6212 m_defaultCellAttr
->SetFont(font
);
6215 void wxGrid
::SetDefaultRenderer(wxGridCellRenderer
*renderer
)
6217 m_defaultCellAttr
->SetRenderer(renderer
);
6220 void wxGrid
::SetDefaultEditor(wxGridCellEditor
*editor
)
6222 m_defaultCellAttr
->SetEditor(editor
);
6225 // ----------------------------------------------------------------------------
6226 // access to the default attrbiutes
6227 // ----------------------------------------------------------------------------
6229 wxColour wxGrid
::GetDefaultCellBackgroundColour()
6231 return m_defaultCellAttr
->GetBackgroundColour();
6234 wxColour wxGrid
::GetDefaultCellTextColour()
6236 return m_defaultCellAttr
->GetTextColour();
6239 wxFont wxGrid
::GetDefaultCellFont()
6241 return m_defaultCellAttr
->GetFont();
6244 void wxGrid
::GetDefaultCellAlignment( int *horiz
, int *vert
)
6246 m_defaultCellAttr
->GetAlignment(horiz
, vert
);
6249 wxGridCellRenderer
*wxGrid
::GetDefaultRenderer() const
6251 return m_defaultCellAttr
->GetRenderer(NULL
);
6254 wxGridCellEditor
*wxGrid
::GetDefaultEditor() const
6256 return m_defaultCellAttr
->GetEditor(NULL
);
6259 // ----------------------------------------------------------------------------
6260 // access to cell attributes
6261 // ----------------------------------------------------------------------------
6263 wxColour wxGrid
::GetCellBackgroundColour(int row
, int col
)
6265 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
6266 wxColour colour
= attr
->GetBackgroundColour();
6271 wxColour wxGrid
::GetCellTextColour( int row
, int col
)
6273 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
6274 wxColour colour
= attr
->GetTextColour();
6279 wxFont wxGrid
::GetCellFont( int row
, int col
)
6281 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
6282 wxFont font
= attr
->GetFont();
6287 void wxGrid
::GetCellAlignment( int row
, int col
, int *horiz
, int *vert
)
6289 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
6290 attr
->GetAlignment(horiz
, vert
);
6294 wxGridCellRenderer
* wxGrid
::GetCellRenderer(int row
, int col
)
6296 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
6297 wxGridCellRenderer
* renderer
= attr
->GetRenderer(GetDefaultRendererForCell(row
,col
));
6302 wxGridCellEditor
* wxGrid
::GetCellEditor(int row
, int col
)
6304 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
6305 wxGridCellEditor
* editor
= attr
->GetEditor(GetDefaultEditorForCell(row
, col
));
6310 bool wxGrid
::IsReadOnly(int row
, int col
) const
6312 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
6313 bool isReadOnly
= attr
->IsReadOnly();
6318 // ----------------------------------------------------------------------------
6319 // attribute support: cache, automatic provider creation, ...
6320 // ----------------------------------------------------------------------------
6322 bool wxGrid
::CanHaveAttributes()
6329 return m_table
->CanHaveAttributes();
6332 void wxGrid
::ClearAttrCache()
6334 if ( m_attrCache
.row
!= -1 )
6336 m_attrCache
.attr
->SafeDecRef();
6337 m_attrCache
.row
= -1;
6341 void wxGrid
::CacheAttr(int row
, int col
, wxGridCellAttr
*attr
) const
6343 wxGrid
*self
= (wxGrid
*)this; // const_cast
6345 self
->ClearAttrCache();
6346 self
->m_attrCache
.row
= row
;
6347 self
->m_attrCache
.col
= col
;
6348 self
->m_attrCache
.attr
= attr
;
6352 bool wxGrid
::LookupAttr(int row
, int col
, wxGridCellAttr
**attr
) const
6354 if ( row
== m_attrCache
.row
&& col
== m_attrCache
.col
)
6356 *attr
= m_attrCache
.attr
;
6357 (*attr
)->SafeIncRef();
6359 #ifdef DEBUG_ATTR_CACHE
6360 gs_nAttrCacheHits
++;
6367 #ifdef DEBUG_ATTR_CACHE
6368 gs_nAttrCacheMisses
++;
6374 wxGridCellAttr
*wxGrid
::GetCellAttr(int row
, int col
) const
6376 wxGridCellAttr
*attr
;
6377 if ( !LookupAttr(row
, col
, &attr
) )
6379 attr
= m_table ? m_table
->GetAttr(row
, col
) : (wxGridCellAttr
*)NULL
;
6380 CacheAttr(row
, col
, attr
);
6384 attr
->SetDefAttr(m_defaultCellAttr
);
6388 attr
= m_defaultCellAttr
;
6395 wxGridCellAttr
*wxGrid
::GetOrCreateCellAttr(int row
, int col
) const
6397 wxGridCellAttr
*attr
;
6398 if ( !LookupAttr(row
, col
, &attr
) || !attr
)
6400 wxASSERT_MSG( m_table
,
6401 _T("we may only be called if CanHaveAttributes() "
6402 "returned TRUE and then m_table should be !NULL") );
6404 attr
= m_table
->GetAttr(row
, col
);
6407 attr
= new wxGridCellAttr
;
6409 // artificially inc the ref count to match DecRef() in caller
6412 m_table
->SetAttr(attr
, row
, col
);
6415 CacheAttr(row
, col
, attr
);
6417 attr
->SetDefAttr(m_defaultCellAttr
);
6421 // ----------------------------------------------------------------------------
6422 // setting cell attributes: this is forwarded to the table
6423 // ----------------------------------------------------------------------------
6425 void wxGrid
::SetRowAttr(int row
, wxGridCellAttr
*attr
)
6427 if ( CanHaveAttributes() )
6429 m_table
->SetRowAttr(attr
, row
);
6437 void wxGrid
::SetColAttr(int col
, wxGridCellAttr
*attr
)
6439 if ( CanHaveAttributes() )
6441 m_table
->SetColAttr(attr
, col
);
6449 void wxGrid
::SetCellBackgroundColour( int row
, int col
, const wxColour
& colour
)
6451 if ( CanHaveAttributes() )
6453 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
6454 attr
->SetBackgroundColour(colour
);
6459 void wxGrid
::SetCellTextColour( int row
, int col
, const wxColour
& colour
)
6461 if ( CanHaveAttributes() )
6463 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
6464 attr
->SetTextColour(colour
);
6469 void wxGrid
::SetCellFont( int row
, int col
, const wxFont
& font
)
6471 if ( CanHaveAttributes() )
6473 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
6474 attr
->SetFont(font
);
6479 void wxGrid
::SetCellAlignment( int row
, int col
, int horiz
, int vert
)
6481 if ( CanHaveAttributes() )
6483 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
6484 attr
->SetAlignment(horiz
, vert
);
6489 void wxGrid
::SetCellRenderer(int row
, int col
, wxGridCellRenderer
*renderer
)
6491 if ( CanHaveAttributes() )
6493 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
6494 attr
->SetRenderer(renderer
);
6499 void wxGrid
::SetCellEditor(int row
, int col
, wxGridCellEditor
* editor
)
6501 if ( CanHaveAttributes() )
6503 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
6504 attr
->SetEditor(editor
);
6509 void wxGrid
::SetReadOnly(int row
, int col
, bool isReadOnly
)
6511 if ( CanHaveAttributes() )
6513 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
6514 attr
->SetReadOnly(isReadOnly
);
6519 // ----------------------------------------------------------------------------
6520 // Data type registration
6521 // ----------------------------------------------------------------------------
6523 void wxGrid
::RegisterDataType(const wxString
& typeName
,
6524 wxGridCellRenderer
* renderer
,
6525 wxGridCellEditor
* editor
)
6527 m_typeRegistry
->RegisterDataType(typeName
, renderer
, editor
);
6531 wxGridCellEditor
* wxGrid
::GetDefaultEditorForCell(int row
, int col
) const
6533 wxString typeName
= m_table
->GetTypeName(row
, col
);
6534 return GetDefaultEditorForType(typeName
);
6537 wxGridCellRenderer
* wxGrid
::GetDefaultRendererForCell(int row
, int col
) const
6539 wxString typeName
= m_table
->GetTypeName(row
, col
);
6540 return GetDefaultRendererForType(typeName
);
6544 wxGrid
::GetDefaultEditorForType(const wxString
& typeName
) const
6546 int index
= m_typeRegistry
->FindDataType(typeName
);
6548 // Should we force the failure here or let it fallback to string handling???
6549 // wxFAIL_MSG(wxT("Unknown data type name"));
6552 return m_typeRegistry
->GetEditor(index
);
6556 wxGrid
::GetDefaultRendererForType(const wxString
& typeName
) const
6558 int index
= m_typeRegistry
->FindDataType(typeName
);
6560 // Should we force the failure here or let it fallback to string handling???
6561 // wxFAIL_MSG(wxT("Unknown data type name"));
6564 return m_typeRegistry
->GetRenderer(index
);
6568 // ----------------------------------------------------------------------------
6570 // ----------------------------------------------------------------------------
6572 void wxGrid
::EnableDragRowSize( bool enable
)
6574 m_canDragRowSize
= enable
;
6578 void wxGrid
::EnableDragColSize( bool enable
)
6580 m_canDragColSize
= enable
;
6584 void wxGrid
::SetDefaultRowSize( int height
, bool resizeExistingRows
)
6586 m_defaultRowHeight
= wxMax( height
, WXGRID_MIN_ROW_HEIGHT
);
6588 if ( resizeExistingRows
)
6596 void wxGrid
::SetRowSize( int row
, int height
)
6598 wxCHECK_RET( row
>= 0 && row
< m_numRows
, _T("invalid row index") );
6600 if ( m_rowHeights
.IsEmpty() )
6602 // need to really create the array
6606 int h
= wxMax( 0, height
);
6607 int diff
= h
- m_rowHeights
[row
];
6609 m_rowHeights
[row
] = h
;
6611 for ( i
= row
; i
< m_numRows
; i
++ )
6613 m_rowBottoms
[i
] += diff
;
6618 void wxGrid
::SetDefaultColSize( int width
, bool resizeExistingCols
)
6620 m_defaultColWidth
= wxMax( width
, WXGRID_MIN_COL_WIDTH
);
6622 if ( resizeExistingCols
)
6630 void wxGrid
::SetColSize( int col
, int width
)
6632 wxCHECK_RET( col
>= 0 && col
< m_numCols
, _T("invalid column index") );
6634 // should we check that it's bigger than GetColMinimalWidth(col) here?
6636 if ( m_colWidths
.IsEmpty() )
6638 // need to really create the array
6642 int w
= wxMax( 0, width
);
6643 int diff
= w
- m_colWidths
[col
];
6644 m_colWidths
[col
] = w
;
6647 for ( i
= col
; i
< m_numCols
; i
++ )
6649 m_colRights
[i
] += diff
;
6655 void wxGrid
::SetColMinimalWidth( int col
, int width
)
6657 m_colMinWidths
.Put(col
, (wxObject
*)width
);
6660 int wxGrid
::GetColMinimalWidth(int col
) const
6662 wxObject
*obj
= m_colMinWidths
.Get(m_dragRowOrCol
);
6663 return obj ?
(int)obj
: WXGRID_MIN_COL_WIDTH
;
6666 void wxGrid
::AutoSizeColumn( int col
, bool setAsMin
)
6668 wxClientDC
dc(m_gridWin
);
6670 wxCoord width
, widthMax
= 0;
6671 for ( int row
= 0; row
< m_numRows
; row
++ )
6673 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
6674 wxGridCellRenderer
* renderer
= attr
->GetRenderer(GetDefaultRendererForCell(row
,col
));
6677 width
= renderer
->GetBestSize(*this, *attr
, dc
, row
, col
).x
;
6678 if ( width
> widthMax
)
6687 // now also compare with the column label width
6688 dc
.SetFont( GetLabelFont() );
6689 dc
.GetTextExtent( GetColLabelValue(col
), &width
, NULL
);
6690 if ( width
> widthMax
)
6697 // empty column - give default width (notice that if widthMax is less
6698 // than default width but != 0, it's ok)
6699 widthMax
= m_defaultColWidth
;
6703 // leave some space around text
6707 SetColSize(col
, widthMax
);
6710 SetColMinimalWidth(col
, widthMax
);
6714 void wxGrid
::AutoSizeColumns( bool setAsMin
)
6716 for ( int col
= 0; col
< m_numCols
; col
++ )
6718 AutoSizeColumn(col
, setAsMin
);
6723 // ------ cell value accessor functions
6726 void wxGrid
::SetCellValue( int row
, int col
, const wxString
& s
)
6730 m_table
->SetValue( row
, col
, s
.c_str() );
6731 if ( !GetBatchCount() )
6733 wxClientDC
dc( m_gridWin
);
6735 DrawCell( dc
, wxGridCellCoords(row
, col
) );
6738 #if 0 // TODO: edit in place
6740 if ( m_currentCellCoords
.GetRow() == row
&&
6741 m_currentCellCoords
.GetCol() == col
)
6743 SetEditControlValue( s
);
6752 // ------ Block, row and col selection
6755 void wxGrid
::SelectRow( int row
, bool addToSelected
)
6759 if ( IsSelection() && addToSelected
)
6762 bool need_refresh
[4];
6766 need_refresh
[3] = FALSE
;
6770 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
6771 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
6772 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
6773 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
6777 need_refresh
[0] = TRUE
;
6778 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( row
, 0 ),
6779 wxGridCellCoords ( oldTop
- 1,
6781 m_selectedTopLeft
.SetRow( row
);
6786 need_refresh
[1] = TRUE
;
6787 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
, 0 ),
6788 wxGridCellCoords ( oldBottom
,
6791 m_selectedTopLeft
.SetCol( 0 );
6794 if ( oldBottom
< row
)
6796 need_refresh
[2] = TRUE
;
6797 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom
+ 1, 0 ),
6798 wxGridCellCoords ( row
,
6800 m_selectedBottomRight
.SetRow( row
);
6803 if ( oldRight
< m_numCols
- 1 )
6805 need_refresh
[3] = TRUE
;
6806 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
6808 wxGridCellCoords ( oldBottom
,
6810 m_selectedBottomRight
.SetCol( m_numCols
- 1 );
6813 for (i
= 0; i
< 4; i
++ )
6814 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
6815 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
6819 r
= SelectionToDeviceRect();
6821 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( FALSE
, &r
);
6823 m_selectedTopLeft
.Set( row
, 0 );
6824 m_selectedBottomRight
.Set( row
, m_numCols
-1 );
6825 r
= SelectionToDeviceRect();
6826 m_gridWin
->Refresh( FALSE
, &r
);
6829 wxGridRangeSelectEvent
gridEvt( GetId(),
6830 wxEVT_GRID_RANGE_SELECT
,
6833 m_selectedBottomRight
);
6835 GetEventHandler()->ProcessEvent(gridEvt
);
6839 void wxGrid
::SelectCol( int col
, bool addToSelected
)
6841 if ( IsSelection() && addToSelected
)
6844 bool need_refresh
[4];
6848 need_refresh
[3] = FALSE
;
6851 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
6852 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
6853 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
6854 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
6856 if ( oldLeft
> col
)
6858 need_refresh
[0] = TRUE
;
6859 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col
),
6860 wxGridCellCoords ( m_numRows
- 1,
6862 m_selectedTopLeft
.SetCol( col
);
6867 need_refresh
[1] = TRUE
;
6868 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft
),
6869 wxGridCellCoords ( oldTop
- 1,
6871 m_selectedTopLeft
.SetRow( 0 );
6874 if ( oldRight
< col
)
6876 need_refresh
[2] = TRUE
;
6877 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight
+ 1 ),
6878 wxGridCellCoords ( m_numRows
- 1,
6880 m_selectedBottomRight
.SetCol( col
);
6883 if ( oldBottom
< m_numRows
- 1 )
6885 need_refresh
[3] = TRUE
;
6886 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom
+ 1,
6888 wxGridCellCoords ( m_numRows
- 1,
6890 m_selectedBottomRight
.SetRow( m_numRows
- 1 );
6893 for (i
= 0; i
< 4; i
++ )
6894 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
6895 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
6901 r
= SelectionToDeviceRect();
6903 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( FALSE
, &r
);
6905 m_selectedTopLeft
.Set( 0, col
);
6906 m_selectedBottomRight
.Set( m_numRows
-1, col
);
6907 r
= SelectionToDeviceRect();
6908 m_gridWin
->Refresh( FALSE
, &r
);
6911 wxGridRangeSelectEvent
gridEvt( GetId(),
6912 wxEVT_GRID_RANGE_SELECT
,
6915 m_selectedBottomRight
);
6917 GetEventHandler()->ProcessEvent(gridEvt
);
6921 void wxGrid
::SelectBlock( int topRow
, int leftCol
, int bottomRow
, int rightCol
)
6924 wxGridCellCoords updateTopLeft
, updateBottomRight
;
6926 if ( topRow
> bottomRow
)
6933 if ( leftCol
> rightCol
)
6940 updateTopLeft
= wxGridCellCoords( topRow
, leftCol
);
6941 updateBottomRight
= wxGridCellCoords( bottomRow
, rightCol
);
6943 if ( m_selectedTopLeft
!= updateTopLeft
||
6944 m_selectedBottomRight
!= updateBottomRight
)
6946 // Compute two optimal update rectangles:
6947 // Either one rectangle is a real subset of the
6948 // other, or they are (almost) disjoint!
6950 bool need_refresh
[4];
6954 need_refresh
[3] = FALSE
;
6957 // Store intermediate values
6958 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
6959 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
6960 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
6961 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
6963 // Determine the outer/inner coordinates.
6964 if (oldLeft
> leftCol
)
6970 if (oldTop
> topRow
)
6976 if (oldRight
< rightCol
)
6979 oldRight
= rightCol
;
6982 if (oldBottom
< bottomRow
)
6985 oldBottom
= bottomRow
;
6989 // Now, either the stuff marked old is the outer
6990 // rectangle or we don't have a situation where one
6991 // is contained in the other.
6993 if ( oldLeft
< leftCol
)
6995 need_refresh
[0] = TRUE
;
6996 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
6998 wxGridCellCoords ( oldBottom
,
7002 if ( oldTop
< topRow
)
7004 need_refresh
[1] = TRUE
;
7005 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
7007 wxGridCellCoords ( topRow
- 1,
7011 if ( oldRight
> rightCol
)
7013 need_refresh
[2] = TRUE
;
7014 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
7016 wxGridCellCoords ( oldBottom
,
7020 if ( oldBottom
> bottomRow
)
7022 need_refresh
[3] = TRUE
;
7023 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow
+ 1,
7025 wxGridCellCoords ( oldBottom
,
7031 m_selectedTopLeft
= updateTopLeft
;
7032 m_selectedBottomRight
= updateBottomRight
;
7034 // various Refresh() calls
7035 for (i
= 0; i
< 4; i
++ )
7036 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
7037 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
7040 // only generate an event if the block is not being selected by
7041 // dragging the mouse (in which case the event will be generated in
7042 // the mouse event handler)
7043 if ( !m_isDragging
)
7045 wxGridRangeSelectEvent
gridEvt( GetId(),
7046 wxEVT_GRID_RANGE_SELECT
,
7049 m_selectedBottomRight
);
7051 GetEventHandler()->ProcessEvent(gridEvt
);
7055 void wxGrid
::SelectAll()
7057 m_selectedTopLeft
.Set( 0, 0 );
7058 m_selectedBottomRight
.Set( m_numRows
-1, m_numCols
-1 );
7060 m_gridWin
->Refresh();
7064 void wxGrid
::ClearSelection()
7066 m_selectedTopLeft
= wxGridNoCellCoords
;
7067 m_selectedBottomRight
= wxGridNoCellCoords
;
7071 // This function returns the rectangle that encloses the given block
7072 // in device coords clipped to the client size of the grid window.
7074 wxRect wxGrid
::BlockToDeviceRect( const wxGridCellCoords
&topLeft
,
7075 const wxGridCellCoords
&bottomRight
)
7077 wxRect
rect( wxGridNoCellRect
);
7080 cellRect
= CellToRect( topLeft
);
7081 if ( cellRect
!= wxGridNoCellRect
)
7087 rect
= wxRect( 0, 0, 0, 0 );
7090 cellRect
= CellToRect( bottomRight
);
7091 if ( cellRect
!= wxGridNoCellRect
)
7097 return wxGridNoCellRect
;
7100 // convert to scrolled coords
7102 int left
, top
, right
, bottom
;
7103 CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top
);
7104 CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom
);
7107 m_gridWin
->GetClientSize( &cw
, &ch
);
7109 rect
.SetLeft( wxMax(0, left
) );
7110 rect
.SetTop( wxMax(0, top
) );
7111 rect
.SetRight( wxMin(cw
, right
) );
7112 rect
.SetBottom( wxMin(ch
, bottom
) );
7120 // ------ Grid event classes
7123 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxEvent
)
7125 wxGridEvent
::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
,
7126 int row
, int col
, int x
, int y
,
7127 bool control
, bool shift
, bool alt
, bool meta
)
7128 : wxNotifyEvent( type
, id
)
7134 m_control
= control
;
7139 SetEventObject(obj
);
7143 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxEvent
)
7145 wxGridSizeEvent
::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
,
7146 int rowOrCol
, int x
, int y
,
7147 bool control
, bool shift
, bool alt
, bool meta
)
7148 : wxNotifyEvent( type
, id
)
7150 m_rowOrCol
= rowOrCol
;
7153 m_control
= control
;
7158 SetEventObject(obj
);
7162 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxEvent
)
7164 wxGridRangeSelectEvent
::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
,
7165 const wxGridCellCoords
& topLeft
,
7166 const wxGridCellCoords
& bottomRight
,
7167 bool control
, bool shift
, bool alt
, bool meta
)
7168 : wxNotifyEvent( type
, id
)
7170 m_topLeft
= topLeft
;
7171 m_bottomRight
= bottomRight
;
7172 m_control
= control
;
7177 SetEventObject(obj
);
7181 #endif // ifndef wxUSE_NEW_GRID