Implemented _ultow() and export [Nt/Zw]QueryVolumeInformationFile().
[wine] / dlls / comctl32 / header.c
1 /*
2  *  Header control
3  *
4  *  Copyright 1998 Eric Kohl
5  *  Copyright 2000 Eric Kohl for CodeWeavers
6  *
7  *  TODO:
8  *   - Imagelist support (partially).
9  *   - Callback items (under construction).
10  *   - Hottrack support (partially).
11  *   - Custom draw support (including Notifications).
12  *   - Drag and Drop support (including Notifications).
13  *   - New messages.
14  *   - Use notification format
15  *
16  *  FIXME:
17  *   - Little flaw when drawing a bitmap on the right side of the text.
18  */
19
20 #include <string.h>
21
22 #include "winbase.h"
23 #include "wine/unicode.h"
24 #include "commctrl.h"
25 #include "comctl32.h"
26 #include "imagelist.h"
27 #include "debugtools.h"
28
29 DEFAULT_DEBUG_CHANNEL(header);
30
31 typedef struct 
32 {
33     INT     cxy;
34     HBITMAP hbm;
35     LPWSTR    pszText;
36     INT     fmt;
37     LPARAM    lParam;
38     INT     iImage;
39     INT     iOrder;             /* see documentation of HD_ITEM */
40
41     BOOL    bDown;              /* is item pressed? (used for drawing) */
42     RECT    rect;               /* bounding rectangle of the item */
43 } HEADER_ITEM;
44
45
46 typedef struct
47 {
48     HWND      hwndNotify;     /* Owner window to send notifications to */
49     INT       nNotifyFormat;    /* format used for WM_NOTIFY messages */
50     UINT      uNumItem; /* number of items (columns) */
51     INT       nHeight;  /* height of the header (pixels) */
52     HFONT     hFont;            /* handle to the current font */
53     HCURSOR   hcurArrow;        /* handle to the arrow cursor */
54     HCURSOR   hcurDivider;      /* handle to a cursor (used over dividers) <-|-> */
55     HCURSOR   hcurDivopen;      /* handle to a cursor (used over dividers) <-||-> */
56     BOOL      bCaptured;        /* Is the mouse captured? */
57     BOOL      bPressed; /* Is a header item pressed (down)? */
58     BOOL      bTracking;        /* Is in tracking mode? */
59     BOOL      bUnicode;       /* Unicode flag */
60     INT       iMoveItem;        /* index of tracked item. (Tracking mode) */
61     INT       xTrackOffset;     /* distance between the right side of the tracked item and the cursor */
62     INT       xOldTrack;        /* track offset (see above) after the last WM_MOUSEMOVE */
63     INT       nOldWidth;        /* width of a sizing item after the last WM_MOUSEMOVE */
64     INT       iHotItem; /* index of hot item (cursor is over this item) */
65
66     HIMAGELIST  himl;           /* handle to a image list (may be 0) */
67     HEADER_ITEM *items;         /* pointer to array of HEADER_ITEM's */
68     BOOL        bRectsValid;    /* validity flag for bounding rectangles */
69 } HEADER_INFO;
70
71
72 #define VERT_BORDER     4
73 #define DIVIDER_WIDTH  10
74
75 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongA(hwnd,0))
76
77
78 inline static LRESULT
79 HEADER_IndexToOrder (HWND hwnd, INT iItem)
80 {
81     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
82     HEADER_ITEM *lpItem = (HEADER_ITEM*)&infoPtr->items[iItem];
83     return lpItem->iOrder;
84 }
85
86
87 static INT 
88 HEADER_OrderToIndex(HWND hwnd, WPARAM wParam)
89 {
90     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
91     INT i,iorder = (INT)wParam;
92   
93     
94     if ((iorder <0) || iorder >infoPtr->uNumItem)
95       return iorder;
96     for (i=0; i<infoPtr->uNumItem; i++)
97       if (HEADER_IndexToOrder(hwnd,i) == iorder)
98         return i;
99     return iorder;
100 }
101
102 static void
103 HEADER_SetItemBounds (HWND hwnd)
104 {
105     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
106     HEADER_ITEM *phdi;
107     RECT rect;
108     int i, x;
109
110     infoPtr->bRectsValid = TRUE;
111
112     if (infoPtr->uNumItem == 0)
113         return;
114
115     GetClientRect (hwnd, &rect);
116
117     x = rect.left;
118     for (i = 0; i < infoPtr->uNumItem; i++) {
119         phdi = &infoPtr->items[HEADER_OrderToIndex(hwnd,i)];
120         phdi->rect.top = rect.top;
121         phdi->rect.bottom = rect.bottom;
122         phdi->rect.left = x;
123         phdi->rect.right = phdi->rect.left + phdi->cxy;
124         x = phdi->rect.right;
125     }
126 }
127
128 static LRESULT
129 HEADER_Size (HWND hwnd, WPARAM wParam)
130 {
131     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
132
133     infoPtr->bRectsValid = FALSE;
134
135     return 0;
136 }
137
138
139 static INT
140 HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
141 {
142     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
143     HEADER_ITEM *phdi = &infoPtr->items[iItem];
144     RECT r;
145     INT  oldBkMode;
146
147     TRACE("DrawItem(iItem %d bHotTrack %d)\n", iItem, bHotTrack);
148
149     if (!infoPtr->bRectsValid)
150         HEADER_SetItemBounds(hwnd);
151     
152     r = phdi->rect;
153     if (r.right - r.left == 0)
154         return phdi->rect.right;
155
156     if (GetWindowLongA (hwnd, GWL_STYLE) & HDS_BUTTONS) {
157         if (phdi->bDown) {
158             DrawEdge (hdc, &r, BDR_RAISEDOUTER,
159                         BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST);
160             r.left += 2;
161             r.top  += 2;
162         }
163         else
164             DrawEdge (hdc, &r, EDGE_RAISED,
165                         BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
166     }
167     else
168         DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
169
170     if (phdi->fmt & HDF_OWNERDRAW) {
171         DRAWITEMSTRUCT dis;
172         dis.CtlType    = ODT_HEADER;
173         dis.CtlID      = GetWindowLongA (hwnd, GWL_ID);
174         dis.itemID     = iItem;
175         dis.itemAction = ODA_DRAWENTIRE;
176         dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
177         dis.hwndItem   = hwnd;
178         dis.hDC        = hdc;
179         dis.rcItem     = r;
180         dis.itemData   = phdi->lParam;
181         SendMessageA (GetParent (hwnd), WM_DRAWITEM,
182                         (WPARAM)dis.CtlID, (LPARAM)&dis);
183     }
184     else {
185         UINT uTextJustify = DT_LEFT;
186
187         if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
188             uTextJustify = DT_CENTER;
189         else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
190             uTextJustify = DT_RIGHT;
191
192         if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) {
193             BITMAP bmp;
194             HDC    hdcBitmap;
195             INT    yD, yS, cx, cy, rx, ry;
196
197             GetObjectA (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp);
198
199             ry = r.bottom - r.top;
200             rx = r.right - r.left;
201
202             if (ry >= bmp.bmHeight) {
203                 cy = bmp.bmHeight;
204                 yD = r.top + (ry - bmp.bmHeight) / 2;
205                 yS = 0;
206             }
207             else {
208                 cy = ry;
209                 yD = r.top;
210                 yS = (bmp.bmHeight - ry) / 2;
211
212             }
213
214             if (rx >= bmp.bmWidth + 6) {
215                 cx = bmp.bmWidth;
216             }
217             else {
218                 cx = rx - 6;
219             }
220
221             hdcBitmap = CreateCompatibleDC (hdc);
222             SelectObject (hdcBitmap, phdi->hbm);
223             BitBlt (hdc, r.left + 3, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY);
224             DeleteDC (hdcBitmap);
225
226             r.left += (bmp.bmWidth + 3);
227         }
228
229
230         if ((phdi->fmt & HDF_BITMAP_ON_RIGHT) && (phdi->hbm)) {
231             BITMAP bmp;
232             HDC    hdcBitmap;
233             INT    xD, yD, yS, cx, cy, rx, ry, tx;
234             RECT   textRect;
235
236             GetObjectA (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp);
237
238             textRect = r;
239             DrawTextW (hdc, phdi->pszText, -1,
240                   &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
241             tx = textRect.right - textRect.left;
242             ry = r.bottom - r.top;
243             rx = r.right - r.left;
244
245             if (ry >= bmp.bmHeight) {
246                 cy = bmp.bmHeight;
247                 yD = r.top + (ry - bmp.bmHeight) / 2;
248                 yS = 0;
249             }
250             else {
251                 cy = ry;
252                 yD = r.top;
253                 yS = (bmp.bmHeight - ry) / 2;
254
255             }
256
257             if (r.left + tx + bmp.bmWidth + 9 <= r.right) {
258                 cx = bmp.bmWidth;
259                 xD = r.left + tx + 6;
260             }
261             else {
262                 if (rx >= bmp.bmWidth + 6) {
263                     cx = bmp.bmWidth;
264                     xD = r.right - bmp.bmWidth - 3;
265                     r.right = xD - 3;
266                 }
267                 else {
268                     cx = rx - 3;
269                     xD = r.left;
270                     r.right = r.left;
271                 }
272             }
273
274             hdcBitmap = CreateCompatibleDC (hdc);
275             SelectObject (hdcBitmap, phdi->hbm);
276             BitBlt (hdc, xD, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY);
277             DeleteDC (hdcBitmap);
278         }
279
280         if ((phdi->fmt & HDF_IMAGE) && (infoPtr->himl)) {
281           r.left +=3;
282           /* FIXME: (r.bottom- (infoPtr->himl->cy))/2 should horicontal center the image
283              It looks like it doesn't work as expected*/
284           ImageList_Draw (infoPtr->himl, phdi->iImage,hdc,r.left, (r.bottom- (infoPtr->himl->cy))/2,0);
285           r.left += infoPtr->himl->cx;
286         }
287
288         if (((phdi->fmt & HDF_STRING)
289                 || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP|
290                                    HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */
291             && (phdi->pszText)) {
292             oldBkMode = SetBkMode(hdc, TRANSPARENT);
293             r.left += 3 ;
294             r.right -= 3;
295             SetTextColor (hdc, (bHotTrack) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
296             DrawTextW (hdc, phdi->pszText, -1,
297                   &r, uTextJustify|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE);
298             if (oldBkMode != TRANSPARENT)
299                 SetBkMode(hdc, oldBkMode);
300         }
301     }/*Ownerdrawn*/
302
303     return phdi->rect.right;
304 }
305
306
307 static void 
308 HEADER_Refresh (HWND hwnd, HDC hdc)
309 {
310     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
311     HFONT hFont, hOldFont;
312     RECT rect;
313     HBRUSH hbrBk;
314     INT i, x;
315
316     /* get rect for the bar, adjusted for the border */
317     GetClientRect (hwnd, &rect);
318
319     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
320     hOldFont = SelectObject (hdc, hFont);
321
322     /* draw Background */
323     hbrBk = GetSysColorBrush(COLOR_3DFACE);
324     FillRect(hdc, &rect, hbrBk);
325
326     x = rect.left;
327     for (i = 0; i < infoPtr->uNumItem; i++) {
328         x = HEADER_DrawItem (hwnd, hdc, HEADER_OrderToIndex(hwnd,i), FALSE);
329     }
330
331     if ((x <= rect.right) && (infoPtr->uNumItem > 0)) {
332         rect.left = x;
333         if (GetWindowLongA (hwnd, GWL_STYLE) & HDS_BUTTONS)
334             DrawEdge (hdc, &rect, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT);
335         else
336             DrawEdge (hdc, &rect, EDGE_ETCHED, BF_BOTTOM);
337     }
338
339     SelectObject (hdc, hOldFont);
340 }
341
342
343 static void
344 HEADER_RefreshItem (HWND hwnd, HDC hdc, INT iItem)
345 {
346     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
347     HFONT hFont, hOldFont;
348
349     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
350     hOldFont = SelectObject (hdc, hFont);
351     HEADER_DrawItem (hwnd, hdc, iItem, FALSE);
352     SelectObject (hdc, hOldFont);
353 }
354
355
356 static void
357 HEADER_InternalHitTest (HWND hwnd, LPPOINT lpPt, UINT *pFlags, INT *pItem)
358 {
359     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
360     RECT rect, rcTest;
361     INT  iCount, width;
362     BOOL bNoWidth;
363
364     GetClientRect (hwnd, &rect);
365
366     *pFlags = 0;
367     bNoWidth = FALSE;
368     if (PtInRect (&rect, *lpPt))
369     {
370         if (infoPtr->uNumItem == 0) {
371             *pFlags |= HHT_NOWHERE;
372             *pItem = 1;
373             TRACE("NOWHERE\n");
374             return;
375         }
376         else {
377             /* somewhere inside */
378             for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
379                 rect = infoPtr->items[iCount].rect;
380                 width = rect.right - rect.left;
381                 if (width == 0) {
382                     bNoWidth = TRUE;
383                     continue;
384                 }
385                 if (PtInRect (&rect, *lpPt)) {
386                     if (width <= 2 * DIVIDER_WIDTH) {
387                         *pFlags |= HHT_ONHEADER;
388                         *pItem = iCount;
389                         TRACE("ON HEADER %d\n", iCount);
390                         return;
391                     }
392                     if (iCount > 0) {
393                         rcTest = rect;
394                         rcTest.right = rcTest.left + DIVIDER_WIDTH;
395                         if (PtInRect (&rcTest, *lpPt)) {
396                             if (bNoWidth) {
397                                 *pFlags |= HHT_ONDIVOPEN;
398                                 *pItem = iCount - 1;
399                                 TRACE("ON DIVOPEN %d\n", *pItem);
400                                 return;
401                             }
402                             else {
403                                 *pFlags |= HHT_ONDIVIDER;
404                                 *pItem = iCount - 1;
405                                 TRACE("ON DIVIDER %d\n", *pItem);
406                                 return;
407                             }
408                         }
409                     }
410                     rcTest = rect;
411                     rcTest.left = rcTest.right - DIVIDER_WIDTH;
412                     if (PtInRect (&rcTest, *lpPt)) {
413                         *pFlags |= HHT_ONDIVIDER;
414                         *pItem = iCount;
415                         TRACE("ON DIVIDER %d\n", *pItem);
416                         return;
417                     }
418
419                     *pFlags |= HHT_ONHEADER;
420                     *pItem = iCount;
421                     TRACE("ON HEADER %d\n", iCount);
422                     return;
423                 }
424             }
425
426             /* check for last divider part (on nowhere) */
427             rect = infoPtr->items[infoPtr->uNumItem-1].rect;
428             rect.left = rect.right;
429             rect.right += DIVIDER_WIDTH;
430             if (PtInRect (&rect, *lpPt)) {
431                 if (bNoWidth) {
432                     *pFlags |= HHT_ONDIVOPEN;
433                     *pItem = infoPtr->uNumItem - 1;
434                     TRACE("ON DIVOPEN %d\n", *pItem);
435                     return;
436                 }
437                 else {
438                     *pFlags |= HHT_ONDIVIDER;
439                     *pItem = infoPtr->uNumItem-1;
440                     TRACE("ON DIVIDER %d\n", *pItem);
441                     return;
442                 }
443             }
444
445             *pFlags |= HHT_NOWHERE;
446             *pItem = 1;
447             TRACE("NOWHERE\n");
448             return;
449         }
450     }
451     else {
452         if (lpPt->x < rect.left) {
453            TRACE("TO LEFT\n");
454            *pFlags |= HHT_TOLEFT;
455         }
456         else if (lpPt->x > rect.right) {
457             TRACE("TO RIGHT\n");
458             *pFlags |= HHT_TORIGHT;
459         }
460
461         if (lpPt->y < rect.top) {
462             TRACE("ABOVE\n");
463             *pFlags |= HHT_ABOVE;
464         }
465         else if (lpPt->y > rect.bottom) {
466             TRACE("BELOW\n");
467             *pFlags |= HHT_BELOW;
468         }
469     }
470
471     *pItem = 1;
472     TRACE("flags=0x%X\n", *pFlags);
473     return;
474 }
475
476
477 static void
478 HEADER_DrawTrackLine (HWND hwnd, HDC hdc, INT x)
479 {
480     RECT rect;
481     HPEN hOldPen;
482     INT  oldRop;
483
484     GetClientRect (hwnd, &rect);
485
486     hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN));
487     oldRop = SetROP2 (hdc, R2_XORPEN);
488     MoveToEx (hdc, x, rect.top, NULL);
489     LineTo (hdc, x, rect.bottom);
490     SetROP2 (hdc, oldRop);
491     SelectObject (hdc, hOldPen);
492 }
493
494
495 static BOOL
496 HEADER_SendSimpleNotify (HWND hwnd, UINT code)
497 {
498     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
499     NMHDR nmhdr;
500
501     nmhdr.hwndFrom = hwnd;
502     nmhdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
503     nmhdr.code     = code;
504
505     return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
506                                    (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
507 }
508
509 static BOOL
510 HEADER_SendHeaderNotify (HWND hwnd, UINT code, INT iItem, INT mask)
511 {
512     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
513     NMHEADERA nmhdr;
514     HDITEMA nmitem;
515
516     nmhdr.hdr.hwndFrom = hwnd;
517     nmhdr.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
518     nmhdr.hdr.code = code;
519     nmhdr.iItem = iItem;
520     nmhdr.iButton = 0;
521     nmhdr.pitem = &nmitem;
522     nmitem.mask = mask;
523     nmitem.cxy = infoPtr->items[iItem].cxy;
524     nmitem.hbm = infoPtr->items[iItem].hbm;
525     nmitem.pszText = NULL;
526     nmitem.cchTextMax = 0;
527 /*    nmitem.pszText = infoPtr->items[iItem].pszText; */
528 /*    nmitem.cchTextMax = infoPtr->items[iItem].cchTextMax; */
529     nmitem.fmt = infoPtr->items[iItem].fmt;
530     nmitem.lParam = infoPtr->items[iItem].lParam;
531     nmitem.iOrder = infoPtr->items[iItem].iOrder;
532     nmitem.iImage = infoPtr->items[iItem].iImage;
533
534     return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
535                                (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
536 }
537
538
539 static BOOL
540 HEADER_SendClickNotify (HWND hwnd, UINT code, INT iItem)
541 {
542     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
543     NMHEADERA nmhdr;
544
545     nmhdr.hdr.hwndFrom = hwnd;
546     nmhdr.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
547     nmhdr.hdr.code = code;
548     nmhdr.iItem = iItem;
549     nmhdr.iButton = 0;
550     nmhdr.pitem = NULL;
551
552     return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
553                                (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
554 }
555
556
557 static LRESULT
558 HEADER_CreateDragImage (HWND hwnd, WPARAM wParam)
559 {
560     FIXME("empty stub!\n");
561     return 0;
562 }
563
564
565 static LRESULT
566 HEADER_DeleteItem (HWND hwnd, WPARAM wParam)
567 {
568     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
569     INT iItem = (INT)wParam;
570
571     TRACE("[iItem=%d]\n", iItem);
572     
573     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
574         return FALSE;
575
576     if (infoPtr->uNumItem == 1) {
577         TRACE("Simple delete!\n");
578         if (infoPtr->items[0].pszText)
579             COMCTL32_Free (infoPtr->items[0].pszText);
580         COMCTL32_Free (infoPtr->items);
581         infoPtr->items = 0;
582         infoPtr->uNumItem = 0;
583     }
584     else {
585         HEADER_ITEM *oldItems = infoPtr->items;
586         TRACE("Complex delete! [iItem=%d]\n", iItem);
587
588         if (infoPtr->items[iItem].pszText)
589             COMCTL32_Free (infoPtr->items[iItem].pszText);
590
591         infoPtr->uNumItem--;
592         infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
593         /* pre delete copy */
594         if (iItem > 0) {
595             memcpy (&infoPtr->items[0], &oldItems[0],
596                     iItem * sizeof(HEADER_ITEM));
597         }
598
599         /* post delete copy */
600         if (iItem < infoPtr->uNumItem) {
601             memcpy (&infoPtr->items[iItem], &oldItems[iItem+1],
602                     (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM));
603         }
604
605         COMCTL32_Free (oldItems);
606     }
607
608     HEADER_SetItemBounds (hwnd);
609
610     InvalidateRect(hwnd, NULL, FALSE);
611     
612     return TRUE;
613 }
614
615
616 static LRESULT
617 HEADER_GetImageList (HWND hwnd)
618 {
619     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
620
621     return (LRESULT)infoPtr->himl;
622 }
623
624
625 static LRESULT
626 HEADER_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
627 {
628     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
629     HDITEMA   *phdi = (HDITEMA*)lParam;
630     INT       nItem = (INT)wParam;
631     HEADER_ITEM *lpItem;
632
633     if (!phdi)
634         return FALSE;
635     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
636         return FALSE;
637
638     TRACE("[nItem=%d]\n", nItem);
639
640     if (phdi->mask == 0)
641         return TRUE;
642
643     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
644     if (phdi->mask & HDI_BITMAP)
645         phdi->hbm = lpItem->hbm;
646
647     if (phdi->mask & HDI_FORMAT)
648         phdi->fmt = lpItem->fmt;
649
650     if (phdi->mask & HDI_WIDTH)
651         phdi->cxy = lpItem->cxy;
652
653     if (phdi->mask & HDI_LPARAM)
654         phdi->lParam = lpItem->lParam;
655
656     if (phdi->mask & HDI_TEXT) {
657         if (lpItem->pszText != LPSTR_TEXTCALLBACKW) {
658             if (lpItem->pszText)
659                 WideCharToMultiByte (CP_ACP, 0, lpItem->pszText, -1,
660                                      phdi->pszText, phdi->cchTextMax, NULL, NULL);
661             else
662                 *phdi->pszText = 0;
663         }       
664         else
665             phdi->pszText = LPSTR_TEXTCALLBACKA;
666     }
667
668     if (phdi->mask & HDI_IMAGE)
669         phdi->iImage = lpItem->iImage;
670
671     if (phdi->mask & HDI_ORDER)
672         phdi->iOrder = lpItem->iOrder;
673
674     return TRUE;
675 }
676
677
678 static LRESULT
679 HEADER_GetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
680 {
681     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
682     HDITEMW   *phdi = (HDITEMW*)lParam;
683     INT       nItem = (INT)wParam;
684     HEADER_ITEM *lpItem;
685
686     if (!phdi)
687         return FALSE;
688     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
689         return FALSE;
690
691     TRACE("[nItem=%d]\n", nItem);
692
693     if (phdi->mask == 0)
694         return TRUE;
695
696     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
697     if (phdi->mask & HDI_BITMAP)
698         phdi->hbm = lpItem->hbm;
699
700     if (phdi->mask & HDI_FORMAT)
701         phdi->fmt = lpItem->fmt;
702
703     if (phdi->mask & HDI_WIDTH)
704         phdi->cxy = lpItem->cxy;
705
706     if (phdi->mask & HDI_LPARAM)
707         phdi->lParam = lpItem->lParam;
708
709     if (phdi->mask & HDI_TEXT) {
710         if (lpItem->pszText != LPSTR_TEXTCALLBACKW) {
711             if (lpItem->pszText)
712                 lstrcpynW (phdi->pszText, lpItem->pszText, phdi->cchTextMax);
713             else
714                 *phdi->pszText = 0;
715         }
716         else
717             phdi->pszText = LPSTR_TEXTCALLBACKW;
718     }
719
720     if (phdi->mask & HDI_IMAGE)
721         phdi->iImage = lpItem->iImage;
722
723     if (phdi->mask & HDI_ORDER)
724         phdi->iOrder = lpItem->iOrder;
725
726     return TRUE;
727 }
728
729
730 inline static LRESULT
731 HEADER_GetItemCount (HWND hwnd)
732 {
733     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
734     return infoPtr->uNumItem;
735 }
736
737
738 static LRESULT
739 HEADER_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
740 {
741     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
742     INT iItem = (INT)wParam;
743     LPRECT lpRect = (LPRECT)lParam;
744
745     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
746         return FALSE;
747
748     lpRect->left   = infoPtr->items[iItem].rect.left;
749     lpRect->right  = infoPtr->items[iItem].rect.right;
750     lpRect->top    = infoPtr->items[iItem].rect.top;
751     lpRect->bottom = infoPtr->items[iItem].rect.bottom;
752
753     return TRUE;
754 }
755
756
757 static LRESULT 
758 HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
759 {
760     int i;
761     LPINT order = (LPINT) lParam;
762     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
763
764     if ((int)wParam <infoPtr->uNumItem)
765       return FALSE;
766     for (i=0; i<(int)wParam; i++)
767       *order++=HEADER_OrderToIndex(hwnd,i);
768     return TRUE;
769 }
770
771 static LRESULT 
772 HEADER_SetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
773 {
774     int i;
775     LPINT order = (LPINT) lParam;
776     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
777     HEADER_ITEM *lpItem;
778
779     if ((int)wParam <infoPtr->uNumItem)
780       return FALSE;
781     for (i=0; i<(int)wParam; i++)
782       {
783         lpItem = (HEADER_ITEM*)&infoPtr->items[*order++];
784         lpItem->iOrder=i;
785       }
786     infoPtr->bRectsValid=0;
787     InvalidateRect(hwnd, NULL, FALSE);
788     return TRUE;
789 }
790
791 inline static LRESULT
792 HEADER_GetUnicodeFormat (HWND hwnd)
793 {
794     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
795     return infoPtr->bUnicode;
796 }
797
798
799 static LRESULT
800 HEADER_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
801 {
802     LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam;
803
804     HEADER_InternalHitTest (hwnd, &phti->pt, &phti->flags, &phti->iItem);
805
806     if (phti->flags == HHT_ONHEADER)
807         return phti->iItem;
808     else
809         return -1;
810 }
811
812
813 static LRESULT
814 HEADER_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
815 {
816     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
817     HDITEMA   *phdi = (HDITEMA*)lParam;
818     INT       nItem = (INT)wParam;
819     HEADER_ITEM *lpItem;
820     INT       len;
821
822     if ((phdi == NULL) || (nItem < 0))
823         return -1;
824
825     if (nItem > infoPtr->uNumItem)
826         nItem = infoPtr->uNumItem;
827
828     if (infoPtr->uNumItem == 0) {
829         infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM));
830         infoPtr->uNumItem++;
831     }
832     else {
833         HEADER_ITEM *oldItems = infoPtr->items;
834
835         infoPtr->uNumItem++;
836         infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
837         if (nItem == 0) {
838             memcpy (&infoPtr->items[1], &oldItems[0],
839                     (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM));
840         }
841         else
842         {
843               /* pre insert copy */
844             if (nItem > 0) {
845                  memcpy (&infoPtr->items[0], &oldItems[0],
846                          nItem * sizeof(HEADER_ITEM));
847             }
848
849             /* post insert copy */
850             if (nItem < infoPtr->uNumItem - 1) {
851                 memcpy (&infoPtr->items[nItem+1], &oldItems[nItem],
852                         (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM));
853             }
854         }
855     
856         COMCTL32_Free (oldItems);
857     }
858
859     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
860     lpItem->bDown = FALSE;
861
862     if (phdi->mask & HDI_WIDTH)
863         lpItem->cxy = phdi->cxy;
864
865     if (phdi->mask & HDI_TEXT) {
866         if (!phdi->pszText) /* null pointer check */
867             phdi->pszText = "";
868         if (phdi->pszText != LPSTR_TEXTCALLBACKA) {
869             len = MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, NULL, 0);
870             lpItem->pszText = COMCTL32_Alloc( len*sizeof(WCHAR) );
871             MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, lpItem->pszText, len);
872         }
873         else
874             lpItem->pszText = LPSTR_TEXTCALLBACKW;
875     }
876
877     if (phdi->mask & HDI_FORMAT)
878         lpItem->fmt = phdi->fmt;
879
880     if (lpItem->fmt == 0)
881         lpItem->fmt = HDF_LEFT;
882
883     if (!(lpItem->fmt &HDF_STRING) && (phdi->mask & HDI_TEXT))
884       {
885         lpItem->fmt |= HDF_STRING;
886       }
887     if (phdi->mask & HDI_BITMAP)
888         lpItem->hbm = phdi->hbm;
889
890     if (phdi->mask & HDI_LPARAM)
891         lpItem->lParam = phdi->lParam;
892
893     if (phdi->mask & HDI_IMAGE)
894         lpItem->iImage = phdi->iImage;
895
896     if (phdi->mask & HDI_ORDER)
897       {
898         lpItem->iOrder = phdi->iOrder;
899       }
900     else
901       lpItem->iOrder=nItem;
902           
903
904     HEADER_SetItemBounds (hwnd);
905
906     InvalidateRect(hwnd, NULL, FALSE);
907
908     return nItem;
909 }
910
911
912 static LRESULT
913 HEADER_InsertItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
914 {
915     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
916     HDITEMW   *phdi = (HDITEMW*)lParam;
917     INT       nItem = (INT)wParam;
918     HEADER_ITEM *lpItem;
919     INT       len;
920
921     if ((phdi == NULL) || (nItem < 0))
922         return -1;
923
924     if (nItem > infoPtr->uNumItem)
925         nItem = infoPtr->uNumItem;
926
927     if (infoPtr->uNumItem == 0) {
928         infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM));
929         infoPtr->uNumItem++;
930     }
931     else {
932         HEADER_ITEM *oldItems = infoPtr->items;
933
934         infoPtr->uNumItem++;
935         infoPtr->items = COMCTL32_Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
936         /* pre insert copy */
937         if (nItem > 0) {
938             memcpy (&infoPtr->items[0], &oldItems[0],
939                     nItem * sizeof(HEADER_ITEM));
940         }
941
942         /* post insert copy */
943         if (nItem < infoPtr->uNumItem - 1) {
944             memcpy (&infoPtr->items[nItem+1], &oldItems[nItem],
945                     (infoPtr->uNumItem - nItem) * sizeof(HEADER_ITEM));
946         }
947
948         COMCTL32_Free (oldItems);
949     }
950
951     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
952     lpItem->bDown = FALSE;
953
954     if (phdi->mask & HDI_WIDTH)
955         lpItem->cxy = phdi->cxy;
956
957     if (phdi->mask & HDI_TEXT) {
958         WCHAR wide_null_char = 0;
959         if (!phdi->pszText) /* null pointer check */
960             phdi->pszText = &wide_null_char;    
961         if (phdi->pszText != LPSTR_TEXTCALLBACKW) {
962             len = strlenW (phdi->pszText);
963             lpItem->pszText = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
964             strcpyW (lpItem->pszText, phdi->pszText);
965         }
966         else
967             lpItem->pszText = LPSTR_TEXTCALLBACKW;
968     }
969
970     if (phdi->mask & HDI_FORMAT)
971         lpItem->fmt = phdi->fmt;
972
973     if (lpItem->fmt == 0)
974         lpItem->fmt = HDF_LEFT;
975
976     if (phdi->mask & HDI_BITMAP)
977         lpItem->hbm = phdi->hbm;
978
979     if (phdi->mask & HDI_LPARAM)
980         lpItem->lParam = phdi->lParam;
981
982     if (phdi->mask & HDI_IMAGE)
983         lpItem->iImage = phdi->iImage;
984
985     if (phdi->mask & HDI_ORDER)
986       {
987         lpItem->iOrder = phdi->iOrder;
988       }
989     else
990       lpItem->iOrder = nItem;
991
992     HEADER_SetItemBounds (hwnd);
993
994     InvalidateRect(hwnd, NULL, FALSE);
995
996     return nItem;
997 }
998
999
1000 static LRESULT
1001 HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam)
1002 {
1003     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1004     LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam;
1005
1006     lpLayout->pwpos->hwnd = hwnd;
1007     lpLayout->pwpos->hwndInsertAfter = 0;
1008     lpLayout->pwpos->x = lpLayout->prc->left;
1009     lpLayout->pwpos->y = lpLayout->prc->top;
1010     lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
1011     if (GetWindowLongA (hwnd, GWL_STYLE) & HDS_HIDDEN)
1012         lpLayout->pwpos->cy = 0;
1013     else {
1014         lpLayout->pwpos->cy = infoPtr->nHeight;
1015         lpLayout->prc->top += infoPtr->nHeight;
1016     }
1017     lpLayout->pwpos->flags = SWP_NOZORDER;
1018
1019     TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1020            lpLayout->pwpos->x, lpLayout->pwpos->y,
1021            lpLayout->pwpos->cx, lpLayout->pwpos->cy);
1022
1023     infoPtr->bRectsValid = FALSE;
1024
1025     return TRUE;
1026 }
1027
1028
1029 static LRESULT
1030 HEADER_SetImageList (HWND hwnd, HIMAGELIST himl)
1031 {
1032     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1033     HIMAGELIST himlOld;
1034
1035     TRACE("(himl 0x%x)\n", (int)himl);
1036     himlOld = infoPtr->himl;
1037     infoPtr->himl = himl;
1038
1039     /* FIXME: Refresh needed??? */
1040
1041     return (LRESULT)himlOld;
1042 }
1043
1044
1045 static LRESULT
1046 HEADER_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1047 {
1048     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1049     HDITEMA *phdi = (HDITEMA*)lParam;
1050     INT nItem = (INT)wParam;
1051     HEADER_ITEM *lpItem;
1052
1053     if (phdi == NULL)
1054         return FALSE;
1055     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1056         return FALSE;
1057
1058     TRACE("[nItem=%d]\n", nItem);
1059
1060         if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, nItem, phdi->mask))
1061         return FALSE;
1062
1063     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
1064     if (phdi->mask & HDI_BITMAP)
1065         lpItem->hbm = phdi->hbm;
1066
1067     if (phdi->mask & HDI_FORMAT)
1068         lpItem->fmt = phdi->fmt;
1069
1070     if (phdi->mask & HDI_LPARAM)
1071         lpItem->lParam = phdi->lParam;
1072
1073     if (phdi->mask & HDI_TEXT) {
1074         if (phdi->pszText != LPSTR_TEXTCALLBACKA) {
1075             if (lpItem->pszText) {
1076                 COMCTL32_Free (lpItem->pszText);
1077                 lpItem->pszText = NULL;
1078             }
1079             if (phdi->pszText) {
1080                 INT len = MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,NULL,0);
1081                 lpItem->pszText = COMCTL32_Alloc( len*sizeof(WCHAR) );
1082                 MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,lpItem->pszText,len);
1083             }
1084         }
1085         else
1086             lpItem->pszText = LPSTR_TEXTCALLBACKW;
1087     }
1088
1089     if (phdi->mask & HDI_WIDTH)
1090         lpItem->cxy = phdi->cxy;
1091
1092     if (phdi->mask & HDI_IMAGE)
1093         lpItem->iImage = phdi->iImage;
1094
1095     if (phdi->mask & HDI_ORDER)
1096       {
1097         lpItem->iOrder = phdi->iOrder;
1098       }
1099     else
1100       lpItem->iOrder = nItem;
1101
1102         HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, nItem, phdi->mask);
1103
1104     HEADER_SetItemBounds (hwnd);
1105
1106     InvalidateRect(hwnd, NULL, FALSE);
1107
1108     return TRUE;
1109 }
1110
1111
1112 static LRESULT
1113 HEADER_SetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1114 {
1115     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1116     HDITEMW *phdi = (HDITEMW*)lParam;
1117     INT nItem = (INT)wParam;
1118     HEADER_ITEM *lpItem;
1119
1120     if (phdi == NULL)
1121         return FALSE;
1122     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1123         return FALSE;
1124
1125     TRACE("[nItem=%d]\n", nItem);
1126
1127         if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGW, nItem, phdi->mask))
1128         return FALSE;
1129
1130     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
1131     if (phdi->mask & HDI_BITMAP)
1132         lpItem->hbm = phdi->hbm;
1133
1134     if (phdi->mask & HDI_FORMAT)
1135         lpItem->fmt = phdi->fmt;
1136
1137     if (phdi->mask & HDI_LPARAM)
1138         lpItem->lParam = phdi->lParam;
1139
1140     if (phdi->mask & HDI_TEXT) {
1141         if (phdi->pszText != LPSTR_TEXTCALLBACKW) {
1142             if (lpItem->pszText) {
1143                 COMCTL32_Free (lpItem->pszText);
1144                 lpItem->pszText = NULL;
1145             }
1146             if (phdi->pszText) {
1147                 INT len = strlenW (phdi->pszText);
1148                 lpItem->pszText = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1149                 strcpyW (lpItem->pszText, phdi->pszText);
1150             }
1151         }
1152         else
1153             lpItem->pszText = LPSTR_TEXTCALLBACKW;
1154     }
1155
1156     if (phdi->mask & HDI_WIDTH)
1157         lpItem->cxy = phdi->cxy;
1158
1159     if (phdi->mask & HDI_IMAGE)
1160         lpItem->iImage = phdi->iImage;
1161
1162     if (phdi->mask & HDI_ORDER)
1163       {
1164         lpItem->iOrder = phdi->iOrder;
1165       }
1166     else
1167       lpItem->iOrder = nItem;
1168
1169         HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGINGW, nItem, phdi->mask);
1170
1171     HEADER_SetItemBounds (hwnd);
1172
1173     InvalidateRect(hwnd, NULL, FALSE);
1174
1175     return TRUE;
1176 }
1177
1178 inline static LRESULT
1179 HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
1180 {
1181     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1182     BOOL bTemp = infoPtr->bUnicode;
1183
1184     infoPtr->bUnicode = (BOOL)wParam;
1185
1186     return bTemp;
1187 }
1188
1189
1190 static LRESULT
1191 HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1192 {
1193     HEADER_INFO *infoPtr;
1194     TEXTMETRICA tm;
1195     HFONT hOldFont;
1196     HDC   hdc;
1197
1198     infoPtr = (HEADER_INFO *)COMCTL32_Alloc (sizeof(HEADER_INFO));
1199     SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1200
1201     infoPtr->hwndNotify = GetParent(hwnd);
1202     infoPtr->uNumItem = 0;
1203     infoPtr->nHeight = 20;
1204     infoPtr->hFont = 0;
1205     infoPtr->items = 0;
1206     infoPtr->bRectsValid = FALSE;
1207     infoPtr->hcurArrow = LoadCursorA (0, IDC_ARROWA);
1208     infoPtr->hcurDivider = LoadCursorA (COMCTL32_hModule, MAKEINTRESOURCEA(IDC_DIVIDER));
1209     infoPtr->hcurDivopen = LoadCursorA (COMCTL32_hModule, MAKEINTRESOURCEA(IDC_DIVIDEROPEN));
1210     infoPtr->bPressed  = FALSE;
1211     infoPtr->bTracking = FALSE;
1212     infoPtr->iMoveItem = 0;
1213     infoPtr->himl = 0;
1214     infoPtr->iHotItem = -1;
1215     infoPtr->bUnicode = IsWindowUnicode (hwnd);
1216     infoPtr->nNotifyFormat =
1217         SendMessageA (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
1218
1219     hdc = GetDC (0);
1220     hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1221     GetTextMetricsA (hdc, &tm);
1222     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1223     SelectObject (hdc, hOldFont);
1224     ReleaseDC (0, hdc);
1225
1226     return 0;
1227 }
1228
1229
1230 static LRESULT
1231 HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1232 {
1233     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1234     HEADER_ITEM *lpItem;
1235     INT nItem;
1236
1237     if (infoPtr->items) {
1238         lpItem = (HEADER_ITEM*)infoPtr->items;
1239         for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
1240             if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACKW))
1241                 COMCTL32_Free (lpItem->pszText);
1242         }
1243         COMCTL32_Free (infoPtr->items);
1244     }
1245
1246     if (infoPtr->himl)
1247         ImageList_Destroy (infoPtr->himl);
1248
1249     COMCTL32_Free (infoPtr);
1250     SetWindowLongA (hwnd, 0, 0);
1251     return 0;
1252 }
1253
1254
1255 static inline LRESULT
1256 HEADER_GetFont (HWND hwnd)
1257 {
1258     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1259
1260     return (LRESULT)infoPtr->hFont;
1261 }
1262
1263
1264 static LRESULT
1265 HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
1266 {
1267     POINT pt;
1268     UINT  flags;
1269     INT   nItem;
1270
1271     pt.x = (INT)LOWORD(lParam); 
1272     pt.y = (INT)HIWORD(lParam);
1273     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1274
1275     if ((GetWindowLongA (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER))
1276         HEADER_SendHeaderNotify (hwnd, HDN_ITEMDBLCLICKA, nItem,0);
1277     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
1278         HEADER_SendHeaderNotify (hwnd, HDN_DIVIDERDBLCLICKA, nItem,0);
1279
1280     return 0;
1281 }
1282
1283
1284 static LRESULT
1285 HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1286 {
1287     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1288     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1289     POINT pt;
1290     UINT  flags;
1291     INT   nItem;
1292     HDC   hdc;
1293
1294     pt.x = (INT)LOWORD(lParam); 
1295     pt.y = (INT)HIWORD(lParam);
1296     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1297
1298     if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
1299         SetCapture (hwnd);
1300         infoPtr->bCaptured = TRUE;   
1301         infoPtr->bPressed  = TRUE;
1302         infoPtr->iMoveItem = nItem;
1303
1304         infoPtr->items[nItem].bDown = TRUE;
1305
1306         /* Send WM_CUSTOMDRAW */
1307         hdc = GetDC (hwnd);
1308         HEADER_RefreshItem (hwnd, hdc, nItem);
1309         ReleaseDC (hwnd, hdc);
1310
1311         TRACE("Pressed item %d!\n", nItem);
1312     } 
1313     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
1314         if (!(HEADER_SendHeaderNotify (hwnd, HDN_BEGINTRACKA, nItem,0))) {
1315             SetCapture (hwnd);
1316             infoPtr->bCaptured = TRUE;   
1317             infoPtr->bTracking = TRUE;
1318             infoPtr->iMoveItem = nItem;
1319             infoPtr->nOldWidth = infoPtr->items[nItem].cxy;
1320             infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
1321
1322             if (!(dwStyle & HDS_FULLDRAG)) {
1323                 infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
1324                 hdc = GetDC (hwnd);
1325                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1326                 ReleaseDC (hwnd, hdc);
1327             }
1328
1329             TRACE("Begin tracking item %d!\n", nItem);
1330         }
1331     }
1332
1333     return 0;
1334 }
1335
1336
1337 static LRESULT
1338 HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1339 {
1340     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1341     /*
1342      *DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1343      */
1344     POINT pt;
1345     UINT  flags;
1346     INT   nItem, nWidth;
1347     HDC   hdc;
1348
1349     pt.x = (INT)SLOWORD(lParam);
1350     pt.y = (INT)SHIWORD(lParam);
1351     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1352
1353     if (infoPtr->bPressed) {
1354         if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) {
1355             infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1356             hdc = GetDC (hwnd);
1357             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1358             ReleaseDC (hwnd, hdc);
1359
1360             HEADER_SendClickNotify (hwnd, HDN_ITEMCLICKA, infoPtr->iMoveItem);
1361         }
1362         else if (flags == HHT_ONHEADER)
1363           {
1364             HEADER_ITEM *lpItem;
1365             INT newindex = HEADER_IndexToOrder(hwnd,nItem);
1366             INT oldindex = HEADER_IndexToOrder(hwnd,infoPtr->iMoveItem);
1367
1368             TRACE("Exchanging [index:order] [%d:%d] [%d:%d]\n",
1369                   infoPtr->iMoveItem,oldindex,nItem,newindex);
1370             lpItem= (HEADER_ITEM*)&infoPtr->items[nItem];
1371             lpItem->iOrder=oldindex;
1372
1373             lpItem= (HEADER_ITEM*)&infoPtr->items[infoPtr->iMoveItem];
1374             lpItem->iOrder = newindex;
1375
1376             infoPtr->bRectsValid = FALSE;
1377             InvalidateRect(hwnd, NULL, FALSE);
1378             /* FIXME: Should some WM_NOTIFY be sent */
1379           }    
1380
1381         TRACE("Released item %d!\n", infoPtr->iMoveItem);
1382         infoPtr->bPressed = FALSE;
1383     }
1384     else if (infoPtr->bTracking) {
1385         TRACE("End tracking item %d!\n", infoPtr->iMoveItem);
1386         infoPtr->bTracking = FALSE;
1387
1388         HEADER_SendHeaderNotify (hwnd, HDN_ENDTRACKA, infoPtr->iMoveItem,0);
1389
1390          /*
1391           * we want to do this even for HDS_FULLDRAG because this is where
1392           * we send the HDN_ITEMCHANGING and HDN_ITEMCHANGED notifications
1393           *
1394           * if (!(dwStyle & HDS_FULLDRAG)) {
1395           */
1396
1397             hdc = GetDC (hwnd);
1398             HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1399             ReleaseDC (hwnd, hdc);
1400                         if (HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH))
1401             {
1402                 infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth;
1403             }
1404             else {
1405                 nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1406                 if (nWidth < 0)
1407                     nWidth = 0;
1408                 infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1409             }
1410
1411                         HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH);
1412             HEADER_SetItemBounds (hwnd);
1413             InvalidateRect(hwnd, NULL, FALSE);
1414        /*     
1415         * }
1416         */
1417     }
1418
1419     if (infoPtr->bCaptured) {
1420         infoPtr->bCaptured = FALSE;
1421         ReleaseCapture ();
1422         HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE);
1423     }
1424
1425     return 0;
1426 }
1427
1428
1429 static LRESULT
1430 HEADER_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
1431 {
1432     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1433
1434     switch (lParam)
1435     {
1436         case NF_QUERY:
1437             return infoPtr->nNotifyFormat;
1438
1439         case NF_REQUERY:
1440             infoPtr->nNotifyFormat =
1441                 SendMessageA ((HWND)wParam, WM_NOTIFYFORMAT,
1442                               (WPARAM)hwnd, (LPARAM)NF_QUERY);
1443             return infoPtr->nNotifyFormat;
1444     }
1445
1446     return 0;
1447 }
1448
1449
1450 static LRESULT
1451 HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1452 {
1453     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1454     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1455     POINT pt;
1456     UINT  flags;
1457     INT   nItem, nWidth;
1458     HDC   hdc;
1459
1460     pt.x = (INT)SLOWORD(lParam);
1461     pt.y = (INT)SHIWORD(lParam);
1462     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1463
1464     if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) {
1465         if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
1466             infoPtr->iHotItem = nItem;
1467         else
1468             infoPtr->iHotItem = -1;
1469         InvalidateRect(hwnd, NULL, FALSE);
1470     }
1471
1472     if (infoPtr->bCaptured) {
1473         if (infoPtr->bPressed) {
1474             if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
1475                 infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
1476             else
1477                 infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1478             hdc = GetDC (hwnd);
1479             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1480             ReleaseDC (hwnd, hdc);
1481
1482             TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem);
1483         }
1484         else if (infoPtr->bTracking) {
1485             if (dwStyle & HDS_FULLDRAG) {
1486                 if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH))
1487                 {
1488                 nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1489                 if (nWidth < 0)
1490                   nWidth = 0;
1491                 infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1492                         HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDA, infoPtr->iMoveItem, HDI_WIDTH);
1493                 }
1494                 HEADER_SetItemBounds (hwnd);
1495                 InvalidateRect(hwnd, NULL, FALSE);
1496             }
1497             else {
1498                 hdc = GetDC (hwnd);
1499                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1500                 infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
1501                 if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
1502                     infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
1503                 infoPtr->items[infoPtr->iMoveItem].cxy = 
1504                     infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
1505                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1506                 ReleaseDC (hwnd, hdc);
1507             HEADER_SendHeaderNotify (hwnd, HDN_TRACKA, infoPtr->iMoveItem, HDI_WIDTH);
1508             }
1509
1510             TRACE("Tracking item %d!\n", infoPtr->iMoveItem);
1511         }
1512     }
1513
1514     if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) {
1515         FIXME("hot track support!\n");
1516     }
1517
1518     return 0;
1519 }
1520
1521
1522 static LRESULT
1523 HEADER_Paint (HWND hwnd, WPARAM wParam)
1524 {
1525     HDC hdc;
1526     PAINTSTRUCT ps;
1527
1528     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1529     HEADER_Refresh (hwnd, hdc);
1530     if(!wParam)
1531         EndPaint (hwnd, &ps);
1532     return 0;
1533 }
1534
1535
1536 static LRESULT
1537 HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1538 {
1539     BOOL bRet;
1540     POINT pt;
1541
1542     pt.x = LOWORD(lParam);
1543     pt.y = HIWORD(lParam);
1544
1545     /* Send a Notify message */
1546     bRet = HEADER_SendSimpleNotify (hwnd, NM_RCLICK);
1547
1548     /* Change to screen coordinate for WM_CONTEXTMENU */
1549     ClientToScreen(hwnd, &pt);
1550
1551     /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1552     SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
1553     
1554     return bRet;
1555 }
1556
1557
1558 static LRESULT
1559 HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1560 {
1561     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1562     POINT pt;
1563     UINT  flags;
1564     INT   nItem;
1565
1566     TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
1567
1568     GetCursorPos (&pt);
1569     ScreenToClient (hwnd, &pt);
1570
1571     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1572
1573     if (flags == HHT_ONDIVIDER)
1574         SetCursor (infoPtr->hcurDivider);
1575     else if (flags == HHT_ONDIVOPEN)
1576         SetCursor (infoPtr->hcurDivopen);
1577     else
1578         SetCursor (infoPtr->hcurArrow);
1579
1580     return 0;
1581 }
1582
1583
1584 static LRESULT
1585 HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1586 {
1587     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1588     TEXTMETRICA tm;
1589     HFONT hFont, hOldFont;
1590     HDC hdc;
1591
1592     infoPtr->hFont = (HFONT)wParam;
1593
1594     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
1595
1596     hdc = GetDC (0);
1597     hOldFont = SelectObject (hdc, hFont);
1598     GetTextMetricsA (hdc, &tm);
1599     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1600     SelectObject (hdc, hOldFont);
1601     ReleaseDC (0, hdc);
1602
1603     infoPtr->bRectsValid = FALSE;
1604         
1605     if (lParam) {
1606         InvalidateRect(hwnd, NULL, FALSE);
1607     }
1608
1609     return 0;
1610 }
1611
1612
1613 static LRESULT WINAPI
1614 HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1615 {
1616     TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx\n", hwnd, msg, wParam, lParam);
1617     if (!HEADER_GetInfoPtr (hwnd) && (msg != WM_CREATE))
1618         return DefWindowProcA (hwnd, msg, wParam, lParam);
1619     switch (msg) {
1620 /*      case HDM_CLEARFILTER: */
1621
1622         case HDM_CREATEDRAGIMAGE:
1623             return HEADER_CreateDragImage (hwnd, wParam);
1624
1625         case HDM_DELETEITEM:
1626             return HEADER_DeleteItem (hwnd, wParam);
1627
1628 /*      case HDM_EDITFILTER: */
1629
1630 /*      case HDM_GETBITMAPMARGIN: */
1631
1632         case HDM_GETIMAGELIST:
1633             return HEADER_GetImageList (hwnd);
1634
1635         case HDM_GETITEMA:
1636             return HEADER_GetItemA (hwnd, wParam, lParam);
1637
1638         case HDM_GETITEMW:
1639             return HEADER_GetItemW (hwnd, wParam, lParam);
1640
1641         case HDM_GETITEMCOUNT:
1642             return HEADER_GetItemCount (hwnd);
1643
1644         case HDM_GETITEMRECT:
1645             return HEADER_GetItemRect (hwnd, wParam, lParam);
1646
1647         case HDM_GETORDERARRAY: 
1648             return HEADER_GetOrderArray(hwnd, wParam, lParam);
1649
1650         case HDM_GETUNICODEFORMAT:
1651             return HEADER_GetUnicodeFormat (hwnd);
1652
1653         case HDM_HITTEST:
1654             return HEADER_HitTest (hwnd, wParam, lParam);
1655
1656         case HDM_INSERTITEMA:
1657             return HEADER_InsertItemA (hwnd, wParam, lParam);
1658
1659         case HDM_INSERTITEMW:
1660             return HEADER_InsertItemW (hwnd, wParam, lParam);
1661
1662         case HDM_LAYOUT:
1663             return HEADER_Layout (hwnd, wParam, lParam);
1664
1665         case HDM_ORDERTOINDEX:
1666             return HEADER_OrderToIndex(hwnd, wParam);
1667
1668 /*      case HDM_SETBITMAPMARGIN: */
1669
1670 /*      case HDM_SETFILTERCHANGETIMEOUT: */
1671
1672 /*      case HDM_SETHOTDIVIDER: */
1673
1674         case HDM_SETIMAGELIST:
1675             return HEADER_SetImageList (hwnd, (HIMAGELIST)lParam);
1676
1677         case HDM_SETITEMA:
1678             return HEADER_SetItemA (hwnd, wParam, lParam);
1679
1680         case HDM_SETITEMW:
1681             return HEADER_SetItemW (hwnd, wParam, lParam);
1682
1683         case HDM_SETORDERARRAY:
1684             return HEADER_SetOrderArray(hwnd, wParam, lParam);
1685
1686         case HDM_SETUNICODEFORMAT:
1687             return HEADER_SetUnicodeFormat (hwnd, wParam);
1688
1689         case WM_CREATE:
1690             return HEADER_Create (hwnd, wParam, lParam);
1691
1692         case WM_DESTROY:
1693             return HEADER_Destroy (hwnd, wParam, lParam);
1694
1695         case WM_ERASEBKGND:
1696             return 1;
1697
1698         case WM_GETDLGCODE:
1699             return DLGC_WANTTAB | DLGC_WANTARROWS;
1700
1701         case WM_GETFONT:
1702             return HEADER_GetFont (hwnd);
1703
1704         case WM_LBUTTONDBLCLK:
1705             return HEADER_LButtonDblClk (hwnd, wParam, lParam);
1706
1707         case WM_LBUTTONDOWN:
1708             return HEADER_LButtonDown (hwnd, wParam, lParam);
1709
1710         case WM_LBUTTONUP:
1711             return HEADER_LButtonUp (hwnd, wParam, lParam);
1712
1713         case WM_MOUSEMOVE:
1714             return HEADER_MouseMove (hwnd, wParam, lParam);
1715
1716         case WM_NOTIFYFORMAT:
1717             return HEADER_NotifyFormat (hwnd, wParam, lParam);
1718
1719         case WM_SIZE:
1720             return HEADER_Size (hwnd, wParam);
1721         
1722         case WM_PAINT:
1723             return HEADER_Paint (hwnd, wParam);
1724
1725         case WM_RBUTTONUP:
1726             return HEADER_RButtonUp (hwnd, wParam, lParam);
1727
1728         case WM_SETCURSOR:
1729             return HEADER_SetCursor (hwnd, wParam, lParam);
1730
1731         case WM_SETFONT:
1732             return HEADER_SetFont (hwnd, wParam, lParam);
1733
1734         default:
1735             if (msg >= WM_USER) 
1736                 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
1737                      msg, wParam, lParam );
1738             return DefWindowProcA (hwnd, msg, wParam, lParam);
1739     }
1740     return 0;
1741 }
1742
1743
1744 VOID
1745 HEADER_Register (void)
1746 {
1747     WNDCLASSA wndClass;
1748
1749     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1750     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
1751     wndClass.lpfnWndProc   = (WNDPROC)HEADER_WindowProc;
1752     wndClass.cbClsExtra    = 0;
1753     wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
1754     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
1755     wndClass.lpszClassName = WC_HEADERA;
1756  
1757     RegisterClassA (&wndClass);
1758 }
1759
1760
1761 VOID
1762 HEADER_Unregister (void)
1763 {
1764     UnregisterClassA (WC_HEADERA, (HINSTANCE)NULL);
1765 }
1766