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