// and add the new ones
for ( n = 0; n < count; n++ )
{
- DoSetOrInsertItem(Insert, n);
+ DoInsertItem(n);
}
}
void wxHeaderCtrl::DoUpdate(unsigned int idx)
{
- DoSetOrInsertItem(Set, idx);
+ // the native control does provide Header_SetItem() but it's inconvenient
+ // to use it because it sends HDN_ITEMCHANGING messages and we'd have to
+ // arrange not to block setting the width from there and the logic would be
+ // more complicated as we'd have to reset the old values as well as setting
+ // the new ones -- so instead just recreate the column
+ Header_DeleteItem(GetHwnd(), idx);
+ DoInsertItem(idx);
}
-void wxHeaderCtrl::DoSetOrInsertItem(Operation oper, unsigned int idx)
+void wxHeaderCtrl::DoInsertItem(unsigned int idx)
{
const wxHeaderColumnBase& col = GetColumn(idx);
// notice that we need to store the string we use the pointer to until we
// pass it to the control
- wxWxCharBuffer buf;
- if ( !col.GetTitle().empty() )
- {
- hdi.mask |= HDI_TEXT;
-
- buf = col.GetTitle().wx_str();
- hdi.pszText = buf.data();
- hdi.cchTextMax = wxStrlen(buf);
- }
+ hdi.mask |= HDI_TEXT;
+ wxWxCharBuffer buf = col.GetTitle().wx_str();
+ hdi.pszText = buf.data();
+ hdi.cchTextMax = wxStrlen(buf);
const wxBitmap bmp = col.GetBitmap();
if ( bmp.IsOk() )
{
- const int bmpWidth = bmp.GetWidth(),
- bmpHeight = bmp.GetHeight();
+ hdi.mask |= HDI_IMAGE;
- if ( !m_imageList )
+ if ( bmp.IsOk() )
{
- m_imageList = new wxImageList(bmpWidth, bmpHeight);
- Header_SetImageList(GetHwnd(), GetHimagelistOf(m_imageList));
+ const int bmpWidth = bmp.GetWidth(),
+ bmpHeight = bmp.GetHeight();
+
+ if ( !m_imageList )
+ {
+ m_imageList = new wxImageList(bmpWidth, bmpHeight);
+ Header_SetImageList(GetHwnd(), GetHimagelistOf(m_imageList));
+ }
+ else // already have an image list
+ {
+ // check that all bitmaps we use have the same size
+ int imageWidth,
+ imageHeight;
+ m_imageList->GetSize(0, imageWidth, imageHeight);
+
+ wxASSERT_MSG( imageWidth == bmpWidth && imageHeight == bmpHeight,
+ "all column bitmaps must have the same size" );
+ }
+
+ m_imageList->Add(bmp);
+ hdi.iImage = m_imageList->GetImageCount() - 1;
}
- else // already have an image list
+ else // no bitmap but we still need to update the item
{
- // check that all bitmaps we use have the same size
- int imageWidth,
- imageHeight;
- m_imageList->GetSize(0, imageWidth, imageHeight);
-
- wxASSERT_MSG( imageWidth == bmpWidth && imageHeight == bmpHeight,
- "all column bitmaps must have the same size" );
+ hdi.iImage = I_IMAGENONE;
}
-
- m_imageList->Add(bmp);
- hdi.mask |= HDI_IMAGE;
- hdi.iImage = m_imageList->GetImageCount() - 1;
}
if ( col.GetAlignment() != wxALIGN_NOT )
hdi.cxy = col.IsHidden() ? 0 : col.GetWidth();
}
- const LRESULT rc = ::SendMessage(GetHwnd(),
- oper == Set ? HDM_SETITEM : HDM_INSERTITEM,
- idx,
- (LPARAM)&hdi);
- if ( oper == Set )
+ if ( ::SendMessage(GetHwnd(), HDM_INSERTITEM, idx, (LPARAM)&hdi) == -1 )
{
- if ( !rc )
- wxLogLastError(_T("Header_SetItem()"));
- }
- else // Insert
- {
- if ( rc == -1 )
- wxLogLastError(_T("Header_InsertItem()"));
+ wxLogLastError(_T("Header_InsertItem()"));
}
}
// wxHeaderCtrl events
// ----------------------------------------------------------------------------
-bool wxHeaderCtrl::SendEvent(wxEventType evtType, unsigned int idx)
-{
- wxHeaderCtrlEvent event(evtType, GetId());
- event.SetEventObject(this);
- event.SetColumn(idx);
-
- return GetEventHandler()->ProcessEvent(event);
-}
-
-bool wxHeaderCtrl::SendClickEvent(bool dblclk, int button, unsigned int idx)
+wxEventType wxHeaderCtrl::GetClickEventType(bool dblclk, int button)
{
wxEventType evtType;
switch ( button )
default:
wxFAIL_MSG( wxS("unexpected event type") );
- return false;
+ evtType = wxEVT_NULL;
}
- return SendEvent(evtType, idx);
+ return evtType;
}
bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{
NMHEADER * const nmhdr = (NMHEADER *)lParam;
- const int idx = nmhdr->iItem;
- switch ( const UINT code = nmhdr->hdr.code )
+ wxEventType evtType = wxEVT_NULL;
+ int idx = nmhdr->iItem;
+ int width = 0;
+ bool cancelled = false;
+ const UINT code = nmhdr->hdr.code;
+ switch ( code )
{
+ // click events
+ // ------------
+
case HDN_ITEMCLICK:
case HDN_ITEMDBLCLICK:
- if ( SendClickEvent(code == HDN_ITEMDBLCLICK, nmhdr->iButton, idx) )
- return true;
+ evtType = GetClickEventType(code == HDN_ITEMDBLCLICK, nmhdr->iButton);
break;
// although we should get the notifications about the right clicks
case NM_RDBLCLK:
{
POINT pt;
- const int col = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
- if ( col != wxNOT_FOUND )
- {
- if ( SendClickEvent(code == NM_RDBLCLK, 1, col) )
- return true;
- }
+ idx = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
+ if ( idx != wxNOT_FOUND )
+ evtType = GetClickEventType(code == NM_RDBLCLK, 1);
//else: ignore clicks outside any column
}
break;
case HDN_DIVIDERDBLCLICK:
- if ( SendEvent(wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK, idx) )
+ 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() )
+ {
+ *result = TRUE;
+
return true;
+ }
+
+ evtType = wxEVT_COMMAND_HEADER_BEGIN_RESIZE;
+ // fall through
+
+ case HDN_TRACKA:
+ case HDN_TRACKW:
+ if ( evtType == wxEVT_NULL )
+ evtType = wxEVT_COMMAND_HEADER_RESIZING;
+ // 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
+ if ( nmhdr->pitem->cxy < GetColumn(idx).GetMinWidth() )
+ {
+ *result = TRUE;
+
+ return true;
+ }
+ }
break;
+
+ case NM_RELEASEDCAPTURE:
+ cancelled = true;
+ break;
+ }
+
+
+ // do generate the corresponding wx event
+ if ( evtType != wxEVT_NULL )
+ {
+ wxHeaderCtrlEvent event(evtType, GetId());
+ event.SetEventObject(this);
+ event.SetColumn(idx);
+ event.SetWidth(width);
+ if ( cancelled )
+ event.SetCancelled();
+
+ if ( GetEventHandler()->ProcessEvent(event) )
+ {
+ if ( !event.IsAllowed() )
+ {
+ // all of HDN_BEGIN{DRAG,TRACK}, HDN_TRACK and HDN_ITEMCHANGING
+ // interpret TRUE return value as meaning to stop the control
+ // default handling of the message
+ *result = TRUE;
+ }
+
+ return true;
+ }
}
return wxHeaderCtrlBase::MSWOnNotify(idCtrl, lParam, result);