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 BOOL bUnicode
; /* Unicode flag */
81 INT iMoveItem
; /* index of tracked item. (Tracking mode) */
82 INT xTrackOffset
; /* distance between the right side of the tracked item and the cursor */
83 INT xOldTrack
; /* track offset (see above) after the last WM_MOUSEMOVE */
84 INT nOldWidth
; /* width of a sizing item after the last WM_MOUSEMOVE */
85 INT iHotItem
; /* index of hot item (cursor is over this item) */
86 INT iMargin
; /* width of the margin that surrounds a bitmap */
88 HIMAGELIST himl
; /* handle to an image list (may be 0) */
89 HEADER_ITEM
*items
; /* pointer to array of HEADER_ITEM's */
90 INT
*order
; /* array of item IDs indexed by order */
91 BOOL bRectsValid
; /* validity flag for bounding rectangles */
96 #define DIVIDER_WIDTH 10
98 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0))
100 static const WCHAR themeClass
[] = {'H','e','a','d','e','r',0};
103 inline static LRESULT
104 HEADER_IndexToOrder (HWND hwnd
, INT iItem
)
106 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
107 HEADER_ITEM
*lpItem
= &infoPtr
->items
[iItem
];
108 return lpItem
->iOrder
;
113 HEADER_OrderToIndex(HWND hwnd
, WPARAM wParam
)
115 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
116 INT iorder
= (INT
)wParam
;
118 if ((iorder
<0) || iorder
>= infoPtr
->uNumItem
)
120 return infoPtr
->order
[iorder
];
124 HEADER_SetItemBounds (HWND hwnd
)
126 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
132 infoPtr
->bRectsValid
= TRUE
;
134 if (infoPtr
->uNumItem
== 0)
137 GetClientRect (hwnd
, &rect
);
140 for (i
= 0; i
< infoPtr
->uNumItem
; i
++) {
141 phdi
= &infoPtr
->items
[HEADER_OrderToIndex(hwnd
,i
)];
142 phdi
->rect
.top
= rect
.top
;
143 phdi
->rect
.bottom
= rect
.bottom
;
145 phdi
->rect
.right
= phdi
->rect
.left
+ ((phdi
->cxy
>0)?phdi
->cxy
:0);
146 x
= phdi
->rect
.right
;
151 HEADER_Size (HWND hwnd
, WPARAM wParam
)
153 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
155 infoPtr
->bRectsValid
= FALSE
;
162 HEADER_DrawItem (HWND hwnd
, HDC hdc
, INT iItem
, BOOL bHotTrack
)
164 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
165 HEADER_ITEM
*phdi
= &infoPtr
->items
[iItem
];
167 INT oldBkMode
, cxEdge
= GetSystemMetrics(SM_CXEDGE
);
168 HTHEME theme
= GetWindowTheme (hwnd
);
170 TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem
, bHotTrack
, infoPtr
->bUnicode
);
172 if (!infoPtr
->bRectsValid
)
173 HEADER_SetItemBounds(hwnd
);
176 if (r
.right
- r
.left
== 0)
177 return phdi
->rect
.right
;
180 int state
= (phdi
->bDown
) ? HIS_PRESSED
:
181 (bHotTrack
? HIS_HOT
: HIS_NORMAL
);
182 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, state
,
184 GetThemeBackgroundContentRect (theme
, hdc
, HP_HEADERITEM
, state
,
188 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) {
190 DrawEdge (hdc
, &r
, BDR_RAISEDOUTER
,
191 BF_RECT
| BF_FLAT
| BF_MIDDLE
| BF_ADJUST
);
194 DrawEdge (hdc
, &r
, EDGE_RAISED
,
195 BF_RECT
| BF_SOFT
| BF_MIDDLE
| BF_ADJUST
);
198 DrawEdge (hdc
, &r
, EDGE_ETCHED
, BF_BOTTOM
| BF_RIGHT
| BF_ADJUST
);
208 if (phdi
->fmt
& HDF_OWNERDRAW
) {
212 nmcd
.hdr
.hwndFrom
= hwnd
;
213 nmcd
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
214 nmcd
.hdr
.code
= NM_CUSTOMDRAW
;
215 nmcd
.dwDrawStage
= CDDS_PREPAINT
| CDDS_ITEM
| CDDS_ITEMPOSTERASE
;
217 nmcd
.dwItemSpec
= iItem
;
219 nmcd
.uItemState
= phdi
->bDown
? CDIS_SELECTED
: 0;
220 nmcd
.lItemlParam
= phdi
->lParam
;
222 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
223 (WPARAM
)nmcd
.hdr
.idFrom
, (LPARAM
)&nmcd
);
225 dis
.CtlType
= ODT_HEADER
;
226 dis
.CtlID
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
228 dis
.itemAction
= ODA_DRAWENTIRE
;
229 dis
.itemState
= phdi
->bDown
? ODS_SELECTED
: 0;
233 dis
.itemData
= phdi
->lParam
;
234 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
235 SendMessageW (infoPtr
->hwndNotify
, WM_DRAWITEM
,
236 (WPARAM
)dis
.CtlID
, (LPARAM
)&dis
);
237 if (oldBkMode
!= TRANSPARENT
)
238 SetBkMode(hdc
, oldBkMode
);
241 UINT rw
, rh
, /* width and height of r */
242 *x
= NULL
, *w
= NULL
; /* x and width of the pic (bmp or img) which is part of cnt */
243 /* cnt,txt,img,bmp */
248 cw
= tw
= iw
= bw
= 0;
249 rw
= r
.right
- r
.left
;
250 rh
= r
.bottom
- r
.top
;
252 if (phdi
->fmt
& HDF_STRING
) {
255 DrawTextW (hdc
, phdi
->pszText
, -1,
256 &textRect
, DT_LEFT
|DT_VCENTER
|DT_SINGLELINE
|DT_CALCRECT
);
257 cw
= textRect
.right
- textRect
.left
+ 2 * infoPtr
->iMargin
;
260 if ((phdi
->fmt
& HDF_IMAGE
) && (infoPtr
->himl
)) {
261 iw
= infoPtr
->himl
->cx
+ 2 * infoPtr
->iMargin
;
266 if ((phdi
->fmt
& HDF_BITMAP
) && (phdi
->hbm
)) {
267 GetObjectW (phdi
->hbm
, sizeof(BITMAP
), (LPVOID
)&bmp
);
268 bw
= bmp
.bmWidth
+ 2 * infoPtr
->iMargin
;
278 /* align cx using the unclipped cw */
279 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_LEFT
)
281 else if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_CENTER
)
282 cx
= r
.left
+ rw
/ 2 - cw
/ 2;
289 if (cx
+ cw
> r
.right
)
292 tx
= cx
+ infoPtr
->iMargin
;
293 /* since cw might have changed we have to recalculate tw */
294 tw
= cw
- infoPtr
->iMargin
* 2;
298 if (phdi
->fmt
& HDF_BITMAP_ON_RIGHT
) {
299 /* put pic behind text */
300 *x
= cx
+ tw
+ infoPtr
->iMargin
* 3;
302 *x
= cx
+ infoPtr
->iMargin
;
303 /* move text behind pic */
309 /* since we're done with the layout we can
310 now calculate the position of bmp which
311 has no influence on alignment and layout
313 if ((phdi
->fmt
& HDF_JUSTIFYMASK
) == HDF_RIGHT
)
314 bx
= cx
- bw
+ infoPtr
->iMargin
;
316 bx
= cx
+ cw
+ infoPtr
->iMargin
;
320 HDC hClipDC
= GetDC(hwnd
);
321 HRGN hClipRgn
= CreateRectRgn(r
.left
, r
.top
, r
.right
, r
.bottom
);
322 SelectClipRgn(hClipDC
, hClipRgn
);
325 HDC hdcBitmap
= CreateCompatibleDC (hClipDC
);
326 SelectObject (hdcBitmap
, phdi
->hbm
);
327 BitBlt (hClipDC
, bx
, r
.top
+ ((INT
)rh
- bmp
.bmHeight
) / 2,
328 bmp
.bmWidth
, bmp
.bmHeight
, hdcBitmap
, 0, 0, SRCCOPY
);
329 DeleteDC (hdcBitmap
);
333 ImageList_DrawEx (infoPtr
->himl
, phdi
->iImage
, hClipDC
,
334 ix
, r
.top
+ ((INT
)rh
- infoPtr
->himl
->cy
) / 2,
335 infoPtr
->himl
->cx
, infoPtr
->himl
->cy
, CLR_DEFAULT
, CLR_DEFAULT
, 0);
338 DeleteObject(hClipRgn
);
339 ReleaseDC(hwnd
, hClipDC
);
342 if (((phdi
->fmt
& HDF_STRING
)
343 || (!(phdi
->fmt
& (HDF_OWNERDRAW
|HDF_STRING
|HDF_BITMAP
|
344 HDF_BITMAP_ON_RIGHT
|HDF_IMAGE
)))) /* no explicit format specified? */
345 && (phdi
->pszText
)) {
346 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
347 SetTextColor (hdc
, (bHotTrack
&& !theme
) ? COLOR_HIGHLIGHT
: COLOR_BTNTEXT
);
350 DrawTextW (hdc
, phdi
->pszText
, -1,
351 &r
, DT_LEFT
|DT_END_ELLIPSIS
|DT_VCENTER
|DT_SINGLELINE
);
352 if (oldBkMode
!= TRANSPARENT
)
353 SetBkMode(hdc
, oldBkMode
);
357 return phdi
->rect
.right
;
362 HEADER_Refresh (HWND hwnd
, HDC hdc
)
364 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
365 HFONT hFont
, hOldFont
;
370 HTHEME theme
= GetWindowTheme (hwnd
);
372 /* get rect for the bar, adjusted for the border */
373 GetClientRect (hwnd
, &rect
);
375 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
376 hOldFont
= SelectObject (hdc
, hFont
);
378 /* draw Background */
380 hbrBk
= GetSysColorBrush(COLOR_3DFACE
);
381 FillRect(hdc
, &rect
, hbrBk
);
385 for (i
= 0; x
<= rect
.right
&& i
< infoPtr
->uNumItem
; i
++) {
386 x
= HEADER_DrawItem (hwnd
, hdc
, HEADER_OrderToIndex(hwnd
,i
),
387 infoPtr
->iHotItem
== i
);
390 if ((x
<= rect
.right
) && (infoPtr
->uNumItem
> 0)) {
393 DrawThemeBackground (theme
, hdc
, HP_HEADERITEM
, HIS_NORMAL
, &rect
,
397 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
)
398 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_TOP
|BF_LEFT
|BF_BOTTOM
|BF_SOFT
);
400 DrawEdge (hdc
, &rect
, EDGE_ETCHED
, BF_BOTTOM
);
404 SelectObject (hdc
, hOldFont
);
409 HEADER_RefreshItem (HWND hwnd
, HDC hdc
, INT iItem
)
411 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
412 HFONT hFont
, hOldFont
;
414 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
415 hOldFont
= SelectObject (hdc
, hFont
);
416 HEADER_DrawItem (hwnd
, hdc
, iItem
, infoPtr
->iHotItem
== iItem
);
417 SelectObject (hdc
, hOldFont
);
422 HEADER_InternalHitTest (HWND hwnd
, LPPOINT lpPt
, UINT
*pFlags
, INT
*pItem
)
424 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
430 GetClientRect (hwnd
, &rect
);
434 if (PtInRect (&rect
, *lpPt
))
436 if (infoPtr
->uNumItem
== 0) {
437 *pFlags
|= HHT_NOWHERE
;
443 /* somewhere inside */
444 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++) {
445 rect
= infoPtr
->items
[iCount
].rect
;
446 width
= rect
.right
- rect
.left
;
451 if (PtInRect (&rect
, *lpPt
)) {
452 if (width
<= 2 * DIVIDER_WIDTH
) {
453 *pFlags
|= HHT_ONHEADER
;
455 TRACE("ON HEADER %d\n", iCount
);
460 rcTest
.right
= rcTest
.left
+ DIVIDER_WIDTH
;
461 if (PtInRect (&rcTest
, *lpPt
)) {
463 *pFlags
|= HHT_ONDIVOPEN
;
465 TRACE("ON DIVOPEN %d\n", *pItem
);
469 *pFlags
|= HHT_ONDIVIDER
;
471 TRACE("ON DIVIDER %d\n", *pItem
);
477 rcTest
.left
= rcTest
.right
- DIVIDER_WIDTH
;
478 if (PtInRect (&rcTest
, *lpPt
)) {
479 *pFlags
|= HHT_ONDIVIDER
;
481 TRACE("ON DIVIDER %d\n", *pItem
);
485 *pFlags
|= HHT_ONHEADER
;
487 TRACE("ON HEADER %d\n", iCount
);
492 /* check for last divider part (on nowhere) */
493 rect
= infoPtr
->items
[infoPtr
->uNumItem
-1].rect
;
494 rect
.left
= rect
.right
;
495 rect
.right
+= DIVIDER_WIDTH
;
496 if (PtInRect (&rect
, *lpPt
)) {
498 *pFlags
|= HHT_ONDIVOPEN
;
499 *pItem
= infoPtr
->uNumItem
- 1;
500 TRACE("ON DIVOPEN %d\n", *pItem
);
504 *pFlags
|= HHT_ONDIVIDER
;
505 *pItem
= infoPtr
->uNumItem
-1;
506 TRACE("ON DIVIDER %d\n", *pItem
);
511 *pFlags
|= HHT_NOWHERE
;
518 if (lpPt
->x
< rect
.left
) {
520 *pFlags
|= HHT_TOLEFT
;
522 else if (lpPt
->x
> rect
.right
) {
524 *pFlags
|= HHT_TORIGHT
;
527 if (lpPt
->y
< rect
.top
) {
529 *pFlags
|= HHT_ABOVE
;
531 else if (lpPt
->y
> rect
.bottom
) {
533 *pFlags
|= HHT_BELOW
;
538 TRACE("flags=0x%X\n", *pFlags
);
544 HEADER_DrawTrackLine (HWND hwnd
, HDC hdc
, INT x
)
550 GetClientRect (hwnd
, &rect
);
552 hOldPen
= SelectObject (hdc
, GetStockObject (BLACK_PEN
));
553 oldRop
= SetROP2 (hdc
, R2_XORPEN
);
554 MoveToEx (hdc
, x
, rect
.top
, NULL
);
555 LineTo (hdc
, x
, rect
.bottom
);
556 SetROP2 (hdc
, oldRop
);
557 SelectObject (hdc
, hOldPen
);
562 HEADER_SendSimpleNotify (HWND hwnd
, UINT code
)
564 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
567 nmhdr
.hwndFrom
= hwnd
;
568 nmhdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
571 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
572 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
576 HEADER_SendHeaderNotify (HWND hwnd
, UINT code
, INT iItem
, INT mask
)
578 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
582 nmhdr
.hdr
.hwndFrom
= hwnd
;
583 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
584 nmhdr
.hdr
.code
= code
;
587 nmhdr
.pitem
= &nmitem
;
589 nmitem
.cxy
= infoPtr
->items
[iItem
].cxy
;
590 nmitem
.hbm
= infoPtr
->items
[iItem
].hbm
;
591 nmitem
.pszText
= NULL
;
592 nmitem
.cchTextMax
= 0;
593 /* nmitem.pszText = infoPtr->items[iItem].pszText; */
594 /* nmitem.cchTextMax = infoPtr->items[iItem].cchTextMax; */
595 nmitem
.fmt
= infoPtr
->items
[iItem
].fmt
;
596 nmitem
.lParam
= infoPtr
->items
[iItem
].lParam
;
597 nmitem
.iOrder
= infoPtr
->items
[iItem
].iOrder
;
598 nmitem
.iImage
= infoPtr
->items
[iItem
].iImage
;
600 return (BOOL
)SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
,
601 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
606 HEADER_SendClickNotify (HWND hwnd
, UINT code
, INT iItem
)
608 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
611 nmhdr
.hdr
.hwndFrom
= hwnd
;
612 nmhdr
.hdr
.idFrom
= GetWindowLongPtrW (hwnd
, GWLP_ID
);
613 nmhdr
.hdr
.code
= code
;
618 return (BOOL
)SendMessageA (infoPtr
->hwndNotify
, WM_NOTIFY
,
619 (WPARAM
)nmhdr
.hdr
.idFrom
, (LPARAM
)&nmhdr
);
624 HEADER_CreateDragImage (HWND hwnd
, WPARAM wParam
)
626 FIXME("empty stub!\n");
632 HEADER_DeleteItem (HWND hwnd
, WPARAM wParam
)
634 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
635 INT iItem
= (INT
)wParam
;
637 TRACE("[iItem=%d]\n", iItem
);
639 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
642 if (infoPtr
->uNumItem
== 1) {
643 TRACE("Simple delete!\n");
644 if (infoPtr
->items
[0].pszText
)
645 Free (infoPtr
->items
[0].pszText
);
646 Free (infoPtr
->items
);
647 Free(infoPtr
->order
);
650 infoPtr
->uNumItem
= 0;
653 HEADER_ITEM
*oldItems
= infoPtr
->items
;
656 TRACE("Complex delete! [iItem=%d]\n", iItem
);
658 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
659 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
660 if (infoPtr
->items
[iItem
].pszText
)
661 Free (infoPtr
->items
[iItem
].pszText
);
662 iOrder
= infoPtr
->items
[iItem
].iOrder
;
665 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
666 /* pre delete copy */
668 memcpy (&infoPtr
->items
[0], &oldItems
[0],
669 iItem
* sizeof(HEADER_ITEM
));
672 /* post delete copy */
673 if (iItem
< infoPtr
->uNumItem
) {
674 memcpy (&infoPtr
->items
[iItem
], &oldItems
[iItem
+1],
675 (infoPtr
->uNumItem
- iItem
) * sizeof(HEADER_ITEM
));
678 /* Correct the orders */
679 if (iOrder
< infoPtr
->uNumItem
)
681 memmove(&infoPtr
->order
[iOrder
], &infoPtr
->order
[iOrder
+ 1],
682 (infoPtr
->uNumItem
- iOrder
) * sizeof(INT
));
683 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
685 if (infoPtr
->order
[i
] > iItem
)
688 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
692 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
693 TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i
, infoPtr
->order
[i
], infoPtr
->items
[i
].iOrder
, infoPtr
->items
[infoPtr
->order
[i
]].iOrder
);
697 HEADER_SetItemBounds (hwnd
);
699 InvalidateRect(hwnd
, NULL
, FALSE
);
706 HEADER_GetImageList (HWND hwnd
)
708 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
710 return (LRESULT
)infoPtr
->himl
;
715 HEADER_GetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
717 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
718 HDITEMA
*phdi
= (HDITEMA
*)lParam
;
719 INT nItem
= (INT
)wParam
;
725 TRACE("[nItem=%d]\n", nItem
);
730 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
)) {
734 lpItem
= &infoPtr
->items
[nItem
];
737 if (phdi
->mask
& HDI_BITMAP
)
738 phdi
->hbm
= (lpItem
!= NULL
) ? lpItem
->hbm
: 0;
740 if (phdi
->mask
& HDI_FORMAT
)
741 phdi
->fmt
= (lpItem
!= NULL
) ? lpItem
->fmt
: 0;
743 if (phdi
->mask
& HDI_WIDTH
)
744 phdi
->cxy
= (lpItem
!= NULL
) ? lpItem
->cxy
: 0;
746 if (phdi
->mask
& HDI_LPARAM
)
747 phdi
->lParam
= (lpItem
!= NULL
) ? lpItem
->lParam
: 0;
749 if (phdi
->mask
& HDI_TEXT
) {
750 if (lpItem
== NULL
) {
753 else if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
) {
755 WideCharToMultiByte (CP_ACP
, 0, lpItem
->pszText
, -1,
756 phdi
->pszText
, phdi
->cchTextMax
, NULL
, NULL
);
761 phdi
->pszText
= LPSTR_TEXTCALLBACKA
;
764 if (phdi
->mask
& HDI_IMAGE
)
765 phdi
->iImage
= (lpItem
!= NULL
) ? lpItem
->iImage
: 0;
767 if (phdi
->mask
& HDI_ORDER
)
768 phdi
->iOrder
= (lpItem
!= NULL
) ? lpItem
->iOrder
: 0;
775 HEADER_GetItemW (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
777 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
778 HDITEMW
*phdi
= (HDITEMW
*)lParam
;
779 INT nItem
= (INT
)wParam
;
785 TRACE("[nItem=%d]\n", nItem
);
790 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
)) {
794 lpItem
= &infoPtr
->items
[nItem
];
797 if (phdi
->mask
& HDI_BITMAP
)
798 phdi
->hbm
= (lpItem
!= NULL
) ? lpItem
->hbm
: 0;
800 if (phdi
->mask
& HDI_FORMAT
)
801 phdi
->fmt
= (lpItem
!= NULL
) ? lpItem
->fmt
: 0;
803 if (phdi
->mask
& HDI_WIDTH
)
804 phdi
->cxy
= (lpItem
!= NULL
) ? lpItem
->cxy
: 0;
806 if (phdi
->mask
& HDI_LPARAM
)
807 phdi
->lParam
= (lpItem
!= NULL
) ? lpItem
->lParam
: 0;
809 if (phdi
->mask
& HDI_TEXT
) {
810 if (lpItem
== NULL
) {
813 else if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
) {
815 lstrcpynW (phdi
->pszText
, lpItem
->pszText
, phdi
->cchTextMax
);
820 phdi
->pszText
= LPSTR_TEXTCALLBACKW
;
823 if (phdi
->mask
& HDI_IMAGE
)
824 phdi
->iImage
= (lpItem
!= NULL
) ? lpItem
->iImage
: 0;
826 if (phdi
->mask
& HDI_ORDER
)
827 phdi
->iOrder
= (lpItem
!= NULL
) ? lpItem
->iOrder
: 0;
833 inline static LRESULT
834 HEADER_GetItemCount (HWND hwnd
)
836 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
837 return infoPtr
->uNumItem
;
842 HEADER_GetItemRect (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
844 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
845 INT iItem
= (INT
)wParam
;
846 LPRECT lpRect
= (LPRECT
)lParam
;
848 if ((iItem
< 0) || (iItem
>= (INT
)infoPtr
->uNumItem
))
851 lpRect
->left
= infoPtr
->items
[iItem
].rect
.left
;
852 lpRect
->right
= infoPtr
->items
[iItem
].rect
.right
;
853 lpRect
->top
= infoPtr
->items
[iItem
].rect
.top
;
854 lpRect
->bottom
= infoPtr
->items
[iItem
].rect
.bottom
;
861 HEADER_GetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
863 LPINT order
= (LPINT
) lParam
;
864 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
866 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
869 memcpy(order
, infoPtr
->order
, infoPtr
->uNumItem
* sizeof(INT
));
874 HEADER_SetOrderArray(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
877 LPINT order
= (LPINT
) lParam
;
878 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
881 if ((unsigned int)wParam
<infoPtr
->uNumItem
)
883 memcpy(infoPtr
->order
, order
, infoPtr
->uNumItem
* sizeof(INT
));
884 for (i
=0; i
<(int)wParam
; i
++)
886 lpItem
= &infoPtr
->items
[*order
++];
889 infoPtr
->bRectsValid
=0;
890 InvalidateRect(hwnd
, NULL
, FALSE
);
894 inline static LRESULT
895 HEADER_GetUnicodeFormat (HWND hwnd
)
897 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
898 return infoPtr
->bUnicode
;
903 HEADER_HitTest (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
905 LPHDHITTESTINFO phti
= (LPHDHITTESTINFO
)lParam
;
907 HEADER_InternalHitTest (hwnd
, &phti
->pt
, &phti
->flags
, &phti
->iItem
);
909 if (phti
->flags
== HHT_NOWHERE
)
917 HEADER_InsertItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
919 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
920 HDITEMA
*phdi
= (HDITEMA
*)lParam
;
921 INT nItem
= (INT
)wParam
;
926 if ((phdi
== NULL
) || (nItem
< 0))
929 if (nItem
> infoPtr
->uNumItem
)
930 nItem
= infoPtr
->uNumItem
;
932 iOrder
= (phdi
->mask
& HDI_ORDER
) ? phdi
->iOrder
: nItem
;
935 else if (infoPtr
->uNumItem
< iOrder
)
936 iOrder
= infoPtr
->uNumItem
;
938 if (infoPtr
->uNumItem
== 0) {
939 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
));
940 infoPtr
->order
= Alloc(sizeof(INT
));
944 HEADER_ITEM
*oldItems
= infoPtr
->items
;
945 INT
*oldOrder
= infoPtr
->order
;
948 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
950 memcpy (&infoPtr
->items
[1], &oldItems
[0],
951 (infoPtr
->uNumItem
-1) * sizeof(HEADER_ITEM
));
955 /* pre insert copy */
957 memcpy (&infoPtr
->items
[0], &oldItems
[0],
958 nItem
* sizeof(HEADER_ITEM
));
961 /* post insert copy */
962 if (nItem
< infoPtr
->uNumItem
- 1) {
963 memcpy (&infoPtr
->items
[nItem
+1], &oldItems
[nItem
],
964 (infoPtr
->uNumItem
- nItem
- 1) * sizeof(HEADER_ITEM
));
968 infoPtr
->order
= Alloc(sizeof(INT
) * infoPtr
->uNumItem
);
969 memcpy(infoPtr
->order
, oldOrder
, iOrder
* sizeof(INT
));
970 infoPtr
->order
[iOrder
] = nItem
;
971 memcpy(&infoPtr
->order
[iOrder
+ 1], &oldOrder
[iOrder
],
972 (infoPtr
->uNumItem
- iOrder
- 1) * sizeof(INT
));
978 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
980 if (i
!= iOrder
&& infoPtr
->order
[i
] >= nItem
)
982 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
985 lpItem
= &infoPtr
->items
[nItem
];
986 lpItem
->bDown
= FALSE
;
988 if (phdi
->mask
& HDI_WIDTH
)
989 lpItem
->cxy
= phdi
->cxy
;
991 if (phdi
->mask
& HDI_TEXT
) {
992 if (!phdi
->pszText
) /* null pointer check */
994 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKA
) {
995 len
= MultiByteToWideChar(CP_ACP
, 0, phdi
->pszText
, -1, NULL
, 0);
996 lpItem
->pszText
= Alloc( len
*sizeof(WCHAR
) );
997 MultiByteToWideChar(CP_ACP
, 0, phdi
->pszText
, -1, lpItem
->pszText
, len
);
1000 lpItem
->pszText
= LPSTR_TEXTCALLBACKW
;
1003 if (phdi
->mask
& HDI_FORMAT
)
1004 lpItem
->fmt
= phdi
->fmt
;
1006 if (lpItem
->fmt
== 0)
1007 lpItem
->fmt
= HDF_LEFT
;
1009 if (!(lpItem
->fmt
& HDF_STRING
) && (phdi
->mask
& HDI_TEXT
))
1011 lpItem
->fmt
|= HDF_STRING
;
1013 if (phdi
->mask
& HDI_BITMAP
)
1014 lpItem
->hbm
= phdi
->hbm
;
1016 if (phdi
->mask
& HDI_LPARAM
)
1017 lpItem
->lParam
= phdi
->lParam
;
1019 if (phdi
->mask
& HDI_IMAGE
)
1020 lpItem
->iImage
= phdi
->iImage
;
1022 lpItem
->iOrder
= iOrder
;
1024 HEADER_SetItemBounds (hwnd
);
1026 InvalidateRect(hwnd
, NULL
, FALSE
);
1033 HEADER_InsertItemW (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1035 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1036 HDITEMW
*phdi
= (HDITEMW
*)lParam
;
1037 INT nItem
= (INT
)wParam
;
1038 HEADER_ITEM
*lpItem
;
1042 if ((phdi
== NULL
) || (nItem
< 0))
1045 if (nItem
> infoPtr
->uNumItem
)
1046 nItem
= infoPtr
->uNumItem
;
1048 iOrder
= (phdi
->mask
& HDI_ORDER
) ? phdi
->iOrder
: nItem
;
1050 if (infoPtr
->uNumItem
== 0) {
1051 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
));
1052 infoPtr
->order
= Alloc(sizeof(INT
));
1053 infoPtr
->uNumItem
++;
1056 HEADER_ITEM
*oldItems
= infoPtr
->items
;
1057 INT
*oldOrder
= infoPtr
->order
;
1059 infoPtr
->uNumItem
++;
1060 infoPtr
->items
= Alloc (sizeof (HEADER_ITEM
) * infoPtr
->uNumItem
);
1062 memcpy (&infoPtr
->items
[1], &oldItems
[0],
1063 (infoPtr
->uNumItem
-1) * sizeof(HEADER_ITEM
));
1067 /* pre insert copy */
1069 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1070 nItem
* sizeof(HEADER_ITEM
));
1073 /* post insert copy */
1074 if (nItem
< infoPtr
->uNumItem
- 1) {
1075 memcpy (&infoPtr
->items
[nItem
+1], &oldItems
[nItem
],
1076 (infoPtr
->uNumItem
- nItem
- 1) * sizeof(HEADER_ITEM
));
1080 infoPtr
->order
= Alloc(infoPtr
->uNumItem
* sizeof(INT
));
1081 memcpy(infoPtr
->order
, oldOrder
, iOrder
* sizeof(INT
));
1082 infoPtr
->order
[iOrder
] = nItem
;
1083 memcpy(&infoPtr
->order
[iOrder
+ 1], &oldOrder
[iOrder
],
1084 (infoPtr
->uNumItem
- iOrder
- 1) * sizeof(INT
));
1090 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1092 if (i
!= iOrder
&& infoPtr
->order
[i
] >= nItem
)
1093 infoPtr
->order
[i
]++;
1094 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1097 lpItem
= &infoPtr
->items
[nItem
];
1098 lpItem
->bDown
= FALSE
;
1100 if (phdi
->mask
& HDI_WIDTH
)
1101 lpItem
->cxy
= phdi
->cxy
;
1103 if (phdi
->mask
& HDI_TEXT
) {
1104 WCHAR wide_null_char
= 0;
1105 if (!phdi
->pszText
) /* null pointer check */
1106 phdi
->pszText
= &wide_null_char
;
1107 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKW
) {
1108 len
= strlenW (phdi
->pszText
);
1109 lpItem
->pszText
= Alloc ((len
+1)*sizeof(WCHAR
));
1110 strcpyW (lpItem
->pszText
, phdi
->pszText
);
1113 lpItem
->pszText
= LPSTR_TEXTCALLBACKW
;
1116 if (phdi
->mask
& HDI_FORMAT
)
1117 lpItem
->fmt
= phdi
->fmt
;
1119 if (lpItem
->fmt
== 0)
1120 lpItem
->fmt
= HDF_LEFT
;
1122 if (!(lpItem
->fmt
&HDF_STRING
) && (phdi
->mask
& HDI_TEXT
))
1124 lpItem
->fmt
|= HDF_STRING
;
1126 if (phdi
->mask
& HDI_BITMAP
)
1127 lpItem
->hbm
= phdi
->hbm
;
1129 if (phdi
->mask
& HDI_LPARAM
)
1130 lpItem
->lParam
= phdi
->lParam
;
1132 if (phdi
->mask
& HDI_IMAGE
)
1133 lpItem
->iImage
= phdi
->iImage
;
1135 lpItem
->iOrder
= iOrder
;
1137 HEADER_SetItemBounds (hwnd
);
1139 InvalidateRect(hwnd
, NULL
, FALSE
);
1146 HEADER_Layout (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1148 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1149 LPHDLAYOUT lpLayout
= (LPHDLAYOUT
)lParam
;
1151 lpLayout
->pwpos
->hwnd
= hwnd
;
1152 lpLayout
->pwpos
->hwndInsertAfter
= 0;
1153 lpLayout
->pwpos
->x
= lpLayout
->prc
->left
;
1154 lpLayout
->pwpos
->y
= lpLayout
->prc
->top
;
1155 lpLayout
->pwpos
->cx
= lpLayout
->prc
->right
- lpLayout
->prc
->left
;
1156 if (GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_HIDDEN
)
1157 lpLayout
->pwpos
->cy
= 0;
1159 lpLayout
->pwpos
->cy
= infoPtr
->nHeight
;
1160 lpLayout
->prc
->top
+= infoPtr
->nHeight
;
1162 lpLayout
->pwpos
->flags
= SWP_NOZORDER
;
1164 TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1165 lpLayout
->pwpos
->x
, lpLayout
->pwpos
->y
,
1166 lpLayout
->pwpos
->cx
, lpLayout
->pwpos
->cy
);
1168 infoPtr
->bRectsValid
= FALSE
;
1175 HEADER_SetImageList (HWND hwnd
, HIMAGELIST himl
)
1177 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1180 TRACE("(himl %p)\n", himl
);
1181 himlOld
= infoPtr
->himl
;
1182 infoPtr
->himl
= himl
;
1184 /* FIXME: Refresh needed??? */
1186 return (LRESULT
)himlOld
;
1191 HEADER_GetBitmapMargin(HWND hwnd
)
1193 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr(hwnd
);
1195 return infoPtr
->iMargin
;
1199 HEADER_SetBitmapMargin(HWND hwnd
, WPARAM wParam
)
1201 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1202 INT oldMargin
= infoPtr
->iMargin
;
1204 infoPtr
->iMargin
= (INT
)wParam
;
1210 HEADER_SetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1212 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1213 HDITEMA
*phdi
= (HDITEMA
*)lParam
;
1214 INT nItem
= (INT
)wParam
;
1215 HEADER_ITEM
*lpItem
;
1219 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1222 TRACE("[nItem=%d]\n", nItem
);
1224 if (HEADER_SendHeaderNotify (hwnd
, HDN_ITEMCHANGINGA
, nItem
, phdi
->mask
))
1227 lpItem
= &infoPtr
->items
[nItem
];
1228 if (phdi
->mask
& HDI_BITMAP
)
1229 lpItem
->hbm
= phdi
->hbm
;
1231 if (phdi
->mask
& HDI_FORMAT
)
1232 lpItem
->fmt
= phdi
->fmt
;
1234 if (phdi
->mask
& HDI_LPARAM
)
1235 lpItem
->lParam
= phdi
->lParam
;
1237 if (phdi
->mask
& HDI_TEXT
) {
1238 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKA
) {
1239 if (lpItem
->pszText
) {
1240 Free (lpItem
->pszText
);
1241 lpItem
->pszText
= NULL
;
1243 if (phdi
->pszText
) {
1244 INT len
= MultiByteToWideChar (CP_ACP
,0,phdi
->pszText
,-1,NULL
,0);
1245 lpItem
->pszText
= Alloc( len
*sizeof(WCHAR
) );
1246 MultiByteToWideChar (CP_ACP
,0,phdi
->pszText
,-1,lpItem
->pszText
,len
);
1250 lpItem
->pszText
= LPSTR_TEXTCALLBACKW
;
1253 if (phdi
->mask
& HDI_WIDTH
)
1254 lpItem
->cxy
= phdi
->cxy
;
1256 if (phdi
->mask
& HDI_IMAGE
)
1257 lpItem
->iImage
= phdi
->iImage
;
1259 if (phdi
->mask
& HDI_ORDER
)
1263 if (lpItem
->iOrder
< phdi
->iOrder
)
1265 memmove(&infoPtr
->order
[lpItem
->iOrder
],
1266 &infoPtr
->order
[lpItem
->iOrder
+ 1],
1267 (phdi
->iOrder
- lpItem
->iOrder
) * sizeof(INT
));
1269 if (phdi
->iOrder
< lpItem
->iOrder
)
1271 memmove(&infoPtr
->order
[phdi
->iOrder
+ 1],
1272 &infoPtr
->order
[phdi
->iOrder
],
1273 (lpItem
->iOrder
- phdi
->iOrder
) * sizeof(INT
));
1275 infoPtr
->order
[phdi
->iOrder
] = nItem
;
1276 nMin
= min(lpItem
->iOrder
, phdi
->iOrder
);
1277 nMax
= max(lpItem
->iOrder
, phdi
->iOrder
);
1278 for (i
= nMin
; i
<= nMax
; i
++)
1280 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1284 HEADER_SendHeaderNotify (hwnd
, HDN_ITEMCHANGEDA
, nItem
, phdi
->mask
);
1286 HEADER_SetItemBounds (hwnd
);
1288 InvalidateRect(hwnd
, NULL
, FALSE
);
1295 HEADER_SetItemW (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1297 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1298 HDITEMW
*phdi
= (HDITEMW
*)lParam
;
1299 INT nItem
= (INT
)wParam
;
1300 HEADER_ITEM
*lpItem
;
1304 if ((nItem
< 0) || (nItem
>= (INT
)infoPtr
->uNumItem
))
1307 TRACE("[nItem=%d]\n", nItem
);
1309 if (HEADER_SendHeaderNotify (hwnd
, HDN_ITEMCHANGINGW
, nItem
, phdi
->mask
))
1312 lpItem
= &infoPtr
->items
[nItem
];
1313 if (phdi
->mask
& HDI_BITMAP
)
1314 lpItem
->hbm
= phdi
->hbm
;
1316 if (phdi
->mask
& HDI_FORMAT
)
1317 lpItem
->fmt
= phdi
->fmt
;
1319 if (phdi
->mask
& HDI_LPARAM
)
1320 lpItem
->lParam
= phdi
->lParam
;
1322 if (phdi
->mask
& HDI_TEXT
) {
1323 if (phdi
->pszText
!= LPSTR_TEXTCALLBACKW
) {
1324 if (lpItem
->pszText
) {
1325 Free (lpItem
->pszText
);
1326 lpItem
->pszText
= NULL
;
1328 if (phdi
->pszText
) {
1329 INT len
= strlenW (phdi
->pszText
);
1330 lpItem
->pszText
= Alloc ((len
+1)*sizeof(WCHAR
));
1331 strcpyW (lpItem
->pszText
, phdi
->pszText
);
1335 lpItem
->pszText
= LPSTR_TEXTCALLBACKW
;
1338 if (phdi
->mask
& HDI_WIDTH
)
1339 lpItem
->cxy
= phdi
->cxy
;
1341 if (phdi
->mask
& HDI_IMAGE
)
1342 lpItem
->iImage
= phdi
->iImage
;
1344 if (phdi
->mask
& HDI_ORDER
)
1348 if (lpItem
->iOrder
< phdi
->iOrder
)
1350 memmove(&infoPtr
->order
[lpItem
->iOrder
],
1351 &infoPtr
->order
[lpItem
->iOrder
+ 1],
1352 (phdi
->iOrder
- lpItem
->iOrder
) * sizeof(INT
));
1354 if (phdi
->iOrder
< lpItem
->iOrder
)
1356 memmove(&infoPtr
->order
[phdi
->iOrder
+ 1],
1357 &infoPtr
->order
[phdi
->iOrder
],
1358 (lpItem
->iOrder
- phdi
->iOrder
) * sizeof(INT
));
1360 infoPtr
->order
[phdi
->iOrder
] = nItem
;
1361 nMin
= min(lpItem
->iOrder
, phdi
->iOrder
);
1362 nMax
= max(lpItem
->iOrder
, phdi
->iOrder
);
1363 for (i
= nMin
; i
<= nMax
; i
++)
1365 infoPtr
->items
[infoPtr
->order
[i
]].iOrder
= infoPtr
->order
[i
];
1369 HEADER_SendHeaderNotify(hwnd
, HDN_ITEMCHANGEDW
, nItem
, phdi
->mask
);
1371 HEADER_SetItemBounds (hwnd
);
1373 InvalidateRect(hwnd
, NULL
, FALSE
);
1378 inline static LRESULT
1379 HEADER_SetUnicodeFormat (HWND hwnd
, WPARAM wParam
)
1381 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1382 BOOL bTemp
= infoPtr
->bUnicode
;
1384 infoPtr
->bUnicode
= (BOOL
)wParam
;
1391 HEADER_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1393 HEADER_INFO
*infoPtr
;
1398 infoPtr
= (HEADER_INFO
*)Alloc (sizeof(HEADER_INFO
));
1399 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
1401 infoPtr
->hwndNotify
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1402 infoPtr
->uNumItem
= 0;
1406 infoPtr
->bRectsValid
= FALSE
;
1407 infoPtr
->hcurArrow
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1408 infoPtr
->hcurDivider
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDER
));
1409 infoPtr
->hcurDivopen
= LoadCursorW (COMCTL32_hModule
, MAKEINTRESOURCEW(IDC_DIVIDEROPEN
));
1410 infoPtr
->bPressed
= FALSE
;
1411 infoPtr
->bTracking
= FALSE
;
1412 infoPtr
->iMoveItem
= 0;
1414 infoPtr
->iHotItem
= -1;
1415 infoPtr
->bUnicode
= IsWindowUnicode (hwnd
);
1416 infoPtr
->iMargin
= 3*GetSystemMetrics(SM_CXEDGE
);
1417 infoPtr
->nNotifyFormat
=
1418 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
1421 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1422 GetTextMetricsW (hdc
, &tm
);
1423 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1424 SelectObject (hdc
, hOldFont
);
1427 OpenThemeData(hwnd
, themeClass
);
1434 HEADER_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1436 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1437 HEADER_ITEM
*lpItem
;
1441 if (infoPtr
->items
) {
1442 lpItem
= infoPtr
->items
;
1443 for (nItem
= 0; nItem
< infoPtr
->uNumItem
; nItem
++, lpItem
++) {
1444 if ((lpItem
->pszText
) && (lpItem
->pszText
!= LPSTR_TEXTCALLBACKW
))
1445 Free (lpItem
->pszText
);
1447 Free (infoPtr
->items
);
1451 Free(infoPtr
->order
);
1454 ImageList_Destroy (infoPtr
->himl
);
1456 SetWindowLongPtrW (hwnd
, 0, 0);
1459 theme
= GetWindowTheme(hwnd
);
1460 CloseThemeData(theme
);
1465 static inline LRESULT
1466 HEADER_GetFont (HWND hwnd
)
1468 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1470 return (LRESULT
)infoPtr
->hFont
;
1475 HEADER_LButtonDblClk (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1481 pt
.x
= (INT
)LOWORD(lParam
);
1482 pt
.y
= (INT
)HIWORD(lParam
);
1483 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1485 if ((GetWindowLongW (hwnd
, GWL_STYLE
) & HDS_BUTTONS
) && (flags
== HHT_ONHEADER
))
1486 HEADER_SendHeaderNotify (hwnd
, HDN_ITEMDBLCLICKA
, nItem
,0);
1487 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
))
1488 HEADER_SendHeaderNotify (hwnd
, HDN_DIVIDERDBLCLICKA
, nItem
,0);
1495 HEADER_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1497 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1498 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1504 pt
.x
= (INT
)LOWORD(lParam
);
1505 pt
.y
= (INT
)HIWORD(lParam
);
1506 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1508 if ((dwStyle
& HDS_BUTTONS
) && (flags
== HHT_ONHEADER
)) {
1510 infoPtr
->bCaptured
= TRUE
;
1511 infoPtr
->bPressed
= TRUE
;
1512 infoPtr
->iMoveItem
= nItem
;
1514 infoPtr
->items
[nItem
].bDown
= TRUE
;
1516 /* Send WM_CUSTOMDRAW */
1518 HEADER_RefreshItem (hwnd
, hdc
, nItem
);
1519 ReleaseDC (hwnd
, hdc
);
1521 TRACE("Pressed item %d!\n", nItem
);
1523 else if ((flags
== HHT_ONDIVIDER
) || (flags
== HHT_ONDIVOPEN
)) {
1524 if (!(HEADER_SendHeaderNotify (hwnd
, HDN_BEGINTRACKA
, nItem
,0))) {
1526 infoPtr
->bCaptured
= TRUE
;
1527 infoPtr
->bTracking
= TRUE
;
1528 infoPtr
->iMoveItem
= nItem
;
1529 infoPtr
->nOldWidth
= infoPtr
->items
[nItem
].cxy
;
1530 infoPtr
->xTrackOffset
= infoPtr
->items
[nItem
].rect
.right
- pt
.x
;
1532 if (!(dwStyle
& HDS_FULLDRAG
)) {
1533 infoPtr
->xOldTrack
= infoPtr
->items
[nItem
].rect
.right
;
1535 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1536 ReleaseDC (hwnd
, hdc
);
1539 TRACE("Begin tracking item %d!\n", nItem
);
1548 HEADER_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1550 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1552 *DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1559 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1560 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1561 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1563 if (infoPtr
->bPressed
) {
1564 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
)) {
1565 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1567 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1568 ReleaseDC (hwnd
, hdc
);
1570 HEADER_SendClickNotify (hwnd
, HDN_ITEMCLICKA
, infoPtr
->iMoveItem
);
1572 else if (flags
== HHT_ONHEADER
)
1574 HEADER_ITEM
*lpItem
;
1575 INT newindex
= HEADER_IndexToOrder(hwnd
,nItem
);
1576 INT oldindex
= HEADER_IndexToOrder(hwnd
,infoPtr
->iMoveItem
);
1578 TRACE("Exchanging [index:order] [%d:%d] [%d:%d]\n",
1579 infoPtr
->iMoveItem
,oldindex
,nItem
,newindex
);
1580 lpItem
= &infoPtr
->items
[nItem
];
1581 lpItem
->iOrder
=oldindex
;
1583 lpItem
= &infoPtr
->items
[infoPtr
->iMoveItem
];
1584 lpItem
->iOrder
= newindex
;
1586 infoPtr
->order
[oldindex
] = nItem
;
1587 infoPtr
->order
[newindex
] = infoPtr
->iMoveItem
;
1589 infoPtr
->bRectsValid
= FALSE
;
1590 InvalidateRect(hwnd
, NULL
, FALSE
);
1591 /* FIXME: Should some WM_NOTIFY be sent */
1594 TRACE("Released item %d!\n", infoPtr
->iMoveItem
);
1595 infoPtr
->bPressed
= FALSE
;
1597 else if (infoPtr
->bTracking
) {
1598 TRACE("End tracking item %d!\n", infoPtr
->iMoveItem
);
1599 infoPtr
->bTracking
= FALSE
;
1601 HEADER_SendHeaderNotify (hwnd
, HDN_ENDTRACKA
, infoPtr
->iMoveItem
,HDI_WIDTH
);
1604 * we want to do this even for HDS_FULLDRAG because this is where
1605 * we send the HDN_ITEMCHANGING and HDN_ITEMCHANGED notifications
1607 * if (!(dwStyle & HDS_FULLDRAG)) {
1611 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1612 ReleaseDC (hwnd
, hdc
);
1613 if (HEADER_SendHeaderNotify(hwnd
, HDN_ITEMCHANGINGA
, infoPtr
->iMoveItem
, HDI_WIDTH
))
1615 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= infoPtr
->nOldWidth
;
1618 nWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1621 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1624 HEADER_SetItemBounds (hwnd
);
1625 InvalidateRect(hwnd
, NULL
, TRUE
);
1626 HEADER_SendHeaderNotify(hwnd
, HDN_ITEMCHANGEDA
, infoPtr
->iMoveItem
, HDI_WIDTH
);
1632 if (infoPtr
->bCaptured
) {
1633 infoPtr
->bCaptured
= FALSE
;
1635 HEADER_SendSimpleNotify (hwnd
, NM_RELEASEDCAPTURE
);
1643 HEADER_NotifyFormat (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1645 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1650 return infoPtr
->nNotifyFormat
;
1653 infoPtr
->nNotifyFormat
=
1654 SendMessageW ((HWND
)wParam
, WM_NOTIFYFORMAT
,
1655 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
1656 return infoPtr
->nNotifyFormat
;
1664 HEADER_MouseLeave (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1666 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1667 /* Reset hot-tracked item when mouse leaves control. */
1668 INT oldHotItem
= infoPtr
->iHotItem
;
1669 HDC hdc
= GetDC (hwnd
);
1671 infoPtr
->iHotItem
= -1;
1672 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1673 ReleaseDC (hwnd
, hdc
);
1680 HEADER_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1682 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1683 DWORD dwStyle
= GetWindowLongW (hwnd
, GWL_STYLE
);
1688 /* With theming, hottracking is always enabled */
1689 BOOL hotTrackEnabled
=
1690 ((dwStyle
& HDS_BUTTONS
) && (dwStyle
& HDS_HOTTRACK
))
1691 || (GetWindowTheme (hwnd
) != NULL
);
1692 INT oldHotItem
= infoPtr
->iHotItem
;
1694 pt
.x
= (INT
)(SHORT
)LOWORD(lParam
);
1695 pt
.y
= (INT
)(SHORT
)HIWORD(lParam
);
1696 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1698 if (hotTrackEnabled
) {
1699 if (flags
& (HHT_ONHEADER
| HHT_ONDIVIDER
| HHT_ONDIVOPEN
))
1700 infoPtr
->iHotItem
= nItem
;
1702 infoPtr
->iHotItem
= -1;
1705 if (infoPtr
->bCaptured
) {
1706 if (infoPtr
->bPressed
) {
1707 BOOL oldState
= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
;
1708 if ((nItem
== infoPtr
->iMoveItem
) && (flags
== HHT_ONHEADER
))
1709 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= TRUE
;
1711 infoPtr
->items
[infoPtr
->iMoveItem
].bDown
= FALSE
;
1712 if (oldState
!= infoPtr
->items
[infoPtr
->iMoveItem
].bDown
) {
1714 HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iMoveItem
);
1715 ReleaseDC (hwnd
, hdc
);
1718 TRACE("Moving pressed item %d!\n", infoPtr
->iMoveItem
);
1720 else if (infoPtr
->bTracking
) {
1721 if (dwStyle
& HDS_FULLDRAG
) {
1722 if (HEADER_SendHeaderNotify (hwnd
, HDN_TRACKA
, infoPtr
->iMoveItem
, HDI_WIDTH
))
1724 nWidth
= pt
.x
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
+ infoPtr
->xTrackOffset
;
1727 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
= nWidth
;
1728 HEADER_SendHeaderNotify(hwnd
, HDN_ITEMCHANGEDA
, infoPtr
->iMoveItem
, HDI_WIDTH
);
1730 HEADER_SetItemBounds (hwnd
);
1734 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1735 infoPtr
->xOldTrack
= pt
.x
+ infoPtr
->xTrackOffset
;
1736 if (infoPtr
->xOldTrack
< infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
)
1737 infoPtr
->xOldTrack
= infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1738 infoPtr
->items
[infoPtr
->iMoveItem
].cxy
=
1739 infoPtr
->xOldTrack
- infoPtr
->items
[infoPtr
->iMoveItem
].rect
.left
;
1740 HEADER_DrawTrackLine (hwnd
, hdc
, infoPtr
->xOldTrack
);
1741 ReleaseDC (hwnd
, hdc
);
1742 HEADER_SendHeaderNotify (hwnd
, HDN_TRACKA
, infoPtr
->iMoveItem
, HDI_WIDTH
);
1745 TRACE("Tracking item %d!\n", infoPtr
->iMoveItem
);
1749 if (hotTrackEnabled
) {
1750 TRACKMOUSEEVENT tme
;
1751 if (oldHotItem
!= infoPtr
->iHotItem
) {
1753 if (oldHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, oldHotItem
);
1754 if (infoPtr
->iHotItem
!= -1) HEADER_RefreshItem (hwnd
, hdc
, infoPtr
->iHotItem
);
1755 ReleaseDC (hwnd
, hdc
);
1757 tme
.cbSize
= sizeof( tme
);
1758 tme
.dwFlags
= TME_LEAVE
;
1759 tme
.hwndTrack
= hwnd
;
1760 TrackMouseEvent( &tme
);
1768 HEADER_Paint (HWND hwnd
, WPARAM wParam
)
1773 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1774 HEADER_Refresh (hwnd
, hdc
);
1776 EndPaint (hwnd
, &ps
);
1782 HEADER_RButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1787 pt
.x
= LOWORD(lParam
);
1788 pt
.y
= HIWORD(lParam
);
1790 /* Send a Notify message */
1791 bRet
= HEADER_SendSimpleNotify (hwnd
, NM_RCLICK
);
1793 /* Change to screen coordinate for WM_CONTEXTMENU */
1794 ClientToScreen(hwnd
, &pt
);
1796 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1797 SendMessageW( hwnd
, WM_CONTEXTMENU
, (WPARAM
) hwnd
, MAKELPARAM(pt
.x
, pt
.y
));
1804 HEADER_SetCursor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1806 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1811 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam
), HIWORD(lParam
));
1814 ScreenToClient (hwnd
, &pt
);
1816 HEADER_InternalHitTest (hwnd
, &pt
, &flags
, &nItem
);
1818 if (flags
== HHT_ONDIVIDER
)
1819 SetCursor (infoPtr
->hcurDivider
);
1820 else if (flags
== HHT_ONDIVOPEN
)
1821 SetCursor (infoPtr
->hcurDivopen
);
1823 SetCursor (infoPtr
->hcurArrow
);
1830 HEADER_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1832 HEADER_INFO
*infoPtr
= HEADER_GetInfoPtr (hwnd
);
1834 HFONT hFont
, hOldFont
;
1837 infoPtr
->hFont
= (HFONT
)wParam
;
1839 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
1842 hOldFont
= SelectObject (hdc
, hFont
);
1843 GetTextMetricsW (hdc
, &tm
);
1844 infoPtr
->nHeight
= tm
.tmHeight
+ VERT_BORDER
;
1845 SelectObject (hdc
, hOldFont
);
1848 infoPtr
->bRectsValid
= FALSE
;
1851 InvalidateRect(hwnd
, NULL
, FALSE
);
1857 /* Update the theme handle after a theme change */
1858 static LRESULT
HEADER_ThemeChanged(HWND hwnd
)
1860 HTHEME theme
= GetWindowTheme(hwnd
);
1861 CloseThemeData(theme
);
1862 OpenThemeData(hwnd
, themeClass
);
1863 InvalidateRect(hwnd
, NULL
, FALSE
);
1868 static LRESULT WINAPI
1869 HEADER_WindowProc (HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1871 TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd
, msg
, wParam
, lParam
);
1872 if (!HEADER_GetInfoPtr (hwnd
) && (msg
!= WM_CREATE
))
1873 return DefWindowProcW (hwnd
, msg
, wParam
, lParam
);
1875 /* case HDM_CLEARFILTER: */
1877 case HDM_CREATEDRAGIMAGE
:
1878 return HEADER_CreateDragImage (hwnd
, wParam
);
1880 case HDM_DELETEITEM
:
1881 return HEADER_DeleteItem (hwnd
, wParam
);
1883 /* case HDM_EDITFILTER: */
1885 case HDM_GETBITMAPMARGIN
:
1886 return HEADER_GetBitmapMargin(hwnd
);
1888 case HDM_GETIMAGELIST
:
1889 return HEADER_GetImageList (hwnd
);
1892 return HEADER_GetItemA (hwnd
, wParam
, lParam
);
1895 return HEADER_GetItemW (hwnd
, wParam
, lParam
);
1897 case HDM_GETITEMCOUNT
:
1898 return HEADER_GetItemCount (hwnd
);
1900 case HDM_GETITEMRECT
:
1901 return HEADER_GetItemRect (hwnd
, wParam
, lParam
);
1903 case HDM_GETORDERARRAY
:
1904 return HEADER_GetOrderArray(hwnd
, wParam
, lParam
);
1906 case HDM_GETUNICODEFORMAT
:
1907 return HEADER_GetUnicodeFormat (hwnd
);
1910 return HEADER_HitTest (hwnd
, wParam
, lParam
);
1912 case HDM_INSERTITEMA
:
1913 return HEADER_InsertItemA (hwnd
, wParam
, lParam
);
1915 case HDM_INSERTITEMW
:
1916 return HEADER_InsertItemW (hwnd
, wParam
, lParam
);
1919 return HEADER_Layout (hwnd
, wParam
, lParam
);
1921 case HDM_ORDERTOINDEX
:
1922 return HEADER_OrderToIndex(hwnd
, wParam
);
1924 case HDM_SETBITMAPMARGIN
:
1925 return HEADER_SetBitmapMargin(hwnd
, wParam
);
1927 /* case HDM_SETFILTERCHANGETIMEOUT: */
1929 /* case HDM_SETHOTDIVIDER: */
1931 case HDM_SETIMAGELIST
:
1932 return HEADER_SetImageList (hwnd
, (HIMAGELIST
)lParam
);
1935 return HEADER_SetItemA (hwnd
, wParam
, lParam
);
1938 return HEADER_SetItemW (hwnd
, wParam
, lParam
);
1940 case HDM_SETORDERARRAY
:
1941 return HEADER_SetOrderArray(hwnd
, wParam
, lParam
);
1943 case HDM_SETUNICODEFORMAT
:
1944 return HEADER_SetUnicodeFormat (hwnd
, wParam
);
1947 return HEADER_Create (hwnd
, wParam
, lParam
);
1950 return HEADER_Destroy (hwnd
, wParam
, lParam
);
1956 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
1959 return HEADER_GetFont (hwnd
);
1961 case WM_LBUTTONDBLCLK
:
1962 return HEADER_LButtonDblClk (hwnd
, wParam
, lParam
);
1964 case WM_LBUTTONDOWN
:
1965 return HEADER_LButtonDown (hwnd
, wParam
, lParam
);
1968 return HEADER_LButtonUp (hwnd
, wParam
, lParam
);
1971 return HEADER_MouseLeave (hwnd
, wParam
, lParam
);
1974 return HEADER_MouseMove (hwnd
, wParam
, lParam
);
1976 case WM_NOTIFYFORMAT
:
1977 return HEADER_NotifyFormat (hwnd
, wParam
, lParam
);
1980 return HEADER_Size (hwnd
, wParam
);
1982 case WM_THEMECHANGED
:
1983 return HEADER_ThemeChanged (hwnd
);
1986 return HEADER_Paint (hwnd
, wParam
);
1989 return HEADER_RButtonUp (hwnd
, wParam
, lParam
);
1992 return HEADER_SetCursor (hwnd
, wParam
, lParam
);
1995 return HEADER_SetFont (hwnd
, wParam
, lParam
);
1998 if ((msg
>= WM_USER
) && (msg
< WM_APP
))
1999 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
2000 msg
, wParam
, lParam
);
2001 return DefWindowProcA (hwnd
, msg
, wParam
, lParam
);
2007 HEADER_Register (void)
2011 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
2012 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
2013 wndClass
.lpfnWndProc
= HEADER_WindowProc
;
2014 wndClass
.cbClsExtra
= 0;
2015 wndClass
.cbWndExtra
= sizeof(HEADER_INFO
*);
2016 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
2017 wndClass
.lpszClassName
= WC_HEADERW
;
2019 RegisterClassW (&wndClass
);
2024 HEADER_Unregister (void)
2026 UnregisterClassW (WC_HEADERW
, NULL
);