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