4 * Copyright 1998 Eric Kohl
5 * Copyright 2000 Eric Kohl for CodeWeavers
6 * Copyright 2003 Maxime Bellenge
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * - Imagelist support (partially).
24 * - Callback items (under construction).
25 * - Hottrack support (partially).
26 * - Custom draw support (including Notifications).
27 * - Drag and Drop support (including Notifications).
29 * - Use notification format
30 * - Correct the order maintenance code to preserve valid order
40 #include "wine/unicode.h"
46 #include "imagelist.h"
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(header
);
61 INT iOrder
; /* see documentation of HD_ITEM */
63 BOOL bDown
; /* is item pressed? (used for drawing) */
64 RECT rect
; /* bounding rectangle of the item */
65 DWORD callbackMask
; /* HDI_* flags for items that are callback */
71 HWND hwndNotify
; /* Owner window to send notifications to */
72 INT nNotifyFormat
; /* format used for WM_NOTIFY messages */
73 UINT uNumItem
; /* number of items (columns) */
74 INT nHeight
; /* height of the header (pixels) */
75 HFONT hFont
; /* handle to the current font */
76 HCURSOR hcurArrow
; /* handle to the arrow cursor */
77 HCURSOR hcurDivider
; /* handle to a cursor (used over dividers) <-|-> */
78 HCURSOR hcurDivopen
; /* handle to a cursor (used over dividers) <-||-> */
79 BOOL bCaptured
; /* Is the mouse captured? */
80 BOOL bPressed
; /* Is a header item pressed (down)? */
81 BOOL bDragging
; /* Are we dragging an item? */
82 BOOL bTracking
; /* Is in tracking mode? */
83 POINT ptLButtonDown
; /* The point where the left button was pressed */
84 INT iMoveItem
; /* index of tracked item. (Tracking mode) */
85 INT xTrackOffset
; /* distance between the right side of the tracked item and the cursor */
86 INT xOldTrack
; /* track offset (see above) after the last WM_MOUSEMOVE */
87 INT nOldWidth
; /* width of a sizing item after the last WM_MOUSEMOVE */
88 INT iHotItem
; /* index of hot item (cursor is over this item) */
89 INT iHotDivider
; /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
90 INT iMargin
; /* width of the margin that surrounds a bitmap */
92 HIMAGELIST himl
; /* handle to an image list (may be 0) */
93 HEADER_ITEM
*items
; /* pointer to array of HEADER_ITEM's */
94 INT
*order
; /* array of item IDs indexed by order */
95 BOOL bRectsValid
; /* validity flag for bounding rectangles */
100 #define DIVIDER_WIDTH 10
101 #define HOT_DIVIDER_WIDTH 2
102 #define MAX_HEADER_TEXT_LEN 260
103 #define HDN_UNICODE_OFFSET 20
104 #define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
106 #define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)
107 #define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)
108 #define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))
109 #define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)
111 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0))
113 static BOOL
HEADER_PrepareCallbackItems(HWND hwnd
, INT iItem
, INT reqMask
);
114 static void HEADER_FreeCallbackItems(HEADER_ITEM
*lpItem
);
116 static const WCHAR themeClass
[] = {'H','e','a','d','e','r',0};
117 static WCHAR emptyString
[] = {0};
119 static void HEADER_DisposeItem(HEADER_ITEM
*lpItem
)
123 Free(lpItem
->pszText
);
127 static void HEADER_StoreHDItemInHeader(HEADER_ITEM
*lpItem
, UINT mask
, HDITEMW
*phdi
, BOOL fUnicode
)
129 if (mask
& HDI_UNSUPPORTED_FIELDS
)
130 FIXME("unsupported header fields %x\n", (mask
& HDI_UNSUPPORTED_FIELDS
));
132 if (mask
& HDI_BITMAP
)
133 lpItem
->hbm
= phdi
->hbm
;
135 if (mask
& HDI_FORMAT
)
136 lpItem
->fmt
= phdi
->fmt
;
138 if (mask
& HDI_LPARAM
)
139 lpItem
->lParam
= phdi
->lParam
;
141 if (mask
& HDI_WIDTH
)
142 lpItem
->cxy
= phdi
->cxy
;
144 if (mask
& HDI_IMAGE
)
146 lpItem
->iImage
= phdi
->iImage
;
147 if (phdi
->iImage
== I_IMAGECALLBACK
)
148 lpItem
->callbackMask
|= HDI_IMAGE
;
150 lpItem
->callbackMask
&= ~HDI_IMAGE
;
157 Free(lpItem
->pszText
);
158 lpItem
->pszText
= NULL
;
161 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers != TEXTCALLBACKA too */
163 LPWSTR pszText
= (phdi
->pszText
!= NULL
? phdi
->pszText
: emptyString
);
165 Str_SetPtrW(&lpItem
->pszText
, pszText
);
167 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)pszText
);
168 lpItem
->callbackMask
&= ~HDI_TEXT
;
172 lpItem
->pszText
= NULL
;
173 lpItem
->callbackMask
|= HDI_TEXT
;
178 inline static LRESULT
179 HEADER_IndexToOrder (HWND hwnd
, INT iItem
)
181 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
182 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
183 return lpItem
->iOrder
;
188 HEADER_OrderToIndex(HWND hwnd
, WPARAM wParam
)
190 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
191 INT iorder
= (INT
)wParam
;
193 if ((iorder
<0) || iorder
>= infoPtr
->uNumItem
)
195 return infoPtr
->order
[iorder
];
199 HEADER_ChangeItemOrder(HEADER_INFO
*infoPtr
, INT iItem
, INT iNewOrder
)
201 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
204 TRACE("%d: %d->%d\n", iItem
, lpItem
->iOrder
, iNewOrder
);
205 if (lpItem
->iOrder
< iNewOrder
)
207 memmove(&infoPtr
->order
[lpItem
->iOrder
],
208 &infoPtr
->order
[lpItem
->iOrder
+ 1],
209 (iNewOrder
- lpItem
->iOrder
) * sizeof(INT
));
211 if (iNewOrder
< lpItem
->iOrder
)
213 memmove(&infoPtr
->order
[iNewOrder
+ 1],
214 &infoPtr
->order
[iNewOrder
],
215 (lpItem
->iOrder
- iNewOrder
) * sizeof(INT
));
217 infoPtr
->order
[iNewOrder
] = iItem
;
218 nMin
= min(lpItem
->iOrder
, iNewOrder
);
219 nMax
= max(lpItem
->iOrder
, iNewOrder
);
220 for (i
= nMin
; i
<= nMax
; i
++)
221 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= i
;
224 /* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
226 HEADER_NextItem(HWND hwnd
, INT iItem
)
228 return HEADER_OrderToIndex(hwnd
, HEADER_IndexToOrder(hwnd
, iItem
)+1);
232 HEADER_PrevItem(HWND hwnd
, INT iItem
)
234 return HEADER_OrderToIndex(hwnd
, HEADER_IndexToOrder(hwnd
, iItem
)-1);
238 HEADER_SetItemBounds (HWND hwnd
)
240 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
246 infoPtr
->bRectsValid
= TRUE
;
248 if (infoPtr
->uNumItem
== 0)
251 GetClientRect (hwnd
, &rect
);
254 for (i
= 0; i
< infoPtr
->uNumItem
; i
++) {
255 phdi
= &infoPtr
->items
[HEADER_OrderToIndex(hwnd
,i
)];
256 phdi
->rect
.top
= rect
.top
;
257 phdi
->rect
.bottom
= rect
.bottom
;
259 phdi
->rect
.right
= phdi
->rect
.left
+ ((phdi
->cxy
>0)?phdi
->cxy
:0);
260 x
= phdi
->rect
.right
;
265 HEADER_Size (HWND hwnd
, WPARAM wParam
)
267 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
269 infoPtr
->bRectsValid
= FALSE
;
274 static void HEADER_GetHotDividerRect(HWND hwnd
, HEADER_INFO
*infoPtr
, RECT
*r
)
276 INT iDivider
= infoPtr
->iHotDivider
;
277 if (infoPtr
->uNumItem
> 0)
281 if (iDivider
< infoPtr
->uNumItem
)
283 lpItem
= &infoPtr
->items
[iDivider
];
284 r
->left
= lpItem
->rect
.left
- HOT_DIVIDER_WIDTH
/2;
285 r
->right
= lpItem
->rect
.left
+ HOT_DIVIDER_WIDTH
/2;
289 lpItem
= &infoPtr
->items
[HEADER_OrderToIndex(hwnd
, infoPtr
->uNumItem
-1)];
290 r
->left
= lpItem
->rect
.right
- HOT_DIVIDER_WIDTH
/2;
291 r
->right
= lpItem
->rect
.right
+ HOT_DIVIDER_WIDTH
/2;
293 r
->top
= lpItem
->rect
.top
;
294 r
->bottom
= lpItem
->rect
.bottom
;
299 GetClientRect(hwnd
, &clientRect
);
301 r
->right
= r
->left
+ HOT_DIVIDER_WIDTH
/2;
307 HEADER_DrawItem (HWND hwnd
, HDC hdc
, INT iItem
, BOOL bHotTrack
)
309 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
310 HEADER_ITEM
*phdi
= &infoPtr
->items
[iItem
];
312 INT oldBkMode
, cxEdge
= GetSystemMetrics(SM_CXEDGE
);
313 HTHEME theme
= GetWindowTheme (hwnd
);
316 TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem
, bHotTrack
, (infoPtr
->nNotifyFormat
== NFR_UNICODE
));
318 if (!infoPtr
->bRectsValid
)
319 HEADER_SetItemBounds(hwnd
);
322 if (r
.right
- r
.left
== 0)
323 return phdi
->rect
.right
;
326 int state
= (phdi
->bDown
) ? HIS_PRESSED
:
327 (bHotTrack
? HIS_HOT
: HIS_NORMAL
);
328 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, state
,
330 GetThemeBackgroundContentRect (theme
, hdc
, HP_HEADERITEM
, state
,
334 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) {
336 DrawEdge (hdc
, &r
, BDR_RAISEDOUTER
,
337 BF_RECT
| BF_FLAT
| BF_MIDDLE
| BF_ADJUST
);
340 DrawEdge (hdc
, &r
, EDGE_RAISED
,
341 BF_RECT
| BF_SOFT
| BF_MIDDLE
| BF_ADJUST
);
344 DrawEdge (hdc
, &r
, EDGE_ETCHED
, BF_BOTTOM
| BF_RIGHT
| BF_ADJUST
);
354 /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
355 SetTextColor (hdc
, (bHotTrack
&& !theme
) ? COLOR_HIGHLIGHT
: COLOR_BTNTEXT
);
356 SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
358 nmcd
.hdr
.hwndFrom
= hwnd
;
359 nmcd
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
360 nmcd
.hdr
.code
= NM_CUSTOMDRAW
;
361 nmcd
.dwDrawStage
= CDDS_PREPAINT
| CDDS_ITEM
| CDDS_ITEMPOSTERASE
;
363 nmcd
.dwItemSpec
= iItem
;
365 nmcd
.uItemState
= phdi
->bDown
? CDIS_SELECTED
: 0;
366 nmcd
.lItemlParam
= phdi
->lParam
;
368 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
, nmcd
.hdr
.idFrom
, (LPARAM
)&nmcd
);
370 if (phdi
->fmt
& HDF_OWNERDRAW
) {
373 dis
.CtlType
= ODT_HEADER
;
374 dis
.CtlID
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
376 dis
.itemAction
= ODA_DRAWENTIRE
;
377 dis
.itemState
= phdi
->bDown
? ODS_SELECTED
: 0;
381 dis
.itemData
= phdi
->lParam
;
382 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
383 SendMessageW (infoPtr
->hwndNotify
, WM_DRAWITEM
,
384 (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
385 if (oldBkMode
!= TRANSPARENT
)
386 SetBkMode(hdc
, oldBkMode
);
389 UINT rw
, rh
, /* width and height of r */
390 *x
= NULL
, *w
= NULL
; /* x and width of the pic (bmp or img) which is part of cnt */
391 /* cnt,txt,img,bmp */
396 HEADER_PrepareCallbackItems(hwnd
, iItem
, HDI_TEXT
|HDI_IMAGE
);
397 cw
= tw
= iw
= bw
= 0;
398 rw
= r
.right
- r
.left
;
399 rh
= r
.bottom
- r
.top
;
402 HBRUSH hbr
= CreateSolidBrush(GetBkColor(hdc
));
403 RECT rcBackground
= r
;
405 rcBackground
.right
-= cxEdge
;
406 rcBackground
.left
+= cxEdge
;
407 FillRect(hdc
, &rcBackground
, hbr
);
410 if (phdi
->fmt
& HDF_STRING
) {
413 DrawTextW (hdc
, phdi
->pszText
, -1,
414 &textRect
, DT_LEFT
|DT_VCENTER
|DT_SINGLELINE
|DT_CALCRECT
);
415 cw
= textRect
.right
- textRect
.left
+ 2 * infoPtr
->iMargin
;
418 if ((phdi
->fmt
& HDF_IMAGE
) && (infoPtr
->himl
)) {
419 iw
= infoPtr
->himl
->cx
+ 2 * infoPtr
->iMargin
;
424 if ((phdi
->fmt
& HDF_BITMAP
) && (phdi
->hbm
)) {
425 GetObjectW (phdi
->hbm
, sizeof(BITMAP
), (LPVOID
)&bmp
);
426 bw
= bmp
.bmWidth
+ 2 * infoPtr
->iMargin
;
436 /* align cx using the unclipped cw */
437 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_LEFT
)
439 else if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_CENTER
)
440 cx
= r
.left
+ rw
/ 2 - cw
/ 2;
447 if (cx
+ cw
> r
.right
)
450 tx
= cx
+ infoPtr
->iMargin
;
451 /* since cw might have changed we have to recalculate tw */
452 tw
= cw
- infoPtr
->iMargin
* 2;
456 if (phdi
->fmt
& HDF_BITMAP_ON_RIGHT
) {
457 /* put pic behind text */
458 *x
= cx
+ tw
+ infoPtr
->iMargin
* 3;
460 *x
= cx
+ infoPtr
->iMargin
;
461 /* move text behind pic */
467 /* since we're done with the layout we can
468 now calculate the position of bmp which
469 has no influence on alignment and layout
471 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_RIGHT
)
472 bx
= cx
- bw
+ infoPtr
->iMargin
;
474 bx
= cx
+ cw
+ infoPtr
->iMargin
;
478 HDC hClipDC
= GetDC(hwnd
);
479 HRGN hClipRgn
= CreateRectRgn(r
.left
, r
.top
, r
.right
, r
.bottom
);
480 SelectClipRgn(hClipDC
, hClipRgn
);
483 HDC hdcBitmap
= CreateCompatibleDC (hClipDC
);
484 SelectObject (hdcBitmap
, phdi
->hbm
);
485 BitBlt (hClipDC
, bx
, r
.top
+ ((INT
)rh
- bmp
.bmHeight
) / 2,
486 bmp
.bmWidth
, bmp
.bmHeight
, hdcBitmap
, 0, 0, SRCCOPY
);
487 DeleteDC (hdcBitmap
);
491 ImageList_DrawEx (infoPtr
->himl
, phdi
->iImage
, hClipDC
,
492 ix
, r
.top
+ ((INT
)rh
- infoPtr
->himl
->cy
) / 2,
493 infoPtr
->himl
->cx
, infoPtr
->himl
->cy
, CLR_DEFAULT
, CLR_DEFAULT
, 0);
496 DeleteObject(hClipRgn
);
497 ReleaseDC(hwnd
, hClipDC
);
500 if (((phdi
->fmt
& HDF_STRING
)
501 || (!(phdi
->fmt
& (HDF_OWNERDRAW
|HDF_STRING
|HDF_BITMAP
|
502 HDF_BITMAP_ON_RIGHT
|HDF_IMAGE
)))) /* no explicit format specified? */
503 && (phdi
->pszText
)) {
504 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
507 DrawTextW (hdc
, phdi
->pszText
, -1,
508 &r
, DT_LEFT
|DT_END_ELLIPSIS
|DT_VCENTER
|DT_SINGLELINE
);
509 if (oldBkMode
!= TRANSPARENT
)
510 SetBkMode(hdc
, oldBkMode
);
512 HEADER_FreeCallbackItems(phdi
);
515 return phdi
->rect
.right
;
519 HEADER_DrawHotDivider(HWND hwnd
, HDC hdc
)
521 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
525 HEADER_GetHotDividerRect(hwnd
, infoPtr
, &r
);
526 brush
= CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT
));
527 FillRect(hdc
, &r
, brush
);
532 HEADER_Refresh (HWND hwnd
, HDC hdc
)
534 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
535 HFONT hFont
, hOldFont
;
540 HTHEME theme
= GetWindowTheme (hwnd
);
542 if (!infoPtr
->bRectsValid
)
543 HEADER_SetItemBounds(hwnd
);
545 /* get rect for the bar, adjusted for the border */
546 GetClientRect (hwnd
, &rect
);
548 if (infoPtr
->bDragging
)
549 ImageList_DragShowNolock(FALSE
);
551 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
552 hOldFont
= SelectObject (hdc
, hFont
);
554 /* draw Background */
555 if (infoPtr
->uNumItem
== 0 && theme
== NULL
) {
556 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
557 FillRect(hdc
, &rect
, hbrBk
);
561 for (i
= 0; x
<= rect
.right
&& i
< infoPtr
->uNumItem
; i
++) {
562 int idx
= HEADER_OrderToIndex(hwnd
,i
);
563 if (RectVisible(hdc
, &infoPtr
->items
[idx
].rect
))
564 HEADER_DrawItem (hwnd
, hdc
, idx
, infoPtr
->iHotItem
== i
);
565 x
= infoPtr
->items
[idx
].rect
.right
;
568 if ((x
<= rect
.right
) && (infoPtr
->uNumItem
> 0)) {
571 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, HIS_NORMAL
, &rect
,
575 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
)
576 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_TOP
|BF_LEFT
|BF_BOTTOM
|BF_SOFT
|BF_MIDDLE
);
578 DrawEdge (hdc
, &rect
, EDGE_ETCHED
, BF_BOTTOM
|BF_MIDDLE
);
582 if (infoPtr
->iHotDivider
!= -1)
583 HEADER_DrawHotDivider(hwnd
, hdc
);
585 if (infoPtr
->bDragging
)
586 ImageList_DragShowNolock(TRUE
);
587 SelectObject (hdc
, hOldFont
);
592 HEADER_RefreshItem (HWND hwnd
, HDC hdc
, INT iItem
)
594 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
595 HFONT hFont
, hOldFont
;
597 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
598 hOldFont
= SelectObject (hdc
, hFont
);
599 HEADER_DrawItem (hwnd
, hdc
, iItem
, infoPtr
->iHotItem
== iItem
);
600 SelectObject (hdc
, hOldFont
);
605 HEADER_InternalHitTest (HWND hwnd
, LPPOINT lpPt
, UINT
*pFlags
, INT
*pItem
)
607 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
613 GetClientRect (hwnd
, &rect
);
617 if (PtInRect (&rect
, *lpPt
))
619 if (infoPtr
->uNumItem
== 0) {
620 *pFlags
|= HHT_NOWHERE
;
626 /* somewhere inside */
627 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++) {
628 rect
= infoPtr
->items
[iCount
].rect
;
629 width
= rect
.right
- rect
.left
;
634 if (PtInRect (&rect
, *lpPt
)) {
635 if (width
<= 2 * DIVIDER_WIDTH
) {
636 *pFlags
|= HHT_ONHEADER
;
638 TRACE("ON HEADER %d\n", iCount
);
641 if (HEADER_IndexToOrder(hwnd
, iCount
) > 0) {
643 rcTest
.right
= rcTest
.left
+ DIVIDER_WIDTH
;
644 if (PtInRect (&rcTest
, *lpPt
)) {
646 *pFlags
|= HHT_ONDIVOPEN
;
647 *pItem
= HEADER_PrevItem(hwnd
, iCount
);
648 TRACE("ON DIVOPEN %d\n", *pItem
);
652 *pFlags
|= HHT_ONDIVIDER
;
653 *pItem
= HEADER_PrevItem(hwnd
, iCount
);
654 TRACE("ON DIVIDER %d\n", *pItem
);
660 rcTest
.left
= rcTest
.right
- DIVIDER_WIDTH
;
661 if (PtInRect (&rcTest
, *lpPt
)) {
662 *pFlags
|= HHT_ONDIVIDER
;
664 TRACE("ON DIVIDER %d\n", *pItem
);
668 *pFlags
|= HHT_ONHEADER
;
670 TRACE("ON HEADER %d\n", iCount
);
675 /* check for last divider part (on nowhere) */
676 rect
= infoPtr
->items
[infoPtr
->uNumItem
-1].rect
;
677 rect
.left
= rect
.right
;
678 rect
.right
+= DIVIDER_WIDTH
;
679 if (PtInRect (&rect
, *lpPt
)) {
681 *pFlags
|= HHT_ONDIVOPEN
;
682 *pItem
= infoPtr
->uNumItem
- 1;
683 TRACE("ON DIVOPEN %d\n", *pItem
);
687 *pFlags
|= HHT_ONDIVIDER
;
688 *pItem
= infoPtr
->uNumItem
-1;
689 TRACE("ON DIVIDER %d\n", *pItem
);
694 *pFlags
|= HHT_NOWHERE
;
701 if (lpPt
->x
< rect
.left
) {
703 *pFlags
|= HHT_TOLEFT
;
705 else if (lpPt
->x
> rect
.right
) {
707 *pFlags
|= HHT_TORIGHT
;
710 if (lpPt
->y
< rect
.top
) {
712 *pFlags
|= HHT_ABOVE
;
714 else if (lpPt
->y
> rect
.bottom
) {
716 *pFlags
|= HHT_BELOW
;
721 TRACE("flags=0x%X\n", *pFlags
);
727 HEADER_DrawTrackLine (HWND hwnd
, HDC hdc
, INT x
)
733 GetClientRect (hwnd
, &rect
);
735 hOldPen
= SelectObject (hdc
, GetStockObject (BLACK_PEN
));
736 oldRop
= SetROP2 (hdc
, R2_XORPEN
);
737 MoveToEx (hdc
, x
, rect
.top
, NULL
);
738 LineTo (hdc
, x
, rect
.bottom
);
739 SetROP2 (hdc
, oldRop
);
740 SelectObject (hdc
, hOldPen
);
745 * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
748 * [I] infoPtr : the header that wants to send the notify
749 * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
750 * [I] src : The source HDITEM. It may be a HDITEMA or HDITEMW
751 * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
752 * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
753 * the HDITEM is no longer in use or NULL if none was needed
755 * NOTE: We depend on HDITEMA and HDITEMW having the same structure
757 static void HEADER_CopyHDItemForNotify(HEADER_INFO
*infoPtr
, HDITEMW
*dest
,
758 HDITEMW
*src
, BOOL fSourceUnicode
, LPVOID
*ppvScratch
)
763 if (src
->mask
& HDI_TEXT
&& src
->pszText
!= LPSTR_TEXTCALLBACKW
) /* covers TEXTCALLBACKA as well */
765 if (fSourceUnicode
&& infoPtr
->nNotifyFormat
!= NFR_UNICODE
)
767 dest
->pszText
= NULL
;
768 Str_SetPtrWtoA((LPSTR
*)&dest
->pszText
, src
->pszText
);
769 *ppvScratch
= dest
->pszText
;
772 if (!fSourceUnicode
&& infoPtr
->nNotifyFormat
== NFR_UNICODE
)
774 dest
->pszText
= NULL
;
775 Str_SetPtrAtoW(&dest
->pszText
, (LPSTR
)src
->pszText
);
776 *ppvScratch
= dest
->pszText
;
781 static UINT
HEADER_NotifyCodeWtoA(UINT code
)
783 /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
784 if (code
>= HDN_LAST
&& code
<= HDN_FIRST_UNICODE
)
785 return code
+ HDN_UNICODE_OFFSET
;
791 HEADER_SendSimpleNotify (HWND hwnd
, UINT code
)
793 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
796 nmhdr
.hwndFrom
= hwnd
;
797 nmhdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
800 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
801 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
805 HEADER_SendHeaderNotifyT (HWND hwnd
, UINT code
, INT iItem
, INT mask
, HDITEMW
*lpItem
)
807 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
813 /* lpItem == NULL means that we should take the actual data from the item */
816 FIXME("(): invalid parameters - lpItem == NULL and (mask & HDI_TEXT)\n");
820 nmitem
.cxy
= infoPtr
->items
[iItem
].cxy
;
821 nmitem
.hbm
= infoPtr
->items
[iItem
].hbm
;
822 nmitem
.pszText
= NULL
;
823 nmitem
.cchTextMax
= 0;
824 nmitem
.fmt
= infoPtr
->items
[iItem
].fmt
;
825 nmitem
.lParam
= infoPtr
->items
[iItem
].lParam
;
826 nmitem
.iOrder
= infoPtr
->items
[iItem
].iOrder
;
827 nmitem
.iImage
= infoPtr
->items
[iItem
].iImage
;
831 nmhdr
.hdr
.hwndFrom
= hwnd
;
832 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
833 nmhdr
.hdr
.code
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
? code
: HEADER_NotifyCodeWtoA(code
));
836 nmhdr
.pitem
= lpItem
;
838 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
839 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
843 * Prepare callback items
844 * depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA
845 * (so we handle the two cases only doing a specific cast for pszText).
846 * Checks if any of the required field are callback. If there are sends a
847 * NMHDISPINFO notify to retrieve these items. The items are stored in the
848 * HEADER_ITEM pszText and iImage fields. They should be freed with
849 * HEADER_FreeCallbackItems.
851 * @param hwnd : hwnd header container handler
852 * @param iItem : the header item id
853 * @param reqMask : required fields. If any of them is callback this function will fetch it
855 * @return TRUE on success, else FALSE
858 HEADER_PrepareCallbackItems(HWND hwnd
, INT iItem
, INT reqMask
)
860 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
861 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
862 DWORD mask
= reqMask
& lpItem
->callbackMask
;
863 NMHDDISPINFOW dispInfo
;
864 void *pvBuffer
= NULL
;
868 if (mask
&HDI_TEXT
&& lpItem
->pszText
!= NULL
)
870 ERR("(): function called without a call to FreeCallbackItems\n");
871 Free(lpItem
->pszText
);
872 lpItem
->pszText
= NULL
;
875 memset(&dispInfo
, 0, sizeof(NMHDDISPINFOW
));
876 dispInfo
.hdr
.hwndFrom
= hwnd
;
877 dispInfo
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
878 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
880 dispInfo
.hdr
.code
= HDN_GETDISPINFOW
;
882 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(WCHAR
));
886 dispInfo
.hdr
.code
= HDN_GETDISPINFOA
;
888 pvBuffer
= Alloc(MAX_HEADER_TEXT_LEN
* sizeof(CHAR
));
890 dispInfo
.pszText
= (LPWSTR
)pvBuffer
;
891 dispInfo
.cchTextMax
= (pvBuffer
!=NULL
?MAX_HEADER_TEXT_LEN
:0);
892 dispInfo
.iItem
= iItem
;
893 dispInfo
.mask
= mask
;
894 dispInfo
.lParam
= lpItem
->lParam
;
896 TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr
->nNotifyFormat
== NFR_UNICODE
?'W':'A');
897 SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
,
898 (WPARAM
) dispInfo
.hdr
.idFrom
,
901 TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n",
903 (infoPtr
->nNotifyFormat
== NFR_UNICODE
? debugstr_w(dispInfo
.pszText
) : (LPSTR
) dispInfo
.pszText
),
904 (void*) dispInfo
.lParam
);
906 if (mask
& HDI_IMAGE
)
907 lpItem
->iImage
= dispInfo
.iImage
;
910 if (infoPtr
->nNotifyFormat
== NFR_UNICODE
)
912 lpItem
->pszText
= (LPWSTR
)pvBuffer
;
914 /* the user might have used his own buffer */
915 if (dispInfo
.pszText
!= lpItem
->pszText
)
916 Str_GetPtrW(dispInfo
.pszText
, lpItem
->pszText
, MAX_HEADER_TEXT_LEN
);
920 Str_SetPtrAtoW(&lpItem
->pszText
, (LPSTR
)dispInfo
.pszText
);
925 if (dispInfo
.mask
& HDI_DI_SETITEM
)
927 /* make the items permanent */
928 lpItem
->callbackMask
&= ~dispInfo
.mask
;
936 * Free the items that might be allocated with HEADER_PrepareCallbackItems
939 * [I] lpItem : the item to free the data
943 HEADER_FreeCallbackItems(HEADER_ITEM
*lpItem
)
945 if (lpItem
->callbackMask
&HDI_TEXT
&& lpItem
->pszText
!= NULL
)
947 Free(lpItem
->pszText
);
948 lpItem
->pszText
= NULL
;
951 if (lpItem
->callbackMask
&HDI_IMAGE
)
952 lpItem
->iImage
= I_IMAGECALLBACK
;
956 HEADER_SendClickNotify (HWND hwnd
, UINT code
, INT iItem
)
958 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
961 nmhdr
.hdr
.hwndFrom
= hwnd
;
962 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
963 nmhdr
.hdr
.code
= code
;
968 return (BOOL
)SendMessageA (infoPtr
->hwndNotify
, WM_NOTIFY
,
969 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
973 HEADER_CreateDragImage (HWND hwnd
, WPARAM wParam
)
975 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
978 HBITMAP hMemory
, hOldBitmap
;
983 if (wParam
< 0 || wParam
>= infoPtr
->uNumItem
)
985 lpItem
= &infoPtr
->items
[wParam
];
986 width
= lpItem
->rect
.right
- lpItem
->rect
.left
;
987 height
= lpItem
->rect
.bottom
- lpItem
->rect
.top
;
989 hDeviceDC
= GetDC(NULL
);
990 hMemoryDC
= CreateCompatibleDC(hDeviceDC
);
991 hMemory
= CreateCompatibleBitmap(hDeviceDC
, width
, height
);
992 ReleaseDC(NULL
, hDeviceDC
);
993 hOldBitmap
= SelectObject(hMemoryDC
, hMemory
);
994 SetViewportOrgEx(hMemoryDC
, -lpItem
->rect
.left
, -lpItem
->rect
.top
, NULL
);
995 HEADER_DrawItem(hwnd
, hMemoryDC
, wParam
, FALSE
);
996 hMemory
= SelectObject(hMemoryDC
, hOldBitmap
);
999 if (hMemory
== NULL
) /* if anything failed */
1002 himl
= ImageList_Create(width
, height
, ILC_COLORDDB
, 1, 1);
1003 ImageList_Add(himl
, hMemory
, NULL
);
1004 DeleteObject(hMemory
);
1005 return (LRESULT
)himl
;
1009 HEADER_SetHotDivider(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1011 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1019 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1021 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &iDivider
);
1023 if (flags
& HHT_TOLEFT
)
1025 else if (flags
& HHT_NOWHERE
|| flags
& HHT_TORIGHT
)
1026 iDivider
= infoPtr
->uNumItem
;
1029 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iDivider
];
1030 if (pt
.x
> (lpItem
->rect
.left
+lpItem
->rect
.right
)/2)
1031 iDivider
= HEADER_NextItem(hwnd
, iDivider
);
1035 iDivider
= (INT
)lParam
;
1037 /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */
1038 if (iDivider
<-1 || iDivider
>(int)infoPtr
->uNumItem
)
1041 if (iDivider
!= infoPtr
->iHotDivider
)
1043 if (infoPtr
->iHotDivider
!= -1)
1045 HEADER_GetHotDividerRect(hwnd
, infoPtr
, &r
);
1046 InvalidateRect(hwnd
, &r
, FALSE
);
1048 infoPtr
->iHotDivider
= iDivider
;
1051 HEADER_GetHotDividerRect(hwnd
, infoPtr
, &r
);
1052 InvalidateRect(hwnd
, &r
, FALSE
);
1059 HEADER_DeleteItem (HWND hwnd
, WPARAM wParam
)
1061 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1062 INT iItem
= (INT
)wParam
;
1064 TRACE("[iItem=%d]\n", iItem
);
1066 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
1069 if (infoPtr
->uNumItem
== 1) {
1070 TRACE("Simple delete!\n");
1071 HEADER_DisposeItem(&infoPtr
->items
[0]);
1072 Free (infoPtr
->items
);
1073 Free(infoPtr
->order
);
1076 infoPtr
->uNumItem
= 0;
1079 HEADER_ITEM
*oldItems
= infoPtr
->items
;
1082 TRACE("Complex delete! [iItem=%d]\n", iItem
);
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
);
1086 HEADER_DisposeItem(&infoPtr
->items
[iItem
]);
1087 iOrder
= infoPtr
->items
[iItem
].iOrder
;
1089 infoPtr
->uNumItem
--;
1090 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
1091 /* pre delete copy */
1093 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1094 iItem
* sizeof(HEADER_ITEM
));
1097 /* post delete copy */
1098 if (iItem
< infoPtr
->uNumItem
) {
1099 memcpy (&infoPtr
->items
[iItem
], &oldItems
[iItem
+1],
1100 (infoPtr
->uNumItem
- iItem
) * sizeof(HEADER_ITEM
));
1103 /* Correct the orders */
1104 if (iOrder
< infoPtr
->uNumItem
)
1106 memmove(&infoPtr
->order
[iOrder
], &infoPtr
->order
[iOrder
+ 1],
1107 (infoPtr
->uNumItem
- iOrder
) * sizeof(INT
));
1108 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1110 if (infoPtr
->order
[i
] > iItem
)
1111 infoPtr
->order
[i
]--;
1113 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1117 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1118 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
1122 HEADER_SetItemBounds (hwnd
);
1124 InvalidateRect(hwnd
, NULL
, FALSE
);
1131 HEADER_GetImageList (HWND hwnd
)
1133 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1135 return (LRESULT
)infoPtr
->himl
;
1140 HEADER_GetItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1142 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1143 HEADER_ITEM
*lpItem
;
1149 TRACE("[nItem=%d]\n", nItem
);
1155 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1158 if (mask
& HDI_UNKNOWN_FIELDS
)
1160 TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask
);
1161 mask
&= HDI_COMCTL32_4_0_FIELDS
;
1164 lpItem
= &infoPtr
->items
[nItem
];
1165 HEADER_PrepareCallbackItems(hwnd
, nItem
, mask
);
1167 if (mask
& HDI_BITMAP
)
1168 phdi
->hbm
= lpItem
->hbm
;
1170 if (mask
& HDI_FORMAT
)
1171 phdi
->fmt
= lpItem
->fmt
;
1173 if (mask
& HDI_WIDTH
)
1174 phdi
->cxy
= lpItem
->cxy
;
1176 if (mask
& HDI_LPARAM
)
1177 phdi
->lParam
= lpItem
->lParam
;
1179 if (mask
& HDI_IMAGE
)
1180 phdi
->iImage
= lpItem
->iImage
;
1182 if (mask
& HDI_ORDER
)
1183 phdi
->iOrder
= lpItem
->iOrder
;
1185 if (mask
& HDI_TEXT
)
1188 Str_GetPtrW (lpItem
->pszText
, phdi
->pszText
, phdi
->cchTextMax
);
1190 Str_GetPtrWtoA (lpItem
->pszText
, (LPSTR
)phdi
->pszText
, phdi
->cchTextMax
);
1193 HEADER_FreeCallbackItems(lpItem
);
1198 inline static LRESULT
1199 HEADER_GetItemCount (HWND hwnd
)
1201 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1202 return infoPtr
->uNumItem
;
1207 HEADER_GetItemRect (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1209 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1210 INT iItem
= (INT
)wParam
;
1211 LPRECT lpRect
= (LPRECT
)lParam
;
1213 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
1216 lpRect
->left
= infoPtr
->items
[iItem
].rect
.left
;
1217 lpRect
->right
= infoPtr
->items
[iItem
].rect
.right
;
1218 lpRect
->top
= infoPtr
->items
[iItem
].rect
.top
;
1219 lpRect
->bottom
= infoPtr
->items
[iItem
].rect
.bottom
;
1226 HEADER_GetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1228 LPINT order
= (LPINT
) lParam
;
1229 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1231 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
1234 memcpy(order
, infoPtr
->order
, infoPtr
->uNumItem
* sizeof(INT
));
1239 HEADER_SetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1242 LPINT order
= (LPINT
) lParam
;
1243 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1244 HEADER_ITEM
*lpItem
;
1246 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
1248 memcpy(infoPtr
->order
, order
, infoPtr
->uNumItem
* sizeof(INT
));
1249 for (i
=0; i
<(int)wParam
; i
++)
1251 lpItem
= &infoPtr
->items
[*order
++];
1254 infoPtr
->bRectsValid
=0;
1255 InvalidateRect(hwnd
, NULL
, FALSE
);
1259 inline static LRESULT
1260 HEADER_GetUnicodeFormat (HWND hwnd
)
1262 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1263 return (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1268 HEADER_HitTest (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1270 LPHDHITTESTINFO phti
= (LPHDHITTESTINFO
)lParam
;
1272 HEADER_InternalHitTest (hwnd
, &phti
->pt
, &phti
->flags
, &phti
->iItem
);
1274 if (phti
->flags
== HHT_NOWHERE
)
1282 HEADER_InsertItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1284 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1285 HEADER_ITEM
*lpItem
;
1290 if ((phdi
== NULL
) || (nItem
< 0) || (phdi
->mask
== 0))
1293 if (nItem
> infoPtr
->uNumItem
)
1294 nItem
= infoPtr
->uNumItem
;
1296 iOrder
= (phdi
->mask
& HDI_ORDER
) ? phdi
->iOrder
: nItem
;
1299 else if (infoPtr
->uNumItem
< iOrder
)
1300 iOrder
= infoPtr
->uNumItem
;
1302 if (infoPtr
->uNumItem
== 0) {
1303 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
));
1304 infoPtr
->order
= Alloc(sizeof(INT
));
1305 infoPtr
->uNumItem
++;
1308 HEADER_ITEM
*oldItems
= infoPtr
->items
;
1309 INT
*oldOrder
= infoPtr
->order
;
1311 infoPtr
->uNumItem
++;
1312 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
1314 memcpy (&infoPtr
->items
[1], &oldItems
[0],
1315 (infoPtr
->uNumItem
-1) * sizeof(HEADER_ITEM
));
1319 /* pre insert copy */
1321 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1322 nItem
* sizeof(HEADER_ITEM
));
1325 /* post insert copy */
1326 if (nItem
< infoPtr
->uNumItem
- 1) {
1327 memcpy (&infoPtr
->items
[nItem
+1], &oldItems
[nItem
],
1328 (infoPtr
->uNumItem
- nItem
- 1) * sizeof(HEADER_ITEM
));
1332 infoPtr
->order
= Alloc(sizeof(INT
) * infoPtr
->uNumItem
);
1333 memcpy(infoPtr
->order
, oldOrder
, iOrder
* sizeof(INT
));
1334 infoPtr
->order
[iOrder
] = nItem
;
1335 memcpy(&infoPtr
->order
[iOrder
+ 1], &oldOrder
[iOrder
],
1336 (infoPtr
->uNumItem
- iOrder
- 1) * sizeof(INT
));
1342 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1344 if (i
!= iOrder
&& infoPtr
->order
[i
] >= nItem
)
1345 infoPtr
->order
[i
]++;
1346 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1349 lpItem
= &infoPtr
->items
[nItem
];
1350 ZeroMemory(lpItem
, sizeof(HEADER_ITEM
));
1351 /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
1352 copyMask
= phdi
->mask
| HDI_WIDTH
| HDI_FORMAT
| HDI_LPARAM
;
1353 HEADER_StoreHDItemInHeader(lpItem
, copyMask
, phdi
, bUnicode
);
1355 /* set automatically some format bits */
1356 if (phdi
->mask
& HDI_TEXT
)
1357 lpItem
->fmt
|= HDF_STRING
;
1359 lpItem
->fmt
&= ~HDF_STRING
;
1361 if (lpItem
->hbm
!= NULL
)
1362 lpItem
->fmt
|= HDF_BITMAP
;
1364 lpItem
->fmt
&= ~HDF_BITMAP
;
1366 if (phdi
->mask
& HDI_IMAGE
)
1367 lpItem
->fmt
|= HDF_IMAGE
;
1369 lpItem
->iOrder
= iOrder
;
1371 HEADER_SetItemBounds (hwnd
);
1373 InvalidateRect(hwnd
, NULL
, FALSE
);
1380 HEADER_Layout (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1382 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1383 LPHDLAYOUT lpLayout
= (LPHDLAYOUT
)lParam
;
1385 lpLayout
->pwpos
->hwnd
= hwnd
;
1386 lpLayout
->pwpos
->hwndInsertAfter
= 0;
1387 lpLayout
->pwpos
->x
= lpLayout
->prc
->left
;
1388 lpLayout
->pwpos
->y
= lpLayout
->prc
->top
;
1389 lpLayout
->pwpos
->cx
= lpLayout
->prc
->right
- lpLayout
->prc
->left
;
1390 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_HIDDEN
)
1391 lpLayout
->pwpos
->cy
= 0;
1393 lpLayout
->pwpos
->cy
= infoPtr
->nHeight
;
1394 lpLayout
->prc
->top
+= infoPtr
->nHeight
;
1396 lpLayout
->pwpos
->flags
= SWP_NOZORDER
;
1398 TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1399 lpLayout
->pwpos
->x
, lpLayout
->pwpos
->y
,
1400 lpLayout
->pwpos
->cx
, lpLayout
->pwpos
->cy
);
1402 infoPtr
->bRectsValid
= FALSE
;
1409 HEADER_SetImageList (HWND hwnd
, HIMAGELIST himl
)
1411 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1414 TRACE("(himl %p)\n", himl
);
1415 himlOld
= infoPtr
->himl
;
1416 infoPtr
->himl
= himl
;
1418 /* FIXME: Refresh needed??? */
1420 return (LRESULT
)himlOld
;
1425 HEADER_GetBitmapMargin(HWND hwnd
)
1427 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1429 return infoPtr
->iMargin
;
1433 HEADER_SetBitmapMargin(HWND hwnd
, WPARAM wParam
)
1435 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1436 INT oldMargin
= infoPtr
->iMargin
;
1438 infoPtr
->iMargin
= (INT
)wParam
;
1444 HEADER_SetItemT (HWND hwnd
, INT nItem
, LPHDITEMW phdi
, BOOL bUnicode
)
1446 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1447 HEADER_ITEM
*lpItem
;
1453 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1456 TRACE("[nItem=%d]\n", nItem
);
1458 HEADER_CopyHDItemForNotify(infoPtr
, &hdNotify
, phdi
, bUnicode
, &pvScratch
);
1459 if (HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGINGW
, nItem
, phdi
->mask
, &hdNotify
))
1461 if (pvScratch
) Free(pvScratch
);
1465 lpItem
= &infoPtr
->items
[nItem
];
1466 HEADER_StoreHDItemInHeader(lpItem
, phdi
->mask
, phdi
, bUnicode
);
1468 if (phdi
->mask
& HDI_ORDER
)
1469 if (phdi
->iOrder
>= 0 && phdi
->iOrder
< infoPtr
->uNumItem
)
1470 HEADER_ChangeItemOrder(infoPtr
, nItem
, phdi
->iOrder
);
1472 HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGEDW
, nItem
, phdi
->mask
, &hdNotify
);
1474 HEADER_SetItemBounds (hwnd
);
1476 InvalidateRect(hwnd
, NULL
, FALSE
);
1478 if (pvScratch
!= NULL
)
1483 inline static LRESULT
1484 HEADER_SetUnicodeFormat (HWND hwnd
, WPARAM wParam
)
1486 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1487 BOOL bTemp
= (infoPtr
->nNotifyFormat
== NFR_UNICODE
);
1489 infoPtr
->nNotifyFormat
= ((BOOL
)wParam
? NFR_UNICODE
: NFR_ANSI
);
1496 HEADER_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1498 HEADER_INFO
*infoPtr
;
1503 infoPtr
= (HEADER_INFO
*)Alloc (sizeof(HEADER_INFO
));
1504 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
1506 infoPtr
->hwndNotify
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1507 infoPtr
->uNumItem
= 0;
1511 infoPtr
->bRectsValid
= FALSE
;
1512 infoPtr
->hcurArrow
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1513 infoPtr
->hcurDivider
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDER
));
1514 infoPtr
->hcurDivopen
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDEROPEN
));
1515 infoPtr
->bPressed
= FALSE
;
1516 infoPtr
->bTracking
= FALSE
;
1517 infoPtr
->iMoveItem
= 0;
1519 infoPtr
->iHotItem
= -1;
1520 infoPtr
->iHotDivider
= -1;
1521 infoPtr
->iMargin
= 3*GetSystemMetrics(SM_CXEDGE
);
1522 infoPtr
->nNotifyFormat
=
1523 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
1526 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1527 GetTextMetricsW (hdc
, &tm
);
1528 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1529 SelectObject (hdc
, hOldFont
);
1532 OpenThemeData(hwnd
, themeClass
);
1539 HEADER_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1541 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1542 HEADER_ITEM
*lpItem
;
1546 if (infoPtr
->items
) {
1547 lpItem
= infoPtr
->items
;
1548 for (nItem
= 0; nItem
< infoPtr
->uNumItem
; nItem
++, lpItem
++) {
1549 HEADER_DisposeItem(lpItem
);
1551 Free (infoPtr
->items
);
1555 Free(infoPtr
->order
);
1558 ImageList_Destroy (infoPtr
->himl
);
1560 SetWindowLongPtrW (hwnd
, 0, 0);
1563 theme
= GetWindowTheme(hwnd
);
1564 CloseThemeData(theme
);
1569 static inline LRESULT
1570 HEADER_GetFont (HWND hwnd
)
1572 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1574 return (LRESULT
)infoPtr
->hFont
;
1579 HEADER_IsDragDistance(HEADER_INFO
*infoPtr
, POINT
*pt
)
1581 /* Windows allows for a mouse movement before starting the drag. We use the
1582 * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance.
1584 return (abs(infoPtr
->ptLButtonDown
.x
- pt
->x
)>GetSystemMetrics(SM_CXDOUBLECLK
) ||
1585 abs(infoPtr
->ptLButtonDown
.y
- pt
->y
)>GetSystemMetrics(SM_CYDOUBLECLK
));
1589 HEADER_LButtonDblClk (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1595 pt
.x
= (INT
)LOWORD(lParam
);
1596 pt
.y
= (INT
)HIWORD(lParam
);
1597 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1599 if ((GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) && (flags
== HHT_ONHEADER
))
1600 HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMDBLCLICKW
, nItem
, 0, NULL
);
1601 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
))
1602 HEADER_SendHeaderNotifyT (hwnd
, HDN_DIVIDERDBLCLICKW
, nItem
, 0, NULL
);
1609 HEADER_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1611 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1612 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1618 pt
.x
= (INT
)LOWORD(lParam
);
1619 pt
.y
= (INT
)HIWORD(lParam
);
1620 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1622 if ((dwStyle
& HDS_BUTTONS
) && (flags
== HHT_ONHEADER
)) {
1624 infoPtr
->bCaptured
= TRUE
;
1625 infoPtr
->bPressed
= TRUE
;
1626 infoPtr
->bDragging
= FALSE
;
1627 infoPtr
->iMoveItem
= nItem
;
1628 infoPtr
->ptLButtonDown
= pt
;
1630 infoPtr
->items
[nItem
].bDown
= TRUE
;
1632 /* Send WM_CUSTOMDRAW */
1634 HEADER_RefreshItem (hwnd
, hdc
, nItem
);
1635 ReleaseDC (hwnd
, hdc
);
1637 TRACE("Pressed item %d!\n", nItem
);
1639 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
)) {
1640 if (!(HEADER_SendHeaderNotifyT (hwnd
, HDN_BEGINTRACKW
, nItem
, HDI_WIDTH
, NULL
))) {
1642 infoPtr
->bCaptured
= TRUE
;
1643 infoPtr
->bTracking
= TRUE
;
1644 infoPtr
->iMoveItem
= nItem
;
1645 infoPtr
->nOldWidth
= infoPtr
->items
[nItem
].cxy
;
1646 infoPtr
->xTrackOffset
= infoPtr
->items
[nItem
].rect
.right
- pt
.x
;
1648 if (!(dwStyle
& HDS_FULLDRAG
)) {
1649 infoPtr
->xOldTrack
= infoPtr
->items
[nItem
].rect
.right
;
1651 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1652 ReleaseDC (hwnd
, hdc
);
1655 TRACE("Begin tracking item %d!\n", nItem
);
1664 HEADER_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1666 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1667 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1673 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1674 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1675 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1677 if (infoPtr
->bPressed
) {
1678 if (infoPtr
->bDragging
)
1680 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1683 ImageList_DragShowNolock(FALSE
);
1684 ImageList_EndDrag();
1685 lpItem
->bDown
=FALSE
;
1687 if (infoPtr
->iHotDivider
== -1)
1689 else if (infoPtr
->iHotDivider
== infoPtr
->uNumItem
)
1690 iNewOrder
= infoPtr
->uNumItem
-1;
1693 iNewOrder
= HEADER_IndexToOrder(hwnd
, infoPtr
->iHotDivider
);
1694 if (iNewOrder
> lpItem
->iOrder
)
1698 /* FIXME: the new order field should be sent, not the old one */
1699 if (iNewOrder
!= -1 &&
1700 !HEADER_SendHeaderNotifyT(hwnd
, HDN_ENDDRAG
, infoPtr
->iMoveItem
, HDI_ORDER
, NULL
))
1702 HEADER_ChangeItemOrder(infoPtr
, infoPtr
->iMoveItem
, iNewOrder
);
1703 infoPtr
->bRectsValid
= FALSE
;
1704 InvalidateRect(hwnd
, NULL
, FALSE
);
1707 InvalidateRect(hwnd
, &infoPtr
->items
[infoPtr
->iMoveItem
].rect
, FALSE
);
1709 HEADER_SetHotDivider(hwnd
, FALSE
, -1);
1711 else if (!(dwStyle
&HDS_DRAGDROP
) || !HEADER_IsDragDistance(infoPtr
, &pt
))
1713 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1715 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1716 ReleaseDC (hwnd
, hdc
);
1718 HEADER_SendClickNotify (hwnd
, HDN_ITEMCLICKA
, infoPtr
->iMoveItem
);
1721 TRACE("Released item %d!\n", infoPtr
->iMoveItem
);
1722 infoPtr
->bPressed
= FALSE
;
1724 else if (infoPtr
->bTracking
) {
1725 TRACE("End tracking item %d!\n", infoPtr
->iMoveItem
);
1726 infoPtr
->bTracking
= FALSE
;
1728 HEADER_SendHeaderNotifyT (hwnd
, HDN_ENDTRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1730 if (!(dwStyle
& HDS_FULLDRAG
)) {
1732 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1733 ReleaseDC (hwnd
, hdc
);
1736 if (HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
))
1738 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= infoPtr
->nOldWidth
;
1741 nWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1744 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1747 HEADER_SetItemBounds (hwnd
);
1748 InvalidateRect(hwnd
, NULL
, TRUE
);
1749 HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1752 if (infoPtr
->bCaptured
) {
1753 infoPtr
->bCaptured
= FALSE
;
1755 HEADER_SendSimpleNotify (hwnd
, NM_RELEASEDCAPTURE
);
1763 HEADER_NotifyFormat (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1765 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1770 return infoPtr
->nNotifyFormat
;
1773 infoPtr
->nNotifyFormat
=
1774 SendMessageW ((HWND
)wParam
, WM_NOTIFYFORMAT
,
1775 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
1776 return infoPtr
->nNotifyFormat
;
1783 HEADER_MouseLeave (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1785 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1786 /* Reset hot-tracked item when mouse leaves control. */
1787 INT oldHotItem
= infoPtr
->iHotItem
;
1788 HDC hdc
= GetDC (hwnd
);
1790 infoPtr
->iHotItem
= -1;
1791 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1792 ReleaseDC (hwnd
, hdc
);
1799 HEADER_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1801 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1802 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1807 /* With theming, hottracking is always enabled */
1808 BOOL hotTrackEnabled
=
1809 ((dwStyle
& HDS_BUTTONS
) && (dwStyle
& HDS_HOTTRACK
))
1810 || (GetWindowTheme (hwnd
) != NULL
);
1811 INT oldHotItem
= infoPtr
->iHotItem
;
1813 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1814 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1815 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1817 if (hotTrackEnabled
) {
1818 if (flags
& (HHT_ONHEADER
| HHT_ONDIVIDER
| HHT_ONDIVOPEN
))
1819 infoPtr
->iHotItem
= nItem
;
1821 infoPtr
->iHotItem
= -1;
1824 if (infoPtr
->bCaptured
) {
1825 /* check if we should drag the header */
1826 if (infoPtr
->bPressed
&& !infoPtr
->bDragging
&& dwStyle
&HDS_DRAGDROP
1827 && HEADER_IsDragDistance(infoPtr
, &pt
))
1829 if (!HEADER_SendHeaderNotifyT(hwnd
, HDN_BEGINDRAG
, infoPtr
->iMoveItem
, 0, NULL
))
1831 HIMAGELIST hDragItem
= (HIMAGELIST
)HEADER_CreateDragImage(hwnd
, infoPtr
->iMoveItem
);
1832 if (hDragItem
!= NULL
)
1834 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1835 TRACE("Starting item drag\n");
1836 ImageList_BeginDrag(hDragItem
, 0, pt
.x
- lpItem
->rect
.left
, 0);
1837 ImageList_DragShowNolock(TRUE
);
1838 ImageList_Destroy(hDragItem
);
1839 infoPtr
->bDragging
= TRUE
;
1844 if (infoPtr
->bDragging
)
1849 ClientToScreen(hwnd
, &drag
);
1850 ImageList_DragMove(drag
.x
, drag
.y
);
1851 HEADER_SetHotDivider(hwnd
, TRUE
, lParam
);
1854 if (infoPtr
->bPressed
&& !infoPtr
->bDragging
) {
1855 BOOL oldState
= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
;
1856 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
))
1857 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= TRUE
;
1859 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1860 if (oldState
!= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
) {
1862 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1863 ReleaseDC (hwnd
, hdc
);
1866 TRACE("Moving pressed item %d!\n", infoPtr
->iMoveItem
);
1868 else if (infoPtr
->bTracking
) {
1869 if (dwStyle
& HDS_FULLDRAG
) {
1870 if (!HEADER_SendHeaderNotifyT (hwnd
, HDN_ITEMCHANGINGW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
))
1872 HEADER_ITEM
*lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1873 INT nOldWidth
= lpItem
->rect
.right
- lpItem
->rect
.left
;
1877 nWidth
= pt
.x
- lpItem
->rect
.left
+ infoPtr
->xTrackOffset
;
1878 if (nWidth
< 0) nWidth
= 0;
1879 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1880 HEADER_SetItemBounds(hwnd
);
1882 GetClientRect(hwnd
, &rcClient
);
1883 rcScroll
= rcClient
;
1884 rcScroll
.left
= lpItem
->rect
.left
+ nOldWidth
;
1885 ScrollWindowEx(hwnd
, nWidth
- nOldWidth
, 0, &rcScroll
, &rcClient
, NULL
, NULL
, 0);
1886 InvalidateRect(hwnd
, &lpItem
->rect
, FALSE
);
1889 HEADER_SendHeaderNotifyT(hwnd
, HDN_ITEMCHANGEDW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1894 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1895 infoPtr
->xOldTrack
= pt
.x
+ infoPtr
->xTrackOffset
;
1896 if (infoPtr
->xOldTrack
< infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
)
1897 infoPtr
->xOldTrack
= infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1898 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
=
1899 infoPtr
->xOldTrack
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1900 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1901 ReleaseDC (hwnd
, hdc
);
1902 HEADER_SendHeaderNotifyT (hwnd
, HDN_TRACKW
, infoPtr
->iMoveItem
, HDI_WIDTH
, NULL
);
1905 TRACE("Tracking item %d!\n", infoPtr
->iMoveItem
);
1909 if (hotTrackEnabled
) {
1910 TRACKMOUSEEVENT tme
;
1911 if (oldHotItem
!= infoPtr
->iHotItem
&& !infoPtr
->bDragging
) {
1913 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1914 if (infoPtr
->iHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iHotItem
);
1915 ReleaseDC (hwnd
, hdc
);
1917 tme
.cbSize
= sizeof( tme
);
1918 tme
.dwFlags
= TME_LEAVE
;
1919 tme
.hwndTrack
= hwnd
;
1920 TrackMouseEvent( &tme
);
1928 HEADER_Paint (HWND hwnd
, WPARAM wParam
)
1933 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1934 HEADER_Refresh (hwnd
, hdc
);
1936 EndPaint (hwnd
, &ps
);
1942 HEADER_RButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1947 pt
.x
= LOWORD(lParam
);
1948 pt
.y
= HIWORD(lParam
);
1950 /* Send a Notify message */
1951 bRet
= HEADER_SendSimpleNotify (hwnd
, NM_RCLICK
);
1953 /* Change to screen coordinate for WM_CONTEXTMENU */
1954 ClientToScreen(hwnd
, &pt
);
1956 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1957 SendMessageW( hwnd
, WM_CONTEXTMENU
, (WPARAM
) hwnd
, MAKELPARAM(pt
.x
, pt
.y
));
1964 HEADER_SetCursor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1966 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1971 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam
), HIWORD(lParam
));
1974 ScreenToClient (hwnd
, &pt
);
1976 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1978 if (flags
== HHT_ONDIVIDER
)
1979 SetCursor (infoPtr
->hcurDivider
);
1980 else if (flags
== HHT_ONDIVOPEN
)
1981 SetCursor (infoPtr
->hcurDivopen
);
1983 SetCursor (infoPtr
->hcurArrow
);
1990 HEADER_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1992 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1994 HFONT hFont
, hOldFont
;
1997 infoPtr
->hFont
= (HFONT
)wParam
;
1999 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
2002 hOldFont
= SelectObject (hdc
, hFont
);
2003 GetTextMetricsW (hdc
, &tm
);
2004 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
2005 SelectObject (hdc
, hOldFont
);
2008 infoPtr
->bRectsValid
= FALSE
;
2011 InvalidateRect(hwnd
, NULL
, FALSE
);
2017 /* Update the theme handle after a theme change */
2018 static LRESULT
HEADER_ThemeChanged(HWND hwnd
)
2020 HTHEME theme
= GetWindowTheme(hwnd
);
2021 CloseThemeData(theme
);
2022 OpenThemeData(hwnd
, themeClass
);
2023 InvalidateRect(hwnd
, NULL
, FALSE
);
2028 static LRESULT WINAPI
2029 HEADER_WindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2031 TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd
, msg
, wParam
, lParam
);
2032 if (!HEADER_GetInfoPtr (hwnd
) && (msg
!= WM_CREATE
))
2033 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
2035 /* case HDM_CLEARFILTER: */
2037 case HDM_CREATEDRAGIMAGE
:
2038 return HEADER_CreateDragImage (hwnd
, wParam
);
2040 case HDM_DELETEITEM
:
2041 return HEADER_DeleteItem (hwnd
, wParam
);
2043 /* case HDM_EDITFILTER: */
2045 case HDM_GETBITMAPMARGIN
:
2046 return HEADER_GetBitmapMargin(hwnd
);
2048 case HDM_GETIMAGELIST
:
2049 return HEADER_GetImageList (hwnd
);
2053 return HEADER_GetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_GETITEMW
);
2055 case HDM_GETITEMCOUNT
:
2056 return HEADER_GetItemCount (hwnd
);
2058 case HDM_GETITEMRECT
:
2059 return HEADER_GetItemRect (hwnd
, wParam
, lParam
);
2061 case HDM_GETORDERARRAY
:
2062 return HEADER_GetOrderArray(hwnd
, wParam
, lParam
);
2064 case HDM_GETUNICODEFORMAT
:
2065 return HEADER_GetUnicodeFormat (hwnd
);
2068 return HEADER_HitTest (hwnd
, wParam
, lParam
);
2070 case HDM_INSERTITEMA
:
2071 case HDM_INSERTITEMW
:
2072 return HEADER_InsertItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_INSERTITEMW
);
2075 return HEADER_Layout (hwnd
, wParam
, lParam
);
2077 case HDM_ORDERTOINDEX
:
2078 return HEADER_OrderToIndex(hwnd
, wParam
);
2080 case HDM_SETBITMAPMARGIN
:
2081 return HEADER_SetBitmapMargin(hwnd
, wParam
);
2083 /* case HDM_SETFILTERCHANGETIMEOUT: */
2085 case HDM_SETHOTDIVIDER
:
2086 return HEADER_SetHotDivider(hwnd
, wParam
, lParam
);
2088 case HDM_SETIMAGELIST
:
2089 return HEADER_SetImageList (hwnd
, (HIMAGELIST
)lParam
);
2093 return HEADER_SetItemT (hwnd
, (INT
)wParam
, (LPHDITEMW
)lParam
, msg
== HDM_SETITEMW
);
2095 case HDM_SETORDERARRAY
:
2096 return HEADER_SetOrderArray(hwnd
, wParam
, lParam
);
2098 case HDM_SETUNICODEFORMAT
:
2099 return HEADER_SetUnicodeFormat (hwnd
, wParam
);
2102 return HEADER_Create (hwnd
, wParam
, lParam
);
2105 return HEADER_Destroy (hwnd
, wParam
, lParam
);
2111 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
2114 return HEADER_GetFont (hwnd
);
2116 case WM_LBUTTONDBLCLK
:
2117 return HEADER_LButtonDblClk (hwnd
, wParam
, lParam
);
2119 case WM_LBUTTONDOWN
:
2120 return HEADER_LButtonDown (hwnd
, wParam
, lParam
);
2123 return HEADER_LButtonUp (hwnd
, wParam
, lParam
);
2126 return HEADER_MouseLeave (hwnd
, wParam
, lParam
);
2129 return HEADER_MouseMove (hwnd
, wParam
, lParam
);
2131 case WM_NOTIFYFORMAT
:
2132 return HEADER_NotifyFormat (hwnd
, wParam
, lParam
);
2135 return HEADER_Size (hwnd
, wParam
);
2137 case WM_THEMECHANGED
:
2138 return HEADER_ThemeChanged (hwnd
);
2140 case WM_PRINTCLIENT
:
2142 return HEADER_Paint (hwnd
, wParam
);
2145 return HEADER_RButtonUp (hwnd
, wParam
, lParam
);
2148 return HEADER_SetCursor (hwnd
, wParam
, lParam
);
2151 return HEADER_SetFont (hwnd
, wParam
, lParam
);
2154 if ((msg
>= WM_USER
) && (msg
< WM_APP
))
2155 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
2156 msg
, wParam
, lParam
);
2157 return DefWindowProcA (hwnd
, msg
, wParam
, lParam
);
2163 HEADER_Register (void)
2167 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
2168 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
2169 wndClass
.lpfnWndProc
= HEADER_WindowProc
;
2170 wndClass
.cbClsExtra
= 0;
2171 wndClass
.cbWndExtra
= sizeof(HEADER_INFO
*);
2172 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
2173 wndClass
.lpszClassName
= WC_HEADERW
;
2175 RegisterClassW (&wndClass
);
2180 HEADER_Unregister (void)
2182 UnregisterClassW (WC_HEADERW
, NULL
);