]> git.saurik.com Git - wxWidgets.git/blame - src/msw/headerctrl.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / msw / headerctrl.cpp
CommitLineData
56873923
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/headerctrl.cpp
3// Purpose: implementation of wxHeaderCtrl for wxMSW
4// Author: Vadim Zeitlin
5// Created: 2008-12-01
56873923
VZ
6// Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
7// Licence: wxWindows licence
8///////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18// for compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
e721a2a2
VZ
25#if wxUSE_HEADERCTRL
26
56873923 27#ifndef WX_PRECOMP
9485b24f 28 #include "wx/app.h"
9ef3e400 29 #include "wx/log.h"
56873923
VZ
30#endif // WX_PRECOMP
31
32#include "wx/headerctrl.h"
3bfaa5a7
VZ
33
34#ifndef wxHAS_GENERIC_HEADERCTRL
35
56873923
VZ
36#include "wx/imaglist.h"
37
38#include "wx/msw/wrapcctl.h"
9ef3e400 39#include "wx/msw/private.h"
56873923 40
9b66a1d3
VZ
41#ifndef HDM_SETBITMAPMARGIN
42 #define HDM_SETBITMAPMARGIN 0x1234
43#endif
44
45#ifndef Header_SetBitmapMargin
46 #define Header_SetBitmapMargin(hwnd, margin) \
47 ::SendMessage((hwnd), HDM_SETBITMAPMARGIN, (WPARAM)(margin), 0)
48#endif
49
fa3d4aaf
VZ
50// from src/msw/listctrl.cpp
51extern int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick);
52
56873923
VZ
53// ============================================================================
54// wxHeaderCtrl implementation
55// ============================================================================
56
57// ----------------------------------------------------------------------------
58// wxHeaderCtrl construction/destruction
59// ----------------------------------------------------------------------------
60
61void wxHeaderCtrl::Init()
62{
040b9528 63 m_numColumns = 0;
56873923 64 m_imageList = NULL;
38cd07c4 65 m_scrollOffset = 0;
421a5048 66 m_colBeingDragged = -1;
56873923
VZ
67}
68
69bool wxHeaderCtrl::Create(wxWindow *parent,
70 wxWindowID id,
71 const wxPoint& pos,
72 const wxSize& size,
73 long style,
74 const wxString& name)
75{
76 // notice that we don't need InitCommonControlsEx(ICC_LISTVIEW_CLASSES)
77 // here as we already call InitCommonControls() in wxApp initialization
78 // code which covers this
79
80 if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
81 return false;
82
9a83f860 83 if ( !MSWCreateControl(WC_HEADER, wxT(""), pos, size) )
56873923
VZ
84 return false;
85
9485b24f
VZ
86 // special hack for margins when using comctl32.dll v6 or later: the
87 // default margin is too big and results in label truncation when the
88 // column width is just about right to show it together with the sort
89 // indicator, so reduce it to a smaller value (in principle we could even
90 // use 0 here but this starts to look ugly)
91 if ( wxApp::GetComCtl32Version() >= 600 )
92 {
93 Header_SetBitmapMargin(GetHwnd(), ::GetSystemMetrics(SM_CXEDGE));
94 }
95
56873923
VZ
96 return true;
97}
98
99WXDWORD wxHeaderCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
100{
101 WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
102
613de0e8 103 if ( style & wxHD_ALLOW_REORDER )
56873923
VZ
104 msStyle |= HDS_DRAGDROP;
105
106 // the control looks nicer with these styles and there doesn't seem to be
107 // any reason to not use them so we always do (as for HDS_HORZ it is 0
108 // anyhow but include it for clarity)
cf3fd63e
FM
109 // NOTE: don't use however HDS_FLAT because it makes the control look
110 // non-native when running WinXP in classic mode
111 msStyle |= HDS_HORZ | HDS_BUTTONS | HDS_FULLDRAG | HDS_HOTTRACK;
56873923
VZ
112
113 return msStyle;
114}
115
116wxHeaderCtrl::~wxHeaderCtrl()
117{
118 delete m_imageList;
119}
120
f24f6579
VZ
121// ----------------------------------------------------------------------------
122// wxHeaderCtrl scrolling
123// ----------------------------------------------------------------------------
124
38cd07c4
VZ
125void wxHeaderCtrl::DoSetSize(int x, int y,
126 int w, int h,
127 int sizeFlags)
128{
129 wxHeaderCtrlBase::DoSetSize(x + m_scrollOffset, y, w - m_scrollOffset, h,
130 sizeFlags);
131}
132
d8fc3398 133void wxHeaderCtrl::DoScrollHorz(int dx)
f24f6579 134{
d8fc3398
VZ
135 // as the native control doesn't support offsetting its contents, we use a
136 // hack here to make it appear correctly when the parent is scrolled:
137 // instead of scrolling or repainting we simply move the control window
138 // itself: to be precise, offset it by the scroll increment to the left and
139 // increment its width to still extend to the right boundary to compensate
140 // for it (notice that dx is negative when scrolling to the right)
38cd07c4
VZ
141 m_scrollOffset += dx;
142
143 wxHeaderCtrlBase::DoSetSize(GetPosition().x + dx, -1,
144 GetSize().x - dx, -1,
145 wxSIZE_USE_EXISTING);
f24f6579
VZ
146}
147
56873923
VZ
148// ----------------------------------------------------------------------------
149// wxHeaderCtrl geometry calculation
150// ----------------------------------------------------------------------------
151
152wxSize wxHeaderCtrl::DoGetBestSize() const
153{
154 RECT rc = wxGetClientRect(GetHwndOf(GetParent()));
155 WINDOWPOS wpos;
156 HDLAYOUT layout = { &rc, &wpos };
157 if ( !Header_Layout(GetHwnd(), &layout) )
158 {
9a83f860 159 wxLogLastError(wxT("Header_Layout"));
56873923
VZ
160 return wxControl::DoGetBestSize();
161 }
162
163 return wxSize(wpos.cx, wpos.cy);
164}
165
166// ----------------------------------------------------------------------------
167// wxHeaderCtrl columns managements
168// ----------------------------------------------------------------------------
169
170unsigned int wxHeaderCtrl::DoGetCount() const
171{
040b9528
VZ
172 // we can't use Header_GetItemCount() here because it doesn't take the
173 // hidden columns into account and we can't find the hidden columns after
174 // the last shown one in MSWFromNativeIdx() without knowing where to stop
175 // so we have to store the columns count internally
176 return m_numColumns;
177}
178
179int wxHeaderCtrl::GetShownColumnsCount() const
180{
181 const int numItems = Header_GetItemCount(GetHwnd());
182
183 wxASSERT_MSG( numItems >= 0 && (unsigned)numItems <= m_numColumns,
184 "unexpected number of items in the native control" );
185
186 return numItems;
56873923
VZ
187}
188
e2bfe673 189void wxHeaderCtrl::DoSetCount(unsigned int count)
56873923 190{
e2bfe673
VZ
191 unsigned n;
192
193 // first delete all old columns
040b9528 194 const unsigned countOld = GetShownColumnsCount();
e2bfe673
VZ
195 for ( n = 0; n < countOld; n++ )
196 {
197 if ( !Header_DeleteItem(GetHwnd(), 0) )
198 {
9a83f860 199 wxLogLastError(wxT("Header_DeleteItem"));
e2bfe673
VZ
200 }
201 }
202
040b9528
VZ
203 // update the column indices order array before changing m_numColumns
204 DoResizeColumnIndices(m_colIndices, count);
205
e2bfe673 206 // and add the new ones
040b9528
VZ
207 m_numColumns = count;
208 m_isHidden.resize(m_numColumns);
e2bfe673
VZ
209 for ( n = 0; n < count; n++ )
210 {
040b9528
VZ
211 const wxHeaderColumn& col = GetColumn(n);
212 if ( col.IsShown() )
213 {
214 m_isHidden[n] = false;
215
216 DoInsertItem(col, n);
217 }
218 else // hidden initially
219 {
220 m_isHidden[n] = true;
221 }
e2bfe673
VZ
222 }
223}
224
225void wxHeaderCtrl::DoUpdate(unsigned int idx)
226{
4de60a27
VZ
227 // the native control does provide Header_SetItem() but it's inconvenient
228 // to use it because it sends HDN_ITEMCHANGING messages and we'd have to
229 // arrange not to block setting the width from there and the logic would be
230 // more complicated as we'd have to reset the old values as well as setting
231 // the new ones -- so instead just recreate the column
702f5349 232
040b9528
VZ
233 const wxHeaderColumn& col = GetColumn(idx);
234 if ( col.IsHidden() )
235 {
236 // column is hidden now
237 if ( !m_isHidden[idx] )
238 {
239 // but it wasn't hidden before, so remove it
240 Header_DeleteItem(GetHwnd(), MSWToNativeIdx(idx));
241
242 m_isHidden[idx] = true;
243 }
244 //else: nothing to do, updating hidden column doesn't have any effect
245 }
246 else // column is shown now
247 {
248 if ( m_isHidden[idx] )
249 {
250 m_isHidden[idx] = false;
251 }
252 else // and it was shown before as well
253 {
254 // we need to remove the old column
255 Header_DeleteItem(GetHwnd(), MSWToNativeIdx(idx));
256 }
257
258 DoInsertItem(col, idx);
259 }
e2bfe673
VZ
260}
261
040b9528 262void wxHeaderCtrl::DoInsertItem(const wxHeaderColumn& col, unsigned int idx)
e2bfe673 263{
040b9528 264 wxASSERT_MSG( !col.IsHidden(), "should only be called for shown columns" );
e2bfe673
VZ
265
266 wxHDITEM hdi;
267
268 // notice that we need to store the string we use the pointer to until we
269 // pass it to the control
89c73d54 270 hdi.mask |= HDI_TEXT;
017dc06b 271 wxWxCharBuffer buf = col.GetTitle().t_str();
89c73d54
VZ
272 hdi.pszText = buf.data();
273 hdi.cchTextMax = wxStrlen(buf);
56873923
VZ
274
275 const wxBitmap bmp = col.GetBitmap();
4de60a27 276 if ( bmp.IsOk() )
56873923 277 {
89c73d54 278 hdi.mask |= HDI_IMAGE;
56873923 279
89c73d54 280 if ( bmp.IsOk() )
56873923 281 {
89c73d54
VZ
282 const int bmpWidth = bmp.GetWidth(),
283 bmpHeight = bmp.GetHeight();
284
285 if ( !m_imageList )
286 {
287 m_imageList = new wxImageList(bmpWidth, bmpHeight);
5c858faa 288 (void) // suppress mingw32 warning about unused computed value
89c73d54
VZ
289 Header_SetImageList(GetHwnd(), GetHimagelistOf(m_imageList));
290 }
291 else // already have an image list
292 {
293 // check that all bitmaps we use have the same size
294 int imageWidth,
295 imageHeight;
296 m_imageList->GetSize(0, imageWidth, imageHeight);
297
298 wxASSERT_MSG( imageWidth == bmpWidth && imageHeight == bmpHeight,
299 "all column bitmaps must have the same size" );
300 }
301
302 m_imageList->Add(bmp);
303 hdi.iImage = m_imageList->GetImageCount() - 1;
56873923 304 }
89c73d54 305 else // no bitmap but we still need to update the item
56873923 306 {
89c73d54 307 hdi.iImage = I_IMAGENONE;
56873923 308 }
56873923
VZ
309 }
310
4de60a27 311 if ( col.GetAlignment() != wxALIGN_NOT )
a0009205 312 {
9485b24f 313 hdi.mask |= HDI_FORMAT | HDF_LEFT;
e2bfe673
VZ
314 switch ( col.GetAlignment() )
315 {
316 case wxALIGN_LEFT:
317 hdi.fmt |= HDF_LEFT;
318 break;
56873923 319
e2bfe673
VZ
320 case wxALIGN_CENTER:
321 case wxALIGN_CENTER_HORIZONTAL:
322 hdi.fmt |= HDF_CENTER;
323 break;
56873923 324
e2bfe673
VZ
325 case wxALIGN_RIGHT:
326 hdi.fmt |= HDF_RIGHT;
327 break;
56873923 328
e2bfe673
VZ
329 default:
330 wxFAIL_MSG( "invalid column header alignment" );
331 }
332 }
a0009205 333
e2bfe673 334 if ( col.IsSortKey() )
a0009205 335 {
e2bfe673
VZ
336 hdi.mask |= HDI_FORMAT;
337 hdi.fmt |= col.IsSortOrderAscending() ? HDF_SORTUP : HDF_SORTDOWN;
a0009205
VZ
338 }
339
040b9528 340 if ( col.GetWidth() != wxCOL_WIDTH_DEFAULT )
a0009205 341 {
e2bfe673 342 hdi.mask |= HDI_WIDTH;
040b9528 343 hdi.cxy = col.GetWidth();
a0009205 344 }
a0009205 345
040b9528 346 hdi.mask |= HDI_ORDER;
2e733ec7 347 hdi.iOrder = MSWToNativeOrder(m_colIndices.Index(idx));
702f5349 348
040b9528
VZ
349 if ( ::SendMessage(GetHwnd(), HDM_INSERTITEM,
350 MSWToNativeIdx(idx), (LPARAM)&hdi) == -1 )
56873923 351 {
9a83f860 352 wxLogLastError(wxT("Header_InsertItem()"));
56873923
VZ
353 }
354}
355
702f5349
VZ
356void wxHeaderCtrl::DoSetColumnsOrder(const wxArrayInt& order)
357{
040b9528
VZ
358 wxArrayInt orderShown;
359 orderShown.reserve(m_numColumns);
360
361 for ( unsigned n = 0; n < m_numColumns; n++ )
362 {
363 const int idx = order[n];
364 if ( GetColumn(idx).IsShown() )
365 orderShown.push_back(MSWToNativeIdx(idx));
366 }
367
368 if ( !Header_SetOrderArray(GetHwnd(), orderShown.size(), &orderShown[0]) )
702f5349 369 {
9a83f860 370 wxLogLastError(wxT("Header_GetOrderArray"));
702f5349 371 }
040b9528
VZ
372
373 m_colIndices = order;
702f5349
VZ
374}
375
376wxArrayInt wxHeaderCtrl::DoGetColumnsOrder() const
377{
040b9528
VZ
378 // we don't use Header_GetOrderArray() here because it doesn't return
379 // information about the hidden columns, instead we just save the columns
380 // order array in DoSetColumnsOrder() and update it when they're reordered
381 return m_colIndices;
382}
383
2e733ec7
VZ
384// ----------------------------------------------------------------------------
385// wxHeaderCtrl indexes and positions translation
386// ----------------------------------------------------------------------------
387
040b9528
VZ
388int wxHeaderCtrl::MSWToNativeIdx(int idx)
389{
390 // don't check for GetColumn(idx).IsShown() as it could have just became
391 // false and we may be called from DoUpdate() to delete the old column
392 wxASSERT_MSG( !m_isHidden[idx],
393 "column must be visible to have an "
394 "index in the native control" );
395
2e733ec7 396 int item = idx;
040b9528 397 for ( int i = 0; i < idx; i++ )
702f5349 398 {
040b9528 399 if ( GetColumn(i).IsHidden() )
2e733ec7 400 item--; // one less column the native control knows about
040b9528
VZ
401 }
402
2e733ec7
VZ
403 wxASSERT_MSG( item >= 0 && item <= GetShownColumnsCount(), "logic error" );
404
405 return item;
040b9528
VZ
406}
407
408int wxHeaderCtrl::MSWFromNativeIdx(int item)
409{
410 wxASSERT_MSG( item >= 0 && item < GetShownColumnsCount(),
411 "column index out of range" );
412
413 // reverse the above function
2e733ec7
VZ
414
415 unsigned idx = item;
416 for ( unsigned n = 0; n < m_numColumns; n++ )
040b9528 417 {
2e733ec7
VZ
418 if ( n > idx )
419 break;
420
421 if ( GetColumn(n).IsHidden() )
422 idx++;
040b9528
VZ
423 }
424
2e733ec7
VZ
425 wxASSERT_MSG( MSWToNativeIdx(idx) == item, "logic error" );
426
427 return idx;
040b9528
VZ
428}
429
2e733ec7 430int wxHeaderCtrl::MSWToNativeOrder(int pos)
040b9528 431{
2e733ec7 432 wxASSERT_MSG( pos >= 0 && static_cast<unsigned>(pos) < m_numColumns,
040b9528
VZ
433 "column position out of range" );
434
2e733ec7
VZ
435 int order = pos;
436 for ( int n = 0; n < pos; n++ )
040b9528 437 {
2e733ec7
VZ
438 if ( GetColumn(m_colIndices[n]).IsHidden() )
439 order--;
702f5349
VZ
440 }
441
2e733ec7
VZ
442 wxASSERT_MSG( order >= 0 && order <= GetShownColumnsCount(), "logic error" );
443
702f5349
VZ
444 return order;
445}
446
2e733ec7
VZ
447int wxHeaderCtrl::MSWFromNativeOrder(int order)
448{
449 wxASSERT_MSG( order >= 0 && order < GetShownColumnsCount(),
450 "native column position out of range" );
451
452 unsigned pos = order;
453 for ( unsigned n = 0; n < m_numColumns; n++ )
454 {
455 if ( n > pos )
456 break;
457
458 if ( GetColumn(m_colIndices[n]).IsHidden() )
459 pos++;
460 }
461
462 wxASSERT_MSG( MSWToNativeOrder(pos) == order, "logic error" );
463
464 return pos;
465}
466
fa3d4aaf
VZ
467// ----------------------------------------------------------------------------
468// wxHeaderCtrl events
469// ----------------------------------------------------------------------------
470
aef252d9 471wxEventType wxHeaderCtrl::GetClickEventType(bool dblclk, int button)
fa3d4aaf
VZ
472{
473 wxEventType evtType;
474 switch ( button )
475 {
476 case 0:
ce7fe42e
VZ
477 evtType = dblclk ? wxEVT_HEADER_DCLICK
478 : wxEVT_HEADER_CLICK;
fa3d4aaf
VZ
479 break;
480
481 case 1:
ce7fe42e
VZ
482 evtType = dblclk ? wxEVT_HEADER_RIGHT_DCLICK
483 : wxEVT_HEADER_RIGHT_CLICK;
fa3d4aaf
VZ
484 break;
485
486 case 2:
ce7fe42e
VZ
487 evtType = dblclk ? wxEVT_HEADER_MIDDLE_DCLICK
488 : wxEVT_HEADER_MIDDLE_CLICK;
fa3d4aaf
VZ
489 break;
490
491 default:
492 wxFAIL_MSG( wxS("unexpected event type") );
aef252d9 493 evtType = wxEVT_NULL;
fa3d4aaf
VZ
494 }
495
aef252d9 496 return evtType;
fa3d4aaf
VZ
497}
498
499bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
500{
501 NMHEADER * const nmhdr = (NMHEADER *)lParam;
502
aef252d9 503 wxEventType evtType = wxEVT_NULL;
aef252d9 504 int width = 0;
702f5349 505 int order = -1;
702f5349 506 bool veto = false;
0c9c5b43 507 const UINT code = nmhdr->hdr.code;
040b9528
VZ
508
509 // we don't have the index for all events, e.g. not for NM_RELEASEDCAPTURE
510 // so only access for header control events (and yes, the direction of
511 // comparisons with FIRST/LAST is correct even if it seems inverted)
512 int idx = code <= HDN_FIRST && code > HDN_LAST ? nmhdr->iItem : -1;
513 if ( idx != -1 )
514 {
515 // we also get bogus HDN_BEGINDRAG with -1 index so don't call
516 // MSWFromNativeIdx() unconditionally for nmhdr->iItem
517 idx = MSWFromNativeIdx(idx);
518 }
519
0c9c5b43 520 switch ( code )
fa3d4aaf 521 {
aef252d9
VZ
522 // click events
523 // ------------
524
fa3d4aaf
VZ
525 case HDN_ITEMCLICK:
526 case HDN_ITEMDBLCLICK:
aef252d9 527 evtType = GetClickEventType(code == HDN_ITEMDBLCLICK, nmhdr->iButton);
421a5048
VZ
528
529 // We're not dragging any more.
530 m_colBeingDragged = -1;
fa3d4aaf
VZ
531 break;
532
533 // although we should get the notifications about the right clicks
534 // via HDN_ITEM[DBL]CLICK too according to MSDN this simply doesn't
535 // happen in practice on any Windows system up to 2003
536 case NM_RCLICK:
537 case NM_RDBLCLK:
538 {
539 POINT pt;
aef252d9
VZ
540 idx = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
541 if ( idx != wxNOT_FOUND )
040b9528
VZ
542 {
543 idx = MSWFromNativeIdx(idx);
36e5a9a7
VZ
544
545 // due to a bug in mingw32 headers NM_RDBLCLK is signed
546 // there so we need a cast to avoid warnings about signed/
547 // unsigned comparison
548 evtType = GetClickEventType(
549 code == static_cast<UINT>(NM_RDBLCLK), 1);
040b9528 550 }
fa3d4aaf
VZ
551 //else: ignore clicks outside any column
552 }
553 break;
3bfaa5a7
VZ
554
555 case HDN_DIVIDERDBLCLICK:
ce7fe42e 556 evtType = wxEVT_HEADER_SEPARATOR_DCLICK;
aef252d9
VZ
557 break;
558
559
560 // column resizing events
561 // ----------------------
562
563 // see comments in wxListCtrl::MSWOnNotify() for why we catch both
564 // ASCII and Unicode versions of this message
565 case HDN_BEGINTRACKA:
566 case HDN_BEGINTRACKW:
d13b34d3 567 // non-resizable columns can't be resized no matter what, don't
0b2e1483
VZ
568 // even generate any events for them
569 if ( !GetColumn(idx).IsResizeable() )
570 {
702f5349
VZ
571 veto = true;
572 break;
0b2e1483
VZ
573 }
574
ce7fe42e 575 evtType = wxEVT_HEADER_BEGIN_RESIZE;
aef252d9
VZ
576 // fall through
577
aef252d9
VZ
578 case HDN_ENDTRACKA:
579 case HDN_ENDTRACKW:
a45caa71
VZ
580 width = nmhdr->pitem->cxy;
581
aef252d9 582 if ( evtType == wxEVT_NULL )
a45caa71 583 {
ce7fe42e 584 evtType = wxEVT_HEADER_END_RESIZE;
aef252d9 585
a45caa71
VZ
586 // don't generate events with invalid width
587 const int minWidth = GetColumn(idx).GetMinWidth();
588 if ( width < minWidth )
589 width = minWidth;
590 }
591 break;
592
f69306fe
VZ
593 // The control is not supposed to send HDN_TRACK when using
594 // HDS_FULLDRAG (which we do use) but apparently some versions of
595 // comctl32.dll still do it, see #13506, so catch both messages
596 // just in case we are dealing with one of these buggy versions.
597 case HDN_TRACK:
a45caa71
VZ
598 case HDN_ITEMCHANGING:
599 if ( nmhdr->pitem && (nmhdr->pitem->mask & HDI_WIDTH) )
600 {
601 // prevent the column from being shrunk beneath its min width
93e4e62b
VZ
602 width = nmhdr->pitem->cxy;
603 if ( width < GetColumn(idx).GetMinWidth() )
604 {
605 // don't generate any events and prevent the change from
606 // happening
702f5349 607 veto = true;
93e4e62b
VZ
608 }
609 else // width is acceptable
610 {
611 // generate the resizing event from here as we don't seem
612 // to be getting HDN_TRACK events at all, at least with
613 // comctl32.dll v6
ce7fe42e 614 evtType = wxEVT_HEADER_RESIZING;
93e4e62b 615 }
702f5349
VZ
616 }
617 break;
618
619
620 // column reordering events
621 // ------------------------
622
623 case HDN_BEGINDRAG:
624 // Windows sometimes sends us events with invalid column indices
040b9528 625 if ( nmhdr->iItem == -1 )
702f5349 626 break;
a45caa71 627
421a5048
VZ
628 // If we are dragging a column that is not draggable and the mouse
629 // is moved over a different column then we get the column number from
630 // the column under the mouse. This results in an unexpected behaviour
631 // if this column is draggable. To prevent this remember the column we
632 // are dragging for the complete drag and drop cycle.
633 if ( m_colBeingDragged == -1 )
634 {
635 m_colBeingDragged = idx;
636 }
637
702f5349 638 // column must have the appropriate flag to be draggable
421a5048 639 if ( !GetColumn(m_colBeingDragged).IsReorderable() )
702f5349
VZ
640 {
641 veto = true;
642 break;
a45caa71 643 }
702f5349 644
ce7fe42e 645 evtType = wxEVT_HEADER_BEGIN_REORDER;
702f5349
VZ
646 break;
647
648 case HDN_ENDDRAG:
702f5349
VZ
649 wxASSERT_MSG( nmhdr->pitem->mask & HDI_ORDER, "should have order" );
650 order = nmhdr->pitem->iOrder;
040b9528
VZ
651
652 // we also get messages with invalid order when column reordering
653 // is cancelled (e.g. by pressing Esc)
654 if ( order == -1 )
655 break;
656
657 order = MSWFromNativeOrder(order);
658
ce7fe42e 659 evtType = wxEVT_HEADER_END_REORDER;
421a5048
VZ
660
661 // We (successfully) ended dragging the column.
662 m_colBeingDragged = -1;
a45caa71
VZ
663 break;
664
665 case NM_RELEASEDCAPTURE:
ce7fe42e 666 evtType = wxEVT_HEADER_DRAGGING_CANCELLED;
421a5048
VZ
667
668 // Dragging the column was cancelled.
669 m_colBeingDragged = -1;
3bfaa5a7 670 break;
fa3d4aaf
VZ
671 }
672
aef252d9
VZ
673
674 // do generate the corresponding wx event
675 if ( evtType != wxEVT_NULL )
676 {
677 wxHeaderCtrlEvent event(evtType, GetId());
678 event.SetEventObject(this);
679 event.SetColumn(idx);
680 event.SetWidth(width);
702f5349
VZ
681 if ( order != -1 )
682 event.SetNewOrder(order);
aef252d9 683
8478ed64 684 const bool processed = GetEventHandler()->ProcessEvent(event);
aef252d9 685
8478ed64 686 if ( processed && !event.IsAllowed() )
702f5349 687 veto = true;
8478ed64
VZ
688
689 if ( !veto )
040b9528
VZ
690 {
691 // special post-processing for HDN_ENDDRAG: we need to update the
692 // internal column indices array if this is allowed to go ahead as
693 // the native control is going to reorder its columns now
ce7fe42e 694 if ( evtType == wxEVT_HEADER_END_REORDER )
040b9528 695 MoveColumnInOrderArray(m_colIndices, idx, order);
8478ed64
VZ
696
697 if ( processed )
698 {
699 // skip default processing below
700 return true;
701 }
040b9528 702 }
aef252d9
VZ
703 }
704
702f5349
VZ
705 if ( veto )
706 {
707 // all of HDN_BEGIN{DRAG,TRACK}, HDN_TRACK and HDN_ITEMCHANGING
708 // interpret TRUE return value as meaning to stop the control
709 // default handling of the message
710 *result = TRUE;
711
712 return true;
713 }
714
fa3d4aaf
VZ
715 return wxHeaderCtrlBase::MSWOnNotify(idCtrl, lParam, result);
716}
3bfaa5a7
VZ
717
718#endif // wxHAS_GENERIC_HEADERCTRL
e721a2a2
VZ
719
720#endif // wxUSE_HEADERCTRL