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