4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Eric Kohl for CodeWeavers
6 * Copyright 2003 Maxime Bellenge
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * - Imagelist support (partially).
24 * - Callback items (under construction).
25 * - Hottrack support (partially).
26 * - Custom draw support (including Notifications).
27 * - Drag and Drop support (including Notifications).
29 * - Use notification format
30 * - Correct the order maintenance code to preserve valid order
39 #include "wine/unicode.h"
45 #include "imagelist.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(header
);
60 INT iOrder
; /* see documentation of HD_ITEM */
62 BOOL bDown
; /* is item pressed? (used for drawing) */
63 RECT rect
; /* bounding rectangle of the item */
64 DWORD callbackMask
; /* HDI_* flags for items that are callback */
70 HWND hwndNotify
; /* Owner window to send notifications to */
71 INT nNotifyFormat
; /* format used for WM_NOTIFY messages */
72 UINT uNumItem
; /* number of items (columns) */
73 INT nHeight
; /* height of the header (pixels) */
74 HFONT hFont
; /* handle to the current font */
75 HCURSOR hcurArrow
; /* handle to the arrow cursor */
76 HCURSOR hcurDivider
; /* handle to a cursor (used over dividers) <-|-> */
77 HCURSOR hcurDivopen
; /* handle to a cursor (used over dividers) <-||-> */
78 BOOL bCaptured
; /* Is the mouse captured? */
79 BOOL bPressed
; /* Is a header item pressed (down)? */
80 BOOL bTracking
; /* Is in tracking mode? */
81 INT iMoveItem
; /* index of tracked item. (Tracking mode) */
82 INT xTrackOffset
; /* distance between the right side of the tracked item and the cursor */
83 INT xOldTrack
; /* track offset (see above) after the last WM_MOUSEMOVE */
84 INT nOldWidth
; /* width of a sizing item after the last WM_MOUSEMOVE */
85 INT iHotItem
; /* index of hot item (cursor is over this item) */
86 INT iMargin
; /* width of the margin that surrounds a bitmap */
88 HIMAGELIST himl
; /* handle to an image list (may be 0) */
89 HEADER_ITEM
*items
; /* pointer to array of HEADER_ITEM's */
90 INT
*order
; /* array of item IDs indexed by order */
91 BOOL bRectsValid
; /* validity flag for bounding rectangles */
96 #define DIVIDER_WIDTH 10
97 #define MAX_HEADER_TEXT_LEN 260
98 #define HDN_UNICODE_OFFSET 20
99 #define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
101 #define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)
102 #define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)
103 #define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))
104 #define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)
106 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0))
108 static BOOL
HEADER_PrepareCallbackItems(HWND hwnd
, INT iItem
, INT reqMask
);
109 static void HEADER_FreeCallbackItems(HEADER_ITEM
*lpItem
);
111 static const WCHAR themeClass
[] = {'H','e','a','d','e','r',0};
112 static WCHAR emptyString
[] = {0};
114 static void HEADER_DisposeItem(HEADER_ITEM
*lpItem
)
118 Free(lpItem
->pszText
);
122 static void HEADER_StoreHDItemInHeader(HEADER_ITEM
*lpItem
, UINT mask
, HDITEMW
*phdi
, BOOL fUnicode
)
124 if (mask
& HDI_UNSUPPORTED_FIELDS
)
125 FIXME("unsupported header fields %x\n", (mask
& HDI_UNSUPPORTED_FIELDS
));
127 if (mask
& HDI_BITMAP
)
128 lpItem
->hbm
= phdi
->hbm
;
130 if (mask
& HDI_FORMAT
)
131 lpItem
->fmt
= phdi
->fmt
;
133 if (mask
& HDI_LPARAM
)
134 lpItem
->lParam
= phdi
->lParam
;
136 if (mask
& HDI_WIDTH
)
137 lpItem
->cxy
= phdi
->cxy
;
139 if (mask
& HDI_IMAGE
)
141 lpItem
->iImage
= phdi
->iImage
;
142 if (phdi
->iImage
== I_IMAGECALLBACK
)
143 lpItem
->callbackMask
|= HDI_IMAGE
;
145 lpItem
->callbackMask
&= ~HDI_IMAGE
;
152 Free(lpItem
->pszText
);
153 lpItem
->pszText
= NULL
;
156 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers != TEXTCALLBACKA too */
158 LPWSTR pszText
= (phdi
->pszText
!= NULL
? phdi
->pszText
: emptyString
);
160 Str_SetPtrW(&lpItem
->pszText
, pszText
);
162 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)pszText
);
163 lpItem
->callbackMask
&= ~HDI_TEXT
;
167 lpItem
->pszText
= NULL
;
168 lpItem
->callbackMask
|= HDI_TEXT
;
173 inline static LRESULT
174 HEADER_IndexToOrder (HWND hwnd
, INT iItem
)
176 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
177 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
178 return lpItem
->iOrder
;
183 HEADER_OrderToIndex(HWND hwnd
, WPARAM wParam
)
185 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
186 INT iorder
= (INT
)wParam
;
188 if ((iorder
<0) || iorder
>= infoPtr
->uNumItem
)
190 return infoPtr
->order
[iorder
];
194 HEADER_SetItemBounds (HWND hwnd
)
196 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
202 infoPtr
->bRectsValid
= TRUE
;
204 if (infoPtr
->uNumItem
== 0)
207 GetClientRect (hwnd
, &rect
);
210 for (i
= 0; i
< infoPtr
->uNumItem
; i
++) {
211 phdi
= &infoPtr
->items
[HEADER_OrderToIndex(hwnd
,i
)];
212 phdi
->rect
.top
= rect
.top
;
213 phdi
->rect
.bottom
= rect
.bottom
;
215 phdi
->rect
.right
= phdi
->rect
.left
+ ((phdi
->cxy
>0)?phdi
->cxy
:0);
216 x
= phdi
->rect
.right
;
221 HEADER_Size (HWND hwnd
, WPARAM wParam
)
223 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
225 infoPtr
->bRectsValid
= FALSE
;
232 HEADER_DrawItem (HWND hwnd
, HDC hdc
, INT iItem
, BOOL bHotTrack
)
234 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
235 HEADER_ITEM
*phdi
= &infoPtr
->items
[iItem
];
237 INT oldBkMode
, cxEdge
= GetSystemMetrics(SM_CXEDGE
);
238 HTHEME theme
= GetWindowTheme (hwnd
);
241 TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem
, bHotTrack
, (infoPtr
->nNotifyFormat
== NFR_UNICODE
));
243 if (!infoPtr
->bRectsValid
)
244 HEADER_SetItemBounds(hwnd
);
247 if (r
.right
- r
.left
== 0)
248 return phdi
->rect
.right
;
251 int state
= (phdi
->bDown
) ? HIS_PRESSED
:
252 (bHotTrack
? HIS_HOT
: HIS_NORMAL
);
253 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, state
,
255 GetThemeBackgroundContentRect (theme
, hdc
, HP_HEADERITEM
, state
,
259 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) {
261 DrawEdge (hdc
, &r
, BDR_RAISEDOUTER
,
262 BF_RECT
| BF_FLAT
| BF_MIDDLE
| BF_ADJUST
);
265 DrawEdge (hdc
, &r
, EDGE_RAISED
,
266 BF_RECT
| BF_SOFT
| BF_MIDDLE
| BF_ADJUST
);
269 DrawEdge (hdc
, &r
, EDGE_ETCHED
, BF_BOTTOM
| BF_RIGHT
| BF_ADJUST
);
279 /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
280 SetTextColor (hdc
, (bHotTrack
&& !theme
) ? COLOR_HIGHLIGHT
: COLOR_BTNTEXT
);
281 SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
283 nmcd
.hdr
.hwndFrom
= hwnd
;
284 nmcd
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
285 nmcd
.hdr
.code
= NM_CUSTOMDRAW
;
286 nmcd
.dwDrawStage
= CDDS_PREPAINT
| CDDS_ITEM
| CDDS_ITEMPOSTERASE
;
288 nmcd
.dwItemSpec
= iItem
;
290 nmcd
.uItemState
= phdi
->bDown
? CDIS_SELECTED
: 0;
291 nmcd
.lItemlParam
= phdi
->lParam
;
293 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
, nmcd
.hdr
.idFrom
, (LPARAM
)&nmcd
);
295 if (phdi
->fmt
& HDF_OWNERDRAW
) {
298 dis
.CtlType
= ODT_HEADER
;
299 dis
.CtlID
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
301 dis
.itemAction
= ODA_DRAWENTIRE
;
302 dis
.itemState
= phdi
->bDown
? ODS_SELECTED
: 0;
306 dis
.itemData
= phdi
->lParam
;
307 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
308 SendMessageW (infoPtr
->hwndNotify
, WM_DRAWITEM
,
309 (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
310 if (oldBkMode
!= TRANSPARENT
)
311 SetBkMode(hdc
, oldBkMode
);
314 UINT rw
, rh
, /* width and height of r */
315 *x
= NULL
, *w
= NULL
; /* x and width of the pic (bmp or img) which is part of cnt */
316 /* cnt,txt,img,bmp */
321 HEADER_PrepareCallbackItems(hwnd
, iItem
, HDI_TEXT
|HDI_IMAGE
);
322 cw
= tw
= iw
= bw
= 0;
323 rw
= r
.right
- r
.left
;
324 rh
= r
.bottom
- r
.top
;
327 HBRUSH hbr
= CreateSolidBrush(GetBkColor(hdc
));
328 RECT rcBackground
= r
;
330 rcBackground
.right
-= cxEdge
;
331 rcBackground
.left
+= cxEdge
;
332 FillRect(hdc
, &rcBackground
, hbr
);
335 if (phdi
->fmt
& HDF_STRING
) {
338 DrawTextW (hdc
, phdi
->pszText
, -1,
339 &textRect
, DT_LEFT
|DT_VCENTER
|DT_SINGLELINE
|DT_CALCRECT
);
340 cw
= textRect
.right
- textRect
.left
+ 2 * infoPtr
->iMargin
;
343 if ((phdi
->fmt
& HDF_IMAGE
) && (infoPtr
->himl
)) {
344 iw
= infoPtr
->himl
->cx
+ 2 * infoPtr
->iMargin
;
349 if ((phdi
->fmt
& HDF_BITMAP
) && (phdi
->hbm
)) {
350 GetObjectW (phdi
->hbm
, sizeof(BITMAP
), (LPVOID
)&bmp
);
351 bw
= bmp
.bmWidth
+ 2 * infoPtr
->iMargin
;
361 /* align cx using the unclipped cw */
362 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_LEFT
)
364 else if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_CENTER
)
365 cx
= r
.left
+ rw
/ 2 - cw
/ 2;
372 if (cx
+ cw
> r
.right
)
375 tx
= cx
+ infoPtr
->iMargin
;
376 /* since cw might have changed we have to recalculate tw */
377 tw
= cw
- infoPtr
->iMargin
* 2;
381 if (phdi
->fmt
& HDF_BITMAP_ON_RIGHT
) {
382 /* put pic behind text */
383 *x
= cx
+ tw
+ infoPtr
->iMargin
* 3;
385 *x
= cx
+ infoPtr
->iMargin
;
386 /* move text behind pic */
392 /* since we're done with the layout we can
393 now calculate the position of bmp which
394 has no influence on alignment and layout
396 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_RIGHT
)
397 bx
= cx
- bw
+ infoPtr
->iMargin
;
399 bx
= cx
+ cw
+ infoPtr
->iMargin
;
403 HDC hClipDC
= GetDC(hwnd
);
404 HRGN hClipRgn
= CreateRectRgn(r
.left
, r
.top
, r
.right
, r
.bottom
);
405 SelectClipRgn(hClipDC
, hClipRgn
);
408 HDC hdcBitmap
= CreateCompatibleDC (hClipDC
);
409 SelectObject (hdcBitmap
, phdi
->hbm
);
410 BitBlt (hClipDC
, bx
, r
.top
+ ((INT
)rh
- bmp
.bmHeight
) / 2,
411 bmp
.bmWidth
, bmp
.bmHeight
, hdcBitmap
, 0, 0, SRCCOPY
);
412 DeleteDC (hdcBitmap
);
416 ImageList_DrawEx (infoPtr
->himl
, phdi
->iImage
, hClipDC
,
417 ix
, r
.top
+ ((INT
)rh
- infoPtr
->himl
->cy
) / 2,
418 infoPtr
->himl
->cx
, infoPtr
->himl
->cy
, CLR_DEFAULT
, CLR_DEFAULT
, 0);
421 DeleteObject(hClipRgn
);
422 ReleaseDC(hwnd
, hClipDC
);
425 if (((phdi
->fmt
& HDF_STRING
)
426 || (!(phdi
->fmt
& (HDF_OWNERDRAW
|HDF_STRING
|HDF_BITMAP
|
427 HDF_BITMAP_ON_RIGHT
|HDF_IMAGE
)))) /* no explicit format specified? */
428 && (phdi
->pszText
)) {
429 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
432 DrawTextW (hdc
, phdi
->pszText
, -1,
433 &r
, DT_LEFT
|DT_END_ELLIPSIS
|DT_VCENTER
|DT_SINGLELINE
);
434 if (oldBkMode
!= TRANSPARENT
)
435 SetBkMode(hdc
, oldBkMode
);
437 HEADER_FreeCallbackItems(phdi
);
440 return phdi
->rect
.right
;
445 HEADER_Refresh (HWND hwnd
, HDC hdc
)
447 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
448 HFONT hFont
, hOldFont
;
453 HTHEME theme
= GetWindowTheme (hwnd
);
455 /* get rect for the bar, adjusted for the border */
456 GetClientRect (hwnd
, &rect
);
458 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
459 hOldFont
= SelectObject (hdc
, hFont
);
461 /* draw Background */
462 if (infoPtr
->uNumItem
== 0 && theme
== NULL
) {
463 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
464 FillRect(hdc
, &rect
, hbrBk
);
468 for (i
= 0; x
<= rect
.right
&& i
< infoPtr
->uNumItem
; i
++) {
469 x
= HEADER_DrawItem (hwnd
, hdc
, HEADER_OrderToIndex(hwnd
,i
),
470 infoPtr
->iHotItem
== i
);
473 if ((x
<= rect
.right
) && (infoPtr
->uNumItem
> 0)) {
476 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, HIS_NORMAL
, &rect
,
480 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
)
481 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_TOP
|BF_LEFT
|BF_BOTTOM
|BF_SOFT
|BF_MIDDLE
);
483 DrawEdge (hdc
, &rect
, EDGE_ETCHED
, BF_BOTTOM
|BF_MIDDLE
);
487 SelectObject (hdc
, hOldFont
);
492 HEADER_RefreshItem (HWND hwnd
, HDC hdc
, INT iItem
)
494 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
495 HFONT hFont
, hOldFont
;
497 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
498 hOldFont
= SelectObject (hdc
, hFont
);
499 HEADER_DrawItem (hwnd
, hdc
, iItem
, infoPtr
->iHotItem
== iItem
);
500 SelectObject (hdc
, hOldFont
);
505 HEADER_InternalHitTest (HWND hwnd
, LPPOINT lpPt
, UINT
*pFlags
, INT
*pItem
)
507 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
513 GetClientRect (hwnd
, &rect
);
517 if (PtInRect (&rect
, *lpPt
))
519 if (infoPtr
->uNumItem
== 0) {
520 *pFlags
|= HHT_NOWHERE
;
526 /* somewhere inside */
527 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++) {
528 rect
= infoPtr
->items
[iCount
].rect
;
529 width
= rect
.right
- rect
.left
;
534 if (PtInRect (&rect
, *lpPt
)) {
535 if (width
<= 2 * DIVIDER_WIDTH
) {
536 *pFlags
|= HHT_ONHEADER
;
538 TRACE("ON HEADER %d\n", iCount
);
543 rcTest
.right
= rcTest
.left
+ DIVIDER_WIDTH
;
544 if (PtInRect (&rcTest
, *lpPt
)) {
546 *pFlags
|= HHT_ONDIVOPEN
;
548 TRACE("ON DIVOPEN %d\n", *pItem
);
552 *pFlags
|= HHT_ONDIVIDER
;
554 TRACE("ON DIVIDER %d\n", *pItem
);
560 rcTest
.left
= rcTest
.right
- DIVIDER_WIDTH
;
561 if (PtInRect (&rcTest
, *lpPt
)) {
562 *pFlags
|= HHT_ONDIVIDER
;
564 TRACE("ON DIVIDER %d\n", *pItem
);
568 *pFlags
|= HHT_ONHEADER
;
570 TRACE("ON HEADER %d\n", iCount
);
575 /* check for last divider part (on nowhere) */
576 rect
= infoPtr
->items
[infoPtr
->uNumItem
-1].rect
;
577 rect
.left
= rect
.right
;
578 rect
.right
+= DIVIDER_WIDTH
;
579 if (PtInRect (&rect
, *lpPt
)) {
581 *pFlags
|= HHT_ONDIVOPEN
;
582 *pItem
= infoPtr
->uNumItem
- 1;
583 TRACE("ON DIVOPEN %d\n", *pItem
);
587 *pFlags
|= HHT_ONDIVIDER
;
588 *pItem
= infoPtr
->uNumItem
-1;
589 TRACE("ON DIVIDER %d\n", *pItem
);
594 *pFlags
|= HHT_NOWHERE
;
601 if (lpPt
->x
< rect
.left
) {
603 *pFlags
|= HHT_TOLEFT
;
605 else if (lpPt
->x
> rect
.right
) {
607 *pFlags
|= HHT_TORIGHT
;
610 if (lpPt
->y
< rect
.top
) {
612 *pFlags
|= HHT_ABOVE
;
614 else if (lpPt
->y
> rect
.bottom
) {
616 *pFlags
|= HHT_BELOW
;
621 TRACE("flags=0x%X\n", *pFlags
);
627 HEADER_DrawTrackLine (HWND hwnd
, HDC hdc
, INT x
)
633 GetClientRect (hwnd
, &rect
);
635 hOldPen
= SelectObject (hdc
, GetStockObject (BLACK_PEN
));
636 oldRop
= SetROP2 (hdc
, R2_XORPEN
);
637 MoveToEx (hdc
, x
, rect
.top
, NULL
);
638 LineTo (hdc
, x
, rect
.bottom
);
639 SetROP2 (hdc
, oldRop
);
640 SelectObject (hdc
, hOldPen
);
645 * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
648 * [I] infoPtr : the header that wants to send the notify
649 * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
650 * [I] src : The source HDITEM. It may be a HDITEMA or HDITEMW
651 * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
652 * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
653 * the HDITEM is no longer in use or NULL if none was needed
655 * NOTE: We depend on HDITEMA and HDITEMW having the same structure
657 static void HEADER_CopyHDItemForNotify(HEADER_INFO
*infoPtr
, HDITEMW
*dest
,
658 HDITEMW
*src
, BOOL fSourceUnicode
, LPVOID
*ppvScratch
)
663 if (src
->mask
& HDI_TEXT
&& src
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers TEXTCALLBACKA as well */
665 if (fSourceUnicode
&& infoPtr
->nNotifyFormat
!= NFR_UNICODE
)
667 dest
->pszText
= NULL
;
668 Str_SetPtrWtoA((LPSTR
*)&dest
->pszText
, src
->pszText
);
669 *ppvScratch
= dest
->pszText
;
672 if (!fSourceUnicode
&& infoPtr
->nNotifyFormat
== NFR_UNICODE
)
674 dest
->pszText
= NULL
;
675 Str_SetPtrAtoW(&dest
->pszText
, (LPSTR
)src
->pszText
);
676 *ppvScratch
= dest
->pszText
;
681 static UINT
HEADER_NotifyCodeWtoA(UINT code
)
683 /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
684 if (code
>= HDN_LAST
&& code
<= HDN_FIRST_UNICODE
)
685 return code
+ HDN_UNICODE_OFFSET
;
691 HEADER_SendSimpleNotify (HWND hwnd
, UINT code
)
693 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
696 nmhdr
.hwndFrom
= hwnd
;
697 nmhdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
700 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
701 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
705 HEADER_SendHeaderNotifyT (HWND hwnd
, UINT code
, INT iItem
, INT mask
, HDITEMW
*lpItem
)
707 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
713 /* lpItem == NULL means that we should take the actual data from the item */
716 FIXME("(): invalid parameters - lpItem == NULL and (mask & HDI_TEXT)\n");
720 nmitem
.cxy
= infoPtr
->items
[iItem
].cxy
;
721 nmitem
.hbm
= infoPtr
->items
[iItem
].hbm
;
722 nmitem
.pszText
= NULL
;
723 nmitem
.cchTextMax
= 0;
724 nmitem
.fmt
= infoPtr
->items
[iItem
].fmt
;
725 nmitem
.lParam
= infoPtr
->items
[iItem
].lParam
;
726 nmitem
.iOrder
= infoPtr
->items
[iItem
].iOrder
;
727 nmitem
.iImage
= infoPtr
->items
[iItem
].iImage
;
731 nmhdr
.hdr
.hwndFrom
= hwnd
;
732 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
733 nmhdr
.hdr
.code
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
? code
: HEADER_NotifyCodeWtoA(code
));
736 nmhdr
.pitem
= lpItem
;
738 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
739 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
743 * Prepare callback items
744 * depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA
745 * (so we handle the two cases only doing a specific cast for pszText).
746 * Checks if any of the required field are callback. If there are sends a
747 * NMHDISPINFO notify to retrieve these items. The items are stored in the
748 * HEADER_ITEM pszText and iImage fields. They should be freed with
749 * HEADER_FreeCallbackItems.
751 * @param hwnd : hwnd header container handler
752 * @param iItem : the header item id
753 * @param reqMask : required fields. If any of them is callback this function will fetch it
755 * @return TRUE on success, else FALSE
758 HEADER_PrepareCallbackItems(HWND hwnd
, INT iItem
, INT reqMask
)
760 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
761 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
762 DWORD mask
= reqMask
& lpItem
->callbackMask
;
763 NMHDDISPINFOW dispInfo
;
764 void *pvBuffer
= NULL
;
768 if (mask
&HDI_TEXT
&& lpItem
->pszText
!= NULL
)
770 ERR("(): function called without a call to FreeCallbackItems\n");
771 Free(lpItem
->pszText
);
772 lpItem
->pszText
= NULL
;
775 memset(&dispInfo
, 0, sizeof(NMHDDISPINFOW
));
776 dispInfo
.hdr
.hwndFrom
= hwnd
;
777 dispInfo
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
778 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
780 dispInfo
.hdr
.code
= HDN_GETDISPINFOW
;
782 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(WCHAR
));
786 dispInfo
.hdr
.code
= HDN_GETDISPINFOA
;
788 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(CHAR
));
790 dispInfo
.pszText
= (LPWSTR
)pvBuffer
;
791 dispInfo
.cchTextMax
= (pvBuffer
!=NULL
?MAX_HEADER_TEXT_LEN
:0);
792 dispInfo
.iItem
= iItem
;
793 dispInfo
.mask
= mask
;
794 dispInfo
.lParam
= lpItem
->lParam
;
796 TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr
->nNotifyFormat
== NFR_UNICODE
?'W':'A');
797 SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
,
798 (WPARAM
) dispInfo
.hdr
.idFrom
,
801 TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n",
803 (infoPtr
->nNotifyFormat
== NFR_UNICODE
? debugstr_w(dispInfo
.pszText
) : (LPSTR
) dispInfo
.pszText
),
804 (void*) dispInfo
.lParam
);
806 if (mask
& HDI_IMAGE
)
807 lpItem
->iImage
= dispInfo
.iImage
;
810 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
812 lpItem
->pszText
= (LPWSTR
)pvBuffer
;
814 /* the user might have used his own buffer */
815 if (dispInfo
.pszText
!= lpItem
->pszText
)
816 Str_GetPtrW(dispInfo
.pszText
, lpItem
->pszText
, MAX_HEADER_TEXT_LEN
);
820 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)dispInfo
.pszText
);
825 if (dispInfo
.mask
& HDI_DI_SETITEM
)
827 /* make the items permanent */
828 lpItem
->callbackMask
&= ~dispInfo
.mask
;
836 * Free the items that might be allocated with HEADER_PrepareCallbackItems
839 * [I] lpItem : the item to free the data
843 HEADER_FreeCallbackItems(HEADER_ITEM
*lpItem
)
845 if (lpItem
->callbackMask
&HDI_TEXT
&& lpItem
->pszText
!= NULL
)
847 Free(lpItem
->pszText
);
848 lpItem
->pszText
= NULL
;
851 if (lpItem
->callbackMask
&HDI_IMAGE
)
852 lpItem
->iImage
= I_IMAGECALLBACK
;
856 HEADER_SendClickNotify (HWND hwnd
, UINT code
, INT iItem
)
858 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
861 nmhdr
.hdr
.hwndFrom
= hwnd
;
862 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
863 nmhdr
.hdr
.code
= code
;
868 return (BOOL
)SendMessageA (infoPtr
->hwndNotify
, WM_NOTIFY
,
869 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
874 HEADER_CreateDragImage (HWND hwnd
, WPARAM wParam
)
876 FIXME("empty stub!\n");
882 HEADER_DeleteItem (HWND hwnd
, WPARAM wParam
)
884 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
885 INT iItem
= (INT
)wParam
;
887 TRACE("[iItem=%d]\n", iItem
);
889 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
892 if (infoPtr
->uNumItem
== 1) {
893 TRACE("Simple delete!\n");
894 HEADER_DisposeItem(&infoPtr
->items
[0]);
895 Free (infoPtr
->items
);
896 Free(infoPtr
->order
);
899 infoPtr
->uNumItem
= 0;
902 HEADER_ITEM
*oldItems
= infoPtr
->items
;
905 TRACE("Complex delete! [iItem=%d]\n", iItem
);
907 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
908 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
909 HEADER_DisposeItem(&infoPtr
->items
[iItem
]);
910 iOrder
= infoPtr
->items
[iItem
].iOrder
;
913 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
914 /* pre delete copy */
916 memcpy (&infoPtr
->items
[0], &oldItems
[0],
917 iItem
* sizeof(HEADER_ITEM
));
920 /* post delete copy */
921 if (iItem
< infoPtr
->uNumItem
) {
922 memcpy (&infoPtr
->items
[iItem
], &oldItems
[iItem
+1],
923 (infoPtr
->uNumItem
- iItem
) * sizeof(HEADER_ITEM
));
926 /* Correct the orders */
927 if (iOrder
< infoPtr
->uNumItem
)
929 memmove(&infoPtr
->order
[iOrder
], &infoPtr
->order
[iOrder
+ 1],
930 (infoPtr
->uNumItem
- iOrder
) * sizeof(INT
));
931 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
933 if (infoPtr
->order
[i
] > iItem
)
936 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
940 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
941 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
945 HEADER_SetItemBounds (hwnd
);
947 InvalidateRect(hwnd
, NULL
, FALSE
);
954 HEADER_GetImageList (HWND hwnd
)
956 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
958 return (LRESULT
)infoPtr
->himl
;
963 HEADER_GetItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
965 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
967 UINT mask
= phdi
->mask
;
972 TRACE("[nItem=%d]\n", nItem
);
976 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
979 if (mask
& HDI_UNKNOWN_FIELDS
)
981 TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask
);
982 mask
&= HDI_COMCTL32_4_0_FIELDS
;
985 lpItem
= &infoPtr
->items
[nItem
];
986 HEADER_PrepareCallbackItems(hwnd
, nItem
, mask
);
988 if (mask
& HDI_BITMAP
)
989 phdi
->hbm
= lpItem
->hbm
;
991 if (mask
& HDI_FORMAT
)
992 phdi
->fmt
= lpItem
->fmt
;
994 if (mask
& HDI_WIDTH
)
995 phdi
->cxy
= lpItem
->cxy
;
997 if (mask
& HDI_LPARAM
)
998 phdi
->lParam
= lpItem
->lParam
;
1000 if (mask
& HDI_IMAGE
)
1001 phdi
->iImage
= lpItem
->iImage
;
1003 if (mask
& HDI_ORDER
)
1004 phdi
->iOrder
= lpItem
->iOrder
;
1006 if (mask
& HDI_TEXT
)
1009 Str_GetPtrW (lpItem
->pszText
, phdi
->pszText
, phdi
->cchTextMax
);
1011 Str_GetPtrWtoA (lpItem
->pszText
, (LPSTR
)phdi
->pszText
, phdi
->cchTextMax
);
1014 HEADER_FreeCallbackItems(lpItem
);
1019 inline static LRESULT
1020 HEADER_GetItemCount (HWND hwnd
)
1022 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1023 return infoPtr
->uNumItem
;
1028 HEADER_GetItemRect (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1030 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1031 INT iItem
= (INT
)wParam
;
1032 LPRECT lpRect
= (LPRECT
)lParam
;
1034 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
1037 lpRect
->left
= infoPtr
->items
[iItem
].rect
.left
;
1038 lpRect
->right
= infoPtr
->items
[iItem
].rect
.right
;
1039 lpRect
->top
= infoPtr
->items
[iItem
].rect
.top
;
1040 lpRect
->bottom
= infoPtr
->items
[iItem
].rect
.bottom
;
1047 HEADER_GetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1049 LPINT order
= (LPINT
) lParam
;
1050 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1052 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
1055 memcpy(order
, infoPtr
->order
, infoPtr
->uNumItem
* sizeof(INT
));
1060 HEADER_SetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1063 LPINT order
= (LPINT
) lParam
;
1064 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1065 HEADER_ITEM
*lpItem
;
1067 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
1069 memcpy(infoPtr
->order
, order
, infoPtr
->uNumItem
* sizeof(INT
));
1070 for (i
=0; i
<(int)wParam
; i
++)
1072 lpItem
= &infoPtr
->items
[*order
++];
1075 infoPtr
->bRectsValid
=0;
1076 InvalidateRect(hwnd
, NULL
, FALSE
);
1080 inline static LRESULT
1081 HEADER_GetUnicodeFormat (HWND hwnd
)
1083 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1084 return (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1089 HEADER_HitTest (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1091 LPHDHITTESTINFO phti
= (LPHDHITTESTINFO
)lParam
;
1093 HEADER_InternalHitTest (hwnd
, &phti
->pt
, &phti
->flags
, &phti
->iItem
);
1095 if (phti
->flags
== HHT_NOWHERE
)
1103 HEADER_InsertItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1105 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1106 HEADER_ITEM
*lpItem
;
1111 if ((phdi
== NULL
) || (nItem
< 0) || (phdi
->mask
== 0))
1114 if (nItem
> infoPtr
->uNumItem
)
1115 nItem
= infoPtr
->uNumItem
;
1117 iOrder
= (phdi
->mask
& HDI_ORDER
) ? phdi
->iOrder
: nItem
;
1120 else if (infoPtr
->uNumItem
< iOrder
)
1121 iOrder
= infoPtr
->uNumItem
;
1123 if (infoPtr
->uNumItem
== 0) {
1124 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
));
1125 infoPtr
->order
= Alloc(sizeof(INT
));
1126 infoPtr
->uNumItem
++;
1129 HEADER_ITEM
*oldItems
= infoPtr
->items
;
1130 INT
*oldOrder
= infoPtr
->order
;
1132 infoPtr
->uNumItem
++;
1133 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
1135 memcpy (&infoPtr
->items
[1], &oldItems
[0],
1136 (infoPtr
->uNumItem
-1) * sizeof(HEADER_ITEM
));
1140 /* pre insert copy */
1142 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1143 nItem
* sizeof(HEADER_ITEM
));
1146 /* post insert copy */
1147 if (nItem
< infoPtr
->uNumItem
- 1) {
1148 memcpy (&infoPtr
->items
[nItem
+1], &oldItems
[nItem
],
1149 (infoPtr
->uNumItem
- nItem
- 1) * sizeof(HEADER_ITEM
));
1153 infoPtr
->order
= Alloc(sizeof(INT
) * infoPtr
->uNumItem
);
1154 memcpy(infoPtr
->order
, oldOrder
, iOrder
* sizeof(INT
));
1155 infoPtr
->order
[iOrder
] = nItem
;
1156 memcpy(&infoPtr
->order
[iOrder
+ 1], &oldOrder
[iOrder
],
1157 (infoPtr
->uNumItem
- iOrder
- 1) * sizeof(INT
));
1163 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1165 if (i
!= iOrder
&& infoPtr
->order
[i
] >= nItem
)
1166 infoPtr
->order
[i
]++;
1167 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1170 lpItem
= &infoPtr
->items
[nItem
];
1171 ZeroMemory(lpItem
, sizeof(HEADER_ITEM
));
1172 /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
1173 copyMask
= phdi
->mask
| HDI_WIDTH
| HDI_FORMAT
| HDI_LPARAM
;
1174 HEADER_StoreHDItemInHeader(lpItem
, copyMask
, phdi
, bUnicode
);
1176 /* set automatically some format bits */
1177 if (phdi
->mask
& HDI_TEXT
)
1178 lpItem
->fmt
|= HDF_STRING
;
1180 lpItem
->fmt
&= ~HDF_STRING
;
1182 if (lpItem
->hbm
!= NULL
)
1183 lpItem
->fmt
|= HDF_BITMAP
;
1185 lpItem
->fmt
&= ~HDF_BITMAP
;
1187 if (phdi
->mask
& HDI_IMAGE
)
1188 lpItem
->fmt
|= HDF_IMAGE
;
1190 lpItem
->iOrder
= iOrder
;
1192 HEADER_SetItemBounds (hwnd
);
1194 InvalidateRect(hwnd
, NULL
, FALSE
);
1201 HEADER_Layout (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1203 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1204 LPHDLAYOUT lpLayout
= (LPHDLAYOUT
)lParam
;
1206 lpLayout
->pwpos
->hwnd
= hwnd
;
1207 lpLayout
->pwpos
->hwndInsertAfter
= 0;
1208 lpLayout
->pwpos
->x
= lpLayout
->prc
->left
;
1209 lpLayout
->pwpos
->y
= lpLayout
->prc
->top
;
1210 lpLayout
->pwpos
->cx
= lpLayout
->prc
->right
- lpLayout
->prc
->left
;
1211 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_HIDDEN
)
1212 lpLayout
->pwpos
->cy
= 0;
1214 lpLayout
->pwpos
->cy
= infoPtr
->nHeight
;
1215 lpLayout
->prc
->top
+= infoPtr
->nHeight
;
1217 lpLayout
->pwpos
->flags
= SWP_NOZORDER
;
1219 TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1220 lpLayout
->pwpos
->x
, lpLayout
->pwpos
->y
,
1221 lpLayout
->pwpos
->cx
, lpLayout
->pwpos
->cy
);
1223 infoPtr
->bRectsValid
= FALSE
;
1230 HEADER_SetImageList (HWND hwnd
, HIMAGELIST himl
)
1232 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1235 TRACE("(himl %p)\n", himl
);
1236 himlOld
= infoPtr
->himl
;
1237 infoPtr
->himl
= himl
;
1239 /* FIXME: Refresh needed??? */
1241 return (LRESULT
)himlOld
;
1246 HEADER_GetBitmapMargin(HWND hwnd
)
1248 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1250 return infoPtr
->iMargin
;
1254 HEADER_SetBitmapMargin(HWND hwnd
, WPARAM wParam
)
1256 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1257 INT oldMargin
= infoPtr
->iMargin
;
1259 infoPtr
->iMargin
= (INT
)wParam
;
1265 HEADER_SetItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1267 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1268 HEADER_ITEM
*lpItem
;
1274 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1277 TRACE("[nItem=%d]\n", nItem
);
1279 HEADER_CopyHDItemForNotify(infoPtr
, &hdNotify
, phdi
, bUnicode
, &pvScratch
);
1280 if (HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGINGW
, nItem
, phdi
->mask
, &hdNotify
))
1282 if (pvScratch
) Free(pvScratch
);
1286 lpItem
= &infoPtr
->items
[nItem
];
1287 HEADER_StoreHDItemInHeader(lpItem
, phdi
->mask
, phdi
, bUnicode
);
1289 if (phdi
->mask
& HDI_ORDER
)
1293 if (lpItem
->iOrder
< phdi
->iOrder
)
1295 memmove(&infoPtr
->order
[lpItem
->iOrder
],
1296 &infoPtr
->order
[lpItem
->iOrder
+ 1],
1297 (phdi
->iOrder
- lpItem
->iOrder
) * sizeof(INT
));
1299 if (phdi
->iOrder
< lpItem
->iOrder
)
1301 memmove(&infoPtr
->order
[phdi
->iOrder
+ 1],
1302 &infoPtr
->order
[phdi
->iOrder
],
1303 (lpItem
->iOrder
- phdi
->iOrder
) * sizeof(INT
));
1305 infoPtr
->order
[phdi
->iOrder
] = nItem
;
1306 nMin
= min(lpItem
->iOrder
, phdi
->iOrder
);
1307 nMax
= max(lpItem
->iOrder
, phdi
->iOrder
);
1308 for (i
= nMin
; i
<= nMax
; i
++)
1310 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1314 HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGEDW
, nItem
, phdi
->mask
, &hdNotify
);
1316 HEADER_SetItemBounds (hwnd
);
1318 InvalidateRect(hwnd
, NULL
, FALSE
);
1320 if (pvScratch
!= NULL
)
1325 inline static LRESULT
1326 HEADER_SetUnicodeFormat (HWND hwnd
, WPARAM wParam
)
1328 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1329 BOOL bTemp
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1331 infoPtr
->nNotifyFormat
= ((BOOL
)wParam
? NFR_UNICODE
: NFR_ANSI
);
1338 HEADER_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1340 HEADER_INFO
*infoPtr
;
1345 infoPtr
= (HEADER_INFO
*)Alloc (sizeof(HEADER_INFO
));
1346 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
1348 infoPtr
->hwndNotify
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1349 infoPtr
->uNumItem
= 0;
1353 infoPtr
->bRectsValid
= FALSE
;
1354 infoPtr
->hcurArrow
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1355 infoPtr
->hcurDivider
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDER
));
1356 infoPtr
->hcurDivopen
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDEROPEN
));
1357 infoPtr
->bPressed
= FALSE
;
1358 infoPtr
->bTracking
= FALSE
;
1359 infoPtr
->iMoveItem
= 0;
1361 infoPtr
->iHotItem
= -1;
1362 infoPtr
->iMargin
= 3*GetSystemMetrics(SM_CXEDGE
);
1363 infoPtr
->nNotifyFormat
=
1364 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
1367 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1368 GetTextMetricsW (hdc
, &tm
);
1369 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1370 SelectObject (hdc
, hOldFont
);
1373 OpenThemeData(hwnd
, themeClass
);
1380 HEADER_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1382 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1383 HEADER_ITEM
*lpItem
;
1387 if (infoPtr
->items
) {
1388 lpItem
= infoPtr
->items
;
1389 for (nItem
= 0; nItem
< infoPtr
->uNumItem
; nItem
++, lpItem
++) {
1390 HEADER_DisposeItem(lpItem
);
1392 Free (infoPtr
->items
);
1396 Free(infoPtr
->order
);
1399 ImageList_Destroy (infoPtr
->himl
);
1401 SetWindowLongPtrW (hwnd
, 0, 0);
1404 theme
= GetWindowTheme(hwnd
);
1405 CloseThemeData(theme
);
1410 static inline LRESULT
1411 HEADER_GetFont (HWND hwnd
)
1413 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1415 return (LRESULT
)infoPtr
->hFont
;
1420 HEADER_LButtonDblClk (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1426 pt
.x
= (INT
)LOWORD(lParam
);
1427 pt
.y
= (INT
)HIWORD(lParam
);
1428 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1430 if ((GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) && (flags
== HHT_ONHEADER
))
1431 HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMDBLCLICKW
, nItem
, 0, NULL
);
1432 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
))
1433 HEADER_SendHeaderNotifyT (hwnd
, HDN_DIVIDERDBLCLICKW
, nItem
, 0, NULL
);
1440 HEADER_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1442 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1443 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1449 pt
.x
= (INT
)LOWORD(lParam
);
1450 pt
.y
= (INT
)HIWORD(lParam
);
1451 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1453 if ((dwStyle
& HDS_BUTTONS
) && (flags
== HHT_ONHEADER
)) {
1455 infoPtr
->bCaptured
= TRUE
;
1456 infoPtr
->bPressed
= TRUE
;
1457 infoPtr
->iMoveItem
= nItem
;
1459 infoPtr
->items
[nItem
].bDown
= TRUE
;
1461 /* Send WM_CUSTOMDRAW */
1463 HEADER_RefreshItem (hwnd
, hdc
, nItem
);
1464 ReleaseDC (hwnd
, hdc
);
1466 TRACE("Pressed item %d!\n", nItem
);
1468 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
)) {
1469 if (!(HEADER_SendHeaderNotifyT (hwnd
, HDN_BEGINTRACKW
, nItem
, HDI_WIDTH
, NULL
))) {
1471 infoPtr
->bCaptured
= TRUE
;
1472 infoPtr
->bTracking
= TRUE
;
1473 infoPtr
->iMoveItem
= nItem
;
1474 infoPtr
->nOldWidth
= infoPtr
->items
[nItem
].cxy
;
1475 infoPtr
->xTrackOffset
= infoPtr
->items
[nItem
].rect
.right
- pt
.x
;
1477 if (!(dwStyle
& HDS_FULLDRAG
)) {
1478 infoPtr
->xOldTrack
= infoPtr
->items
[nItem
].rect
.right
;
1480 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1481 ReleaseDC (hwnd
, hdc
);
1484 TRACE("Begin tracking item %d!\n", nItem
);
1493 HEADER_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1495 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1496 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1502 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1503 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1504 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1506 if (infoPtr
->bPressed
) {
1507 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
)) {
1508 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1510 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1511 ReleaseDC (hwnd
, hdc
);
1513 HEADER_SendClickNotify (hwnd
, HDN_ITEMCLICKA
, infoPtr
->iMoveItem
);
1515 else if (flags
== HHT_ONHEADER
)
1517 HEADER_ITEM
*lpItem
;
1518 INT newindex
= HEADER_IndexToOrder(hwnd
,nItem
);
1519 INT oldindex
= HEADER_IndexToOrder(hwnd
,infoPtr
->iMoveItem
);
1521 TRACE("Exchanging [index:order] [%d:%d] [%d:%d]\n",
1522 infoPtr
->iMoveItem
,oldindex
,nItem
,newindex
);
1523 lpItem
= &infoPtr
->items
[nItem
];
1524 lpItem
->iOrder
=oldindex
;
1526 lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1527 lpItem
->iOrder
= newindex
;
1529 infoPtr
->order
[oldindex
] = nItem
;
1530 infoPtr
->order
[newindex
] = infoPtr
->iMoveItem
;
1532 infoPtr
->bRectsValid
= FALSE
;
1533 InvalidateRect(hwnd
, NULL
, FALSE
);
1534 /* FIXME: Should some WM_NOTIFY be sent */
1537 TRACE("Released item %d!\n", infoPtr
->iMoveItem
);
1538 infoPtr
->bPressed
= FALSE
;
1540 else if (infoPtr
->bTracking
) {
1541 TRACE("End tracking item %d!\n", infoPtr
->iMoveItem
);
1542 infoPtr
->bTracking
= FALSE
;
1544 HEADER_SendHeaderNotifyT (hwnd
, HDN_ENDTRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1546 if (!(dwStyle
& HDS_FULLDRAG
)) {
1548 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1549 ReleaseDC (hwnd
, hdc
);
1552 if (HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
))
1554 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= infoPtr
->nOldWidth
;
1557 nWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1560 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1563 HEADER_SetItemBounds (hwnd
);
1564 InvalidateRect(hwnd
, NULL
, TRUE
);
1565 HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1568 if (infoPtr
->bCaptured
) {
1569 infoPtr
->bCaptured
= FALSE
;
1571 HEADER_SendSimpleNotify (hwnd
, NM_RELEASEDCAPTURE
);
1579 HEADER_NotifyFormat (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1581 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1586 return infoPtr
->nNotifyFormat
;
1589 infoPtr
->nNotifyFormat
=
1590 SendMessageW ((HWND
)wParam
, WM_NOTIFYFORMAT
,
1591 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
1592 return infoPtr
->nNotifyFormat
;
1600 HEADER_MouseLeave (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1602 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1603 /* Reset hot-tracked item when mouse leaves control. */
1604 INT oldHotItem
= infoPtr
->iHotItem
;
1605 HDC hdc
= GetDC (hwnd
);
1607 infoPtr
->iHotItem
= -1;
1608 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1609 ReleaseDC (hwnd
, hdc
);
1616 HEADER_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1618 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1619 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1624 /* With theming, hottracking is always enabled */
1625 BOOL hotTrackEnabled
=
1626 ((dwStyle
& HDS_BUTTONS
) && (dwStyle
& HDS_HOTTRACK
))
1627 || (GetWindowTheme (hwnd
) != NULL
);
1628 INT oldHotItem
= infoPtr
->iHotItem
;
1630 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1631 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1632 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1634 if (hotTrackEnabled
) {
1635 if (flags
& (HHT_ONHEADER
| HHT_ONDIVIDER
| HHT_ONDIVOPEN
))
1636 infoPtr
->iHotItem
= nItem
;
1638 infoPtr
->iHotItem
= -1;
1641 if (infoPtr
->bCaptured
) {
1642 if (infoPtr
->bPressed
) {
1643 BOOL oldState
= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
;
1644 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
))
1645 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= TRUE
;
1647 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1648 if (oldState
!= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
) {
1650 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1651 ReleaseDC (hwnd
, hdc
);
1654 TRACE("Moving pressed item %d!\n", infoPtr
->iMoveItem
);
1656 else if (infoPtr
->bTracking
) {
1657 if (dwStyle
& HDS_FULLDRAG
) {
1658 if (!HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
))
1660 nWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1663 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1664 HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1666 HEADER_SetItemBounds (hwnd
);
1667 InvalidateRect(hwnd
, NULL
, FALSE
);
1671 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1672 infoPtr
->xOldTrack
= pt
.x
+ infoPtr
->xTrackOffset
;
1673 if (infoPtr
->xOldTrack
< infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
)
1674 infoPtr
->xOldTrack
= infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1675 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
=
1676 infoPtr
->xOldTrack
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1677 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1678 ReleaseDC (hwnd
, hdc
);
1679 HEADER_SendHeaderNotifyT (hwnd
, HDN_TRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1682 TRACE("Tracking item %d!\n", infoPtr
->iMoveItem
);
1686 if (hotTrackEnabled
) {
1687 TRACKMOUSEEVENT tme
;
1688 if (oldHotItem
!= infoPtr
->iHotItem
) {
1690 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1691 if (infoPtr
->iHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iHotItem
);
1692 ReleaseDC (hwnd
, hdc
);
1694 tme
.cbSize
= sizeof( tme
);
1695 tme
.dwFlags
= TME_LEAVE
;
1696 tme
.hwndTrack
= hwnd
;
1697 TrackMouseEvent( &tme
);
1705 HEADER_Paint (HWND hwnd
, WPARAM wParam
)
1710 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1711 HEADER_Refresh (hwnd
, hdc
);
1713 EndPaint (hwnd
, &ps
);
1719 HEADER_RButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1724 pt
.x
= LOWORD(lParam
);
1725 pt
.y
= HIWORD(lParam
);
1727 /* Send a Notify message */
1728 bRet
= HEADER_SendSimpleNotify (hwnd
, NM_RCLICK
);
1730 /* Change to screen coordinate for WM_CONTEXTMENU */
1731 ClientToScreen(hwnd
, &pt
);
1733 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1734 SendMessageW( hwnd
, WM_CONTEXTMENU
, (WPARAM
) hwnd
, MAKELPARAM(pt
.x
, pt
.y
));
1741 HEADER_SetCursor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1743 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1748 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam
), HIWORD(lParam
));
1751 ScreenToClient (hwnd
, &pt
);
1753 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1755 if (flags
== HHT_ONDIVIDER
)
1756 SetCursor (infoPtr
->hcurDivider
);
1757 else if (flags
== HHT_ONDIVOPEN
)
1758 SetCursor (infoPtr
->hcurDivopen
);
1760 SetCursor (infoPtr
->hcurArrow
);
1767 HEADER_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1769 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1771 HFONT hFont
, hOldFont
;
1774 infoPtr
->hFont
= (HFONT
)wParam
;
1776 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
1779 hOldFont
= SelectObject (hdc
, hFont
);
1780 GetTextMetricsW (hdc
, &tm
);
1781 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1782 SelectObject (hdc
, hOldFont
);
1785 infoPtr
->bRectsValid
= FALSE
;
1788 InvalidateRect(hwnd
, NULL
, FALSE
);
1794 /* Update the theme handle after a theme change */
1795 static LRESULT
HEADER_ThemeChanged(HWND hwnd
)
1797 HTHEME theme
= GetWindowTheme(hwnd
);
1798 CloseThemeData(theme
);
1799 OpenThemeData(hwnd
, themeClass
);
1800 InvalidateRect(hwnd
, NULL
, FALSE
);
1805 static LRESULT WINAPI
1806 HEADER_WindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1808 TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd
, msg
, wParam
, lParam
);
1809 if (!HEADER_GetInfoPtr (hwnd
) && (msg
!= WM_CREATE
))
1810 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1812 /* case HDM_CLEARFILTER: */
1814 case HDM_CREATEDRAGIMAGE
:
1815 return HEADER_CreateDragImage (hwnd
, wParam
);
1817 case HDM_DELETEITEM
:
1818 return HEADER_DeleteItem (hwnd
, wParam
);
1820 /* case HDM_EDITFILTER: */
1822 case HDM_GETBITMAPMARGIN
:
1823 return HEADER_GetBitmapMargin(hwnd
);
1825 case HDM_GETIMAGELIST
:
1826 return HEADER_GetImageList (hwnd
);
1830 return HEADER_GetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_GETITEMW
);
1832 case HDM_GETITEMCOUNT
:
1833 return HEADER_GetItemCount (hwnd
);
1835 case HDM_GETITEMRECT
:
1836 return HEADER_GetItemRect (hwnd
, wParam
, lParam
);
1838 case HDM_GETORDERARRAY
:
1839 return HEADER_GetOrderArray(hwnd
, wParam
, lParam
);
1841 case HDM_GETUNICODEFORMAT
:
1842 return HEADER_GetUnicodeFormat (hwnd
);
1845 return HEADER_HitTest (hwnd
, wParam
, lParam
);
1847 case HDM_INSERTITEMA
:
1848 case HDM_INSERTITEMW
:
1849 return HEADER_InsertItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_INSERTITEMW
);
1852 return HEADER_Layout (hwnd
, wParam
, lParam
);
1854 case HDM_ORDERTOINDEX
:
1855 return HEADER_OrderToIndex(hwnd
, wParam
);
1857 case HDM_SETBITMAPMARGIN
:
1858 return HEADER_SetBitmapMargin(hwnd
, wParam
);
1860 /* case HDM_SETFILTERCHANGETIMEOUT: */
1862 /* case HDM_SETHOTDIVIDER: */
1864 case HDM_SETIMAGELIST
:
1865 return HEADER_SetImageList (hwnd
, (HIMAGELIST
)lParam
);
1869 return HEADER_SetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_SETITEMW
);
1871 case HDM_SETORDERARRAY
:
1872 return HEADER_SetOrderArray(hwnd
, wParam
, lParam
);
1874 case HDM_SETUNICODEFORMAT
:
1875 return HEADER_SetUnicodeFormat (hwnd
, wParam
);
1878 return HEADER_Create (hwnd
, wParam
, lParam
);
1881 return HEADER_Destroy (hwnd
, wParam
, lParam
);
1887 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
1890 return HEADER_GetFont (hwnd
);
1892 case WM_LBUTTONDBLCLK
:
1893 return HEADER_LButtonDblClk (hwnd
, wParam
, lParam
);
1895 case WM_LBUTTONDOWN
:
1896 return HEADER_LButtonDown (hwnd
, wParam
, lParam
);
1899 return HEADER_LButtonUp (hwnd
, wParam
, lParam
);
1902 return HEADER_MouseLeave (hwnd
, wParam
, lParam
);
1905 return HEADER_MouseMove (hwnd
, wParam
, lParam
);
1907 case WM_NOTIFYFORMAT
:
1908 return HEADER_NotifyFormat (hwnd
, wParam
, lParam
);
1911 return HEADER_Size (hwnd
, wParam
);
1913 case WM_THEMECHANGED
:
1914 return HEADER_ThemeChanged (hwnd
);
1916 case WM_PRINTCLIENT
:
1918 return HEADER_Paint (hwnd
, wParam
);
1921 return HEADER_RButtonUp (hwnd
, wParam
, lParam
);
1924 return HEADER_SetCursor (hwnd
, wParam
, lParam
);
1927 return HEADER_SetFont (hwnd
, wParam
, lParam
);
1930 if ((msg
>= WM_USER
) && (msg
< WM_APP
))
1931 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
1932 msg
, wParam
, lParam
);
1933 return DefWindowProcA (hwnd
, msg
, wParam
, lParam
);
1939 HEADER_Register (void)
1943 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
1944 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
1945 wndClass
.lpfnWndProc
= HEADER_WindowProc
;
1946 wndClass
.cbClsExtra
= 0;
1947 wndClass
.cbWndExtra
= sizeof(HEADER_INFO
*);
1948 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1949 wndClass
.lpszClassName
= WC_HEADERW
;
1951 RegisterClassW (&wndClass
);
1956 HEADER_Unregister (void)
1958 UnregisterClassW (WC_HEADERW
, NULL
);