4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Eric Kohl for CodeWeavers
6 * Copyright 2003 Maxime Bellenge
7 * Copyright 2006 Mikolaj Zalewski
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * - Imagelist support (completed?)
25 * - Hottrack support (completed?)
26 * - Filters support (HDS_FILTER, HDI_FILTER, HDM_*FILTER*, HDN_*FILTER*)
27 * - New Windows Vista features
36 #include "wine/unicode.h"
42 #include "imagelist.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(header
);
57 INT iOrder
; /* see documentation of HD_ITEM */
59 BOOL bDown
; /* is item pressed? (used for drawing) */
60 RECT rect
; /* bounding rectangle of the item */
61 DWORD callbackMask
; /* HDI_* flags for items that are callback */
67 HWND hwndSelf
; /* Control window */
68 HWND hwndNotify
; /* Owner window to send notifications to */
69 INT nNotifyFormat
; /* format used for WM_NOTIFY messages */
70 UINT uNumItem
; /* number of items (columns) */
71 INT nHeight
; /* height of the header (pixels) */
72 HFONT hFont
; /* handle to the current font */
73 HCURSOR hcurArrow
; /* handle to the arrow cursor */
74 HCURSOR hcurDivider
; /* handle to a cursor (used over dividers) <-|-> */
75 HCURSOR hcurDivopen
; /* handle to a cursor (used over dividers) <-||-> */
76 BOOL bCaptured
; /* Is the mouse captured? */
77 BOOL bPressed
; /* Is a header item pressed (down)? */
78 BOOL bDragging
; /* Are we dragging an item? */
79 BOOL bTracking
; /* Is in tracking mode? */
80 POINT ptLButtonDown
; /* The point where the left button was pressed */
81 DWORD dwStyle
; /* the cached window GWL_STYLE */
82 INT iMoveItem
; /* index of tracked item. (Tracking mode) */
83 INT xTrackOffset
; /* distance between the right side of the tracked item and the cursor */
84 INT xOldTrack
; /* track offset (see above) after the last WM_MOUSEMOVE */
85 INT iHotItem
; /* index of hot item (cursor is over this item) */
86 INT iHotDivider
; /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
87 INT iMargin
; /* width of the margin that surrounds a bitmap */
89 HIMAGELIST himl
; /* handle to an image list (may be 0) */
90 HEADER_ITEM
*items
; /* pointer to array of HEADER_ITEM's */
91 INT
*order
; /* array of item IDs indexed by order */
92 BOOL bRectsValid
; /* validity flag for bounding rectangles */
97 #define DIVIDER_WIDTH 10
98 #define HOT_DIVIDER_WIDTH 2
99 #define MAX_HEADER_TEXT_LEN 260
100 #define HDN_UNICODE_OFFSET 20
101 #define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
103 #define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)
104 #define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)
105 #define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))
106 #define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)
109 static BOOL
HEADER_PrepareCallbackItems(const HEADER_INFO
*infoPtr
, INT iItem
, INT reqMask
);
110 static void HEADER_FreeCallbackItems(HEADER_ITEM
*lpItem
);
111 static LRESULT
HEADER_SendNotify(const HEADER_INFO
*infoPtr
, UINT code
, NMHDR
*hdr
);
112 static LRESULT
HEADER_SendCtrlCustomDraw(const HEADER_INFO
*infoPtr
, DWORD dwDrawStage
, HDC hdc
, const RECT
*rect
);
114 static const WCHAR themeClass
[] = {'H','e','a','d','e','r',0};
116 static void HEADER_StoreHDItemInHeader(HEADER_ITEM
*lpItem
, UINT mask
, const HDITEMW
*phdi
, BOOL fUnicode
)
118 if (mask
& HDI_UNSUPPORTED_FIELDS
)
119 FIXME("unsupported header fields %x\n", (mask
& HDI_UNSUPPORTED_FIELDS
));
121 if (mask
& HDI_BITMAP
)
122 lpItem
->hbm
= phdi
->hbm
;
124 if (mask
& HDI_FORMAT
)
125 lpItem
->fmt
= phdi
->fmt
;
127 if (mask
& HDI_LPARAM
)
128 lpItem
->lParam
= phdi
->lParam
;
130 if (mask
& HDI_WIDTH
)
131 lpItem
->cxy
= phdi
->cxy
;
133 if (mask
& HDI_IMAGE
)
135 lpItem
->iImage
= phdi
->iImage
;
136 if (phdi
->iImage
== I_IMAGECALLBACK
)
137 lpItem
->callbackMask
|= HDI_IMAGE
;
139 lpItem
->callbackMask
&= ~HDI_IMAGE
;
144 Free(lpItem
->pszText
);
145 lpItem
->pszText
= NULL
;
147 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers != TEXTCALLBACKA too */
149 static const WCHAR emptyString
[] = {0};
151 LPCWSTR pszText
= (phdi
->pszText
!= NULL
? phdi
->pszText
: emptyString
);
153 Str_SetPtrW(&lpItem
->pszText
, pszText
);
155 Str_SetPtrAtoW(&lpItem
->pszText
, (LPCSTR
)pszText
);
156 lpItem
->callbackMask
&= ~HDI_TEXT
;
160 lpItem
->pszText
= NULL
;
161 lpItem
->callbackMask
|= HDI_TEXT
;
166 static inline LRESULT
167 HEADER_IndexToOrder (const HEADER_INFO
*infoPtr
, INT iItem
)
169 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
170 return lpItem
->iOrder
;
175 HEADER_OrderToIndex(const HEADER_INFO
*infoPtr
, INT iorder
)
177 if ((iorder
<0) || iorder
>= infoPtr
->uNumItem
)
179 return infoPtr
->order
[iorder
];
183 HEADER_ChangeItemOrder(const HEADER_INFO
*infoPtr
, INT iItem
, INT iNewOrder
)
185 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
188 TRACE("%d: %d->%d\n", iItem
, lpItem
->iOrder
, iNewOrder
);
189 if (lpItem
->iOrder
< iNewOrder
)
191 memmove(&infoPtr
->order
[lpItem
->iOrder
],
192 &infoPtr
->order
[lpItem
->iOrder
+ 1],
193 (iNewOrder
- lpItem
->iOrder
) * sizeof(INT
));
195 if (iNewOrder
< lpItem
->iOrder
)
197 memmove(&infoPtr
->order
[iNewOrder
+ 1],
198 &infoPtr
->order
[iNewOrder
],
199 (lpItem
->iOrder
- iNewOrder
) * sizeof(INT
));
201 infoPtr
->order
[iNewOrder
] = iItem
;
202 nMin
= min(lpItem
->iOrder
, iNewOrder
);
203 nMax
= max(lpItem
->iOrder
, iNewOrder
);
204 for (i
= nMin
; i
<= nMax
; i
++)
205 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= i
;
208 /* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
210 HEADER_NextItem(const HEADER_INFO
*infoPtr
, INT iItem
)
212 return HEADER_OrderToIndex(infoPtr
, HEADER_IndexToOrder(infoPtr
, iItem
)+1);
216 HEADER_PrevItem(const HEADER_INFO
*infoPtr
, INT iItem
)
218 return HEADER_OrderToIndex(infoPtr
, HEADER_IndexToOrder(infoPtr
, iItem
)-1);
222 HEADER_SetItemBounds (HEADER_INFO
*infoPtr
)
229 infoPtr
->bRectsValid
= TRUE
;
231 if (infoPtr
->uNumItem
== 0)
234 GetClientRect (infoPtr
->hwndSelf
, &rect
);
237 for (i
= 0; i
< infoPtr
->uNumItem
; i
++) {
238 phdi
= &infoPtr
->items
[HEADER_OrderToIndex(infoPtr
,i
)];
239 phdi
->rect
.top
= rect
.top
;
240 phdi
->rect
.bottom
= rect
.bottom
;
242 phdi
->rect
.right
= phdi
->rect
.left
+ ((phdi
->cxy
>0)?phdi
->cxy
:0);
243 x
= phdi
->rect
.right
;
248 HEADER_Size (HEADER_INFO
*infoPtr
)
250 infoPtr
->bRectsValid
= FALSE
;
255 static void HEADER_GetHotDividerRect(const HEADER_INFO
*infoPtr
, RECT
*r
)
257 INT iDivider
= infoPtr
->iHotDivider
;
258 if (infoPtr
->uNumItem
> 0)
262 if (iDivider
< infoPtr
->uNumItem
)
264 lpItem
= &infoPtr
->items
[iDivider
];
265 r
->left
= lpItem
->rect
.left
- HOT_DIVIDER_WIDTH
/2;
266 r
->right
= lpItem
->rect
.left
+ HOT_DIVIDER_WIDTH
/2;
270 lpItem
= &infoPtr
->items
[HEADER_OrderToIndex(infoPtr
, infoPtr
->uNumItem
-1)];
271 r
->left
= lpItem
->rect
.right
- HOT_DIVIDER_WIDTH
/2;
272 r
->right
= lpItem
->rect
.right
+ HOT_DIVIDER_WIDTH
/2;
274 r
->top
= lpItem
->rect
.top
;
275 r
->bottom
= lpItem
->rect
.bottom
;
280 GetClientRect(infoPtr
->hwndSelf
, &clientRect
);
282 r
->right
= r
->left
+ HOT_DIVIDER_WIDTH
/2;
288 HEADER_DrawItem (HEADER_INFO
*infoPtr
, HDC hdc
, INT iItem
, BOOL bHotTrack
, LRESULT lCDFlags
)
290 HEADER_ITEM
*phdi
= &infoPtr
->items
[iItem
];
293 HTHEME theme
= GetWindowTheme (infoPtr
->hwndSelf
);
296 TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem
, bHotTrack
, (infoPtr
->nNotifyFormat
== NFR_UNICODE
));
299 if (r
.right
- r
.left
== 0)
300 return phdi
->rect
.right
;
302 /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
303 SetTextColor(hdc
, (bHotTrack
&& !theme
) ? COLOR_HIGHLIGHT
: COLOR_BTNTEXT
);
304 SetBkColor(hdc
, comctl32_color
.clr3dFace
);
306 if (lCDFlags
& CDRF_NOTIFYITEMDRAW
&& !(phdi
->fmt
& HDF_OWNERDRAW
))
308 LRESULT lCDItemFlags
;
310 nmcd
.dwDrawStage
= CDDS_PREPAINT
| CDDS_ITEM
;
312 nmcd
.dwItemSpec
= iItem
;
314 nmcd
.uItemState
= phdi
->bDown
? CDIS_SELECTED
: 0;
315 nmcd
.lItemlParam
= phdi
->lParam
;
317 lCDItemFlags
= HEADER_SendNotify(infoPtr
, NM_CUSTOMDRAW
, (NMHDR
*)&nmcd
);
318 if (lCDItemFlags
& CDRF_SKIPDEFAULT
)
319 return phdi
->rect
.right
;
323 int state
= (phdi
->bDown
) ? HIS_PRESSED
:
324 (bHotTrack
? HIS_HOT
: HIS_NORMAL
);
325 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, state
,
327 GetThemeBackgroundContentRect (theme
, hdc
, HP_HEADERITEM
, state
,
333 if (!(infoPtr
->dwStyle
& HDS_FLAT
))
335 if (infoPtr
->dwStyle
& HDS_BUTTONS
) {
337 DrawEdge (hdc
, &r
, BDR_RAISEDOUTER
,
338 BF_RECT
| BF_FLAT
| BF_MIDDLE
| BF_ADJUST
);
341 DrawEdge (hdc
, &r
, EDGE_RAISED
,
342 BF_RECT
| BF_SOFT
| BF_MIDDLE
| BF_ADJUST
);
345 DrawEdge (hdc
, &r
, EDGE_ETCHED
, BF_BOTTOM
| BF_RIGHT
| BF_ADJUST
);
348 hbr
= CreateSolidBrush(GetBkColor(hdc
));
349 FillRect(hdc
, &r
, hbr
);
357 if (phdi
->fmt
& HDF_OWNERDRAW
) {
360 dis
.CtlType
= ODT_HEADER
;
361 dis
.CtlID
= GetWindowLongPtrW (infoPtr
->hwndSelf
, GWLP_ID
);
363 dis
.itemAction
= ODA_DRAWENTIRE
;
364 dis
.itemState
= phdi
->bDown
? ODS_SELECTED
: 0;
365 dis
.hwndItem
= infoPtr
->hwndSelf
;
367 dis
.rcItem
= phdi
->rect
;
368 dis
.itemData
= phdi
->lParam
;
369 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
370 SendMessageW (infoPtr
->hwndNotify
, WM_DRAWITEM
,
371 (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
372 if (oldBkMode
!= TRANSPARENT
)
373 SetBkMode(hdc
, oldBkMode
);
376 UINT rw
, rh
, /* width and height of r */
377 *x
= NULL
, *w
= NULL
; /* x and width of the pic (bmp or img) which is part of cnt */
378 /* cnt,txt,img,bmp */
383 HEADER_PrepareCallbackItems(infoPtr
, iItem
, HDI_TEXT
|HDI_IMAGE
);
384 cw
= tw
= iw
= bw
= 0;
385 rw
= r
.right
- r
.left
;
386 rh
= r
.bottom
- r
.top
;
388 if (phdi
->fmt
& HDF_STRING
) {
391 SetRectEmpty(&textRect
);
392 DrawTextW (hdc
, phdi
->pszText
, -1,
393 &textRect
, DT_LEFT
|DT_VCENTER
|DT_SINGLELINE
|DT_CALCRECT
);
394 cw
= textRect
.right
- textRect
.left
+ 2 * infoPtr
->iMargin
;
397 if ((phdi
->fmt
& HDF_IMAGE
) && (infoPtr
->himl
)) {
398 iw
= infoPtr
->himl
->cx
+ 2 * infoPtr
->iMargin
;
403 if ((phdi
->fmt
& HDF_BITMAP
) && (phdi
->hbm
)) {
404 GetObjectW (phdi
->hbm
, sizeof(BITMAP
), &bmp
);
405 bw
= bmp
.bmWidth
+ 2 * infoPtr
->iMargin
;
415 /* align cx using the unclipped cw */
416 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_LEFT
)
418 else if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_CENTER
)
419 cx
= r
.left
+ rw
/ 2 - cw
/ 2;
426 if (cx
+ cw
> r
.right
)
429 tx
= cx
+ infoPtr
->iMargin
;
430 /* since cw might have changed we have to recalculate tw */
431 tw
= cw
- infoPtr
->iMargin
* 2;
435 if (phdi
->fmt
& HDF_BITMAP_ON_RIGHT
) {
436 /* put pic behind text */
437 *x
= cx
+ tw
+ infoPtr
->iMargin
* 3;
439 *x
= cx
+ infoPtr
->iMargin
;
440 /* move text behind pic */
446 /* since we're done with the layout we can
447 now calculate the position of bmp which
448 has no influence on alignment and layout
450 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_RIGHT
)
451 bx
= cx
- bw
+ infoPtr
->iMargin
;
453 bx
= cx
+ cw
+ infoPtr
->iMargin
;
457 HDC hClipDC
= GetDC(infoPtr
->hwndSelf
);
458 HRGN hClipRgn
= CreateRectRgn(r
.left
, r
.top
, r
.right
, r
.bottom
);
459 SelectClipRgn(hClipDC
, hClipRgn
);
462 HDC hdcBitmap
= CreateCompatibleDC (hClipDC
);
463 SelectObject (hdcBitmap
, phdi
->hbm
);
464 BitBlt (hClipDC
, bx
, r
.top
+ ((INT
)rh
- bmp
.bmHeight
) / 2,
465 bmp
.bmWidth
, bmp
.bmHeight
, hdcBitmap
, 0, 0, SRCCOPY
);
466 DeleteDC (hdcBitmap
);
470 ImageList_DrawEx (infoPtr
->himl
, phdi
->iImage
, hClipDC
,
471 ix
, r
.top
+ ((INT
)rh
- infoPtr
->himl
->cy
) / 2,
472 infoPtr
->himl
->cx
, infoPtr
->himl
->cy
, CLR_DEFAULT
, CLR_DEFAULT
, 0);
475 DeleteObject(hClipRgn
);
476 ReleaseDC(infoPtr
->hwndSelf
, hClipDC
);
479 if (((phdi
->fmt
& HDF_STRING
)
480 || (!(phdi
->fmt
& (HDF_OWNERDRAW
|HDF_STRING
|HDF_BITMAP
|
481 HDF_BITMAP_ON_RIGHT
|HDF_IMAGE
)))) /* no explicit format specified? */
482 && (phdi
->pszText
)) {
483 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
486 DrawTextW (hdc
, phdi
->pszText
, -1,
487 &r
, DT_LEFT
|DT_END_ELLIPSIS
|DT_VCENTER
|DT_SINGLELINE
);
488 if (oldBkMode
!= TRANSPARENT
)
489 SetBkMode(hdc
, oldBkMode
);
491 HEADER_FreeCallbackItems(phdi
);
494 return phdi
->rect
.right
;
498 HEADER_DrawHotDivider(const HEADER_INFO
*infoPtr
, HDC hdc
)
503 HEADER_GetHotDividerRect(infoPtr
, &r
);
504 brush
= CreateSolidBrush(comctl32_color
.clrHighlight
);
505 FillRect(hdc
, &r
, brush
);
510 HEADER_Refresh (HEADER_INFO
*infoPtr
, HDC hdc
)
512 HFONT hFont
, hOldFont
;
518 HTHEME theme
= GetWindowTheme (infoPtr
->hwndSelf
);
520 if (!infoPtr
->bRectsValid
)
521 HEADER_SetItemBounds(infoPtr
);
523 /* get rect for the bar, adjusted for the border */
524 GetClientRect (infoPtr
->hwndSelf
, &rect
);
525 lCDFlags
= HEADER_SendCtrlCustomDraw(infoPtr
, CDDS_PREPAINT
, hdc
, &rect
);
527 if (infoPtr
->bDragging
)
528 ImageList_DragShowNolock(FALSE
);
530 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
531 hOldFont
= SelectObject (hdc
, hFont
);
533 /* draw Background */
534 if (infoPtr
->uNumItem
== 0 && theme
== NULL
) {
535 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
536 FillRect(hdc
, &rect
, hbrBk
);
540 for (i
= 0; x
<= rect
.right
&& i
< infoPtr
->uNumItem
; i
++) {
541 int idx
= HEADER_OrderToIndex(infoPtr
,i
);
542 if (RectVisible(hdc
, &infoPtr
->items
[idx
].rect
))
543 HEADER_DrawItem(infoPtr
, hdc
, idx
, infoPtr
->iHotItem
== idx
, lCDFlags
);
544 x
= infoPtr
->items
[idx
].rect
.right
;
549 if ((x
<= rect
.right
) && RectVisible(hdc
, &rcRest
) && (infoPtr
->uNumItem
> 0)) {
551 DrawThemeBackground(theme
, hdc
, HP_HEADERITEM
, HIS_NORMAL
, &rcRest
, NULL
);
553 else if (infoPtr
->dwStyle
& HDS_FLAT
) {
554 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
555 FillRect(hdc
, &rcRest
, hbrBk
);
559 if (infoPtr
->dwStyle
& HDS_BUTTONS
)
560 DrawEdge (hdc
, &rcRest
, EDGE_RAISED
, BF_TOP
|BF_LEFT
|BF_BOTTOM
|BF_SOFT
|BF_MIDDLE
);
562 DrawEdge (hdc
, &rcRest
, EDGE_ETCHED
, BF_BOTTOM
|BF_MIDDLE
);
566 if (infoPtr
->iHotDivider
!= -1)
567 HEADER_DrawHotDivider(infoPtr
, hdc
);
569 if (infoPtr
->bDragging
)
570 ImageList_DragShowNolock(TRUE
);
571 SelectObject (hdc
, hOldFont
);
573 if (lCDFlags
& CDRF_NOTIFYPOSTPAINT
)
574 HEADER_SendCtrlCustomDraw(infoPtr
, CDDS_POSTPAINT
, hdc
, &rect
);
579 HEADER_RefreshItem (HEADER_INFO
*infoPtr
, INT iItem
)
581 if (!infoPtr
->bRectsValid
)
582 HEADER_SetItemBounds(infoPtr
);
584 InvalidateRect(infoPtr
->hwndSelf
, &infoPtr
->items
[iItem
].rect
, FALSE
);
589 HEADER_InternalHitTest (const HEADER_INFO
*infoPtr
, const POINT
*lpPt
, UINT
*pFlags
, INT
*pItem
)
596 GetClientRect (infoPtr
->hwndSelf
, &rect
);
600 if (PtInRect (&rect
, *lpPt
))
602 if (infoPtr
->uNumItem
== 0) {
603 *pFlags
|= HHT_NOWHERE
;
609 /* somewhere inside */
610 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++) {
611 rect
= infoPtr
->items
[iCount
].rect
;
612 width
= rect
.right
- rect
.left
;
617 if (PtInRect (&rect
, *lpPt
)) {
618 if (width
<= 2 * DIVIDER_WIDTH
) {
619 *pFlags
|= HHT_ONHEADER
;
621 TRACE("ON HEADER %d\n", iCount
);
624 if (HEADER_IndexToOrder(infoPtr
, iCount
) > 0) {
626 rcTest
.right
= rcTest
.left
+ DIVIDER_WIDTH
;
627 if (PtInRect (&rcTest
, *lpPt
)) {
629 *pFlags
|= HHT_ONDIVOPEN
;
630 *pItem
= HEADER_PrevItem(infoPtr
, iCount
);
631 TRACE("ON DIVOPEN %d\n", *pItem
);
635 *pFlags
|= HHT_ONDIVIDER
;
636 *pItem
= HEADER_PrevItem(infoPtr
, iCount
);
637 TRACE("ON DIVIDER %d\n", *pItem
);
643 rcTest
.left
= rcTest
.right
- DIVIDER_WIDTH
;
644 if (PtInRect (&rcTest
, *lpPt
)) {
645 *pFlags
|= HHT_ONDIVIDER
;
647 TRACE("ON DIVIDER %d\n", *pItem
);
651 *pFlags
|= HHT_ONHEADER
;
653 TRACE("ON HEADER %d\n", iCount
);
658 /* check for last divider part (on nowhere) */
659 rect
= infoPtr
->items
[infoPtr
->uNumItem
-1].rect
;
660 rect
.left
= rect
.right
;
661 rect
.right
+= DIVIDER_WIDTH
;
662 if (PtInRect (&rect
, *lpPt
)) {
664 *pFlags
|= HHT_ONDIVOPEN
;
665 *pItem
= infoPtr
->uNumItem
- 1;
666 TRACE("ON DIVOPEN %d\n", *pItem
);
670 *pFlags
|= HHT_ONDIVIDER
;
671 *pItem
= infoPtr
->uNumItem
-1;
672 TRACE("ON DIVIDER %d\n", *pItem
);
677 *pFlags
|= HHT_NOWHERE
;
684 if (lpPt
->x
< rect
.left
) {
686 *pFlags
|= HHT_TOLEFT
;
688 else if (lpPt
->x
> rect
.right
) {
690 *pFlags
|= HHT_TORIGHT
;
693 if (lpPt
->y
< rect
.top
) {
695 *pFlags
|= HHT_ABOVE
;
697 else if (lpPt
->y
> rect
.bottom
) {
699 *pFlags
|= HHT_BELOW
;
704 TRACE("flags=0x%X\n", *pFlags
);
710 HEADER_DrawTrackLine (const HEADER_INFO
*infoPtr
, HDC hdc
, INT x
)
716 GetClientRect (infoPtr
->hwndSelf
, &rect
);
718 hOldPen
= SelectObject (hdc
, GetStockObject (BLACK_PEN
));
719 oldRop
= SetROP2 (hdc
, R2_XORPEN
);
720 MoveToEx (hdc
, x
, rect
.top
, NULL
);
721 LineTo (hdc
, x
, rect
.bottom
);
722 SetROP2 (hdc
, oldRop
);
723 SelectObject (hdc
, hOldPen
);
728 * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
731 * [I] infoPtr : the header that wants to send the notify
732 * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
733 * [I] src : The source HDITEM. It may be a HDITEMA or HDITEMW
734 * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
735 * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
736 * the HDITEM is no longer in use or NULL if none was needed
738 * NOTE: We depend on HDITEMA and HDITEMW having the same structure
740 static void HEADER_CopyHDItemForNotify(const HEADER_INFO
*infoPtr
, HDITEMW
*dest
,
741 const HDITEMW
*src
, BOOL fSourceUnicode
, LPVOID
*ppvScratch
)
746 if (src
->mask
& HDI_TEXT
&& src
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers TEXTCALLBACKA as well */
748 if (fSourceUnicode
&& infoPtr
->nNotifyFormat
!= NFR_UNICODE
)
750 dest
->pszText
= NULL
;
751 Str_SetPtrWtoA((LPSTR
*)&dest
->pszText
, src
->pszText
);
752 *ppvScratch
= dest
->pszText
;
755 if (!fSourceUnicode
&& infoPtr
->nNotifyFormat
== NFR_UNICODE
)
757 dest
->pszText
= NULL
;
758 Str_SetPtrAtoW(&dest
->pszText
, (LPSTR
)src
->pszText
);
759 *ppvScratch
= dest
->pszText
;
764 static UINT
HEADER_NotifyCodeWtoA(UINT code
)
766 /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
767 if (code
>= HDN_LAST
&& code
<= HDN_FIRST_UNICODE
)
768 return code
+ HDN_UNICODE_OFFSET
;
774 HEADER_SendNotify(const HEADER_INFO
*infoPtr
, UINT code
, NMHDR
*nmhdr
)
776 nmhdr
->hwndFrom
= infoPtr
->hwndSelf
;
777 nmhdr
->idFrom
= GetWindowLongPtrW (infoPtr
->hwndSelf
, GWLP_ID
);
780 return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
,
781 nmhdr
->idFrom
, (LPARAM
)nmhdr
);
785 HEADER_SendSimpleNotify (const HEADER_INFO
*infoPtr
, UINT code
)
788 return (BOOL
)HEADER_SendNotify(infoPtr
, code
, &nmhdr
);
792 HEADER_SendCtrlCustomDraw(const HEADER_INFO
*infoPtr
, DWORD dwDrawStage
, HDC hdc
, const RECT
*rect
)
795 nm
.dwDrawStage
= dwDrawStage
;
802 return HEADER_SendNotify(infoPtr
, NM_CUSTOMDRAW
, (NMHDR
*)&nm
);
806 HEADER_SendNotifyWithHDItemT(const HEADER_INFO
*infoPtr
, UINT code
, INT iItem
, HDITEMW
*lpItem
)
810 if (infoPtr
->nNotifyFormat
!= NFR_UNICODE
)
811 code
= HEADER_NotifyCodeWtoA(code
);
814 nmhdr
.pitem
= lpItem
;
816 return (BOOL
)HEADER_SendNotify(infoPtr
, code
, (NMHDR
*)&nmhdr
);
820 HEADER_SendNotifyWithIntFieldT(const HEADER_INFO
*infoPtr
, UINT code
, INT iItem
, INT mask
, INT iValue
)
824 /* copying only the iValue should be ok but to make the code more robust we copy everything */
825 nmitem
.cxy
= infoPtr
->items
[iItem
].cxy
;
826 nmitem
.hbm
= infoPtr
->items
[iItem
].hbm
;
827 nmitem
.pszText
= NULL
;
828 nmitem
.cchTextMax
= 0;
829 nmitem
.fmt
= infoPtr
->items
[iItem
].fmt
;
830 nmitem
.lParam
= infoPtr
->items
[iItem
].lParam
;
831 nmitem
.iOrder
= infoPtr
->items
[iItem
].iOrder
;
832 nmitem
.iImage
= infoPtr
->items
[iItem
].iImage
;
841 nmitem
.iOrder
= iValue
;
844 ERR("invalid mask value 0x%x\n", iValue
);
847 return HEADER_SendNotifyWithHDItemT(infoPtr
, code
, iItem
, &nmitem
);
851 * Prepare callback items
852 * depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA
853 * (so we handle the two cases only doing a specific cast for pszText).
854 * Checks if any of the required field are callback. If there are sends a
855 * NMHDISPINFO notify to retrieve these items. The items are stored in the
856 * HEADER_ITEM pszText and iImage fields. They should be freed with
857 * HEADER_FreeCallbackItems.
859 * @param hwnd : hwnd header container handler
860 * @param iItem : the header item id
861 * @param reqMask : required fields. If any of them is callback this function will fetch it
863 * @return TRUE on success, else FALSE
866 HEADER_PrepareCallbackItems(const HEADER_INFO
*infoPtr
, INT iItem
, INT reqMask
)
868 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
869 DWORD mask
= reqMask
& lpItem
->callbackMask
;
870 NMHDDISPINFOW dispInfo
;
871 void *pvBuffer
= NULL
;
875 if (mask
&HDI_TEXT
&& lpItem
->pszText
!= NULL
)
877 ERR("(): function called without a call to FreeCallbackItems\n");
878 Free(lpItem
->pszText
);
879 lpItem
->pszText
= NULL
;
882 memset(&dispInfo
, 0, sizeof(NMHDDISPINFOW
));
883 dispInfo
.hdr
.hwndFrom
= infoPtr
->hwndSelf
;
884 dispInfo
.hdr
.idFrom
= GetWindowLongPtrW (infoPtr
->hwndSelf
, GWLP_ID
);
885 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
887 dispInfo
.hdr
.code
= HDN_GETDISPINFOW
;
889 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(WCHAR
));
893 dispInfo
.hdr
.code
= HDN_GETDISPINFOA
;
895 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(CHAR
));
897 dispInfo
.pszText
= pvBuffer
;
898 dispInfo
.cchTextMax
= (pvBuffer
!=NULL
?MAX_HEADER_TEXT_LEN
:0);
899 dispInfo
.iItem
= iItem
;
900 dispInfo
.mask
= mask
;
901 dispInfo
.lParam
= lpItem
->lParam
;
903 TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr
->nNotifyFormat
== NFR_UNICODE
?'W':'A');
904 SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, dispInfo
.hdr
.idFrom
, (LPARAM
)&dispInfo
);
906 TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n",
908 (infoPtr
->nNotifyFormat
== NFR_UNICODE
? debugstr_w(dispInfo
.pszText
) : (LPSTR
) dispInfo
.pszText
),
909 (void*) dispInfo
.lParam
);
911 if (mask
& HDI_IMAGE
)
912 lpItem
->iImage
= dispInfo
.iImage
;
915 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
917 lpItem
->pszText
= pvBuffer
;
919 /* the user might have used his own buffer */
920 if (dispInfo
.pszText
!= lpItem
->pszText
)
921 Str_GetPtrW(dispInfo
.pszText
, lpItem
->pszText
, MAX_HEADER_TEXT_LEN
);
925 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)dispInfo
.pszText
);
930 if (dispInfo
.mask
& HDI_DI_SETITEM
)
932 /* make the items permanent */
933 lpItem
->callbackMask
&= ~dispInfo
.mask
;
941 * Free the items that might be allocated with HEADER_PrepareCallbackItems
944 * [I] lpItem : the item to free the data
948 HEADER_FreeCallbackItems(HEADER_ITEM
*lpItem
)
950 if (lpItem
->callbackMask
&HDI_TEXT
)
952 Free(lpItem
->pszText
);
953 lpItem
->pszText
= NULL
;
956 if (lpItem
->callbackMask
&HDI_IMAGE
)
957 lpItem
->iImage
= I_IMAGECALLBACK
;
961 HEADER_CreateDragImage (HEADER_INFO
*infoPtr
, INT iItem
)
965 HBITMAP hMemory
, hOldBitmap
;
973 if (iItem
>= infoPtr
->uNumItem
)
976 if (!infoPtr
->bRectsValid
)
977 HEADER_SetItemBounds(infoPtr
);
979 lpItem
= &infoPtr
->items
[iItem
];
980 width
= lpItem
->rect
.right
- lpItem
->rect
.left
;
981 height
= lpItem
->rect
.bottom
- lpItem
->rect
.top
;
983 hDeviceDC
= GetDC(NULL
);
984 hMemoryDC
= CreateCompatibleDC(hDeviceDC
);
985 hMemory
= CreateCompatibleBitmap(hDeviceDC
, width
, height
);
986 ReleaseDC(NULL
, hDeviceDC
);
987 hOldBitmap
= SelectObject(hMemoryDC
, hMemory
);
988 SetViewportOrgEx(hMemoryDC
, -lpItem
->rect
.left
, -lpItem
->rect
.top
, NULL
);
989 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject(SYSTEM_FONT
);
990 SelectObject(hMemoryDC
, hFont
);
992 GetClientRect(infoPtr
->hwndSelf
, &rc
);
993 lCDFlags
= HEADER_SendCtrlCustomDraw(infoPtr
, CDDS_PREPAINT
, hMemoryDC
, &rc
);
994 HEADER_DrawItem(infoPtr
, hMemoryDC
, iItem
, FALSE
, lCDFlags
);
995 if (lCDFlags
& CDRF_NOTIFYPOSTPAINT
)
996 HEADER_SendCtrlCustomDraw(infoPtr
, CDDS_POSTPAINT
, hMemoryDC
, &rc
);
998 hMemory
= SelectObject(hMemoryDC
, hOldBitmap
);
1001 if (hMemory
== NULL
) /* if anything failed */
1004 himl
= ImageList_Create(width
, height
, ILC_COLORDDB
, 1, 1);
1005 ImageList_Add(himl
, hMemory
, NULL
);
1006 DeleteObject(hMemory
);
1007 return (LRESULT
)himl
;
1011 HEADER_SetHotDivider(HEADER_INFO
*infoPtr
, WPARAM wParam
, LPARAM lParam
)
1020 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1022 HEADER_InternalHitTest (infoPtr
, &pt
, &flags
, &iDivider
);
1024 if (flags
& HHT_TOLEFT
)
1026 else if (flags
& HHT_NOWHERE
|| flags
& HHT_TORIGHT
)
1027 iDivider
= infoPtr
->uNumItem
;
1030 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iDivider
];
1031 if (pt
.x
> (lpItem
->rect
.left
+lpItem
->rect
.right
)/2)
1032 iDivider
= HEADER_NextItem(infoPtr
, iDivider
);
1036 iDivider
= (INT
)lParam
;
1038 /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */
1039 if (iDivider
<-1 || iDivider
>(int)infoPtr
->uNumItem
)
1042 if (iDivider
!= infoPtr
->iHotDivider
)
1044 if (infoPtr
->iHotDivider
!= -1)
1046 HEADER_GetHotDividerRect(infoPtr
, &r
);
1047 InvalidateRect(infoPtr
->hwndSelf
, &r
, FALSE
);
1049 infoPtr
->iHotDivider
= iDivider
;
1052 HEADER_GetHotDividerRect(infoPtr
, &r
);
1053 InvalidateRect(infoPtr
->hwndSelf
, &r
, FALSE
);
1060 HEADER_DeleteItem (HEADER_INFO
*infoPtr
, INT iItem
)
1065 TRACE("[iItem=%d]\n", iItem
);
1067 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
1070 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1071 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
1073 iOrder
= infoPtr
->items
[iItem
].iOrder
;
1074 Free(infoPtr
->items
[iItem
].pszText
);
1076 infoPtr
->uNumItem
--;
1077 memmove(&infoPtr
->items
[iItem
], &infoPtr
->items
[iItem
+ 1],
1078 (infoPtr
->uNumItem
- iItem
) * sizeof(HEADER_ITEM
));
1079 memmove(&infoPtr
->order
[iOrder
], &infoPtr
->order
[iOrder
+ 1],
1080 (infoPtr
->uNumItem
- iOrder
) * sizeof(INT
));
1081 infoPtr
->items
= ReAlloc(infoPtr
->items
, sizeof(HEADER_ITEM
) * infoPtr
->uNumItem
);
1082 infoPtr
->order
= ReAlloc(infoPtr
->order
, sizeof(INT
) * infoPtr
->uNumItem
);
1084 /* Correct the orders */
1085 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1087 if (infoPtr
->order
[i
] > iItem
)
1088 infoPtr
->order
[i
]--;
1090 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= i
;
1092 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1093 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
1095 HEADER_SetItemBounds (infoPtr
);
1096 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
1103 HEADER_GetImageList (const HEADER_INFO
*infoPtr
)
1105 return (LRESULT
)infoPtr
->himl
;
1110 HEADER_GetItemT (const HEADER_INFO
*infoPtr
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1112 HEADER_ITEM
*lpItem
;
1118 TRACE("[nItem=%d]\n", nItem
);
1124 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1127 if (mask
& HDI_UNKNOWN_FIELDS
)
1129 TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask
);
1130 mask
&= HDI_COMCTL32_4_0_FIELDS
;
1133 lpItem
= &infoPtr
->items
[nItem
];
1134 HEADER_PrepareCallbackItems(infoPtr
, nItem
, mask
);
1136 if (mask
& HDI_BITMAP
)
1137 phdi
->hbm
= lpItem
->hbm
;
1139 if (mask
& HDI_FORMAT
)
1140 phdi
->fmt
= lpItem
->fmt
;
1142 if (mask
& HDI_WIDTH
)
1143 phdi
->cxy
= lpItem
->cxy
;
1145 if (mask
& HDI_LPARAM
)
1146 phdi
->lParam
= lpItem
->lParam
;
1148 if (mask
& HDI_IMAGE
)
1149 phdi
->iImage
= lpItem
->iImage
;
1151 if (mask
& HDI_ORDER
)
1152 phdi
->iOrder
= lpItem
->iOrder
;
1154 if (mask
& HDI_TEXT
)
1157 Str_GetPtrW (lpItem
->pszText
, phdi
->pszText
, phdi
->cchTextMax
);
1159 Str_GetPtrWtoA (lpItem
->pszText
, (LPSTR
)phdi
->pszText
, phdi
->cchTextMax
);
1162 HEADER_FreeCallbackItems(lpItem
);
1167 static inline LRESULT
1168 HEADER_GetItemCount (const HEADER_INFO
*infoPtr
)
1170 return infoPtr
->uNumItem
;
1175 HEADER_GetItemRect (const HEADER_INFO
*infoPtr
, INT iItem
, LPRECT lpRect
)
1177 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
1180 lpRect
->left
= infoPtr
->items
[iItem
].rect
.left
;
1181 lpRect
->right
= infoPtr
->items
[iItem
].rect
.right
;
1182 lpRect
->top
= infoPtr
->items
[iItem
].rect
.top
;
1183 lpRect
->bottom
= infoPtr
->items
[iItem
].rect
.bottom
;
1190 HEADER_GetOrderArray(const HEADER_INFO
*infoPtr
, INT size
, LPINT order
)
1192 if ((UINT
)size
<infoPtr
->uNumItem
)
1195 memcpy(order
, infoPtr
->order
, infoPtr
->uNumItem
* sizeof(INT
));
1200 HEADER_SetOrderArray(HEADER_INFO
*infoPtr
, INT size
, const INT
*order
)
1203 HEADER_ITEM
*lpItem
;
1205 if ((UINT
)size
<infoPtr
->uNumItem
)
1207 memcpy(infoPtr
->order
, order
, infoPtr
->uNumItem
* sizeof(INT
));
1208 for (i
=0; i
<size
; i
++)
1210 lpItem
= &infoPtr
->items
[*order
++];
1213 infoPtr
->bRectsValid
=0;
1214 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
1218 static inline LRESULT
1219 HEADER_GetUnicodeFormat (const HEADER_INFO
*infoPtr
)
1221 return (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1226 HEADER_HitTest (const HEADER_INFO
*infoPtr
, LPHDHITTESTINFO phti
)
1228 HEADER_InternalHitTest (infoPtr
, &phti
->pt
, &phti
->flags
, &phti
->iItem
);
1230 if (phti
->flags
== HHT_NOWHERE
)
1238 HEADER_InsertItemT (HEADER_INFO
*infoPtr
, INT nItem
, const HDITEMW
*phdi
, BOOL bUnicode
)
1240 HEADER_ITEM
*lpItem
;
1245 if ((phdi
== NULL
) || (nItem
< 0) || (phdi
->mask
== 0))
1248 if (nItem
> infoPtr
->uNumItem
)
1249 nItem
= infoPtr
->uNumItem
;
1251 iOrder
= (phdi
->mask
& HDI_ORDER
) ? phdi
->iOrder
: nItem
;
1254 else if (infoPtr
->uNumItem
< iOrder
)
1255 iOrder
= infoPtr
->uNumItem
;
1257 infoPtr
->uNumItem
++;
1258 infoPtr
->items
= ReAlloc(infoPtr
->items
, sizeof(HEADER_ITEM
) * infoPtr
->uNumItem
);
1259 infoPtr
->order
= ReAlloc(infoPtr
->order
, sizeof(INT
) * infoPtr
->uNumItem
);
1261 /* make space for the new item */
1262 memmove(&infoPtr
->items
[nItem
+ 1], &infoPtr
->items
[nItem
],
1263 (infoPtr
->uNumItem
- nItem
- 1) * sizeof(HEADER_ITEM
));
1264 memmove(&infoPtr
->order
[iOrder
+ 1], &infoPtr
->order
[iOrder
],
1265 (infoPtr
->uNumItem
- iOrder
- 1) * sizeof(INT
));
1267 /* update the order array */
1268 infoPtr
->order
[iOrder
] = nItem
;
1269 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1271 if (i
!= iOrder
&& infoPtr
->order
[i
] >= nItem
)
1272 infoPtr
->order
[i
]++;
1273 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= i
;
1276 lpItem
= &infoPtr
->items
[nItem
];
1277 ZeroMemory(lpItem
, sizeof(HEADER_ITEM
));
1278 /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
1279 copyMask
= phdi
->mask
| HDI_WIDTH
| HDI_FORMAT
| HDI_LPARAM
;
1280 HEADER_StoreHDItemInHeader(lpItem
, copyMask
, phdi
, bUnicode
);
1281 lpItem
->iOrder
= iOrder
;
1283 /* set automatically some format bits */
1284 if (phdi
->mask
& HDI_TEXT
)
1285 lpItem
->fmt
|= HDF_STRING
;
1287 lpItem
->fmt
&= ~HDF_STRING
;
1289 if (lpItem
->hbm
!= NULL
)
1290 lpItem
->fmt
|= HDF_BITMAP
;
1292 lpItem
->fmt
&= ~HDF_BITMAP
;
1294 if (phdi
->mask
& HDI_IMAGE
)
1295 lpItem
->fmt
|= HDF_IMAGE
;
1297 HEADER_SetItemBounds (infoPtr
);
1298 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
1305 HEADER_Layout (HEADER_INFO
*infoPtr
, LPHDLAYOUT lpLayout
)
1307 lpLayout
->pwpos
->hwnd
= infoPtr
->hwndSelf
;
1308 lpLayout
->pwpos
->hwndInsertAfter
= 0;
1309 lpLayout
->pwpos
->x
= lpLayout
->prc
->left
;
1310 lpLayout
->pwpos
->y
= lpLayout
->prc
->top
;
1311 lpLayout
->pwpos
->cx
= lpLayout
->prc
->right
- lpLayout
->prc
->left
;
1312 if (infoPtr
->dwStyle
& HDS_HIDDEN
)
1313 lpLayout
->pwpos
->cy
= 0;
1315 lpLayout
->pwpos
->cy
= infoPtr
->nHeight
;
1316 lpLayout
->prc
->top
+= infoPtr
->nHeight
;
1318 lpLayout
->pwpos
->flags
= SWP_NOZORDER
;
1320 TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1321 lpLayout
->pwpos
->x
, lpLayout
->pwpos
->y
,
1322 lpLayout
->pwpos
->cx
, lpLayout
->pwpos
->cy
);
1324 infoPtr
->bRectsValid
= FALSE
;
1331 HEADER_SetImageList (HEADER_INFO
*infoPtr
, HIMAGELIST himl
)
1335 TRACE("(himl %p)\n", himl
);
1336 himlOld
= infoPtr
->himl
;
1337 infoPtr
->himl
= himl
;
1339 /* FIXME: Refresh needed??? */
1341 return (LRESULT
)himlOld
;
1346 HEADER_GetBitmapMargin(const HEADER_INFO
*infoPtr
)
1348 return infoPtr
->iMargin
;
1352 HEADER_SetBitmapMargin(HEADER_INFO
*infoPtr
, INT iMargin
)
1354 INT oldMargin
= infoPtr
->iMargin
;
1356 infoPtr
->iMargin
= iMargin
;
1362 HEADER_SetItemT (HEADER_INFO
*infoPtr
, INT nItem
, const HDITEMW
*phdi
, BOOL bUnicode
)
1364 HEADER_ITEM
*lpItem
;
1370 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1373 TRACE("[nItem=%d]\n", nItem
);
1375 HEADER_CopyHDItemForNotify(infoPtr
, &hdNotify
, phdi
, bUnicode
, &pvScratch
);
1376 if (HEADER_SendNotifyWithHDItemT(infoPtr
, HDN_ITEMCHANGINGW
, nItem
, &hdNotify
))
1382 lpItem
= &infoPtr
->items
[nItem
];
1383 HEADER_StoreHDItemInHeader(lpItem
, phdi
->mask
, phdi
, bUnicode
);
1385 if (phdi
->mask
& HDI_ORDER
)
1386 if (phdi
->iOrder
>= 0 && phdi
->iOrder
< infoPtr
->uNumItem
)
1387 HEADER_ChangeItemOrder(infoPtr
, nItem
, phdi
->iOrder
);
1389 HEADER_SendNotifyWithHDItemT(infoPtr
, HDN_ITEMCHANGEDW
, nItem
, &hdNotify
);
1391 HEADER_SetItemBounds (infoPtr
);
1393 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
1399 static inline LRESULT
1400 HEADER_SetUnicodeFormat (HEADER_INFO
*infoPtr
, WPARAM wParam
)
1402 BOOL bTemp
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1404 infoPtr
->nNotifyFormat
= ((BOOL
)wParam
? NFR_UNICODE
: NFR_ANSI
);
1411 HEADER_Create (HWND hwnd
, const CREATESTRUCTW
*lpcs
)
1413 HEADER_INFO
*infoPtr
;
1418 infoPtr
= Alloc (sizeof(HEADER_INFO
));
1419 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
1421 infoPtr
->hwndSelf
= hwnd
;
1422 infoPtr
->hwndNotify
= lpcs
->hwndParent
;
1423 infoPtr
->uNumItem
= 0;
1427 infoPtr
->bRectsValid
= FALSE
;
1428 infoPtr
->hcurArrow
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1429 infoPtr
->hcurDivider
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDER
));
1430 infoPtr
->hcurDivopen
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDEROPEN
));
1431 infoPtr
->bPressed
= FALSE
;
1432 infoPtr
->bTracking
= FALSE
;
1433 infoPtr
->dwStyle
= lpcs
->style
;
1434 infoPtr
->iMoveItem
= 0;
1436 infoPtr
->iHotItem
= -1;
1437 infoPtr
->iHotDivider
= -1;
1438 infoPtr
->iMargin
= 3*GetSystemMetrics(SM_CXEDGE
);
1439 infoPtr
->nNotifyFormat
=
1440 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
1443 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1444 GetTextMetricsW (hdc
, &tm
);
1445 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1446 SelectObject (hdc
, hOldFont
);
1449 OpenThemeData(hwnd
, themeClass
);
1456 HEADER_Destroy (HEADER_INFO
*infoPtr
)
1458 HTHEME theme
= GetWindowTheme(infoPtr
->hwndSelf
);
1459 CloseThemeData(theme
);
1464 HEADER_NCDestroy (HEADER_INFO
*infoPtr
)
1466 HEADER_ITEM
*lpItem
;
1469 if (infoPtr
->items
) {
1470 lpItem
= infoPtr
->items
;
1471 for (nItem
= 0; nItem
< infoPtr
->uNumItem
; nItem
++, lpItem
++) {
1472 Free(lpItem
->pszText
);
1474 Free (infoPtr
->items
);
1477 Free(infoPtr
->order
);
1480 ImageList_Destroy (infoPtr
->himl
);
1482 SetWindowLongPtrW (infoPtr
->hwndSelf
, 0, 0);
1489 static inline LRESULT
1490 HEADER_GetFont (const HEADER_INFO
*infoPtr
)
1492 return (LRESULT
)infoPtr
->hFont
;
1497 HEADER_IsDragDistance(const HEADER_INFO
*infoPtr
, const POINT
*pt
)
1499 /* Windows allows for a mouse movement before starting the drag. We use the
1500 * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance.
1502 return (abs(infoPtr
->ptLButtonDown
.x
- pt
->x
)>GetSystemMetrics(SM_CXDOUBLECLK
) ||
1503 abs(infoPtr
->ptLButtonDown
.y
- pt
->y
)>GetSystemMetrics(SM_CYDOUBLECLK
));
1507 HEADER_LButtonDblClk (const HEADER_INFO
*infoPtr
, INT x
, INT y
)
1515 HEADER_InternalHitTest (infoPtr
, &pt
, &flags
, &nItem
);
1517 if ((infoPtr
->dwStyle
& HDS_BUTTONS
) && (flags
== HHT_ONHEADER
))
1518 HEADER_SendNotifyWithHDItemT(infoPtr
, HDN_ITEMDBLCLICKW
, nItem
, NULL
);
1519 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
))
1520 HEADER_SendNotifyWithHDItemT(infoPtr
, HDN_DIVIDERDBLCLICKW
, nItem
, NULL
);
1527 HEADER_LButtonDown (HEADER_INFO
*infoPtr
, INT x
, INT y
)
1536 HEADER_InternalHitTest (infoPtr
, &pt
, &flags
, &nItem
);
1538 if ((infoPtr
->dwStyle
& HDS_BUTTONS
) && (flags
== HHT_ONHEADER
)) {
1539 SetCapture (infoPtr
->hwndSelf
);
1540 infoPtr
->bCaptured
= TRUE
;
1541 infoPtr
->bPressed
= TRUE
;
1542 infoPtr
->bDragging
= FALSE
;
1543 infoPtr
->iMoveItem
= nItem
;
1544 infoPtr
->ptLButtonDown
= pt
;
1546 infoPtr
->items
[nItem
].bDown
= TRUE
;
1548 /* Send WM_CUSTOMDRAW */
1549 hdc
= GetDC (infoPtr
->hwndSelf
);
1550 HEADER_RefreshItem (infoPtr
, nItem
);
1551 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1553 TRACE("Pressed item %d!\n", nItem
);
1555 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
)) {
1556 INT iCurrWidth
= infoPtr
->items
[nItem
].cxy
;
1557 if (!HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_BEGINTRACKW
, nItem
, HDI_WIDTH
, iCurrWidth
))
1559 SetCapture (infoPtr
->hwndSelf
);
1560 infoPtr
->bCaptured
= TRUE
;
1561 infoPtr
->bTracking
= TRUE
;
1562 infoPtr
->iMoveItem
= nItem
;
1563 infoPtr
->xTrackOffset
= infoPtr
->items
[nItem
].rect
.right
- pt
.x
;
1565 if (!(infoPtr
->dwStyle
& HDS_FULLDRAG
)) {
1566 infoPtr
->xOldTrack
= infoPtr
->items
[nItem
].rect
.right
;
1567 hdc
= GetDC (infoPtr
->hwndSelf
);
1568 HEADER_DrawTrackLine (infoPtr
, hdc
, infoPtr
->xOldTrack
);
1569 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1572 TRACE("Begin tracking item %d!\n", nItem
);
1581 HEADER_LButtonUp (HEADER_INFO
*infoPtr
, INT x
, INT y
)
1590 HEADER_InternalHitTest (infoPtr
, &pt
, &flags
, &nItem
);
1592 if (infoPtr
->bPressed
) {
1593 if (infoPtr
->bDragging
)
1595 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1598 ImageList_DragShowNolock(FALSE
);
1599 ImageList_EndDrag();
1600 lpItem
->bDown
=FALSE
;
1602 if (infoPtr
->iHotDivider
== -1)
1604 else if (infoPtr
->iHotDivider
== infoPtr
->uNumItem
)
1605 iNewOrder
= infoPtr
->uNumItem
-1;
1608 iNewOrder
= HEADER_IndexToOrder(infoPtr
, infoPtr
->iHotDivider
);
1609 if (iNewOrder
> lpItem
->iOrder
)
1613 if (iNewOrder
!= -1 &&
1614 !HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_ENDDRAG
, infoPtr
->iMoveItem
, HDI_ORDER
, iNewOrder
))
1616 HEADER_ChangeItemOrder(infoPtr
, infoPtr
->iMoveItem
, iNewOrder
);
1617 infoPtr
->bRectsValid
= FALSE
;
1618 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
1621 InvalidateRect(infoPtr
->hwndSelf
, &infoPtr
->items
[infoPtr
->iMoveItem
].rect
, FALSE
);
1623 infoPtr
->bDragging
= FALSE
;
1624 HEADER_SetHotDivider(infoPtr
, FALSE
, -1);
1626 else if (!(infoPtr
->dwStyle
& HDS_DRAGDROP
) || !HEADER_IsDragDistance(infoPtr
, &pt
))
1628 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1629 hdc
= GetDC (infoPtr
->hwndSelf
);
1630 HEADER_RefreshItem (infoPtr
, infoPtr
->iMoveItem
);
1631 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1633 HEADER_SendNotifyWithHDItemT(infoPtr
, HDN_ITEMCLICKW
, infoPtr
->iMoveItem
, NULL
);
1636 TRACE("Released item %d!\n", infoPtr
->iMoveItem
);
1637 infoPtr
->bPressed
= FALSE
;
1639 else if (infoPtr
->bTracking
) {
1640 INT iNewWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1643 TRACE("End tracking item %d!\n", infoPtr
->iMoveItem
);
1644 infoPtr
->bTracking
= FALSE
;
1646 HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_ENDTRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iNewWidth
);
1648 if (!(infoPtr
->dwStyle
& HDS_FULLDRAG
)) {
1649 hdc
= GetDC (infoPtr
->hwndSelf
);
1650 HEADER_DrawTrackLine (infoPtr
, hdc
, infoPtr
->xOldTrack
);
1651 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1654 if (!HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iNewWidth
))
1656 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= iNewWidth
;
1657 HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iNewWidth
);
1660 HEADER_SetItemBounds (infoPtr
);
1661 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
1664 if (infoPtr
->bCaptured
) {
1665 infoPtr
->bCaptured
= FALSE
;
1667 HEADER_SendSimpleNotify (infoPtr
, NM_RELEASEDCAPTURE
);
1675 HEADER_NotifyFormat (HEADER_INFO
*infoPtr
, WPARAM wParam
, LPARAM lParam
)
1680 return infoPtr
->nNotifyFormat
;
1683 infoPtr
->nNotifyFormat
=
1684 SendMessageW ((HWND
)wParam
, WM_NOTIFYFORMAT
,
1685 (WPARAM
)infoPtr
->hwndSelf
, (LPARAM
)NF_QUERY
);
1686 return infoPtr
->nNotifyFormat
;
1693 HEADER_MouseLeave (HEADER_INFO
*infoPtr
)
1695 /* Reset hot-tracked item when mouse leaves control. */
1696 INT oldHotItem
= infoPtr
->iHotItem
;
1697 HDC hdc
= GetDC (infoPtr
->hwndSelf
);
1699 infoPtr
->iHotItem
= -1;
1700 if (oldHotItem
!= -1) HEADER_RefreshItem (infoPtr
, oldHotItem
);
1701 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1708 HEADER_MouseMove (HEADER_INFO
*infoPtr
, LPARAM lParam
)
1714 /* With theming, hottracking is always enabled */
1715 BOOL hotTrackEnabled
=
1716 ((infoPtr
->dwStyle
& HDS_BUTTONS
) && (infoPtr
->dwStyle
& HDS_HOTTRACK
))
1717 || (GetWindowTheme (infoPtr
->hwndSelf
) != NULL
);
1718 INT oldHotItem
= infoPtr
->iHotItem
;
1720 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1721 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1722 HEADER_InternalHitTest (infoPtr
, &pt
, &flags
, &nItem
);
1724 if (hotTrackEnabled
) {
1725 if (flags
& (HHT_ONHEADER
| HHT_ONDIVIDER
| HHT_ONDIVOPEN
))
1726 infoPtr
->iHotItem
= nItem
;
1728 infoPtr
->iHotItem
= -1;
1731 if (infoPtr
->bCaptured
) {
1732 /* check if we should drag the header */
1733 if (infoPtr
->bPressed
&& !infoPtr
->bDragging
&& (infoPtr
->dwStyle
& HDS_DRAGDROP
)
1734 && HEADER_IsDragDistance(infoPtr
, &pt
))
1736 if (!HEADER_SendNotifyWithHDItemT(infoPtr
, HDN_BEGINDRAG
, infoPtr
->iMoveItem
, NULL
))
1738 HIMAGELIST hDragItem
= (HIMAGELIST
)HEADER_CreateDragImage(infoPtr
, infoPtr
->iMoveItem
);
1739 if (hDragItem
!= NULL
)
1741 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1742 TRACE("Starting item drag\n");
1743 ImageList_BeginDrag(hDragItem
, 0, pt
.x
- lpItem
->rect
.left
, 0);
1744 ImageList_DragShowNolock(TRUE
);
1745 ImageList_Destroy(hDragItem
);
1746 infoPtr
->bDragging
= TRUE
;
1751 if (infoPtr
->bDragging
)
1756 ClientToScreen(infoPtr
->hwndSelf
, &drag
);
1757 ImageList_DragMove(drag
.x
, drag
.y
);
1758 HEADER_SetHotDivider(infoPtr
, TRUE
, lParam
);
1761 if (infoPtr
->bPressed
&& !infoPtr
->bDragging
) {
1762 BOOL oldState
= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
;
1763 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
))
1764 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= TRUE
;
1766 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1767 if (oldState
!= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
) {
1768 hdc
= GetDC (infoPtr
->hwndSelf
);
1769 HEADER_RefreshItem (infoPtr
, infoPtr
->iMoveItem
);
1770 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1773 TRACE("Moving pressed item %d!\n", infoPtr
->iMoveItem
);
1775 else if (infoPtr
->bTracking
) {
1776 if (infoPtr
->dwStyle
& HDS_FULLDRAG
) {
1777 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1778 nWidth
= pt
.x
- lpItem
->rect
.left
+ infoPtr
->xTrackOffset
;
1779 if (!HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, nWidth
))
1781 INT nOldWidth
= lpItem
->rect
.right
- lpItem
->rect
.left
;
1785 if (nWidth
< 0) nWidth
= 0;
1786 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1787 HEADER_SetItemBounds(infoPtr
);
1789 GetClientRect(infoPtr
->hwndSelf
, &rcClient
);
1790 rcScroll
= rcClient
;
1791 rcScroll
.left
= lpItem
->rect
.left
+ nOldWidth
;
1792 ScrollWindowEx(infoPtr
->hwndSelf
, nWidth
- nOldWidth
, 0, &rcScroll
, &rcClient
, NULL
, NULL
, 0);
1793 InvalidateRect(infoPtr
->hwndSelf
, &lpItem
->rect
, FALSE
);
1794 UpdateWindow(infoPtr
->hwndSelf
);
1796 HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, nWidth
);
1801 hdc
= GetDC (infoPtr
->hwndSelf
);
1802 HEADER_DrawTrackLine (infoPtr
, hdc
, infoPtr
->xOldTrack
);
1803 infoPtr
->xOldTrack
= pt
.x
+ infoPtr
->xTrackOffset
;
1804 if (infoPtr
->xOldTrack
< infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
)
1805 infoPtr
->xOldTrack
= infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1806 HEADER_DrawTrackLine (infoPtr
, hdc
, infoPtr
->xOldTrack
);
1807 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1808 iTrackWidth
= infoPtr
->xOldTrack
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1809 /* FIXME: should stop tracking if HDN_TRACK returns TRUE */
1810 HEADER_SendNotifyWithIntFieldT(infoPtr
, HDN_TRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iTrackWidth
);
1813 TRACE("Tracking item %d!\n", infoPtr
->iMoveItem
);
1817 if (hotTrackEnabled
) {
1818 TRACKMOUSEEVENT tme
;
1819 if (oldHotItem
!= infoPtr
->iHotItem
&& !infoPtr
->bDragging
) {
1820 hdc
= GetDC (infoPtr
->hwndSelf
);
1821 if (oldHotItem
!= -1) HEADER_RefreshItem (infoPtr
, oldHotItem
);
1822 if (infoPtr
->iHotItem
!= -1) HEADER_RefreshItem (infoPtr
, infoPtr
->iHotItem
);
1823 ReleaseDC (infoPtr
->hwndSelf
, hdc
);
1825 tme
.cbSize
= sizeof( tme
);
1826 tme
.dwFlags
= TME_LEAVE
;
1827 tme
.hwndTrack
= infoPtr
->hwndSelf
;
1828 TrackMouseEvent( &tme
);
1836 HEADER_Paint (HEADER_INFO
*infoPtr
, HDC hdcParam
)
1841 hdc
= hdcParam
==0 ? BeginPaint (infoPtr
->hwndSelf
, &ps
) : hdcParam
;
1842 HEADER_Refresh (infoPtr
, hdc
);
1844 EndPaint (infoPtr
->hwndSelf
, &ps
);
1850 HEADER_RButtonUp (HEADER_INFO
*infoPtr
, INT x
, INT y
)
1858 /* Send a Notify message */
1859 bRet
= HEADER_SendSimpleNotify (infoPtr
, NM_RCLICK
);
1861 /* Change to screen coordinate for WM_CONTEXTMENU */
1862 ClientToScreen(infoPtr
->hwndSelf
, &pt
);
1864 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1865 SendMessageW( infoPtr
->hwndSelf
, WM_CONTEXTMENU
, (WPARAM
) infoPtr
->hwndSelf
, MAKELPARAM(pt
.x
, pt
.y
));
1872 HEADER_SetCursor (HEADER_INFO
*infoPtr
, LPARAM lParam
)
1878 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam
), HIWORD(lParam
));
1881 ScreenToClient (infoPtr
->hwndSelf
, &pt
);
1883 HEADER_InternalHitTest (infoPtr
, &pt
, &flags
, &nItem
);
1885 if (flags
== HHT_ONDIVIDER
)
1886 SetCursor (infoPtr
->hcurDivider
);
1887 else if (flags
== HHT_ONDIVOPEN
)
1888 SetCursor (infoPtr
->hcurDivopen
);
1890 SetCursor (infoPtr
->hcurArrow
);
1897 HEADER_SetFont (HEADER_INFO
*infoPtr
, HFONT hFont
, WORD Redraw
)
1903 infoPtr
->hFont
= hFont
;
1906 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
));
1907 GetTextMetricsW (hdc
, &tm
);
1908 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1909 SelectObject (hdc
, hOldFont
);
1912 infoPtr
->bRectsValid
= FALSE
;
1915 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
1921 static LRESULT
HEADER_SetRedraw(HEADER_INFO
*infoPtr
, WPARAM wParam
, LPARAM lParam
)
1923 /* ignoring the InvalidateRect calls is handled by user32. But some apps expect
1924 * that we invalidate the header and this has to be done manually */
1927 ret
= DefWindowProcW(infoPtr
->hwndSelf
, WM_SETREDRAW
, wParam
, lParam
);
1929 InvalidateRect(infoPtr
->hwndSelf
, NULL
, TRUE
);
1933 static INT
HEADER_StyleChanged(HEADER_INFO
*infoPtr
, WPARAM wStyleType
,
1934 const STYLESTRUCT
*lpss
)
1936 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
1937 wStyleType
, lpss
->styleOld
, lpss
->styleNew
);
1939 if (wStyleType
!= GWL_STYLE
) return 0;
1941 infoPtr
->dwStyle
= lpss
->styleNew
;
1946 /* Update the theme handle after a theme change */
1947 static LRESULT
HEADER_ThemeChanged(const HEADER_INFO
*infoPtr
)
1949 HTHEME theme
= GetWindowTheme(infoPtr
->hwndSelf
);
1950 CloseThemeData(theme
);
1951 OpenThemeData(infoPtr
->hwndSelf
, themeClass
);
1952 InvalidateRect(infoPtr
->hwndSelf
, NULL
, FALSE
);
1957 static LRESULT WINAPI
1958 HEADER_WindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1960 HEADER_INFO
*infoPtr
= (HEADER_INFO
*)GetWindowLongPtrW(hwnd
, 0);
1962 TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd
, msg
, wParam
, lParam
);
1963 if (!infoPtr
&& (msg
!= WM_CREATE
))
1964 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1966 /* case HDM_CLEARFILTER: */
1968 case HDM_CREATEDRAGIMAGE
:
1969 return HEADER_CreateDragImage (infoPtr
, (INT
)wParam
);
1971 case HDM_DELETEITEM
:
1972 return HEADER_DeleteItem (infoPtr
, (INT
)wParam
);
1974 /* case HDM_EDITFILTER: */
1976 case HDM_GETBITMAPMARGIN
:
1977 return HEADER_GetBitmapMargin(infoPtr
);
1979 case HDM_GETIMAGELIST
:
1980 return HEADER_GetImageList (infoPtr
);
1984 return HEADER_GetItemT (infoPtr
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_GETITEMW
);
1986 case HDM_GETITEMCOUNT
:
1987 return HEADER_GetItemCount (infoPtr
);
1989 case HDM_GETITEMRECT
:
1990 return HEADER_GetItemRect (infoPtr
, (INT
)wParam
, (LPRECT
)lParam
);
1992 case HDM_GETORDERARRAY
:
1993 return HEADER_GetOrderArray(infoPtr
, (INT
)wParam
, (LPINT
)lParam
);
1995 case HDM_GETUNICODEFORMAT
:
1996 return HEADER_GetUnicodeFormat (infoPtr
);
1999 return HEADER_HitTest (infoPtr
, (LPHDHITTESTINFO
)lParam
);
2001 case HDM_INSERTITEMA
:
2002 case HDM_INSERTITEMW
:
2003 return HEADER_InsertItemT (infoPtr
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_INSERTITEMW
);
2006 return HEADER_Layout (infoPtr
, (LPHDLAYOUT
)lParam
);
2008 case HDM_ORDERTOINDEX
:
2009 return HEADER_OrderToIndex(infoPtr
, (INT
)wParam
);
2011 case HDM_SETBITMAPMARGIN
:
2012 return HEADER_SetBitmapMargin(infoPtr
, (INT
)wParam
);
2014 /* case HDM_SETFILTERCHANGETIMEOUT: */
2016 case HDM_SETHOTDIVIDER
:
2017 return HEADER_SetHotDivider(infoPtr
, wParam
, lParam
);
2019 case HDM_SETIMAGELIST
:
2020 return HEADER_SetImageList (infoPtr
, (HIMAGELIST
)lParam
);
2024 return HEADER_SetItemT (infoPtr
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_SETITEMW
);
2026 case HDM_SETORDERARRAY
:
2027 return HEADER_SetOrderArray(infoPtr
, (INT
)wParam
, (LPINT
)lParam
);
2029 case HDM_SETUNICODEFORMAT
:
2030 return HEADER_SetUnicodeFormat (infoPtr
, wParam
);
2033 return HEADER_Create (hwnd
, (LPCREATESTRUCTW
)lParam
);
2036 return HEADER_Destroy (infoPtr
);
2039 return HEADER_NCDestroy (infoPtr
);
2045 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
2048 return HEADER_GetFont (infoPtr
);
2050 case WM_LBUTTONDBLCLK
:
2051 return HEADER_LButtonDblClk (infoPtr
, (SHORT
)LOWORD(lParam
), (SHORT
)HIWORD(lParam
));
2053 case WM_LBUTTONDOWN
:
2054 return HEADER_LButtonDown (infoPtr
, (SHORT
)LOWORD(lParam
), (SHORT
)HIWORD(lParam
));
2057 return HEADER_LButtonUp (infoPtr
, (SHORT
)LOWORD(lParam
), (SHORT
)HIWORD(lParam
));
2060 return HEADER_MouseLeave (infoPtr
);
2063 return HEADER_MouseMove (infoPtr
, lParam
);
2065 case WM_NOTIFYFORMAT
:
2066 return HEADER_NotifyFormat (infoPtr
, wParam
, lParam
);
2069 return HEADER_Size (infoPtr
);
2071 case WM_THEMECHANGED
:
2072 return HEADER_ThemeChanged (infoPtr
);
2074 case WM_PRINTCLIENT
:
2076 return HEADER_Paint (infoPtr
, (HDC
)wParam
);
2079 return HEADER_RButtonUp (infoPtr
, (SHORT
)LOWORD(lParam
), (SHORT
)HIWORD(lParam
));
2082 return HEADER_SetCursor (infoPtr
, lParam
);
2085 return HEADER_SetFont (infoPtr
, (HFONT
)wParam
, (WORD
)lParam
);
2088 return HEADER_SetRedraw(infoPtr
, wParam
, lParam
);
2090 case WM_STYLECHANGED
:
2091 return HEADER_StyleChanged(infoPtr
, wParam
, (LPSTYLESTRUCT
)lParam
);
2093 case WM_SYSCOLORCHANGE
:
2094 COMCTL32_RefreshSysColors();
2098 if ((msg
>= WM_USER
) && (msg
< WM_APP
) && !COMCTL32_IsReflectedMessage(msg
))
2099 ERR("unknown msg %04x wp=%04lx lp=%08lx\n",
2100 msg
, wParam
, lParam
);
2101 return DefWindowProcW(hwnd
, msg
, wParam
, lParam
);
2107 HEADER_Register (void)
2111 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
2112 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
2113 wndClass
.lpfnWndProc
= HEADER_WindowProc
;
2114 wndClass
.cbClsExtra
= 0;
2115 wndClass
.cbWndExtra
= sizeof(HEADER_INFO
*);
2116 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
2117 wndClass
.lpszClassName
= WC_HEADERW
;
2119 RegisterClassW (&wndClass
);
2124 HEADER_Unregister (void)
2126 UnregisterClassW (WC_HEADERW
, NULL
);