1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/headerctrlcmn.cpp
3 // Purpose: implementation of wxHeaderCtrlBase
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
29 #include "wx/headerctrl.h"
31 // ----------------------------------------------------------------------------
33 // ----------------------------------------------------------------------------
38 const unsigned int wxNO_COLUMN
= static_cast<unsigned>(-1);
40 } // anonymous namespace
42 // ============================================================================
43 // wxHeaderCtrlBase implementation
44 // ============================================================================
46 extern WXDLLIMPEXP_DATA_CORE(const char) wxHeaderCtrlNameStr
[] = "wxHeaderCtrl";
48 BEGIN_EVENT_TABLE(wxHeaderCtrlBase
, wxControl
)
49 EVT_HEADER_SEPARATOR_DCLICK(wxID_ANY
, wxHeaderCtrlBase::OnSeparatorDClick
)
52 void wxHeaderCtrlBase::ScrollWindow(int dx
,
53 int WXUNUSED_UNLESS_DEBUG(dy
),
54 const wxRect
* WXUNUSED_UNLESS_DEBUG(rect
))
57 // this doesn't make sense at all
58 wxASSERT_MSG( !dy
, "header window can't be scrolled vertically" );
60 // this would actually be nice to support for "frozen" headers but it isn't
61 // supported currently
62 wxASSERT_MSG( !rect
, "header window can't be scrolled partially" );
67 void wxHeaderCtrlBase::SetColumnCount(unsigned int count
)
69 if ( count
== GetColumnCount() )
72 OnColumnCountChanging(count
);
77 // ----------------------------------------------------------------------------
78 // wxHeaderCtrlBase event handling
79 // ----------------------------------------------------------------------------
81 void wxHeaderCtrlBase::OnSeparatorDClick(wxHeaderCtrlEvent
& event
)
83 const unsigned col
= event
.GetColumn();
85 int w
= wxWindowBase::GetTextExtent(GetColumn(col
).GetTitle()).x
;
86 w
+= 4*GetCharWidth(); // add some arbitrary margins around text
88 if ( !UpdateColumnWidthToFit(col
, w
) )
94 // ----------------------------------------------------------------------------
95 // wxHeaderCtrlBase column reordering
96 // ----------------------------------------------------------------------------
98 void wxHeaderCtrlBase::SetColumnsOrder(const wxArrayInt
& order
)
100 const unsigned count
= GetColumnCount();
101 wxCHECK_RET( order
.size() == count
, "wrong number of columns" );
103 // check the array validity
104 wxArrayInt
seen(count
, 0);
105 for ( unsigned n
= 0; n
< count
; n
++ )
107 const unsigned idx
= order
[n
];
108 wxCHECK_RET( idx
< count
, "invalid column index" );
109 wxCHECK_RET( !seen
[idx
], "duplicate column index" );
114 DoSetColumnsOrder(order
);
116 // TODO-RTL: do we need to reverse the array?
119 void wxHeaderCtrlBase::ResetColumnsOrder()
121 const unsigned count
= GetColumnCount();
122 wxArrayInt
order(count
);
123 for ( unsigned n
= 0; n
< count
; n
++ )
126 DoSetColumnsOrder(order
);
129 wxArrayInt
wxHeaderCtrlBase::GetColumnsOrder() const
131 const wxArrayInt order
= DoGetColumnsOrder();
133 wxASSERT_MSG( order
.size() == GetColumnCount(), "invalid order array" );
138 unsigned int wxHeaderCtrlBase::GetColumnAt(unsigned int pos
) const
140 wxCHECK_MSG( pos
< GetColumnCount(), wxNO_COLUMN
, "invalid position" );
142 return GetColumnsOrder()[pos
];
145 unsigned int wxHeaderCtrlBase::GetColumnPos(unsigned int idx
) const
147 const unsigned count
= GetColumnCount();
149 wxCHECK_MSG( idx
< count
, wxNO_COLUMN
, "invalid index" );
151 const wxArrayInt order
= GetColumnsOrder();
152 for ( unsigned n
= 0; n
< count
; n
++ )
154 if ( (unsigned)order
[n
] == idx
)
158 wxFAIL_MSG( "column unexpectedly not displayed at all" );
164 void wxHeaderCtrlBase::MoveColumnInOrderArray(wxArrayInt
& order
,
168 const unsigned count
= order
.size();
171 orderNew
.reserve(count
);
172 for ( unsigned n
= 0; ; n
++ )
174 // NB: order of checks is important for this to work when the new
175 // column position is the same as the old one
177 // insert the column at its new position
178 if ( orderNew
.size() == pos
)
179 orderNew
.push_back(idx
);
184 // delete the column from its old position
185 const unsigned idxOld
= order
[n
];
189 orderNew
.push_back(idxOld
);
192 order
.swap(orderNew
);
196 wxHeaderCtrlBase::DoResizeColumnIndices(wxArrayInt
& colIndices
, unsigned int count
)
198 // update the column indices array if necessary
199 const unsigned countOld
= colIndices
.size();
200 if ( count
> countOld
)
202 // all new columns have default positions equal to their indices
203 for ( unsigned n
= countOld
; n
< count
; n
++ )
204 colIndices
.push_back(n
);
206 else if ( count
< countOld
)
208 // filter out all the positions which are invalid now while keeping the
209 // order of the remaining ones
210 wxArrayInt colIndicesNew
;
211 colIndicesNew
.reserve(count
);
212 for ( unsigned n
= 0; n
< countOld
; n
++ )
214 const unsigned idx
= colIndices
[n
];
216 colIndicesNew
.push_back(idx
);
219 colIndices
.swap(colIndicesNew
);
221 else // count didn't really change, we shouldn't even be called
223 wxFAIL_MSG( "useless call to DoResizeColumnIndices()" );
226 wxASSERT_MSG( colIndices
.size() == count
, "logic error" );
229 // ----------------------------------------------------------------------------
230 // wxHeaderCtrl extra UI
231 // ----------------------------------------------------------------------------
233 int wxHeaderCtrlBase::ShowColumnsMenu(const wxString
& title
)
236 if ( !title
.empty() )
237 menu
.SetTitle(title
);
239 const unsigned count
= GetColumnCount();
240 for ( unsigned n
= 0; n
< count
; n
++ )
242 const wxHeaderColumn
& col
= GetColumn(n
);
243 menu
.AppendCheckItem(n
, col
.GetTitle());
248 return GetPopupMenuSelectionFromUser(menu
,
249 ScreenToClient(wxGetMousePosition()));
252 // ============================================================================
253 // wxHeaderCtrlSimple implementation
254 // ============================================================================
256 void wxHeaderCtrlSimple::Init()
258 m_sortKey
= wxNO_COLUMN
;
261 wxHeaderColumn
& wxHeaderCtrlSimple::GetColumn(unsigned int idx
)
266 void wxHeaderCtrlSimple::DoInsert(const wxHeaderColumnSimple
& col
, unsigned int idx
)
268 m_cols
.insert(m_cols
.begin() + idx
, col
);
273 void wxHeaderCtrlSimple::DoDelete(unsigned int idx
)
275 m_cols
.erase(m_cols
.begin() + idx
);
276 if ( idx
== m_sortKey
)
277 m_sortKey
= wxNO_COLUMN
;
282 void wxHeaderCtrlSimple::DeleteAllColumns()
285 m_sortKey
= wxNO_COLUMN
;
291 void wxHeaderCtrlSimple::DoShowColumn(unsigned int idx
, bool show
)
293 if ( show
!= m_cols
[idx
].IsShown() )
295 m_cols
[idx
].SetHidden(!show
);
301 void wxHeaderCtrlSimple::DoShowSortIndicator(unsigned int idx
, bool ascending
)
303 RemoveSortIndicator();
305 m_cols
[idx
].SetAsSortKey(ascending
);
311 void wxHeaderCtrlSimple::RemoveSortIndicator()
313 if ( m_sortKey
!= wxNO_COLUMN
)
315 const unsigned sortOld
= m_sortKey
;
316 m_sortKey
= wxNO_COLUMN
;
318 m_cols
[sortOld
].UnsetAsSortKey();
320 UpdateColumn(sortOld
);
325 wxHeaderCtrlSimple::UpdateColumnWidthToFit(unsigned int idx
, int widthTitle
)
327 const int widthContents
= GetBestFittingWidth(idx
);
328 if ( widthContents
== -1 )
331 m_cols
[idx
].SetWidth(wxMax(widthContents
, widthTitle
));
336 // ============================================================================
337 // wxHeaderCtrlEvent implementation
338 // ============================================================================
340 IMPLEMENT_DYNAMIC_CLASS(wxHeaderCtrlEvent
, wxNotifyEvent
)
342 const wxEventType wxEVT_COMMAND_HEADER_CLICK
= wxNewEventType();
343 const wxEventType wxEVT_COMMAND_HEADER_RIGHT_CLICK
= wxNewEventType();
344 const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_CLICK
= wxNewEventType();
346 const wxEventType wxEVT_COMMAND_HEADER_DCLICK
= wxNewEventType();
347 const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK
= wxNewEventType();
348 const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_DCLICK
= wxNewEventType();
350 const wxEventType wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK
= wxNewEventType();
352 const wxEventType wxEVT_COMMAND_HEADER_BEGIN_RESIZE
= wxNewEventType();
353 const wxEventType wxEVT_COMMAND_HEADER_RESIZING
= wxNewEventType();
354 const wxEventType wxEVT_COMMAND_HEADER_END_RESIZE
= wxNewEventType();
356 const wxEventType wxEVT_COMMAND_HEADER_BEGIN_REORDER
= wxNewEventType();
357 const wxEventType wxEVT_COMMAND_HEADER_END_REORDER
= wxNewEventType();
359 const wxEventType wxEVT_COMMAND_HEADER_DRAGGING_CANCELLED
= wxNewEventType();