+ hdi.cxy = col.GetWidth();
+ }
+
+ hdi.mask |= HDI_ORDER;
+ hdi.iOrder = MSWToNativeOrder(m_colIndices.Index(idx));
+
+ if ( ::SendMessage(GetHwnd(), HDM_INSERTITEM,
+ MSWToNativeIdx(idx), (LPARAM)&hdi) == -1 )
+ {
+ wxLogLastError(_T("Header_InsertItem()"));
+ }
+}
+
+void wxHeaderCtrl::DoSetColumnsOrder(const wxArrayInt& order)
+{
+ wxArrayInt orderShown;
+ orderShown.reserve(m_numColumns);
+
+ for ( unsigned n = 0; n < m_numColumns; n++ )
+ {
+ const int idx = order[n];
+ if ( GetColumn(idx).IsShown() )
+ orderShown.push_back(MSWToNativeIdx(idx));
+ }
+
+ if ( !Header_SetOrderArray(GetHwnd(), orderShown.size(), &orderShown[0]) )
+ {
+ wxLogLastError(_T("Header_GetOrderArray"));
+ }
+
+ m_colIndices = order;
+}
+
+wxArrayInt wxHeaderCtrl::DoGetColumnsOrder() const
+{
+ // we don't use Header_GetOrderArray() here because it doesn't return
+ // information about the hidden columns, instead we just save the columns
+ // order array in DoSetColumnsOrder() and update it when they're reordered
+ return m_colIndices;
+}
+
+// ----------------------------------------------------------------------------
+// wxHeaderCtrl indexes and positions translation
+// ----------------------------------------------------------------------------
+
+int wxHeaderCtrl::MSWToNativeIdx(int idx)
+{
+ // don't check for GetColumn(idx).IsShown() as it could have just became
+ // false and we may be called from DoUpdate() to delete the old column
+ wxASSERT_MSG( !m_isHidden[idx],
+ "column must be visible to have an "
+ "index in the native control" );
+
+ int item = idx;
+ for ( int i = 0; i < idx; i++ )
+ {
+ if ( GetColumn(i).IsHidden() )
+ item--; // one less column the native control knows about
+ }
+
+ wxASSERT_MSG( item >= 0 && item <= GetShownColumnsCount(), "logic error" );
+
+ return item;
+}
+
+int wxHeaderCtrl::MSWFromNativeIdx(int item)
+{
+ wxASSERT_MSG( item >= 0 && item < GetShownColumnsCount(),
+ "column index out of range" );
+
+ // reverse the above function
+
+ unsigned idx = item;
+ for ( unsigned n = 0; n < m_numColumns; n++ )
+ {
+ if ( n > idx )
+ break;
+
+ if ( GetColumn(n).IsHidden() )
+ idx++;
+ }
+
+ wxASSERT_MSG( MSWToNativeIdx(idx) == item, "logic error" );
+
+ return idx;
+}
+
+int wxHeaderCtrl::MSWToNativeOrder(int pos)
+{
+ wxASSERT_MSG( pos >= 0 && static_cast<unsigned>(pos) < m_numColumns,
+ "column position out of range" );
+
+ int order = pos;
+ for ( int n = 0; n < pos; n++ )
+ {
+ if ( GetColumn(m_colIndices[n]).IsHidden() )
+ order--;
+ }
+
+ wxASSERT_MSG( order >= 0 && order <= GetShownColumnsCount(), "logic error" );
+
+ return order;
+}
+
+int wxHeaderCtrl::MSWFromNativeOrder(int order)
+{
+ wxASSERT_MSG( order >= 0 && order < GetShownColumnsCount(),
+ "native column position out of range" );
+
+ unsigned pos = order;
+ for ( unsigned n = 0; n < m_numColumns; n++ )
+ {
+ if ( n > pos )
+ break;
+
+ if ( GetColumn(m_colIndices[n]).IsHidden() )
+ pos++;
+ }
+
+ wxASSERT_MSG( MSWToNativeOrder(pos) == order, "logic error" );
+
+ return pos;
+}
+
+// ----------------------------------------------------------------------------
+// wxHeaderCtrl events
+// ----------------------------------------------------------------------------
+
+wxEventType wxHeaderCtrl::GetClickEventType(bool dblclk, int button)
+{
+ wxEventType evtType;
+ switch ( button )
+ {
+ case 0:
+ evtType = dblclk ? wxEVT_COMMAND_HEADER_DCLICK
+ : wxEVT_COMMAND_HEADER_CLICK;
+ break;
+
+ case 1:
+ evtType = dblclk ? wxEVT_COMMAND_HEADER_RIGHT_DCLICK
+ : wxEVT_COMMAND_HEADER_RIGHT_CLICK;
+ break;
+
+ case 2:
+ evtType = dblclk ? wxEVT_COMMAND_HEADER_MIDDLE_DCLICK
+ : wxEVT_COMMAND_HEADER_MIDDLE_CLICK;
+ break;
+
+ default:
+ wxFAIL_MSG( wxS("unexpected event type") );
+ evtType = wxEVT_NULL;
+ }
+
+ return evtType;
+}
+
+bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
+{
+ NMHEADER * const nmhdr = (NMHEADER *)lParam;
+
+ wxEventType evtType = wxEVT_NULL;
+ int width = 0;
+ int order = -1;
+ bool veto = false;
+ const UINT code = nmhdr->hdr.code;
+
+ // we don't have the index for all events, e.g. not for NM_RELEASEDCAPTURE
+ // so only access for header control events (and yes, the direction of
+ // comparisons with FIRST/LAST is correct even if it seems inverted)
+ int idx = code <= HDN_FIRST && code > HDN_LAST ? nmhdr->iItem : -1;
+ if ( idx != -1 )
+ {
+ // we also get bogus HDN_BEGINDRAG with -1 index so don't call
+ // MSWFromNativeIdx() unconditionally for nmhdr->iItem
+ idx = MSWFromNativeIdx(idx);
+ }
+
+ switch ( code )
+ {
+ // click events
+ // ------------
+
+ case HDN_ITEMCLICK:
+ case HDN_ITEMDBLCLICK:
+ evtType = GetClickEventType(code == HDN_ITEMDBLCLICK, nmhdr->iButton);
+ break;
+
+ // although we should get the notifications about the right clicks
+ // via HDN_ITEM[DBL]CLICK too according to MSDN this simply doesn't
+ // happen in practice on any Windows system up to 2003
+ case NM_RCLICK:
+ case NM_RDBLCLK:
+ {
+ POINT pt;
+ idx = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
+ if ( idx != wxNOT_FOUND )
+ {
+ idx = MSWFromNativeIdx(idx);
+ evtType = GetClickEventType(code == NM_RDBLCLK, 1);
+ }
+ //else: ignore clicks outside any column
+ }
+ break;
+
+ case HDN_DIVIDERDBLCLICK:
+ evtType = wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK;
+ break;
+
+
+ // column resizing events
+ // ----------------------
+
+ // see comments in wxListCtrl::MSWOnNotify() for why we catch both
+ // ASCII and Unicode versions of this message
+ case HDN_BEGINTRACKA:
+ case HDN_BEGINTRACKW:
+ // non-resizeable columns can't be resized no matter what, don't
+ // even generate any events for them
+ if ( !GetColumn(idx).IsResizeable() )
+ {
+ veto = true;
+ break;
+ }
+
+ evtType = wxEVT_COMMAND_HEADER_BEGIN_RESIZE;
+ // fall through
+
+ case HDN_ENDTRACKA:
+ case HDN_ENDTRACKW:
+ width = nmhdr->pitem->cxy;
+
+ if ( evtType == wxEVT_NULL )
+ {
+ evtType = wxEVT_COMMAND_HEADER_END_RESIZE;
+
+ // don't generate events with invalid width
+ const int minWidth = GetColumn(idx).GetMinWidth();
+ if ( width < minWidth )
+ width = minWidth;
+ }
+ break;
+
+ case HDN_ITEMCHANGING:
+ if ( nmhdr->pitem && (nmhdr->pitem->mask & HDI_WIDTH) )
+ {
+ // prevent the column from being shrunk beneath its min width
+ width = nmhdr->pitem->cxy;
+ if ( width < GetColumn(idx).GetMinWidth() )
+ {
+ // don't generate any events and prevent the change from
+ // happening
+ veto = true;
+ }
+ else // width is acceptable
+ {
+ // generate the resizing event from here as we don't seem
+ // to be getting HDN_TRACK events at all, at least with
+ // comctl32.dll v6
+ evtType = wxEVT_COMMAND_HEADER_RESIZING;
+ }
+ }
+ break;
+
+
+ // column reordering events
+ // ------------------------
+
+ case HDN_BEGINDRAG:
+ // Windows sometimes sends us events with invalid column indices
+ if ( nmhdr->iItem == -1 )
+ break;
+
+ // column must have the appropriate flag to be draggable
+ if ( !GetColumn(idx).IsReorderable() )
+ {
+ veto = true;
+ break;
+ }
+
+ evtType = wxEVT_COMMAND_HEADER_BEGIN_REORDER;
+ break;
+
+ case HDN_ENDDRAG:
+ wxASSERT_MSG( nmhdr->pitem->mask & HDI_ORDER, "should have order" );
+ order = nmhdr->pitem->iOrder;
+
+ // we also get messages with invalid order when column reordering
+ // is cancelled (e.g. by pressing Esc)
+ if ( order == -1 )
+ break;
+
+ order = MSWFromNativeOrder(order);
+
+ evtType = wxEVT_COMMAND_HEADER_END_REORDER;
+ break;
+
+ case NM_RELEASEDCAPTURE:
+ evtType = wxEVT_COMMAND_HEADER_DRAGGING_CANCELLED;
+ break;