#pragma pack(?) changed to #include "*pack*.h"
[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 "debug.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 (header, "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 (header, "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 (header, "ON DIVOPEN %d\n", *pItem);
339                                 return;
340                             }
341                             else {
342                                 *pFlags |= HHT_ONDIVIDER;
343                                 *pItem = iCount - 1;
344                                 TRACE (header, "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 (header, "ON DIVIDER %d\n", *pItem);
355                         return;
356                     }
357
358                     *pFlags |= HHT_ONHEADER;
359                     *pItem = iCount;
360                     TRACE (header, "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 (header, "ON DIVOPEN %d\n", *pItem);
374                     return;
375                 }
376                 else {
377                     *pFlags |= HHT_ONDIVIDER;
378                     *pItem = infoPtr->uNumItem-1;
379                     TRACE (header, "ON DIVIDER %d\n", *pItem);
380                     return;
381                 }
382             }
383
384             *pFlags |= HHT_NOWHERE;
385             *pItem = 1;
386             TRACE (header, "NOWHERE\n");
387             return;
388         }
389     }
390     else {
391         if (lpPt->x < rect.left) {
392            TRACE (header, "TO LEFT\n");
393            *pFlags |= HHT_TOLEFT;
394         }
395         else if (lpPt->x > rect.right) {
396             TRACE (header, "TO LEFT\n");
397             *pFlags |= HHT_TORIGHT;
398         }
399
400         if (lpPt->y < rect.top) {
401             TRACE (header, "ABOVE\n");
402             *pFlags |= HHT_ABOVE;
403         }
404         else if (lpPt->y > rect.bottom) {
405             TRACE (header, "BELOW\n");
406             *pFlags |= HHT_BELOW;
407         }
408     }
409
410     *pItem = 1;
411     TRACE (header, "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 (header, "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(header, "[iItem=%d]\n", iItem);
511     
512     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
513         return FALSE;
514
515     if (infoPtr->uNumItem == 1) {
516         TRACE(header, "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(header, "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 (header, "[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 (header, "[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) * 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         if (!phdi->pszText) /* null pointer check */
852                 phdi->pszText = "";
853         if (phdi->pszText != LPSTR_TEXTCALLBACKW) {
854             len = lstrlenW (phdi->pszText);
855             lpItem->pszText = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
856             lstrcpyW (lpItem->pszText, phdi->pszText);
857         }
858         else
859             lpItem->pszText = LPSTR_TEXTCALLBACKW;
860     }
861
862     if (phdi->mask & HDI_FORMAT)
863         lpItem->fmt = phdi->fmt;
864
865     if (lpItem->fmt == 0)
866         lpItem->fmt = HDF_LEFT;
867
868     if (phdi->mask & HDI_BITMAP)
869         lpItem->hbm = phdi->hbm;
870
871     if (phdi->mask & HDI_LPARAM)
872         lpItem->lParam = phdi->lParam;
873
874     if (phdi->mask & HDI_IMAGE)
875         lpItem->iImage = phdi->iImage;
876
877     if (phdi->mask & HDI_ORDER)
878         lpItem->iOrder = phdi->iOrder;
879
880     HEADER_SetItemBounds (hwnd);
881
882     hdc = GetDC (hwnd);
883     HEADER_Refresh (hwnd, hdc);
884     ReleaseDC (hwnd, hdc);
885
886     return nItem;
887 }
888
889
890 static LRESULT
891 HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam)
892 {
893     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
894     LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam;
895
896     lpLayout->pwpos->hwnd = hwnd;
897     lpLayout->pwpos->hwndInsertAfter = 0;
898     lpLayout->pwpos->x = lpLayout->prc->left;
899     lpLayout->pwpos->y = lpLayout->prc->top;
900     lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
901     if (GetWindowLongA (hwnd, GWL_STYLE) & HDS_HIDDEN)
902         lpLayout->pwpos->cy = 0;
903     else
904         lpLayout->pwpos->cy = infoPtr->nHeight;
905     lpLayout->pwpos->flags = SWP_NOZORDER;
906
907     TRACE (header, "Layout x=%d y=%d cx=%d cy=%d\n",
908            lpLayout->pwpos->x, lpLayout->pwpos->y,
909            lpLayout->pwpos->cx, lpLayout->pwpos->cy);
910
911     HEADER_ForceItemBounds (hwnd, lpLayout->pwpos->cy);
912
913     /* hack */
914 #ifdef __HDM_LAYOUT_HACK__
915     MoveWindow (lpLayout->pwpos->hwnd, lpLayout->pwpos->x, lpLayout->pwpos->y,
916                   lpLayout->pwpos->cx, lpLayout->pwpos->cy, TRUE);
917 #endif
918
919     return TRUE;
920 }
921
922
923 static LRESULT
924 HEADER_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
925 {
926     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
927     HIMAGELIST himlOld;
928
929     himlOld = infoPtr->himl;
930     infoPtr->himl = (HIMAGELIST)lParam;
931
932     /* FIXME: Refresh needed??? */
933
934     return (LRESULT)himlOld;
935 }
936
937
938 static LRESULT
939 HEADER_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
940 {
941     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
942     HDITEMA *phdi = (HDITEMA*)lParam;
943     INT nItem = (INT)wParam;
944     HEADER_ITEM *lpItem;
945     HDC hdc;
946
947     if (phdi == NULL)
948         return FALSE;
949     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
950         return FALSE;
951
952     TRACE (header, "[nItem=%d]\n", nItem);
953
954     if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, nItem))
955         return FALSE;
956
957     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
958     if (phdi->mask & HDI_BITMAP)
959         lpItem->hbm = phdi->hbm;
960
961     if (phdi->mask & HDI_FORMAT)
962         lpItem->fmt = phdi->fmt;
963
964     if (phdi->mask & HDI_LPARAM)
965         lpItem->lParam = phdi->lParam;
966
967     if (phdi->mask & HDI_TEXT) {
968         if (phdi->pszText != LPSTR_TEXTCALLBACKA) {
969             if (lpItem->pszText) {
970                 COMCTL32_Free (lpItem->pszText);
971                 lpItem->pszText = NULL;
972             }
973             if (phdi->pszText) {
974                 INT len = lstrlenA (phdi->pszText);
975                 lpItem->pszText = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
976                 lstrcpyAtoW (lpItem->pszText, phdi->pszText);
977             }
978         }
979         else
980             lpItem->pszText = LPSTR_TEXTCALLBACKW;
981     }
982
983     if (phdi->mask & HDI_WIDTH)
984         lpItem->cxy = phdi->cxy;
985
986     if (phdi->mask & HDI_IMAGE)
987         lpItem->iImage = phdi->iImage;
988
989     if (phdi->mask & HDI_ORDER)
990         lpItem->iOrder = phdi->iOrder;
991
992     HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, nItem);
993
994     HEADER_SetItemBounds (hwnd);
995     hdc = GetDC (hwnd);
996     HEADER_Refresh (hwnd, hdc);
997     ReleaseDC (hwnd, hdc);
998
999     return TRUE;
1000 }
1001
1002
1003 static LRESULT
1004 HEADER_SetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1005 {
1006     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1007     HDITEMW *phdi = (HDITEMW*)lParam;
1008     INT nItem = (INT)wParam;
1009     HEADER_ITEM *lpItem;
1010     HDC hdc;
1011
1012     if (phdi == NULL)
1013         return FALSE;
1014     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1015         return FALSE;
1016
1017     TRACE (header, "[nItem=%d]\n", nItem);
1018
1019     if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, nItem))
1020         return FALSE;
1021
1022     lpItem = (HEADER_ITEM*)&infoPtr->items[nItem];
1023     if (phdi->mask & HDI_BITMAP)
1024         lpItem->hbm = phdi->hbm;
1025
1026     if (phdi->mask & HDI_FORMAT)
1027         lpItem->fmt = phdi->fmt;
1028
1029     if (phdi->mask & HDI_LPARAM)
1030         lpItem->lParam = phdi->lParam;
1031
1032     if (phdi->mask & HDI_TEXT) {
1033         if (phdi->pszText != LPSTR_TEXTCALLBACKW) {
1034             if (lpItem->pszText) {
1035                 COMCTL32_Free (lpItem->pszText);
1036                 lpItem->pszText = NULL;
1037             }
1038             if (phdi->pszText) {
1039                 INT len = lstrlenW (phdi->pszText);
1040                 lpItem->pszText = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1041                 lstrcpyW (lpItem->pszText, phdi->pszText);
1042             }
1043         }
1044         else
1045             lpItem->pszText = LPSTR_TEXTCALLBACKW;
1046     }
1047
1048     if (phdi->mask & HDI_WIDTH)
1049         lpItem->cxy = phdi->cxy;
1050
1051     if (phdi->mask & HDI_IMAGE)
1052         lpItem->iImage = phdi->iImage;
1053
1054     if (phdi->mask & HDI_ORDER)
1055         lpItem->iOrder = phdi->iOrder;
1056
1057     HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, nItem);
1058
1059     HEADER_SetItemBounds (hwnd);
1060     hdc = GetDC (hwnd);
1061     HEADER_Refresh (hwnd, hdc);
1062     ReleaseDC (hwnd, hdc);
1063
1064     return TRUE;
1065 }
1066
1067
1068 /* << HEADER_SetOrderArray >> */
1069
1070
1071 __inline__ static LRESULT
1072 HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
1073 {
1074     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1075     BOOL bTemp = infoPtr->bUnicode;
1076
1077     infoPtr->bUnicode = (BOOL)wParam;
1078
1079     return bTemp;
1080 }
1081
1082
1083 static LRESULT
1084 HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1085 {
1086     HEADER_INFO *infoPtr;
1087     TEXTMETRICA tm;
1088     HFONT hOldFont;
1089     HDC   hdc;
1090
1091     infoPtr = (HEADER_INFO *)COMCTL32_Alloc (sizeof(HEADER_INFO));
1092     SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1093
1094     infoPtr->uNumItem = 0;
1095     infoPtr->nHeight = 20;
1096     infoPtr->hFont = 0;
1097     infoPtr->items = 0;
1098     infoPtr->hcurArrow = LoadCursorA (0, IDC_ARROWA);
1099     infoPtr->hcurDivider = LoadCursorA (0, IDC_SIZEWEA);
1100     infoPtr->hcurDivopen = LoadCursorA (0, IDC_SIZENSA);
1101     infoPtr->bPressed  = FALSE;
1102     infoPtr->bTracking = FALSE;
1103     infoPtr->iMoveItem = 0;
1104     infoPtr->himl = 0;
1105     infoPtr->iHotItem = -1;
1106     infoPtr->bUnicode = IsWindowUnicode (hwnd);
1107
1108     hdc = GetDC (0);
1109     hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1110     GetTextMetricsA (hdc, &tm);
1111     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1112     SelectObject (hdc, hOldFont);
1113     ReleaseDC (0, hdc);
1114
1115     return 0;
1116 }
1117
1118
1119 static LRESULT
1120 HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1121 {
1122     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1123     HEADER_ITEM *lpItem;
1124     INT nItem;
1125
1126     if (infoPtr->items) {
1127         lpItem = (HEADER_ITEM*)infoPtr->items;
1128         for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
1129             if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACKW))
1130                 COMCTL32_Free (lpItem->pszText);
1131         }
1132         COMCTL32_Free (infoPtr->items);
1133     }
1134
1135     if (infoPtr->himl)
1136         ImageList_Destroy (infoPtr->himl);
1137
1138     COMCTL32_Free (infoPtr);
1139
1140     return 0;
1141 }
1142
1143
1144 static __inline__ LRESULT
1145 HEADER_GetFont (HWND hwnd)
1146 {
1147     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1148
1149     return (LRESULT)infoPtr->hFont;
1150 }
1151
1152
1153 static LRESULT
1154 HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
1155 {
1156     POINT pt;
1157     UINT  flags;
1158     INT   nItem;
1159
1160     pt.x = (INT)LOWORD(lParam); 
1161     pt.y = (INT)HIWORD(lParam);
1162     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1163
1164     if ((GetWindowLongA (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER))
1165         HEADER_SendHeaderNotify (hwnd, HDN_ITEMDBLCLICKA, nItem);
1166     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
1167         HEADER_SendHeaderNotify (hwnd, HDN_DIVIDERDBLCLICKA, nItem);
1168
1169     return 0;
1170 }
1171
1172
1173 static LRESULT
1174 HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1175 {
1176     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1177     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1178     POINT pt;
1179     UINT  flags;
1180     INT   nItem;
1181     HDC   hdc;
1182
1183     pt.x = (INT)LOWORD(lParam); 
1184     pt.y = (INT)HIWORD(lParam);
1185     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1186
1187     if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
1188         SetCapture (hwnd);
1189         infoPtr->bCaptured = TRUE;   
1190         infoPtr->bPressed  = TRUE;
1191         infoPtr->iMoveItem = nItem;
1192
1193         infoPtr->items[nItem].bDown = TRUE;
1194
1195         /* Send WM_CUSTOMDRAW */
1196         hdc = GetDC (hwnd);
1197         HEADER_RefreshItem (hwnd, hdc, nItem);
1198         ReleaseDC (hwnd, hdc);
1199
1200         TRACE (header, "Pressed item %d!\n", nItem);
1201     } 
1202     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
1203         if (!(HEADER_SendHeaderNotify (hwnd, HDN_BEGINTRACKA, nItem))) {
1204             SetCapture (hwnd);
1205             infoPtr->bCaptured = TRUE;   
1206             infoPtr->bTracking = TRUE;
1207             infoPtr->iMoveItem = nItem;
1208             infoPtr->nOldWidth = infoPtr->items[nItem].cxy;
1209             infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
1210
1211             if (!(dwStyle & HDS_FULLDRAG)) {
1212                 infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
1213                 hdc = GetDC (hwnd);
1214                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1215                 ReleaseDC (hwnd, hdc);
1216             }
1217
1218             TRACE (header, "Begin tracking item %d!\n", nItem);
1219         }
1220     }
1221
1222     return 0;
1223 }
1224
1225
1226 static LRESULT
1227 HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1228 {
1229     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1230     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1231     POINT pt;
1232     UINT  flags;
1233     INT   nItem, nWidth;
1234     HDC   hdc;
1235
1236     pt.x = (INT)LOWORD(lParam);
1237     pt.y = (INT)HIWORD(lParam);
1238     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1239
1240     if (infoPtr->bPressed) {
1241         if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) {
1242             infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1243             hdc = GetDC (hwnd);
1244             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1245             ReleaseDC (hwnd, hdc);
1246
1247             HEADER_SendClickNotify (hwnd, HDN_ITEMCLICKA, infoPtr->iMoveItem);
1248         }
1249         TRACE (header, "Released item %d!\n", infoPtr->iMoveItem);
1250         infoPtr->bPressed = FALSE;
1251     }
1252     else if (infoPtr->bTracking) {
1253         TRACE (header, "End tracking item %d!\n", infoPtr->iMoveItem);
1254         infoPtr->bTracking = FALSE;
1255
1256         HEADER_SendHeaderNotify (hwnd, HDN_ENDTRACKA, infoPtr->iMoveItem);
1257
1258         if (!(dwStyle & HDS_FULLDRAG)) {
1259             hdc = GetDC (hwnd);
1260             HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1261             ReleaseDC (hwnd, hdc);
1262             if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem))
1263                 infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth;
1264             else {
1265                 nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1266                 if (nWidth < 0)
1267                     nWidth = 0;
1268                 infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1269                 HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, infoPtr->iMoveItem);
1270             }
1271
1272             HEADER_SetItemBounds (hwnd);
1273             hdc = GetDC (hwnd);
1274             HEADER_Refresh (hwnd, hdc);
1275             ReleaseDC (hwnd, hdc);
1276         }
1277     }
1278
1279     if (infoPtr->bCaptured) {
1280         infoPtr->bCaptured = FALSE;
1281         ReleaseCapture ();
1282         HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE);
1283     }
1284
1285     return 0;
1286 }
1287
1288
1289 static LRESULT
1290 HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1291 {
1292     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1293     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1294     POINT pt;
1295     UINT  flags;
1296     INT   nItem, nWidth;
1297     HDC   hdc;
1298
1299     pt.x = (INT)LOWORD(lParam);
1300     pt.y = (INT)HIWORD(lParam);
1301     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1302
1303     if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) {
1304         if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
1305             infoPtr->iHotItem = nItem;
1306         else
1307             infoPtr->iHotItem = -1;
1308         hdc = GetDC (hwnd);
1309         HEADER_Refresh (hwnd, hdc);
1310         ReleaseDC (hwnd, hdc);
1311     }
1312
1313     if (infoPtr->bCaptured) {
1314         if (infoPtr->bPressed) {
1315             if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
1316                 infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
1317             else
1318                 infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1319             hdc = GetDC (hwnd);
1320             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1321             ReleaseDC (hwnd, hdc);
1322
1323             TRACE (header, "Moving pressed item %d!\n", infoPtr->iMoveItem);
1324         }
1325         else if (infoPtr->bTracking) {
1326             if (dwStyle & HDS_FULLDRAG) {
1327                 if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem))
1328                     infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth;
1329                 else {
1330                     nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1331                     if (nWidth < 0)
1332                         nWidth = 0;
1333                     infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1334                     HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA,
1335                                              infoPtr->iMoveItem);
1336                 }
1337                 HEADER_SetItemBounds (hwnd);
1338                 hdc = GetDC (hwnd);
1339                 HEADER_Refresh (hwnd, hdc);
1340                 ReleaseDC (hwnd, hdc);
1341             }
1342             else {
1343                 hdc = GetDC (hwnd);
1344                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1345                 infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
1346                 if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
1347                     infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
1348                 infoPtr->items[infoPtr->iMoveItem].cxy = 
1349                     infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
1350                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1351                 ReleaseDC (hwnd, hdc);
1352             }
1353
1354             HEADER_SendHeaderNotify (hwnd, HDN_TRACKA, infoPtr->iMoveItem);
1355             TRACE (header, "Tracking item %d!\n", infoPtr->iMoveItem);
1356         }
1357     }
1358
1359     if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) {
1360         FIXME (header, "hot track support!\n");
1361     }
1362
1363     return 0;
1364 }
1365
1366
1367 static LRESULT
1368 HEADER_Paint (HWND hwnd, WPARAM wParam)
1369 {
1370     HDC hdc;
1371     PAINTSTRUCT ps;
1372
1373     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1374     HEADER_Refresh (hwnd, hdc);
1375     if(!wParam)
1376         EndPaint (hwnd, &ps);
1377     return 0;
1378 }
1379
1380
1381 static LRESULT
1382 HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1383 {
1384     return HEADER_SendSimpleNotify (hwnd, NM_RCLICK);
1385 }
1386
1387
1388 static LRESULT
1389 HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1390 {
1391     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1392     POINT pt;
1393     UINT  flags;
1394     INT   nItem;
1395
1396     TRACE (header, "code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
1397
1398     GetCursorPos (&pt);
1399     ScreenToClient (hwnd, &pt);
1400
1401     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1402
1403     if (flags == HHT_ONDIVIDER)
1404         SetCursor (infoPtr->hcurDivider);
1405     else if (flags == HHT_ONDIVOPEN)
1406         SetCursor (infoPtr->hcurDivopen);
1407     else
1408         SetCursor (infoPtr->hcurArrow);
1409
1410     return 0;
1411 }
1412
1413
1414 static LRESULT
1415 HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1416 {
1417     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1418     TEXTMETRICA tm;
1419     HFONT hFont, hOldFont;
1420     HDC hdc;
1421
1422     infoPtr->hFont = (HFONT)wParam;
1423
1424     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
1425
1426     hdc = GetDC (0);
1427     hOldFont = SelectObject (hdc, hFont);
1428     GetTextMetricsA (hdc, &tm);
1429     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1430     SelectObject (hdc, hOldFont);
1431     ReleaseDC (0, hdc);
1432
1433     if (lParam) {
1434         HEADER_ForceItemBounds (hwnd, infoPtr->nHeight);
1435         hdc = GetDC (hwnd);
1436         HEADER_Refresh (hwnd, hdc);
1437         ReleaseDC (hwnd, hdc);
1438     }
1439
1440     return 0;
1441 }
1442
1443
1444 LRESULT WINAPI
1445 HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1446 {
1447     switch (msg) {
1448         case HDM_CREATEDRAGIMAGE:
1449             return HEADER_CreateDragImage (hwnd, wParam);
1450
1451         case HDM_DELETEITEM:
1452             return HEADER_DeleteItem (hwnd, wParam);
1453
1454         case HDM_GETIMAGELIST:
1455             return HEADER_GetImageList (hwnd);
1456
1457         case HDM_GETITEMA:
1458             return HEADER_GetItemA (hwnd, wParam, lParam);
1459
1460         case HDM_GETITEMW:
1461             return HEADER_GetItemW (hwnd, wParam, lParam);
1462
1463         case HDM_GETITEMCOUNT:
1464             return HEADER_GetItemCount (hwnd);
1465
1466         case HDM_GETITEMRECT:
1467             return HEADER_GetItemRect (hwnd, wParam, lParam);
1468
1469 /*      case HDM_GETORDERARRAY: */
1470
1471         case HDM_GETUNICODEFORMAT:
1472             return HEADER_GetUnicodeFormat (hwnd);
1473
1474         case HDM_HITTEST:
1475             return HEADER_HitTest (hwnd, wParam, lParam);
1476
1477         case HDM_INSERTITEMA:
1478             return HEADER_InsertItemA (hwnd, wParam, lParam);
1479
1480         case HDM_INSERTITEMW:
1481             return HEADER_InsertItemW (hwnd, wParam, lParam);
1482
1483         case HDM_LAYOUT:
1484             return HEADER_Layout (hwnd, wParam, lParam);
1485
1486         case HDM_SETIMAGELIST:
1487             return HEADER_SetImageList (hwnd, wParam, lParam);
1488
1489         case HDM_SETITEMA:
1490             return HEADER_SetItemA (hwnd, wParam, lParam);
1491
1492         case HDM_SETITEMW:
1493             return HEADER_SetItemW (hwnd, wParam, lParam);
1494
1495 /*      case HDM_SETORDERARRAY: */
1496
1497         case HDM_SETUNICODEFORMAT:
1498             return HEADER_SetUnicodeFormat (hwnd, wParam);
1499
1500
1501         case WM_CREATE:
1502             return HEADER_Create (hwnd, wParam, lParam);
1503
1504         case WM_DESTROY:
1505             return HEADER_Destroy (hwnd, wParam, lParam);
1506
1507         case WM_ERASEBKGND:
1508             return 1;
1509
1510         case WM_GETDLGCODE:
1511             return DLGC_WANTTAB | DLGC_WANTARROWS;
1512
1513         case WM_GETFONT:
1514             return HEADER_GetFont (hwnd);
1515
1516         case WM_LBUTTONDBLCLK:
1517             return HEADER_LButtonDblClk (hwnd, wParam, lParam);
1518
1519         case WM_LBUTTONDOWN:
1520             return HEADER_LButtonDown (hwnd, wParam, lParam);
1521
1522         case WM_LBUTTONUP:
1523             return HEADER_LButtonUp (hwnd, wParam, lParam);
1524
1525         case WM_MOUSEMOVE:
1526             return HEADER_MouseMove (hwnd, wParam, lParam);
1527
1528 /*      case WM_NOTIFYFORMAT: */
1529
1530         case WM_PAINT:
1531             return HEADER_Paint (hwnd, wParam);
1532
1533         case WM_RBUTTONUP:
1534             return HEADER_RButtonUp (hwnd, wParam, lParam);
1535
1536         case WM_SETCURSOR:
1537             return HEADER_SetCursor (hwnd, wParam, lParam);
1538
1539         case WM_SETFONT:
1540             return HEADER_SetFont (hwnd, wParam, lParam);
1541
1542         default:
1543             if (msg >= WM_USER) 
1544                 ERR (header, "unknown msg %04x wp=%04x lp=%08lx\n",
1545                      msg, wParam, lParam );
1546             return DefWindowProcA (hwnd, msg, wParam, lParam);
1547     }
1548     return 0;
1549 }
1550
1551
1552 VOID
1553 HEADER_Register (VOID)
1554 {
1555     WNDCLASSA wndClass;
1556
1557     if (GlobalFindAtomA (WC_HEADERA)) return;
1558
1559     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1560     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
1561     wndClass.lpfnWndProc   = (WNDPROC)HEADER_WindowProc;
1562     wndClass.cbClsExtra    = 0;
1563     wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
1564     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
1565     wndClass.lpszClassName = WC_HEADERA;
1566  
1567     RegisterClassA (&wndClass);
1568 }
1569
1570
1571 VOID
1572 HEADER_Unregister (VOID)
1573 {
1574     if (GlobalFindAtomA (WC_HEADERA))
1575         UnregisterClassA (WC_HEADERA, (HINSTANCE)NULL);
1576 }
1577