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