comctl32: Properly handle negative coordinates for mouse events.
[wine] / dlls / comctl32 / header.c
1 /*
2  *  Header control
3  *
4  *  Copyright 1998 Eric Kohl
5  *  Copyright 2000 Eric Kohl for CodeWeavers
6  *  Copyright 2003 Maxime Bellenge
7  *  Copyright 2006 Mikolaj Zalewski
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  *
23  *  TODO:
24  *   - Imagelist support (completed?)
25  *   - Hottrack support (completed?)
26  *   - Filters support (HDS_FILTER, HDI_FILTER, HDM_*FILTER*, HDN_*FILTER*)
27  *   - New Windows Vista features
28  */
29
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wine/unicode.h"
37 #include "wingdi.h"
38 #include "winuser.h"
39 #include "winnls.h"
40 #include "commctrl.h"
41 #include "comctl32.h"
42 #include "imagelist.h"
43 #include "tmschema.h"
44 #include "uxtheme.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(header);
48
49 typedef struct
50 {
51     INT     cxy;
52     HBITMAP hbm;
53     LPWSTR    pszText;
54     INT     fmt;
55     LPARAM    lParam;
56     INT     iImage;
57     INT     iOrder;             /* see documentation of HD_ITEM */
58
59     BOOL    bDown;              /* is item pressed? (used for drawing) */
60     RECT    rect;               /* bounding rectangle of the item */
61     DWORD   callbackMask;       /* HDI_* flags for items that are callback */
62 } HEADER_ITEM;
63
64
65 typedef struct
66 {
67     HWND      hwndNotify;       /* Owner window to send notifications to */
68     INT       nNotifyFormat;    /* format used for WM_NOTIFY messages */
69     UINT      uNumItem;         /* number of items (columns) */
70     INT       nHeight;          /* height of the header (pixels) */
71     HFONT     hFont;            /* handle to the current font */
72     HCURSOR   hcurArrow;        /* handle to the arrow cursor */
73     HCURSOR   hcurDivider;      /* handle to a cursor (used over dividers) <-|-> */
74     HCURSOR   hcurDivopen;      /* handle to a cursor (used over dividers) <-||-> */
75     BOOL      bCaptured;        /* Is the mouse captured? */
76     BOOL      bPressed;         /* Is a header item pressed (down)? */
77     BOOL      bDragging;        /* Are we dragging an item? */
78     BOOL      bTracking;        /* Is in tracking mode? */
79     POINT     ptLButtonDown;    /* The point where the left button was pressed */
80     INT       iMoveItem;        /* index of tracked item. (Tracking mode) */
81     INT       xTrackOffset;     /* distance between the right side of the tracked item and the cursor */
82     INT       xOldTrack;        /* track offset (see above) after the last WM_MOUSEMOVE */
83     INT       iHotItem;         /* index of hot item (cursor is over this item) */
84     INT       iHotDivider;      /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
85     INT       iMargin;          /* width of the margin that surrounds a bitmap */
86
87     HIMAGELIST  himl;           /* handle to an image list (may be 0) */
88     HEADER_ITEM *items;         /* pointer to array of HEADER_ITEM's */
89     INT         *order;         /* array of item IDs indexed by order */
90     BOOL        bRectsValid;    /* validity flag for bounding rectangles */
91 } HEADER_INFO;
92
93
94 #define VERT_BORDER     4
95 #define DIVIDER_WIDTH  10
96 #define HOT_DIVIDER_WIDTH 2
97 #define MAX_HEADER_TEXT_LEN 260
98 #define HDN_UNICODE_OFFSET 20
99 #define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
100
101 #define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)
102 #define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)
103 #define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))
104 #define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)
105
106 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0))
107
108 static BOOL HEADER_PrepareCallbackItems(HWND hwnd, INT iItem, INT reqMask);
109 static void HEADER_FreeCallbackItems(HEADER_ITEM *lpItem);
110 static LRESULT HEADER_SendNotify(HWND hwnd, UINT code, NMHDR *hdr);
111 static LRESULT HEADER_SendCtrlCustomDraw(HWND hwnd, DWORD dwDrawStage, HDC hdc, RECT *rect);
112
113 static const WCHAR themeClass[] = {'H','e','a','d','e','r',0};
114 static WCHAR emptyString[] = {0};
115
116 static void HEADER_DisposeItem(HEADER_ITEM *lpItem)
117 {
118     if (lpItem->pszText)
119     {
120         Free(lpItem->pszText);
121     }
122 }
123
124 static void HEADER_StoreHDItemInHeader(HEADER_ITEM *lpItem, UINT mask, HDITEMW *phdi, BOOL fUnicode)
125 {
126     if (mask & HDI_UNSUPPORTED_FIELDS)
127         FIXME("unsupported header fields %x\n", (mask & HDI_UNSUPPORTED_FIELDS));
128     
129     if (mask & HDI_BITMAP)
130         lpItem->hbm = phdi->hbm;
131
132     if (mask & HDI_FORMAT)
133         lpItem->fmt = phdi->fmt;
134
135     if (mask & HDI_LPARAM)
136         lpItem->lParam = phdi->lParam;
137
138     if (mask & HDI_WIDTH)
139         lpItem->cxy = phdi->cxy;
140
141     if (mask & HDI_IMAGE) 
142     {
143         lpItem->iImage = phdi->iImage;
144         if (phdi->iImage == I_IMAGECALLBACK)
145             lpItem->callbackMask |= HDI_IMAGE;
146         else
147             lpItem->callbackMask &= ~HDI_IMAGE;
148     }
149
150     if (mask & HDI_TEXT)
151     {
152         if (lpItem->pszText)
153         {
154             Free(lpItem->pszText);
155             lpItem->pszText = NULL;
156         }
157
158         if (phdi->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */
159         {
160             LPWSTR pszText = (phdi->pszText != NULL ? phdi->pszText : emptyString);
161             if (fUnicode)
162                 Str_SetPtrW(&lpItem->pszText, pszText);
163             else
164                 Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)pszText);
165             lpItem->callbackMask &= ~HDI_TEXT;
166         }
167         else
168         {
169             lpItem->pszText = NULL;
170             lpItem->callbackMask |= HDI_TEXT;
171         }  
172     }
173 }
174
175 inline static LRESULT
176 HEADER_IndexToOrder (HWND hwnd, INT iItem)
177 {
178     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
179     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
180     return lpItem->iOrder;
181 }
182
183
184 static INT
185 HEADER_OrderToIndex(HWND hwnd, WPARAM wParam)
186 {
187     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
188     INT iorder = (INT)wParam;
189
190     if ((iorder <0) || iorder >= infoPtr->uNumItem)
191       return iorder;
192     return infoPtr->order[iorder];
193 }
194
195 static void
196 HEADER_ChangeItemOrder(HEADER_INFO *infoPtr, INT iItem, INT iNewOrder)
197 {
198     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
199     INT i, nMin, nMax;
200
201     TRACE("%d: %d->%d\n", iItem, lpItem->iOrder, iNewOrder);
202     if (lpItem->iOrder < iNewOrder)
203     {
204         memmove(&infoPtr->order[lpItem->iOrder],
205                &infoPtr->order[lpItem->iOrder + 1],
206                (iNewOrder - lpItem->iOrder) * sizeof(INT));
207     }
208     if (iNewOrder < lpItem->iOrder)
209     {
210         memmove(&infoPtr->order[iNewOrder + 1],
211                 &infoPtr->order[iNewOrder],
212                 (lpItem->iOrder - iNewOrder) * sizeof(INT));
213     }
214     infoPtr->order[iNewOrder] = iItem;
215     nMin = min(lpItem->iOrder, iNewOrder);
216     nMax = max(lpItem->iOrder, iNewOrder);
217     for (i = nMin; i <= nMax; i++)
218         infoPtr->items[infoPtr->order[i]].iOrder = i;
219 }
220
221 /* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
222 static INT
223 HEADER_NextItem(HWND hwnd, INT iItem)
224 {
225     return HEADER_OrderToIndex(hwnd, HEADER_IndexToOrder(hwnd, iItem)+1);
226 }
227
228 static INT
229 HEADER_PrevItem(HWND hwnd, INT iItem)
230 {
231     return HEADER_OrderToIndex(hwnd, HEADER_IndexToOrder(hwnd, iItem)-1);
232 }
233
234 static void
235 HEADER_SetItemBounds (HWND hwnd)
236 {
237     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
238     HEADER_ITEM *phdi;
239     RECT rect;
240     unsigned int i;
241     int x;
242
243     infoPtr->bRectsValid = TRUE;
244
245     if (infoPtr->uNumItem == 0)
246         return;
247
248     GetClientRect (hwnd, &rect);
249
250     x = rect.left;
251     for (i = 0; i < infoPtr->uNumItem; i++) {
252         phdi = &infoPtr->items[HEADER_OrderToIndex(hwnd,i)];
253         phdi->rect.top = rect.top;
254         phdi->rect.bottom = rect.bottom;
255         phdi->rect.left = x;
256         phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0);
257         x = phdi->rect.right;
258     }
259 }
260
261 static LRESULT
262 HEADER_Size (HWND hwnd, WPARAM wParam)
263 {
264     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
265
266     infoPtr->bRectsValid = FALSE;
267
268     return 0;
269 }
270
271 static void HEADER_GetHotDividerRect(HWND hwnd, HEADER_INFO *infoPtr, RECT *r)
272 {
273     INT iDivider = infoPtr->iHotDivider;
274     if (infoPtr->uNumItem > 0)
275     {
276         HEADER_ITEM *lpItem;
277         
278         if (iDivider < infoPtr->uNumItem)
279         {
280             lpItem = &infoPtr->items[iDivider];
281             r->left  = lpItem->rect.left - HOT_DIVIDER_WIDTH/2;
282             r->right = lpItem->rect.left + HOT_DIVIDER_WIDTH/2;
283         }
284         else
285         {
286             lpItem = &infoPtr->items[HEADER_OrderToIndex(hwnd, infoPtr->uNumItem-1)];
287             r->left  = lpItem->rect.right - HOT_DIVIDER_WIDTH/2;
288             r->right = lpItem->rect.right + HOT_DIVIDER_WIDTH/2;
289         }
290         r->top    = lpItem->rect.top;
291         r->bottom = lpItem->rect.bottom;
292     }
293     else
294     {
295         RECT clientRect;
296         GetClientRect(hwnd, &clientRect);
297         *r = clientRect;
298         r->right = r->left + HOT_DIVIDER_WIDTH/2;
299     }
300 }
301
302
303 static INT
304 HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack, LRESULT lCDFlags)
305 {
306     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
307     HEADER_ITEM *phdi = &infoPtr->items[iItem];
308     RECT r;
309     INT  oldBkMode;
310     HTHEME theme = GetWindowTheme (hwnd);
311     NMCUSTOMDRAW nmcd;
312
313     TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, (infoPtr->nNotifyFormat == NFR_UNICODE));
314
315     r = phdi->rect;
316     if (r.right - r.left == 0)
317         return phdi->rect.right;
318
319     /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
320     SetTextColor(hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
321     SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
322
323     if (lCDFlags & CDRF_NOTIFYITEMDRAW && !(phdi->fmt & HDF_OWNERDRAW))
324     {
325         LRESULT lCDItemFlags;
326
327         nmcd.dwDrawStage  = CDDS_PREPAINT | CDDS_ITEM;
328         nmcd.hdc          = hdc;
329         nmcd.dwItemSpec   = iItem;
330         nmcd.rc           = r;
331         nmcd.uItemState   = phdi->bDown ? CDIS_SELECTED : 0;
332         nmcd.lItemlParam  = phdi->lParam;
333
334         lCDItemFlags = HEADER_SendNotify(hwnd, NM_CUSTOMDRAW, (NMHDR *)&nmcd);
335         if (lCDItemFlags & CDRF_SKIPDEFAULT)
336             return phdi->rect.right;
337     }
338
339     if (theme != NULL) {
340         int state = (phdi->bDown) ? HIS_PRESSED :
341             (bHotTrack ? HIS_HOT : HIS_NORMAL);
342         DrawThemeBackground (theme, hdc, HP_HEADERITEM, state,
343             &r, NULL);
344         GetThemeBackgroundContentRect (theme, hdc, HP_HEADERITEM, state,
345             &r, &r);
346     }
347     else {
348         HBRUSH hbr;
349     
350         if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) {
351             if (phdi->bDown) {
352                 DrawEdge (hdc, &r, BDR_RAISEDOUTER,
353                             BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST);
354             }
355             else
356                 DrawEdge (hdc, &r, EDGE_RAISED,
357                             BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
358         }
359         else
360             DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
361
362         hbr = CreateSolidBrush(GetBkColor(hdc));
363         FillRect(hdc, &r, hbr);
364         DeleteObject(hbr);
365     }
366     if (phdi->bDown) {
367         r.left += 2;
368         r.top  += 2;
369     }
370
371     if (phdi->fmt & HDF_OWNERDRAW) {
372         DRAWITEMSTRUCT dis;
373
374         dis.CtlType    = ODT_HEADER;
375         dis.CtlID      = GetWindowLongPtrW (hwnd, GWLP_ID);
376         dis.itemID     = iItem;
377         dis.itemAction = ODA_DRAWENTIRE;
378         dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
379         dis.hwndItem   = hwnd;
380         dis.hDC        = hdc;
381         dis.rcItem     = phdi->rect;
382         dis.itemData   = phdi->lParam;
383         oldBkMode = SetBkMode(hdc, TRANSPARENT);
384         SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM,
385                         (WPARAM)dis.CtlID, (LPARAM)&dis);
386         if (oldBkMode != TRANSPARENT)
387             SetBkMode(hdc, oldBkMode);
388     }
389     else {
390         UINT rw, rh, /* width and height of r */
391              *x = NULL, *w = NULL; /* x and width of the pic (bmp or img) which is part of cnt */
392           /* cnt,txt,img,bmp */
393         UINT cx, tx, ix, bx,
394              cw, tw, iw, bw;
395         BITMAP bmp;
396
397         HEADER_PrepareCallbackItems(hwnd, iItem, HDI_TEXT|HDI_IMAGE);
398         cw = tw = iw = bw = 0;
399         rw = r.right - r.left;
400         rh = r.bottom - r.top;
401
402         if (phdi->fmt & HDF_STRING) {
403             RECT textRect;
404
405             DrawTextW (hdc, phdi->pszText, -1,
406                        &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
407             cw = textRect.right - textRect.left + 2 * infoPtr->iMargin;
408         }
409
410         if ((phdi->fmt & HDF_IMAGE) && (infoPtr->himl)) {
411             iw = infoPtr->himl->cx + 2 * infoPtr->iMargin;
412             x = &ix;
413             w = &iw;
414         }
415
416         if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) {
417             GetObjectW (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp);
418             bw = bmp.bmWidth + 2 * infoPtr->iMargin;
419             if (!iw) {
420                 x = &bx;
421                 w = &bw;
422             }
423         }
424
425         if (bw || iw)
426             cw += *w; 
427
428         /* align cx using the unclipped cw */
429         if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT)
430             cx = r.left;
431         else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
432             cx = r.left + rw / 2 - cw / 2;
433         else /* HDF_RIGHT */
434             cx = r.right - cw;
435         
436         /* clip cx & cw */
437         if (cx < r.left)
438             cx = r.left;
439         if (cx + cw > r.right)
440             cw = r.right - cx;
441         
442         tx = cx + infoPtr->iMargin;
443         /* since cw might have changed we have to recalculate tw */
444         tw = cw - infoPtr->iMargin * 2;
445                         
446         if (iw || bw) {
447             tw -= *w;
448             if (phdi->fmt & HDF_BITMAP_ON_RIGHT) {
449                 /* put pic behind text */
450                 *x = cx + tw + infoPtr->iMargin * 3;
451             } else {
452                 *x = cx + infoPtr->iMargin;
453                 /* move text behind pic */
454                 tx += *w;
455             }
456         }
457
458         if (iw && bw) {
459             /* since we're done with the layout we can
460                now calculate the position of bmp which
461                has no influence on alignment and layout
462                because of img */
463             if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
464                 bx = cx - bw + infoPtr->iMargin;
465             else
466                 bx = cx + cw + infoPtr->iMargin;
467         }
468
469         if (iw || bw) {
470             HDC hClipDC = GetDC(hwnd);
471             HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
472             SelectClipRgn(hClipDC, hClipRgn);
473             
474             if (bw) {
475                 HDC hdcBitmap = CreateCompatibleDC (hClipDC);
476                 SelectObject (hdcBitmap, phdi->hbm);
477                 BitBlt (hClipDC, bx, r.top + ((INT)rh - bmp.bmHeight) / 2, 
478                         bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
479                 DeleteDC (hdcBitmap);
480             }
481
482             if (iw) {
483                 ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, 
484                                   ix, r.top + ((INT)rh - infoPtr->himl->cy) / 2,
485                                   infoPtr->himl->cx, infoPtr->himl->cy, CLR_DEFAULT, CLR_DEFAULT, 0);
486             }
487
488             DeleteObject(hClipRgn);
489             ReleaseDC(hwnd, hClipDC);
490         }
491         
492         if (((phdi->fmt & HDF_STRING)
493                 || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP|
494                                    HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */
495             && (phdi->pszText)) {
496             oldBkMode = SetBkMode(hdc, TRANSPARENT);
497             r.left  = tx;
498             r.right = tx + tw;
499             DrawTextW (hdc, phdi->pszText, -1,
500                        &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE);
501             if (oldBkMode != TRANSPARENT)
502                 SetBkMode(hdc, oldBkMode);
503         }
504         HEADER_FreeCallbackItems(phdi);
505     }/*Ownerdrawn*/
506
507     return phdi->rect.right;
508 }
509
510 static void
511 HEADER_DrawHotDivider(HWND hwnd, HDC hdc)
512 {
513     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
514     HBRUSH brush;
515     RECT r;
516     
517     HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
518     brush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
519     FillRect(hdc, &r, brush);
520     DeleteObject(brush);
521 }
522
523 static void
524 HEADER_Refresh (HWND hwnd, HDC hdc)
525 {
526     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
527     HFONT hFont, hOldFont;
528     RECT rect, rcRest;
529     HBRUSH hbrBk;
530     UINT i;
531     INT x;
532     LRESULT lCDFlags;
533     HTHEME theme = GetWindowTheme (hwnd);
534
535     if (!infoPtr->bRectsValid)
536         HEADER_SetItemBounds(hwnd);
537
538     /* get rect for the bar, adjusted for the border */
539     GetClientRect (hwnd, &rect);
540     lCDFlags = HEADER_SendCtrlCustomDraw(hwnd, CDDS_PREPAINT, hdc, &rect);
541     
542     if (infoPtr->bDragging)
543         ImageList_DragShowNolock(FALSE);
544
545     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
546     hOldFont = SelectObject (hdc, hFont);
547
548     /* draw Background */
549     if (infoPtr->uNumItem == 0 && theme == NULL) {
550         hbrBk = GetSysColorBrush(COLOR_3DFACE);
551         FillRect(hdc, &rect, hbrBk);
552     }
553
554     x = rect.left;
555     for (i = 0; x <= rect.right && i < infoPtr->uNumItem; i++) {
556         int idx = HEADER_OrderToIndex(hwnd,i);
557         if (RectVisible(hdc, &infoPtr->items[idx].rect))
558             HEADER_DrawItem(hwnd, hdc, idx, infoPtr->iHotItem == idx, lCDFlags);
559         x = infoPtr->items[idx].rect.right;
560     }
561
562     rcRest = rect;
563     rcRest.left = x;
564     if ((x <= rect.right) && RectVisible(hdc, &rcRest) && (infoPtr->uNumItem > 0)) {
565         if (theme != NULL) {
566             DrawThemeBackground(theme, hdc, HP_HEADERITEM, HIS_NORMAL, &rcRest, NULL);
567         }
568         else {
569             if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS)
570                 DrawEdge (hdc, &rcRest, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT|BF_MIDDLE);
571             else
572                 DrawEdge (hdc, &rcRest, EDGE_ETCHED, BF_BOTTOM|BF_MIDDLE);
573         }
574     }
575     
576     if (infoPtr->iHotDivider != -1)
577         HEADER_DrawHotDivider(hwnd, hdc);
578
579     if (infoPtr->bDragging)
580         ImageList_DragShowNolock(TRUE);
581     SelectObject (hdc, hOldFont);
582     
583     if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
584         HEADER_SendCtrlCustomDraw(hwnd, CDDS_POSTPAINT, hdc, &rect);
585 }
586
587
588 static void
589 HEADER_RefreshItem (HWND hwnd, HDC hdc, INT iItem)
590 {
591     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
592
593     if (!infoPtr->bRectsValid)
594         HEADER_SetItemBounds(hwnd);
595
596     InvalidateRect(hwnd, &infoPtr->items[iItem].rect, FALSE);
597 }
598
599
600 static void
601 HEADER_InternalHitTest (HWND hwnd, LPPOINT lpPt, UINT *pFlags, INT *pItem)
602 {
603     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
604     RECT rect, rcTest;
605     UINT iCount;
606     INT width;
607     BOOL bNoWidth;
608
609     GetClientRect (hwnd, &rect);
610
611     *pFlags = 0;
612     bNoWidth = FALSE;
613     if (PtInRect (&rect, *lpPt))
614     {
615         if (infoPtr->uNumItem == 0) {
616             *pFlags |= HHT_NOWHERE;
617             *pItem = 1;
618             TRACE("NOWHERE\n");
619             return;
620         }
621         else {
622             /* somewhere inside */
623             for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
624                 rect = infoPtr->items[iCount].rect;
625                 width = rect.right - rect.left;
626                 if (width == 0) {
627                     bNoWidth = TRUE;
628                     continue;
629                 }
630                 if (PtInRect (&rect, *lpPt)) {
631                     if (width <= 2 * DIVIDER_WIDTH) {
632                         *pFlags |= HHT_ONHEADER;
633                         *pItem = iCount;
634                         TRACE("ON HEADER %d\n", iCount);
635                         return;
636                     }
637                     if (HEADER_IndexToOrder(hwnd, iCount) > 0) {
638                         rcTest = rect;
639                         rcTest.right = rcTest.left + DIVIDER_WIDTH;
640                         if (PtInRect (&rcTest, *lpPt)) {
641                             if (bNoWidth) {
642                                 *pFlags |= HHT_ONDIVOPEN;
643                                 *pItem = HEADER_PrevItem(hwnd, iCount);
644                                 TRACE("ON DIVOPEN %d\n", *pItem);
645                                 return;
646                             }
647                             else {
648                                 *pFlags |= HHT_ONDIVIDER;
649                                 *pItem = HEADER_PrevItem(hwnd, iCount);
650                                 TRACE("ON DIVIDER %d\n", *pItem);
651                                 return;
652                             }
653                         }
654                     }
655                     rcTest = rect;
656                     rcTest.left = rcTest.right - DIVIDER_WIDTH;
657                     if (PtInRect (&rcTest, *lpPt)) {
658                         *pFlags |= HHT_ONDIVIDER;
659                         *pItem = iCount;
660                         TRACE("ON DIVIDER %d\n", *pItem);
661                         return;
662                     }
663
664                     *pFlags |= HHT_ONHEADER;
665                     *pItem = iCount;
666                     TRACE("ON HEADER %d\n", iCount);
667                     return;
668                 }
669             }
670
671             /* check for last divider part (on nowhere) */
672             rect = infoPtr->items[infoPtr->uNumItem-1].rect;
673             rect.left = rect.right;
674             rect.right += DIVIDER_WIDTH;
675             if (PtInRect (&rect, *lpPt)) {
676                 if (bNoWidth) {
677                     *pFlags |= HHT_ONDIVOPEN;
678                     *pItem = infoPtr->uNumItem - 1;
679                     TRACE("ON DIVOPEN %d\n", *pItem);
680                     return;
681                 }
682                 else {
683                     *pFlags |= HHT_ONDIVIDER;
684                     *pItem = infoPtr->uNumItem-1;
685                     TRACE("ON DIVIDER %d\n", *pItem);
686                     return;
687                 }
688             }
689
690             *pFlags |= HHT_NOWHERE;
691             *pItem = 1;
692             TRACE("NOWHERE\n");
693             return;
694         }
695     }
696     else {
697         if (lpPt->x < rect.left) {
698            TRACE("TO LEFT\n");
699            *pFlags |= HHT_TOLEFT;
700         }
701         else if (lpPt->x > rect.right) {
702             TRACE("TO RIGHT\n");
703             *pFlags |= HHT_TORIGHT;
704         }
705
706         if (lpPt->y < rect.top) {
707             TRACE("ABOVE\n");
708             *pFlags |= HHT_ABOVE;
709         }
710         else if (lpPt->y > rect.bottom) {
711             TRACE("BELOW\n");
712             *pFlags |= HHT_BELOW;
713         }
714     }
715
716     *pItem = 1;
717     TRACE("flags=0x%X\n", *pFlags);
718     return;
719 }
720
721
722 static void
723 HEADER_DrawTrackLine (HWND hwnd, HDC hdc, INT x)
724 {
725     RECT rect;
726     HPEN hOldPen;
727     INT  oldRop;
728
729     GetClientRect (hwnd, &rect);
730
731     hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN));
732     oldRop = SetROP2 (hdc, R2_XORPEN);
733     MoveToEx (hdc, x, rect.top, NULL);
734     LineTo (hdc, x, rect.bottom);
735     SetROP2 (hdc, oldRop);
736     SelectObject (hdc, hOldPen);
737 }
738
739 /***
740  * DESCRIPTION:
741  * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
742  *
743  * PARAMETER(S):
744  * [I] infoPtr : the header that wants to send the notify
745  * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
746  * [I] src  : The source HDITEM. It may be a HDITEMA or HDITEMW
747  * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
748  * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
749  *                  the HDITEM is no longer in use or NULL if none was needed
750  * 
751  * NOTE: We depend on HDITEMA and HDITEMW having the same structure
752  */
753 static void HEADER_CopyHDItemForNotify(HEADER_INFO *infoPtr, HDITEMW *dest,
754     HDITEMW *src, BOOL fSourceUnicode, LPVOID *ppvScratch)
755 {
756     *ppvScratch = NULL;
757     *dest = *src;
758     
759     if (src->mask & HDI_TEXT && src->pszText != LPSTR_TEXTCALLBACKW) /* covers TEXTCALLBACKA as well */
760     {
761         if (fSourceUnicode && infoPtr->nNotifyFormat != NFR_UNICODE)
762         {
763             dest->pszText = NULL;
764             Str_SetPtrWtoA((LPSTR *)&dest->pszText, src->pszText);
765             *ppvScratch = dest->pszText;
766         }
767         
768         if (!fSourceUnicode && infoPtr->nNotifyFormat == NFR_UNICODE)
769         {
770             dest->pszText = NULL;
771             Str_SetPtrAtoW(&dest->pszText, (LPSTR)src->pszText);
772             *ppvScratch = dest->pszText;
773         }
774     }
775 }
776
777 static UINT HEADER_NotifyCodeWtoA(UINT code)
778 {
779     /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
780     if (code >= HDN_LAST && code <= HDN_FIRST_UNICODE)
781         return code + HDN_UNICODE_OFFSET;
782     else
783         return code;
784 }
785
786 static LRESULT
787 HEADER_SendNotify(HWND hwnd, UINT code, NMHDR *nmhdr)
788 {
789     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
790
791     nmhdr->hwndFrom = hwnd;
792     nmhdr->idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
793     nmhdr->code     = code;
794
795     return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
796                                    (WPARAM)nmhdr->idFrom, (LPARAM)nmhdr);
797 }
798
799 static BOOL
800 HEADER_SendSimpleNotify (HWND hwnd, UINT code)
801 {
802     NMHDR nmhdr;
803     return (BOOL)HEADER_SendNotify(hwnd, code, &nmhdr);
804 }
805
806 static LRESULT
807 HEADER_SendCtrlCustomDraw(HWND hwnd, DWORD dwDrawStage, HDC hdc, RECT *rect)
808 {
809     NMCUSTOMDRAW nm;
810     nm.dwDrawStage = dwDrawStage;
811     nm.hdc = hdc;
812     nm.rc = *rect;
813     nm.dwItemSpec = 0;
814     nm.uItemState = 0;
815     nm.lItemlParam = 0;
816
817     return HEADER_SendNotify(hwnd, NM_CUSTOMDRAW, (NMHDR *)&nm);
818 }
819
820 static BOOL
821 HEADER_SendNotifyWithHDItemT(HWND hwnd, UINT code, INT iItem, HDITEMW *lpItem)
822 {
823     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
824     NMHEADERW nmhdr;
825     
826     if (infoPtr->nNotifyFormat != NFR_UNICODE)
827         code = HEADER_NotifyCodeWtoA(code);
828     nmhdr.iItem = iItem;
829     nmhdr.iButton = 0;
830     nmhdr.pitem = lpItem;
831
832     return (BOOL)HEADER_SendNotify(hwnd, code, (NMHDR *)&nmhdr);
833 }
834
835 static BOOL
836 HEADER_SendNotifyWithIntFieldT(HWND hwnd, UINT code, INT iItem, INT mask, INT iValue)
837 {
838     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
839     HDITEMW nmitem;
840
841     /* copying only the iValue should be ok but to make the code more robust we copy everything */
842     nmitem.cxy = infoPtr->items[iItem].cxy;
843     nmitem.hbm = infoPtr->items[iItem].hbm;
844     nmitem.pszText = NULL;
845     nmitem.cchTextMax = 0;
846     nmitem.fmt = infoPtr->items[iItem].fmt;
847     nmitem.lParam = infoPtr->items[iItem].lParam;
848     nmitem.iOrder = infoPtr->items[iItem].iOrder;
849     nmitem.iImage = infoPtr->items[iItem].iImage;
850
851     nmitem.mask = mask;
852     switch (mask)
853     {
854         case HDI_WIDTH:
855             nmitem.cxy = iValue;
856             break;
857         case HDI_ORDER:
858             nmitem.iOrder = iValue;
859             break;
860         default:
861             ERR("invalid mask value 0x%x\n", iValue);
862     }
863
864     return HEADER_SendNotifyWithHDItemT(hwnd, code, iItem, &nmitem);
865 }
866
867 /**
868  * Prepare callback items
869  *   depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA 
870  *   (so we handle the two cases only doing a specific cast for pszText).
871  * Checks if any of the required field are callback. If there are sends a 
872  * NMHDISPINFO notify to retrieve these items. The items are stored in the
873  * HEADER_ITEM pszText and iImage fields. They should be freed with
874  * HEADER_FreeCallbackItems.
875  *
876  * @param hwnd : hwnd header container handler
877  * @param iItem : the header item id
878  * @param reqMask : required fields. If any of them is callback this function will fetch it
879  *
880  * @return TRUE on success, else FALSE
881  */
882 static BOOL
883 HEADER_PrepareCallbackItems(HWND hwnd, INT iItem, INT reqMask)
884 {
885     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
886     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
887     DWORD mask = reqMask & lpItem->callbackMask;
888     NMHDDISPINFOW dispInfo;
889     void *pvBuffer = NULL;
890
891     if (mask == 0)
892         return TRUE;
893     if (mask&HDI_TEXT && lpItem->pszText != NULL)
894     {
895         ERR("(): function called without a call to FreeCallbackItems\n");
896         Free(lpItem->pszText);
897         lpItem->pszText = NULL;
898     }
899     
900     memset(&dispInfo, 0, sizeof(NMHDDISPINFOW));
901     dispInfo.hdr.hwndFrom = hwnd;
902     dispInfo.hdr.idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
903     if (infoPtr->nNotifyFormat == NFR_UNICODE)
904     {
905         dispInfo.hdr.code = HDN_GETDISPINFOW;
906         if (mask & HDI_TEXT)
907             pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(WCHAR));
908     }
909     else
910     {
911         dispInfo.hdr.code = HDN_GETDISPINFOA;
912         if (mask & HDI_TEXT)
913             pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(CHAR));
914     }
915     dispInfo.pszText      = (LPWSTR)pvBuffer;
916     dispInfo.cchTextMax   = (pvBuffer!=NULL?MAX_HEADER_TEXT_LEN:0);
917     dispInfo.iItem        = iItem;
918     dispInfo.mask         = mask;
919     dispInfo.lParam       = lpItem->lParam;
920     
921     TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr->nNotifyFormat == NFR_UNICODE?'W':'A');
922     SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, 
923                  (WPARAM) dispInfo.hdr.idFrom, 
924                  (LPARAM) &dispInfo);
925
926     TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n", 
927           dispInfo.mask,
928           (infoPtr->nNotifyFormat == NFR_UNICODE ? debugstr_w(dispInfo.pszText) : (LPSTR) dispInfo.pszText),
929           (void*) dispInfo.lParam);
930           
931     if (mask & HDI_IMAGE)
932         lpItem->iImage = dispInfo.iImage;
933     if (mask & HDI_TEXT)
934     {
935         if (infoPtr->nNotifyFormat == NFR_UNICODE)
936         {
937             lpItem->pszText = (LPWSTR)pvBuffer;
938
939             /* the user might have used his own buffer */
940             if (dispInfo.pszText != lpItem->pszText)
941                 Str_GetPtrW(dispInfo.pszText, lpItem->pszText, MAX_HEADER_TEXT_LEN);
942         }
943         else
944         {
945             Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)dispInfo.pszText);
946             Free(pvBuffer);
947         }
948     }
949         
950     if (dispInfo.mask & HDI_DI_SETITEM) 
951     {
952         /* make the items permanent */
953         lpItem->callbackMask &= ~dispInfo.mask;
954     }
955     
956     return TRUE;
957 }
958
959 /***
960  * DESCRIPTION:
961  * Free the items that might be allocated with HEADER_PrepareCallbackItems
962  *
963  * PARAMETER(S):
964  * [I] lpItem : the item to free the data
965  *
966  */
967 static void
968 HEADER_FreeCallbackItems(HEADER_ITEM *lpItem)
969 {
970     if (lpItem->callbackMask&HDI_TEXT && lpItem->pszText != NULL)
971     {
972         Free(lpItem->pszText);
973         lpItem->pszText = NULL;
974     }
975     
976     if (lpItem->callbackMask&HDI_IMAGE)
977         lpItem->iImage = I_IMAGECALLBACK;
978 }
979
980 static LRESULT
981 HEADER_CreateDragImage (HWND hwnd, WPARAM wParam)
982 {
983     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
984     HEADER_ITEM *lpItem;
985     HIMAGELIST himl;
986     HBITMAP hMemory, hOldBitmap;
987     LRESULT lCDFlags;
988     RECT rc;
989     HDC hMemoryDC;
990     HDC hDeviceDC;
991     int height, width;
992     
993     if (wParam < 0 || wParam >= infoPtr->uNumItem)
994         return FALSE;
995
996     if (!infoPtr->bRectsValid)
997         HEADER_SetItemBounds(hwnd);
998
999     lpItem = &infoPtr->items[wParam];
1000     width = lpItem->rect.right - lpItem->rect.left;
1001     height = lpItem->rect.bottom - lpItem->rect.top;
1002     
1003     hDeviceDC = GetDC(NULL);
1004     hMemoryDC = CreateCompatibleDC(hDeviceDC);
1005     hMemory = CreateCompatibleBitmap(hDeviceDC, width, height);
1006     ReleaseDC(NULL, hDeviceDC);
1007     hOldBitmap = SelectObject(hMemoryDC, hMemory);
1008     SetViewportOrgEx(hMemoryDC, -lpItem->rect.left, -lpItem->rect.top, NULL);
1009
1010     GetClientRect(hwnd, &rc);
1011     lCDFlags = HEADER_SendCtrlCustomDraw(hwnd, CDDS_PREPAINT, hMemoryDC, &rc);
1012     HEADER_DrawItem(hwnd, hMemoryDC, wParam, FALSE, lCDFlags);
1013     if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
1014         HEADER_SendCtrlCustomDraw(hwnd, CDDS_POSTPAINT, hMemoryDC, &rc);
1015     
1016     hMemory = SelectObject(hMemoryDC, hOldBitmap);
1017     DeleteDC(hMemoryDC);
1018     
1019     if (hMemory == NULL)    /* if anything failed */
1020         return FALSE;
1021     
1022     himl = ImageList_Create(width, height, ILC_COLORDDB, 1, 1);
1023     ImageList_Add(himl, hMemory, NULL);
1024     DeleteObject(hMemory);
1025     return (LRESULT)himl;
1026 }
1027
1028 static LRESULT
1029 HEADER_SetHotDivider(HWND hwnd, WPARAM wParam, LPARAM lParam)
1030 {
1031     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1032     INT iDivider;
1033     RECT r;
1034     
1035     if (wParam)
1036     {
1037         POINT pt;
1038         UINT flags;
1039         pt.x = (INT)(SHORT)LOWORD(lParam);
1040         pt.y = 0;
1041         HEADER_InternalHitTest (hwnd, &pt, &flags, &iDivider);
1042         
1043         if (flags & HHT_TOLEFT)
1044             iDivider = 0;
1045         else if (flags & HHT_NOWHERE || flags & HHT_TORIGHT)
1046             iDivider = infoPtr->uNumItem;
1047         else
1048         {
1049             HEADER_ITEM *lpItem = &infoPtr->items[iDivider];
1050             if (pt.x > (lpItem->rect.left+lpItem->rect.right)/2)
1051                 iDivider = HEADER_NextItem(hwnd, iDivider);
1052         }
1053     }
1054     else
1055         iDivider = (INT)lParam;
1056         
1057     /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */
1058     if (iDivider<-1 || iDivider>(int)infoPtr->uNumItem)
1059         return iDivider;
1060
1061     if (iDivider != infoPtr->iHotDivider)
1062     {
1063         if (infoPtr->iHotDivider != -1)
1064         {
1065             HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
1066             InvalidateRect(hwnd, &r, FALSE);
1067         }
1068         infoPtr->iHotDivider = iDivider;
1069         if (iDivider != -1)
1070         {
1071             HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
1072             InvalidateRect(hwnd, &r, FALSE);
1073         }
1074     }
1075     return iDivider;
1076 }
1077
1078 static LRESULT
1079 HEADER_DeleteItem (HWND hwnd, WPARAM wParam)
1080 {
1081     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1082     INT iItem = (INT)wParam;
1083     INT iOrder;
1084     INT i;
1085
1086     TRACE("[iItem=%d]\n", iItem);
1087
1088     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
1089         return FALSE;
1090
1091     for (i = 0; i < infoPtr->uNumItem; i++)
1092        TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
1093
1094     iOrder = infoPtr->items[iItem].iOrder;
1095     HEADER_DisposeItem(&infoPtr->items[iItem]);
1096
1097     infoPtr->uNumItem--;
1098     memmove(&infoPtr->items[iItem], &infoPtr->items[iItem + 1],
1099             (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM));
1100     memmove(&infoPtr->order[iOrder], &infoPtr->order[iOrder + 1],
1101             (infoPtr->uNumItem - iOrder) * sizeof(INT));
1102     infoPtr->items = ReAlloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem);
1103     infoPtr->order = ReAlloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem);
1104         
1105     /* Correct the orders */
1106     for (i = 0; i < infoPtr->uNumItem; i++)
1107     {
1108         if (infoPtr->order[i] > iItem)
1109             infoPtr->order[i]--;
1110         if (i >= iOrder)
1111             infoPtr->items[infoPtr->order[i]].iOrder = i;
1112     }
1113     for (i = 0; i < infoPtr->uNumItem; i++)
1114        TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
1115
1116     HEADER_SetItemBounds (hwnd);
1117     InvalidateRect(hwnd, NULL, FALSE);
1118
1119     return TRUE;
1120 }
1121
1122
1123 static LRESULT
1124 HEADER_GetImageList (HWND hwnd)
1125 {
1126     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1127
1128     return (LRESULT)infoPtr->himl;
1129 }
1130
1131
1132 static LRESULT
1133 HEADER_GetItemT (HWND hwnd, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
1134 {
1135     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1136     HEADER_ITEM *lpItem;
1137     UINT mask;
1138
1139     if (!phdi)
1140         return FALSE;
1141
1142     TRACE("[nItem=%d]\n", nItem);
1143
1144     mask = phdi->mask;
1145     if (mask == 0)
1146         return TRUE;
1147
1148     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1149         return FALSE;
1150
1151     if (mask & HDI_UNKNOWN_FIELDS)
1152     {
1153         TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask);
1154         mask &= HDI_COMCTL32_4_0_FIELDS;
1155     }
1156     
1157     lpItem = &infoPtr->items[nItem];
1158     HEADER_PrepareCallbackItems(hwnd, nItem, mask);
1159
1160     if (mask & HDI_BITMAP)
1161         phdi->hbm = lpItem->hbm;
1162
1163     if (mask & HDI_FORMAT)
1164         phdi->fmt = lpItem->fmt;
1165
1166     if (mask & HDI_WIDTH)
1167         phdi->cxy = lpItem->cxy;
1168
1169     if (mask & HDI_LPARAM)
1170         phdi->lParam = lpItem->lParam;
1171
1172     if (mask & HDI_IMAGE) 
1173         phdi->iImage = lpItem->iImage;
1174
1175     if (mask & HDI_ORDER)
1176         phdi->iOrder = lpItem->iOrder;
1177
1178     if (mask & HDI_TEXT)
1179     {
1180         if (bUnicode)
1181             Str_GetPtrW (lpItem->pszText, phdi->pszText, phdi->cchTextMax);
1182         else
1183             Str_GetPtrWtoA (lpItem->pszText, (LPSTR)phdi->pszText, phdi->cchTextMax);
1184     }
1185
1186     HEADER_FreeCallbackItems(lpItem);
1187     return TRUE;
1188 }
1189
1190
1191 inline static LRESULT
1192 HEADER_GetItemCount (HWND hwnd)
1193 {
1194     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1195     return infoPtr->uNumItem;
1196 }
1197
1198
1199 static LRESULT
1200 HEADER_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
1201 {
1202     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1203     INT iItem = (INT)wParam;
1204     LPRECT lpRect = (LPRECT)lParam;
1205
1206     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
1207         return FALSE;
1208
1209     lpRect->left   = infoPtr->items[iItem].rect.left;
1210     lpRect->right  = infoPtr->items[iItem].rect.right;
1211     lpRect->top    = infoPtr->items[iItem].rect.top;
1212     lpRect->bottom = infoPtr->items[iItem].rect.bottom;
1213
1214     return TRUE;
1215 }
1216
1217
1218 static LRESULT
1219 HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
1220 {
1221     LPINT order = (LPINT) lParam;
1222     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1223
1224     if ((unsigned int)wParam <infoPtr->uNumItem)
1225       return FALSE;
1226
1227     memcpy(order, infoPtr->order, infoPtr->uNumItem * sizeof(INT));
1228     return TRUE;
1229 }
1230
1231 static LRESULT
1232 HEADER_SetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
1233 {
1234     int i;
1235     LPINT order = (LPINT) lParam;
1236     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1237     HEADER_ITEM *lpItem;
1238
1239     if ((unsigned int)wParam <infoPtr->uNumItem)
1240       return FALSE;
1241     memcpy(infoPtr->order, order, infoPtr->uNumItem * sizeof(INT));
1242     for (i=0; i<(int)wParam; i++)
1243       {
1244         lpItem = &infoPtr->items[*order++];
1245         lpItem->iOrder=i;
1246       }
1247     infoPtr->bRectsValid=0;
1248     InvalidateRect(hwnd, NULL, FALSE);
1249     return TRUE;
1250 }
1251
1252 inline static LRESULT
1253 HEADER_GetUnicodeFormat (HWND hwnd)
1254 {
1255     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1256     return (infoPtr->nNotifyFormat == NFR_UNICODE);
1257 }
1258
1259
1260 static LRESULT
1261 HEADER_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
1262 {
1263     LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam;
1264
1265     HEADER_InternalHitTest (hwnd, &phti->pt, &phti->flags, &phti->iItem);
1266
1267     if (phti->flags == HHT_NOWHERE)
1268         return -1;
1269     else
1270         return phti->iItem;
1271 }
1272
1273
1274 static LRESULT
1275 HEADER_InsertItemT (HWND hwnd, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
1276 {
1277     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1278     HEADER_ITEM *lpItem;
1279     INT       iOrder;
1280     UINT      i;
1281     UINT      copyMask;
1282
1283     if ((phdi == NULL) || (nItem < 0) || (phdi->mask == 0))
1284         return -1;
1285
1286     if (nItem > infoPtr->uNumItem)
1287         nItem = infoPtr->uNumItem;
1288
1289     iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem;
1290     if (iOrder < 0)
1291         iOrder = 0;
1292     else if (infoPtr->uNumItem < iOrder)
1293         iOrder = infoPtr->uNumItem;
1294
1295     infoPtr->uNumItem++;
1296     infoPtr->items = ReAlloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem);
1297     infoPtr->order = ReAlloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem);
1298     
1299     /* make space for the new item */
1300     memmove(&infoPtr->items[nItem + 1], &infoPtr->items[nItem],
1301             (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM));
1302     memmove(&infoPtr->order[iOrder + 1], &infoPtr->order[iOrder],
1303            (infoPtr->uNumItem - iOrder - 1) * sizeof(INT));
1304
1305     /* update the order array */
1306     infoPtr->order[iOrder] = nItem;
1307     for (i = 0; i < infoPtr->uNumItem; i++)
1308     {
1309         if (i != iOrder && infoPtr->order[i] >= nItem)
1310             infoPtr->order[i]++;
1311         infoPtr->items[infoPtr->order[i]].iOrder = i;
1312     }
1313
1314     lpItem = &infoPtr->items[nItem];
1315     ZeroMemory(lpItem, sizeof(HEADER_ITEM));
1316     /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
1317     copyMask = phdi->mask | HDI_WIDTH | HDI_FORMAT | HDI_LPARAM;
1318     HEADER_StoreHDItemInHeader(lpItem, copyMask, phdi, bUnicode);
1319     lpItem->iOrder = iOrder;
1320
1321     /* set automatically some format bits */
1322     if (phdi->mask & HDI_TEXT)
1323         lpItem->fmt |= HDF_STRING;
1324     else
1325         lpItem->fmt &= ~HDF_STRING;
1326
1327     if (lpItem->hbm != NULL)
1328         lpItem->fmt |= HDF_BITMAP;
1329     else
1330         lpItem->fmt &= ~HDF_BITMAP;
1331
1332     if (phdi->mask & HDI_IMAGE)
1333         lpItem->fmt |= HDF_IMAGE;
1334
1335     HEADER_SetItemBounds (hwnd);
1336     InvalidateRect(hwnd, NULL, FALSE);
1337
1338     return nItem;
1339 }
1340
1341
1342 static LRESULT
1343 HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam)
1344 {
1345     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1346     LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam;
1347
1348     lpLayout->pwpos->hwnd = hwnd;
1349     lpLayout->pwpos->hwndInsertAfter = 0;
1350     lpLayout->pwpos->x = lpLayout->prc->left;
1351     lpLayout->pwpos->y = lpLayout->prc->top;
1352     lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
1353     if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_HIDDEN)
1354         lpLayout->pwpos->cy = 0;
1355     else {
1356         lpLayout->pwpos->cy = infoPtr->nHeight;
1357         lpLayout->prc->top += infoPtr->nHeight;
1358     }
1359     lpLayout->pwpos->flags = SWP_NOZORDER;
1360
1361     TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1362            lpLayout->pwpos->x, lpLayout->pwpos->y,
1363            lpLayout->pwpos->cx, lpLayout->pwpos->cy);
1364
1365     infoPtr->bRectsValid = FALSE;
1366
1367     return TRUE;
1368 }
1369
1370
1371 static LRESULT
1372 HEADER_SetImageList (HWND hwnd, HIMAGELIST himl)
1373 {
1374     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1375     HIMAGELIST himlOld;
1376
1377     TRACE("(himl %p)\n", himl);
1378     himlOld = infoPtr->himl;
1379     infoPtr->himl = himl;
1380
1381     /* FIXME: Refresh needed??? */
1382
1383     return (LRESULT)himlOld;
1384 }
1385
1386
1387 static LRESULT
1388 HEADER_GetBitmapMargin(HWND hwnd)
1389 {
1390     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1391     
1392     return infoPtr->iMargin;
1393 }
1394
1395 static LRESULT
1396 HEADER_SetBitmapMargin(HWND hwnd, WPARAM wParam)
1397 {
1398     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1399     INT oldMargin = infoPtr->iMargin;
1400
1401     infoPtr->iMargin = (INT)wParam;
1402
1403     return oldMargin;
1404 }
1405
1406 static LRESULT
1407 HEADER_SetItemT (HWND hwnd, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
1408 {
1409     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1410     HEADER_ITEM *lpItem;
1411     HDITEMW hdNotify;
1412     void *pvScratch;
1413
1414     if (phdi == NULL)
1415         return FALSE;
1416     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1417         return FALSE;
1418
1419     TRACE("[nItem=%d]\n", nItem);
1420
1421     HEADER_CopyHDItemForNotify(infoPtr, &hdNotify, phdi, bUnicode, &pvScratch);
1422     if (HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMCHANGINGW, nItem, &hdNotify))
1423     {
1424         if (pvScratch) Free(pvScratch);
1425         return FALSE;
1426     }
1427
1428     lpItem = &infoPtr->items[nItem];
1429     HEADER_StoreHDItemInHeader(lpItem, phdi->mask, phdi, bUnicode);
1430
1431     if (phdi->mask & HDI_ORDER)
1432         if (phdi->iOrder >= 0 && phdi->iOrder < infoPtr->uNumItem)
1433             HEADER_ChangeItemOrder(infoPtr, nItem, phdi->iOrder);
1434
1435     HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMCHANGEDW, nItem, &hdNotify);
1436
1437     HEADER_SetItemBounds (hwnd);
1438
1439     InvalidateRect(hwnd, NULL, FALSE);
1440
1441     if (pvScratch != NULL)
1442         Free(pvScratch);
1443     return TRUE;
1444 }
1445
1446 inline static LRESULT
1447 HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
1448 {
1449     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1450     BOOL bTemp = (infoPtr->nNotifyFormat == NFR_UNICODE);
1451
1452     infoPtr->nNotifyFormat = ((BOOL)wParam ? NFR_UNICODE : NFR_ANSI);
1453
1454     return bTemp;
1455 }
1456
1457
1458 static LRESULT
1459 HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1460 {
1461     HEADER_INFO *infoPtr;
1462     TEXTMETRICW tm;
1463     HFONT hOldFont;
1464     HDC   hdc;
1465
1466     infoPtr = (HEADER_INFO *)Alloc (sizeof(HEADER_INFO));
1467     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
1468
1469     infoPtr->hwndNotify = ((LPCREATESTRUCTA)lParam)->hwndParent;
1470     infoPtr->uNumItem = 0;
1471     infoPtr->hFont = 0;
1472     infoPtr->items = 0;
1473     infoPtr->order = 0;
1474     infoPtr->bRectsValid = FALSE;
1475     infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1476     infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER));
1477     infoPtr->hcurDivopen = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDEROPEN));
1478     infoPtr->bPressed  = FALSE;
1479     infoPtr->bTracking = FALSE;
1480     infoPtr->iMoveItem = 0;
1481     infoPtr->himl = 0;
1482     infoPtr->iHotItem = -1;
1483     infoPtr->iHotDivider = -1;
1484     infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE);
1485     infoPtr->nNotifyFormat =
1486         SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
1487
1488     hdc = GetDC (0);
1489     hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1490     GetTextMetricsW (hdc, &tm);
1491     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1492     SelectObject (hdc, hOldFont);
1493     ReleaseDC (0, hdc);
1494
1495     OpenThemeData(hwnd, themeClass);
1496
1497     return 0;
1498 }
1499
1500
1501 static LRESULT
1502 HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1503 {
1504     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1505     HEADER_ITEM *lpItem;
1506     INT nItem;
1507     HTHEME theme;
1508
1509     if (infoPtr->items) {
1510         lpItem = infoPtr->items;
1511         for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
1512             HEADER_DisposeItem(lpItem);
1513         }
1514         Free (infoPtr->items);
1515     }
1516
1517     if (infoPtr->order)
1518         Free(infoPtr->order);
1519
1520     if (infoPtr->himl)
1521         ImageList_Destroy (infoPtr->himl);
1522
1523     SetWindowLongPtrW (hwnd, 0, 0);
1524     Free (infoPtr);
1525
1526     theme = GetWindowTheme(hwnd);
1527     CloseThemeData(theme);
1528     return 0;
1529 }
1530
1531
1532 static inline LRESULT
1533 HEADER_GetFont (HWND hwnd)
1534 {
1535     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1536
1537     return (LRESULT)infoPtr->hFont;
1538 }
1539
1540
1541 static BOOL
1542 HEADER_IsDragDistance(HEADER_INFO *infoPtr, POINT *pt)
1543 {
1544     /* Windows allows for a mouse movement before starting the drag. We use the
1545      * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance.
1546      */
1547     return (abs(infoPtr->ptLButtonDown.x - pt->x)>GetSystemMetrics(SM_CXDOUBLECLK) ||
1548             abs(infoPtr->ptLButtonDown.y - pt->y)>GetSystemMetrics(SM_CYDOUBLECLK));
1549 }
1550
1551 static LRESULT
1552 HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
1553 {
1554     POINT pt;
1555     UINT  flags;
1556     INT   nItem;
1557
1558     pt.x = (short)LOWORD(lParam);
1559     pt.y = (short)HIWORD(lParam);
1560     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1561
1562     if ((GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER))
1563         HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMDBLCLICKW, nItem, NULL);
1564     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
1565         HEADER_SendNotifyWithHDItemT(hwnd, HDN_DIVIDERDBLCLICKW, nItem, NULL);
1566
1567     return 0;
1568 }
1569
1570
1571 static LRESULT
1572 HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1573 {
1574     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1575     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1576     POINT pt;
1577     UINT  flags;
1578     INT   nItem;
1579     HDC   hdc;
1580
1581     pt.x = (short)LOWORD(lParam);
1582     pt.y = (short)HIWORD(lParam);
1583     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1584
1585     if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
1586         SetCapture (hwnd);
1587         infoPtr->bCaptured = TRUE;
1588         infoPtr->bPressed  = TRUE;
1589         infoPtr->bDragging = FALSE;
1590         infoPtr->iMoveItem = nItem;
1591         infoPtr->ptLButtonDown = pt;
1592
1593         infoPtr->items[nItem].bDown = TRUE;
1594
1595         /* Send WM_CUSTOMDRAW */
1596         hdc = GetDC (hwnd);
1597         HEADER_RefreshItem (hwnd, hdc, nItem);
1598         ReleaseDC (hwnd, hdc);
1599
1600         TRACE("Pressed item %d!\n", nItem);
1601     }
1602     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
1603         INT iCurrWidth = infoPtr->items[nItem].cxy;
1604         if (!HEADER_SendNotifyWithIntFieldT(hwnd, HDN_BEGINTRACKW, nItem, HDI_WIDTH, iCurrWidth))
1605         {
1606             SetCapture (hwnd);
1607             infoPtr->bCaptured = TRUE;
1608             infoPtr->bTracking = TRUE;
1609             infoPtr->iMoveItem = nItem;
1610             infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
1611
1612             if (!(dwStyle & HDS_FULLDRAG)) {
1613                 infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
1614                 hdc = GetDC (hwnd);
1615                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1616                 ReleaseDC (hwnd, hdc);
1617             }
1618
1619             TRACE("Begin tracking item %d!\n", nItem);
1620         }
1621     }
1622
1623     return 0;
1624 }
1625
1626
1627 static LRESULT
1628 HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1629 {
1630     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1631     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1632     POINT pt;
1633     UINT  flags;
1634     INT   nItem;
1635     HDC   hdc;
1636
1637     pt.x = (INT)(SHORT)LOWORD(lParam);
1638     pt.y = (INT)(SHORT)HIWORD(lParam);
1639     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1640
1641     if (infoPtr->bPressed) {
1642         if (infoPtr->bDragging)
1643         {
1644             HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
1645             INT iNewOrder;
1646             
1647             ImageList_DragShowNolock(FALSE);
1648             ImageList_EndDrag();
1649             lpItem->bDown=FALSE;
1650             
1651             if (infoPtr->iHotDivider == -1)
1652                 iNewOrder = -1;
1653             else if (infoPtr->iHotDivider == infoPtr->uNumItem)
1654                 iNewOrder = infoPtr->uNumItem-1;
1655             else
1656             {
1657                 iNewOrder = HEADER_IndexToOrder(hwnd, infoPtr->iHotDivider);
1658                 if (iNewOrder > lpItem->iOrder)
1659                     iNewOrder--;
1660             }
1661
1662             if (iNewOrder != -1 &&
1663                 !HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ENDDRAG, infoPtr->iMoveItem, HDI_ORDER, iNewOrder))
1664             {
1665                 HEADER_ChangeItemOrder(infoPtr, infoPtr->iMoveItem, iNewOrder);
1666                 infoPtr->bRectsValid = FALSE;
1667                 InvalidateRect(hwnd, NULL, FALSE);
1668             }
1669             else
1670                 InvalidateRect(hwnd, &infoPtr->items[infoPtr->iMoveItem].rect, FALSE);
1671                 
1672             HEADER_SetHotDivider(hwnd, FALSE, -1);
1673         }
1674         else if (!(dwStyle&HDS_DRAGDROP) || !HEADER_IsDragDistance(infoPtr, &pt))
1675         {
1676             infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1677             hdc = GetDC (hwnd);
1678             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1679             ReleaseDC (hwnd, hdc);
1680
1681             HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMCLICKW, infoPtr->iMoveItem, NULL);
1682         }
1683
1684         TRACE("Released item %d!\n", infoPtr->iMoveItem);
1685         infoPtr->bPressed = FALSE;
1686     }
1687     else if (infoPtr->bTracking) {
1688         INT iNewWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1689         if (iNewWidth < 0)
1690             iNewWidth = 0;
1691         TRACE("End tracking item %d!\n", infoPtr->iMoveItem);
1692         infoPtr->bTracking = FALSE;
1693
1694         HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ENDTRACKW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
1695
1696         if (!(dwStyle & HDS_FULLDRAG)) {
1697             hdc = GetDC (hwnd);
1698             HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1699             ReleaseDC (hwnd, hdc);
1700         }
1701           
1702         if (!HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth))
1703         {
1704             infoPtr->items[infoPtr->iMoveItem].cxy = iNewWidth;
1705             HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
1706         }
1707
1708         HEADER_SetItemBounds (hwnd);
1709         InvalidateRect(hwnd, NULL, TRUE);
1710     }
1711
1712     if (infoPtr->bCaptured) {
1713         infoPtr->bCaptured = FALSE;
1714         ReleaseCapture ();
1715         HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE);
1716     }
1717
1718     return 0;
1719 }
1720
1721
1722 static LRESULT
1723 HEADER_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
1724 {
1725     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1726
1727     switch (lParam)
1728     {
1729         case NF_QUERY:
1730             return infoPtr->nNotifyFormat;
1731
1732         case NF_REQUERY:
1733             infoPtr->nNotifyFormat =
1734                 SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT,
1735                               (WPARAM)hwnd, (LPARAM)NF_QUERY);
1736             return infoPtr->nNotifyFormat;
1737     }
1738
1739     return 0;
1740 }
1741
1742 static LRESULT
1743 HEADER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
1744 {
1745     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1746     /* Reset hot-tracked item when mouse leaves control. */
1747     INT oldHotItem = infoPtr->iHotItem;
1748     HDC hdc = GetDC (hwnd);
1749
1750     infoPtr->iHotItem = -1;
1751     if (oldHotItem != -1) HEADER_RefreshItem (hwnd, hdc, oldHotItem);
1752     ReleaseDC (hwnd, hdc);
1753
1754     return 0;
1755 }
1756
1757
1758 static LRESULT
1759 HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1760 {
1761     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1762     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1763     POINT pt;
1764     UINT  flags;
1765     INT   nItem, nWidth;
1766     HDC   hdc;
1767     /* With theming, hottracking is always enabled */
1768     BOOL  hotTrackEnabled =
1769         ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK))
1770         || (GetWindowTheme (hwnd) != NULL);
1771     INT oldHotItem = infoPtr->iHotItem;
1772
1773     pt.x = (INT)(SHORT)LOWORD(lParam);
1774     pt.y = (INT)(SHORT)HIWORD(lParam);
1775     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1776
1777     if (hotTrackEnabled) {
1778         if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
1779             infoPtr->iHotItem = nItem;
1780         else
1781             infoPtr->iHotItem = -1;
1782     }
1783
1784     if (infoPtr->bCaptured) {
1785         /* check if we should drag the header */
1786         if (infoPtr->bPressed && !infoPtr->bDragging && dwStyle&HDS_DRAGDROP
1787             && HEADER_IsDragDistance(infoPtr, &pt))
1788         {
1789             if (!HEADER_SendNotifyWithHDItemT(hwnd, HDN_BEGINDRAG, infoPtr->iMoveItem, NULL))
1790             {
1791                 HIMAGELIST hDragItem = (HIMAGELIST)HEADER_CreateDragImage(hwnd, infoPtr->iMoveItem);
1792                 if (hDragItem != NULL)
1793                 {
1794                     HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
1795                     TRACE("Starting item drag\n");
1796                     ImageList_BeginDrag(hDragItem, 0, pt.x - lpItem->rect.left, 0);
1797                     ImageList_DragShowNolock(TRUE);
1798                     ImageList_Destroy(hDragItem);
1799                     infoPtr->bDragging = TRUE;
1800                 }
1801             }
1802         }
1803         
1804         if (infoPtr->bDragging)
1805         {
1806             POINT drag;
1807             drag.x = pt.x;
1808             drag.y = 0;
1809             ClientToScreen(hwnd, &drag);
1810             ImageList_DragMove(drag.x, drag.y);
1811             HEADER_SetHotDivider(hwnd, TRUE, lParam);
1812         }
1813         
1814         if (infoPtr->bPressed && !infoPtr->bDragging) {
1815             BOOL oldState = infoPtr->items[infoPtr->iMoveItem].bDown;
1816             if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
1817                 infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
1818             else
1819                 infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1820             if (oldState != infoPtr->items[infoPtr->iMoveItem].bDown) {
1821                 hdc = GetDC (hwnd);
1822                 HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1823                 ReleaseDC (hwnd, hdc);
1824             }
1825
1826             TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem);
1827         }
1828         else if (infoPtr->bTracking) {
1829             if (dwStyle & HDS_FULLDRAG) {
1830                 HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
1831                 nWidth = pt.x - lpItem->rect.left + infoPtr->xTrackOffset;
1832                 if (!HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, nWidth))
1833                 {
1834                     INT nOldWidth = lpItem->rect.right - lpItem->rect.left;
1835                     RECT rcClient;
1836                     RECT rcScroll;
1837                     
1838                     if (nWidth < 0) nWidth = 0;
1839                     infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1840                     HEADER_SetItemBounds(hwnd);
1841                     
1842                     GetClientRect(hwnd, &rcClient);
1843                     rcScroll = rcClient;
1844                     rcScroll.left = lpItem->rect.left + nOldWidth;
1845                     ScrollWindowEx(hwnd, nWidth - nOldWidth, 0, &rcScroll, &rcClient, NULL, NULL, 0);
1846                     InvalidateRect(hwnd, &lpItem->rect, FALSE);
1847                     UpdateWindow(hwnd);
1848                     
1849                     HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, nWidth);
1850                 }
1851             }
1852             else {
1853                 INT iTrackWidth;
1854                 hdc = GetDC (hwnd);
1855                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1856                 infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
1857                 if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
1858                     infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
1859                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1860                 ReleaseDC (hwnd, hdc);
1861                 iTrackWidth = infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
1862                 /* FIXME: should stop tracking if HDN_TRACK returns TRUE */
1863                 HEADER_SendNotifyWithIntFieldT(hwnd, HDN_TRACKW, infoPtr->iMoveItem, HDI_WIDTH, iTrackWidth);
1864             }
1865
1866             TRACE("Tracking item %d!\n", infoPtr->iMoveItem);
1867         }
1868     }
1869
1870     if (hotTrackEnabled) {
1871         TRACKMOUSEEVENT tme;
1872         if (oldHotItem != infoPtr->iHotItem && !infoPtr->bDragging) {
1873             hdc = GetDC (hwnd);
1874             if (oldHotItem != -1) HEADER_RefreshItem (hwnd, hdc, oldHotItem);
1875             if (infoPtr->iHotItem != -1) HEADER_RefreshItem (hwnd, hdc, infoPtr->iHotItem);
1876             ReleaseDC (hwnd, hdc);
1877         }
1878         tme.cbSize = sizeof( tme );
1879         tme.dwFlags = TME_LEAVE;
1880         tme.hwndTrack = hwnd;
1881         TrackMouseEvent( &tme );
1882     }
1883
1884     return 0;
1885 }
1886
1887
1888 static LRESULT
1889 HEADER_Paint (HWND hwnd, WPARAM wParam)
1890 {
1891     HDC hdc;
1892     PAINTSTRUCT ps;
1893
1894     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1895     HEADER_Refresh (hwnd, hdc);
1896     if(!wParam)
1897         EndPaint (hwnd, &ps);
1898     return 0;
1899 }
1900
1901
1902 static LRESULT
1903 HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1904 {
1905     BOOL bRet;
1906     POINT pt;
1907
1908     pt.x = (short)LOWORD(lParam);
1909     pt.y = (short)HIWORD(lParam);
1910
1911     /* Send a Notify message */
1912     bRet = HEADER_SendSimpleNotify (hwnd, NM_RCLICK);
1913
1914     /* Change to screen coordinate for WM_CONTEXTMENU */
1915     ClientToScreen(hwnd, &pt);
1916
1917     /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1918     SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
1919
1920     return bRet;
1921 }
1922
1923
1924 static LRESULT
1925 HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1926 {
1927     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1928     POINT pt;
1929     UINT  flags;
1930     INT   nItem;
1931
1932     TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
1933
1934     GetCursorPos (&pt);
1935     ScreenToClient (hwnd, &pt);
1936
1937     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1938
1939     if (flags == HHT_ONDIVIDER)
1940         SetCursor (infoPtr->hcurDivider);
1941     else if (flags == HHT_ONDIVOPEN)
1942         SetCursor (infoPtr->hcurDivopen);
1943     else
1944         SetCursor (infoPtr->hcurArrow);
1945
1946     return 0;
1947 }
1948
1949
1950 static LRESULT
1951 HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1952 {
1953     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1954     TEXTMETRICW tm;
1955     HFONT hFont, hOldFont;
1956     HDC hdc;
1957
1958     infoPtr->hFont = (HFONT)wParam;
1959
1960     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
1961
1962     hdc = GetDC (0);
1963     hOldFont = SelectObject (hdc, hFont);
1964     GetTextMetricsW (hdc, &tm);
1965     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1966     SelectObject (hdc, hOldFont);
1967     ReleaseDC (0, hdc);
1968
1969     infoPtr->bRectsValid = FALSE;
1970
1971     if (lParam) {
1972         InvalidateRect(hwnd, NULL, FALSE);
1973     }
1974
1975     return 0;
1976 }
1977
1978 static LRESULT HEADER_SetRedraw(HWND hwnd, WPARAM wParam, LPARAM lParam)
1979 {
1980     /* ignoring the InvalidateRect calls is handled by user32. But some apps expect
1981      * that we invalidate the header and this has to be done manually  */
1982     LRESULT ret;
1983
1984     ret = DefWindowProcW(hwnd, WM_SETREDRAW, wParam, lParam);
1985     if (wParam)
1986         InvalidateRect(hwnd, NULL, TRUE);
1987     return ret;
1988 }
1989
1990 /* Update the theme handle after a theme change */
1991 static LRESULT HEADER_ThemeChanged(HWND hwnd)
1992 {
1993     HTHEME theme = GetWindowTheme(hwnd);
1994     CloseThemeData(theme);
1995     OpenThemeData(hwnd, themeClass);
1996     InvalidateRect(hwnd, NULL, FALSE);
1997     return 0;
1998 }
1999
2000
2001 static LRESULT WINAPI
2002 HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2003 {
2004     TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, msg, wParam, lParam);
2005     if (!HEADER_GetInfoPtr (hwnd) && (msg != WM_CREATE))
2006         return DefWindowProcW (hwnd, msg, wParam, lParam);
2007     switch (msg) {
2008 /*      case HDM_CLEARFILTER: */
2009
2010         case HDM_CREATEDRAGIMAGE:
2011             return HEADER_CreateDragImage (hwnd, wParam);
2012
2013         case HDM_DELETEITEM:
2014             return HEADER_DeleteItem (hwnd, wParam);
2015
2016 /*      case HDM_EDITFILTER: */
2017
2018         case HDM_GETBITMAPMARGIN:
2019             return HEADER_GetBitmapMargin(hwnd);
2020
2021         case HDM_GETIMAGELIST:
2022             return HEADER_GetImageList (hwnd);
2023
2024         case HDM_GETITEMA:
2025         case HDM_GETITEMW:
2026             return HEADER_GetItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_GETITEMW);
2027
2028         case HDM_GETITEMCOUNT:
2029             return HEADER_GetItemCount (hwnd);
2030
2031         case HDM_GETITEMRECT:
2032             return HEADER_GetItemRect (hwnd, wParam, lParam);
2033
2034         case HDM_GETORDERARRAY:
2035             return HEADER_GetOrderArray(hwnd, wParam, lParam);
2036
2037         case HDM_GETUNICODEFORMAT:
2038             return HEADER_GetUnicodeFormat (hwnd);
2039
2040         case HDM_HITTEST:
2041             return HEADER_HitTest (hwnd, wParam, lParam);
2042
2043         case HDM_INSERTITEMA:
2044         case HDM_INSERTITEMW:
2045             return HEADER_InsertItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_INSERTITEMW);
2046
2047         case HDM_LAYOUT:
2048             return HEADER_Layout (hwnd, wParam, lParam);
2049
2050         case HDM_ORDERTOINDEX:
2051             return HEADER_OrderToIndex(hwnd, wParam);
2052
2053         case HDM_SETBITMAPMARGIN:
2054             return HEADER_SetBitmapMargin(hwnd, wParam);
2055
2056 /*      case HDM_SETFILTERCHANGETIMEOUT: */
2057
2058         case HDM_SETHOTDIVIDER:
2059             return HEADER_SetHotDivider(hwnd, wParam, lParam);
2060
2061         case HDM_SETIMAGELIST:
2062             return HEADER_SetImageList (hwnd, (HIMAGELIST)lParam);
2063
2064         case HDM_SETITEMA:
2065         case HDM_SETITEMW:
2066             return HEADER_SetItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_SETITEMW);
2067
2068         case HDM_SETORDERARRAY:
2069             return HEADER_SetOrderArray(hwnd, wParam, lParam);
2070
2071         case HDM_SETUNICODEFORMAT:
2072             return HEADER_SetUnicodeFormat (hwnd, wParam);
2073
2074         case WM_CREATE:
2075             return HEADER_Create (hwnd, wParam, lParam);
2076
2077         case WM_DESTROY:
2078             return HEADER_Destroy (hwnd, wParam, lParam);
2079
2080         case WM_ERASEBKGND:
2081             return 1;
2082
2083         case WM_GETDLGCODE:
2084             return DLGC_WANTTAB | DLGC_WANTARROWS;
2085
2086         case WM_GETFONT:
2087             return HEADER_GetFont (hwnd);
2088
2089         case WM_LBUTTONDBLCLK:
2090             return HEADER_LButtonDblClk (hwnd, wParam, lParam);
2091
2092         case WM_LBUTTONDOWN:
2093             return HEADER_LButtonDown (hwnd, wParam, lParam);
2094
2095         case WM_LBUTTONUP:
2096             return HEADER_LButtonUp (hwnd, wParam, lParam);
2097
2098         case WM_MOUSELEAVE:
2099             return HEADER_MouseLeave (hwnd, wParam, lParam);
2100
2101         case WM_MOUSEMOVE:
2102             return HEADER_MouseMove (hwnd, wParam, lParam);
2103
2104         case WM_NOTIFYFORMAT:
2105             return HEADER_NotifyFormat (hwnd, wParam, lParam);
2106
2107         case WM_SIZE:
2108             return HEADER_Size (hwnd, wParam);
2109
2110         case WM_THEMECHANGED:
2111             return HEADER_ThemeChanged (hwnd);
2112
2113         case WM_PRINTCLIENT:
2114         case WM_PAINT:
2115             return HEADER_Paint (hwnd, wParam);
2116
2117         case WM_RBUTTONUP:
2118             return HEADER_RButtonUp (hwnd, wParam, lParam);
2119
2120         case WM_SETCURSOR:
2121             return HEADER_SetCursor (hwnd, wParam, lParam);
2122
2123         case WM_SETFONT:
2124             return HEADER_SetFont (hwnd, wParam, lParam);
2125
2126         case WM_SETREDRAW:
2127             return HEADER_SetRedraw(hwnd, wParam, lParam);
2128
2129         default:
2130             if ((msg >= WM_USER) && (msg < WM_APP))
2131                 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
2132                      msg, wParam, lParam );
2133             return DefWindowProcW(hwnd, msg, wParam, lParam);
2134     }
2135 }
2136
2137
2138 VOID
2139 HEADER_Register (void)
2140 {
2141     WNDCLASSW wndClass;
2142
2143     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2144     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
2145     wndClass.lpfnWndProc   = HEADER_WindowProc;
2146     wndClass.cbClsExtra    = 0;
2147     wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
2148     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
2149     wndClass.lpszClassName = WC_HEADERW;
2150
2151     RegisterClassW (&wndClass);
2152 }
2153
2154
2155 VOID
2156 HEADER_Unregister (void)
2157 {
2158     UnregisterClassW (WC_HEADERW, NULL);
2159 }