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