1 ///////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/grid.cpp
3 // Purpose: wxGrid and related classes
4 // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5 // Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
15 - Replace use of wxINVERT with wxOverlay
16 - Make Begin/EndBatch() the same as the generic Freeze/Thaw()
17 - Review the column reordering code, it's a mess.
18 - Implement row reordering after dealing with the columns.
21 // For compilers that support precompilation, includes "wx/wx.h".
22 #include "wx/wxprec.h"
34 #include "wx/dcclient.h"
35 #include "wx/settings.h"
37 #include "wx/textctrl.h"
38 #include "wx/checkbox.h"
39 #include "wx/combobox.h"
40 #include "wx/valtext.h"
43 #include "wx/listbox.h"
46 #include "wx/textfile.h"
47 #include "wx/spinctrl.h"
48 #include "wx/tokenzr.h"
49 #include "wx/renderer.h"
50 #include "wx/headerctrl.h"
52 #include "wx/generic/gridsel.h"
53 #include "wx/generic/gridctrl.h"
54 #include "wx/generic/grideditors.h"
55 #include "wx/generic/private/grid.h"
57 const char wxGridNameStr
[] = "grid";
59 #if defined(__WXMOTIF__)
60 #define WXUNUSED_MOTIF(identifier) WXUNUSED(identifier)
62 #define WXUNUSED_MOTIF(identifier) identifier
65 #if defined(__WXGTK__)
66 #define WXUNUSED_GTK(identifier) WXUNUSED(identifier)
68 #define WXUNUSED_GTK(identifier) identifier
71 // Required for wxIs... functions
75 // ----------------------------------------------------------------------------
77 // ----------------------------------------------------------------------------
79 //#define DEBUG_ATTR_CACHE
80 #ifdef DEBUG_ATTR_CACHE
81 static size_t gs_nAttrCacheHits
= 0;
82 static size_t gs_nAttrCacheMisses
= 0;
85 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 wxGridCellCoords
wxGridNoCellCoords( -1, -1 );
90 wxRect
wxGridNoCellRect( -1, -1, -1, -1 );
96 const size_t GRID_SCROLL_LINE_X
= 15;
97 const size_t GRID_SCROLL_LINE_Y
= GRID_SCROLL_LINE_X
;
99 // the size of hash tables used a bit everywhere (the max number of elements
100 // in these hash tables is the number of rows/columns)
101 const int GRID_HASH_SIZE
= 100;
103 // the minimal distance in pixels the mouse needs to move to start a drag
105 const int DRAG_SENSITIVITY
= 3;
107 } // anonymous namespace
109 #include "wx/arrimpl.cpp"
111 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
)
112 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray
)
114 // ----------------------------------------------------------------------------
116 // ----------------------------------------------------------------------------
118 wxDEFINE_EVENT( wxEVT_GRID_CELL_LEFT_CLICK
, wxGridEvent
);
119 wxDEFINE_EVENT( wxEVT_GRID_CELL_RIGHT_CLICK
, wxGridEvent
);
120 wxDEFINE_EVENT( wxEVT_GRID_CELL_LEFT_DCLICK
, wxGridEvent
);
121 wxDEFINE_EVENT( wxEVT_GRID_CELL_RIGHT_DCLICK
, wxGridEvent
);
122 wxDEFINE_EVENT( wxEVT_GRID_CELL_BEGIN_DRAG
, wxGridEvent
);
123 wxDEFINE_EVENT( wxEVT_GRID_LABEL_LEFT_CLICK
, wxGridEvent
);
124 wxDEFINE_EVENT( wxEVT_GRID_LABEL_RIGHT_CLICK
, wxGridEvent
);
125 wxDEFINE_EVENT( wxEVT_GRID_LABEL_LEFT_DCLICK
, wxGridEvent
);
126 wxDEFINE_EVENT( wxEVT_GRID_LABEL_RIGHT_DCLICK
, wxGridEvent
);
127 wxDEFINE_EVENT( wxEVT_GRID_ROW_SIZE
, wxGridSizeEvent
);
128 wxDEFINE_EVENT( wxEVT_GRID_COL_SIZE
, wxGridSizeEvent
);
129 wxDEFINE_EVENT( wxEVT_GRID_COL_MOVE
, wxGridEvent
);
130 wxDEFINE_EVENT( wxEVT_GRID_COL_SORT
, wxGridEvent
);
131 wxDEFINE_EVENT( wxEVT_GRID_RANGE_SELECT
, wxGridRangeSelectEvent
);
132 wxDEFINE_EVENT( wxEVT_GRID_CELL_CHANGING
, wxGridEvent
);
133 wxDEFINE_EVENT( wxEVT_GRID_CELL_CHANGED
, wxGridEvent
);
134 wxDEFINE_EVENT( wxEVT_GRID_SELECT_CELL
, wxGridEvent
);
135 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_SHOWN
, wxGridEvent
);
136 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_HIDDEN
, wxGridEvent
);
137 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_CREATED
, wxGridEditorCreatedEvent
);
139 // ============================================================================
141 // ============================================================================
143 IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler
, wxEvtHandler
)
145 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler
, wxEvtHandler
)
146 EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus
)
147 EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown
)
148 EVT_CHAR( wxGridCellEditorEvtHandler::OnChar
)
151 BEGIN_EVENT_TABLE(wxGridHeaderCtrl
, wxHeaderCtrl
)
152 EVT_HEADER_CLICK(wxID_ANY
, wxGridHeaderCtrl::OnClick
)
154 EVT_HEADER_BEGIN_RESIZE(wxID_ANY
, wxGridHeaderCtrl::OnBeginResize
)
155 EVT_HEADER_RESIZING(wxID_ANY
, wxGridHeaderCtrl::OnResizing
)
156 EVT_HEADER_END_RESIZE(wxID_ANY
, wxGridHeaderCtrl::OnEndResize
)
158 EVT_HEADER_BEGIN_REORDER(wxID_ANY
, wxGridHeaderCtrl::OnBeginReorder
)
159 EVT_HEADER_END_REORDER(wxID_ANY
, wxGridHeaderCtrl::OnEndReorder
)
162 wxGridOperations
& wxGridRowOperations::Dual() const
164 static wxGridColumnOperations s_colOper
;
169 wxGridOperations
& wxGridColumnOperations::Dual() const
171 static wxGridRowOperations s_rowOper
;
176 // ----------------------------------------------------------------------------
177 // wxGridCellWorker is an (almost) empty common base class for
178 // wxGridCellRenderer and wxGridCellEditor managing ref counting
179 // ----------------------------------------------------------------------------
181 void wxGridCellWorker::SetParameters(const wxString
& WXUNUSED(params
))
186 wxGridCellWorker::~wxGridCellWorker()
190 // ----------------------------------------------------------------------------
192 // ----------------------------------------------------------------------------
194 void wxGridCellAttr::Init(wxGridCellAttr
*attrDefault
)
198 m_isReadOnly
= Unset
;
203 m_attrkind
= wxGridCellAttr::Cell
;
205 m_sizeRows
= m_sizeCols
= 1;
206 m_overflow
= UnsetOverflow
;
208 SetDefAttr(attrDefault
);
211 wxGridCellAttr
*wxGridCellAttr::Clone() const
213 wxGridCellAttr
*attr
= new wxGridCellAttr(m_defGridAttr
);
215 if ( HasTextColour() )
216 attr
->SetTextColour(GetTextColour());
217 if ( HasBackgroundColour() )
218 attr
->SetBackgroundColour(GetBackgroundColour());
220 attr
->SetFont(GetFont());
221 if ( HasAlignment() )
222 attr
->SetAlignment(m_hAlign
, m_vAlign
);
224 attr
->SetSize( m_sizeRows
, m_sizeCols
);
228 attr
->SetRenderer(m_renderer
);
229 m_renderer
->IncRef();
233 attr
->SetEditor(m_editor
);
240 attr
->SetOverflow( m_overflow
== Overflow
);
241 attr
->SetKind( m_attrkind
);
246 void wxGridCellAttr::MergeWith(wxGridCellAttr
*mergefrom
)
248 if ( !HasTextColour() && mergefrom
->HasTextColour() )
249 SetTextColour(mergefrom
->GetTextColour());
250 if ( !HasBackgroundColour() && mergefrom
->HasBackgroundColour() )
251 SetBackgroundColour(mergefrom
->GetBackgroundColour());
252 if ( !HasFont() && mergefrom
->HasFont() )
253 SetFont(mergefrom
->GetFont());
254 if ( !HasAlignment() && mergefrom
->HasAlignment() )
257 mergefrom
->GetAlignment( &hAlign
, &vAlign
);
258 SetAlignment(hAlign
, vAlign
);
260 if ( !HasSize() && mergefrom
->HasSize() )
261 mergefrom
->GetSize( &m_sizeRows
, &m_sizeCols
);
263 // Directly access member functions as GetRender/Editor don't just return
264 // m_renderer/m_editor
266 // Maybe add support for merge of Render and Editor?
267 if (!HasRenderer() && mergefrom
->HasRenderer() )
269 m_renderer
= mergefrom
->m_renderer
;
270 m_renderer
->IncRef();
272 if ( !HasEditor() && mergefrom
->HasEditor() )
274 m_editor
= mergefrom
->m_editor
;
277 if ( !HasReadWriteMode() && mergefrom
->HasReadWriteMode() )
278 SetReadOnly(mergefrom
->IsReadOnly());
280 if (!HasOverflowMode() && mergefrom
->HasOverflowMode() )
281 SetOverflow(mergefrom
->GetOverflow());
283 SetDefAttr(mergefrom
->m_defGridAttr
);
286 void wxGridCellAttr::SetSize(int num_rows
, int num_cols
)
288 // The size of a cell is normally 1,1
290 // If this cell is larger (2,2) then this is the top left cell
291 // the other cells that will be covered (lower right cells) must be
292 // set to negative or zero values such that
293 // row + num_rows of the covered cell points to the larger cell (this cell)
294 // same goes for the col + num_cols.
296 // Size of 0,0 is NOT valid, neither is <=0 and any positive value
298 wxASSERT_MSG( (!((num_rows
> 0) && (num_cols
<= 0)) ||
299 !((num_rows
<= 0) && (num_cols
> 0)) ||
300 !((num_rows
== 0) && (num_cols
== 0))),
301 wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
303 m_sizeRows
= num_rows
;
304 m_sizeCols
= num_cols
;
307 const wxColour
& wxGridCellAttr::GetTextColour() const
313 else if (m_defGridAttr
&& m_defGridAttr
!= this)
315 return m_defGridAttr
->GetTextColour();
319 wxFAIL_MSG(wxT("Missing default cell attribute"));
324 const wxColour
& wxGridCellAttr::GetBackgroundColour() const
326 if (HasBackgroundColour())
330 else if (m_defGridAttr
&& m_defGridAttr
!= this)
332 return m_defGridAttr
->GetBackgroundColour();
336 wxFAIL_MSG(wxT("Missing default cell attribute"));
341 const wxFont
& wxGridCellAttr::GetFont() const
347 else if (m_defGridAttr
&& m_defGridAttr
!= this)
349 return m_defGridAttr
->GetFont();
353 wxFAIL_MSG(wxT("Missing default cell attribute"));
358 void wxGridCellAttr::GetAlignment(int *hAlign
, int *vAlign
) const
367 else if (m_defGridAttr
&& m_defGridAttr
!= this)
369 m_defGridAttr
->GetAlignment(hAlign
, vAlign
);
373 wxFAIL_MSG(wxT("Missing default cell attribute"));
377 void wxGridCellAttr::GetSize( int *num_rows
, int *num_cols
) const
380 *num_rows
= m_sizeRows
;
382 *num_cols
= m_sizeCols
;
385 // GetRenderer and GetEditor use a slightly different decision path about
386 // which attribute to use. If a non-default attr object has one then it is
387 // used, otherwise the default editor or renderer is fetched from the grid and
388 // used. It should be the default for the data type of the cell. If it is
389 // NULL (because the table has a type that the grid does not have in its
390 // registry), then the grid's default editor or renderer is used.
392 wxGridCellRenderer
* wxGridCellAttr::GetRenderer(const wxGrid
* grid
, int row
, int col
) const
394 wxGridCellRenderer
*renderer
= NULL
;
396 if ( m_renderer
&& this != m_defGridAttr
)
398 // use the cells renderer if it has one
399 renderer
= m_renderer
;
402 else // no non-default cell renderer
404 // get default renderer for the data type
407 // GetDefaultRendererForCell() will do IncRef() for us
408 renderer
= grid
->GetDefaultRendererForCell(row
, col
);
411 if ( renderer
== NULL
)
413 if ( (m_defGridAttr
!= NULL
) && (m_defGridAttr
!= this) )
415 // if we still don't have one then use the grid default
416 // (no need for IncRef() here neither)
417 renderer
= m_defGridAttr
->GetRenderer(NULL
, 0, 0);
419 else // default grid attr
421 // use m_renderer which we had decided not to use initially
422 renderer
= m_renderer
;
429 // we're supposed to always find something
430 wxASSERT_MSG(renderer
, wxT("Missing default cell renderer"));
435 // same as above, except for s/renderer/editor/g
436 wxGridCellEditor
* wxGridCellAttr::GetEditor(const wxGrid
* grid
, int row
, int col
) const
438 wxGridCellEditor
*editor
= NULL
;
440 if ( m_editor
&& this != m_defGridAttr
)
442 // use the cells editor if it has one
446 else // no non default cell editor
448 // get default editor for the data type
451 // GetDefaultEditorForCell() will do IncRef() for us
452 editor
= grid
->GetDefaultEditorForCell(row
, col
);
455 if ( editor
== NULL
)
457 if ( (m_defGridAttr
!= NULL
) && (m_defGridAttr
!= this) )
459 // if we still don't have one then use the grid default
460 // (no need for IncRef() here neither)
461 editor
= m_defGridAttr
->GetEditor(NULL
, 0, 0);
463 else // default grid attr
465 // use m_editor which we had decided not to use initially
473 // we're supposed to always find something
474 wxASSERT_MSG(editor
, wxT("Missing default cell editor"));
479 // ----------------------------------------------------------------------------
480 // wxGridCellAttrData
481 // ----------------------------------------------------------------------------
483 void wxGridCellAttrData::SetAttr(wxGridCellAttr
*attr
, int row
, int col
)
485 // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not
486 // touch attribute's reference counting explicitly, since this
487 // is managed by class wxGridCellWithAttr
488 int n
= FindIndex(row
, col
);
489 if ( n
== wxNOT_FOUND
)
494 m_attrs
.Add(new wxGridCellWithAttr(row
, col
, attr
));
496 //else: nothing to do
498 else // we already have an attribute for this cell
502 // change the attribute
503 m_attrs
[(size_t)n
].ChangeAttr(attr
);
507 // remove this attribute
508 m_attrs
.RemoveAt((size_t)n
);
513 wxGridCellAttr
*wxGridCellAttrData::GetAttr(int row
, int col
) const
515 wxGridCellAttr
*attr
= NULL
;
517 int n
= FindIndex(row
, col
);
518 if ( n
!= wxNOT_FOUND
)
520 attr
= m_attrs
[(size_t)n
].attr
;
527 void wxGridCellAttrData::UpdateAttrRows( size_t pos
, int numRows
)
529 size_t count
= m_attrs
.GetCount();
530 for ( size_t n
= 0; n
< count
; n
++ )
532 wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
533 wxCoord row
= coords
.GetRow();
534 if ((size_t)row
>= pos
)
538 // If rows inserted, include row counter where necessary
539 coords
.SetRow(row
+ numRows
);
541 else if (numRows
< 0)
543 // If rows deleted ...
544 if ((size_t)row
>= pos
- numRows
)
546 // ...either decrement row counter (if row still exists)...
547 coords
.SetRow(row
+ numRows
);
551 // ...or remove the attribute
561 void wxGridCellAttrData::UpdateAttrCols( size_t pos
, int numCols
)
563 size_t count
= m_attrs
.GetCount();
564 for ( size_t n
= 0; n
< count
; n
++ )
566 wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
567 wxCoord col
= coords
.GetCol();
568 if ( (size_t)col
>= pos
)
572 // If rows inserted, include row counter where necessary
573 coords
.SetCol(col
+ numCols
);
575 else if (numCols
< 0)
577 // If rows deleted ...
578 if ((size_t)col
>= pos
- numCols
)
580 // ...either decrement row counter (if row still exists)...
581 coords
.SetCol(col
+ numCols
);
585 // ...or remove the attribute
595 int wxGridCellAttrData::FindIndex(int row
, int col
) const
597 size_t count
= m_attrs
.GetCount();
598 for ( size_t n
= 0; n
< count
; n
++ )
600 const wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
601 if ( (coords
.GetRow() == row
) && (coords
.GetCol() == col
) )
610 // ----------------------------------------------------------------------------
611 // wxGridRowOrColAttrData
612 // ----------------------------------------------------------------------------
614 wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
616 size_t count
= m_attrs
.GetCount();
617 for ( size_t n
= 0; n
< count
; n
++ )
619 m_attrs
[n
]->DecRef();
623 wxGridCellAttr
*wxGridRowOrColAttrData::GetAttr(int rowOrCol
) const
625 wxGridCellAttr
*attr
= NULL
;
627 int n
= m_rowsOrCols
.Index(rowOrCol
);
628 if ( n
!= wxNOT_FOUND
)
630 attr
= m_attrs
[(size_t)n
];
637 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr
*attr
, int rowOrCol
)
639 int i
= m_rowsOrCols
.Index(rowOrCol
);
640 if ( i
== wxNOT_FOUND
)
644 // add the attribute - no need to do anything to reference count
645 // since we take ownership of the attribute.
646 m_rowsOrCols
.Add(rowOrCol
);
653 size_t n
= (size_t)i
;
654 if ( m_attrs
[n
] == attr
)
659 // change the attribute, handling reference count manually,
660 // taking ownership of the new attribute.
661 m_attrs
[n
]->DecRef();
666 // remove this attribute, handling reference count manually
667 m_attrs
[n
]->DecRef();
668 m_rowsOrCols
.RemoveAt(n
);
674 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols
)
676 size_t count
= m_attrs
.GetCount();
677 for ( size_t n
= 0; n
< count
; n
++ )
679 int & rowOrCol
= m_rowsOrCols
[n
];
680 if ( (size_t)rowOrCol
>= pos
)
682 if ( numRowsOrCols
> 0 )
684 // If rows inserted, include row counter where necessary
685 rowOrCol
+= numRowsOrCols
;
687 else if ( numRowsOrCols
< 0)
689 // If rows deleted, either decrement row counter (if row still exists)
690 if ((size_t)rowOrCol
>= pos
- numRowsOrCols
)
691 rowOrCol
+= numRowsOrCols
;
694 m_rowsOrCols
.RemoveAt(n
);
695 m_attrs
[n
]->DecRef();
705 // ----------------------------------------------------------------------------
706 // wxGridCellAttrProvider
707 // ----------------------------------------------------------------------------
709 wxGridCellAttrProvider::wxGridCellAttrProvider()
714 wxGridCellAttrProvider::~wxGridCellAttrProvider()
719 void wxGridCellAttrProvider::InitData()
721 m_data
= new wxGridCellAttrProviderData
;
724 wxGridCellAttr
*wxGridCellAttrProvider::GetAttr(int row
, int col
,
725 wxGridCellAttr::wxAttrKind kind
) const
727 wxGridCellAttr
*attr
= NULL
;
732 case (wxGridCellAttr::Any
):
733 // Get cached merge attributes.
734 // Currently not used as no cache implemented as not mutable
735 // attr = m_data->m_mergeAttr.GetAttr(row, col);
738 // Basically implement old version.
739 // Also check merge cache, so we don't have to re-merge every time..
740 wxGridCellAttr
*attrcell
= m_data
->m_cellAttrs
.GetAttr(row
, col
);
741 wxGridCellAttr
*attrrow
= m_data
->m_rowAttrs
.GetAttr(row
);
742 wxGridCellAttr
*attrcol
= m_data
->m_colAttrs
.GetAttr(col
);
744 if ((attrcell
!= attrrow
) && (attrrow
!= attrcol
) && (attrcell
!= attrcol
))
746 // Two or more are non NULL
747 attr
= new wxGridCellAttr
;
748 attr
->SetKind(wxGridCellAttr::Merged
);
750 // Order is important..
753 attr
->MergeWith(attrcell
);
758 attr
->MergeWith(attrcol
);
763 attr
->MergeWith(attrrow
);
767 // store merge attr if cache implemented
769 //m_data->m_mergeAttr.SetAttr(attr, row, col);
773 // one or none is non null return it or null.
792 case (wxGridCellAttr::Cell
):
793 attr
= m_data
->m_cellAttrs
.GetAttr(row
, col
);
796 case (wxGridCellAttr::Col
):
797 attr
= m_data
->m_colAttrs
.GetAttr(col
);
800 case (wxGridCellAttr::Row
):
801 attr
= m_data
->m_rowAttrs
.GetAttr(row
);
806 // (wxGridCellAttr::Default):
807 // (wxGridCellAttr::Merged):
815 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr
*attr
,
821 m_data
->m_cellAttrs
.SetAttr(attr
, row
, col
);
824 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr
*attr
, int row
)
829 m_data
->m_rowAttrs
.SetAttr(attr
, row
);
832 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr
*attr
, int col
)
837 m_data
->m_colAttrs
.SetAttr(attr
, col
);
840 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos
, int numRows
)
844 m_data
->m_cellAttrs
.UpdateAttrRows( pos
, numRows
);
846 m_data
->m_rowAttrs
.UpdateAttrRowsOrCols( pos
, numRows
);
850 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos
, int numCols
)
854 m_data
->m_cellAttrs
.UpdateAttrCols( pos
, numCols
);
856 m_data
->m_colAttrs
.UpdateAttrRowsOrCols( pos
, numCols
);
860 // ----------------------------------------------------------------------------
862 // ----------------------------------------------------------------------------
864 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject
)
866 wxGridTableBase::wxGridTableBase()
869 m_attrProvider
= NULL
;
872 wxGridTableBase::~wxGridTableBase()
874 delete m_attrProvider
;
877 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider
*attrProvider
)
879 delete m_attrProvider
;
880 m_attrProvider
= attrProvider
;
883 bool wxGridTableBase::CanHaveAttributes()
885 if ( ! GetAttrProvider() )
887 // use the default attr provider by default
888 SetAttrProvider(new wxGridCellAttrProvider
);
894 wxGridCellAttr
*wxGridTableBase::GetAttr(int row
, int col
, wxGridCellAttr::wxAttrKind kind
)
896 if ( m_attrProvider
)
897 return m_attrProvider
->GetAttr(row
, col
, kind
);
902 void wxGridTableBase::SetAttr(wxGridCellAttr
* attr
, int row
, int col
)
904 if ( m_attrProvider
)
907 attr
->SetKind(wxGridCellAttr::Cell
);
908 m_attrProvider
->SetAttr(attr
, row
, col
);
912 // as we take ownership of the pointer and don't store it, we must
918 void wxGridTableBase::SetRowAttr(wxGridCellAttr
*attr
, int row
)
920 if ( m_attrProvider
)
922 attr
->SetKind(wxGridCellAttr::Row
);
923 m_attrProvider
->SetRowAttr(attr
, row
);
927 // as we take ownership of the pointer and don't store it, we must
933 void wxGridTableBase::SetColAttr(wxGridCellAttr
*attr
, int col
)
935 if ( m_attrProvider
)
937 attr
->SetKind(wxGridCellAttr::Col
);
938 m_attrProvider
->SetColAttr(attr
, col
);
942 // as we take ownership of the pointer and don't store it, we must
948 bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos
),
949 size_t WXUNUSED(numRows
) )
951 wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
956 bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows
) )
958 wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
963 bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos
),
964 size_t WXUNUSED(numRows
) )
966 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
971 bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos
),
972 size_t WXUNUSED(numCols
) )
974 wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
979 bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols
) )
981 wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
986 bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos
),
987 size_t WXUNUSED(numCols
) )
989 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
994 wxString
wxGridTableBase::GetRowLabelValue( int row
)
998 // RD: Starting the rows at zero confuses users,
999 // no matter how much it makes sense to us geeks.
1005 wxString
wxGridTableBase::GetColLabelValue( int col
)
1007 // default col labels are:
1008 // cols 0 to 25 : A-Z
1009 // cols 26 to 675 : AA-ZZ
1014 for ( n
= 1; ; n
++ )
1016 s
+= (wxChar
) (_T('A') + (wxChar
)(col
% 26));
1022 // reverse the string...
1024 for ( i
= 0; i
< n
; i
++ )
1032 wxString
wxGridTableBase::GetTypeName( int WXUNUSED(row
), int WXUNUSED(col
) )
1034 return wxGRID_VALUE_STRING
;
1037 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row
), int WXUNUSED(col
),
1038 const wxString
& typeName
)
1040 return typeName
== wxGRID_VALUE_STRING
;
1043 bool wxGridTableBase::CanSetValueAs( int row
, int col
, const wxString
& typeName
)
1045 return CanGetValueAs(row
, col
, typeName
);
1048 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
) )
1053 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
) )
1058 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
) )
1063 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
),
1064 long WXUNUSED(value
) )
1068 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
),
1069 double WXUNUSED(value
) )
1073 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
),
1074 bool WXUNUSED(value
) )
1078 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
),
1079 const wxString
& WXUNUSED(typeName
) )
1084 void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
),
1085 const wxString
& WXUNUSED(typeName
),
1086 void* WXUNUSED(value
) )
1090 //////////////////////////////////////////////////////////////////////
1092 // Message class for the grid table to send requests and notifications
1096 wxGridTableMessage::wxGridTableMessage()
1104 wxGridTableMessage::wxGridTableMessage( wxGridTableBase
*table
, int id
,
1105 int commandInt1
, int commandInt2
)
1109 m_comInt1
= commandInt1
;
1110 m_comInt2
= commandInt2
;
1113 //////////////////////////////////////////////////////////////////////
1115 // A basic grid table for string data. An object of this class will
1116 // created by wxGrid if you don't specify an alternative table class.
1119 WX_DEFINE_OBJARRAY(wxGridStringArray
)
1121 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase
)
1123 wxGridStringTable::wxGridStringTable()
1128 wxGridStringTable::wxGridStringTable( int numRows
, int numCols
)
1131 m_data
.Alloc( numRows
);
1134 sa
.Alloc( numCols
);
1135 sa
.Add( wxEmptyString
, numCols
);
1137 m_data
.Add( sa
, numRows
);
1140 wxGridStringTable::~wxGridStringTable()
1144 int wxGridStringTable::GetNumberRows()
1146 return m_data
.GetCount();
1149 int wxGridStringTable::GetNumberCols()
1151 if ( m_data
.GetCount() > 0 )
1152 return m_data
[0].GetCount();
1157 wxString
wxGridStringTable::GetValue( int row
, int col
)
1159 wxCHECK_MSG( (row
< GetNumberRows()) && (col
< GetNumberCols()),
1161 _T("invalid row or column index in wxGridStringTable") );
1163 return m_data
[row
][col
];
1166 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& value
)
1168 wxCHECK_RET( (row
< GetNumberRows()) && (col
< GetNumberCols()),
1169 _T("invalid row or column index in wxGridStringTable") );
1171 m_data
[row
][col
] = value
;
1174 void wxGridStringTable::Clear()
1177 int numRows
, numCols
;
1179 numRows
= m_data
.GetCount();
1182 numCols
= m_data
[0].GetCount();
1184 for ( row
= 0; row
< numRows
; row
++ )
1186 for ( col
= 0; col
< numCols
; col
++ )
1188 m_data
[row
][col
] = wxEmptyString
;
1194 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows
)
1196 size_t curNumRows
= m_data
.GetCount();
1197 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() :
1198 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
1200 if ( pos
>= curNumRows
)
1202 return AppendRows( numRows
);
1206 sa
.Alloc( curNumCols
);
1207 sa
.Add( wxEmptyString
, curNumCols
);
1208 m_data
.Insert( sa
, pos
, numRows
);
1212 wxGridTableMessage
msg( this,
1213 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
,
1217 GetView()->ProcessTableMessage( msg
);
1223 bool wxGridStringTable::AppendRows( size_t numRows
)
1225 size_t curNumRows
= m_data
.GetCount();
1226 size_t curNumCols
= ( curNumRows
> 0
1227 ? m_data
[0].GetCount()
1228 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
1231 if ( curNumCols
> 0 )
1233 sa
.Alloc( curNumCols
);
1234 sa
.Add( wxEmptyString
, curNumCols
);
1237 m_data
.Add( sa
, numRows
);
1241 wxGridTableMessage
msg( this,
1242 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
,
1245 GetView()->ProcessTableMessage( msg
);
1251 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows
)
1253 size_t curNumRows
= m_data
.GetCount();
1255 if ( pos
>= curNumRows
)
1257 wxFAIL_MSG( wxString::Format
1259 wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
1261 (unsigned long)numRows
,
1262 (unsigned long)curNumRows
1268 if ( numRows
> curNumRows
- pos
)
1270 numRows
= curNumRows
- pos
;
1273 if ( numRows
>= curNumRows
)
1279 m_data
.RemoveAt( pos
, numRows
);
1284 wxGridTableMessage
msg( this,
1285 wxGRIDTABLE_NOTIFY_ROWS_DELETED
,
1289 GetView()->ProcessTableMessage( msg
);
1295 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols
)
1299 size_t curNumRows
= m_data
.GetCount();
1300 size_t curNumCols
= ( curNumRows
> 0
1301 ? m_data
[0].GetCount()
1302 : ( GetView() ? GetView()->GetNumberCols() : 0 ) );
1304 if ( pos
>= curNumCols
)
1306 return AppendCols( numCols
);
1309 if ( !m_colLabels
.IsEmpty() )
1311 m_colLabels
.Insert( wxEmptyString
, pos
, numCols
);
1314 for ( i
= pos
; i
< pos
+ numCols
; i
++ )
1315 m_colLabels
[i
] = wxGridTableBase::GetColLabelValue( i
);
1318 for ( row
= 0; row
< curNumRows
; row
++ )
1320 for ( col
= pos
; col
< pos
+ numCols
; col
++ )
1322 m_data
[row
].Insert( wxEmptyString
, col
);
1328 wxGridTableMessage
msg( this,
1329 wxGRIDTABLE_NOTIFY_COLS_INSERTED
,
1333 GetView()->ProcessTableMessage( msg
);
1339 bool wxGridStringTable::AppendCols( size_t numCols
)
1343 size_t curNumRows
= m_data
.GetCount();
1345 for ( row
= 0; row
< curNumRows
; row
++ )
1347 m_data
[row
].Add( wxEmptyString
, numCols
);
1352 wxGridTableMessage
msg( this,
1353 wxGRIDTABLE_NOTIFY_COLS_APPENDED
,
1356 GetView()->ProcessTableMessage( msg
);
1362 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols
)
1366 size_t curNumRows
= m_data
.GetCount();
1367 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() :
1368 ( GetView() ? GetView()->GetNumberCols() : 0 ) );
1370 if ( pos
>= curNumCols
)
1372 wxFAIL_MSG( wxString::Format
1374 wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
1376 (unsigned long)numCols
,
1377 (unsigned long)curNumCols
1384 colID
= GetView()->GetColAt( pos
);
1388 if ( numCols
> curNumCols
- colID
)
1390 numCols
= curNumCols
- colID
;
1393 if ( !m_colLabels
.IsEmpty() )
1395 // m_colLabels stores just as many elements as it needs, e.g. if only
1396 // the label of the first column had been set it would have only one
1397 // element and not numCols, so account for it
1398 int nToRm
= m_colLabels
.size() - colID
;
1400 m_colLabels
.RemoveAt( colID
, nToRm
);
1403 for ( row
= 0; row
< curNumRows
; row
++ )
1405 if ( numCols
>= curNumCols
)
1407 m_data
[row
].Clear();
1411 m_data
[row
].RemoveAt( colID
, numCols
);
1417 wxGridTableMessage
msg( this,
1418 wxGRIDTABLE_NOTIFY_COLS_DELETED
,
1422 GetView()->ProcessTableMessage( msg
);
1428 wxString
wxGridStringTable::GetRowLabelValue( int row
)
1430 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
1432 // using default label
1434 return wxGridTableBase::GetRowLabelValue( row
);
1438 return m_rowLabels
[row
];
1442 wxString
wxGridStringTable::GetColLabelValue( int col
)
1444 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
1446 // using default label
1448 return wxGridTableBase::GetColLabelValue( col
);
1452 return m_colLabels
[col
];
1456 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value
)
1458 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
1460 int n
= m_rowLabels
.GetCount();
1463 for ( i
= n
; i
<= row
; i
++ )
1465 m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) );
1469 m_rowLabels
[row
] = value
;
1472 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value
)
1474 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
1476 int n
= m_colLabels
.GetCount();
1479 for ( i
= n
; i
<= col
; i
++ )
1481 m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) );
1485 m_colLabels
[col
] = value
;
1489 //////////////////////////////////////////////////////////////////////
1490 //////////////////////////////////////////////////////////////////////
1492 BEGIN_EVENT_TABLE(wxGridSubwindow
, wxWindow
)
1493 EVT_MOUSE_CAPTURE_LOST(wxGridSubwindow::OnMouseCaptureLost
)
1496 void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
))
1498 m_owner
->CancelMouseCapture();
1501 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxGridSubwindow
)
1502 EVT_PAINT( wxGridRowLabelWindow::OnPaint
)
1503 EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel
)
1504 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent
)
1507 void wxGridRowLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1511 // NO - don't do this because it will set both the x and y origin
1512 // coords to match the parent scrolled window and we just want to
1513 // set the y coord - MB
1515 // m_owner->PrepareDC( dc );
1518 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
1519 wxPoint pt
= dc
.GetDeviceOrigin();
1520 dc
.SetDeviceOrigin( pt
.x
, pt
.y
-y
);
1522 wxArrayInt rows
= m_owner
->CalcRowLabelsExposed( GetUpdateRegion() );
1523 m_owner
->DrawRowLabels( dc
, rows
);
1526 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
1528 m_owner
->ProcessRowLabelMouseEvent( event
);
1531 void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent
& event
)
1533 if (!m_owner
->GetEventHandler()->ProcessEvent( event
))
1537 //////////////////////////////////////////////////////////////////////
1539 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxGridSubwindow
)
1540 EVT_PAINT( wxGridColLabelWindow::OnPaint
)
1541 EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel
)
1542 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent
)
1545 void wxGridColLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1549 // NO - don't do this because it will set both the x and y origin
1550 // coords to match the parent scrolled window and we just want to
1551 // set the x coord - MB
1553 // m_owner->PrepareDC( dc );
1556 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
1557 wxPoint pt
= dc
.GetDeviceOrigin();
1558 if (GetLayoutDirection() == wxLayout_RightToLeft
)
1559 dc
.SetDeviceOrigin( pt
.x
+x
, pt
.y
);
1561 dc
.SetDeviceOrigin( pt
.x
-x
, pt
.y
);
1563 wxArrayInt cols
= m_owner
->CalcColLabelsExposed( GetUpdateRegion() );
1564 m_owner
->DrawColLabels( dc
, cols
);
1567 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
1569 m_owner
->ProcessColLabelMouseEvent( event
);
1572 void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent
& event
)
1574 if (!m_owner
->GetEventHandler()->ProcessEvent( event
))
1578 //////////////////////////////////////////////////////////////////////
1580 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxGridSubwindow
)
1581 EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel
)
1582 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent
)
1583 EVT_PAINT( wxGridCornerLabelWindow::OnPaint
)
1586 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1590 m_owner
->DrawCornerLabel(dc
);
1593 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
1595 m_owner
->ProcessCornerLabelMouseEvent( event
);
1598 void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent
& event
)
1600 if (!m_owner
->GetEventHandler()->ProcessEvent(event
))
1604 //////////////////////////////////////////////////////////////////////
1606 BEGIN_EVENT_TABLE( wxGridWindow
, wxGridSubwindow
)
1607 EVT_PAINT( wxGridWindow::OnPaint
)
1608 EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel
)
1609 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent
)
1610 EVT_KEY_DOWN( wxGridWindow::OnKeyDown
)
1611 EVT_KEY_UP( wxGridWindow::OnKeyUp
)
1612 EVT_CHAR( wxGridWindow::OnChar
)
1613 EVT_SET_FOCUS( wxGridWindow::OnFocus
)
1614 EVT_KILL_FOCUS( wxGridWindow::OnFocus
)
1615 EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground
)
1618 void wxGridWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1620 wxPaintDC
dc( this );
1621 m_owner
->PrepareDC( dc
);
1622 wxRegion reg
= GetUpdateRegion();
1623 wxGridCellCoordsArray dirtyCells
= m_owner
->CalcCellsExposed( reg
);
1624 m_owner
->DrawGridCellArea( dc
, dirtyCells
);
1626 m_owner
->DrawGridSpace( dc
);
1628 m_owner
->DrawAllGridLines( dc
, reg
);
1630 m_owner
->DrawHighlight( dc
, dirtyCells
);
1633 void wxGridWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
1635 wxWindow::ScrollWindow( dx
, dy
, rect
);
1636 m_owner
->GetGridRowLabelWindow()->ScrollWindow( 0, dy
, rect
);
1637 m_owner
->GetGridColLabelWindow()->ScrollWindow( dx
, 0, rect
);
1640 void wxGridWindow::OnMouseEvent( wxMouseEvent
& event
)
1642 if (event
.ButtonDown(wxMOUSE_BTN_LEFT
) && FindFocus() != this)
1645 m_owner
->ProcessGridCellMouseEvent( event
);
1648 void wxGridWindow::OnMouseWheel( wxMouseEvent
& event
)
1650 if (!m_owner
->GetEventHandler()->ProcessEvent( event
))
1654 // This seems to be required for wxMotif/wxGTK otherwise the mouse
1655 // cursor must be in the cell edit control to get key events
1657 void wxGridWindow::OnKeyDown( wxKeyEvent
& event
)
1659 if ( !m_owner
->GetEventHandler()->ProcessEvent( event
) )
1663 void wxGridWindow::OnKeyUp( wxKeyEvent
& event
)
1665 if ( !m_owner
->GetEventHandler()->ProcessEvent( event
) )
1669 void wxGridWindow::OnChar( wxKeyEvent
& event
)
1671 if ( !m_owner
->GetEventHandler()->ProcessEvent( event
) )
1675 void wxGridWindow::OnEraseBackground( wxEraseEvent
& WXUNUSED(event
) )
1679 void wxGridWindow::OnFocus(wxFocusEvent
& event
)
1681 // and if we have any selection, it has to be repainted, because it
1682 // uses different colour when the grid is not focused:
1683 if ( m_owner
->IsSelection() )
1689 // NB: Note that this code is in "else" branch only because the other
1690 // branch refreshes everything and so there's no point in calling
1691 // Refresh() again, *not* because it should only be done if
1692 // !IsSelection(). If the above code is ever optimized to refresh
1693 // only selected area, this needs to be moved out of the "else"
1694 // branch so that it's always executed.
1696 // current cell cursor {dis,re}appears on focus change:
1697 const wxGridCellCoords
cursorCoords(m_owner
->GetGridCursorRow(),
1698 m_owner
->GetGridCursorCol());
1699 const wxRect cursor
=
1700 m_owner
->BlockToDeviceRect(cursorCoords
, cursorCoords
);
1701 Refresh(true, &cursor
);
1704 if ( !m_owner
->GetEventHandler()->ProcessEvent( event
) )
1708 #define internalXToCol(x) XToCol(x, true)
1709 #define internalYToRow(y) YToRow(y, true)
1711 /////////////////////////////////////////////////////////////////////
1713 #if wxUSE_EXTENDED_RTTI
1714 WX_DEFINE_FLAGS( wxGridStyle
)
1716 wxBEGIN_FLAGS( wxGridStyle
)
1717 // new style border flags, we put them first to
1718 // use them for streaming out
1719 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
1720 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
1721 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
1722 wxFLAGS_MEMBER(wxBORDER_RAISED
)
1723 wxFLAGS_MEMBER(wxBORDER_STATIC
)
1724 wxFLAGS_MEMBER(wxBORDER_NONE
)
1726 // old style border flags
1727 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
1728 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
1729 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
1730 wxFLAGS_MEMBER(wxRAISED_BORDER
)
1731 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
1732 wxFLAGS_MEMBER(wxBORDER
)
1734 // standard window styles
1735 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
1736 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
1737 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
1738 wxFLAGS_MEMBER(wxWANTS_CHARS
)
1739 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
1740 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
1741 wxFLAGS_MEMBER(wxVSCROLL
)
1742 wxFLAGS_MEMBER(wxHSCROLL
)
1744 wxEND_FLAGS( wxGridStyle
)
1746 IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid
, wxScrolledWindow
,"wx/grid.h")
1748 wxBEGIN_PROPERTIES_TABLE(wxGrid
)
1749 wxHIDE_PROPERTY( Children
)
1750 wxPROPERTY_FLAGS( WindowStyle
, wxGridStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
1751 wxEND_PROPERTIES_TABLE()
1753 wxBEGIN_HANDLERS_TABLE(wxGrid
)
1754 wxEND_HANDLERS_TABLE()
1756 wxCONSTRUCTOR_5( wxGrid
, wxWindow
* , Parent
, wxWindowID
, Id
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
1759 TODO : Expose more information of a list's layout, etc. via appropriate objects (e.g., NotebookPageInfo)
1762 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow
)
1765 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow
)
1766 EVT_PAINT( wxGrid::OnPaint
)
1767 EVT_SIZE( wxGrid::OnSize
)
1768 EVT_KEY_DOWN( wxGrid::OnKeyDown
)
1769 EVT_KEY_UP( wxGrid::OnKeyUp
)
1770 EVT_CHAR ( wxGrid::OnChar
)
1771 EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground
)
1774 bool wxGrid::Create(wxWindow
*parent
, wxWindowID id
,
1775 const wxPoint
& pos
, const wxSize
& size
,
1776 long style
, const wxString
& name
)
1778 if (!wxScrolledWindow::Create(parent
, id
, pos
, size
,
1779 style
| wxWANTS_CHARS
, name
))
1782 m_colMinWidths
= wxLongToLongHashMap(GRID_HASH_SIZE
);
1783 m_rowMinHeights
= wxLongToLongHashMap(GRID_HASH_SIZE
);
1786 SetInitialSize(size
);
1787 SetScrollRate(m_scrollLineX
, m_scrollLineY
);
1796 m_winCapture
->ReleaseMouse();
1798 // Ensure that the editor control is destroyed before the grid is,
1799 // otherwise we crash later when the editor tries to do something with the
1800 // half destroyed grid
1801 HideCellEditControl();
1803 // Must do this or ~wxScrollHelper will pop the wrong event handler
1804 SetTargetWindow(this);
1806 wxSafeDecRef(m_defaultCellAttr
);
1808 #ifdef DEBUG_ATTR_CACHE
1809 size_t total
= gs_nAttrCacheHits
+ gs_nAttrCacheMisses
;
1810 wxPrintf(_T("wxGrid attribute cache statistics: "
1811 "total: %u, hits: %u (%u%%)\n"),
1812 total
, gs_nAttrCacheHits
,
1813 total
? (gs_nAttrCacheHits
*100) / total
: 0);
1816 // if we own the table, just delete it, otherwise at least don't leave it
1817 // with dangling view pointer
1820 else if ( m_table
&& m_table
->GetView() == this )
1821 m_table
->SetView(NULL
);
1823 delete m_typeRegistry
;
1828 // ----- internal init and update functions
1831 // NOTE: If using the default visual attributes works everywhere then this can
1832 // be removed as well as the #else cases below.
1833 #define _USE_VISATTR 0
1835 void wxGrid::Create()
1837 // create the type registry
1838 m_typeRegistry
= new wxGridTypeRegistry
;
1840 m_cellEditCtrlEnabled
= false;
1842 m_defaultCellAttr
= new wxGridCellAttr();
1844 // Set default cell attributes
1845 m_defaultCellAttr
->SetDefAttr(m_defaultCellAttr
);
1846 m_defaultCellAttr
->SetKind(wxGridCellAttr::Default
);
1847 m_defaultCellAttr
->SetFont(GetFont());
1848 m_defaultCellAttr
->SetAlignment(wxALIGN_LEFT
, wxALIGN_TOP
);
1849 m_defaultCellAttr
->SetRenderer(new wxGridCellStringRenderer
);
1850 m_defaultCellAttr
->SetEditor(new wxGridCellTextEditor
);
1853 wxVisualAttributes gva
= wxListBox::GetClassDefaultAttributes();
1854 wxVisualAttributes lva
= wxPanel::GetClassDefaultAttributes();
1856 m_defaultCellAttr
->SetTextColour(gva
.colFg
);
1857 m_defaultCellAttr
->SetBackgroundColour(gva
.colBg
);
1860 m_defaultCellAttr
->SetTextColour(
1861 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
));
1862 m_defaultCellAttr
->SetBackgroundColour(
1863 wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
1868 m_currentCellCoords
= wxGridNoCellCoords
;
1870 // subwindow components that make up the wxGrid
1871 m_rowLabelWin
= new wxGridRowLabelWindow(this);
1872 CreateColumnWindow();
1873 m_cornerLabelWin
= new wxGridCornerLabelWindow(this);
1874 m_gridWin
= new wxGridWindow( this );
1876 SetTargetWindow( m_gridWin
);
1879 wxColour gfg
= gva
.colFg
;
1880 wxColour gbg
= gva
.colBg
;
1881 wxColour lfg
= lva
.colFg
;
1882 wxColour lbg
= lva
.colBg
;
1884 wxColour gfg
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT
);
1885 wxColour gbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW
);
1886 wxColour lfg
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT
);
1887 wxColour lbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
1890 m_cornerLabelWin
->SetOwnForegroundColour(lfg
);
1891 m_cornerLabelWin
->SetOwnBackgroundColour(lbg
);
1892 m_rowLabelWin
->SetOwnForegroundColour(lfg
);
1893 m_rowLabelWin
->SetOwnBackgroundColour(lbg
);
1894 m_colWindow
->SetOwnForegroundColour(lfg
);
1895 m_colWindow
->SetOwnBackgroundColour(lbg
);
1897 m_gridWin
->SetOwnForegroundColour(gfg
);
1898 m_gridWin
->SetOwnBackgroundColour(gbg
);
1900 m_labelBackgroundColour
= m_rowLabelWin
->GetBackgroundColour();
1901 m_labelTextColour
= m_rowLabelWin
->GetForegroundColour();
1903 // now that we have the grid window, use its font to compute the default
1905 m_defaultRowHeight
= m_gridWin
->GetCharHeight();
1906 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1907 m_defaultRowHeight
+= 8;
1909 m_defaultRowHeight
+= 4;
1914 void wxGrid::CreateColumnWindow()
1916 if ( m_useNativeHeader
)
1918 m_colWindow
= new wxGridHeaderCtrl(this);
1919 m_colLabelHeight
= m_colWindow
->GetBestSize().y
;
1921 else // draw labels ourselves
1923 m_colWindow
= new wxGridColLabelWindow(this);
1924 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
1928 bool wxGrid::CreateGrid( int numRows
, int numCols
,
1929 wxGridSelectionModes selmode
)
1931 wxCHECK_MSG( !m_created
,
1933 wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
1935 return SetTable(new wxGridStringTable(numRows
, numCols
), true, selmode
);
1938 void wxGrid::SetSelectionMode(wxGridSelectionModes selmode
)
1940 wxCHECK_RET( m_created
,
1941 wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") );
1943 m_selection
->SetSelectionMode( selmode
);
1946 wxGrid::wxGridSelectionModes
wxGrid::GetSelectionMode() const
1948 wxCHECK_MSG( m_created
, wxGridSelectCells
,
1949 wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") );
1951 return m_selection
->GetSelectionMode();
1955 wxGrid::SetTable(wxGridTableBase
*table
,
1957 wxGrid::wxGridSelectionModes selmode
)
1959 bool checkSelection
= false;
1962 // stop all processing
1967 m_table
->SetView(0);
1979 checkSelection
= true;
1981 // kill row and column size arrays
1982 m_colWidths
.Empty();
1983 m_colRights
.Empty();
1984 m_rowHeights
.Empty();
1985 m_rowBottoms
.Empty();
1990 m_numRows
= table
->GetNumberRows();
1991 m_numCols
= table
->GetNumberCols();
1993 if ( m_useNativeHeader
)
1994 GetGridColHeader()->SetColumnCount(m_numCols
);
1997 m_table
->SetView( this );
1998 m_ownTable
= takeOwnership
;
1999 m_selection
= new wxGridSelection( this, selmode
);
2002 // If the newly set table is smaller than the
2003 // original one current cell and selection regions
2004 // might be invalid,
2005 m_selectedBlockCorner
= wxGridNoCellCoords
;
2006 m_currentCellCoords
=
2007 wxGridCellCoords(wxMin(m_numRows
, m_currentCellCoords
.GetRow()),
2008 wxMin(m_numCols
, m_currentCellCoords
.GetCol()));
2009 if (m_selectedBlockTopLeft
.GetRow() >= m_numRows
||
2010 m_selectedBlockTopLeft
.GetCol() >= m_numCols
)
2012 m_selectedBlockTopLeft
= wxGridNoCellCoords
;
2013 m_selectedBlockBottomRight
= wxGridNoCellCoords
;
2016 m_selectedBlockBottomRight
=
2017 wxGridCellCoords(wxMin(m_numRows
,
2018 m_selectedBlockBottomRight
.GetRow()),
2020 m_selectedBlockBottomRight
.GetCol()));
2034 m_cornerLabelWin
= NULL
;
2035 m_rowLabelWin
= NULL
;
2043 m_defaultCellAttr
= NULL
;
2044 m_typeRegistry
= NULL
;
2045 m_winCapture
= NULL
;
2047 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
2048 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
2051 m_attrCache
.row
= -1;
2052 m_attrCache
.col
= -1;
2053 m_attrCache
.attr
= NULL
;
2055 m_labelFont
= GetFont();
2056 m_labelFont
.SetWeight( wxBOLD
);
2058 m_rowLabelHorizAlign
= wxALIGN_CENTRE
;
2059 m_rowLabelVertAlign
= wxALIGN_CENTRE
;
2061 m_colLabelHorizAlign
= wxALIGN_CENTRE
;
2062 m_colLabelVertAlign
= wxALIGN_CENTRE
;
2063 m_colLabelTextOrientation
= wxHORIZONTAL
;
2065 m_defaultColWidth
= WXGRID_DEFAULT_COL_WIDTH
;
2066 m_defaultRowHeight
= 0; // this will be initialized after creation
2068 m_minAcceptableColWidth
= WXGRID_MIN_COL_WIDTH
;
2069 m_minAcceptableRowHeight
= WXGRID_MIN_ROW_HEIGHT
;
2071 m_gridLineColour
= wxColour( 192,192,192 );
2072 m_gridLinesEnabled
= true;
2073 m_gridLinesClipHorz
=
2074 m_gridLinesClipVert
= true;
2075 m_cellHighlightColour
= *wxBLACK
;
2076 m_cellHighlightPenWidth
= 2;
2077 m_cellHighlightROPenWidth
= 1;
2079 m_canDragColMove
= false;
2081 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
2082 m_winCapture
= NULL
;
2083 m_canDragRowSize
= true;
2084 m_canDragColSize
= true;
2085 m_canDragGridSize
= true;
2086 m_canDragCell
= false;
2088 m_dragRowOrCol
= -1;
2089 m_isDragging
= false;
2090 m_startDragPos
= wxDefaultPosition
;
2092 m_sortCol
= wxNOT_FOUND
;
2093 m_sortIsAscending
= true;
2096 m_nativeColumnLabels
= false;
2098 m_waitForSlowClick
= false;
2100 m_rowResizeCursor
= wxCursor( wxCURSOR_SIZENS
);
2101 m_colResizeCursor
= wxCursor( wxCURSOR_SIZEWE
);
2103 m_currentCellCoords
= wxGridNoCellCoords
;
2105 m_selectedBlockTopLeft
=
2106 m_selectedBlockBottomRight
=
2107 m_selectedBlockCorner
= wxGridNoCellCoords
;
2109 m_selectionBackground
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
2110 m_selectionForeground
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
2112 m_editable
= true; // default for whole grid
2114 m_inOnKeyDown
= false;
2120 m_scrollLineX
= GRID_SCROLL_LINE_X
;
2121 m_scrollLineY
= GRID_SCROLL_LINE_Y
;
2124 // ----------------------------------------------------------------------------
2125 // the idea is to call these functions only when necessary because they create
2126 // quite big arrays which eat memory mostly unnecessary - in particular, if
2127 // default widths/heights are used for all rows/columns, we may not use these
2130 // with some extra code, it should be possible to only store the widths/heights
2131 // different from default ones (resulting in space savings for huge grids) but
2132 // this is not done currently
2133 // ----------------------------------------------------------------------------
2135 void wxGrid::InitRowHeights()
2137 m_rowHeights
.Empty();
2138 m_rowBottoms
.Empty();
2140 m_rowHeights
.Alloc( m_numRows
);
2141 m_rowBottoms
.Alloc( m_numRows
);
2143 m_rowHeights
.Add( m_defaultRowHeight
, m_numRows
);
2146 for ( int i
= 0; i
< m_numRows
; i
++ )
2148 rowBottom
+= m_defaultRowHeight
;
2149 m_rowBottoms
.Add( rowBottom
);
2153 void wxGrid::InitColWidths()
2155 m_colWidths
.Empty();
2156 m_colRights
.Empty();
2158 m_colWidths
.Alloc( m_numCols
);
2159 m_colRights
.Alloc( m_numCols
);
2161 m_colWidths
.Add( m_defaultColWidth
, m_numCols
);
2163 for ( int i
= 0; i
< m_numCols
; i
++ )
2165 int colRight
= ( GetColPos( i
) + 1 ) * m_defaultColWidth
;
2166 m_colRights
.Add( colRight
);
2170 int wxGrid::GetColWidth(int col
) const
2172 return m_colWidths
.IsEmpty() ? m_defaultColWidth
: m_colWidths
[col
];
2175 int wxGrid::GetColLeft(int col
) const
2177 return m_colRights
.IsEmpty() ? GetColPos( col
) * m_defaultColWidth
2178 : m_colRights
[col
] - m_colWidths
[col
];
2181 int wxGrid::GetColRight(int col
) const
2183 return m_colRights
.IsEmpty() ? (GetColPos( col
) + 1) * m_defaultColWidth
2187 int wxGrid::GetRowHeight(int row
) const
2189 return m_rowHeights
.IsEmpty() ? m_defaultRowHeight
: m_rowHeights
[row
];
2192 int wxGrid::GetRowTop(int row
) const
2194 return m_rowBottoms
.IsEmpty() ? row
* m_defaultRowHeight
2195 : m_rowBottoms
[row
] - m_rowHeights
[row
];
2198 int wxGrid::GetRowBottom(int row
) const
2200 return m_rowBottoms
.IsEmpty() ? (row
+ 1) * m_defaultRowHeight
2201 : m_rowBottoms
[row
];
2204 void wxGrid::CalcDimensions()
2206 // compute the size of the scrollable area
2207 int w
= m_numCols
> 0 ? GetColRight(GetColAt(m_numCols
- 1)) : 0;
2208 int h
= m_numRows
> 0 ? GetRowBottom(m_numRows
- 1) : 0;
2213 // take into account editor if shown
2214 if ( IsCellEditControlShown() )
2217 int r
= m_currentCellCoords
.GetRow();
2218 int c
= m_currentCellCoords
.GetCol();
2219 int x
= GetColLeft(c
);
2220 int y
= GetRowTop(r
);
2222 // how big is the editor
2223 wxGridCellAttr
* attr
= GetCellAttr(r
, c
);
2224 wxGridCellEditor
* editor
= attr
->GetEditor(this, r
, c
);
2225 editor
->GetControl()->GetSize(&w2
, &h2
);
2236 // preserve (more or less) the previous position
2238 GetViewStart( &x
, &y
);
2240 // ensure the position is valid for the new scroll ranges
2242 x
= wxMax( w
- 1, 0 );
2244 y
= wxMax( h
- 1, 0 );
2246 // update the virtual size and refresh the scrollbars to reflect it
2247 m_gridWin
->SetVirtualSize(w
, h
);
2251 // if our OnSize() hadn't been called (it would if we have scrollbars), we
2252 // still must reposition the children
2256 wxSize
wxGrid::GetSizeAvailableForScrollTarget(const wxSize
& size
)
2258 wxSize
sizeGridWin(size
);
2259 sizeGridWin
.x
-= m_rowLabelWidth
;
2260 sizeGridWin
.y
-= m_colLabelHeight
;
2265 void wxGrid::CalcWindowSizes()
2267 // escape if the window is has not been fully created yet
2269 if ( m_cornerLabelWin
== NULL
)
2273 GetClientSize( &cw
, &ch
);
2275 // the grid may be too small to have enough space for the labels yet, don't
2276 // size the windows to negative sizes in this case
2277 int gw
= cw
- m_rowLabelWidth
;
2278 int gh
= ch
- m_colLabelHeight
;
2284 if ( m_cornerLabelWin
&& m_cornerLabelWin
->IsShown() )
2285 m_cornerLabelWin
->SetSize( 0, 0, m_rowLabelWidth
, m_colLabelHeight
);
2287 if ( m_colWindow
&& m_colWindow
->IsShown() )
2288 m_colWindow
->SetSize( m_rowLabelWidth
, 0, gw
, m_colLabelHeight
);
2290 if ( m_rowLabelWin
&& m_rowLabelWin
->IsShown() )
2291 m_rowLabelWin
->SetSize( 0, m_colLabelHeight
, m_rowLabelWidth
, gh
);
2293 if ( m_gridWin
&& m_gridWin
->IsShown() )
2294 m_gridWin
->SetSize( m_rowLabelWidth
, m_colLabelHeight
, gw
, gh
);
2297 // this is called when the grid table sends a message
2298 // to indicate that it has been redimensioned
2300 bool wxGrid::Redimension( wxGridTableMessage
& msg
)
2303 bool result
= false;
2305 // Clear the attribute cache as the attribute might refer to a different
2306 // cell than stored in the cache after adding/removing rows/columns.
2309 // By the same reasoning, the editor should be dismissed if columns are
2310 // added or removed. And for consistency, it should IMHO always be
2311 // removed, not only if the cell "underneath" it actually changes.
2312 // For now, I intentionally do not save the editor's content as the
2313 // cell it might want to save that stuff to might no longer exist.
2314 HideCellEditControl();
2316 switch ( msg
.GetId() )
2318 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
2320 size_t pos
= msg
.GetCommandInt();
2321 int numRows
= msg
.GetCommandInt2();
2323 m_numRows
+= numRows
;
2325 if ( !m_rowHeights
.IsEmpty() )
2327 m_rowHeights
.Insert( m_defaultRowHeight
, pos
, numRows
);
2328 m_rowBottoms
.Insert( 0, pos
, numRows
);
2332 bottom
= m_rowBottoms
[pos
- 1];
2334 for ( i
= pos
; i
< m_numRows
; i
++ )
2336 bottom
+= m_rowHeights
[i
];
2337 m_rowBottoms
[i
] = bottom
;
2341 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2343 // if we have just inserted cols into an empty grid the current
2344 // cell will be undefined...
2346 SetCurrentCell( 0, 0 );
2350 m_selection
->UpdateRows( pos
, numRows
);
2351 wxGridCellAttrProvider
* attrProvider
= m_table
->GetAttrProvider();
2353 attrProvider
->UpdateAttrRows( pos
, numRows
);
2355 if ( !GetBatchCount() )
2358 m_rowLabelWin
->Refresh();
2364 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
2366 int numRows
= msg
.GetCommandInt();
2367 int oldNumRows
= m_numRows
;
2368 m_numRows
+= numRows
;
2370 if ( !m_rowHeights
.IsEmpty() )
2372 m_rowHeights
.Add( m_defaultRowHeight
, numRows
);
2373 m_rowBottoms
.Add( 0, numRows
);
2376 if ( oldNumRows
> 0 )
2377 bottom
= m_rowBottoms
[oldNumRows
- 1];
2379 for ( i
= oldNumRows
; i
< m_numRows
; i
++ )
2381 bottom
+= m_rowHeights
[i
];
2382 m_rowBottoms
[i
] = bottom
;
2386 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2388 // if we have just inserted cols into an empty grid the current
2389 // cell will be undefined...
2391 SetCurrentCell( 0, 0 );
2394 if ( !GetBatchCount() )
2397 m_rowLabelWin
->Refresh();
2403 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
2405 size_t pos
= msg
.GetCommandInt();
2406 int numRows
= msg
.GetCommandInt2();
2407 m_numRows
-= numRows
;
2409 if ( !m_rowHeights
.IsEmpty() )
2411 m_rowHeights
.RemoveAt( pos
, numRows
);
2412 m_rowBottoms
.RemoveAt( pos
, numRows
);
2415 for ( i
= 0; i
< m_numRows
; i
++ )
2417 h
+= m_rowHeights
[i
];
2418 m_rowBottoms
[i
] = h
;
2424 m_currentCellCoords
= wxGridNoCellCoords
;
2428 if ( m_currentCellCoords
.GetRow() >= m_numRows
)
2429 m_currentCellCoords
.Set( 0, 0 );
2433 m_selection
->UpdateRows( pos
, -((int)numRows
) );
2434 wxGridCellAttrProvider
* attrProvider
= m_table
->GetAttrProvider();
2437 attrProvider
->UpdateAttrRows( pos
, -((int)numRows
) );
2439 // ifdef'd out following patch from Paul Gammans
2441 // No need to touch column attributes, unless we
2442 // removed _all_ rows, in this case, we remove
2443 // all column attributes.
2444 // I hate to do this here, but the
2445 // needed data is not available inside UpdateAttrRows.
2446 if ( !GetNumberRows() )
2447 attrProvider
->UpdateAttrCols( 0, -GetNumberCols() );
2451 if ( !GetBatchCount() )
2454 m_rowLabelWin
->Refresh();
2460 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
2462 size_t pos
= msg
.GetCommandInt();
2463 int numCols
= msg
.GetCommandInt2();
2464 m_numCols
+= numCols
;
2466 if ( m_useNativeHeader
)
2467 GetGridColHeader()->SetColumnCount(m_numCols
);
2469 if ( !m_colAt
.IsEmpty() )
2471 //Shift the column IDs
2473 for ( i
= 0; i
< m_numCols
- numCols
; i
++ )
2475 if ( m_colAt
[i
] >= (int)pos
)
2476 m_colAt
[i
] += numCols
;
2479 m_colAt
.Insert( pos
, pos
, numCols
);
2481 //Set the new columns' positions
2482 for ( i
= pos
+ 1; i
< (int)pos
+ numCols
; i
++ )
2488 if ( !m_colWidths
.IsEmpty() )
2490 m_colWidths
.Insert( m_defaultColWidth
, pos
, numCols
);
2491 m_colRights
.Insert( 0, pos
, numCols
);
2495 right
= m_colRights
[GetColAt( pos
- 1 )];
2498 for ( colPos
= pos
; colPos
< m_numCols
; colPos
++ )
2500 i
= GetColAt( colPos
);
2502 right
+= m_colWidths
[i
];
2503 m_colRights
[i
] = right
;
2507 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2509 // if we have just inserted cols into an empty grid the current
2510 // cell will be undefined...
2512 SetCurrentCell( 0, 0 );
2516 m_selection
->UpdateCols( pos
, numCols
);
2517 wxGridCellAttrProvider
* attrProvider
= m_table
->GetAttrProvider();
2519 attrProvider
->UpdateAttrCols( pos
, numCols
);
2520 if ( !GetBatchCount() )
2523 m_colWindow
->Refresh();
2529 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
2531 int numCols
= msg
.GetCommandInt();
2532 int oldNumCols
= m_numCols
;
2533 m_numCols
+= numCols
;
2534 if ( m_useNativeHeader
)
2535 GetGridColHeader()->SetColumnCount(m_numCols
);
2537 if ( !m_colAt
.IsEmpty() )
2539 m_colAt
.Add( 0, numCols
);
2541 //Set the new columns' positions
2543 for ( i
= oldNumCols
; i
< m_numCols
; i
++ )
2549 if ( !m_colWidths
.IsEmpty() )
2551 m_colWidths
.Add( m_defaultColWidth
, numCols
);
2552 m_colRights
.Add( 0, numCols
);
2555 if ( oldNumCols
> 0 )
2556 right
= m_colRights
[GetColAt( oldNumCols
- 1 )];
2559 for ( colPos
= oldNumCols
; colPos
< m_numCols
; colPos
++ )
2561 i
= GetColAt( colPos
);
2563 right
+= m_colWidths
[i
];
2564 m_colRights
[i
] = right
;
2568 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2570 // if we have just inserted cols into an empty grid the current
2571 // cell will be undefined...
2573 SetCurrentCell( 0, 0 );
2575 if ( !GetBatchCount() )
2578 m_colWindow
->Refresh();
2584 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
2586 size_t pos
= msg
.GetCommandInt();
2587 int numCols
= msg
.GetCommandInt2();
2588 m_numCols
-= numCols
;
2589 if ( m_useNativeHeader
)
2590 GetGridColHeader()->SetColumnCount(m_numCols
);
2592 if ( !m_colAt
.IsEmpty() )
2594 int colID
= GetColAt( pos
);
2596 m_colAt
.RemoveAt( pos
, numCols
);
2598 //Shift the column IDs
2600 for ( colPos
= 0; colPos
< m_numCols
; colPos
++ )
2602 if ( m_colAt
[colPos
] > colID
)
2603 m_colAt
[colPos
] -= numCols
;
2607 if ( !m_colWidths
.IsEmpty() )
2609 m_colWidths
.RemoveAt( pos
, numCols
);
2610 m_colRights
.RemoveAt( pos
, numCols
);
2614 for ( colPos
= 0; colPos
< m_numCols
; colPos
++ )
2616 i
= GetColAt( colPos
);
2618 w
+= m_colWidths
[i
];
2625 m_currentCellCoords
= wxGridNoCellCoords
;
2629 if ( m_currentCellCoords
.GetCol() >= m_numCols
)
2630 m_currentCellCoords
.Set( 0, 0 );
2634 m_selection
->UpdateCols( pos
, -((int)numCols
) );
2635 wxGridCellAttrProvider
* attrProvider
= m_table
->GetAttrProvider();
2638 attrProvider
->UpdateAttrCols( pos
, -((int)numCols
) );
2640 // ifdef'd out following patch from Paul Gammans
2642 // No need to touch row attributes, unless we
2643 // removed _all_ columns, in this case, we remove
2644 // all row attributes.
2645 // I hate to do this here, but the
2646 // needed data is not available inside UpdateAttrCols.
2647 if ( !GetNumberCols() )
2648 attrProvider
->UpdateAttrRows( 0, -GetNumberRows() );
2652 if ( !GetBatchCount() )
2655 m_colWindow
->Refresh();
2662 if (result
&& !GetBatchCount() )
2663 m_gridWin
->Refresh();
2668 wxArrayInt
wxGrid::CalcRowLabelsExposed( const wxRegion
& reg
) const
2670 wxRegionIterator
iter( reg
);
2673 wxArrayInt rowlabels
;
2680 // TODO: remove this when we can...
2681 // There is a bug in wxMotif that gives garbage update
2682 // rectangles if you jump-scroll a long way by clicking the
2683 // scrollbar with middle button. This is a work-around
2685 #if defined(__WXMOTIF__)
2687 m_gridWin
->GetClientSize( &cw
, &ch
);
2688 if ( r
.GetTop() > ch
)
2690 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
2693 // logical bounds of update region
2696 CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top
);
2697 CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom
);
2699 // find the row labels within these bounds
2702 for ( row
= internalYToRow(top
); row
< m_numRows
; row
++ )
2704 if ( GetRowBottom(row
) < top
)
2707 if ( GetRowTop(row
) > bottom
)
2710 rowlabels
.Add( row
);
2719 wxArrayInt
wxGrid::CalcColLabelsExposed( const wxRegion
& reg
) const
2721 wxRegionIterator
iter( reg
);
2724 wxArrayInt colLabels
;
2731 // TODO: remove this when we can...
2732 // There is a bug in wxMotif that gives garbage update
2733 // rectangles if you jump-scroll a long way by clicking the
2734 // scrollbar with middle button. This is a work-around
2736 #if defined(__WXMOTIF__)
2738 m_gridWin
->GetClientSize( &cw
, &ch
);
2739 if ( r
.GetLeft() > cw
)
2741 r
.SetRight( wxMin( r
.GetRight(), cw
) );
2744 // logical bounds of update region
2747 CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy
);
2748 CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy
);
2750 // find the cells within these bounds
2754 for ( colPos
= GetColPos( internalXToCol(left
) ); colPos
< m_numCols
; colPos
++ )
2756 col
= GetColAt( colPos
);
2758 if ( GetColRight(col
) < left
)
2761 if ( GetColLeft(col
) > right
)
2764 colLabels
.Add( col
);
2773 wxGridCellCoordsArray
wxGrid::CalcCellsExposed( const wxRegion
& reg
) const
2775 wxRegionIterator
iter( reg
);
2778 wxGridCellCoordsArray cellsExposed
;
2780 int left
, top
, right
, bottom
;
2785 // TODO: remove this when we can...
2786 // There is a bug in wxMotif that gives garbage update
2787 // rectangles if you jump-scroll a long way by clicking the
2788 // scrollbar with middle button. This is a work-around
2790 #if defined(__WXMOTIF__)
2792 m_gridWin
->GetClientSize( &cw
, &ch
);
2793 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
2794 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
2795 r
.SetRight( wxMin( r
.GetRight(), cw
) );
2796 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
2799 // logical bounds of update region
2801 CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
2802 CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
2804 // find the cells within these bounds
2806 for ( int row
= internalYToRow(top
); row
< m_numRows
; row
++ )
2808 if ( GetRowBottom(row
) <= top
)
2811 if ( GetRowTop(row
) > bottom
)
2814 // add all dirty cells in this row: notice that the columns which
2815 // are dirty don't depend on the row so we compute them only once
2816 // for the first dirty row and then reuse for all the next ones
2819 // do determine the dirty columns
2820 for ( int pos
= XToPos(left
); pos
<= XToPos(right
); pos
++ )
2821 cols
.push_back(GetColAt(pos
));
2823 // if there are no dirty columns at all, nothing to do
2828 const size_t count
= cols
.size();
2829 for ( size_t n
= 0; n
< count
; n
++ )
2830 cellsExposed
.Add(wxGridCellCoords(row
, cols
[n
]));
2836 return cellsExposed
;
2840 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent
& event
)
2843 wxPoint
pos( event
.GetPosition() );
2844 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
2846 if ( event
.Dragging() )
2850 m_isDragging
= true;
2851 m_rowLabelWin
->CaptureMouse();
2854 if ( event
.LeftIsDown() )
2856 switch ( m_cursorMode
)
2858 case WXGRID_CURSOR_RESIZE_ROW
:
2860 int cw
, ch
, left
, dummy
;
2861 m_gridWin
->GetClientSize( &cw
, &ch
);
2862 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
2864 wxClientDC
dc( m_gridWin
);
2867 GetRowTop(m_dragRowOrCol
) +
2868 GetRowMinimalHeight(m_dragRowOrCol
) );
2869 dc
.SetLogicalFunction(wxINVERT
);
2870 if ( m_dragLastPos
>= 0 )
2872 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
2874 dc
.DrawLine( left
, y
, left
+cw
, y
);
2879 case WXGRID_CURSOR_SELECT_ROW
:
2881 if ( (row
= YToRow( y
)) >= 0 )
2884 m_selection
->SelectRow(row
, event
);
2889 // default label to suppress warnings about "enumeration value
2890 // 'xxx' not handled in switch
2898 if ( m_isDragging
&& (event
.Entering() || event
.Leaving()) )
2903 if (m_rowLabelWin
->HasCapture())
2904 m_rowLabelWin
->ReleaseMouse();
2905 m_isDragging
= false;
2908 // ------------ Entering or leaving the window
2910 if ( event
.Entering() || event
.Leaving() )
2912 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
);
2915 // ------------ Left button pressed
2917 else if ( event
.LeftDown() )
2919 // don't send a label click event for a hit on the
2920 // edge of the row label - this is probably the user
2921 // wanting to resize the row
2923 if ( YToEdgeOfRow(y
) < 0 )
2927 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event
) )
2929 if ( !event
.ShiftDown() && !event
.CmdDown() )
2933 if ( event
.ShiftDown() )
2935 m_selection
->SelectBlock
2937 m_currentCellCoords
.GetRow(), 0,
2938 row
, GetNumberCols() - 1,
2944 m_selection
->SelectRow(row
, event
);
2948 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW
, m_rowLabelWin
);
2953 // starting to drag-resize a row
2954 if ( CanDragRowSize() )
2955 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
);
2959 // ------------ Left double click
2961 else if (event
.LeftDClick() )
2963 row
= YToEdgeOfRow(y
);
2968 !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event
) )
2970 // no default action at the moment
2975 // adjust row height depending on label text
2976 AutoSizeRowLabelSize( row
);
2978 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow());
2983 // ------------ Left button released
2985 else if ( event
.LeftUp() )
2987 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
2989 DoEndDragResizeRow();
2991 // Note: we are ending the event *after* doing
2992 // default processing in this case
2994 SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
2997 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
);
3001 // ------------ Right button down
3003 else if ( event
.RightDown() )
3007 !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event
) )
3009 // no default action at the moment
3013 // ------------ Right double click
3015 else if ( event
.RightDClick() )
3019 !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event
) )
3021 // no default action at the moment
3025 // ------------ No buttons down and mouse moving
3027 else if ( event
.Moving() )
3029 m_dragRowOrCol
= YToEdgeOfRow( y
);
3030 if ( m_dragRowOrCol
>= 0 )
3032 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3034 // don't capture the mouse yet
3035 if ( CanDragRowSize() )
3036 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
, false);
3039 else if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
3041 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
, false);
3046 void wxGrid::UpdateColumnSortingIndicator(int col
)
3048 wxCHECK_RET( col
!= wxNOT_FOUND
, "invalid column index" );
3050 if ( m_useNativeHeader
)
3051 GetGridColHeader()->UpdateColumn(col
);
3052 else if ( m_nativeColumnLabels
)
3053 m_colWindow
->Refresh();
3054 //else: sorting indicator display not yet implemented in grid version
3057 void wxGrid::SetSortingColumn(int col
, bool ascending
)
3059 if ( col
== m_sortCol
)
3061 // we are already using this column for sorting (or not sorting at all)
3062 // but we might still change the sorting order, check for it
3063 if ( m_sortCol
!= wxNOT_FOUND
&& ascending
!= m_sortIsAscending
)
3065 m_sortIsAscending
= ascending
;
3067 UpdateColumnSortingIndicator(m_sortCol
);
3070 else // we're changing the column used for sorting
3072 const int sortColOld
= m_sortCol
;
3074 // change it before updating the column as we want GetSortingColumn()
3075 // to return the correct new value
3078 if ( sortColOld
!= wxNOT_FOUND
)
3079 UpdateColumnSortingIndicator(sortColOld
);
3081 if ( m_sortCol
!= wxNOT_FOUND
)
3083 m_sortIsAscending
= ascending
;
3084 UpdateColumnSortingIndicator(m_sortCol
);
3089 void wxGrid::DoColHeaderClick(int col
)
3091 // we consider that the grid was resorted if this event is processed and
3093 if ( SendEvent(wxEVT_GRID_COL_SORT
, -1, col
) == 1 )
3095 SetSortingColumn(col
, IsSortingBy(col
) ? !m_sortIsAscending
: true);
3100 void wxGrid::DoStartResizeCol(int col
)
3102 m_dragRowOrCol
= col
;
3104 DoUpdateResizeColWidth(GetColWidth(m_dragRowOrCol
));
3107 void wxGrid::DoUpdateResizeCol(int x
)
3109 int cw
, ch
, dummy
, top
;
3110 m_gridWin
->GetClientSize( &cw
, &ch
);
3111 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
3113 wxClientDC
dc( m_gridWin
);
3116 x
= wxMax( x
, GetColLeft(m_dragRowOrCol
) + GetColMinimalWidth(m_dragRowOrCol
));
3117 dc
.SetLogicalFunction(wxINVERT
);
3118 if ( m_dragLastPos
>= 0 )
3120 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ ch
);
3122 dc
.DrawLine( x
, top
, x
, top
+ ch
);
3126 void wxGrid::DoUpdateResizeColWidth(int w
)
3128 DoUpdateResizeCol(GetColLeft(m_dragRowOrCol
) + w
);
3131 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event
)
3134 wxPoint
pos( event
.GetPosition() );
3135 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
3137 int col
= XToCol(x
);
3138 if ( event
.Dragging() )
3142 m_isDragging
= true;
3143 GetColLabelWindow()->CaptureMouse();
3145 if ( m_cursorMode
== WXGRID_CURSOR_MOVE_COL
&& col
!= -1 )
3146 DoStartMoveCol(col
);
3149 if ( event
.LeftIsDown() )
3151 switch ( m_cursorMode
)
3153 case WXGRID_CURSOR_RESIZE_COL
:
3154 DoUpdateResizeCol(x
);
3157 case WXGRID_CURSOR_SELECT_COL
:
3162 m_selection
->SelectCol(col
, event
);
3167 case WXGRID_CURSOR_MOVE_COL
:
3169 int posNew
= XToPos(x
);
3170 int colNew
= GetColAt(posNew
);
3172 // determine the position of the drop marker
3174 if ( x
>= GetColLeft(colNew
) + (GetColWidth(colNew
) / 2) )
3175 markerX
= GetColRight(colNew
);
3177 markerX
= GetColLeft(colNew
);
3179 if ( markerX
!= m_dragLastPos
)
3181 wxClientDC
dc( GetColLabelWindow() );
3185 GetColLabelWindow()->GetClientSize( &cw
, &ch
);
3189 //Clean up the last indicator
3190 if ( m_dragLastPos
>= 0 )
3192 wxPen
pen( GetColLabelWindow()->GetBackgroundColour(), 2 );
3194 dc
.DrawLine( m_dragLastPos
+ 1, 0, m_dragLastPos
+ 1, ch
);
3195 dc
.SetPen(wxNullPen
);
3197 if ( XToCol( m_dragLastPos
) != -1 )
3198 DrawColLabel( dc
, XToCol( m_dragLastPos
) );
3201 const wxColour
*color
;
3202 //Moving to the same place? Don't draw a marker
3203 if ( colNew
== m_dragRowOrCol
)
3204 color
= wxLIGHT_GREY
;
3209 wxPen
pen( *color
, 2 );
3212 dc
.DrawLine( markerX
, 0, markerX
, ch
);
3214 dc
.SetPen(wxNullPen
);
3216 m_dragLastPos
= markerX
- 1;
3221 // default label to suppress warnings about "enumeration value
3222 // 'xxx' not handled in switch
3230 if ( m_isDragging
&& (event
.Entering() || event
.Leaving()) )
3235 if (GetColLabelWindow()->HasCapture())
3236 GetColLabelWindow()->ReleaseMouse();
3237 m_isDragging
= false;
3240 // ------------ Entering or leaving the window
3242 if ( event
.Entering() || event
.Leaving() )
3244 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow());
3247 // ------------ Left button pressed
3249 else if ( event
.LeftDown() )
3251 // don't send a label click event for a hit on the
3252 // edge of the col label - this is probably the user
3253 // wanting to resize the col
3255 if ( XToEdgeOfCol(x
) < 0 )
3258 !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event
) )
3260 if ( m_canDragColMove
)
3262 //Show button as pressed
3263 wxClientDC
dc( GetColLabelWindow() );
3264 int colLeft
= GetColLeft( col
);
3265 int colRight
= GetColRight( col
) - 1;
3266 dc
.SetPen( wxPen( GetColLabelWindow()->GetBackgroundColour(), 1 ) );
3267 dc
.DrawLine( colLeft
, 1, colLeft
, m_colLabelHeight
-1 );
3268 dc
.DrawLine( colLeft
, 1, colRight
, 1 );
3270 ChangeCursorMode(WXGRID_CURSOR_MOVE_COL
, GetColLabelWindow());
3274 if ( !event
.ShiftDown() && !event
.CmdDown() )
3278 if ( event
.ShiftDown() )
3280 m_selection
->SelectBlock
3282 0, m_currentCellCoords
.GetCol(),
3283 GetNumberRows() - 1, col
,
3289 m_selection
->SelectCol(col
, event
);
3293 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL
, GetColLabelWindow());
3299 // starting to drag-resize a col
3301 if ( CanDragColSize() )
3302 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, GetColLabelWindow());
3306 // ------------ Left double click
3308 if ( event
.LeftDClick() )
3310 const int colEdge
= XToEdgeOfCol(x
);
3311 if ( colEdge
== -1 )
3314 ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event
) )
3316 // no default action at the moment
3321 // adjust column width depending on label text
3322 AutoSizeColLabelSize( colEdge
);
3324 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow());
3329 // ------------ Left button released
3331 else if ( event
.LeftUp() )
3333 switch ( m_cursorMode
)
3335 case WXGRID_CURSOR_RESIZE_COL
:
3336 DoEndDragResizeCol();
3339 case WXGRID_CURSOR_MOVE_COL
:
3340 if ( m_dragLastPos
== -1 || col
== m_dragRowOrCol
)
3342 // the column didn't actually move anywhere
3344 DoColHeaderClick(col
);
3345 m_colWindow
->Refresh(); // "unpress" the column
3349 DoEndMoveCol(XToPos(x
));
3353 case WXGRID_CURSOR_SELECT_COL
:
3354 case WXGRID_CURSOR_SELECT_CELL
:
3355 case WXGRID_CURSOR_RESIZE_ROW
:
3356 case WXGRID_CURSOR_SELECT_ROW
:
3358 DoColHeaderClick(col
);
3362 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow());
3366 // ------------ Right button down
3368 else if ( event
.RightDown() )
3371 !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event
) )
3373 // no default action at the moment
3377 // ------------ Right double click
3379 else if ( event
.RightDClick() )
3382 !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event
) )
3384 // no default action at the moment
3388 // ------------ No buttons down and mouse moving
3390 else if ( event
.Moving() )
3392 m_dragRowOrCol
= XToEdgeOfCol( x
);
3393 if ( m_dragRowOrCol
>= 0 )
3395 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3397 // don't capture the cursor yet
3398 if ( CanDragColSize() )
3399 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, GetColLabelWindow(), false);
3402 else if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
3404 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow(), false);
3409 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event
)
3411 if ( event
.LeftDown() )
3413 // indicate corner label by having both row and
3416 if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event
) )
3421 else if ( event
.LeftDClick() )
3423 SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event
);
3425 else if ( event
.RightDown() )
3427 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event
) )
3429 // no default action at the moment
3432 else if ( event
.RightDClick() )
3434 if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event
) )
3436 // no default action at the moment
3441 void wxGrid::CancelMouseCapture()
3443 // cancel operation currently in progress, whatever it is
3446 m_isDragging
= false;
3447 m_startDragPos
= wxDefaultPosition
;
3449 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
3450 m_winCapture
->SetCursor( *wxSTANDARD_CURSOR
);
3451 m_winCapture
= NULL
;
3453 // remove traces of whatever we drew on screen
3458 void wxGrid::ChangeCursorMode(CursorMode mode
,
3463 static const wxChar
*cursorModes
[] =
3473 wxLogTrace(_T("grid"),
3474 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
3475 win
== m_colWindow
? _T("colLabelWin")
3476 : win
? _T("rowLabelWin")
3478 cursorModes
[m_cursorMode
], cursorModes
[mode
]);
3481 if ( mode
== m_cursorMode
&&
3482 win
== m_winCapture
&&
3483 captureMouse
== (m_winCapture
!= NULL
))
3488 // by default use the grid itself
3494 m_winCapture
->ReleaseMouse();
3495 m_winCapture
= NULL
;
3498 m_cursorMode
= mode
;
3500 switch ( m_cursorMode
)
3502 case WXGRID_CURSOR_RESIZE_ROW
:
3503 win
->SetCursor( m_rowResizeCursor
);
3506 case WXGRID_CURSOR_RESIZE_COL
:
3507 win
->SetCursor( m_colResizeCursor
);
3510 case WXGRID_CURSOR_MOVE_COL
:
3511 win
->SetCursor( wxCursor(wxCURSOR_HAND
) );
3515 win
->SetCursor( *wxSTANDARD_CURSOR
);
3519 // we need to capture mouse when resizing
3520 bool resize
= m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
||
3521 m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
;
3523 if ( captureMouse
&& resize
)
3525 win
->CaptureMouse();
3530 // ----------------------------------------------------------------------------
3531 // grid mouse event processing
3532 // ----------------------------------------------------------------------------
3535 wxGrid::DoGridCellDrag(wxMouseEvent
& event
,
3536 const wxGridCellCoords
& coords
,
3539 if ( coords
== wxGridNoCellCoords
)
3540 return; // we're outside any valid cell
3542 // Hide the edit control, so it won't interfere with drag-shrinking.
3543 if ( IsCellEditControlShown() )
3545 HideCellEditControl();
3546 SaveEditControlValue();
3549 switch ( event
.GetModifiers() )
3552 if ( m_selectedBlockCorner
== wxGridNoCellCoords
)
3553 m_selectedBlockCorner
= coords
;
3554 UpdateBlockBeingSelected(m_selectedBlockCorner
, coords
);
3558 if ( CanDragCell() )
3562 if ( m_selectedBlockCorner
== wxGridNoCellCoords
)
3563 m_selectedBlockCorner
= coords
;
3565 SendEvent(wxEVT_GRID_CELL_BEGIN_DRAG
, coords
, event
);
3570 UpdateBlockBeingSelected(m_currentCellCoords
, coords
);
3574 // we don't handle the other key modifiers
3579 void wxGrid::DoGridLineDrag(wxMouseEvent
& event
, const wxGridOperations
& oper
)
3581 wxClientDC
dc(m_gridWin
);
3583 dc
.SetLogicalFunction(wxINVERT
);
3585 const wxRect
rectWin(CalcUnscrolledPosition(wxPoint(0, 0)),
3586 m_gridWin
->GetClientSize());
3588 // erase the previously drawn line, if any
3589 if ( m_dragLastPos
>= 0 )
3590 oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
);
3592 // we need the vertical position for rows and horizontal for columns here
3593 m_dragLastPos
= oper
.Dual().Select(CalcUnscrolledPosition(event
.GetPosition()));
3595 // don't allow resizing beneath the minimal size
3596 const int posMin
= oper
.GetLineStartPos(this, m_dragRowOrCol
) +
3597 oper
.GetMinimalLineSize(this, m_dragRowOrCol
);
3598 if ( m_dragLastPos
< posMin
)
3599 m_dragLastPos
= posMin
;
3601 // and draw it at the new position
3602 oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
);
3605 void wxGrid::DoGridDragEvent(wxMouseEvent
& event
, const wxGridCellCoords
& coords
)
3607 if ( !m_isDragging
)
3609 // Don't start doing anything until the mouse has been dragged far
3611 const wxPoint
& pt
= event
.GetPosition();
3612 if ( m_startDragPos
== wxDefaultPosition
)
3614 m_startDragPos
= pt
;
3618 if ( abs(m_startDragPos
.x
- pt
.x
) <= DRAG_SENSITIVITY
&&
3619 abs(m_startDragPos
.y
- pt
.y
) <= DRAG_SENSITIVITY
)
3623 const bool isFirstDrag
= !m_isDragging
;
3624 m_isDragging
= true;
3626 switch ( m_cursorMode
)
3628 case WXGRID_CURSOR_SELECT_CELL
:
3629 DoGridCellDrag(event
, coords
, isFirstDrag
);
3632 case WXGRID_CURSOR_RESIZE_ROW
:
3633 DoGridLineDrag(event
, wxGridRowOperations());
3636 case WXGRID_CURSOR_RESIZE_COL
:
3637 DoGridLineDrag(event
, wxGridColumnOperations());
3646 m_winCapture
= m_gridWin
;
3647 m_winCapture
->CaptureMouse();
3652 wxGrid::DoGridCellLeftDown(wxMouseEvent
& event
,
3653 const wxGridCellCoords
& coords
,
3656 if ( SendEvent(wxEVT_GRID_CELL_LEFT_CLICK
, coords
, event
) )
3658 // event handled by user code, no need to do anything here
3662 if ( !event
.CmdDown() )
3665 if ( event
.ShiftDown() )
3669 m_selection
->SelectBlock(m_currentCellCoords
, coords
, event
);
3670 m_selectedBlockCorner
= coords
;
3673 else if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 )
3675 DisableCellEditControl();
3676 MakeCellVisible( coords
);
3678 if ( event
.CmdDown() )
3682 m_selection
->ToggleCellSelection(coords
, event
);
3685 m_selectedBlockTopLeft
= wxGridNoCellCoords
;
3686 m_selectedBlockBottomRight
= wxGridNoCellCoords
;
3687 m_selectedBlockCorner
= coords
;
3691 m_waitForSlowClick
= m_currentCellCoords
== coords
&&
3692 coords
!= wxGridNoCellCoords
;
3693 SetCurrentCell( coords
);
3699 wxGrid::DoGridCellLeftDClick(wxMouseEvent
& event
,
3700 const wxGridCellCoords
& coords
,
3703 if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 )
3705 if ( !SendEvent(wxEVT_GRID_CELL_LEFT_DCLICK
, coords
, event
) )
3707 // we want double click to select a cell and start editing
3708 // (i.e. to behave in same way as sequence of two slow clicks):
3709 m_waitForSlowClick
= true;
3715 wxGrid::DoGridCellLeftUp(wxMouseEvent
& event
, const wxGridCellCoords
& coords
)
3717 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3721 m_winCapture
->ReleaseMouse();
3722 m_winCapture
= NULL
;
3725 if ( coords
== m_currentCellCoords
&& m_waitForSlowClick
&& CanEnableCellControl() )
3728 EnableCellEditControl();
3730 wxGridCellAttr
*attr
= GetCellAttr(coords
);
3731 wxGridCellEditor
*editor
= attr
->GetEditor(this, coords
.GetRow(), coords
.GetCol());
3732 editor
->StartingClick();
3736 m_waitForSlowClick
= false;
3738 else if ( m_selectedBlockTopLeft
!= wxGridNoCellCoords
&&
3739 m_selectedBlockBottomRight
!= wxGridNoCellCoords
)
3743 m_selection
->SelectBlock( m_selectedBlockTopLeft
,
3744 m_selectedBlockBottomRight
,
3748 m_selectedBlockTopLeft
= wxGridNoCellCoords
;
3749 m_selectedBlockBottomRight
= wxGridNoCellCoords
;
3751 // Show the edit control, if it has been hidden for
3753 ShowCellEditControl();
3756 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
3758 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3759 DoEndDragResizeRow();
3761 // Note: we are ending the event *after* doing
3762 // default processing in this case
3764 SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
3766 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
3768 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3769 DoEndDragResizeCol();
3776 wxGrid::DoGridMouseMoveEvent(wxMouseEvent
& WXUNUSED(event
),
3777 const wxGridCellCoords
& coords
,
3780 if ( coords
.GetRow() < 0 || coords
.GetCol() < 0 )
3782 // out of grid cell area
3783 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3787 int dragRow
= YToEdgeOfRow( pos
.y
);
3788 int dragCol
= XToEdgeOfCol( pos
.x
);
3790 // Dragging on the corner of a cell to resize in both
3791 // directions is not implemented yet...
3793 if ( dragRow
>= 0 && dragCol
>= 0 )
3795 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3801 m_dragRowOrCol
= dragRow
;
3803 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3805 if ( CanDragRowSize() && CanDragGridSize() )
3806 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, NULL
, false);
3809 // When using the native header window we can only resize the columns by
3810 // dragging the dividers in it because we can't make it enter into the
3811 // column resizing mode programmatically
3812 else if ( dragCol
>= 0 && !m_useNativeHeader
)
3814 m_dragRowOrCol
= dragCol
;
3816 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
3818 if ( CanDragColSize() && CanDragGridSize() )
3819 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, NULL
, false);
3822 else // Neither on a row or col edge
3824 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
3826 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3831 void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent
& event
)
3833 const wxPoint pos
= CalcUnscrolledPosition(event
.GetPosition());
3835 // coordinates of the cell under mouse
3836 wxGridCellCoords coords
= XYToCell(pos
);
3838 int cell_rows
, cell_cols
;
3839 GetCellSize( coords
.GetRow(), coords
.GetCol(), &cell_rows
, &cell_cols
);
3840 if ( (cell_rows
< 0) || (cell_cols
< 0) )
3842 coords
.SetRow(coords
.GetRow() + cell_rows
);
3843 coords
.SetCol(coords
.GetCol() + cell_cols
);
3846 if ( event
.Dragging() )
3848 if ( event
.LeftIsDown() )
3849 DoGridDragEvent(event
, coords
);
3855 m_isDragging
= false;
3856 m_startDragPos
= wxDefaultPosition
;
3858 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
3859 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
3862 if ( event
.Entering() || event
.Leaving() )
3864 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
3865 m_gridWin
->SetCursor( *wxSTANDARD_CURSOR
);
3869 // deal with various button presses
3870 if ( event
.IsButton() )
3872 if ( coords
!= wxGridNoCellCoords
)
3874 DisableCellEditControl();
3876 if ( event
.LeftDown() )
3877 DoGridCellLeftDown(event
, coords
, pos
);
3878 else if ( event
.LeftDClick() )
3879 DoGridCellLeftDClick(event
, coords
, pos
);
3880 else if ( event
.RightDown() )
3881 SendEvent(wxEVT_GRID_CELL_RIGHT_CLICK
, coords
, event
);
3882 else if ( event
.RightDClick() )
3883 SendEvent(wxEVT_GRID_CELL_RIGHT_DCLICK
, coords
, event
);
3886 // this one should be called even if we're not over any cell
3887 if ( event
.LeftUp() )
3889 DoGridCellLeftUp(event
, coords
);
3892 else if ( event
.Moving() )
3894 DoGridMouseMoveEvent(event
, coords
, pos
);
3896 else // unknown mouse event?
3902 void wxGrid::DoEndDragResizeLine(const wxGridOperations
& oper
)
3904 if ( m_dragLastPos
== -1 )
3907 const wxGridOperations
& doper
= oper
.Dual();
3909 const wxSize size
= m_gridWin
->GetClientSize();
3911 const wxPoint ptOrigin
= CalcUnscrolledPosition(wxPoint(0, 0));
3913 // erase the last line we drew
3914 wxClientDC
dc(m_gridWin
);
3916 dc
.SetLogicalFunction(wxINVERT
);
3918 const int posLineStart
= oper
.Select(ptOrigin
);
3919 const int posLineEnd
= oper
.Select(ptOrigin
) + oper
.Select(size
);
3921 oper
.DrawParallelLine(dc
, posLineStart
, posLineEnd
, m_dragLastPos
);
3923 // temporarily hide the edit control before resizing
3924 HideCellEditControl();
3925 SaveEditControlValue();
3927 // do resize the line
3928 const int lineStart
= oper
.GetLineStartPos(this, m_dragRowOrCol
);
3929 oper
.SetLineSize(this, m_dragRowOrCol
,
3930 wxMax(m_dragLastPos
- lineStart
,
3931 oper
.GetMinimalLineSize(this, m_dragRowOrCol
)));
3935 // refresh now if we're not frozen
3936 if ( !GetBatchCount() )
3938 // we need to refresh everything beyond the resized line in the header
3941 // get the position from which to refresh in the other direction
3942 wxRect
rect(CellToRect(oper
.MakeCoords(m_dragRowOrCol
, 0)));
3943 rect
.SetPosition(CalcScrolledPosition(rect
.GetPosition()));
3945 // we only need the ordinate (for rows) or abscissa (for columns) here,
3946 // and need to cover the entire window in the other direction
3947 oper
.Select(rect
) = 0;
3949 wxRect
rectHeader(rect
.GetPosition(),
3952 oper
.GetHeaderWindowSize(this),
3953 doper
.Select(size
) - doper
.Select(rect
)
3956 oper
.GetHeaderWindow(this)->Refresh(true, &rectHeader
);
3959 // also refresh the grid window: extend the rectangle
3962 oper
.SelectSize(rect
) = oper
.Select(size
);
3964 int subtractLines
= 0;
3965 const int lineStart
= oper
.PosToLine(this, posLineStart
);
3966 if ( lineStart
>= 0 )
3968 // ensure that if we have a multi-cell block we redraw all of
3969 // it by increasing the refresh area to cover it entirely if a
3970 // part of it is affected
3971 const int lineEnd
= oper
.PosToLine(this, posLineEnd
, true);
3972 for ( int line
= lineStart
; line
< lineEnd
; line
++ )
3974 int cellLines
= oper
.Select(
3975 GetCellSize(oper
.MakeCoords(m_dragRowOrCol
, line
)));
3976 if ( cellLines
< subtractLines
)
3977 subtractLines
= cellLines
;
3982 oper
.GetLineStartPos(this, m_dragRowOrCol
+ subtractLines
);
3983 startPos
= doper
.CalcScrolledPosition(this, startPos
);
3985 doper
.Select(rect
) = startPos
;
3986 doper
.SelectSize(rect
) = doper
.Select(size
) - startPos
;
3988 m_gridWin
->Refresh(false, &rect
);
3992 // show the edit control back again
3993 ShowCellEditControl();
3996 void wxGrid::DoEndDragResizeRow()
3998 DoEndDragResizeLine(wxGridRowOperations());
4001 void wxGrid::DoEndDragResizeCol(wxMouseEvent
*event
)
4003 DoEndDragResizeLine(wxGridColumnOperations());
4005 // Note: we are ending the event *after* doing
4006 // default processing in this case
4009 SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, *event
);
4011 SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
);
4014 void wxGrid::DoStartMoveCol(int col
)
4016 m_dragRowOrCol
= col
;
4019 void wxGrid::DoEndMoveCol(int pos
)
4021 wxASSERT_MSG( m_dragRowOrCol
!= -1, "no matching DoStartMoveCol?" );
4023 if ( SendEvent(wxEVT_GRID_COL_MOVE
, -1, m_dragRowOrCol
) != -1 )
4024 SetColPos(m_dragRowOrCol
, pos
);
4025 //else: vetoed by user
4027 m_dragRowOrCol
= -1;
4030 void wxGrid::RefreshAfterColPosChange()
4032 // recalculate the column rights as the column positions have changed,
4033 // unless we calculate them dynamically because all columns widths are the
4034 // same and it's easy to do
4035 if ( !m_colWidths
.empty() )
4038 for ( int colPos
= 0; colPos
< m_numCols
; colPos
++ )
4040 int colID
= GetColAt( colPos
);
4042 colRight
+= m_colWidths
[colID
];
4043 m_colRights
[colID
] = colRight
;
4047 // and make the changes visible
4048 if ( m_useNativeHeader
)
4050 if ( m_colAt
.empty() )
4051 GetGridColHeader()->ResetColumnsOrder();
4053 GetGridColHeader()->SetColumnsOrder(m_colAt
);
4057 m_colWindow
->Refresh();
4059 m_gridWin
->Refresh();
4062 void wxGrid::SetColumnsOrder(const wxArrayInt
& order
)
4066 RefreshAfterColPosChange();
4069 void wxGrid::SetColPos(int idx
, int pos
)
4071 // we're going to need m_colAt now, initialize it if needed
4072 if ( m_colAt
.empty() )
4074 m_colAt
.reserve(m_numCols
);
4075 for ( int i
= 0; i
< m_numCols
; i
++ )
4076 m_colAt
.push_back(i
);
4079 wxHeaderCtrl::MoveColumnInOrderArray(m_colAt
, idx
, pos
);
4081 RefreshAfterColPosChange();
4084 void wxGrid::ResetColPos()
4088 RefreshAfterColPosChange();
4091 void wxGrid::EnableDragColMove( bool enable
)
4093 if ( m_canDragColMove
== enable
)
4096 if ( m_useNativeHeader
)
4098 // update all columns to make them [not] reorderable
4099 GetGridColHeader()->SetColumnCount(m_numCols
);
4102 m_canDragColMove
= enable
;
4104 // we use to call ResetColPos() from here if !enable but this doesn't seem
4105 // right as it would mean there would be no way to "freeze" the current
4106 // columns order by disabling moving them after putting them in the desired
4107 // order, whereas now you can always call ResetColPos() manually if needed
4112 // ------ interaction with data model
4114 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg
)
4116 switch ( msg
.GetId() )
4118 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
:
4119 return GetModelValues();
4121 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
:
4122 return SetModelValues();
4124 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
4125 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
4126 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
4127 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
4128 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
4129 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
4130 return Redimension( msg
);
4137 // The behaviour of this function depends on the grid table class
4138 // Clear() function. For the default wxGridStringTable class the
4139 // behaviour is to replace all cell contents with wxEmptyString but
4140 // not to change the number of rows or cols.
4142 void wxGrid::ClearGrid()
4146 if (IsCellEditControlEnabled())
4147 DisableCellEditControl();
4150 if (!GetBatchCount())
4151 m_gridWin
->Refresh();
4156 wxGrid::DoModifyLines(bool (wxGridTableBase::*funcModify
)(size_t, size_t),
4157 int pos
, int num
, bool WXUNUSED(updateLabels
) )
4159 wxCHECK_MSG( m_created
, false, "must finish creating the grid first" );
4164 if ( IsCellEditControlEnabled() )
4165 DisableCellEditControl();
4167 return (m_table
->*funcModify
)(pos
, num
);
4169 // the table will have sent the results of the insert row
4170 // operation to this view object as a grid table message
4174 wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend
)(size_t),
4175 int num
, bool WXUNUSED(updateLabels
))
4177 wxCHECK_MSG( m_created
, false, "must finish creating the grid first" );
4182 return (m_table
->*funcAppend
)(num
);
4186 // ----- event handlers
4189 // Generate a grid event based on a mouse event and return:
4190 // -1 if the event was vetoed
4191 // +1 if the event was processed (but not vetoed)
4192 // 0 if the event wasn't handled
4194 wxGrid::SendEvent(const wxEventType type
,
4196 wxMouseEvent
& mouseEv
)
4198 bool claimed
, vetoed
;
4200 if ( type
== wxEVT_GRID_ROW_SIZE
|| type
== wxEVT_GRID_COL_SIZE
)
4202 int rowOrCol
= (row
== -1 ? col
: row
);
4204 wxGridSizeEvent
gridEvt( GetId(),
4208 mouseEv
.GetX() + GetRowLabelSize(),
4209 mouseEv
.GetY() + GetColLabelSize(),
4212 claimed
= GetEventHandler()->ProcessEvent(gridEvt
);
4213 vetoed
= !gridEvt
.IsAllowed();
4215 else if ( type
== wxEVT_GRID_RANGE_SELECT
)
4217 // Right now, it should _never_ end up here!
4218 wxGridRangeSelectEvent
gridEvt( GetId(),
4221 m_selectedBlockTopLeft
,
4222 m_selectedBlockBottomRight
,
4226 claimed
= GetEventHandler()->ProcessEvent(gridEvt
);
4227 vetoed
= !gridEvt
.IsAllowed();
4229 else if ( type
== wxEVT_GRID_LABEL_LEFT_CLICK
||
4230 type
== wxEVT_GRID_LABEL_LEFT_DCLICK
||
4231 type
== wxEVT_GRID_LABEL_RIGHT_CLICK
||
4232 type
== wxEVT_GRID_LABEL_RIGHT_DCLICK
)
4234 wxPoint pos
= mouseEv
.GetPosition();
4236 if ( mouseEv
.GetEventObject() == GetGridRowLabelWindow() )
4237 pos
.y
+= GetColLabelSize();
4238 if ( mouseEv
.GetEventObject() == GetGridColLabelWindow() )
4239 pos
.x
+= GetRowLabelSize();
4241 wxGridEvent
gridEvt( GetId(),
4249 claimed
= GetEventHandler()->ProcessEvent(gridEvt
);
4250 vetoed
= !gridEvt
.IsAllowed();
4254 wxGridEvent
gridEvt( GetId(),
4258 mouseEv
.GetX() + GetRowLabelSize(),
4259 mouseEv
.GetY() + GetColLabelSize(),
4262 claimed
= GetEventHandler()->ProcessEvent(gridEvt
);
4263 vetoed
= !gridEvt
.IsAllowed();
4266 // A Veto'd event may not be `claimed' so test this first
4270 return claimed
? 1 : 0;
4273 // Generate a grid event of specified type, return value same as above
4276 wxGrid::SendEvent(const wxEventType type
, int row
, int col
, const wxString
& s
)
4278 bool claimed
, vetoed
;
4280 if ( type
== wxEVT_GRID_ROW_SIZE
|| type
== wxEVT_GRID_COL_SIZE
)
4282 int rowOrCol
= (row
== -1 ? col
: row
);
4284 wxGridSizeEvent
gridEvt( GetId(), type
, this, rowOrCol
);
4286 claimed
= GetEventHandler()->ProcessEvent(gridEvt
);
4287 vetoed
= !gridEvt
.IsAllowed();
4291 wxGridEvent
gridEvt( GetId(), type
, this, row
, col
);
4292 gridEvt
.SetString(s
);
4294 claimed
= GetEventHandler()->ProcessEvent(gridEvt
);
4295 vetoed
= !gridEvt
.IsAllowed();
4298 // A Veto'd event may not be `claimed' so test this first
4302 return claimed
? 1 : 0;
4305 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
4307 // needed to prevent zillions of paint events on MSW
4311 void wxGrid::Refresh(bool eraseb
, const wxRect
* rect
)
4313 // Don't do anything if between Begin/EndBatch...
4314 // EndBatch() will do all this on the last nested one anyway.
4315 if ( m_created
&& !GetBatchCount() )
4317 // Refresh to get correct scrolled position:
4318 wxScrolledWindow::Refresh(eraseb
, rect
);
4322 int rect_x
, rect_y
, rectWidth
, rectHeight
;
4323 int width_label
, width_cell
, height_label
, height_cell
;
4326 // Copy rectangle can get scroll offsets..
4327 rect_x
= rect
->GetX();
4328 rect_y
= rect
->GetY();
4329 rectWidth
= rect
->GetWidth();
4330 rectHeight
= rect
->GetHeight();
4332 width_label
= m_rowLabelWidth
- rect_x
;
4333 if (width_label
> rectWidth
)
4334 width_label
= rectWidth
;
4336 height_label
= m_colLabelHeight
- rect_y
;
4337 if (height_label
> rectHeight
)
4338 height_label
= rectHeight
;
4340 if (rect_x
> m_rowLabelWidth
)
4342 x
= rect_x
- m_rowLabelWidth
;
4343 width_cell
= rectWidth
;
4348 width_cell
= rectWidth
- (m_rowLabelWidth
- rect_x
);
4351 if (rect_y
> m_colLabelHeight
)
4353 y
= rect_y
- m_colLabelHeight
;
4354 height_cell
= rectHeight
;
4359 height_cell
= rectHeight
- (m_colLabelHeight
- rect_y
);
4362 // Paint corner label part intersecting rect.
4363 if ( width_label
> 0 && height_label
> 0 )
4365 wxRect
anotherrect(rect_x
, rect_y
, width_label
, height_label
);
4366 m_cornerLabelWin
->Refresh(eraseb
, &anotherrect
);
4369 // Paint col labels part intersecting rect.
4370 if ( width_cell
> 0 && height_label
> 0 )
4372 wxRect
anotherrect(x
, rect_y
, width_cell
, height_label
);
4373 m_colWindow
->Refresh(eraseb
, &anotherrect
);
4376 // Paint row labels part intersecting rect.
4377 if ( width_label
> 0 && height_cell
> 0 )
4379 wxRect
anotherrect(rect_x
, y
, width_label
, height_cell
);
4380 m_rowLabelWin
->Refresh(eraseb
, &anotherrect
);
4383 // Paint cell area part intersecting rect.
4384 if ( width_cell
> 0 && height_cell
> 0 )
4386 wxRect
anotherrect(x
, y
, width_cell
, height_cell
);
4387 m_gridWin
->Refresh(eraseb
, &anotherrect
);
4392 m_cornerLabelWin
->Refresh(eraseb
, NULL
);
4393 m_colWindow
->Refresh(eraseb
, NULL
);
4394 m_rowLabelWin
->Refresh(eraseb
, NULL
);
4395 m_gridWin
->Refresh(eraseb
, NULL
);
4400 void wxGrid::OnSize(wxSizeEvent
& WXUNUSED(event
))
4402 if (m_targetWindow
!= this) // check whether initialisation has been done
4404 // reposition our children windows
4409 void wxGrid::OnKeyDown( wxKeyEvent
& event
)
4411 if ( m_inOnKeyDown
)
4413 // shouldn't be here - we are going round in circles...
4415 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
4418 m_inOnKeyDown
= true;
4420 // propagate the event up and see if it gets processed
4421 wxWindow
*parent
= GetParent();
4422 wxKeyEvent
keyEvt( event
);
4423 keyEvt
.SetEventObject( parent
);
4425 if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt
) )
4427 if (GetLayoutDirection() == wxLayout_RightToLeft
)
4429 if (event
.GetKeyCode() == WXK_RIGHT
)
4430 event
.m_keyCode
= WXK_LEFT
;
4431 else if (event
.GetKeyCode() == WXK_LEFT
)
4432 event
.m_keyCode
= WXK_RIGHT
;
4435 // try local handlers
4436 switch ( event
.GetKeyCode() )
4439 if ( event
.ControlDown() )
4440 MoveCursorUpBlock( event
.ShiftDown() );
4442 MoveCursorUp( event
.ShiftDown() );
4446 if ( event
.ControlDown() )
4447 MoveCursorDownBlock( event
.ShiftDown() );
4449 MoveCursorDown( event
.ShiftDown() );
4453 if ( event
.ControlDown() )
4454 MoveCursorLeftBlock( event
.ShiftDown() );
4456 MoveCursorLeft( event
.ShiftDown() );
4460 if ( event
.ControlDown() )
4461 MoveCursorRightBlock( event
.ShiftDown() );
4463 MoveCursorRight( event
.ShiftDown() );
4467 case WXK_NUMPAD_ENTER
:
4468 if ( event
.ControlDown() )
4470 event
.Skip(); // to let the edit control have the return
4474 if ( GetGridCursorRow() < GetNumberRows()-1 )
4476 MoveCursorDown( event
.ShiftDown() );
4480 // at the bottom of a column
4481 DisableCellEditControl();
4491 if (event
.ShiftDown())
4493 if ( GetGridCursorCol() > 0 )
4495 MoveCursorLeft( false );
4500 DisableCellEditControl();
4505 if ( GetGridCursorCol() < GetNumberCols() - 1 )
4507 MoveCursorRight( false );
4512 DisableCellEditControl();
4518 if ( event
.ControlDown() )
4529 if ( event
.ControlDown() )
4531 GoToCell(m_numRows
- 1, m_numCols
- 1);
4548 // Ctrl-Space selects the current column, Shift-Space -- the
4549 // current row and Ctrl-Shift-Space -- everything
4550 switch ( m_selection
? event
.GetModifiers() : wxMOD_NONE
)
4553 m_selection
->SelectCol(m_currentCellCoords
.GetCol());
4557 m_selection
->SelectRow(m_currentCellCoords
.GetRow());
4560 case wxMOD_CONTROL
| wxMOD_SHIFT
:
4561 m_selection
->SelectBlock(0, 0,
4562 m_numRows
- 1, m_numCols
- 1);
4566 if ( !IsEditable() )
4568 MoveCursorRight(false);
4571 //else: fall through
4584 m_inOnKeyDown
= false;
4587 void wxGrid::OnKeyUp( wxKeyEvent
& event
)
4589 // try local handlers
4591 if ( event
.GetKeyCode() == WXK_SHIFT
)
4593 if ( m_selectedBlockTopLeft
!= wxGridNoCellCoords
&&
4594 m_selectedBlockBottomRight
!= wxGridNoCellCoords
)
4598 m_selection
->SelectBlock(
4599 m_selectedBlockTopLeft
,
4600 m_selectedBlockBottomRight
,
4605 m_selectedBlockTopLeft
= wxGridNoCellCoords
;
4606 m_selectedBlockBottomRight
= wxGridNoCellCoords
;
4607 m_selectedBlockCorner
= wxGridNoCellCoords
;
4611 void wxGrid::OnChar( wxKeyEvent
& event
)
4613 // is it possible to edit the current cell at all?
4614 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
4616 // yes, now check whether the cells editor accepts the key
4617 int row
= m_currentCellCoords
.GetRow();
4618 int col
= m_currentCellCoords
.GetCol();
4619 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
4620 wxGridCellEditor
*editor
= attr
->GetEditor(this, row
, col
);
4622 // <F2> is special and will always start editing, for
4623 // other keys - ask the editor itself
4624 if ( (event
.GetKeyCode() == WXK_F2
&& !event
.HasModifiers())
4625 || editor
->IsAcceptedKey(event
) )
4627 // ensure cell is visble
4628 MakeCellVisible(row
, col
);
4629 EnableCellEditControl();
4631 // a problem can arise if the cell is not completely
4632 // visible (even after calling MakeCellVisible the
4633 // control is not created and calling StartingKey will
4635 if ( event
.GetKeyCode() != WXK_F2
&& editor
->IsCreated() && m_cellEditCtrlEnabled
)
4636 editor
->StartingKey(event
);
4652 void wxGrid::OnEraseBackground(wxEraseEvent
&)
4656 bool wxGrid::SetCurrentCell( const wxGridCellCoords
& coords
)
4658 if ( SendEvent(wxEVT_GRID_SELECT_CELL
, coords
) == -1 )
4660 // the event has been vetoed - do nothing
4664 #if !defined(__WXMAC__)
4665 wxClientDC
dc( m_gridWin
);
4669 if ( m_currentCellCoords
!= wxGridNoCellCoords
)
4671 DisableCellEditControl();
4673 if ( IsVisible( m_currentCellCoords
, false ) )
4676 r
= BlockToDeviceRect( m_currentCellCoords
, m_currentCellCoords
);
4677 if ( !m_gridLinesEnabled
)
4685 wxGridCellCoordsArray cells
= CalcCellsExposed( r
);
4687 // Otherwise refresh redraws the highlight!
4688 m_currentCellCoords
= coords
;
4690 #if defined(__WXMAC__)
4691 m_gridWin
->Refresh(true /*, & r */);
4693 DrawGridCellArea( dc
, cells
);
4694 DrawAllGridLines( dc
, r
);
4699 m_currentCellCoords
= coords
;
4701 wxGridCellAttr
*attr
= GetCellAttr( coords
);
4702 #if !defined(__WXMAC__)
4703 DrawCellHighlight( dc
, attr
);
4711 wxGrid::UpdateBlockBeingSelected(int topRow
, int leftCol
,
4712 int bottomRow
, int rightCol
)
4716 switch ( m_selection
->GetSelectionMode() )
4719 wxFAIL_MSG( "unknown selection mode" );
4722 case wxGridSelectCells
:
4723 // arbitrary blocks selection allowed so just use the cell
4724 // coordinates as is
4727 case wxGridSelectRows
:
4728 // only full rows selection allowd, ensure that we do select
4731 rightCol
= GetNumberCols() - 1;
4734 case wxGridSelectColumns
:
4735 // same as above but for columns
4737 bottomRow
= GetNumberRows() - 1;
4740 case wxGridSelectRowsOrColumns
:
4741 // in this mode we can select only full rows or full columns so
4742 // it doesn't make sense to select blocks at all (and we can't
4743 // extend the block because there is no preferred direction, we
4744 // could only extend it to cover the entire grid but this is
4750 m_selectedBlockCorner
= wxGridCellCoords(bottomRow
, rightCol
);
4751 MakeCellVisible(m_selectedBlockCorner
);
4753 EnsureFirstLessThanSecond(topRow
, bottomRow
);
4754 EnsureFirstLessThanSecond(leftCol
, rightCol
);
4756 wxGridCellCoords updateTopLeft
= wxGridCellCoords(topRow
, leftCol
),
4757 updateBottomRight
= wxGridCellCoords(bottomRow
, rightCol
);
4759 // First the case that we selected a completely new area
4760 if ( m_selectedBlockTopLeft
== wxGridNoCellCoords
||
4761 m_selectedBlockBottomRight
== wxGridNoCellCoords
)
4764 rect
= BlockToDeviceRect( wxGridCellCoords ( topRow
, leftCol
),
4765 wxGridCellCoords ( bottomRow
, rightCol
) );
4766 m_gridWin
->Refresh( false, &rect
);
4769 // Now handle changing an existing selection area.
4770 else if ( m_selectedBlockTopLeft
!= updateTopLeft
||
4771 m_selectedBlockBottomRight
!= updateBottomRight
)
4773 // Compute two optimal update rectangles:
4774 // Either one rectangle is a real subset of the
4775 // other, or they are (almost) disjoint!
4777 bool need_refresh
[4];
4781 need_refresh
[3] = false;
4784 // Store intermediate values
4785 wxCoord oldLeft
= m_selectedBlockTopLeft
.GetCol();
4786 wxCoord oldTop
= m_selectedBlockTopLeft
.GetRow();
4787 wxCoord oldRight
= m_selectedBlockBottomRight
.GetCol();
4788 wxCoord oldBottom
= m_selectedBlockBottomRight
.GetRow();
4790 // Determine the outer/inner coordinates.
4791 EnsureFirstLessThanSecond(oldLeft
, leftCol
);
4792 EnsureFirstLessThanSecond(oldTop
, topRow
);
4793 EnsureFirstLessThanSecond(rightCol
, oldRight
);
4794 EnsureFirstLessThanSecond(bottomRow
, oldBottom
);
4796 // Now, either the stuff marked old is the outer
4797 // rectangle or we don't have a situation where one
4798 // is contained in the other.
4800 if ( oldLeft
< leftCol
)
4802 // Refresh the newly selected or deselected
4803 // area to the left of the old or new selection.
4804 need_refresh
[0] = true;
4805 rect
[0] = BlockToDeviceRect(
4806 wxGridCellCoords( oldTop
, oldLeft
),
4807 wxGridCellCoords( oldBottom
, leftCol
- 1 ) );
4810 if ( oldTop
< topRow
)
4812 // Refresh the newly selected or deselected
4813 // area above the old or new selection.
4814 need_refresh
[1] = true;
4815 rect
[1] = BlockToDeviceRect(
4816 wxGridCellCoords( oldTop
, leftCol
),
4817 wxGridCellCoords( topRow
- 1, rightCol
) );
4820 if ( oldRight
> rightCol
)
4822 // Refresh the newly selected or deselected
4823 // area to the right of the old or new selection.
4824 need_refresh
[2] = true;
4825 rect
[2] = BlockToDeviceRect(
4826 wxGridCellCoords( oldTop
, rightCol
+ 1 ),
4827 wxGridCellCoords( oldBottom
, oldRight
) );
4830 if ( oldBottom
> bottomRow
)
4832 // Refresh the newly selected or deselected
4833 // area below the old or new selection.
4834 need_refresh
[3] = true;
4835 rect
[3] = BlockToDeviceRect(
4836 wxGridCellCoords( bottomRow
+ 1, leftCol
),
4837 wxGridCellCoords( oldBottom
, rightCol
) );
4840 // various Refresh() calls
4841 for (i
= 0; i
< 4; i
++ )
4842 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
4843 m_gridWin
->Refresh( false, &(rect
[i
]) );
4847 m_selectedBlockTopLeft
= updateTopLeft
;
4848 m_selectedBlockBottomRight
= updateBottomRight
;
4852 // ------ functions to get/send data (see also public functions)
4855 bool wxGrid::GetModelValues()
4857 // Hide the editor, so it won't hide a changed value.
4858 HideCellEditControl();
4862 // all we need to do is repaint the grid
4864 m_gridWin
->Refresh();
4871 bool wxGrid::SetModelValues()
4875 // Disable the editor, so it won't hide a changed value.
4876 // Do we also want to save the current value of the editor first?
4878 DisableCellEditControl();
4882 for ( row
= 0; row
< m_numRows
; row
++ )
4884 for ( col
= 0; col
< m_numCols
; col
++ )
4886 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) );
4896 // Note - this function only draws cells that are in the list of
4897 // exposed cells (usually set from the update region by
4898 // CalcExposedCells)
4900 void wxGrid::DrawGridCellArea( wxDC
& dc
, const wxGridCellCoordsArray
& cells
)
4902 if ( !m_numRows
|| !m_numCols
)
4905 int i
, numCells
= cells
.GetCount();
4906 int row
, col
, cell_rows
, cell_cols
;
4907 wxGridCellCoordsArray redrawCells
;
4909 for ( i
= numCells
- 1; i
>= 0; i
-- )
4911 row
= cells
[i
].GetRow();
4912 col
= cells
[i
].GetCol();
4913 GetCellSize( row
, col
, &cell_rows
, &cell_cols
);
4915 // If this cell is part of a multicell block, find owner for repaint
4916 if ( cell_rows
<= 0 || cell_cols
<= 0 )
4918 wxGridCellCoords
cell( row
+ cell_rows
, col
+ cell_cols
);
4919 bool marked
= false;
4920 for ( int j
= 0; j
< numCells
; j
++ )
4922 if ( cell
== cells
[j
] )
4931 int count
= redrawCells
.GetCount();
4932 for (int j
= 0; j
< count
; j
++)
4934 if ( cell
== redrawCells
[j
] )
4942 redrawCells
.Add( cell
);
4945 // don't bother drawing this cell
4949 // If this cell is empty, find cell to left that might want to overflow
4950 if (m_table
&& m_table
->IsEmptyCell(row
, col
))
4952 for ( int l
= 0; l
< cell_rows
; l
++ )
4954 // find a cell in this row to leave already marked for repaint
4956 for (int k
= 0; k
< int(redrawCells
.GetCount()); k
++)
4957 if ((redrawCells
[k
].GetCol() < left
) &&
4958 (redrawCells
[k
].GetRow() == row
))
4960 left
= redrawCells
[k
].GetCol();
4964 left
= 0; // oh well
4966 for (int j
= col
- 1; j
>= left
; j
--)
4968 if (!m_table
->IsEmptyCell(row
+ l
, j
))
4970 if (GetCellOverflow(row
+ l
, j
))
4972 wxGridCellCoords
cell(row
+ l
, j
);
4973 bool marked
= false;
4975 for (int k
= 0; k
< numCells
; k
++)
4977 if ( cell
== cells
[k
] )
4986 int count
= redrawCells
.GetCount();
4987 for (int k
= 0; k
< count
; k
++)
4989 if ( cell
== redrawCells
[k
] )
4996 redrawCells
.Add( cell
);
5005 DrawCell( dc
, cells
[i
] );
5008 numCells
= redrawCells
.GetCount();
5010 for ( i
= numCells
- 1; i
>= 0; i
-- )
5012 DrawCell( dc
, redrawCells
[i
] );
5016 void wxGrid::DrawGridSpace( wxDC
& dc
)
5019 m_gridWin
->GetClientSize( &cw
, &ch
);
5022 CalcUnscrolledPosition( cw
, ch
, &right
, &bottom
);
5024 int rightCol
= m_numCols
> 0 ? GetColRight(GetColAt( m_numCols
- 1 )) : 0;
5025 int bottomRow
= m_numRows
> 0 ? GetRowBottom(m_numRows
- 1) : 0;
5027 if ( right
> rightCol
|| bottom
> bottomRow
)
5030 CalcUnscrolledPosition( 0, 0, &left
, &top
);
5032 dc
.SetBrush(GetDefaultCellBackgroundColour());
5033 dc
.SetPen( *wxTRANSPARENT_PEN
);
5035 if ( right
> rightCol
)
5037 dc
.DrawRectangle( rightCol
, top
, right
- rightCol
, ch
);
5040 if ( bottom
> bottomRow
)
5042 dc
.DrawRectangle( left
, bottomRow
, cw
, bottom
- bottomRow
);
5047 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords
)
5049 int row
= coords
.GetRow();
5050 int col
= coords
.GetCol();
5052 if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
5055 // we draw the cell border ourselves
5056 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
5058 bool isCurrent
= coords
== m_currentCellCoords
;
5060 wxRect rect
= CellToRect( row
, col
);
5062 // if the editor is shown, we should use it and not the renderer
5063 // Note: However, only if it is really _shown_, i.e. not hidden!
5064 if ( isCurrent
&& IsCellEditControlShown() )
5066 // NB: this "#if..." is temporary and fixes a problem where the
5067 // edit control is erased by this code after being rendered.
5068 // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered
5069 // implicitly, causing this out-of order render.
5070 #if !defined(__WXMAC__)
5071 wxGridCellEditor
*editor
= attr
->GetEditor(this, row
, col
);
5072 editor
->PaintBackground(rect
, attr
);
5078 // but all the rest is drawn by the cell renderer and hence may be customized
5079 wxGridCellRenderer
*renderer
= attr
->GetRenderer(this, row
, col
);
5080 renderer
->Draw(*this, *attr
, dc
, rect
, row
, col
, IsInSelection(coords
));
5087 void wxGrid::DrawCellHighlight( wxDC
& dc
, const wxGridCellAttr
*attr
)
5089 // don't show highlight when the grid doesn't have focus
5093 int row
= m_currentCellCoords
.GetRow();
5094 int col
= m_currentCellCoords
.GetCol();
5096 if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
5099 wxRect rect
= CellToRect(row
, col
);
5101 // hmmm... what could we do here to show that the cell is disabled?
5102 // for now, I just draw a thinner border than for the other ones, but
5103 // it doesn't look really good
5105 int penWidth
= attr
->IsReadOnly() ? m_cellHighlightROPenWidth
: m_cellHighlightPenWidth
;
5109 // The center of the drawn line is where the position/width/height of
5110 // the rectangle is actually at (on wxMSW at least), so the
5111 // size of the rectangle is reduced to compensate for the thickness of
5112 // the line. If this is too strange on non-wxMSW platforms then
5113 // please #ifdef this appropriately.
5114 rect
.x
+= penWidth
/ 2;
5115 rect
.y
+= penWidth
/ 2;
5116 rect
.width
-= penWidth
- 1;
5117 rect
.height
-= penWidth
- 1;
5119 // Now draw the rectangle
5120 // use the cellHighlightColour if the cell is inside a selection, this
5121 // will ensure the cell is always visible.
5122 dc
.SetPen(wxPen(IsInSelection(row
,col
) ? m_selectionForeground
5123 : m_cellHighlightColour
,
5125 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
5126 dc
.DrawRectangle(rect
);
5130 wxPen
wxGrid::GetDefaultGridLinePen()
5132 return wxPen(GetGridLineColour());
5135 wxPen
wxGrid::GetRowGridLinePen(int WXUNUSED(row
))
5137 return GetDefaultGridLinePen();
5140 wxPen
wxGrid::GetColGridLinePen(int WXUNUSED(col
))
5142 return GetDefaultGridLinePen();
5145 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords
)
5147 int row
= coords
.GetRow();
5148 int col
= coords
.GetCol();
5149 if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
5153 wxRect rect
= CellToRect( row
, col
);
5155 // right hand border
5156 dc
.SetPen( GetColGridLinePen(col
) );
5157 dc
.DrawLine( rect
.x
+ rect
.width
, rect
.y
,
5158 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
+ 1 );
5161 dc
.SetPen( GetRowGridLinePen(row
) );
5162 dc
.DrawLine( rect
.x
, rect
.y
+ rect
.height
,
5163 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
5166 void wxGrid::DrawHighlight(wxDC
& dc
, const wxGridCellCoordsArray
& cells
)
5168 // This if block was previously in wxGrid::OnPaint but that doesn't
5169 // seem to get called under wxGTK - MB
5171 if ( m_currentCellCoords
== wxGridNoCellCoords
&&
5172 m_numRows
&& m_numCols
)
5174 m_currentCellCoords
.Set(0, 0);
5177 if ( IsCellEditControlShown() )
5179 // don't show highlight when the edit control is shown
5183 // if the active cell was repainted, repaint its highlight too because it
5184 // might have been damaged by the grid lines
5185 size_t count
= cells
.GetCount();
5186 for ( size_t n
= 0; n
< count
; n
++ )
5188 wxGridCellCoords cell
= cells
[n
];
5190 // If we are using attributes, then we may have just exposed another
5191 // cell in a partially-visible merged cluster of cells. If the "anchor"
5192 // (upper left) cell of this merged cluster is the cell indicated by
5193 // m_currentCellCoords, then we need to refresh the cell highlight even
5194 // though the "anchor" itself is not part of our update segment.
5195 if ( CanHaveAttributes() )
5199 GetCellSize(cell
.GetRow(), cell
.GetCol(), &rows
, &cols
);
5202 cell
.SetRow(cell
.GetRow() + rows
);
5205 cell
.SetCol(cell
.GetCol() + cols
);
5208 if ( cell
== m_currentCellCoords
)
5210 wxGridCellAttr
* attr
= GetCellAttr(m_currentCellCoords
);
5211 DrawCellHighlight(dc
, attr
);
5219 // This is used to redraw all grid lines e.g. when the grid line colour
5222 void wxGrid::DrawAllGridLines( wxDC
& dc
, const wxRegion
& WXUNUSED(reg
) )
5224 if ( !m_gridLinesEnabled
)
5227 int top
, bottom
, left
, right
;
5230 m_gridWin
->GetClientSize(&cw
, &ch
);
5231 CalcUnscrolledPosition( 0, 0, &left
, &top
);
5232 CalcUnscrolledPosition( cw
, ch
, &right
, &bottom
);
5234 // avoid drawing grid lines past the last row and col
5235 if ( m_gridLinesClipHorz
)
5240 const int lastColRight
= GetColRight(GetColAt(m_numCols
- 1));
5241 if ( right
> lastColRight
)
5242 right
= lastColRight
;
5245 if ( m_gridLinesClipVert
)
5250 const int lastRowBottom
= GetRowBottom(m_numRows
- 1);
5251 if ( bottom
> lastRowBottom
)
5252 bottom
= lastRowBottom
;
5255 // no gridlines inside multicells, clip them out
5256 int leftCol
= GetColPos( internalXToCol(left
) );
5257 int topRow
= internalYToRow(top
);
5258 int rightCol
= GetColPos( internalXToCol(right
) );
5259 int bottomRow
= internalYToRow(bottom
);
5261 wxRegion
clippedcells(0, 0, cw
, ch
);
5263 int cell_rows
, cell_cols
;
5266 for ( int j
= topRow
; j
<= bottomRow
; j
++ )
5268 for ( int colPos
= leftCol
; colPos
<= rightCol
; colPos
++ )
5270 int i
= GetColAt( colPos
);
5272 GetCellSize( j
, i
, &cell_rows
, &cell_cols
);
5273 if ((cell_rows
> 1) || (cell_cols
> 1))
5275 rect
= CellToRect(j
,i
);
5276 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
5277 clippedcells
.Subtract(rect
);
5279 else if ((cell_rows
< 0) || (cell_cols
< 0))
5281 rect
= CellToRect(j
+ cell_rows
, i
+ cell_cols
);
5282 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
5283 clippedcells
.Subtract(rect
);
5288 dc
.SetDeviceClippingRegion( clippedcells
);
5291 // horizontal grid lines
5292 for ( int i
= internalYToRow(top
); i
< m_numRows
; i
++ )
5294 int bot
= GetRowBottom(i
) - 1;
5301 dc
.SetPen( GetRowGridLinePen(i
) );
5302 dc
.DrawLine( left
, bot
, right
, bot
);
5306 // vertical grid lines
5307 for ( int colPos
= leftCol
; colPos
< m_numCols
; colPos
++ )
5309 int i
= GetColAt( colPos
);
5311 int colRight
= GetColRight(i
);
5313 if (GetLayoutDirection() != wxLayout_RightToLeft
)
5317 if ( colRight
> right
)
5320 if ( colRight
>= left
)
5322 dc
.SetPen( GetColGridLinePen(i
) );
5323 dc
.DrawLine( colRight
, top
, colRight
, bottom
);
5327 dc
.DestroyClippingRegion();
5330 void wxGrid::DrawRowLabels( wxDC
& dc
, const wxArrayInt
& rows
)
5335 const size_t numLabels
= rows
.GetCount();
5336 for ( size_t i
= 0; i
< numLabels
; i
++ )
5338 DrawRowLabel( dc
, rows
[i
] );
5342 void wxGrid::DrawRowLabel( wxDC
& dc
, int row
)
5344 if ( GetRowHeight(row
) <= 0 || m_rowLabelWidth
<= 0 )
5349 int rowTop
= GetRowTop(row
),
5350 rowBottom
= GetRowBottom(row
) - 1;
5352 dc
.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
)));
5353 dc
.DrawLine( m_rowLabelWidth
- 1, rowTop
, m_rowLabelWidth
- 1, rowBottom
);
5354 dc
.DrawLine( 0, rowTop
, 0, rowBottom
);
5355 dc
.DrawLine( 0, rowBottom
, m_rowLabelWidth
, rowBottom
);
5357 dc
.SetPen( *wxWHITE_PEN
);
5358 dc
.DrawLine( 1, rowTop
, 1, rowBottom
);
5359 dc
.DrawLine( 1, rowTop
, m_rowLabelWidth
- 1, rowTop
);
5361 dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT
);
5362 dc
.SetTextForeground( GetLabelTextColour() );
5363 dc
.SetFont( GetLabelFont() );
5366 GetRowLabelAlignment( &hAlign
, &vAlign
);
5369 rect
.SetY( GetRowTop(row
) + 2 );
5370 rect
.SetWidth( m_rowLabelWidth
- 4 );
5371 rect
.SetHeight( GetRowHeight(row
) - 4 );
5372 DrawTextRectangle( dc
, GetRowLabelValue( row
), rect
, hAlign
, vAlign
);
5375 void wxGrid::UseNativeColHeader(bool native
)
5377 if ( native
== m_useNativeHeader
)
5381 m_useNativeHeader
= native
;
5383 CreateColumnWindow();
5385 if ( m_useNativeHeader
)
5386 GetGridColHeader()->SetColumnCount(m_numCols
);
5390 void wxGrid::SetUseNativeColLabels( bool native
)
5392 wxASSERT_MSG( !m_useNativeHeader
,
5393 "doesn't make sense when using native header" );
5395 m_nativeColumnLabels
= native
;
5398 int height
= wxRendererNative::Get().GetHeaderButtonHeight( this );
5399 SetColLabelSize( height
);
5402 GetColLabelWindow()->Refresh();
5403 m_cornerLabelWin
->Refresh();
5406 void wxGrid::DrawColLabels( wxDC
& dc
,const wxArrayInt
& cols
)
5411 const size_t numLabels
= cols
.GetCount();
5412 for ( size_t i
= 0; i
< numLabels
; i
++ )
5414 DrawColLabel( dc
, cols
[i
] );
5418 void wxGrid::DrawCornerLabel(wxDC
& dc
)
5420 if ( m_nativeColumnLabels
)
5422 wxRect
rect(wxSize(m_rowLabelWidth
, m_colLabelHeight
));
5425 wxRendererNative::Get().DrawHeaderButton(m_cornerLabelWin
, dc
, rect
, 0);
5429 dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
)));
5430 dc
.DrawLine( m_rowLabelWidth
- 1, m_colLabelHeight
- 1,
5431 m_rowLabelWidth
- 1, 0 );
5432 dc
.DrawLine( m_rowLabelWidth
- 1, m_colLabelHeight
- 1,
5433 0, m_colLabelHeight
- 1 );
5434 dc
.DrawLine( 0, 0, m_rowLabelWidth
, 0 );
5435 dc
.DrawLine( 0, 0, 0, m_colLabelHeight
);
5437 dc
.SetPen( *wxWHITE_PEN
);
5438 dc
.DrawLine( 1, 1, m_rowLabelWidth
- 1, 1 );
5439 dc
.DrawLine( 1, 1, 1, m_colLabelHeight
- 1 );
5443 void wxGrid::DrawColLabel(wxDC
& dc
, int col
)
5445 if ( GetColWidth(col
) <= 0 || m_colLabelHeight
<= 0 )
5448 int colLeft
= GetColLeft(col
);
5450 wxRect
rect(colLeft
, 0, GetColWidth(col
), m_colLabelHeight
);
5452 if ( m_nativeColumnLabels
)
5454 wxRendererNative::Get().DrawHeaderButton
5456 GetColLabelWindow(),
5461 ? IsSortOrderAscending()
5462 ? wxHDR_SORT_ICON_UP
5463 : wxHDR_SORT_ICON_DOWN
5464 : wxHDR_SORT_ICON_NONE
5469 int colRight
= GetColRight(col
) - 1;
5471 dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
)));
5472 dc
.DrawLine( colRight
, 0,
5473 colRight
, m_colLabelHeight
- 1 );
5474 dc
.DrawLine( colLeft
, 0,
5476 dc
.DrawLine( colLeft
, m_colLabelHeight
- 1,
5477 colRight
+ 1, m_colLabelHeight
- 1 );
5479 dc
.SetPen( *wxWHITE_PEN
);
5480 dc
.DrawLine( colLeft
, 1, colLeft
, m_colLabelHeight
- 1 );
5481 dc
.DrawLine( colLeft
, 1, colRight
, 1 );
5484 dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT
);
5485 dc
.SetTextForeground( GetLabelTextColour() );
5486 dc
.SetFont( GetLabelFont() );
5489 GetColLabelAlignment( &hAlign
, &vAlign
);
5490 const int orient
= GetColLabelTextOrientation();
5493 DrawTextRectangle(dc
, GetColLabelValue(col
), rect
, hAlign
, vAlign
, orient
);
5496 // TODO: these 2 functions should be replaced with wxDC::DrawLabel() to which
5497 // we just have to add textOrientation support
5498 void wxGrid::DrawTextRectangle( wxDC
& dc
,
5499 const wxString
& value
,
5503 int textOrientation
)
5505 wxArrayString lines
;
5507 StringToLines( value
, lines
);
5509 DrawTextRectangle(dc
, lines
, rect
, horizAlign
, vertAlign
, textOrientation
);
5512 void wxGrid::DrawTextRectangle(wxDC
& dc
,
5513 const wxArrayString
& lines
,
5517 int textOrientation
)
5519 if ( lines
.empty() )
5522 wxDCClipper
clip(dc
, rect
);
5527 if ( textOrientation
== wxHORIZONTAL
)
5528 GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight
);
5530 GetTextBoxSize( dc
, lines
, &textHeight
, &textWidth
);
5534 switch ( vertAlign
)
5536 case wxALIGN_BOTTOM
:
5537 if ( textOrientation
== wxHORIZONTAL
)
5538 y
= rect
.y
+ (rect
.height
- textHeight
- 1);
5540 x
= rect
.x
+ rect
.width
- textWidth
;
5543 case wxALIGN_CENTRE
:
5544 if ( textOrientation
== wxHORIZONTAL
)
5545 y
= rect
.y
+ ((rect
.height
- textHeight
) / 2);
5547 x
= rect
.x
+ ((rect
.width
- textWidth
) / 2);
5552 if ( textOrientation
== wxHORIZONTAL
)
5559 // Align each line of a multi-line label
5560 size_t nLines
= lines
.GetCount();
5561 for ( size_t l
= 0; l
< nLines
; l
++ )
5563 const wxString
& line
= lines
[l
];
5567 *(textOrientation
== wxHORIZONTAL
? &y
: &x
) += dc
.GetCharHeight();
5571 wxCoord lineWidth
= 0,
5573 dc
.GetTextExtent(line
, &lineWidth
, &lineHeight
);
5575 switch ( horizAlign
)
5578 if ( textOrientation
== wxHORIZONTAL
)
5579 x
= rect
.x
+ (rect
.width
- lineWidth
- 1);
5581 y
= rect
.y
+ lineWidth
+ 1;
5584 case wxALIGN_CENTRE
:
5585 if ( textOrientation
== wxHORIZONTAL
)
5586 x
= rect
.x
+ ((rect
.width
- lineWidth
) / 2);
5588 y
= rect
.y
+ rect
.height
- ((rect
.height
- lineWidth
) / 2);
5593 if ( textOrientation
== wxHORIZONTAL
)
5596 y
= rect
.y
+ rect
.height
- 1;
5600 if ( textOrientation
== wxHORIZONTAL
)
5602 dc
.DrawText( line
, x
, y
);
5607 dc
.DrawRotatedText( line
, x
, y
, 90.0 );
5613 // Split multi-line text up into an array of strings.
5614 // Any existing contents of the string array are preserved.
5616 // TODO: refactor wxTextFile::Read() and reuse the same code from here
5617 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines
) const
5621 wxString eol
= wxTextFile::GetEOL( wxTextFileType_Unix
);
5622 wxString tVal
= wxTextFile::Translate( value
, wxTextFileType_Unix
);
5624 while ( startPos
< (int)tVal
.length() )
5626 pos
= tVal
.Mid(startPos
).Find( eol
);
5631 else if ( pos
== 0 )
5633 lines
.Add( wxEmptyString
);
5637 lines
.Add( tVal
.Mid(startPos
, pos
) );
5640 startPos
+= pos
+ 1;
5643 if ( startPos
< (int)tVal
.length() )
5645 lines
.Add( tVal
.Mid( startPos
) );
5649 void wxGrid::GetTextBoxSize( const wxDC
& dc
,
5650 const wxArrayString
& lines
,
5651 long *width
, long *height
) const
5655 wxCoord lineW
= 0, lineH
= 0;
5658 for ( i
= 0; i
< lines
.GetCount(); i
++ )
5660 dc
.GetTextExtent( lines
[i
], &lineW
, &lineH
);
5661 w
= wxMax( w
, lineW
);
5670 // ------ Batch processing.
5672 void wxGrid::EndBatch()
5674 if ( m_batchCount
> 0 )
5677 if ( !m_batchCount
)
5680 m_rowLabelWin
->Refresh();
5681 m_colWindow
->Refresh();
5682 m_cornerLabelWin
->Refresh();
5683 m_gridWin
->Refresh();
5688 // Use this, rather than wxWindow::Refresh(), to force an immediate
5689 // repainting of the grid. Has no effect if you are already inside a
5690 // BeginBatch / EndBatch block.
5692 void wxGrid::ForceRefresh()
5698 bool wxGrid::Enable(bool enable
)
5700 if ( !wxScrolledWindow::Enable(enable
) )
5703 // redraw in the new state
5704 m_gridWin
->Refresh();
5710 // ------ Edit control functions
5713 void wxGrid::EnableEditing( bool edit
)
5715 if ( edit
!= m_editable
)
5718 EnableCellEditControl(edit
);
5723 void wxGrid::EnableCellEditControl( bool enable
)
5728 if ( enable
!= m_cellEditCtrlEnabled
)
5732 if ( SendEvent(wxEVT_GRID_EDITOR_SHOWN
) == -1 )
5735 // this should be checked by the caller!
5736 wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") );
5738 // do it before ShowCellEditControl()
5739 m_cellEditCtrlEnabled
= enable
;
5741 ShowCellEditControl();
5745 SendEvent(wxEVT_GRID_EDITOR_HIDDEN
);
5747 HideCellEditControl();
5748 SaveEditControlValue();
5750 // do it after HideCellEditControl()
5751 m_cellEditCtrlEnabled
= enable
;
5756 bool wxGrid::IsCurrentCellReadOnly() const
5759 wxGridCellAttr
* attr
= ((wxGrid
*)this)->GetCellAttr(m_currentCellCoords
);
5760 bool readonly
= attr
->IsReadOnly();
5766 bool wxGrid::CanEnableCellControl() const
5768 return m_editable
&& (m_currentCellCoords
!= wxGridNoCellCoords
) &&
5769 !IsCurrentCellReadOnly();
5772 bool wxGrid::IsCellEditControlEnabled() const
5774 // the cell edit control might be disable for all cells or just for the
5775 // current one if it's read only
5776 return m_cellEditCtrlEnabled
? !IsCurrentCellReadOnly() : false;
5779 bool wxGrid::IsCellEditControlShown() const
5781 bool isShown
= false;
5783 if ( m_cellEditCtrlEnabled
)
5785 int row
= m_currentCellCoords
.GetRow();
5786 int col
= m_currentCellCoords
.GetCol();
5787 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
5788 wxGridCellEditor
* editor
= attr
->GetEditor((wxGrid
*) this, row
, col
);
5793 if ( editor
->IsCreated() )
5795 isShown
= editor
->GetControl()->IsShown();
5805 void wxGrid::ShowCellEditControl()
5807 if ( IsCellEditControlEnabled() )
5809 if ( !IsVisible( m_currentCellCoords
, false ) )
5811 m_cellEditCtrlEnabled
= false;
5816 wxRect rect
= CellToRect( m_currentCellCoords
);
5817 int row
= m_currentCellCoords
.GetRow();
5818 int col
= m_currentCellCoords
.GetCol();
5820 // if this is part of a multicell, find owner (topleft)
5821 int cell_rows
, cell_cols
;
5822 GetCellSize( row
, col
, &cell_rows
, &cell_cols
);
5823 if ( cell_rows
<= 0 || cell_cols
<= 0 )
5827 m_currentCellCoords
.SetRow( row
);
5828 m_currentCellCoords
.SetCol( col
);
5831 // erase the highlight and the cell contents because the editor
5832 // might not cover the entire cell
5833 wxClientDC
dc( m_gridWin
);
5835 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
5836 dc
.SetBrush(wxBrush(attr
->GetBackgroundColour()));
5837 dc
.SetPen(*wxTRANSPARENT_PEN
);
5838 dc
.DrawRectangle(rect
);
5840 // convert to scrolled coords
5841 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
5847 // cell is shifted by one pixel
5848 // However, don't allow x or y to become negative
5849 // since the SetSize() method interprets that as
5856 wxGridCellEditor
* editor
= attr
->GetEditor(this, row
, col
);
5857 if ( !editor
->IsCreated() )
5859 editor
->Create(m_gridWin
, wxID_ANY
,
5860 new wxGridCellEditorEvtHandler(this, editor
));
5862 wxGridEditorCreatedEvent
evt(GetId(),
5863 wxEVT_GRID_EDITOR_CREATED
,
5867 editor
->GetControl());
5868 GetEventHandler()->ProcessEvent(evt
);
5871 // resize editor to overflow into righthand cells if allowed
5872 int maxWidth
= rect
.width
;
5873 wxString value
= GetCellValue(row
, col
);
5874 if ( (value
!= wxEmptyString
) && (attr
->GetOverflow()) )
5877 GetTextExtent(value
, &maxWidth
, &y
, NULL
, NULL
, &attr
->GetFont());
5878 if (maxWidth
< rect
.width
)
5879 maxWidth
= rect
.width
;
5882 int client_right
= m_gridWin
->GetClientSize().GetWidth();
5883 if (rect
.x
+ maxWidth
> client_right
)
5884 maxWidth
= client_right
- rect
.x
;
5886 if ((maxWidth
> rect
.width
) && (col
< m_numCols
) && m_table
)
5888 GetCellSize( row
, col
, &cell_rows
, &cell_cols
);
5889 // may have changed earlier
5890 for (int i
= col
+ cell_cols
; i
< m_numCols
; i
++)
5893 GetCellSize( row
, i
, &c_rows
, &c_cols
);
5895 // looks weird going over a multicell
5896 if (m_table
->IsEmptyCell( row
, i
) &&
5897 (rect
.width
< maxWidth
) && (c_rows
== 1))
5899 rect
.width
+= GetColWidth( i
);
5905 if (rect
.GetRight() > client_right
)
5906 rect
.SetRight( client_right
- 1 );
5909 editor
->SetCellAttr( attr
);
5910 editor
->SetSize( rect
);
5912 editor
->GetControl()->Move(
5913 editor
->GetControl()->GetPosition().x
+ nXMove
,
5914 editor
->GetControl()->GetPosition().y
);
5915 editor
->Show( true, attr
);
5917 // recalc dimensions in case we need to
5918 // expand the scrolled window to account for editor
5921 editor
->BeginEdit(row
, col
, this);
5922 editor
->SetCellAttr(NULL
);
5930 void wxGrid::HideCellEditControl()
5932 if ( IsCellEditControlEnabled() )
5934 int row
= m_currentCellCoords
.GetRow();
5935 int col
= m_currentCellCoords
.GetCol();
5937 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
5938 wxGridCellEditor
*editor
= attr
->GetEditor(this, row
, col
);
5939 const bool editorHadFocus
= editor
->GetControl()->HasFocus();
5940 editor
->Show( false );
5944 // return the focus to the grid itself if the editor had it
5946 // note that we must not do this unconditionally to avoid stealing
5947 // focus from the window which just received it if we are hiding the
5948 // editor precisely because we lost focus
5949 if ( editorHadFocus
)
5950 m_gridWin
->SetFocus();
5952 // refresh whole row to the right
5953 wxRect
rect( CellToRect(row
, col
) );
5954 CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y
);
5955 rect
.width
= m_gridWin
->GetClientSize().GetWidth() - rect
.x
;
5958 // ensure that the pixels under the focus ring get refreshed as well
5959 rect
.Inflate(10, 10);
5962 m_gridWin
->Refresh( false, &rect
);
5966 void wxGrid::SaveEditControlValue()
5968 if ( IsCellEditControlEnabled() )
5970 int row
= m_currentCellCoords
.GetRow();
5971 int col
= m_currentCellCoords
.GetCol();
5973 wxString oldval
= GetCellValue(row
, col
);
5975 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
5976 wxGridCellEditor
* editor
= attr
->GetEditor(this, row
, col
);
5979 bool changed
= editor
->EndEdit(oldval
, &newval
);
5981 if ( changed
&& SendEvent(wxEVT_GRID_CELL_CHANGING
, newval
) != -1 )
5983 editor
->ApplyEdit(row
, col
, this);
5985 // for compatibility reasons dating back to wx 2.8 when this event
5986 // was called wxEVT_GRID_CELL_CHANGE and wxEVT_GRID_CELL_CHANGING
5987 // didn't exist we allow vetoing this one too
5988 if ( SendEvent(wxEVT_GRID_CELL_CHANGED
, oldval
) == -1 )
5990 // Event has been vetoed, set the data back.
5991 SetCellValue(row
, col
, oldval
);
6001 // ------ Grid location functions
6002 // Note that all of these functions work with the logical coordinates of
6003 // grid cells and labels so you will need to convert from device
6004 // coordinates for mouse events etc.
6007 wxGridCellCoords
wxGrid::XYToCell(int x
, int y
) const
6009 int row
= YToRow(y
);
6010 int col
= XToCol(x
);
6012 return row
== -1 || col
== -1 ? wxGridNoCellCoords
6013 : wxGridCellCoords(row
, col
);
6016 // compute row or column from some (unscrolled) coordinate value, using either
6017 // m_defaultRowHeight/m_defaultColWidth or binary search on array of
6018 // m_rowBottoms/m_colRights to do it quickly (linear search shouldn't be used
6020 int wxGrid::PosToLinePos(int coord
,
6022 const wxGridOperations
& oper
) const
6024 const int numLines
= oper
.GetNumberOfLines(this);
6027 return clipToMinMax
&& numLines
> 0 ? 0 : wxNOT_FOUND
;
6029 const int defaultLineSize
= oper
.GetDefaultLineSize(this);
6030 wxCHECK_MSG( defaultLineSize
, -1, "can't have 0 default line size" );
6032 int maxPos
= coord
/ defaultLineSize
,
6035 // check for the simplest case: if we have no explicit line sizes
6036 // configured, then we already know the line this position falls in
6037 const wxArrayInt
& lineEnds
= oper
.GetLineEnds(this);
6038 if ( lineEnds
.empty() )
6040 if ( maxPos
< numLines
)
6043 return clipToMinMax
? numLines
- 1 : -1;
6047 // adjust maxPos before starting the binary search
6048 if ( maxPos
>= numLines
)
6050 maxPos
= numLines
- 1;
6054 if ( coord
>= lineEnds
[oper
.GetLineAt(this, maxPos
)])
6057 const int minDist
= oper
.GetMinimalAcceptableLineSize(this);
6059 maxPos
= coord
/ minDist
;
6061 maxPos
= numLines
- 1;
6064 if ( maxPos
>= numLines
)
6065 maxPos
= numLines
- 1;
6068 // check if the position is beyond the last column
6069 const int lineAtMaxPos
= oper
.GetLineAt(this, maxPos
);
6070 if ( coord
>= lineEnds
[lineAtMaxPos
] )
6071 return clipToMinMax
? maxPos
: -1;
6073 // or before the first one
6074 const int lineAt0
= oper
.GetLineAt(this, 0);
6075 if ( coord
< lineEnds
[lineAt0
] )
6079 // finally do perform the binary search
6080 while ( minPos
< maxPos
)
6082 wxCHECK_MSG( lineEnds
[oper
.GetLineAt(this, minPos
)] <= coord
&&
6083 coord
< lineEnds
[oper
.GetLineAt(this, maxPos
)],
6085 "wxGrid: internal error in PosToLinePos()" );
6087 if ( coord
>= lineEnds
[oper
.GetLineAt(this, maxPos
- 1)] )
6092 const int median
= minPos
+ (maxPos
- minPos
+ 1) / 2;
6093 if ( coord
< lineEnds
[oper
.GetLineAt(this, median
)] )
6103 wxGrid::PosToLine(int coord
,
6105 const wxGridOperations
& oper
) const
6107 int pos
= PosToLinePos(coord
, clipToMinMax
, oper
);
6109 return pos
== wxNOT_FOUND
? wxNOT_FOUND
: oper
.GetLineAt(this, pos
);
6112 int wxGrid::YToRow(int y
, bool clipToMinMax
) const
6114 return PosToLine(y
, clipToMinMax
, wxGridRowOperations());
6117 int wxGrid::XToCol(int x
, bool clipToMinMax
) const
6119 return PosToLine(x
, clipToMinMax
, wxGridColumnOperations());
6122 int wxGrid::XToPos(int x
) const
6124 return PosToLinePos(x
, true /* clip */, wxGridColumnOperations());
6127 // return the row number that that the y coord is near the edge of, or -1 if
6128 // not near an edge.
6130 // coords can only possibly be near an edge if
6131 // (a) the row/column is large enough to still allow for an "inner" area
6132 // that is _not_ near the edge (i.e., if the height/width is smaller
6133 // than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be
6136 // (b) resizing rows/columns (the thing for which edge detection is
6137 // relevant at all) is enabled.
6139 int wxGrid::PosToEdgeOfLine(int pos
, const wxGridOperations
& oper
) const
6141 if ( !oper
.CanResizeLines(this) )
6144 const int line
= oper
.PosToLine(this, pos
, true);
6146 if ( oper
.GetLineSize(this, line
) > WXGRID_LABEL_EDGE_ZONE
)
6148 // We know that we are in this line, test whether we are close enough
6149 // to start or end border, respectively.
6150 if ( abs(oper
.GetLineEndPos(this, line
) - pos
) < WXGRID_LABEL_EDGE_ZONE
)
6152 else if ( line
> 0 &&
6153 pos
- oper
.GetLineStartPos(this,
6154 line
) < WXGRID_LABEL_EDGE_ZONE
)
6161 int wxGrid::YToEdgeOfRow(int y
) const
6163 return PosToEdgeOfLine(y
, wxGridRowOperations());
6166 int wxGrid::XToEdgeOfCol(int x
) const
6168 return PosToEdgeOfLine(x
, wxGridColumnOperations());
6171 wxRect
wxGrid::CellToRect( int row
, int col
) const
6173 wxRect
rect( -1, -1, -1, -1 );
6175 if ( row
>= 0 && row
< m_numRows
&&
6176 col
>= 0 && col
< m_numCols
)
6178 int i
, cell_rows
, cell_cols
;
6179 rect
.width
= rect
.height
= 0;
6180 GetCellSize( row
, col
, &cell_rows
, &cell_cols
);
6181 // if negative then find multicell owner
6186 GetCellSize( row
, col
, &cell_rows
, &cell_cols
);
6188 rect
.x
= GetColLeft(col
);
6189 rect
.y
= GetRowTop(row
);
6190 for (i
=col
; i
< col
+ cell_cols
; i
++)
6191 rect
.width
+= GetColWidth(i
);
6192 for (i
=row
; i
< row
+ cell_rows
; i
++)
6193 rect
.height
+= GetRowHeight(i
);
6196 // if grid lines are enabled, then the area of the cell is a bit smaller
6197 if (m_gridLinesEnabled
)
6206 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible
) const
6208 // get the cell rectangle in logical coords
6210 wxRect
r( CellToRect( row
, col
) );
6212 // convert to device coords
6214 int left
, top
, right
, bottom
;
6215 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
6216 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
6218 // check against the client area of the grid window
6220 m_gridWin
->GetClientSize( &cw
, &ch
);
6222 if ( wholeCellVisible
)
6224 // is the cell wholly visible ?
6225 return ( left
>= 0 && right
<= cw
&&
6226 top
>= 0 && bottom
<= ch
);
6230 // is the cell partly visible ?
6232 return ( ((left
>= 0 && left
< cw
) || (right
> 0 && right
<= cw
)) &&
6233 ((top
>= 0 && top
< ch
) || (bottom
> 0 && bottom
<= ch
)) );
6237 // make the specified cell location visible by doing a minimal amount
6240 void wxGrid::MakeCellVisible( int row
, int col
)
6243 int xpos
= -1, ypos
= -1;
6245 if ( row
>= 0 && row
< m_numRows
&&
6246 col
>= 0 && col
< m_numCols
)
6248 // get the cell rectangle in logical coords
6249 wxRect
r( CellToRect( row
, col
) );
6251 // convert to device coords
6252 int left
, top
, right
, bottom
;
6253 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
6254 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
6257 m_gridWin
->GetClientSize( &cw
, &ch
);
6263 else if ( bottom
> ch
)
6265 int h
= r
.GetHeight();
6267 for ( i
= row
- 1; i
>= 0; i
-- )
6269 int rowHeight
= GetRowHeight(i
);
6270 if ( h
+ rowHeight
> ch
)
6277 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
6278 // have rounding errors (this is important, because if we do,
6279 // we might not scroll at all and some cells won't be redrawn)
6281 // Sometimes GRID_SCROLL_LINE / 2 is not enough,
6282 // so just add a full scroll unit...
6283 ypos
+= m_scrollLineY
;
6286 // special handling for wide cells - show always left part of the cell!
6287 // Otherwise, e.g. when stepping from row to row, it would jump between
6288 // left and right part of the cell on every step!
6290 if ( left
< 0 || (right
- left
) >= cw
)
6294 else if ( right
> cw
)
6296 // position the view so that the cell is on the right
6298 CalcUnscrolledPosition(0, 0, &x0
, &y0
);
6299 xpos
= x0
+ (right
- cw
);
6301 // see comment for ypos above
6302 xpos
+= m_scrollLineX
;
6305 if ( xpos
!= -1 || ypos
!= -1 )
6308 xpos
/= m_scrollLineX
;
6310 ypos
/= m_scrollLineY
;
6311 Scroll( xpos
, ypos
);
6318 // ------ Grid cursor movement functions
6322 wxGrid::DoMoveCursor(bool expandSelection
,
6323 const wxGridDirectionOperations
& diroper
)
6325 if ( m_currentCellCoords
== wxGridNoCellCoords
)
6328 if ( expandSelection
)
6330 wxGridCellCoords coords
= m_selectedBlockCorner
;
6331 if ( coords
== wxGridNoCellCoords
)
6332 coords
= m_currentCellCoords
;
6334 if ( diroper
.IsAtBoundary(coords
) )
6337 diroper
.Advance(coords
);
6339 UpdateBlockBeingSelected(m_currentCellCoords
, coords
);
6341 else // don't expand selection
6345 if ( diroper
.IsAtBoundary(m_currentCellCoords
) )
6348 wxGridCellCoords coords
= m_currentCellCoords
;
6349 diroper
.Advance(coords
);
6357 bool wxGrid::MoveCursorUp(bool expandSelection
)
6359 return DoMoveCursor(expandSelection
,
6360 wxGridBackwardOperations(this, wxGridRowOperations()));
6363 bool wxGrid::MoveCursorDown(bool expandSelection
)
6365 return DoMoveCursor(expandSelection
,
6366 wxGridForwardOperations(this, wxGridRowOperations()));
6369 bool wxGrid::MoveCursorLeft(bool expandSelection
)
6371 return DoMoveCursor(expandSelection
,
6372 wxGridBackwardOperations(this, wxGridColumnOperations()));
6375 bool wxGrid::MoveCursorRight(bool expandSelection
)
6377 return DoMoveCursor(expandSelection
,
6378 wxGridForwardOperations(this, wxGridColumnOperations()));
6381 bool wxGrid::DoMoveCursorByPage(const wxGridDirectionOperations
& diroper
)
6383 if ( m_currentCellCoords
== wxGridNoCellCoords
)
6386 if ( diroper
.IsAtBoundary(m_currentCellCoords
) )
6389 const int oldRow
= m_currentCellCoords
.GetRow();
6390 int newRow
= diroper
.MoveByPixelDistance(oldRow
, m_gridWin
->GetClientSize().y
);
6391 if ( newRow
== oldRow
)
6393 wxGridCellCoords
coords(m_currentCellCoords
);
6394 diroper
.Advance(coords
);
6395 newRow
= coords
.GetRow();
6398 GoToCell(newRow
, m_currentCellCoords
.GetCol());
6403 bool wxGrid::MovePageUp()
6405 return DoMoveCursorByPage(
6406 wxGridBackwardOperations(this, wxGridRowOperations()));
6409 bool wxGrid::MovePageDown()
6411 return DoMoveCursorByPage(
6412 wxGridForwardOperations(this, wxGridRowOperations()));
6415 // helper of DoMoveCursorByBlock(): advance the cell coordinates using diroper
6416 // until we find a non-empty cell or reach the grid end
6418 wxGrid::AdvanceToNextNonEmpty(wxGridCellCoords
& coords
,
6419 const wxGridDirectionOperations
& diroper
)
6421 while ( !diroper
.IsAtBoundary(coords
) )
6423 diroper
.Advance(coords
);
6424 if ( !m_table
->IsEmpty(coords
) )
6430 wxGrid::DoMoveCursorByBlock(bool expandSelection
,
6431 const wxGridDirectionOperations
& diroper
)
6433 if ( !m_table
|| m_currentCellCoords
== wxGridNoCellCoords
)
6436 if ( diroper
.IsAtBoundary(m_currentCellCoords
) )
6439 wxGridCellCoords
coords(m_currentCellCoords
);
6440 if ( m_table
->IsEmpty(coords
) )
6442 // we are in an empty cell: find the next block of non-empty cells
6443 AdvanceToNextNonEmpty(coords
, diroper
);
6445 else // current cell is not empty
6447 diroper
.Advance(coords
);
6448 if ( m_table
->IsEmpty(coords
) )
6450 // we started at the end of a block, find the next one
6451 AdvanceToNextNonEmpty(coords
, diroper
);
6453 else // we're in a middle of a block
6455 // go to the end of it, i.e. find the last cell before the next
6457 while ( !diroper
.IsAtBoundary(coords
) )
6459 wxGridCellCoords
coordsNext(coords
);
6460 diroper
.Advance(coordsNext
);
6461 if ( m_table
->IsEmpty(coordsNext
) )
6464 coords
= coordsNext
;
6469 if ( expandSelection
)
6471 UpdateBlockBeingSelected(m_currentCellCoords
, coords
);
6482 bool wxGrid::MoveCursorUpBlock(bool expandSelection
)
6484 return DoMoveCursorByBlock(
6486 wxGridBackwardOperations(this, wxGridRowOperations())
6490 bool wxGrid::MoveCursorDownBlock( bool expandSelection
)
6492 return DoMoveCursorByBlock(
6494 wxGridForwardOperations(this, wxGridRowOperations())
6498 bool wxGrid::MoveCursorLeftBlock( bool expandSelection
)
6500 return DoMoveCursorByBlock(
6502 wxGridBackwardOperations(this, wxGridColumnOperations())
6506 bool wxGrid::MoveCursorRightBlock( bool expandSelection
)
6508 return DoMoveCursorByBlock(
6510 wxGridForwardOperations(this, wxGridColumnOperations())
6515 // ------ Label values and formatting
6518 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert
) const
6521 *horiz
= m_rowLabelHorizAlign
;
6523 *vert
= m_rowLabelVertAlign
;
6526 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert
) const
6529 *horiz
= m_colLabelHorizAlign
;
6531 *vert
= m_colLabelVertAlign
;
6534 int wxGrid::GetColLabelTextOrientation() const
6536 return m_colLabelTextOrientation
;
6539 wxString
wxGrid::GetRowLabelValue( int row
) const
6543 return m_table
->GetRowLabelValue( row
);
6553 wxString
wxGrid::GetColLabelValue( int col
) const
6557 return m_table
->GetColLabelValue( col
);
6567 void wxGrid::SetRowLabelSize( int width
)
6569 wxASSERT( width
>= 0 || width
== wxGRID_AUTOSIZE
);
6571 if ( width
== wxGRID_AUTOSIZE
)
6573 width
= CalcColOrRowLabelAreaMinSize(wxGRID_ROW
);
6576 if ( width
!= m_rowLabelWidth
)
6580 m_rowLabelWin
->Show( false );
6581 m_cornerLabelWin
->Show( false );
6583 else if ( m_rowLabelWidth
== 0 )
6585 m_rowLabelWin
->Show( true );
6586 if ( m_colLabelHeight
> 0 )
6587 m_cornerLabelWin
->Show( true );
6590 m_rowLabelWidth
= width
;
6592 wxScrolledWindow::Refresh( true );
6596 void wxGrid::SetColLabelSize( int height
)
6598 wxASSERT( height
>=0 || height
== wxGRID_AUTOSIZE
);
6600 if ( height
== wxGRID_AUTOSIZE
)
6602 height
= CalcColOrRowLabelAreaMinSize(wxGRID_COLUMN
);
6605 if ( height
!= m_colLabelHeight
)
6609 m_colWindow
->Show( false );
6610 m_cornerLabelWin
->Show( false );
6612 else if ( m_colLabelHeight
== 0 )
6614 m_colWindow
->Show( true );
6615 if ( m_rowLabelWidth
> 0 )
6616 m_cornerLabelWin
->Show( true );
6619 m_colLabelHeight
= height
;
6621 wxScrolledWindow::Refresh( true );
6625 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour
)
6627 if ( m_labelBackgroundColour
!= colour
)
6629 m_labelBackgroundColour
= colour
;
6630 m_rowLabelWin
->SetBackgroundColour( colour
);
6631 m_colWindow
->SetBackgroundColour( colour
);
6632 m_cornerLabelWin
->SetBackgroundColour( colour
);
6634 if ( !GetBatchCount() )
6636 m_rowLabelWin
->Refresh();
6637 m_colWindow
->Refresh();
6638 m_cornerLabelWin
->Refresh();
6643 void wxGrid::SetLabelTextColour( const wxColour
& colour
)
6645 if ( m_labelTextColour
!= colour
)
6647 m_labelTextColour
= colour
;
6648 if ( !GetBatchCount() )
6650 m_rowLabelWin
->Refresh();
6651 m_colWindow
->Refresh();
6656 void wxGrid::SetLabelFont( const wxFont
& font
)
6659 if ( !GetBatchCount() )
6661 m_rowLabelWin
->Refresh();
6662 m_colWindow
->Refresh();
6666 void wxGrid::SetRowLabelAlignment( int horiz
, int vert
)
6668 // allow old (incorrect) defs to be used
6671 case wxLEFT
: horiz
= wxALIGN_LEFT
; break;
6672 case wxRIGHT
: horiz
= wxALIGN_RIGHT
; break;
6673 case wxCENTRE
: horiz
= wxALIGN_CENTRE
; break;
6678 case wxTOP
: vert
= wxALIGN_TOP
; break;
6679 case wxBOTTOM
: vert
= wxALIGN_BOTTOM
; break;
6680 case wxCENTRE
: vert
= wxALIGN_CENTRE
; break;
6683 if ( horiz
== wxALIGN_LEFT
|| horiz
== wxALIGN_CENTRE
|| horiz
== wxALIGN_RIGHT
)
6685 m_rowLabelHorizAlign
= horiz
;
6688 if ( vert
== wxALIGN_TOP
|| vert
== wxALIGN_CENTRE
|| vert
== wxALIGN_BOTTOM
)
6690 m_rowLabelVertAlign
= vert
;
6693 if ( !GetBatchCount() )
6695 m_rowLabelWin
->Refresh();
6699 void wxGrid::SetColLabelAlignment( int horiz
, int vert
)
6701 // allow old (incorrect) defs to be used
6704 case wxLEFT
: horiz
= wxALIGN_LEFT
; break;
6705 case wxRIGHT
: horiz
= wxALIGN_RIGHT
; break;
6706 case wxCENTRE
: horiz
= wxALIGN_CENTRE
; break;
6711 case wxTOP
: vert
= wxALIGN_TOP
; break;
6712 case wxBOTTOM
: vert
= wxALIGN_BOTTOM
; break;
6713 case wxCENTRE
: vert
= wxALIGN_CENTRE
; break;
6716 if ( horiz
== wxALIGN_LEFT
|| horiz
== wxALIGN_CENTRE
|| horiz
== wxALIGN_RIGHT
)
6718 m_colLabelHorizAlign
= horiz
;
6721 if ( vert
== wxALIGN_TOP
|| vert
== wxALIGN_CENTRE
|| vert
== wxALIGN_BOTTOM
)
6723 m_colLabelVertAlign
= vert
;
6726 if ( !GetBatchCount() )
6728 m_colWindow
->Refresh();
6732 // Note: under MSW, the default column label font must be changed because it
6733 // does not support vertical printing
6735 // Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD);
6736 // pGrid->SetLabelFont(font);
6737 // pGrid->SetColLabelTextOrientation(wxVERTICAL);
6739 void wxGrid::SetColLabelTextOrientation( int textOrientation
)
6741 if ( textOrientation
== wxHORIZONTAL
|| textOrientation
== wxVERTICAL
)
6742 m_colLabelTextOrientation
= textOrientation
;
6744 if ( !GetBatchCount() )
6745 m_colWindow
->Refresh();
6748 void wxGrid::SetRowLabelValue( int row
, const wxString
& s
)
6752 m_table
->SetRowLabelValue( row
, s
);
6753 if ( !GetBatchCount() )
6755 wxRect rect
= CellToRect( row
, 0 );
6756 if ( rect
.height
> 0 )
6758 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
);
6760 rect
.width
= m_rowLabelWidth
;
6761 m_rowLabelWin
->Refresh( true, &rect
);
6767 void wxGrid::SetColLabelValue( int col
, const wxString
& s
)
6771 m_table
->SetColLabelValue( col
, s
);
6772 if ( !GetBatchCount() )
6774 if ( m_useNativeHeader
)
6776 GetGridColHeader()->UpdateColumn(col
);
6780 wxRect rect
= CellToRect( 0, col
);
6781 if ( rect
.width
> 0 )
6783 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
);
6785 rect
.height
= m_colLabelHeight
;
6786 GetColLabelWindow()->Refresh( true, &rect
);
6793 void wxGrid::SetGridLineColour( const wxColour
& colour
)
6795 if ( m_gridLineColour
!= colour
)
6797 m_gridLineColour
= colour
;
6799 if ( GridLinesEnabled() )
6804 void wxGrid::SetCellHighlightColour( const wxColour
& colour
)
6806 if ( m_cellHighlightColour
!= colour
)
6808 m_cellHighlightColour
= colour
;
6810 wxClientDC
dc( m_gridWin
);
6812 wxGridCellAttr
* attr
= GetCellAttr(m_currentCellCoords
);
6813 DrawCellHighlight(dc
, attr
);
6818 void wxGrid::SetCellHighlightPenWidth(int width
)
6820 if (m_cellHighlightPenWidth
!= width
)
6822 m_cellHighlightPenWidth
= width
;
6824 // Just redrawing the cell highlight is not enough since that won't
6825 // make any visible change if the the thickness is getting smaller.
6826 int row
= m_currentCellCoords
.GetRow();
6827 int col
= m_currentCellCoords
.GetCol();
6828 if ( row
== -1 || col
== -1 || GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
6831 wxRect rect
= CellToRect(row
, col
);
6832 m_gridWin
->Refresh(true, &rect
);
6836 void wxGrid::SetCellHighlightROPenWidth(int width
)
6838 if (m_cellHighlightROPenWidth
!= width
)
6840 m_cellHighlightROPenWidth
= width
;
6842 // Just redrawing the cell highlight is not enough since that won't
6843 // make any visible change if the the thickness is getting smaller.
6844 int row
= m_currentCellCoords
.GetRow();
6845 int col
= m_currentCellCoords
.GetCol();
6846 if ( row
== -1 || col
== -1 ||
6847 GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 )
6850 wxRect rect
= CellToRect(row
, col
);
6851 m_gridWin
->Refresh(true, &rect
);
6855 void wxGrid::RedrawGridLines()
6857 // the lines will be redrawn when the window is thawn
6858 if ( GetBatchCount() )
6861 if ( GridLinesEnabled() )
6863 wxClientDC
dc( m_gridWin
);
6865 DrawAllGridLines( dc
, wxRegion() );
6867 else // remove the grid lines
6869 m_gridWin
->Refresh();
6873 void wxGrid::EnableGridLines( bool enable
)
6875 if ( enable
!= m_gridLinesEnabled
)
6877 m_gridLinesEnabled
= enable
;
6883 void wxGrid::DoClipGridLines(bool& var
, bool clip
)
6889 if ( GridLinesEnabled() )
6894 int wxGrid::GetDefaultRowSize() const
6896 return m_defaultRowHeight
;
6899 int wxGrid::GetRowSize( int row
) const
6901 wxCHECK_MSG( row
>= 0 && row
< m_numRows
, 0, _T("invalid row index") );
6903 return GetRowHeight(row
);
6906 int wxGrid::GetDefaultColSize() const
6908 return m_defaultColWidth
;
6911 int wxGrid::GetColSize( int col
) const
6913 wxCHECK_MSG( col
>= 0 && col
< m_numCols
, 0, _T("invalid column index") );
6915 return GetColWidth(col
);
6918 // ============================================================================
6919 // access to the grid attributes: each of them has a default value in the grid
6920 // itself and may be overidden on a per-cell basis
6921 // ============================================================================
6923 // ----------------------------------------------------------------------------
6924 // setting default attributes
6925 // ----------------------------------------------------------------------------
6927 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& col
)
6929 m_defaultCellAttr
->SetBackgroundColour(col
);
6931 m_gridWin
->SetBackgroundColour(col
);
6935 void wxGrid::SetDefaultCellTextColour( const wxColour
& col
)
6937 m_defaultCellAttr
->SetTextColour(col
);
6940 void wxGrid::SetDefaultCellAlignment( int horiz
, int vert
)
6942 m_defaultCellAttr
->SetAlignment(horiz
, vert
);
6945 void wxGrid::SetDefaultCellOverflow( bool allow
)
6947 m_defaultCellAttr
->SetOverflow(allow
);
6950 void wxGrid::SetDefaultCellFont( const wxFont
& font
)
6952 m_defaultCellAttr
->SetFont(font
);
6955 // For editors and renderers the type registry takes precedence over the
6956 // default attr, so we need to register the new editor/renderer for the string
6957 // data type in order to make setting a default editor/renderer appear to
6960 void wxGrid::SetDefaultRenderer(wxGridCellRenderer
*renderer
)
6962 RegisterDataType(wxGRID_VALUE_STRING
,
6964 GetDefaultEditorForType(wxGRID_VALUE_STRING
));
6967 void wxGrid::SetDefaultEditor(wxGridCellEditor
*editor
)
6969 RegisterDataType(wxGRID_VALUE_STRING
,
6970 GetDefaultRendererForType(wxGRID_VALUE_STRING
),
6974 // ----------------------------------------------------------------------------
6975 // access to the default attributes
6976 // ----------------------------------------------------------------------------
6978 wxColour
wxGrid::GetDefaultCellBackgroundColour() const
6980 return m_defaultCellAttr
->GetBackgroundColour();
6983 wxColour
wxGrid::GetDefaultCellTextColour() const
6985 return m_defaultCellAttr
->GetTextColour();
6988 wxFont
wxGrid::GetDefaultCellFont() const
6990 return m_defaultCellAttr
->GetFont();
6993 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert
) const
6995 m_defaultCellAttr
->GetAlignment(horiz
, vert
);
6998 bool wxGrid::GetDefaultCellOverflow() const
7000 return m_defaultCellAttr
->GetOverflow();
7003 wxGridCellRenderer
*wxGrid::GetDefaultRenderer() const
7005 return m_defaultCellAttr
->GetRenderer(NULL
, 0, 0);
7008 wxGridCellEditor
*wxGrid::GetDefaultEditor() const
7010 return m_defaultCellAttr
->GetEditor(NULL
, 0, 0);
7013 // ----------------------------------------------------------------------------
7014 // access to cell attributes
7015 // ----------------------------------------------------------------------------
7017 wxColour
wxGrid::GetCellBackgroundColour(int row
, int col
) const
7019 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
7020 wxColour colour
= attr
->GetBackgroundColour();
7026 wxColour
wxGrid::GetCellTextColour( int row
, int col
) const
7028 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
7029 wxColour colour
= attr
->GetTextColour();
7035 wxFont
wxGrid::GetCellFont( int row
, int col
) const
7037 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
7038 wxFont font
= attr
->GetFont();
7044 void wxGrid::GetCellAlignment( int row
, int col
, int *horiz
, int *vert
) const
7046 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
7047 attr
->GetAlignment(horiz
, vert
);
7051 bool wxGrid::GetCellOverflow( int row
, int col
) const
7053 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
7054 bool allow
= attr
->GetOverflow();
7060 void wxGrid::GetCellSize( int row
, int col
, int *num_rows
, int *num_cols
) const
7062 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
7063 attr
->GetSize( num_rows
, num_cols
);
7067 wxGridCellRenderer
* wxGrid::GetCellRenderer(int row
, int col
) const
7069 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
7070 wxGridCellRenderer
* renderer
= attr
->GetRenderer(this, row
, col
);
7076 wxGridCellEditor
* wxGrid::GetCellEditor(int row
, int col
) const
7078 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
7079 wxGridCellEditor
* editor
= attr
->GetEditor(this, row
, col
);
7085 bool wxGrid::IsReadOnly(int row
, int col
) const
7087 wxGridCellAttr
* attr
= GetCellAttr(row
, col
);
7088 bool isReadOnly
= attr
->IsReadOnly();
7094 // ----------------------------------------------------------------------------
7095 // attribute support: cache, automatic provider creation, ...
7096 // ----------------------------------------------------------------------------
7098 bool wxGrid::CanHaveAttributes() const
7105 return m_table
->CanHaveAttributes();
7108 void wxGrid::ClearAttrCache()
7110 if ( m_attrCache
.row
!= -1 )
7112 wxGridCellAttr
*oldAttr
= m_attrCache
.attr
;
7113 m_attrCache
.attr
= NULL
;
7114 m_attrCache
.row
= -1;
7115 // wxSafeDecRec(...) might cause event processing that accesses
7116 // the cached attribute, if one exists (e.g. by deleting the
7117 // editor stored within the attribute). Therefore it is important
7118 // to invalidate the cache before calling wxSafeDecRef!
7119 wxSafeDecRef(oldAttr
);
7123 void wxGrid::CacheAttr(int row
, int col
, wxGridCellAttr
*attr
) const
7127 wxGrid
*self
= (wxGrid
*)this; // const_cast
7129 self
->ClearAttrCache();
7130 self
->m_attrCache
.row
= row
;
7131 self
->m_attrCache
.col
= col
;
7132 self
->m_attrCache
.attr
= attr
;
7137 bool wxGrid::LookupAttr(int row
, int col
, wxGridCellAttr
**attr
) const
7139 if ( row
== m_attrCache
.row
&& col
== m_attrCache
.col
)
7141 *attr
= m_attrCache
.attr
;
7142 wxSafeIncRef(m_attrCache
.attr
);
7144 #ifdef DEBUG_ATTR_CACHE
7145 gs_nAttrCacheHits
++;
7152 #ifdef DEBUG_ATTR_CACHE
7153 gs_nAttrCacheMisses
++;
7160 wxGridCellAttr
*wxGrid::GetCellAttr(int row
, int col
) const
7162 wxGridCellAttr
*attr
= NULL
;
7163 // Additional test to avoid looking at the cache e.g. for
7164 // wxNoCellCoords, as this will confuse memory management.
7167 if ( !LookupAttr(row
, col
, &attr
) )
7169 attr
= m_table
? m_table
->GetAttr(row
, col
, wxGridCellAttr::Any
)
7171 CacheAttr(row
, col
, attr
);
7177 attr
->SetDefAttr(m_defaultCellAttr
);
7181 attr
= m_defaultCellAttr
;
7188 wxGridCellAttr
*wxGrid::GetOrCreateCellAttr(int row
, int col
) const
7190 wxGridCellAttr
*attr
= NULL
;
7191 bool canHave
= ((wxGrid
*)this)->CanHaveAttributes();
7193 wxCHECK_MSG( canHave
, attr
, _T("Cell attributes not allowed"));
7194 wxCHECK_MSG( m_table
, attr
, _T("must have a table") );
7196 attr
= m_table
->GetAttr(row
, col
, wxGridCellAttr::Cell
);
7199 attr
= new wxGridCellAttr(m_defaultCellAttr
);
7201 // artificially inc the ref count to match DecRef() in caller
7203 m_table
->SetAttr(attr
, row
, col
);
7209 // ----------------------------------------------------------------------------
7210 // setting column attributes (wrappers around SetColAttr)
7211 // ----------------------------------------------------------------------------
7213 void wxGrid::SetColFormatBool(int col
)
7215 SetColFormatCustom(col
, wxGRID_VALUE_BOOL
);
7218 void wxGrid::SetColFormatNumber(int col
)
7220 SetColFormatCustom(col
, wxGRID_VALUE_NUMBER
);
7223 void wxGrid::SetColFormatFloat(int col
, int width
, int precision
)
7225 wxString typeName
= wxGRID_VALUE_FLOAT
;
7226 if ( (width
!= -1) || (precision
!= -1) )
7228 typeName
<< _T(':') << width
<< _T(',') << precision
;
7231 SetColFormatCustom(col
, typeName
);
7234 void wxGrid::SetColFormatCustom(int col
, const wxString
& typeName
)
7236 wxGridCellAttr
*attr
= m_table
->GetAttr(-1, col
, wxGridCellAttr::Col
);
7238 attr
= new wxGridCellAttr
;
7239 wxGridCellRenderer
*renderer
= GetDefaultRendererForType(typeName
);
7240 attr
->SetRenderer(renderer
);
7241 wxGridCellEditor
*editor
= GetDefaultEditorForType(typeName
);
7242 attr
->SetEditor(editor
);
7244 SetColAttr(col
, attr
);
7248 // ----------------------------------------------------------------------------
7249 // setting cell attributes: this is forwarded to the table
7250 // ----------------------------------------------------------------------------
7252 void wxGrid::SetAttr(int row
, int col
, wxGridCellAttr
*attr
)
7254 if ( CanHaveAttributes() )
7256 m_table
->SetAttr(attr
, row
, col
);
7265 void wxGrid::SetRowAttr(int row
, wxGridCellAttr
*attr
)
7267 if ( CanHaveAttributes() )
7269 m_table
->SetRowAttr(attr
, row
);
7278 void wxGrid::SetColAttr(int col
, wxGridCellAttr
*attr
)
7280 if ( CanHaveAttributes() )
7282 m_table
->SetColAttr(attr
, col
);
7291 void wxGrid::SetCellBackgroundColour( int row
, int col
, const wxColour
& colour
)
7293 if ( CanHaveAttributes() )
7295 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7296 attr
->SetBackgroundColour(colour
);
7301 void wxGrid::SetCellTextColour( int row
, int col
, const wxColour
& colour
)
7303 if ( CanHaveAttributes() )
7305 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7306 attr
->SetTextColour(colour
);
7311 void wxGrid::SetCellFont( int row
, int col
, const wxFont
& font
)
7313 if ( CanHaveAttributes() )
7315 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7316 attr
->SetFont(font
);
7321 void wxGrid::SetCellAlignment( int row
, int col
, int horiz
, int vert
)
7323 if ( CanHaveAttributes() )
7325 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7326 attr
->SetAlignment(horiz
, vert
);
7331 void wxGrid::SetCellOverflow( int row
, int col
, bool allow
)
7333 if ( CanHaveAttributes() )
7335 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7336 attr
->SetOverflow(allow
);
7341 void wxGrid::SetCellSize( int row
, int col
, int num_rows
, int num_cols
)
7343 if ( CanHaveAttributes() )
7345 int cell_rows
, cell_cols
;
7347 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7348 attr
->GetSize(&cell_rows
, &cell_cols
);
7349 attr
->SetSize(num_rows
, num_cols
);
7352 // Cannot set the size of a cell to 0 or negative values
7353 // While it is perfectly legal to do that, this function cannot
7354 // handle all the possibilies, do it by hand by getting the CellAttr.
7355 // You can only set the size of a cell to 1,1 or greater with this fn
7356 wxASSERT_MSG( !((cell_rows
< 1) || (cell_cols
< 1)),
7357 wxT("wxGrid::SetCellSize setting cell size that is already part of another cell"));
7358 wxASSERT_MSG( !((num_rows
< 1) || (num_cols
< 1)),
7359 wxT("wxGrid::SetCellSize setting cell size to < 1"));
7361 // if this was already a multicell then "turn off" the other cells first
7362 if ((cell_rows
> 1) || (cell_cols
> 1))
7365 for (j
=row
; j
< row
+ cell_rows
; j
++)
7367 for (i
=col
; i
< col
+ cell_cols
; i
++)
7369 if ((i
!= col
) || (j
!= row
))
7371 wxGridCellAttr
*attr_stub
= GetOrCreateCellAttr(j
, i
);
7372 attr_stub
->SetSize( 1, 1 );
7373 attr_stub
->DecRef();
7379 // mark the cells that will be covered by this cell to
7380 // negative or zero values to point back at this cell
7381 if (((num_rows
> 1) || (num_cols
> 1)) && (num_rows
>= 1) && (num_cols
>= 1))
7384 for (j
=row
; j
< row
+ num_rows
; j
++)
7386 for (i
=col
; i
< col
+ num_cols
; i
++)
7388 if ((i
!= col
) || (j
!= row
))
7390 wxGridCellAttr
*attr_stub
= GetOrCreateCellAttr(j
, i
);
7391 attr_stub
->SetSize( row
- j
, col
- i
);
7392 attr_stub
->DecRef();
7400 void wxGrid::SetCellRenderer(int row
, int col
, wxGridCellRenderer
*renderer
)
7402 if ( CanHaveAttributes() )
7404 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7405 attr
->SetRenderer(renderer
);
7410 void wxGrid::SetCellEditor(int row
, int col
, wxGridCellEditor
* editor
)
7412 if ( CanHaveAttributes() )
7414 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7415 attr
->SetEditor(editor
);
7420 void wxGrid::SetReadOnly(int row
, int col
, bool isReadOnly
)
7422 if ( CanHaveAttributes() )
7424 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
7425 attr
->SetReadOnly(isReadOnly
);
7430 // ----------------------------------------------------------------------------
7431 // Data type registration
7432 // ----------------------------------------------------------------------------
7434 void wxGrid::RegisterDataType(const wxString
& typeName
,
7435 wxGridCellRenderer
* renderer
,
7436 wxGridCellEditor
* editor
)
7438 m_typeRegistry
->RegisterDataType(typeName
, renderer
, editor
);
7442 wxGridCellEditor
* wxGrid::GetDefaultEditorForCell(int row
, int col
) const
7444 wxString typeName
= m_table
->GetTypeName(row
, col
);
7445 return GetDefaultEditorForType(typeName
);
7448 wxGridCellRenderer
* wxGrid::GetDefaultRendererForCell(int row
, int col
) const
7450 wxString typeName
= m_table
->GetTypeName(row
, col
);
7451 return GetDefaultRendererForType(typeName
);
7454 wxGridCellEditor
* wxGrid::GetDefaultEditorForType(const wxString
& typeName
) const
7456 int index
= m_typeRegistry
->FindOrCloneDataType(typeName
);
7457 if ( index
== wxNOT_FOUND
)
7459 wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str()));
7464 return m_typeRegistry
->GetEditor(index
);
7467 wxGridCellRenderer
* wxGrid::GetDefaultRendererForType(const wxString
& typeName
) const
7469 int index
= m_typeRegistry
->FindOrCloneDataType(typeName
);
7470 if ( index
== wxNOT_FOUND
)
7472 wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str()));
7477 return m_typeRegistry
->GetRenderer(index
);
7480 // ----------------------------------------------------------------------------
7482 // ----------------------------------------------------------------------------
7484 void wxGrid::EnableDragRowSize( bool enable
)
7486 m_canDragRowSize
= enable
;
7489 void wxGrid::EnableDragColSize( bool enable
)
7491 m_canDragColSize
= enable
;
7494 void wxGrid::EnableDragGridSize( bool enable
)
7496 m_canDragGridSize
= enable
;
7499 void wxGrid::EnableDragCell( bool enable
)
7501 m_canDragCell
= enable
;
7504 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows
)
7506 m_defaultRowHeight
= wxMax( height
, m_minAcceptableRowHeight
);
7508 if ( resizeExistingRows
)
7510 // since we are resizing all rows to the default row size,
7511 // we can simply clear the row heights and row bottoms
7512 // arrays (which also allows us to take advantage of
7513 // some speed optimisations)
7514 m_rowHeights
.Empty();
7515 m_rowBottoms
.Empty();
7516 if ( !GetBatchCount() )
7521 void wxGrid::SetRowSize( int row
, int height
)
7523 wxCHECK_RET( row
>= 0 && row
< m_numRows
, _T("invalid row index") );
7525 // if < 0 then calculate new height from label
7529 wxArrayString lines
;
7530 wxClientDC
dc(m_rowLabelWin
);
7531 dc
.SetFont(GetLabelFont());
7532 StringToLines(GetRowLabelValue( row
), lines
);
7533 GetTextBoxSize( dc
, lines
, &w
, &h
);
7534 //check that it is not less than the minimal height
7535 height
= wxMax(h
, GetRowMinimalAcceptableHeight());
7538 // See comment in SetColSize
7539 if ( height
< GetRowMinimalAcceptableHeight())
7542 if ( m_rowHeights
.IsEmpty() )
7544 // need to really create the array
7548 int h
= wxMax( 0, height
);
7549 int diff
= h
- m_rowHeights
[row
];
7551 m_rowHeights
[row
] = h
;
7552 for ( int i
= row
; i
< m_numRows
; i
++ )
7554 m_rowBottoms
[i
] += diff
;
7557 if ( !GetBatchCount() )
7561 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols
)
7563 // we dont allow zero default column width
7564 m_defaultColWidth
= wxMax( wxMax( width
, m_minAcceptableColWidth
), 1 );
7566 if ( resizeExistingCols
)
7568 // since we are resizing all columns to the default column size,
7569 // we can simply clear the col widths and col rights
7570 // arrays (which also allows us to take advantage of
7571 // some speed optimisations)
7572 m_colWidths
.Empty();
7573 m_colRights
.Empty();
7574 if ( !GetBatchCount() )
7579 void wxGrid::SetColSize( int col
, int width
)
7581 wxCHECK_RET( col
>= 0 && col
< m_numCols
, _T("invalid column index") );
7583 // if < 0 then calculate new width from label
7587 wxArrayString lines
;
7588 wxClientDC
dc(m_colWindow
);
7589 dc
.SetFont(GetLabelFont());
7590 StringToLines(GetColLabelValue(col
), lines
);
7591 if ( GetColLabelTextOrientation() == wxHORIZONTAL
)
7592 GetTextBoxSize( dc
, lines
, &w
, &h
);
7594 GetTextBoxSize( dc
, lines
, &h
, &w
);
7596 //check that it is not less than the minimal width
7597 width
= wxMax(width
, GetColMinimalAcceptableWidth());
7600 // we intentionally don't test whether the width is less than
7601 // GetColMinimalWidth() here but we do compare it with
7602 // GetColMinimalAcceptableWidth() as otherwise things currently break (see
7603 // #651) -- and we also always allow the width of 0 as it has the special
7604 // sense of hiding the column
7605 if ( width
> 0 && width
< GetColMinimalAcceptableWidth() )
7608 if ( m_colWidths
.IsEmpty() )
7610 // need to really create the array
7614 const int diff
= width
- m_colWidths
[col
];
7615 m_colWidths
[col
] = width
;
7616 if ( m_useNativeHeader
)
7617 GetGridColHeader()->UpdateColumn(col
);
7618 //else: will be refreshed when the header is redrawn
7620 for ( int colPos
= GetColPos(col
); colPos
< m_numCols
; colPos
++ )
7622 m_colRights
[GetColAt(colPos
)] += diff
;
7625 if ( !GetBatchCount() )
7632 void wxGrid::SetColMinimalWidth( int col
, int width
)
7634 if (width
> GetColMinimalAcceptableWidth())
7636 wxLongToLongHashMap::key_type key
= (wxLongToLongHashMap::key_type
)col
;
7637 m_colMinWidths
[key
] = width
;
7641 void wxGrid::SetRowMinimalHeight( int row
, int width
)
7643 if (width
> GetRowMinimalAcceptableHeight())
7645 wxLongToLongHashMap::key_type key
= (wxLongToLongHashMap::key_type
)row
;
7646 m_rowMinHeights
[key
] = width
;
7650 int wxGrid::GetColMinimalWidth(int col
) const
7652 wxLongToLongHashMap::key_type key
= (wxLongToLongHashMap::key_type
)col
;
7653 wxLongToLongHashMap::const_iterator it
= m_colMinWidths
.find(key
);
7655 return it
!= m_colMinWidths
.end() ? (int)it
->second
: m_minAcceptableColWidth
;
7658 int wxGrid::GetRowMinimalHeight(int row
) const
7660 wxLongToLongHashMap::key_type key
= (wxLongToLongHashMap::key_type
)row
;
7661 wxLongToLongHashMap::const_iterator it
= m_rowMinHeights
.find(key
);
7663 return it
!= m_rowMinHeights
.end() ? (int)it
->second
: m_minAcceptableRowHeight
;
7666 void wxGrid::SetColMinimalAcceptableWidth( int width
)
7668 // We do allow a width of 0 since this gives us
7669 // an easy way to temporarily hiding columns.
7671 m_minAcceptableColWidth
= width
;
7674 void wxGrid::SetRowMinimalAcceptableHeight( int height
)
7676 // We do allow a height of 0 since this gives us
7677 // an easy way to temporarily hiding rows.
7679 m_minAcceptableRowHeight
= height
;
7682 int wxGrid::GetColMinimalAcceptableWidth() const
7684 return m_minAcceptableColWidth
;
7687 int wxGrid::GetRowMinimalAcceptableHeight() const
7689 return m_minAcceptableRowHeight
;
7692 // ----------------------------------------------------------------------------
7694 // ----------------------------------------------------------------------------
7697 wxGrid::AutoSizeColOrRow(int colOrRow
, bool setAsMin
, wxGridDirection direction
)
7699 const bool column
= direction
== wxGRID_COLUMN
;
7701 wxClientDC
dc(m_gridWin
);
7703 // cancel editing of cell
7704 HideCellEditControl();
7705 SaveEditControlValue();
7707 // init both of them to avoid compiler warnings, even if we only need one
7715 wxCoord extent
, extentMax
= 0;
7716 int max
= column
? m_numRows
: m_numCols
;
7717 for ( int rowOrCol
= 0; rowOrCol
< max
; rowOrCol
++ )
7724 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
7725 wxGridCellRenderer
*renderer
= attr
->GetRenderer(this, row
, col
);
7728 wxSize size
= renderer
->GetBestSize(*this, *attr
, dc
, row
, col
);
7729 extent
= column
? size
.x
: size
.y
;
7730 if ( extent
> extentMax
)
7739 // now also compare with the column label extent
7741 dc
.SetFont( GetLabelFont() );
7745 dc
.GetMultiLineTextExtent( GetColLabelValue(col
), &w
, &h
);
7746 if ( GetColLabelTextOrientation() == wxVERTICAL
)
7750 dc
.GetMultiLineTextExtent( GetRowLabelValue(row
), &w
, &h
);
7752 extent
= column
? w
: h
;
7753 if ( extent
> extentMax
)
7758 // empty column - give default extent (notice that if extentMax is less
7759 // than default extent but != 0, it's OK)
7760 extentMax
= column
? m_defaultColWidth
: m_defaultRowHeight
;
7765 // leave some space around text
7773 // Ensure automatic width is not less than minimal width. See the
7774 // comment in SetColSize() for explanation of why this isn't done
7777 extentMax
= wxMax(extentMax
, GetColMinimalWidth(col
));
7779 SetColSize( col
, extentMax
);
7780 if ( !GetBatchCount() )
7782 if ( m_useNativeHeader
)
7784 GetGridColHeader()->UpdateColumn(col
);
7789 m_gridWin
->GetClientSize( &cw
, &ch
);
7790 wxRect
rect ( CellToRect( 0, col
) );
7792 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
);
7793 rect
.width
= cw
- rect
.x
;
7794 rect
.height
= m_colLabelHeight
;
7795 GetColLabelWindow()->Refresh( true, &rect
);
7801 // Ensure automatic width is not less than minimal height. See the
7802 // comment in SetColSize() for explanation of why this isn't done
7805 extentMax
= wxMax(extentMax
, GetRowMinimalHeight(row
));
7807 SetRowSize(row
, extentMax
);
7808 if ( !GetBatchCount() )
7811 m_gridWin
->GetClientSize( &cw
, &ch
);
7812 wxRect
rect( CellToRect( row
, 0 ) );
7814 CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
);
7815 rect
.width
= m_rowLabelWidth
;
7816 rect
.height
= ch
- rect
.y
;
7817 m_rowLabelWin
->Refresh( true, &rect
);
7824 SetColMinimalWidth(col
, extentMax
);
7826 SetRowMinimalHeight(row
, extentMax
);
7830 wxCoord
wxGrid::CalcColOrRowLabelAreaMinSize(wxGridDirection direction
)
7832 // calculate size for the rows or columns?
7833 const bool calcRows
= direction
== wxGRID_ROW
;
7835 wxClientDC
dc(calcRows
? GetGridRowLabelWindow()
7836 : GetGridColLabelWindow());
7837 dc
.SetFont(GetLabelFont());
7839 // which dimension should we take into account for calculations?
7841 // for columns, the text can be only horizontal so it's easy but for rows
7842 // we also have to take into account the text orientation
7844 useWidth
= calcRows
|| (GetColLabelTextOrientation() == wxVERTICAL
);
7846 wxArrayString lines
;
7847 wxCoord extentMax
= 0;
7849 const int numRowsOrCols
= calcRows
? m_numRows
: m_numCols
;
7850 for ( int rowOrCol
= 0; rowOrCol
< numRowsOrCols
; rowOrCol
++ )
7854 wxString label
= calcRows
? GetRowLabelValue(rowOrCol
)
7855 : GetColLabelValue(rowOrCol
);
7856 StringToLines(label
, lines
);
7859 GetTextBoxSize(dc
, lines
, &w
, &h
);
7861 const wxCoord extent
= useWidth
? w
: h
;
7862 if ( extent
> extentMax
)
7868 // empty column - give default extent (notice that if extentMax is less
7869 // than default extent but != 0, it's OK)
7870 extentMax
= calcRows
? GetDefaultRowLabelSize()
7871 : GetDefaultColLabelSize();
7874 // leave some space around text (taken from AutoSizeColOrRow)
7883 int wxGrid::SetOrCalcColumnSizes(bool calcOnly
, bool setAsMin
)
7885 int width
= m_rowLabelWidth
;
7887 wxGridUpdateLocker locker
;
7889 locker
.Create(this);
7891 for ( int col
= 0; col
< m_numCols
; col
++ )
7894 AutoSizeColumn(col
, setAsMin
);
7896 width
+= GetColWidth(col
);
7902 int wxGrid::SetOrCalcRowSizes(bool calcOnly
, bool setAsMin
)
7904 int height
= m_colLabelHeight
;
7906 wxGridUpdateLocker locker
;
7908 locker
.Create(this);
7910 for ( int row
= 0; row
< m_numRows
; row
++ )
7913 AutoSizeRow(row
, setAsMin
);
7915 height
+= GetRowHeight(row
);
7921 void wxGrid::AutoSize()
7923 wxGridUpdateLocker
locker(this);
7925 wxSize
size(SetOrCalcColumnSizes(false) - m_rowLabelWidth
+ m_extraWidth
,
7926 SetOrCalcRowSizes(false) - m_colLabelHeight
+ m_extraHeight
);
7928 // we know that we're not going to have scrollbars so disable them now to
7929 // avoid trouble in SetClientSize() which can otherwise set the correct
7930 // client size but also leave space for (not needed any more) scrollbars
7931 SetScrollbars(0, 0, 0, 0, 0, 0, true);
7933 // restore the scroll rate parameters overwritten by SetScrollbars()
7934 SetScrollRate(m_scrollLineX
, m_scrollLineY
);
7936 SetClientSize(size
.x
+ m_rowLabelWidth
, size
.y
+ m_colLabelHeight
);
7939 void wxGrid::AutoSizeRowLabelSize( int row
)
7941 // Hide the edit control, so it
7942 // won't interfere with drag-shrinking.
7943 if ( IsCellEditControlShown() )
7945 HideCellEditControl();
7946 SaveEditControlValue();
7949 // autosize row height depending on label text
7950 SetRowSize(row
, -1);
7954 void wxGrid::AutoSizeColLabelSize( int col
)
7956 // Hide the edit control, so it
7957 // won't interfere with drag-shrinking.
7958 if ( IsCellEditControlShown() )
7960 HideCellEditControl();
7961 SaveEditControlValue();
7964 // autosize column width depending on label text
7965 SetColSize(col
, -1);
7969 wxSize
wxGrid::DoGetBestSize() const
7971 wxGrid
*self
= (wxGrid
*)this; // const_cast
7973 // we do the same as in AutoSize() here with the exception that we don't
7974 // change the column/row sizes, only calculate them
7975 wxSize
size(self
->SetOrCalcColumnSizes(true) - m_rowLabelWidth
+ m_extraWidth
,
7976 self
->SetOrCalcRowSizes(true) - m_colLabelHeight
+ m_extraHeight
);
7978 // NOTE: This size should be cached, but first we need to add calls to
7979 // InvalidateBestSize everywhere that could change the results of this
7981 // CacheBestSize(size);
7983 return wxSize(size
.x
+ m_rowLabelWidth
, size
.y
+ m_colLabelHeight
)
7984 + GetWindowBorderSize();
7992 wxPen
& wxGrid::GetDividerPen() const
7997 // ----------------------------------------------------------------------------
7998 // cell value accessor functions
7999 // ----------------------------------------------------------------------------
8001 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s
)
8005 m_table
->SetValue( row
, col
, s
);
8006 if ( !GetBatchCount() )
8009 wxRect
rect( CellToRect( row
, col
) );
8011 rect
.width
= m_gridWin
->GetClientSize().GetWidth();
8012 CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
);
8013 m_gridWin
->Refresh( false, &rect
);
8016 if ( m_currentCellCoords
.GetRow() == row
&&
8017 m_currentCellCoords
.GetCol() == col
&&
8018 IsCellEditControlShown())
8019 // Note: If we are using IsCellEditControlEnabled,
8020 // this interacts badly with calling SetCellValue from
8021 // an EVT_GRID_CELL_CHANGE handler.
8023 HideCellEditControl();
8024 ShowCellEditControl(); // will reread data from table
8029 // ----------------------------------------------------------------------------
8030 // block, row and column selection
8031 // ----------------------------------------------------------------------------
8033 void wxGrid::SelectRow( int row
, bool addToSelected
)
8038 if ( !addToSelected
)
8041 m_selection
->SelectRow(row
);
8044 void wxGrid::SelectCol( int col
, bool addToSelected
)
8049 if ( !addToSelected
)
8052 m_selection
->SelectCol(col
);
8055 void wxGrid::SelectBlock(int topRow
, int leftCol
, int bottomRow
, int rightCol
,
8061 if ( !addToSelected
)
8064 m_selection
->SelectBlock(topRow
, leftCol
, bottomRow
, rightCol
);
8067 void wxGrid::SelectAll()
8069 if ( m_numRows
> 0 && m_numCols
> 0 )
8072 m_selection
->SelectBlock( 0, 0, m_numRows
- 1, m_numCols
- 1 );
8076 // ----------------------------------------------------------------------------
8077 // cell, row and col deselection
8078 // ----------------------------------------------------------------------------
8080 void wxGrid::DeselectLine(int line
, const wxGridOperations
& oper
)
8085 const wxGridSelectionModes mode
= m_selection
->GetSelectionMode();
8086 if ( mode
== oper
.GetSelectionMode() )
8088 const wxGridCellCoords
c(oper
.MakeCoords(line
, 0));
8089 if ( m_selection
->IsInSelection(c
) )
8090 m_selection
->ToggleCellSelection(c
);
8092 else if ( mode
!= oper
.Dual().GetSelectionMode() )
8094 const int nOther
= oper
.Dual().GetNumberOfLines(this);
8095 for ( int i
= 0; i
< nOther
; i
++ )
8097 const wxGridCellCoords
c(oper
.MakeCoords(line
, i
));
8098 if ( m_selection
->IsInSelection(c
) )
8099 m_selection
->ToggleCellSelection(c
);
8102 //else: can only select orthogonal lines so no lines in this direction
8103 // could have been selected anyhow
8106 void wxGrid::DeselectRow(int row
)
8108 DeselectLine(row
, wxGridRowOperations());
8111 void wxGrid::DeselectCol(int col
)
8113 DeselectLine(col
, wxGridColumnOperations());
8116 void wxGrid::DeselectCell( int row
, int col
)
8118 if ( m_selection
&& m_selection
->IsInSelection(row
, col
) )
8119 m_selection
->ToggleCellSelection(row
, col
);
8122 bool wxGrid::IsSelection() const
8124 return ( m_selection
&& (m_selection
->IsSelection() ||
8125 ( m_selectedBlockTopLeft
!= wxGridNoCellCoords
&&
8126 m_selectedBlockBottomRight
!= wxGridNoCellCoords
) ) );
8129 bool wxGrid::IsInSelection( int row
, int col
) const
8131 return ( m_selection
&& (m_selection
->IsInSelection( row
, col
) ||
8132 ( row
>= m_selectedBlockTopLeft
.GetRow() &&
8133 col
>= m_selectedBlockTopLeft
.GetCol() &&
8134 row
<= m_selectedBlockBottomRight
.GetRow() &&
8135 col
<= m_selectedBlockBottomRight
.GetCol() )) );
8138 wxGridCellCoordsArray
wxGrid::GetSelectedCells() const
8142 wxGridCellCoordsArray a
;
8146 return m_selection
->m_cellSelection
;
8149 wxGridCellCoordsArray
wxGrid::GetSelectionBlockTopLeft() const
8153 wxGridCellCoordsArray a
;
8157 return m_selection
->m_blockSelectionTopLeft
;
8160 wxGridCellCoordsArray
wxGrid::GetSelectionBlockBottomRight() const
8164 wxGridCellCoordsArray a
;
8168 return m_selection
->m_blockSelectionBottomRight
;
8171 wxArrayInt
wxGrid::GetSelectedRows() const
8179 return m_selection
->m_rowSelection
;
8182 wxArrayInt
wxGrid::GetSelectedCols() const
8190 return m_selection
->m_colSelection
;
8193 void wxGrid::ClearSelection()
8195 wxRect r1
= BlockToDeviceRect(m_selectedBlockTopLeft
,
8196 m_selectedBlockBottomRight
);
8197 wxRect r2
= BlockToDeviceRect(m_currentCellCoords
,
8198 m_selectedBlockCorner
);
8200 m_selectedBlockTopLeft
=
8201 m_selectedBlockBottomRight
=
8202 m_selectedBlockCorner
= wxGridNoCellCoords
;
8204 Refresh( false, &r1
);
8205 Refresh( false, &r2
);
8208 m_selection
->ClearSelection();
8211 // This function returns the rectangle that encloses the given block
8212 // in device coords clipped to the client size of the grid window.
8214 wxRect
wxGrid::BlockToDeviceRect( const wxGridCellCoords
& topLeft
,
8215 const wxGridCellCoords
& bottomRight
) const
8218 wxRect tempCellRect
= CellToRect(topLeft
);
8219 if ( tempCellRect
!= wxGridNoCellRect
)
8221 resultRect
= tempCellRect
;
8225 resultRect
= wxRect(0, 0, 0, 0);
8228 tempCellRect
= CellToRect(bottomRight
);
8229 if ( tempCellRect
!= wxGridNoCellRect
)
8231 resultRect
+= tempCellRect
;
8235 // If both inputs were "wxGridNoCellRect," then there's nothing to do.
8236 return wxGridNoCellRect
;
8239 // Ensure that left/right and top/bottom pairs are in order.
8240 int left
= resultRect
.GetLeft();
8241 int top
= resultRect
.GetTop();
8242 int right
= resultRect
.GetRight();
8243 int bottom
= resultRect
.GetBottom();
8245 int leftCol
= topLeft
.GetCol();
8246 int topRow
= topLeft
.GetRow();
8247 int rightCol
= bottomRight
.GetCol();
8248 int bottomRow
= bottomRight
.GetRow();
8272 // The following loop is ONLY necessary to detect and handle merged cells.
8274 m_gridWin
->GetClientSize( &cw
, &ch
);
8276 // Get the origin coordinates: notice that they will be negative if the
8277 // grid is scrolled downwards/to the right.
8278 int gridOriginX
= 0;
8279 int gridOriginY
= 0;
8280 CalcScrolledPosition(gridOriginX
, gridOriginY
, &gridOriginX
, &gridOriginY
);
8282 int onScreenLeftmostCol
= internalXToCol(-gridOriginX
);
8283 int onScreenUppermostRow
= internalYToRow(-gridOriginY
);
8285 int onScreenRightmostCol
= internalXToCol(-gridOriginX
+ cw
);
8286 int onScreenBottommostRow
= internalYToRow(-gridOriginY
+ ch
);
8288 // Bound our loop so that we only examine the portion of the selected block
8289 // that is shown on screen. Therefore, we compare the Top-Left block values
8290 // to the Top-Left screen values, and the Bottom-Right block values to the
8291 // Bottom-Right screen values, choosing appropriately.
8292 const int visibleTopRow
= wxMax(topRow
, onScreenUppermostRow
);
8293 const int visibleBottomRow
= wxMin(bottomRow
, onScreenBottommostRow
);
8294 const int visibleLeftCol
= wxMax(leftCol
, onScreenLeftmostCol
);
8295 const int visibleRightCol
= wxMin(rightCol
, onScreenRightmostCol
);
8297 for ( int j
= visibleTopRow
; j
<= visibleBottomRow
; j
++ )
8299 for ( int i
= visibleLeftCol
; i
<= visibleRightCol
; i
++ )
8301 if ( (j
== visibleTopRow
) || (j
== visibleBottomRow
) ||
8302 (i
== visibleLeftCol
) || (i
== visibleRightCol
) )
8304 tempCellRect
= CellToRect( j
, i
);
8306 if (tempCellRect
.x
< left
)
8307 left
= tempCellRect
.x
;
8308 if (tempCellRect
.y
< top
)
8309 top
= tempCellRect
.y
;
8310 if (tempCellRect
.x
+ tempCellRect
.width
> right
)
8311 right
= tempCellRect
.x
+ tempCellRect
.width
;
8312 if (tempCellRect
.y
+ tempCellRect
.height
> bottom
)
8313 bottom
= tempCellRect
.y
+ tempCellRect
.height
;
8317 i
= visibleRightCol
; // jump over inner cells.
8322 // Convert to scrolled coords
8323 CalcScrolledPosition( left
, top
, &left
, &top
);
8324 CalcScrolledPosition( right
, bottom
, &right
, &bottom
);
8326 if (right
< 0 || bottom
< 0 || left
> cw
|| top
> ch
)
8327 return wxRect(0,0,0,0);
8329 resultRect
.SetLeft( wxMax(0, left
) );
8330 resultRect
.SetTop( wxMax(0, top
) );
8331 resultRect
.SetRight( wxMin(cw
, right
) );
8332 resultRect
.SetBottom( wxMin(ch
, bottom
) );
8337 // ----------------------------------------------------------------------------
8339 // ----------------------------------------------------------------------------
8341 #if wxUSE_DRAG_AND_DROP
8343 // this allow setting drop target directly on wxGrid
8344 void wxGrid::SetDropTarget(wxDropTarget
*dropTarget
)
8346 GetGridWindow()->SetDropTarget(dropTarget
);
8349 #endif // wxUSE_DRAG_AND_DROP
8351 // ----------------------------------------------------------------------------
8352 // grid event classes
8353 // ----------------------------------------------------------------------------
8355 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxNotifyEvent
)
8357 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
,
8358 int row
, int col
, int x
, int y
, bool sel
,
8359 bool control
, bool shift
, bool alt
, bool meta
)
8360 : wxNotifyEvent( type
, id
),
8361 wxKeyboardState(control
, shift
, alt
, meta
)
8363 Init(row
, col
, x
, y
, sel
);
8365 SetEventObject(obj
);
8368 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxNotifyEvent
)
8370 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
,
8371 int rowOrCol
, int x
, int y
,
8372 bool control
, bool shift
, bool alt
, bool meta
)
8373 : wxNotifyEvent( type
, id
),
8374 wxKeyboardState(control
, shift
, alt
, meta
)
8376 Init(rowOrCol
, x
, y
);
8378 SetEventObject(obj
);
8382 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxNotifyEvent
)
8384 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
,
8385 const wxGridCellCoords
& topLeft
,
8386 const wxGridCellCoords
& bottomRight
,
8387 bool sel
, bool control
,
8388 bool shift
, bool alt
, bool meta
)
8389 : wxNotifyEvent( type
, id
),
8390 wxKeyboardState(control
, shift
, alt
, meta
)
8392 Init(topLeft
, bottomRight
, sel
);
8394 SetEventObject(obj
);
8398 IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent
, wxCommandEvent
)
8400 wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id
, wxEventType type
,
8401 wxObject
* obj
, int row
,
8402 int col
, wxControl
* ctrl
)
8403 : wxCommandEvent(type
, id
)
8405 SetEventObject(obj
);
8412 // ----------------------------------------------------------------------------
8413 // wxGridTypeRegistry
8414 // ----------------------------------------------------------------------------
8416 wxGridTypeRegistry::~wxGridTypeRegistry()
8418 size_t count
= m_typeinfo
.GetCount();
8419 for ( size_t i
= 0; i
< count
; i
++ )
8420 delete m_typeinfo
[i
];
8423 void wxGridTypeRegistry::RegisterDataType(const wxString
& typeName
,
8424 wxGridCellRenderer
* renderer
,
8425 wxGridCellEditor
* editor
)
8427 wxGridDataTypeInfo
* info
= new wxGridDataTypeInfo(typeName
, renderer
, editor
);
8429 // is it already registered?
8430 int loc
= FindRegisteredDataType(typeName
);
8431 if ( loc
!= wxNOT_FOUND
)
8433 delete m_typeinfo
[loc
];
8434 m_typeinfo
[loc
] = info
;
8438 m_typeinfo
.Add(info
);
8442 int wxGridTypeRegistry::FindRegisteredDataType(const wxString
& typeName
)
8444 size_t count
= m_typeinfo
.GetCount();
8445 for ( size_t i
= 0; i
< count
; i
++ )
8447 if ( typeName
== m_typeinfo
[i
]->m_typeName
)
8456 int wxGridTypeRegistry::FindDataType(const wxString
& typeName
)
8458 int index
= FindRegisteredDataType(typeName
);
8459 if ( index
== wxNOT_FOUND
)
8461 // check whether this is one of the standard ones, in which case
8462 // register it "on the fly"
8464 if ( typeName
== wxGRID_VALUE_STRING
)
8466 RegisterDataType(wxGRID_VALUE_STRING
,
8467 new wxGridCellStringRenderer
,
8468 new wxGridCellTextEditor
);
8471 #endif // wxUSE_TEXTCTRL
8473 if ( typeName
== wxGRID_VALUE_BOOL
)
8475 RegisterDataType(wxGRID_VALUE_BOOL
,
8476 new wxGridCellBoolRenderer
,
8477 new wxGridCellBoolEditor
);
8480 #endif // wxUSE_CHECKBOX
8482 if ( typeName
== wxGRID_VALUE_NUMBER
)
8484 RegisterDataType(wxGRID_VALUE_NUMBER
,
8485 new wxGridCellNumberRenderer
,
8486 new wxGridCellNumberEditor
);
8488 else if ( typeName
== wxGRID_VALUE_FLOAT
)
8490 RegisterDataType(wxGRID_VALUE_FLOAT
,
8491 new wxGridCellFloatRenderer
,
8492 new wxGridCellFloatEditor
);
8495 #endif // wxUSE_TEXTCTRL
8497 if ( typeName
== wxGRID_VALUE_CHOICE
)
8499 RegisterDataType(wxGRID_VALUE_CHOICE
,
8500 new wxGridCellStringRenderer
,
8501 new wxGridCellChoiceEditor
);
8504 #endif // wxUSE_COMBOBOX
8509 // we get here only if just added the entry for this type, so return
8511 index
= m_typeinfo
.GetCount() - 1;
8517 int wxGridTypeRegistry::FindOrCloneDataType(const wxString
& typeName
)
8519 int index
= FindDataType(typeName
);
8520 if ( index
== wxNOT_FOUND
)
8522 // the first part of the typename is the "real" type, anything after ':'
8523 // are the parameters for the renderer
8524 index
= FindDataType(typeName
.BeforeFirst(_T(':')));
8525 if ( index
== wxNOT_FOUND
)
8530 wxGridCellRenderer
*renderer
= GetRenderer(index
);
8531 wxGridCellRenderer
*rendererOld
= renderer
;
8532 renderer
= renderer
->Clone();
8533 rendererOld
->DecRef();
8535 wxGridCellEditor
*editor
= GetEditor(index
);
8536 wxGridCellEditor
*editorOld
= editor
;
8537 editor
= editor
->Clone();
8538 editorOld
->DecRef();
8540 // do it even if there are no parameters to reset them to defaults
8541 wxString params
= typeName
.AfterFirst(_T(':'));
8542 renderer
->SetParameters(params
);
8543 editor
->SetParameters(params
);
8545 // register the new typename
8546 RegisterDataType(typeName
, renderer
, editor
);
8548 // we just registered it, it's the last one
8549 index
= m_typeinfo
.GetCount() - 1;
8555 wxGridCellRenderer
* wxGridTypeRegistry::GetRenderer(int index
)
8557 wxGridCellRenderer
* renderer
= m_typeinfo
[index
]->m_renderer
;
8564 wxGridCellEditor
* wxGridTypeRegistry::GetEditor(int index
)
8566 wxGridCellEditor
* editor
= m_typeinfo
[index
]->m_editor
;
8573 #endif // wxUSE_GRID