4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Eric Kohl for CodeWeavers
6 * Copyright 2003 Maxime Bellenge
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * - Imagelist support (partially).
24 * - Callback items (under construction).
25 * - Hottrack support (partially).
26 * - Custom draw support (including Notifications).
27 * - Drag and Drop support (including Notifications).
29 * - Use notification format
30 * - Correct the order maintenance code to preserve valid order
39 #include "wine/unicode.h"
45 #include "imagelist.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(header
);
60 INT iOrder
; /* see documentation of HD_ITEM */
62 BOOL bDown
; /* is item pressed? (used for drawing) */
63 RECT rect
; /* bounding rectangle of the item */
69 HWND hwndNotify
; /* Owner window to send notifications to */
70 INT nNotifyFormat
; /* format used for WM_NOTIFY messages */
71 UINT uNumItem
; /* number of items (columns) */
72 INT nHeight
; /* height of the header (pixels) */
73 HFONT hFont
; /* handle to the current font */
74 HCURSOR hcurArrow
; /* handle to the arrow cursor */
75 HCURSOR hcurDivider
; /* handle to a cursor (used over dividers) <-|-> */
76 HCURSOR hcurDivopen
; /* handle to a cursor (used over dividers) <-||-> */
77 BOOL bCaptured
; /* Is the mouse captured? */
78 BOOL bPressed
; /* Is a header item pressed (down)? */
79 BOOL bTracking
; /* Is in tracking mode? */
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 nOldWidth
; /* width of a sizing item after the last WM_MOUSEMOVE */
84 INT iHotItem
; /* index of hot item (cursor is over this item) */
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 HDN_UNICODE_OFFSET 20
97 #define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
99 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0))
101 static const WCHAR themeClass
[] = {'H','e','a','d','e','r',0};
104 inline static LRESULT
105 HEADER_IndexToOrder (HWND hwnd
, INT iItem
)
107 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
108 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
109 return lpItem
->iOrder
;
114 HEADER_OrderToIndex(HWND hwnd
, WPARAM wParam
)
116 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
117 INT iorder
= (INT
)wParam
;
119 if ((iorder
<0) || iorder
>= infoPtr
->uNumItem
)
121 return infoPtr
->order
[iorder
];
125 HEADER_SetItemBounds (HWND hwnd
)
127 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
133 infoPtr
->bRectsValid
= TRUE
;
135 if (infoPtr
->uNumItem
== 0)
138 GetClientRect (hwnd
, &rect
);
141 for (i
= 0; i
< infoPtr
->uNumItem
; i
++) {
142 phdi
= &infoPtr
->items
[HEADER_OrderToIndex(hwnd
,i
)];
143 phdi
->rect
.top
= rect
.top
;
144 phdi
->rect
.bottom
= rect
.bottom
;
146 phdi
->rect
.right
= phdi
->rect
.left
+ ((phdi
->cxy
>0)?phdi
->cxy
:0);
147 x
= phdi
->rect
.right
;
152 HEADER_Size (HWND hwnd
, WPARAM wParam
)
154 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
156 infoPtr
->bRectsValid
= FALSE
;
163 HEADER_DrawItem (HWND hwnd
, HDC hdc
, INT iItem
, BOOL bHotTrack
)
165 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
166 HEADER_ITEM
*phdi
= &infoPtr
->items
[iItem
];
168 INT oldBkMode
, cxEdge
= GetSystemMetrics(SM_CXEDGE
);
169 HTHEME theme
= GetWindowTheme (hwnd
);
172 TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem
, bHotTrack
, (infoPtr
->nNotifyFormat
== NFR_UNICODE
));
174 if (!infoPtr
->bRectsValid
)
175 HEADER_SetItemBounds(hwnd
);
178 if (r
.right
- r
.left
== 0)
179 return phdi
->rect
.right
;
182 int state
= (phdi
->bDown
) ? HIS_PRESSED
:
183 (bHotTrack
? HIS_HOT
: HIS_NORMAL
);
184 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, state
,
186 GetThemeBackgroundContentRect (theme
, hdc
, HP_HEADERITEM
, state
,
190 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) {
192 DrawEdge (hdc
, &r
, BDR_RAISEDOUTER
,
193 BF_RECT
| BF_FLAT
| BF_MIDDLE
| BF_ADJUST
);
196 DrawEdge (hdc
, &r
, EDGE_RAISED
,
197 BF_RECT
| BF_SOFT
| BF_MIDDLE
| BF_ADJUST
);
200 DrawEdge (hdc
, &r
, EDGE_ETCHED
, BF_BOTTOM
| BF_RIGHT
| BF_ADJUST
);
210 /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
211 SetTextColor (hdc
, (bHotTrack
&& !theme
) ? COLOR_HIGHLIGHT
: COLOR_BTNTEXT
);
212 SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
214 nmcd
.hdr
.hwndFrom
= hwnd
;
215 nmcd
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
216 nmcd
.hdr
.code
= NM_CUSTOMDRAW
;
217 nmcd
.dwDrawStage
= CDDS_PREPAINT
| CDDS_ITEM
| CDDS_ITEMPOSTERASE
;
219 nmcd
.dwItemSpec
= iItem
;
221 nmcd
.uItemState
= phdi
->bDown
? CDIS_SELECTED
: 0;
222 nmcd
.lItemlParam
= phdi
->lParam
;
224 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
, nmcd
.hdr
.idFrom
, (LPARAM
)&nmcd
);
226 if (phdi
->fmt
& HDF_OWNERDRAW
) {
229 dis
.CtlType
= ODT_HEADER
;
230 dis
.CtlID
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
232 dis
.itemAction
= ODA_DRAWENTIRE
;
233 dis
.itemState
= phdi
->bDown
? ODS_SELECTED
: 0;
237 dis
.itemData
= phdi
->lParam
;
238 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
239 SendMessageW (infoPtr
->hwndNotify
, WM_DRAWITEM
,
240 (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
241 if (oldBkMode
!= TRANSPARENT
)
242 SetBkMode(hdc
, oldBkMode
);
245 UINT rw
, rh
, /* width and height of r */
246 *x
= NULL
, *w
= NULL
; /* x and width of the pic (bmp or img) which is part of cnt */
247 /* cnt,txt,img,bmp */
252 cw
= tw
= iw
= bw
= 0;
253 rw
= r
.right
- r
.left
;
254 rh
= r
.bottom
- r
.top
;
257 HBRUSH hbr
= CreateSolidBrush(GetBkColor(hdc
));
258 RECT rcBackground
= r
;
260 rcBackground
.right
-= cxEdge
;
261 FillRect(hdc
, &rcBackground
, hbr
);
264 if (phdi
->fmt
& HDF_STRING
) {
267 DrawTextW (hdc
, phdi
->pszText
, -1,
268 &textRect
, DT_LEFT
|DT_VCENTER
|DT_SINGLELINE
|DT_CALCRECT
);
269 cw
= textRect
.right
- textRect
.left
+ 2 * infoPtr
->iMargin
;
272 if ((phdi
->fmt
& HDF_IMAGE
) && (infoPtr
->himl
)) {
273 iw
= infoPtr
->himl
->cx
+ 2 * infoPtr
->iMargin
;
278 if ((phdi
->fmt
& HDF_BITMAP
) && (phdi
->hbm
)) {
279 GetObjectW (phdi
->hbm
, sizeof(BITMAP
), (LPVOID
)&bmp
);
280 bw
= bmp
.bmWidth
+ 2 * infoPtr
->iMargin
;
290 /* align cx using the unclipped cw */
291 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_LEFT
)
293 else if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_CENTER
)
294 cx
= r
.left
+ rw
/ 2 - cw
/ 2;
301 if (cx
+ cw
> r
.right
)
304 tx
= cx
+ infoPtr
->iMargin
;
305 /* since cw might have changed we have to recalculate tw */
306 tw
= cw
- infoPtr
->iMargin
* 2;
310 if (phdi
->fmt
& HDF_BITMAP_ON_RIGHT
) {
311 /* put pic behind text */
312 *x
= cx
+ tw
+ infoPtr
->iMargin
* 3;
314 *x
= cx
+ infoPtr
->iMargin
;
315 /* move text behind pic */
321 /* since we're done with the layout we can
322 now calculate the position of bmp which
323 has no influence on alignment and layout
325 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_RIGHT
)
326 bx
= cx
- bw
+ infoPtr
->iMargin
;
328 bx
= cx
+ cw
+ infoPtr
->iMargin
;
332 HDC hClipDC
= GetDC(hwnd
);
333 HRGN hClipRgn
= CreateRectRgn(r
.left
, r
.top
, r
.right
, r
.bottom
);
334 SelectClipRgn(hClipDC
, hClipRgn
);
337 HDC hdcBitmap
= CreateCompatibleDC (hClipDC
);
338 SelectObject (hdcBitmap
, phdi
->hbm
);
339 BitBlt (hClipDC
, bx
, r
.top
+ ((INT
)rh
- bmp
.bmHeight
) / 2,
340 bmp
.bmWidth
, bmp
.bmHeight
, hdcBitmap
, 0, 0, SRCCOPY
);
341 DeleteDC (hdcBitmap
);
345 ImageList_DrawEx (infoPtr
->himl
, phdi
->iImage
, hClipDC
,
346 ix
, r
.top
+ ((INT
)rh
- infoPtr
->himl
->cy
) / 2,
347 infoPtr
->himl
->cx
, infoPtr
->himl
->cy
, CLR_DEFAULT
, CLR_DEFAULT
, 0);
350 DeleteObject(hClipRgn
);
351 ReleaseDC(hwnd
, hClipDC
);
354 if (((phdi
->fmt
& HDF_STRING
)
355 || (!(phdi
->fmt
& (HDF_OWNERDRAW
|HDF_STRING
|HDF_BITMAP
|
356 HDF_BITMAP_ON_RIGHT
|HDF_IMAGE
)))) /* no explicit format specified? */
357 && (phdi
->pszText
)) {
358 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
361 DrawTextW (hdc
, phdi
->pszText
, -1,
362 &r
, DT_LEFT
|DT_END_ELLIPSIS
|DT_VCENTER
|DT_SINGLELINE
);
363 if (oldBkMode
!= TRANSPARENT
)
364 SetBkMode(hdc
, oldBkMode
);
368 return phdi
->rect
.right
;
373 HEADER_Refresh (HWND hwnd
, HDC hdc
)
375 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
376 HFONT hFont
, hOldFont
;
381 HTHEME theme
= GetWindowTheme (hwnd
);
383 /* get rect for the bar, adjusted for the border */
384 GetClientRect (hwnd
, &rect
);
386 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
387 hOldFont
= SelectObject (hdc
, hFont
);
389 /* draw Background */
391 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
392 FillRect(hdc
, &rect
, hbrBk
);
396 for (i
= 0; x
<= rect
.right
&& i
< infoPtr
->uNumItem
; i
++) {
397 x
= HEADER_DrawItem (hwnd
, hdc
, HEADER_OrderToIndex(hwnd
,i
),
398 infoPtr
->iHotItem
== i
);
401 if ((x
<= rect
.right
) && (infoPtr
->uNumItem
> 0)) {
404 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, HIS_NORMAL
, &rect
,
408 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
)
409 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_TOP
|BF_LEFT
|BF_BOTTOM
|BF_SOFT
);
411 DrawEdge (hdc
, &rect
, EDGE_ETCHED
, BF_BOTTOM
);
415 SelectObject (hdc
, hOldFont
);
420 HEADER_RefreshItem (HWND hwnd
, HDC hdc
, INT iItem
)
422 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
423 HFONT hFont
, hOldFont
;
425 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
426 hOldFont
= SelectObject (hdc
, hFont
);
427 HEADER_DrawItem (hwnd
, hdc
, iItem
, infoPtr
->iHotItem
== iItem
);
428 SelectObject (hdc
, hOldFont
);
433 HEADER_InternalHitTest (HWND hwnd
, LPPOINT lpPt
, UINT
*pFlags
, INT
*pItem
)
435 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
441 GetClientRect (hwnd
, &rect
);
445 if (PtInRect (&rect
, *lpPt
))
447 if (infoPtr
->uNumItem
== 0) {
448 *pFlags
|= HHT_NOWHERE
;
454 /* somewhere inside */
455 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++) {
456 rect
= infoPtr
->items
[iCount
].rect
;
457 width
= rect
.right
- rect
.left
;
462 if (PtInRect (&rect
, *lpPt
)) {
463 if (width
<= 2 * DIVIDER_WIDTH
) {
464 *pFlags
|= HHT_ONHEADER
;
466 TRACE("ON HEADER %d\n", iCount
);
471 rcTest
.right
= rcTest
.left
+ DIVIDER_WIDTH
;
472 if (PtInRect (&rcTest
, *lpPt
)) {
474 *pFlags
|= HHT_ONDIVOPEN
;
476 TRACE("ON DIVOPEN %d\n", *pItem
);
480 *pFlags
|= HHT_ONDIVIDER
;
482 TRACE("ON DIVIDER %d\n", *pItem
);
488 rcTest
.left
= rcTest
.right
- DIVIDER_WIDTH
;
489 if (PtInRect (&rcTest
, *lpPt
)) {
490 *pFlags
|= HHT_ONDIVIDER
;
492 TRACE("ON DIVIDER %d\n", *pItem
);
496 *pFlags
|= HHT_ONHEADER
;
498 TRACE("ON HEADER %d\n", iCount
);
503 /* check for last divider part (on nowhere) */
504 rect
= infoPtr
->items
[infoPtr
->uNumItem
-1].rect
;
505 rect
.left
= rect
.right
;
506 rect
.right
+= DIVIDER_WIDTH
;
507 if (PtInRect (&rect
, *lpPt
)) {
509 *pFlags
|= HHT_ONDIVOPEN
;
510 *pItem
= infoPtr
->uNumItem
- 1;
511 TRACE("ON DIVOPEN %d\n", *pItem
);
515 *pFlags
|= HHT_ONDIVIDER
;
516 *pItem
= infoPtr
->uNumItem
-1;
517 TRACE("ON DIVIDER %d\n", *pItem
);
522 *pFlags
|= HHT_NOWHERE
;
529 if (lpPt
->x
< rect
.left
) {
531 *pFlags
|= HHT_TOLEFT
;
533 else if (lpPt
->x
> rect
.right
) {
535 *pFlags
|= HHT_TORIGHT
;
538 if (lpPt
->y
< rect
.top
) {
540 *pFlags
|= HHT_ABOVE
;
542 else if (lpPt
->y
> rect
.bottom
) {
544 *pFlags
|= HHT_BELOW
;
549 TRACE("flags=0x%X\n", *pFlags
);
555 HEADER_DrawTrackLine (HWND hwnd
, HDC hdc
, INT x
)
561 GetClientRect (hwnd
, &rect
);
563 hOldPen
= SelectObject (hdc
, GetStockObject (BLACK_PEN
));
564 oldRop
= SetROP2 (hdc
, R2_XORPEN
);
565 MoveToEx (hdc
, x
, rect
.top
, NULL
);
566 LineTo (hdc
, x
, rect
.bottom
);
567 SetROP2 (hdc
, oldRop
);
568 SelectObject (hdc
, hOldPen
);
573 * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
576 * [I] infoPtr : the header that wants to send the notify
577 * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
578 * [I] src : The source HDITEM. It may be a HDITEMA or HDITEMW
579 * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
580 * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
581 * the HDITEM is no longer in use or NULL if none was needed
583 * NOTE: We depend on HDITEMA and HDITEMW having the same structure
585 static void HEADER_CopyHDItemForNotify(HEADER_INFO
*infoPtr
, HDITEMW
*dest
,
586 HDITEMW
*src
, BOOL fSourceUnicode
, LPVOID
*ppvScratch
)
591 if (src
->mask
& HDI_TEXT
&& src
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers TEXTCALLBACKA as well */
593 if (fSourceUnicode
&& infoPtr
->nNotifyFormat
!= NFR_UNICODE
)
595 dest
->pszText
= NULL
;
596 Str_SetPtrWtoA((LPSTR
*)&dest
->pszText
, src
->pszText
);
597 *ppvScratch
= dest
->pszText
;
600 if (!fSourceUnicode
&& infoPtr
->nNotifyFormat
== NFR_UNICODE
)
602 dest
->pszText
= NULL
;
603 Str_SetPtrAtoW(&dest
->pszText
, (LPSTR
)src
->pszText
);
604 *ppvScratch
= dest
->pszText
;
609 static UINT
HEADER_NotifyCodeWtoA(UINT code
)
611 /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
612 if (code
>= HDN_LAST
&& code
<= HDN_FIRST_UNICODE
)
613 return code
+ HDN_UNICODE_OFFSET
;
619 HEADER_SendSimpleNotify (HWND hwnd
, UINT code
)
621 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
624 nmhdr
.hwndFrom
= hwnd
;
625 nmhdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
628 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
629 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
633 HEADER_SendHeaderNotifyT (HWND hwnd
, UINT code
, INT iItem
, INT mask
, HDITEMW
*lpItem
)
635 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
641 /* lpItem == NULL means that we should take the actual data from the item */
644 FIXME("(): invalid parameters - lpItem == NULL and (mask & HDI_TEXT)\n");
648 nmitem
.cxy
= infoPtr
->items
[iItem
].cxy
;
649 nmitem
.hbm
= infoPtr
->items
[iItem
].hbm
;
650 nmitem
.pszText
= NULL
;
651 nmitem
.cchTextMax
= 0;
652 nmitem
.fmt
= infoPtr
->items
[iItem
].fmt
;
653 nmitem
.lParam
= infoPtr
->items
[iItem
].lParam
;
654 nmitem
.iOrder
= infoPtr
->items
[iItem
].iOrder
;
655 nmitem
.iImage
= infoPtr
->items
[iItem
].iImage
;
659 nmhdr
.hdr
.hwndFrom
= hwnd
;
660 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
661 nmhdr
.hdr
.code
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
? code
: HEADER_NotifyCodeWtoA(code
));
664 nmhdr
.pitem
= lpItem
;
666 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
667 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
671 * Send Disp Info notification.
672 * depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA
673 * (so we handle the two cases only doing a specific cast for pszText).
675 * @param hwnd : hwnd header container handler
676 * @param mask : notification mask (usually HDI_TEXT or HDI_IMAGE)
677 * @param pDispInfo : NMHDDISPINFO structure (can be unicode or ansi)
678 * @param isW : TRUE if dispinfo is Unicode
681 HEADER_SendHeaderDispInfoNotify(HWND hwnd
, INT iItem
, INT mask
, LPHDITEMW phdi
, HEADER_ITEM
* lpItem
, BOOL isW
)
683 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
685 BOOL convertToAnsi
= FALSE
;
686 BOOL convertToUnicode
= FALSE
;
687 BOOL isUnicodeNotify
= FALSE
;
688 NMHDDISPINFOW dispInfo
;
692 convertToAnsi
= (isW
&& infoPtr
->nNotifyFormat
== NFR_ANSI
);
693 convertToUnicode
= (!isW
&& infoPtr
->nNotifyFormat
== NFR_UNICODE
);
695 isUnicodeNotify
= (isW
&& !convertToAnsi
);
697 memset(&dispInfo
, 0, sizeof(NMHDDISPINFOW
));
698 dispInfo
.hdr
.hwndFrom
= hwnd
;
699 dispInfo
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
700 if (isUnicodeNotify
|| convertToUnicode
)
702 dispInfo
.hdr
.code
= HDN_GETDISPINFOW
;
706 dispInfo
.hdr
.code
= HDN_GETDISPINFOA
;
708 dispInfo
.iItem
= iItem
;
709 dispInfo
.mask
= mask
;
711 dispInfo.pszText = Alloc(sizeof(WCHAR) * 260);
712 dispInfo.cchTextMax = 260;
714 ret
= (BOOL
) SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
,
715 (WPARAM
) dispInfo
.hdr
.idFrom
,
718 TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n",
720 (isUnicodeNotify
? debugstr_w(dispInfo
.pszText
) : (LPSTR
) dispInfo
.pszText
),
721 (void*) dispInfo
.lParam
);
723 if (dispInfo
.mask
& HDI_DI_SETITEM
)
725 if (dispInfo
.mask
& HDI_IMAGE
)
727 lpItem
->iImage
= dispInfo
.iImage
;
729 if (dispInfo
.mask
& HDI_TEXT
)
731 if (isUnicodeNotify
|| convertToUnicode
)
732 Str_SetPtrW(&lpItem
->pszText
, (LPCWSTR
)dispInfo
.pszText
);
733 else /*if (convertToAnsi || !isW)*/
734 Str_SetPtrAtoW(&lpItem
->pszText
, (LPCSTR
)dispInfo
.pszText
);
737 FIXME("NMHDDISPINFO returns with flags HDI_DI_SETITEM\n");
742 if ((phdi
->mask
& mask
) & HDI_IMAGE
)
744 phdi
->iImage
= dispInfo
.iImage
;
746 if ((phdi
->mask
& mask
) & HDI_TEXT
)
749 Str_GetPtrW ((LPCWSTR
)dispInfo
.pszText
, phdi
->pszText
, phdi
->cchTextMax
);
750 else if (convertToUnicode
)
751 Str_GetPtrWtoA ((LPCWSTR
)dispInfo
.pszText
, (LPSTR
)phdi
->pszText
, phdi
->cchTextMax
);
753 Str_GetPtrA ((LPCSTR
)dispInfo
.pszText
, (LPSTR
)phdi
->pszText
, phdi
->cchTextMax
);
761 HEADER_SendClickNotify (HWND hwnd
, UINT code
, INT iItem
)
763 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
766 nmhdr
.hdr
.hwndFrom
= hwnd
;
767 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
768 nmhdr
.hdr
.code
= code
;
773 return (BOOL
)SendMessageA (infoPtr
->hwndNotify
, WM_NOTIFY
,
774 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
779 HEADER_CreateDragImage (HWND hwnd
, WPARAM wParam
)
781 FIXME("empty stub!\n");
787 HEADER_DeleteItem (HWND hwnd
, WPARAM wParam
)
789 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
790 INT iItem
= (INT
)wParam
;
792 TRACE("[iItem=%d]\n", iItem
);
794 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
797 if (infoPtr
->uNumItem
== 1) {
798 TRACE("Simple delete!\n");
799 if (infoPtr
->items
[0].pszText
)
800 Free (infoPtr
->items
[0].pszText
);
801 Free (infoPtr
->items
);
802 Free(infoPtr
->order
);
805 infoPtr
->uNumItem
= 0;
808 HEADER_ITEM
*oldItems
= infoPtr
->items
;
811 TRACE("Complex delete! [iItem=%d]\n", iItem
);
813 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
814 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
815 if (infoPtr
->items
[iItem
].pszText
)
816 Free (infoPtr
->items
[iItem
].pszText
);
817 iOrder
= infoPtr
->items
[iItem
].iOrder
;
820 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
821 /* pre delete copy */
823 memcpy (&infoPtr
->items
[0], &oldItems
[0],
824 iItem
* sizeof(HEADER_ITEM
));
827 /* post delete copy */
828 if (iItem
< infoPtr
->uNumItem
) {
829 memcpy (&infoPtr
->items
[iItem
], &oldItems
[iItem
+1],
830 (infoPtr
->uNumItem
- iItem
) * sizeof(HEADER_ITEM
));
833 /* Correct the orders */
834 if (iOrder
< infoPtr
->uNumItem
)
836 memmove(&infoPtr
->order
[iOrder
], &infoPtr
->order
[iOrder
+ 1],
837 (infoPtr
->uNumItem
- iOrder
) * sizeof(INT
));
838 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
840 if (infoPtr
->order
[i
] > iItem
)
843 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
847 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
848 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
852 HEADER_SetItemBounds (hwnd
);
854 InvalidateRect(hwnd
, NULL
, FALSE
);
861 HEADER_GetImageList (HWND hwnd
)
863 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
865 return (LRESULT
)infoPtr
->himl
;
870 HEADER_GetItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
872 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
878 TRACE("[nItem=%d]\n", nItem
);
882 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
885 lpItem
= &infoPtr
->items
[nItem
];
887 if (phdi
->mask
& HDI_BITMAP
)
888 phdi
->hbm
= (lpItem
!= NULL
) ? lpItem
->hbm
: 0;
890 if (phdi
->mask
& HDI_FORMAT
)
891 phdi
->fmt
= (lpItem
!= NULL
) ? lpItem
->fmt
: 0;
893 if (phdi
->mask
& HDI_WIDTH
)
894 phdi
->cxy
= (lpItem
!= NULL
) ? lpItem
->cxy
: 0;
896 if (phdi
->mask
& HDI_LPARAM
)
897 phdi
->lParam
= (lpItem
!= NULL
) ? lpItem
->lParam
: 0;
899 if (phdi
->mask
& HDI_IMAGE
)
901 phdi
->iImage
= (lpItem
!= NULL
) ? lpItem
->iImage
: 0;
902 if (lpItem
->iImage
== I_IMAGECALLBACK
)
904 HEADER_SendHeaderDispInfoNotify(hwnd
, nItem
, HDI_IMAGE
, phdi
, lpItem
, bUnicode
);
908 if (phdi
->mask
& HDI_ORDER
)
909 phdi
->iOrder
= (lpItem
!= NULL
) ? lpItem
->iOrder
: 0;
911 if (phdi
->mask
& HDI_TEXT
)
913 if (lpItem
== NULL
) *phdi
->pszText
= 0; /* null pointer check */
914 else if (lpItem
->pszText
== LPSTR_TEXTCALLBACKW
) /* covers == TEXTCALLBACKA too */
916 HEADER_SendHeaderDispInfoNotify(hwnd
, nItem
, HDI_TEXT
, phdi
, lpItem
, bUnicode
);
921 Str_GetPtrW (lpItem
->pszText
, phdi
->pszText
, phdi
->cchTextMax
);
923 Str_GetPtrWtoA (lpItem
->pszText
, (LPSTR
)phdi
->pszText
, phdi
->cchTextMax
);
931 inline static LRESULT
932 HEADER_GetItemCount (HWND hwnd
)
934 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
935 return infoPtr
->uNumItem
;
940 HEADER_GetItemRect (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
942 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
943 INT iItem
= (INT
)wParam
;
944 LPRECT lpRect
= (LPRECT
)lParam
;
946 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
949 lpRect
->left
= infoPtr
->items
[iItem
].rect
.left
;
950 lpRect
->right
= infoPtr
->items
[iItem
].rect
.right
;
951 lpRect
->top
= infoPtr
->items
[iItem
].rect
.top
;
952 lpRect
->bottom
= infoPtr
->items
[iItem
].rect
.bottom
;
959 HEADER_GetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
961 LPINT order
= (LPINT
) lParam
;
962 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
964 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
967 memcpy(order
, infoPtr
->order
, infoPtr
->uNumItem
* sizeof(INT
));
972 HEADER_SetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
975 LPINT order
= (LPINT
) lParam
;
976 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
979 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
981 memcpy(infoPtr
->order
, order
, infoPtr
->uNumItem
* sizeof(INT
));
982 for (i
=0; i
<(int)wParam
; i
++)
984 lpItem
= &infoPtr
->items
[*order
++];
987 infoPtr
->bRectsValid
=0;
988 InvalidateRect(hwnd
, NULL
, FALSE
);
992 inline static LRESULT
993 HEADER_GetUnicodeFormat (HWND hwnd
)
995 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
996 return (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1001 HEADER_HitTest (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1003 LPHDHITTESTINFO phti
= (LPHDHITTESTINFO
)lParam
;
1005 HEADER_InternalHitTest (hwnd
, &phti
->pt
, &phti
->flags
, &phti
->iItem
);
1007 if (phti
->flags
== HHT_NOWHERE
)
1015 HEADER_InsertItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1017 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1018 HEADER_ITEM
*lpItem
;
1022 if ((phdi
== NULL
) || (nItem
< 0))
1025 if (nItem
> infoPtr
->uNumItem
)
1026 nItem
= infoPtr
->uNumItem
;
1028 iOrder
= (phdi
->mask
& HDI_ORDER
) ? phdi
->iOrder
: nItem
;
1031 else if (infoPtr
->uNumItem
< iOrder
)
1032 iOrder
= infoPtr
->uNumItem
;
1034 if (infoPtr
->uNumItem
== 0) {
1035 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
));
1036 infoPtr
->order
= Alloc(sizeof(INT
));
1037 infoPtr
->uNumItem
++;
1040 HEADER_ITEM
*oldItems
= infoPtr
->items
;
1041 INT
*oldOrder
= infoPtr
->order
;
1043 infoPtr
->uNumItem
++;
1044 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
1046 memcpy (&infoPtr
->items
[1], &oldItems
[0],
1047 (infoPtr
->uNumItem
-1) * sizeof(HEADER_ITEM
));
1051 /* pre insert copy */
1053 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1054 nItem
* sizeof(HEADER_ITEM
));
1057 /* post insert copy */
1058 if (nItem
< infoPtr
->uNumItem
- 1) {
1059 memcpy (&infoPtr
->items
[nItem
+1], &oldItems
[nItem
],
1060 (infoPtr
->uNumItem
- nItem
- 1) * sizeof(HEADER_ITEM
));
1064 infoPtr
->order
= Alloc(sizeof(INT
) * infoPtr
->uNumItem
);
1065 memcpy(infoPtr
->order
, oldOrder
, iOrder
* sizeof(INT
));
1066 infoPtr
->order
[iOrder
] = nItem
;
1067 memcpy(&infoPtr
->order
[iOrder
+ 1], &oldOrder
[iOrder
],
1068 (infoPtr
->uNumItem
- iOrder
- 1) * sizeof(INT
));
1074 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1076 if (i
!= iOrder
&& infoPtr
->order
[i
] >= nItem
)
1077 infoPtr
->order
[i
]++;
1078 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1081 lpItem
= &infoPtr
->items
[nItem
];
1082 lpItem
->bDown
= FALSE
;
1084 if (phdi
->mask
& HDI_WIDTH
)
1085 lpItem
->cxy
= phdi
->cxy
;
1087 if (phdi
->mask
& HDI_FORMAT
)
1088 lpItem
->fmt
= phdi
->fmt
;
1090 if (lpItem
->fmt
== 0)
1091 lpItem
->fmt
= HDF_LEFT
;
1093 if (phdi
->mask
& HDI_BITMAP
)
1094 lpItem
->hbm
= phdi
->hbm
;
1096 if (phdi
->mask
& HDI_LPARAM
)
1097 lpItem
->lParam
= phdi
->lParam
;
1099 if (phdi
->mask
& HDI_IMAGE
)
1101 if (phdi
->iImage
!= I_IMAGECALLBACK
)
1103 lpItem
->iImage
= phdi
->iImage
;
1107 lpItem
->iImage
= phdi
->iImage
;
1108 HEADER_SendHeaderDispInfoNotify(hwnd
, nItem
, HDI_IMAGE
, NULL
, lpItem
, bUnicode
);
1112 if (phdi
->mask
& HDI_TEXT
)
1114 if (!phdi
->pszText
) phdi
->pszText
= '\0'; /* null pointer check */
1115 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers != TEXTCALLBACKA too */
1118 Str_SetPtrW(&lpItem
->pszText
, phdi
->pszText
);
1120 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)phdi
->pszText
);
1124 lpItem
->pszText
= phdi
->pszText
;
1125 HEADER_SendHeaderDispInfoNotify(hwnd
, nItem
, HDI_TEXT
, NULL
, lpItem
, bUnicode
);
1127 lpItem
->fmt
|= HDF_STRING
;
1130 lpItem
->iOrder
= iOrder
;
1132 HEADER_SetItemBounds (hwnd
);
1134 InvalidateRect(hwnd
, NULL
, FALSE
);
1141 HEADER_Layout (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1143 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1144 LPHDLAYOUT lpLayout
= (LPHDLAYOUT
)lParam
;
1146 lpLayout
->pwpos
->hwnd
= hwnd
;
1147 lpLayout
->pwpos
->hwndInsertAfter
= 0;
1148 lpLayout
->pwpos
->x
= lpLayout
->prc
->left
;
1149 lpLayout
->pwpos
->y
= lpLayout
->prc
->top
;
1150 lpLayout
->pwpos
->cx
= lpLayout
->prc
->right
- lpLayout
->prc
->left
;
1151 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_HIDDEN
)
1152 lpLayout
->pwpos
->cy
= 0;
1154 lpLayout
->pwpos
->cy
= infoPtr
->nHeight
;
1155 lpLayout
->prc
->top
+= infoPtr
->nHeight
;
1157 lpLayout
->pwpos
->flags
= SWP_NOZORDER
;
1159 TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1160 lpLayout
->pwpos
->x
, lpLayout
->pwpos
->y
,
1161 lpLayout
->pwpos
->cx
, lpLayout
->pwpos
->cy
);
1163 infoPtr
->bRectsValid
= FALSE
;
1170 HEADER_SetImageList (HWND hwnd
, HIMAGELIST himl
)
1172 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1175 TRACE("(himl %p)\n", himl
);
1176 himlOld
= infoPtr
->himl
;
1177 infoPtr
->himl
= himl
;
1179 /* FIXME: Refresh needed??? */
1181 return (LRESULT
)himlOld
;
1186 HEADER_GetBitmapMargin(HWND hwnd
)
1188 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1190 return infoPtr
->iMargin
;
1194 HEADER_SetBitmapMargin(HWND hwnd
, WPARAM wParam
)
1196 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1197 INT oldMargin
= infoPtr
->iMargin
;
1199 infoPtr
->iMargin
= (INT
)wParam
;
1205 HEADER_SetItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1207 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1208 HEADER_ITEM
*lpItem
;
1214 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1217 TRACE("[nItem=%d]\n", nItem
);
1219 HEADER_CopyHDItemForNotify(infoPtr
, &hdNotify
, phdi
, bUnicode
, &pvScratch
);
1220 if (HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGINGW
, nItem
, phdi
->mask
, &hdNotify
))
1222 if (pvScratch
) Free(pvScratch
);
1226 lpItem
= &infoPtr
->items
[nItem
];
1227 if (phdi
->mask
& HDI_BITMAP
)
1228 lpItem
->hbm
= phdi
->hbm
;
1230 if (phdi
->mask
& HDI_FORMAT
)
1231 lpItem
->fmt
= phdi
->fmt
;
1233 if (phdi
->mask
& HDI_LPARAM
)
1234 lpItem
->lParam
= phdi
->lParam
;
1236 if (phdi
->mask
& HDI_WIDTH
)
1237 lpItem
->cxy
= phdi
->cxy
;
1239 if (phdi
->mask
& HDI_IMAGE
)
1241 if (phdi
->iImage
!= I_IMAGECALLBACK
)
1243 lpItem
->iImage
= phdi
->iImage
;
1247 lpItem
->iImage
= phdi
->iImage
;
1248 HEADER_SendHeaderDispInfoNotify(hwnd
, nItem
, HDI_IMAGE
, NULL
, lpItem
, bUnicode
);
1252 if (phdi
->mask
& HDI_TEXT
)
1254 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers != TEXTCALLBACKA too */
1256 if (lpItem
->pszText
)
1258 Free(lpItem
->pszText
);
1259 lpItem
->pszText
= NULL
;
1264 Str_SetPtrW(&lpItem
->pszText
, phdi
->pszText
);
1266 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)phdi
->pszText
);
1271 lpItem
->pszText
= phdi
->pszText
;
1272 HEADER_SendHeaderDispInfoNotify(hwnd
, nItem
, HDI_TEXT
, NULL
, lpItem
, bUnicode
);
1276 if (phdi
->mask
& HDI_ORDER
)
1280 if (lpItem
->iOrder
< phdi
->iOrder
)
1282 memmove(&infoPtr
->order
[lpItem
->iOrder
],
1283 &infoPtr
->order
[lpItem
->iOrder
+ 1],
1284 (phdi
->iOrder
- lpItem
->iOrder
) * sizeof(INT
));
1286 if (phdi
->iOrder
< lpItem
->iOrder
)
1288 memmove(&infoPtr
->order
[phdi
->iOrder
+ 1],
1289 &infoPtr
->order
[phdi
->iOrder
],
1290 (lpItem
->iOrder
- phdi
->iOrder
) * sizeof(INT
));
1292 infoPtr
->order
[phdi
->iOrder
] = nItem
;
1293 nMin
= min(lpItem
->iOrder
, phdi
->iOrder
);
1294 nMax
= max(lpItem
->iOrder
, phdi
->iOrder
);
1295 for (i
= nMin
; i
<= nMax
; i
++)
1297 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1301 HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGEDW
, nItem
, phdi
->mask
, &hdNotify
);
1303 HEADER_SetItemBounds (hwnd
);
1305 InvalidateRect(hwnd
, NULL
, FALSE
);
1307 if (pvScratch
!= NULL
)
1312 inline static LRESULT
1313 HEADER_SetUnicodeFormat (HWND hwnd
, WPARAM wParam
)
1315 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1316 BOOL bTemp
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1318 infoPtr
->nNotifyFormat
= ((BOOL
)wParam
? NFR_UNICODE
: NFR_ANSI
);
1325 HEADER_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1327 HEADER_INFO
*infoPtr
;
1332 infoPtr
= (HEADER_INFO
*)Alloc (sizeof(HEADER_INFO
));
1333 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
1335 infoPtr
->hwndNotify
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1336 infoPtr
->uNumItem
= 0;
1340 infoPtr
->bRectsValid
= FALSE
;
1341 infoPtr
->hcurArrow
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1342 infoPtr
->hcurDivider
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDER
));
1343 infoPtr
->hcurDivopen
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDEROPEN
));
1344 infoPtr
->bPressed
= FALSE
;
1345 infoPtr
->bTracking
= FALSE
;
1346 infoPtr
->iMoveItem
= 0;
1348 infoPtr
->iHotItem
= -1;
1349 infoPtr
->iMargin
= 3*GetSystemMetrics(SM_CXEDGE
);
1350 infoPtr
->nNotifyFormat
=
1351 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
1354 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1355 GetTextMetricsW (hdc
, &tm
);
1356 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1357 SelectObject (hdc
, hOldFont
);
1360 OpenThemeData(hwnd
, themeClass
);
1367 HEADER_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1369 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1370 HEADER_ITEM
*lpItem
;
1374 if (infoPtr
->items
) {
1375 lpItem
= infoPtr
->items
;
1376 for (nItem
= 0; nItem
< infoPtr
->uNumItem
; nItem
++, lpItem
++) {
1377 if ((lpItem
->pszText
) && (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
))
1378 Free (lpItem
->pszText
);
1380 Free (infoPtr
->items
);
1384 Free(infoPtr
->order
);
1387 ImageList_Destroy (infoPtr
->himl
);
1389 SetWindowLongPtrW (hwnd
, 0, 0);
1392 theme
= GetWindowTheme(hwnd
);
1393 CloseThemeData(theme
);
1398 static inline LRESULT
1399 HEADER_GetFont (HWND hwnd
)
1401 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1403 return (LRESULT
)infoPtr
->hFont
;
1408 HEADER_LButtonDblClk (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1414 pt
.x
= (INT
)LOWORD(lParam
);
1415 pt
.y
= (INT
)HIWORD(lParam
);
1416 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1418 if ((GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) && (flags
== HHT_ONHEADER
))
1419 HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMDBLCLICKW
, nItem
, 0, NULL
);
1420 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
))
1421 HEADER_SendHeaderNotifyT (hwnd
, HDN_DIVIDERDBLCLICKW
, nItem
, 0, NULL
);
1428 HEADER_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1430 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1431 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1437 pt
.x
= (INT
)LOWORD(lParam
);
1438 pt
.y
= (INT
)HIWORD(lParam
);
1439 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1441 if ((dwStyle
& HDS_BUTTONS
) && (flags
== HHT_ONHEADER
)) {
1443 infoPtr
->bCaptured
= TRUE
;
1444 infoPtr
->bPressed
= TRUE
;
1445 infoPtr
->iMoveItem
= nItem
;
1447 infoPtr
->items
[nItem
].bDown
= TRUE
;
1449 /* Send WM_CUSTOMDRAW */
1451 HEADER_RefreshItem (hwnd
, hdc
, nItem
);
1452 ReleaseDC (hwnd
, hdc
);
1454 TRACE("Pressed item %d!\n", nItem
);
1456 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
)) {
1457 if (!(HEADER_SendHeaderNotifyT (hwnd
, HDN_BEGINTRACKW
, nItem
, 0, NULL
))) {
1459 infoPtr
->bCaptured
= TRUE
;
1460 infoPtr
->bTracking
= TRUE
;
1461 infoPtr
->iMoveItem
= nItem
;
1462 infoPtr
->nOldWidth
= infoPtr
->items
[nItem
].cxy
;
1463 infoPtr
->xTrackOffset
= infoPtr
->items
[nItem
].rect
.right
- pt
.x
;
1465 if (!(dwStyle
& HDS_FULLDRAG
)) {
1466 infoPtr
->xOldTrack
= infoPtr
->items
[nItem
].rect
.right
;
1468 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1469 ReleaseDC (hwnd
, hdc
);
1472 TRACE("Begin tracking item %d!\n", nItem
);
1481 HEADER_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1483 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1484 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1490 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1491 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1492 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1494 if (infoPtr
->bPressed
) {
1495 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
)) {
1496 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1498 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1499 ReleaseDC (hwnd
, hdc
);
1501 HEADER_SendClickNotify (hwnd
, HDN_ITEMCLICKA
, infoPtr
->iMoveItem
);
1503 else if (flags
== HHT_ONHEADER
)
1505 HEADER_ITEM
*lpItem
;
1506 INT newindex
= HEADER_IndexToOrder(hwnd
,nItem
);
1507 INT oldindex
= HEADER_IndexToOrder(hwnd
,infoPtr
->iMoveItem
);
1509 TRACE("Exchanging [index:order] [%d:%d] [%d:%d]\n",
1510 infoPtr
->iMoveItem
,oldindex
,nItem
,newindex
);
1511 lpItem
= &infoPtr
->items
[nItem
];
1512 lpItem
->iOrder
=oldindex
;
1514 lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1515 lpItem
->iOrder
= newindex
;
1517 infoPtr
->order
[oldindex
] = nItem
;
1518 infoPtr
->order
[newindex
] = infoPtr
->iMoveItem
;
1520 infoPtr
->bRectsValid
= FALSE
;
1521 InvalidateRect(hwnd
, NULL
, FALSE
);
1522 /* FIXME: Should some WM_NOTIFY be sent */
1525 TRACE("Released item %d!\n", infoPtr
->iMoveItem
);
1526 infoPtr
->bPressed
= FALSE
;
1528 else if (infoPtr
->bTracking
) {
1529 TRACE("End tracking item %d!\n", infoPtr
->iMoveItem
);
1530 infoPtr
->bTracking
= FALSE
;
1532 HEADER_SendHeaderNotifyT (hwnd
, HDN_ENDTRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1534 if (!(dwStyle
& HDS_FULLDRAG
)) {
1536 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1537 ReleaseDC (hwnd
, hdc
);
1540 if (HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
))
1542 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= infoPtr
->nOldWidth
;
1545 nWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1548 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1551 HEADER_SetItemBounds (hwnd
);
1552 InvalidateRect(hwnd
, NULL
, TRUE
);
1553 HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1556 if (infoPtr
->bCaptured
) {
1557 infoPtr
->bCaptured
= FALSE
;
1559 HEADER_SendSimpleNotify (hwnd
, NM_RELEASEDCAPTURE
);
1567 HEADER_NotifyFormat (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1569 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1574 return infoPtr
->nNotifyFormat
;
1577 infoPtr
->nNotifyFormat
=
1578 SendMessageW ((HWND
)wParam
, WM_NOTIFYFORMAT
,
1579 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
1580 return infoPtr
->nNotifyFormat
;
1588 HEADER_MouseLeave (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1590 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1591 /* Reset hot-tracked item when mouse leaves control. */
1592 INT oldHotItem
= infoPtr
->iHotItem
;
1593 HDC hdc
= GetDC (hwnd
);
1595 infoPtr
->iHotItem
= -1;
1596 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1597 ReleaseDC (hwnd
, hdc
);
1604 HEADER_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1606 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1607 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1612 /* With theming, hottracking is always enabled */
1613 BOOL hotTrackEnabled
=
1614 ((dwStyle
& HDS_BUTTONS
) && (dwStyle
& HDS_HOTTRACK
))
1615 || (GetWindowTheme (hwnd
) != NULL
);
1616 INT oldHotItem
= infoPtr
->iHotItem
;
1618 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1619 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1620 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1622 if (hotTrackEnabled
) {
1623 if (flags
& (HHT_ONHEADER
| HHT_ONDIVIDER
| HHT_ONDIVOPEN
))
1624 infoPtr
->iHotItem
= nItem
;
1626 infoPtr
->iHotItem
= -1;
1629 if (infoPtr
->bCaptured
) {
1630 if (infoPtr
->bPressed
) {
1631 BOOL oldState
= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
;
1632 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
))
1633 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= TRUE
;
1635 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1636 if (oldState
!= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
) {
1638 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1639 ReleaseDC (hwnd
, hdc
);
1642 TRACE("Moving pressed item %d!\n", infoPtr
->iMoveItem
);
1644 else if (infoPtr
->bTracking
) {
1645 if (dwStyle
& HDS_FULLDRAG
) {
1646 if (!HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
))
1648 nWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1651 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1652 HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1654 HEADER_SetItemBounds (hwnd
);
1655 InvalidateRect(hwnd
, NULL
, FALSE
);
1659 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1660 infoPtr
->xOldTrack
= pt
.x
+ infoPtr
->xTrackOffset
;
1661 if (infoPtr
->xOldTrack
< infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
)
1662 infoPtr
->xOldTrack
= infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1663 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
=
1664 infoPtr
->xOldTrack
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1665 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1666 ReleaseDC (hwnd
, hdc
);
1667 HEADER_SendHeaderNotifyT (hwnd
, HDN_TRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1670 TRACE("Tracking item %d!\n", infoPtr
->iMoveItem
);
1674 if (hotTrackEnabled
) {
1675 TRACKMOUSEEVENT tme
;
1676 if (oldHotItem
!= infoPtr
->iHotItem
) {
1678 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1679 if (infoPtr
->iHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iHotItem
);
1680 ReleaseDC (hwnd
, hdc
);
1682 tme
.cbSize
= sizeof( tme
);
1683 tme
.dwFlags
= TME_LEAVE
;
1684 tme
.hwndTrack
= hwnd
;
1685 TrackMouseEvent( &tme
);
1693 HEADER_Paint (HWND hwnd
, WPARAM wParam
)
1698 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1699 HEADER_Refresh (hwnd
, hdc
);
1701 EndPaint (hwnd
, &ps
);
1707 HEADER_RButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1712 pt
.x
= LOWORD(lParam
);
1713 pt
.y
= HIWORD(lParam
);
1715 /* Send a Notify message */
1716 bRet
= HEADER_SendSimpleNotify (hwnd
, NM_RCLICK
);
1718 /* Change to screen coordinate for WM_CONTEXTMENU */
1719 ClientToScreen(hwnd
, &pt
);
1721 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1722 SendMessageW( hwnd
, WM_CONTEXTMENU
, (WPARAM
) hwnd
, MAKELPARAM(pt
.x
, pt
.y
));
1729 HEADER_SetCursor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1731 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1736 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam
), HIWORD(lParam
));
1739 ScreenToClient (hwnd
, &pt
);
1741 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1743 if (flags
== HHT_ONDIVIDER
)
1744 SetCursor (infoPtr
->hcurDivider
);
1745 else if (flags
== HHT_ONDIVOPEN
)
1746 SetCursor (infoPtr
->hcurDivopen
);
1748 SetCursor (infoPtr
->hcurArrow
);
1755 HEADER_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1757 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1759 HFONT hFont
, hOldFont
;
1762 infoPtr
->hFont
= (HFONT
)wParam
;
1764 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
1767 hOldFont
= SelectObject (hdc
, hFont
);
1768 GetTextMetricsW (hdc
, &tm
);
1769 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1770 SelectObject (hdc
, hOldFont
);
1773 infoPtr
->bRectsValid
= FALSE
;
1776 InvalidateRect(hwnd
, NULL
, FALSE
);
1782 /* Update the theme handle after a theme change */
1783 static LRESULT
HEADER_ThemeChanged(HWND hwnd
)
1785 HTHEME theme
= GetWindowTheme(hwnd
);
1786 CloseThemeData(theme
);
1787 OpenThemeData(hwnd
, themeClass
);
1788 InvalidateRect(hwnd
, NULL
, FALSE
);
1793 static LRESULT WINAPI
1794 HEADER_WindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1796 TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd
, msg
, wParam
, lParam
);
1797 if (!HEADER_GetInfoPtr (hwnd
) && (msg
!= WM_CREATE
))
1798 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1800 /* case HDM_CLEARFILTER: */
1802 case HDM_CREATEDRAGIMAGE
:
1803 return HEADER_CreateDragImage (hwnd
, wParam
);
1805 case HDM_DELETEITEM
:
1806 return HEADER_DeleteItem (hwnd
, wParam
);
1808 /* case HDM_EDITFILTER: */
1810 case HDM_GETBITMAPMARGIN
:
1811 return HEADER_GetBitmapMargin(hwnd
);
1813 case HDM_GETIMAGELIST
:
1814 return HEADER_GetImageList (hwnd
);
1818 return HEADER_GetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_GETITEMW
);
1820 case HDM_GETITEMCOUNT
:
1821 return HEADER_GetItemCount (hwnd
);
1823 case HDM_GETITEMRECT
:
1824 return HEADER_GetItemRect (hwnd
, wParam
, lParam
);
1826 case HDM_GETORDERARRAY
:
1827 return HEADER_GetOrderArray(hwnd
, wParam
, lParam
);
1829 case HDM_GETUNICODEFORMAT
:
1830 return HEADER_GetUnicodeFormat (hwnd
);
1833 return HEADER_HitTest (hwnd
, wParam
, lParam
);
1835 case HDM_INSERTITEMA
:
1836 case HDM_INSERTITEMW
:
1837 return HEADER_InsertItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_INSERTITEMW
);
1840 return HEADER_Layout (hwnd
, wParam
, lParam
);
1842 case HDM_ORDERTOINDEX
:
1843 return HEADER_OrderToIndex(hwnd
, wParam
);
1845 case HDM_SETBITMAPMARGIN
:
1846 return HEADER_SetBitmapMargin(hwnd
, wParam
);
1848 /* case HDM_SETFILTERCHANGETIMEOUT: */
1850 /* case HDM_SETHOTDIVIDER: */
1852 case HDM_SETIMAGELIST
:
1853 return HEADER_SetImageList (hwnd
, (HIMAGELIST
)lParam
);
1857 return HEADER_SetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_SETITEMW
);
1859 case HDM_SETORDERARRAY
:
1860 return HEADER_SetOrderArray(hwnd
, wParam
, lParam
);
1862 case HDM_SETUNICODEFORMAT
:
1863 return HEADER_SetUnicodeFormat (hwnd
, wParam
);
1866 return HEADER_Create (hwnd
, wParam
, lParam
);
1869 return HEADER_Destroy (hwnd
, wParam
, lParam
);
1875 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
1878 return HEADER_GetFont (hwnd
);
1880 case WM_LBUTTONDBLCLK
:
1881 return HEADER_LButtonDblClk (hwnd
, wParam
, lParam
);
1883 case WM_LBUTTONDOWN
:
1884 return HEADER_LButtonDown (hwnd
, wParam
, lParam
);
1887 return HEADER_LButtonUp (hwnd
, wParam
, lParam
);
1890 return HEADER_MouseLeave (hwnd
, wParam
, lParam
);
1893 return HEADER_MouseMove (hwnd
, wParam
, lParam
);
1895 case WM_NOTIFYFORMAT
:
1896 return HEADER_NotifyFormat (hwnd
, wParam
, lParam
);
1899 return HEADER_Size (hwnd
, wParam
);
1901 case WM_THEMECHANGED
:
1902 return HEADER_ThemeChanged (hwnd
);
1904 case WM_PRINTCLIENT
:
1906 return HEADER_Paint (hwnd
, wParam
);
1909 return HEADER_RButtonUp (hwnd
, wParam
, lParam
);
1912 return HEADER_SetCursor (hwnd
, wParam
, lParam
);
1915 return HEADER_SetFont (hwnd
, wParam
, lParam
);
1918 if ((msg
>= WM_USER
) && (msg
< WM_APP
))
1919 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
1920 msg
, wParam
, lParam
);
1921 return DefWindowProcA (hwnd
, msg
, wParam
, lParam
);
1927 HEADER_Register (void)
1931 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
1932 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
1933 wndClass
.lpfnWndProc
= HEADER_WindowProc
;
1934 wndClass
.cbClsExtra
= 0;
1935 wndClass
.cbWndExtra
= sizeof(HEADER_INFO
*);
1936 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1937 wndClass
.lpszClassName
= WC_HEADERW
;
1939 RegisterClassW (&wndClass
);
1944 HEADER_Unregister (void)
1946 UnregisterClassW (WC_HEADERW
, NULL
);