+void wxDataViewHeaderWindowMSW::UpdateDisplay()
+{
+ // remove old columns
+ for (int j=0, max=Header_GetItemCount((HWND)m_hWnd); j < max; j++)
+ Header_DeleteItem((HWND)m_hWnd, 0);
+
+ // add the updated array of columns to the header control
+ unsigned int cols = GetOwner()->GetColumnCount();
+ unsigned int added = 0;
+ for (unsigned int i = 0; i < cols; i++)
+ {
+ wxDataViewColumn *col = GetColumn( i );
+ if (col->IsHidden())
+ continue; // don't add it!
+
+ HDITEM hdi;
+ hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;
+ hdi.pszText = (wxChar *) col->GetTitle().c_str();
+ hdi.cxy = col->GetWidth();
+ hdi.cchTextMax = sizeof(hdi.pszText)/sizeof(hdi.pszText[0]);
+ hdi.fmt = HDF_LEFT | HDF_STRING;
+
+ // lParam is reserved for application's use:
+ // we store there the column index to use it later in MSWOnNotify
+ // (since columns may have been hidden)
+ hdi.lParam = (LPARAM)i;
+
+ // the native wxMSW implementation of the header window
+ // draws the column separator COLUMN_WIDTH_OFFSET pixels
+ // on the right: to correct this effect we make the column
+ // exactly COLUMN_WIDTH_OFFSET wider (for the first column):
+ if (i == 0)
+ hdi.cxy += COLUMN_WIDTH_OFFSET;
+
+ switch (col->GetAlignment())
+ {
+ case wxALIGN_LEFT:
+ hdi.fmt |= HDF_LEFT;
+ break;
+ case wxALIGN_CENTER:
+ case wxALIGN_CENTER_HORIZONTAL:
+ hdi.fmt |= HDF_CENTER;
+ break;
+ case wxALIGN_RIGHT:
+ hdi.fmt |= HDF_RIGHT;
+ break;
+
+ default:
+ // such alignment is not allowed for the column header!
+ wxFAIL;
+ }
+
+ SendMessage((HWND)m_hWnd, HDM_INSERTITEM,
+ (WPARAM)added, (LPARAM)&hdi);
+ added++;
+ }
+}
+
+unsigned int wxDataViewHeaderWindowMSW::GetColumnIdxFromHeader(NMHEADER *nmHDR)
+{
+ unsigned int idx;
+
+ // NOTE: we don't just return nmHDR->iItem because when there are
+ // hidden columns, nmHDR->iItem may be different from
+ // nmHDR->pitem->lParam
+
+ if (nmHDR->pitem && nmHDR->pitem->mask & HDI_LPARAM)
+ {
+ idx = (unsigned int)nmHDR->pitem->lParam;
+ return idx;
+ }
+
+ HDITEM item;
+ item.mask = HDI_LPARAM;
+ Header_GetItem((HWND)m_hWnd, nmHDR->iItem, &item);
+
+ return (unsigned int)item.lParam;
+}
+
+bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
+{
+ NMHDR *nmhdr = (NMHDR *)lParam;
+
+ // is it a message from the header?
+ if ( nmhdr->hwndFrom != (HWND)m_hWnd )
+ return wxWindow::MSWOnNotify(idCtrl, lParam, result);
+
+ NMHEADER *nmHDR = (NMHEADER *)nmhdr;
+ switch ( nmhdr->code )
+ {
+ case HDN_BEGINTRACK:
+ // user has started to resize a column:
+ // do we need to veto it?
+ if (!GetColumn(nmHDR->iItem)->IsResizeable())
+ {
+ // veto it!
+ *result = TRUE;
+ }
+ break;
+
+ case HDN_BEGINDRAG:
+ // user has started to reorder a column
+ break;
+
+ case HDN_ITEMCHANGING:
+ if (nmHDR->pitem != NULL &&
+ (nmHDR->pitem->mask & HDI_WIDTH) != 0)
+ {
+ int minWidth = GetColumnFromHeader(nmHDR)->GetMinWidth();
+ if (nmHDR->pitem->cxy < minWidth)
+ {
+ // do not allow the user to resize this column under
+ // its minimal width:
+ *result = TRUE;
+ }
+ }
+ break;
+
+ case HDN_ITEMCHANGED: // user is resizing a column
+ case HDN_ENDTRACK: // user has finished resizing a column
+ case HDN_ENDDRAG: // user has finished reordering a column
+
+ // update the width of the modified column:
+ if (nmHDR->pitem != NULL &&
+ (nmHDR->pitem->mask & HDI_WIDTH) != 0)
+ {
+ unsigned int idx = GetColumnIdxFromHeader(nmHDR);
+ unsigned int w = nmHDR->pitem->cxy;
+ wxDataViewColumn *col = GetColumn(idx);
+
+ // see UpdateDisplay() for more info about COLUMN_WIDTH_OFFSET
+ if (idx == 0 && w > COLUMN_WIDTH_OFFSET)
+ w -= COLUMN_WIDTH_OFFSET;
+
+ if (w >= (unsigned)col->GetMinWidth())
+ col->SetInternalWidth(w);
+ }
+ break;
+
+ case HDN_ITEMCLICK:
+ {
+ unsigned int idx = GetColumnIdxFromHeader(nmHDR);
+ wxEventType evt = nmHDR->iButton == 0 ?
+ wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK :
+ wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK;
+ SendEvent(evt, idx);
+ }
+ break;
+
+ case NM_RCLICK:
+ {
+ // NOTE: for some reason (i.e. for a bug in Windows)
+ // the HDN_ITEMCLICK notification is not sent on
+ // right clicks, so we need to handle NM_RCLICK
+
+ POINT ptClick;
+ int column = wxMSWGetColumnClicked(nmhdr, &ptClick);
+ if (column != wxNOT_FOUND)
+ {
+ HDITEM item;
+ item.mask = HDI_LPARAM;
+ Header_GetItem((HWND)m_hWnd, column, &item);
+
+ // 'idx' may be different from 'column' if there are
+ // hidden columns...
+ unsigned int idx = (unsigned int)item.lParam;
+ SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
+ idx);
+ }
+ }
+ break;
+
+ case HDN_GETDISPINFOW:
+ // see wxListCtrl::MSWOnNotify for more info!
+ break;
+
+ case HDN_ITEMDBLCLICK:
+ {
+ unsigned int idx = GetColumnIdxFromHeader(nmHDR);
+ int w = GetOwner()->GetBestColumnWidth(idx);
+
+ // update the native control:
+ HDITEM hd;
+ ZeroMemory(&hd, sizeof(hd));
+ hd.mask = HDI_WIDTH;
+ hd.cxy = w;
+ Header_SetItem(GetHwnd(),
+ nmHDR->iItem, // NOTE: we don't want 'idx' here!
+ &hd);
+
+ // update the wxDataViewColumn class:
+ GetColumn(idx)->SetInternalWidth(w);
+ }
+ break;
+
+ default:
+ return wxWindow::MSWOnNotify(idCtrl, lParam, result);
+ }
+
+ return true;
+}
+
+void wxDataViewHeaderWindowMSW::ScrollWindow(int WXUNUSED(dx), int WXUNUSED(dy),
+ const wxRect *WXUNUSED(rect))
+{
+ wxSize ourSz = GetClientSize();
+ wxSize ownerSz = m_owner->GetClientSize();
+
+ // where should the (logical) origin of this window be placed?
+ int x1 = 0, y1 = 0;
+ m_owner->CalcUnscrolledPosition(0, 0, &x1, &y1);
+
+ // put this window on top of our parent and
+ SetWindowPos((HWND)m_hWnd, HWND_TOP, -x1, 0,
+ ownerSz.GetWidth() + x1, ourSz.GetHeight(),
+ SWP_SHOWWINDOW);
+}
+
+void wxDataViewHeaderWindowMSW::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
+ int WXUNUSED(w), int WXUNUSED(h),
+ int WXUNUSED(f))
+{
+ // the wxDataViewCtrl's internal wxBoxSizer will call this function when
+ // the wxDataViewCtrl window gets resized: the following dummy call
+ // to ScrollWindow() is required in order to get this header window
+ // correctly repainted when it's (horizontally) scrolled:
+
+ ScrollWindow(0, 0);
+}