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 hwndNotify
; /* Owner window to send notifications to */
68 INT nNotifyFormat
; /* format used for WM_NOTIFY messages */
69 UINT uNumItem
; /* number of items (columns) */
70 INT nHeight
; /* height of the header (pixels) */
71 HFONT hFont
; /* handle to the current font */
72 HCURSOR hcurArrow
; /* handle to the arrow cursor */
73 HCURSOR hcurDivider
; /* handle to a cursor (used over dividers) <-|-> */
74 HCURSOR hcurDivopen
; /* handle to a cursor (used over dividers) <-||-> */
75 BOOL bCaptured
; /* Is the mouse captured? */
76 BOOL bPressed
; /* Is a header item pressed (down)? */
77 BOOL bDragging
; /* Are we dragging an item? */
78 BOOL bTracking
; /* Is in tracking mode? */
79 POINT ptLButtonDown
; /* The point where the left button was pressed */
80 INT iMoveItem
; /* index of tracked item. (Tracking mode) */
81 INT xTrackOffset
; /* distance between the right side of the tracked item and the cursor */
82 INT xOldTrack
; /* track offset (see above) after the last WM_MOUSEMOVE */
83 INT iHotItem
; /* index of hot item (cursor is over this item) */
84 INT iHotDivider
; /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
85 INT iMargin
; /* width of the margin that surrounds a bitmap */
87 HIMAGELIST himl
; /* handle to an image list (may be 0) */
88 HEADER_ITEM
*items
; /* pointer to array of HEADER_ITEM's */
89 INT
*order
; /* array of item IDs indexed by order */
90 BOOL bRectsValid
; /* validity flag for bounding rectangles */
95 #define DIVIDER_WIDTH 10
96 #define HOT_DIVIDER_WIDTH 2
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
);
110 static LRESULT
HEADER_SendNotify(HWND hwnd
, UINT code
, NMHDR
*hdr
);
111 static LRESULT
HEADER_SendCtrlCustomDraw(HWND hwnd
, DWORD dwDrawStage
, HDC hdc
, const RECT
*rect
);
113 static const WCHAR themeClass
[] = {'H','e','a','d','e','r',0};
114 static WCHAR emptyString
[] = {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 LPWSTR pszText
= (phdi
->pszText
!= NULL
? phdi
->pszText
: emptyString
);
151 Str_SetPtrW(&lpItem
->pszText
, pszText
);
153 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)pszText
);
154 lpItem
->callbackMask
&= ~HDI_TEXT
;
158 lpItem
->pszText
= NULL
;
159 lpItem
->callbackMask
|= HDI_TEXT
;
164 static inline LRESULT
165 HEADER_IndexToOrder (HWND hwnd
, INT iItem
)
167 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
168 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
169 return lpItem
->iOrder
;
174 HEADER_OrderToIndex(HWND hwnd
, WPARAM wParam
)
176 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
177 INT iorder
= (INT
)wParam
;
179 if ((iorder
<0) || iorder
>= infoPtr
->uNumItem
)
181 return infoPtr
->order
[iorder
];
185 HEADER_ChangeItemOrder(const HEADER_INFO
*infoPtr
, INT iItem
, INT iNewOrder
)
187 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
190 TRACE("%d: %d->%d\n", iItem
, lpItem
->iOrder
, iNewOrder
);
191 if (lpItem
->iOrder
< iNewOrder
)
193 memmove(&infoPtr
->order
[lpItem
->iOrder
],
194 &infoPtr
->order
[lpItem
->iOrder
+ 1],
195 (iNewOrder
- lpItem
->iOrder
) * sizeof(INT
));
197 if (iNewOrder
< lpItem
->iOrder
)
199 memmove(&infoPtr
->order
[iNewOrder
+ 1],
200 &infoPtr
->order
[iNewOrder
],
201 (lpItem
->iOrder
- iNewOrder
) * sizeof(INT
));
203 infoPtr
->order
[iNewOrder
] = iItem
;
204 nMin
= min(lpItem
->iOrder
, iNewOrder
);
205 nMax
= max(lpItem
->iOrder
, iNewOrder
);
206 for (i
= nMin
; i
<= nMax
; i
++)
207 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= i
;
210 /* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
212 HEADER_NextItem(HWND hwnd
, INT iItem
)
214 return HEADER_OrderToIndex(hwnd
, HEADER_IndexToOrder(hwnd
, iItem
)+1);
218 HEADER_PrevItem(HWND hwnd
, INT iItem
)
220 return HEADER_OrderToIndex(hwnd
, HEADER_IndexToOrder(hwnd
, iItem
)-1);
224 HEADER_SetItemBounds (HWND hwnd
)
226 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
232 infoPtr
->bRectsValid
= TRUE
;
234 if (infoPtr
->uNumItem
== 0)
237 GetClientRect (hwnd
, &rect
);
240 for (i
= 0; i
< infoPtr
->uNumItem
; i
++) {
241 phdi
= &infoPtr
->items
[HEADER_OrderToIndex(hwnd
,i
)];
242 phdi
->rect
.top
= rect
.top
;
243 phdi
->rect
.bottom
= rect
.bottom
;
245 phdi
->rect
.right
= phdi
->rect
.left
+ ((phdi
->cxy
>0)?phdi
->cxy
:0);
246 x
= phdi
->rect
.right
;
251 HEADER_Size (HWND hwnd
, WPARAM wParam
)
253 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
255 infoPtr
->bRectsValid
= FALSE
;
260 static void HEADER_GetHotDividerRect(HWND hwnd
, const HEADER_INFO
*infoPtr
, RECT
*r
)
262 INT iDivider
= infoPtr
->iHotDivider
;
263 if (infoPtr
->uNumItem
> 0)
267 if (iDivider
< infoPtr
->uNumItem
)
269 lpItem
= &infoPtr
->items
[iDivider
];
270 r
->left
= lpItem
->rect
.left
- HOT_DIVIDER_WIDTH
/2;
271 r
->right
= lpItem
->rect
.left
+ HOT_DIVIDER_WIDTH
/2;
275 lpItem
= &infoPtr
->items
[HEADER_OrderToIndex(hwnd
, infoPtr
->uNumItem
-1)];
276 r
->left
= lpItem
->rect
.right
- HOT_DIVIDER_WIDTH
/2;
277 r
->right
= lpItem
->rect
.right
+ HOT_DIVIDER_WIDTH
/2;
279 r
->top
= lpItem
->rect
.top
;
280 r
->bottom
= lpItem
->rect
.bottom
;
285 GetClientRect(hwnd
, &clientRect
);
287 r
->right
= r
->left
+ HOT_DIVIDER_WIDTH
/2;
293 HEADER_DrawItem (HWND hwnd
, HDC hdc
, INT iItem
, BOOL bHotTrack
, LRESULT lCDFlags
)
295 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
296 HEADER_ITEM
*phdi
= &infoPtr
->items
[iItem
];
299 HTHEME theme
= GetWindowTheme (hwnd
);
302 TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem
, bHotTrack
, (infoPtr
->nNotifyFormat
== NFR_UNICODE
));
305 if (r
.right
- r
.left
== 0)
306 return phdi
->rect
.right
;
308 /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
309 SetTextColor(hdc
, (bHotTrack
&& !theme
) ? COLOR_HIGHLIGHT
: COLOR_BTNTEXT
);
310 SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
312 if (lCDFlags
& CDRF_NOTIFYITEMDRAW
&& !(phdi
->fmt
& HDF_OWNERDRAW
))
314 LRESULT lCDItemFlags
;
316 nmcd
.dwDrawStage
= CDDS_PREPAINT
| CDDS_ITEM
;
318 nmcd
.dwItemSpec
= iItem
;
320 nmcd
.uItemState
= phdi
->bDown
? CDIS_SELECTED
: 0;
321 nmcd
.lItemlParam
= phdi
->lParam
;
323 lCDItemFlags
= HEADER_SendNotify(hwnd
, NM_CUSTOMDRAW
, (NMHDR
*)&nmcd
);
324 if (lCDItemFlags
& CDRF_SKIPDEFAULT
)
325 return phdi
->rect
.right
;
329 int state
= (phdi
->bDown
) ? HIS_PRESSED
:
330 (bHotTrack
? HIS_HOT
: HIS_NORMAL
);
331 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, state
,
333 GetThemeBackgroundContentRect (theme
, hdc
, HP_HEADERITEM
, state
,
339 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) {
341 DrawEdge (hdc
, &r
, BDR_RAISEDOUTER
,
342 BF_RECT
| BF_FLAT
| BF_MIDDLE
| BF_ADJUST
);
345 DrawEdge (hdc
, &r
, EDGE_RAISED
,
346 BF_RECT
| BF_SOFT
| BF_MIDDLE
| BF_ADJUST
);
349 DrawEdge (hdc
, &r
, EDGE_ETCHED
, BF_BOTTOM
| BF_RIGHT
| BF_ADJUST
);
351 hbr
= CreateSolidBrush(GetBkColor(hdc
));
352 FillRect(hdc
, &r
, hbr
);
360 if (phdi
->fmt
& HDF_OWNERDRAW
) {
363 dis
.CtlType
= ODT_HEADER
;
364 dis
.CtlID
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
366 dis
.itemAction
= ODA_DRAWENTIRE
;
367 dis
.itemState
= phdi
->bDown
? ODS_SELECTED
: 0;
370 dis
.rcItem
= phdi
->rect
;
371 dis
.itemData
= phdi
->lParam
;
372 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
373 SendMessageW (infoPtr
->hwndNotify
, WM_DRAWITEM
,
374 (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
375 if (oldBkMode
!= TRANSPARENT
)
376 SetBkMode(hdc
, oldBkMode
);
379 UINT rw
, rh
, /* width and height of r */
380 *x
= NULL
, *w
= NULL
; /* x and width of the pic (bmp or img) which is part of cnt */
381 /* cnt,txt,img,bmp */
386 HEADER_PrepareCallbackItems(hwnd
, iItem
, HDI_TEXT
|HDI_IMAGE
);
387 cw
= tw
= iw
= bw
= 0;
388 rw
= r
.right
- r
.left
;
389 rh
= r
.bottom
- r
.top
;
391 if (phdi
->fmt
& HDF_STRING
) {
394 SetRectEmpty(&textRect
);
395 DrawTextW (hdc
, phdi
->pszText
, -1,
396 &textRect
, DT_LEFT
|DT_VCENTER
|DT_SINGLELINE
|DT_CALCRECT
);
397 cw
= textRect
.right
- textRect
.left
+ 2 * infoPtr
->iMargin
;
400 if ((phdi
->fmt
& HDF_IMAGE
) && (infoPtr
->himl
)) {
401 iw
= infoPtr
->himl
->cx
+ 2 * infoPtr
->iMargin
;
406 if ((phdi
->fmt
& HDF_BITMAP
) && (phdi
->hbm
)) {
407 GetObjectW (phdi
->hbm
, sizeof(BITMAP
), (LPVOID
)&bmp
);
408 bw
= bmp
.bmWidth
+ 2 * infoPtr
->iMargin
;
418 /* align cx using the unclipped cw */
419 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_LEFT
)
421 else if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_CENTER
)
422 cx
= r
.left
+ rw
/ 2 - cw
/ 2;
429 if (cx
+ cw
> r
.right
)
432 tx
= cx
+ infoPtr
->iMargin
;
433 /* since cw might have changed we have to recalculate tw */
434 tw
= cw
- infoPtr
->iMargin
* 2;
438 if (phdi
->fmt
& HDF_BITMAP_ON_RIGHT
) {
439 /* put pic behind text */
440 *x
= cx
+ tw
+ infoPtr
->iMargin
* 3;
442 *x
= cx
+ infoPtr
->iMargin
;
443 /* move text behind pic */
449 /* since we're done with the layout we can
450 now calculate the position of bmp which
451 has no influence on alignment and layout
453 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_RIGHT
)
454 bx
= cx
- bw
+ infoPtr
->iMargin
;
456 bx
= cx
+ cw
+ infoPtr
->iMargin
;
460 HDC hClipDC
= GetDC(hwnd
);
461 HRGN hClipRgn
= CreateRectRgn(r
.left
, r
.top
, r
.right
, r
.bottom
);
462 SelectClipRgn(hClipDC
, hClipRgn
);
465 HDC hdcBitmap
= CreateCompatibleDC (hClipDC
);
466 SelectObject (hdcBitmap
, phdi
->hbm
);
467 BitBlt (hClipDC
, bx
, r
.top
+ ((INT
)rh
- bmp
.bmHeight
) / 2,
468 bmp
.bmWidth
, bmp
.bmHeight
, hdcBitmap
, 0, 0, SRCCOPY
);
469 DeleteDC (hdcBitmap
);
473 ImageList_DrawEx (infoPtr
->himl
, phdi
->iImage
, hClipDC
,
474 ix
, r
.top
+ ((INT
)rh
- infoPtr
->himl
->cy
) / 2,
475 infoPtr
->himl
->cx
, infoPtr
->himl
->cy
, CLR_DEFAULT
, CLR_DEFAULT
, 0);
478 DeleteObject(hClipRgn
);
479 ReleaseDC(hwnd
, hClipDC
);
482 if (((phdi
->fmt
& HDF_STRING
)
483 || (!(phdi
->fmt
& (HDF_OWNERDRAW
|HDF_STRING
|HDF_BITMAP
|
484 HDF_BITMAP_ON_RIGHT
|HDF_IMAGE
)))) /* no explicit format specified? */
485 && (phdi
->pszText
)) {
486 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
489 DrawTextW (hdc
, phdi
->pszText
, -1,
490 &r
, DT_LEFT
|DT_END_ELLIPSIS
|DT_VCENTER
|DT_SINGLELINE
);
491 if (oldBkMode
!= TRANSPARENT
)
492 SetBkMode(hdc
, oldBkMode
);
494 HEADER_FreeCallbackItems(phdi
);
497 return phdi
->rect
.right
;
501 HEADER_DrawHotDivider(HWND hwnd
, HDC hdc
)
503 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
507 HEADER_GetHotDividerRect(hwnd
, infoPtr
, &r
);
508 brush
= CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT
));
509 FillRect(hdc
, &r
, brush
);
514 HEADER_Refresh (HWND hwnd
, HDC hdc
)
516 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
517 HFONT hFont
, hOldFont
;
523 HTHEME theme
= GetWindowTheme (hwnd
);
525 if (!infoPtr
->bRectsValid
)
526 HEADER_SetItemBounds(hwnd
);
528 /* get rect for the bar, adjusted for the border */
529 GetClientRect (hwnd
, &rect
);
530 lCDFlags
= HEADER_SendCtrlCustomDraw(hwnd
, CDDS_PREPAINT
, hdc
, &rect
);
532 if (infoPtr
->bDragging
)
533 ImageList_DragShowNolock(FALSE
);
535 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
536 hOldFont
= SelectObject (hdc
, hFont
);
538 /* draw Background */
539 if (infoPtr
->uNumItem
== 0 && theme
== NULL
) {
540 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
541 FillRect(hdc
, &rect
, hbrBk
);
545 for (i
= 0; x
<= rect
.right
&& i
< infoPtr
->uNumItem
; i
++) {
546 int idx
= HEADER_OrderToIndex(hwnd
,i
);
547 if (RectVisible(hdc
, &infoPtr
->items
[idx
].rect
))
548 HEADER_DrawItem(hwnd
, hdc
, idx
, infoPtr
->iHotItem
== idx
, lCDFlags
);
549 x
= infoPtr
->items
[idx
].rect
.right
;
554 if ((x
<= rect
.right
) && RectVisible(hdc
, &rcRest
) && (infoPtr
->uNumItem
> 0)) {
556 DrawThemeBackground(theme
, hdc
, HP_HEADERITEM
, HIS_NORMAL
, &rcRest
, NULL
);
559 if (GetWindowLongW (hwnd
, GWL_STYLE
) & 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(hwnd
, hdc
);
569 if (infoPtr
->bDragging
)
570 ImageList_DragShowNolock(TRUE
);
571 SelectObject (hdc
, hOldFont
);
573 if (lCDFlags
& CDRF_NOTIFYPOSTPAINT
)
574 HEADER_SendCtrlCustomDraw(hwnd
, CDDS_POSTPAINT
, hdc
, &rect
);
579 HEADER_RefreshItem (HWND hwnd
, HDC hdc
, INT iItem
)
581 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
583 if (!infoPtr
->bRectsValid
)
584 HEADER_SetItemBounds(hwnd
);
586 InvalidateRect(hwnd
, &infoPtr
->items
[iItem
].rect
, FALSE
);
591 HEADER_InternalHitTest (HWND hwnd
, const POINT
*lpPt
, UINT
*pFlags
, INT
*pItem
)
593 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
599 GetClientRect (hwnd
, &rect
);
603 if (PtInRect (&rect
, *lpPt
))
605 if (infoPtr
->uNumItem
== 0) {
606 *pFlags
|= HHT_NOWHERE
;
612 /* somewhere inside */
613 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++) {
614 rect
= infoPtr
->items
[iCount
].rect
;
615 width
= rect
.right
- rect
.left
;
620 if (PtInRect (&rect
, *lpPt
)) {
621 if (width
<= 2 * DIVIDER_WIDTH
) {
622 *pFlags
|= HHT_ONHEADER
;
624 TRACE("ON HEADER %d\n", iCount
);
627 if (HEADER_IndexToOrder(hwnd
, iCount
) > 0) {
629 rcTest
.right
= rcTest
.left
+ DIVIDER_WIDTH
;
630 if (PtInRect (&rcTest
, *lpPt
)) {
632 *pFlags
|= HHT_ONDIVOPEN
;
633 *pItem
= HEADER_PrevItem(hwnd
, iCount
);
634 TRACE("ON DIVOPEN %d\n", *pItem
);
638 *pFlags
|= HHT_ONDIVIDER
;
639 *pItem
= HEADER_PrevItem(hwnd
, iCount
);
640 TRACE("ON DIVIDER %d\n", *pItem
);
646 rcTest
.left
= rcTest
.right
- DIVIDER_WIDTH
;
647 if (PtInRect (&rcTest
, *lpPt
)) {
648 *pFlags
|= HHT_ONDIVIDER
;
650 TRACE("ON DIVIDER %d\n", *pItem
);
654 *pFlags
|= HHT_ONHEADER
;
656 TRACE("ON HEADER %d\n", iCount
);
661 /* check for last divider part (on nowhere) */
662 rect
= infoPtr
->items
[infoPtr
->uNumItem
-1].rect
;
663 rect
.left
= rect
.right
;
664 rect
.right
+= DIVIDER_WIDTH
;
665 if (PtInRect (&rect
, *lpPt
)) {
667 *pFlags
|= HHT_ONDIVOPEN
;
668 *pItem
= infoPtr
->uNumItem
- 1;
669 TRACE("ON DIVOPEN %d\n", *pItem
);
673 *pFlags
|= HHT_ONDIVIDER
;
674 *pItem
= infoPtr
->uNumItem
-1;
675 TRACE("ON DIVIDER %d\n", *pItem
);
680 *pFlags
|= HHT_NOWHERE
;
687 if (lpPt
->x
< rect
.left
) {
689 *pFlags
|= HHT_TOLEFT
;
691 else if (lpPt
->x
> rect
.right
) {
693 *pFlags
|= HHT_TORIGHT
;
696 if (lpPt
->y
< rect
.top
) {
698 *pFlags
|= HHT_ABOVE
;
700 else if (lpPt
->y
> rect
.bottom
) {
702 *pFlags
|= HHT_BELOW
;
707 TRACE("flags=0x%X\n", *pFlags
);
713 HEADER_DrawTrackLine (HWND hwnd
, HDC hdc
, INT x
)
719 GetClientRect (hwnd
, &rect
);
721 hOldPen
= SelectObject (hdc
, GetStockObject (BLACK_PEN
));
722 oldRop
= SetROP2 (hdc
, R2_XORPEN
);
723 MoveToEx (hdc
, x
, rect
.top
, NULL
);
724 LineTo (hdc
, x
, rect
.bottom
);
725 SetROP2 (hdc
, oldRop
);
726 SelectObject (hdc
, hOldPen
);
731 * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
734 * [I] infoPtr : the header that wants to send the notify
735 * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
736 * [I] src : The source HDITEM. It may be a HDITEMA or HDITEMW
737 * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
738 * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
739 * the HDITEM is no longer in use or NULL if none was needed
741 * NOTE: We depend on HDITEMA and HDITEMW having the same structure
743 static void HEADER_CopyHDItemForNotify(const HEADER_INFO
*infoPtr
, HDITEMW
*dest
,
744 const HDITEMW
*src
, BOOL fSourceUnicode
, LPVOID
*ppvScratch
)
749 if (src
->mask
& HDI_TEXT
&& src
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers TEXTCALLBACKA as well */
751 if (fSourceUnicode
&& infoPtr
->nNotifyFormat
!= NFR_UNICODE
)
753 dest
->pszText
= NULL
;
754 Str_SetPtrWtoA((LPSTR
*)&dest
->pszText
, src
->pszText
);
755 *ppvScratch
= dest
->pszText
;
758 if (!fSourceUnicode
&& infoPtr
->nNotifyFormat
== NFR_UNICODE
)
760 dest
->pszText
= NULL
;
761 Str_SetPtrAtoW(&dest
->pszText
, (LPSTR
)src
->pszText
);
762 *ppvScratch
= dest
->pszText
;
767 static UINT
HEADER_NotifyCodeWtoA(UINT code
)
769 /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
770 if (code
>= HDN_LAST
&& code
<= HDN_FIRST_UNICODE
)
771 return code
+ HDN_UNICODE_OFFSET
;
777 HEADER_SendNotify(HWND hwnd
, UINT code
, NMHDR
*nmhdr
)
779 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
781 nmhdr
->hwndFrom
= hwnd
;
782 nmhdr
->idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
785 return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
,
786 (WPARAM
)nmhdr
->idFrom
, (LPARAM
)nmhdr
);
790 HEADER_SendSimpleNotify (HWND hwnd
, UINT code
)
793 return (BOOL
)HEADER_SendNotify(hwnd
, code
, &nmhdr
);
797 HEADER_SendCtrlCustomDraw(HWND hwnd
, DWORD dwDrawStage
, HDC hdc
, const RECT
*rect
)
800 nm
.dwDrawStage
= dwDrawStage
;
807 return HEADER_SendNotify(hwnd
, NM_CUSTOMDRAW
, (NMHDR
*)&nm
);
811 HEADER_SendNotifyWithHDItemT(HWND hwnd
, UINT code
, INT iItem
, HDITEMW
*lpItem
)
813 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
816 if (infoPtr
->nNotifyFormat
!= NFR_UNICODE
)
817 code
= HEADER_NotifyCodeWtoA(code
);
820 nmhdr
.pitem
= lpItem
;
822 return (BOOL
)HEADER_SendNotify(hwnd
, code
, (NMHDR
*)&nmhdr
);
826 HEADER_SendNotifyWithIntFieldT(HWND hwnd
, UINT code
, INT iItem
, INT mask
, INT iValue
)
828 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
831 /* copying only the iValue should be ok but to make the code more robust we copy everything */
832 nmitem
.cxy
= infoPtr
->items
[iItem
].cxy
;
833 nmitem
.hbm
= infoPtr
->items
[iItem
].hbm
;
834 nmitem
.pszText
= NULL
;
835 nmitem
.cchTextMax
= 0;
836 nmitem
.fmt
= infoPtr
->items
[iItem
].fmt
;
837 nmitem
.lParam
= infoPtr
->items
[iItem
].lParam
;
838 nmitem
.iOrder
= infoPtr
->items
[iItem
].iOrder
;
839 nmitem
.iImage
= infoPtr
->items
[iItem
].iImage
;
848 nmitem
.iOrder
= iValue
;
851 ERR("invalid mask value 0x%x\n", iValue
);
854 return HEADER_SendNotifyWithHDItemT(hwnd
, code
, iItem
, &nmitem
);
858 * Prepare callback items
859 * depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA
860 * (so we handle the two cases only doing a specific cast for pszText).
861 * Checks if any of the required field are callback. If there are sends a
862 * NMHDISPINFO notify to retrieve these items. The items are stored in the
863 * HEADER_ITEM pszText and iImage fields. They should be freed with
864 * HEADER_FreeCallbackItems.
866 * @param hwnd : hwnd header container handler
867 * @param iItem : the header item id
868 * @param reqMask : required fields. If any of them is callback this function will fetch it
870 * @return TRUE on success, else FALSE
873 HEADER_PrepareCallbackItems(HWND hwnd
, INT iItem
, INT reqMask
)
875 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
876 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
877 DWORD mask
= reqMask
& lpItem
->callbackMask
;
878 NMHDDISPINFOW dispInfo
;
879 void *pvBuffer
= NULL
;
883 if (mask
&HDI_TEXT
&& lpItem
->pszText
!= NULL
)
885 ERR("(): function called without a call to FreeCallbackItems\n");
886 Free(lpItem
->pszText
);
887 lpItem
->pszText
= NULL
;
890 memset(&dispInfo
, 0, sizeof(NMHDDISPINFOW
));
891 dispInfo
.hdr
.hwndFrom
= hwnd
;
892 dispInfo
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
893 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
895 dispInfo
.hdr
.code
= HDN_GETDISPINFOW
;
897 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(WCHAR
));
901 dispInfo
.hdr
.code
= HDN_GETDISPINFOA
;
903 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(CHAR
));
905 dispInfo
.pszText
= (LPWSTR
)pvBuffer
;
906 dispInfo
.cchTextMax
= (pvBuffer
!=NULL
?MAX_HEADER_TEXT_LEN
:0);
907 dispInfo
.iItem
= iItem
;
908 dispInfo
.mask
= mask
;
909 dispInfo
.lParam
= lpItem
->lParam
;
911 TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr
->nNotifyFormat
== NFR_UNICODE
?'W':'A');
912 SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
,
913 (WPARAM
) dispInfo
.hdr
.idFrom
,
916 TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n",
918 (infoPtr
->nNotifyFormat
== NFR_UNICODE
? debugstr_w(dispInfo
.pszText
) : (LPSTR
) dispInfo
.pszText
),
919 (void*) dispInfo
.lParam
);
921 if (mask
& HDI_IMAGE
)
922 lpItem
->iImage
= dispInfo
.iImage
;
925 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
927 lpItem
->pszText
= (LPWSTR
)pvBuffer
;
929 /* the user might have used his own buffer */
930 if (dispInfo
.pszText
!= lpItem
->pszText
)
931 Str_GetPtrW(dispInfo
.pszText
, lpItem
->pszText
, MAX_HEADER_TEXT_LEN
);
935 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)dispInfo
.pszText
);
940 if (dispInfo
.mask
& HDI_DI_SETITEM
)
942 /* make the items permanent */
943 lpItem
->callbackMask
&= ~dispInfo
.mask
;
951 * Free the items that might be allocated with HEADER_PrepareCallbackItems
954 * [I] lpItem : the item to free the data
958 HEADER_FreeCallbackItems(HEADER_ITEM
*lpItem
)
960 if (lpItem
->callbackMask
&HDI_TEXT
)
962 Free(lpItem
->pszText
);
963 lpItem
->pszText
= NULL
;
966 if (lpItem
->callbackMask
&HDI_IMAGE
)
967 lpItem
->iImage
= I_IMAGECALLBACK
;
971 HEADER_CreateDragImage (HWND hwnd
, WPARAM wParam
)
973 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
976 HBITMAP hMemory
, hOldBitmap
;
984 if (wParam
< 0 || wParam
>= infoPtr
->uNumItem
)
987 if (!infoPtr
->bRectsValid
)
988 HEADER_SetItemBounds(hwnd
);
990 lpItem
= &infoPtr
->items
[wParam
];
991 width
= lpItem
->rect
.right
- lpItem
->rect
.left
;
992 height
= lpItem
->rect
.bottom
- lpItem
->rect
.top
;
994 hDeviceDC
= GetDC(NULL
);
995 hMemoryDC
= CreateCompatibleDC(hDeviceDC
);
996 hMemory
= CreateCompatibleBitmap(hDeviceDC
, width
, height
);
997 ReleaseDC(NULL
, hDeviceDC
);
998 hOldBitmap
= SelectObject(hMemoryDC
, hMemory
);
999 SetViewportOrgEx(hMemoryDC
, -lpItem
->rect
.left
, -lpItem
->rect
.top
, NULL
);
1000 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject(SYSTEM_FONT
);
1001 SelectObject(hMemoryDC
, hFont
);
1003 GetClientRect(hwnd
, &rc
);
1004 lCDFlags
= HEADER_SendCtrlCustomDraw(hwnd
, CDDS_PREPAINT
, hMemoryDC
, &rc
);
1005 HEADER_DrawItem(hwnd
, hMemoryDC
, wParam
, FALSE
, lCDFlags
);
1006 if (lCDFlags
& CDRF_NOTIFYPOSTPAINT
)
1007 HEADER_SendCtrlCustomDraw(hwnd
, CDDS_POSTPAINT
, hMemoryDC
, &rc
);
1009 hMemory
= SelectObject(hMemoryDC
, hOldBitmap
);
1010 DeleteDC(hMemoryDC
);
1012 if (hMemory
== NULL
) /* if anything failed */
1015 himl
= ImageList_Create(width
, height
, ILC_COLORDDB
, 1, 1);
1016 ImageList_Add(himl
, hMemory
, NULL
);
1017 DeleteObject(hMemory
);
1018 return (LRESULT
)himl
;
1022 HEADER_SetHotDivider(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1024 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1032 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1034 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &iDivider
);
1036 if (flags
& HHT_TOLEFT
)
1038 else if (flags
& HHT_NOWHERE
|| flags
& HHT_TORIGHT
)
1039 iDivider
= infoPtr
->uNumItem
;
1042 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iDivider
];
1043 if (pt
.x
> (lpItem
->rect
.left
+lpItem
->rect
.right
)/2)
1044 iDivider
= HEADER_NextItem(hwnd
, iDivider
);
1048 iDivider
= (INT
)lParam
;
1050 /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */
1051 if (iDivider
<-1 || iDivider
>(int)infoPtr
->uNumItem
)
1054 if (iDivider
!= infoPtr
->iHotDivider
)
1056 if (infoPtr
->iHotDivider
!= -1)
1058 HEADER_GetHotDividerRect(hwnd
, infoPtr
, &r
);
1059 InvalidateRect(hwnd
, &r
, FALSE
);
1061 infoPtr
->iHotDivider
= iDivider
;
1064 HEADER_GetHotDividerRect(hwnd
, infoPtr
, &r
);
1065 InvalidateRect(hwnd
, &r
, FALSE
);
1072 HEADER_DeleteItem (HWND hwnd
, WPARAM wParam
)
1074 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1075 INT iItem
= (INT
)wParam
;
1079 TRACE("[iItem=%d]\n", iItem
);
1081 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
1084 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1085 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
1087 iOrder
= infoPtr
->items
[iItem
].iOrder
;
1088 Free(infoPtr
->items
[iItem
].pszText
);
1090 infoPtr
->uNumItem
--;
1091 memmove(&infoPtr
->items
[iItem
], &infoPtr
->items
[iItem
+ 1],
1092 (infoPtr
->uNumItem
- iItem
) * sizeof(HEADER_ITEM
));
1093 memmove(&infoPtr
->order
[iOrder
], &infoPtr
->order
[iOrder
+ 1],
1094 (infoPtr
->uNumItem
- iOrder
) * sizeof(INT
));
1095 infoPtr
->items
= ReAlloc(infoPtr
->items
, sizeof(HEADER_ITEM
) * infoPtr
->uNumItem
);
1096 infoPtr
->order
= ReAlloc(infoPtr
->order
, sizeof(INT
) * infoPtr
->uNumItem
);
1098 /* Correct the orders */
1099 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1101 if (infoPtr
->order
[i
] > iItem
)
1102 infoPtr
->order
[i
]--;
1104 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= i
;
1106 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1107 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
1109 HEADER_SetItemBounds (hwnd
);
1110 InvalidateRect(hwnd
, NULL
, FALSE
);
1117 HEADER_GetImageList (HWND hwnd
)
1119 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1121 return (LRESULT
)infoPtr
->himl
;
1126 HEADER_GetItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1128 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1129 HEADER_ITEM
*lpItem
;
1135 TRACE("[nItem=%d]\n", nItem
);
1141 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1144 if (mask
& HDI_UNKNOWN_FIELDS
)
1146 TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask
);
1147 mask
&= HDI_COMCTL32_4_0_FIELDS
;
1150 lpItem
= &infoPtr
->items
[nItem
];
1151 HEADER_PrepareCallbackItems(hwnd
, nItem
, mask
);
1153 if (mask
& HDI_BITMAP
)
1154 phdi
->hbm
= lpItem
->hbm
;
1156 if (mask
& HDI_FORMAT
)
1157 phdi
->fmt
= lpItem
->fmt
;
1159 if (mask
& HDI_WIDTH
)
1160 phdi
->cxy
= lpItem
->cxy
;
1162 if (mask
& HDI_LPARAM
)
1163 phdi
->lParam
= lpItem
->lParam
;
1165 if (mask
& HDI_IMAGE
)
1166 phdi
->iImage
= lpItem
->iImage
;
1168 if (mask
& HDI_ORDER
)
1169 phdi
->iOrder
= lpItem
->iOrder
;
1171 if (mask
& HDI_TEXT
)
1174 Str_GetPtrW (lpItem
->pszText
, phdi
->pszText
, phdi
->cchTextMax
);
1176 Str_GetPtrWtoA (lpItem
->pszText
, (LPSTR
)phdi
->pszText
, phdi
->cchTextMax
);
1179 HEADER_FreeCallbackItems(lpItem
);
1184 static inline LRESULT
1185 HEADER_GetItemCount (HWND hwnd
)
1187 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1188 return infoPtr
->uNumItem
;
1193 HEADER_GetItemRect (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1195 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1196 INT iItem
= (INT
)wParam
;
1197 LPRECT lpRect
= (LPRECT
)lParam
;
1199 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
1202 lpRect
->left
= infoPtr
->items
[iItem
].rect
.left
;
1203 lpRect
->right
= infoPtr
->items
[iItem
].rect
.right
;
1204 lpRect
->top
= infoPtr
->items
[iItem
].rect
.top
;
1205 lpRect
->bottom
= infoPtr
->items
[iItem
].rect
.bottom
;
1212 HEADER_GetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1214 LPINT order
= (LPINT
) lParam
;
1215 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1217 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
1220 memcpy(order
, infoPtr
->order
, infoPtr
->uNumItem
* sizeof(INT
));
1225 HEADER_SetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1228 LPINT order
= (LPINT
) lParam
;
1229 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1230 HEADER_ITEM
*lpItem
;
1232 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
1234 memcpy(infoPtr
->order
, order
, infoPtr
->uNumItem
* sizeof(INT
));
1235 for (i
=0; i
<(int)wParam
; i
++)
1237 lpItem
= &infoPtr
->items
[*order
++];
1240 infoPtr
->bRectsValid
=0;
1241 InvalidateRect(hwnd
, NULL
, FALSE
);
1245 static inline LRESULT
1246 HEADER_GetUnicodeFormat (HWND hwnd
)
1248 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1249 return (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1254 HEADER_HitTest (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1256 LPHDHITTESTINFO phti
= (LPHDHITTESTINFO
)lParam
;
1258 HEADER_InternalHitTest (hwnd
, &phti
->pt
, &phti
->flags
, &phti
->iItem
);
1260 if (phti
->flags
== HHT_NOWHERE
)
1268 HEADER_InsertItemT (HWND hwnd
, INT nItem
, const HDITEMW
*phdi
, BOOL bUnicode
)
1270 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1271 HEADER_ITEM
*lpItem
;
1276 if ((phdi
== NULL
) || (nItem
< 0) || (phdi
->mask
== 0))
1279 if (nItem
> infoPtr
->uNumItem
)
1280 nItem
= infoPtr
->uNumItem
;
1282 iOrder
= (phdi
->mask
& HDI_ORDER
) ? phdi
->iOrder
: nItem
;
1285 else if (infoPtr
->uNumItem
< iOrder
)
1286 iOrder
= infoPtr
->uNumItem
;
1288 infoPtr
->uNumItem
++;
1289 infoPtr
->items
= ReAlloc(infoPtr
->items
, sizeof(HEADER_ITEM
) * infoPtr
->uNumItem
);
1290 infoPtr
->order
= ReAlloc(infoPtr
->order
, sizeof(INT
) * infoPtr
->uNumItem
);
1292 /* make space for the new item */
1293 memmove(&infoPtr
->items
[nItem
+ 1], &infoPtr
->items
[nItem
],
1294 (infoPtr
->uNumItem
- nItem
- 1) * sizeof(HEADER_ITEM
));
1295 memmove(&infoPtr
->order
[iOrder
+ 1], &infoPtr
->order
[iOrder
],
1296 (infoPtr
->uNumItem
- iOrder
- 1) * sizeof(INT
));
1298 /* update the order array */
1299 infoPtr
->order
[iOrder
] = nItem
;
1300 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1302 if (i
!= iOrder
&& infoPtr
->order
[i
] >= nItem
)
1303 infoPtr
->order
[i
]++;
1304 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= i
;
1307 lpItem
= &infoPtr
->items
[nItem
];
1308 ZeroMemory(lpItem
, sizeof(HEADER_ITEM
));
1309 /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
1310 copyMask
= phdi
->mask
| HDI_WIDTH
| HDI_FORMAT
| HDI_LPARAM
;
1311 HEADER_StoreHDItemInHeader(lpItem
, copyMask
, phdi
, bUnicode
);
1312 lpItem
->iOrder
= iOrder
;
1314 /* set automatically some format bits */
1315 if (phdi
->mask
& HDI_TEXT
)
1316 lpItem
->fmt
|= HDF_STRING
;
1318 lpItem
->fmt
&= ~HDF_STRING
;
1320 if (lpItem
->hbm
!= NULL
)
1321 lpItem
->fmt
|= HDF_BITMAP
;
1323 lpItem
->fmt
&= ~HDF_BITMAP
;
1325 if (phdi
->mask
& HDI_IMAGE
)
1326 lpItem
->fmt
|= HDF_IMAGE
;
1328 HEADER_SetItemBounds (hwnd
);
1329 InvalidateRect(hwnd
, NULL
, FALSE
);
1336 HEADER_Layout (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1338 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1339 LPHDLAYOUT lpLayout
= (LPHDLAYOUT
)lParam
;
1341 lpLayout
->pwpos
->hwnd
= hwnd
;
1342 lpLayout
->pwpos
->hwndInsertAfter
= 0;
1343 lpLayout
->pwpos
->x
= lpLayout
->prc
->left
;
1344 lpLayout
->pwpos
->y
= lpLayout
->prc
->top
;
1345 lpLayout
->pwpos
->cx
= lpLayout
->prc
->right
- lpLayout
->prc
->left
;
1346 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_HIDDEN
)
1347 lpLayout
->pwpos
->cy
= 0;
1349 lpLayout
->pwpos
->cy
= infoPtr
->nHeight
;
1350 lpLayout
->prc
->top
+= infoPtr
->nHeight
;
1352 lpLayout
->pwpos
->flags
= SWP_NOZORDER
;
1354 TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1355 lpLayout
->pwpos
->x
, lpLayout
->pwpos
->y
,
1356 lpLayout
->pwpos
->cx
, lpLayout
->pwpos
->cy
);
1358 infoPtr
->bRectsValid
= FALSE
;
1365 HEADER_SetImageList (HWND hwnd
, HIMAGELIST himl
)
1367 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1370 TRACE("(himl %p)\n", himl
);
1371 himlOld
= infoPtr
->himl
;
1372 infoPtr
->himl
= himl
;
1374 /* FIXME: Refresh needed??? */
1376 return (LRESULT
)himlOld
;
1381 HEADER_GetBitmapMargin(HWND hwnd
)
1383 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1385 return infoPtr
->iMargin
;
1389 HEADER_SetBitmapMargin(HWND hwnd
, WPARAM wParam
)
1391 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1392 INT oldMargin
= infoPtr
->iMargin
;
1394 infoPtr
->iMargin
= (INT
)wParam
;
1400 HEADER_SetItemT (HWND hwnd
, INT nItem
, const HDITEMW
*phdi
, BOOL bUnicode
)
1402 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1403 HEADER_ITEM
*lpItem
;
1409 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1412 TRACE("[nItem=%d]\n", nItem
);
1414 HEADER_CopyHDItemForNotify(infoPtr
, &hdNotify
, phdi
, bUnicode
, &pvScratch
);
1415 if (HEADER_SendNotifyWithHDItemT(hwnd
, HDN_ITEMCHANGINGW
, nItem
, &hdNotify
))
1421 lpItem
= &infoPtr
->items
[nItem
];
1422 HEADER_StoreHDItemInHeader(lpItem
, phdi
->mask
, phdi
, bUnicode
);
1424 if (phdi
->mask
& HDI_ORDER
)
1425 if (phdi
->iOrder
>= 0 && phdi
->iOrder
< infoPtr
->uNumItem
)
1426 HEADER_ChangeItemOrder(infoPtr
, nItem
, phdi
->iOrder
);
1428 HEADER_SendNotifyWithHDItemT(hwnd
, HDN_ITEMCHANGEDW
, nItem
, &hdNotify
);
1430 HEADER_SetItemBounds (hwnd
);
1432 InvalidateRect(hwnd
, NULL
, FALSE
);
1438 static inline LRESULT
1439 HEADER_SetUnicodeFormat (HWND hwnd
, WPARAM wParam
)
1441 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1442 BOOL bTemp
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1444 infoPtr
->nNotifyFormat
= ((BOOL
)wParam
? NFR_UNICODE
: NFR_ANSI
);
1451 HEADER_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1453 HEADER_INFO
*infoPtr
;
1458 infoPtr
= (HEADER_INFO
*)Alloc (sizeof(HEADER_INFO
));
1459 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
1461 infoPtr
->hwndNotify
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1462 infoPtr
->uNumItem
= 0;
1466 infoPtr
->bRectsValid
= FALSE
;
1467 infoPtr
->hcurArrow
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1468 infoPtr
->hcurDivider
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDER
));
1469 infoPtr
->hcurDivopen
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDEROPEN
));
1470 infoPtr
->bPressed
= FALSE
;
1471 infoPtr
->bTracking
= FALSE
;
1472 infoPtr
->iMoveItem
= 0;
1474 infoPtr
->iHotItem
= -1;
1475 infoPtr
->iHotDivider
= -1;
1476 infoPtr
->iMargin
= 3*GetSystemMetrics(SM_CXEDGE
);
1477 infoPtr
->nNotifyFormat
=
1478 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
1481 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1482 GetTextMetricsW (hdc
, &tm
);
1483 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1484 SelectObject (hdc
, hOldFont
);
1487 OpenThemeData(hwnd
, themeClass
);
1494 HEADER_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1496 HTHEME theme
= GetWindowTheme(hwnd
);
1497 CloseThemeData(theme
);
1502 HEADER_NCDestroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1504 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1505 HEADER_ITEM
*lpItem
;
1508 if (infoPtr
->items
) {
1509 lpItem
= infoPtr
->items
;
1510 for (nItem
= 0; nItem
< infoPtr
->uNumItem
; nItem
++, lpItem
++) {
1511 Free(lpItem
->pszText
);
1513 Free (infoPtr
->items
);
1516 Free(infoPtr
->order
);
1519 ImageList_Destroy (infoPtr
->himl
);
1521 SetWindowLongPtrW (hwnd
, 0, 0);
1528 static inline LRESULT
1529 HEADER_GetFont (HWND hwnd
)
1531 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1533 return (LRESULT
)infoPtr
->hFont
;
1538 HEADER_IsDragDistance(const HEADER_INFO
*infoPtr
, const POINT
*pt
)
1540 /* Windows allows for a mouse movement before starting the drag. We use the
1541 * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance.
1543 return (abs(infoPtr
->ptLButtonDown
.x
- pt
->x
)>GetSystemMetrics(SM_CXDOUBLECLK
) ||
1544 abs(infoPtr
->ptLButtonDown
.y
- pt
->y
)>GetSystemMetrics(SM_CYDOUBLECLK
));
1548 HEADER_LButtonDblClk (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1554 pt
.x
= (short)LOWORD(lParam
);
1555 pt
.y
= (short)HIWORD(lParam
);
1556 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1558 if ((GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) && (flags
== HHT_ONHEADER
))
1559 HEADER_SendNotifyWithHDItemT(hwnd
, HDN_ITEMDBLCLICKW
, nItem
, NULL
);
1560 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
))
1561 HEADER_SendNotifyWithHDItemT(hwnd
, HDN_DIVIDERDBLCLICKW
, nItem
, NULL
);
1568 HEADER_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1570 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1571 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1577 pt
.x
= (short)LOWORD(lParam
);
1578 pt
.y
= (short)HIWORD(lParam
);
1579 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1581 if ((dwStyle
& HDS_BUTTONS
) && (flags
== HHT_ONHEADER
)) {
1583 infoPtr
->bCaptured
= TRUE
;
1584 infoPtr
->bPressed
= TRUE
;
1585 infoPtr
->bDragging
= FALSE
;
1586 infoPtr
->iMoveItem
= nItem
;
1587 infoPtr
->ptLButtonDown
= pt
;
1589 infoPtr
->items
[nItem
].bDown
= TRUE
;
1591 /* Send WM_CUSTOMDRAW */
1593 HEADER_RefreshItem (hwnd
, hdc
, nItem
);
1594 ReleaseDC (hwnd
, hdc
);
1596 TRACE("Pressed item %d!\n", nItem
);
1598 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
)) {
1599 INT iCurrWidth
= infoPtr
->items
[nItem
].cxy
;
1600 if (!HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_BEGINTRACKW
, nItem
, HDI_WIDTH
, iCurrWidth
))
1603 infoPtr
->bCaptured
= TRUE
;
1604 infoPtr
->bTracking
= TRUE
;
1605 infoPtr
->iMoveItem
= nItem
;
1606 infoPtr
->xTrackOffset
= infoPtr
->items
[nItem
].rect
.right
- pt
.x
;
1608 if (!(dwStyle
& HDS_FULLDRAG
)) {
1609 infoPtr
->xOldTrack
= infoPtr
->items
[nItem
].rect
.right
;
1611 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1612 ReleaseDC (hwnd
, hdc
);
1615 TRACE("Begin tracking item %d!\n", nItem
);
1624 HEADER_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1626 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1627 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1633 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1634 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1635 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1637 if (infoPtr
->bPressed
) {
1638 if (infoPtr
->bDragging
)
1640 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1643 ImageList_DragShowNolock(FALSE
);
1644 ImageList_EndDrag();
1645 lpItem
->bDown
=FALSE
;
1647 if (infoPtr
->iHotDivider
== -1)
1649 else if (infoPtr
->iHotDivider
== infoPtr
->uNumItem
)
1650 iNewOrder
= infoPtr
->uNumItem
-1;
1653 iNewOrder
= HEADER_IndexToOrder(hwnd
, infoPtr
->iHotDivider
);
1654 if (iNewOrder
> lpItem
->iOrder
)
1658 if (iNewOrder
!= -1 &&
1659 !HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_ENDDRAG
, infoPtr
->iMoveItem
, HDI_ORDER
, iNewOrder
))
1661 HEADER_ChangeItemOrder(infoPtr
, infoPtr
->iMoveItem
, iNewOrder
);
1662 infoPtr
->bRectsValid
= FALSE
;
1663 InvalidateRect(hwnd
, NULL
, FALSE
);
1666 InvalidateRect(hwnd
, &infoPtr
->items
[infoPtr
->iMoveItem
].rect
, FALSE
);
1668 HEADER_SetHotDivider(hwnd
, FALSE
, -1);
1670 else if (!(dwStyle
&HDS_DRAGDROP
) || !HEADER_IsDragDistance(infoPtr
, &pt
))
1672 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1674 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1675 ReleaseDC (hwnd
, hdc
);
1677 HEADER_SendNotifyWithHDItemT(hwnd
, HDN_ITEMCLICKW
, infoPtr
->iMoveItem
, NULL
);
1680 TRACE("Released item %d!\n", infoPtr
->iMoveItem
);
1681 infoPtr
->bPressed
= FALSE
;
1683 else if (infoPtr
->bTracking
) {
1684 INT iNewWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1687 TRACE("End tracking item %d!\n", infoPtr
->iMoveItem
);
1688 infoPtr
->bTracking
= FALSE
;
1690 HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_ENDTRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iNewWidth
);
1692 if (!(dwStyle
& HDS_FULLDRAG
)) {
1694 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1695 ReleaseDC (hwnd
, hdc
);
1698 if (!HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iNewWidth
))
1700 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= iNewWidth
;
1701 HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iNewWidth
);
1704 HEADER_SetItemBounds (hwnd
);
1705 InvalidateRect(hwnd
, NULL
, TRUE
);
1708 if (infoPtr
->bCaptured
) {
1709 infoPtr
->bCaptured
= FALSE
;
1711 HEADER_SendSimpleNotify (hwnd
, NM_RELEASEDCAPTURE
);
1719 HEADER_NotifyFormat (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1721 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1726 return infoPtr
->nNotifyFormat
;
1729 infoPtr
->nNotifyFormat
=
1730 SendMessageW ((HWND
)wParam
, WM_NOTIFYFORMAT
,
1731 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
1732 return infoPtr
->nNotifyFormat
;
1739 HEADER_MouseLeave (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1741 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1742 /* Reset hot-tracked item when mouse leaves control. */
1743 INT oldHotItem
= infoPtr
->iHotItem
;
1744 HDC hdc
= GetDC (hwnd
);
1746 infoPtr
->iHotItem
= -1;
1747 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1748 ReleaseDC (hwnd
, hdc
);
1755 HEADER_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1757 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1758 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1763 /* With theming, hottracking is always enabled */
1764 BOOL hotTrackEnabled
=
1765 ((dwStyle
& HDS_BUTTONS
) && (dwStyle
& HDS_HOTTRACK
))
1766 || (GetWindowTheme (hwnd
) != NULL
);
1767 INT oldHotItem
= infoPtr
->iHotItem
;
1769 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1770 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1771 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1773 if (hotTrackEnabled
) {
1774 if (flags
& (HHT_ONHEADER
| HHT_ONDIVIDER
| HHT_ONDIVOPEN
))
1775 infoPtr
->iHotItem
= nItem
;
1777 infoPtr
->iHotItem
= -1;
1780 if (infoPtr
->bCaptured
) {
1781 /* check if we should drag the header */
1782 if (infoPtr
->bPressed
&& !infoPtr
->bDragging
&& dwStyle
&HDS_DRAGDROP
1783 && HEADER_IsDragDistance(infoPtr
, &pt
))
1785 if (!HEADER_SendNotifyWithHDItemT(hwnd
, HDN_BEGINDRAG
, infoPtr
->iMoveItem
, NULL
))
1787 HIMAGELIST hDragItem
= (HIMAGELIST
)HEADER_CreateDragImage(hwnd
, infoPtr
->iMoveItem
);
1788 if (hDragItem
!= NULL
)
1790 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1791 TRACE("Starting item drag\n");
1792 ImageList_BeginDrag(hDragItem
, 0, pt
.x
- lpItem
->rect
.left
, 0);
1793 ImageList_DragShowNolock(TRUE
);
1794 ImageList_Destroy(hDragItem
);
1795 infoPtr
->bDragging
= TRUE
;
1800 if (infoPtr
->bDragging
)
1805 ClientToScreen(hwnd
, &drag
);
1806 ImageList_DragMove(drag
.x
, drag
.y
);
1807 HEADER_SetHotDivider(hwnd
, TRUE
, lParam
);
1810 if (infoPtr
->bPressed
&& !infoPtr
->bDragging
) {
1811 BOOL oldState
= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
;
1812 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
))
1813 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= TRUE
;
1815 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1816 if (oldState
!= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
) {
1818 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1819 ReleaseDC (hwnd
, hdc
);
1822 TRACE("Moving pressed item %d!\n", infoPtr
->iMoveItem
);
1824 else if (infoPtr
->bTracking
) {
1825 if (dwStyle
& HDS_FULLDRAG
) {
1826 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1827 nWidth
= pt
.x
- lpItem
->rect
.left
+ infoPtr
->xTrackOffset
;
1828 if (!HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, nWidth
))
1830 INT nOldWidth
= lpItem
->rect
.right
- lpItem
->rect
.left
;
1834 if (nWidth
< 0) nWidth
= 0;
1835 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1836 HEADER_SetItemBounds(hwnd
);
1838 GetClientRect(hwnd
, &rcClient
);
1839 rcScroll
= rcClient
;
1840 rcScroll
.left
= lpItem
->rect
.left
+ nOldWidth
;
1841 ScrollWindowEx(hwnd
, nWidth
- nOldWidth
, 0, &rcScroll
, &rcClient
, NULL
, NULL
, 0);
1842 InvalidateRect(hwnd
, &lpItem
->rect
, FALSE
);
1845 HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, nWidth
);
1851 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1852 infoPtr
->xOldTrack
= pt
.x
+ infoPtr
->xTrackOffset
;
1853 if (infoPtr
->xOldTrack
< infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
)
1854 infoPtr
->xOldTrack
= infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1855 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1856 ReleaseDC (hwnd
, hdc
);
1857 iTrackWidth
= infoPtr
->xOldTrack
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1858 /* FIXME: should stop tracking if HDN_TRACK returns TRUE */
1859 HEADER_SendNotifyWithIntFieldT(hwnd
, HDN_TRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, iTrackWidth
);
1862 TRACE("Tracking item %d!\n", infoPtr
->iMoveItem
);
1866 if (hotTrackEnabled
) {
1867 TRACKMOUSEEVENT tme
;
1868 if (oldHotItem
!= infoPtr
->iHotItem
&& !infoPtr
->bDragging
) {
1870 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1871 if (infoPtr
->iHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iHotItem
);
1872 ReleaseDC (hwnd
, hdc
);
1874 tme
.cbSize
= sizeof( tme
);
1875 tme
.dwFlags
= TME_LEAVE
;
1876 tme
.hwndTrack
= hwnd
;
1877 TrackMouseEvent( &tme
);
1885 HEADER_Paint (HWND hwnd
, WPARAM wParam
)
1890 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1891 HEADER_Refresh (hwnd
, hdc
);
1893 EndPaint (hwnd
, &ps
);
1899 HEADER_RButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1904 pt
.x
= (short)LOWORD(lParam
);
1905 pt
.y
= (short)HIWORD(lParam
);
1907 /* Send a Notify message */
1908 bRet
= HEADER_SendSimpleNotify (hwnd
, NM_RCLICK
);
1910 /* Change to screen coordinate for WM_CONTEXTMENU */
1911 ClientToScreen(hwnd
, &pt
);
1913 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1914 SendMessageW( hwnd
, WM_CONTEXTMENU
, (WPARAM
) hwnd
, MAKELPARAM(pt
.x
, pt
.y
));
1921 HEADER_SetCursor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1923 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1928 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam
), HIWORD(lParam
));
1931 ScreenToClient (hwnd
, &pt
);
1933 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1935 if (flags
== HHT_ONDIVIDER
)
1936 SetCursor (infoPtr
->hcurDivider
);
1937 else if (flags
== HHT_ONDIVOPEN
)
1938 SetCursor (infoPtr
->hcurDivopen
);
1940 SetCursor (infoPtr
->hcurArrow
);
1947 HEADER_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1949 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1951 HFONT hFont
, hOldFont
;
1954 infoPtr
->hFont
= (HFONT
)wParam
;
1956 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
1959 hOldFont
= SelectObject (hdc
, hFont
);
1960 GetTextMetricsW (hdc
, &tm
);
1961 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1962 SelectObject (hdc
, hOldFont
);
1965 infoPtr
->bRectsValid
= FALSE
;
1968 InvalidateRect(hwnd
, NULL
, FALSE
);
1974 static LRESULT
HEADER_SetRedraw(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1976 /* ignoring the InvalidateRect calls is handled by user32. But some apps expect
1977 * that we invalidate the header and this has to be done manually */
1980 ret
= DefWindowProcW(hwnd
, WM_SETREDRAW
, wParam
, lParam
);
1982 InvalidateRect(hwnd
, NULL
, TRUE
);
1986 /* Update the theme handle after a theme change */
1987 static LRESULT
HEADER_ThemeChanged(HWND hwnd
)
1989 HTHEME theme
= GetWindowTheme(hwnd
);
1990 CloseThemeData(theme
);
1991 OpenThemeData(hwnd
, themeClass
);
1992 InvalidateRect(hwnd
, NULL
, FALSE
);
1997 static LRESULT WINAPI
1998 HEADER_WindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2000 TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd
, msg
, wParam
, lParam
);
2001 if (!HEADER_GetInfoPtr (hwnd
) && (msg
!= WM_CREATE
))
2002 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
2004 /* case HDM_CLEARFILTER: */
2006 case HDM_CREATEDRAGIMAGE
:
2007 return HEADER_CreateDragImage (hwnd
, wParam
);
2009 case HDM_DELETEITEM
:
2010 return HEADER_DeleteItem (hwnd
, wParam
);
2012 /* case HDM_EDITFILTER: */
2014 case HDM_GETBITMAPMARGIN
:
2015 return HEADER_GetBitmapMargin(hwnd
);
2017 case HDM_GETIMAGELIST
:
2018 return HEADER_GetImageList (hwnd
);
2022 return HEADER_GetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_GETITEMW
);
2024 case HDM_GETITEMCOUNT
:
2025 return HEADER_GetItemCount (hwnd
);
2027 case HDM_GETITEMRECT
:
2028 return HEADER_GetItemRect (hwnd
, wParam
, lParam
);
2030 case HDM_GETORDERARRAY
:
2031 return HEADER_GetOrderArray(hwnd
, wParam
, lParam
);
2033 case HDM_GETUNICODEFORMAT
:
2034 return HEADER_GetUnicodeFormat (hwnd
);
2037 return HEADER_HitTest (hwnd
, wParam
, lParam
);
2039 case HDM_INSERTITEMA
:
2040 case HDM_INSERTITEMW
:
2041 return HEADER_InsertItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_INSERTITEMW
);
2044 return HEADER_Layout (hwnd
, wParam
, lParam
);
2046 case HDM_ORDERTOINDEX
:
2047 return HEADER_OrderToIndex(hwnd
, wParam
);
2049 case HDM_SETBITMAPMARGIN
:
2050 return HEADER_SetBitmapMargin(hwnd
, wParam
);
2052 /* case HDM_SETFILTERCHANGETIMEOUT: */
2054 case HDM_SETHOTDIVIDER
:
2055 return HEADER_SetHotDivider(hwnd
, wParam
, lParam
);
2057 case HDM_SETIMAGELIST
:
2058 return HEADER_SetImageList (hwnd
, (HIMAGELIST
)lParam
);
2062 return HEADER_SetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_SETITEMW
);
2064 case HDM_SETORDERARRAY
:
2065 return HEADER_SetOrderArray(hwnd
, wParam
, lParam
);
2067 case HDM_SETUNICODEFORMAT
:
2068 return HEADER_SetUnicodeFormat (hwnd
, wParam
);
2071 return HEADER_Create (hwnd
, wParam
, lParam
);
2074 return HEADER_Destroy (hwnd
, wParam
, lParam
);
2077 return HEADER_NCDestroy (hwnd
, wParam
, lParam
);
2083 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
2086 return HEADER_GetFont (hwnd
);
2088 case WM_LBUTTONDBLCLK
:
2089 return HEADER_LButtonDblClk (hwnd
, wParam
, lParam
);
2091 case WM_LBUTTONDOWN
:
2092 return HEADER_LButtonDown (hwnd
, wParam
, lParam
);
2095 return HEADER_LButtonUp (hwnd
, wParam
, lParam
);
2098 return HEADER_MouseLeave (hwnd
, wParam
, lParam
);
2101 return HEADER_MouseMove (hwnd
, wParam
, lParam
);
2103 case WM_NOTIFYFORMAT
:
2104 return HEADER_NotifyFormat (hwnd
, wParam
, lParam
);
2107 return HEADER_Size (hwnd
, wParam
);
2109 case WM_THEMECHANGED
:
2110 return HEADER_ThemeChanged (hwnd
);
2112 case WM_PRINTCLIENT
:
2114 return HEADER_Paint (hwnd
, wParam
);
2117 return HEADER_RButtonUp (hwnd
, wParam
, lParam
);
2120 return HEADER_SetCursor (hwnd
, wParam
, lParam
);
2123 return HEADER_SetFont (hwnd
, wParam
, lParam
);
2126 return HEADER_SetRedraw(hwnd
, wParam
, lParam
);
2129 if ((msg
>= WM_USER
) && (msg
< WM_APP
))
2130 ERR("unknown msg %04x wp=%04lx lp=%08lx\n",
2131 msg
, wParam
, lParam
);
2132 return DefWindowProcW(hwnd
, msg
, wParam
, lParam
);
2138 HEADER_Register (void)
2142 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
2143 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
2144 wndClass
.lpfnWndProc
= HEADER_WindowProc
;
2145 wndClass
.cbClsExtra
= 0;
2146 wndClass
.cbWndExtra
= sizeof(HEADER_INFO
*);
2147 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
2148 wndClass
.lpszClassName
= WC_HEADERW
;
2150 RegisterClassW (&wndClass
);
2155 HEADER_Unregister (void)
2157 UnregisterClassW (WC_HEADERW
, NULL
);