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