header.c 61.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *  Header control
 *
 *  Copyright 1998 Eric Kohl
5
 *  Copyright 2000 Eric Kohl for CodeWeavers
6
 *  Copyright 2003 Maxime Bellenge
7
 *  Copyright 2006 Mikolaj Zalewski
Alexandre Julliard's avatar
Alexandre Julliard committed
8
 *
9 10 11 12 13 14 15 16 17 18 19 20
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
23
 *  TODO:
24 25 26 27
 *   - Imagelist support (completed?)
 *   - Hottrack support (completed?)
 *   - Filters support (HDS_FILTER, HDI_FILTER, HDM_*FILTER*, HDN_*FILTER*)
 *   - New Windows Vista features
Alexandre Julliard's avatar
Alexandre Julliard committed
28 29
 */

30
#include <stdarg.h>
31
#include <stdlib.h>
32 33
#include <string.h>

34
#include "windef.h"
35
#include "winbase.h"
36
#include "wine/unicode.h"
37 38 39
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
40
#include "commctrl.h"
41
#include "comctl32.h"
42
#include "vssym32.h"
43
#include "uxtheme.h"
44
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
45

46
WINE_DEFAULT_DEBUG_CHANNEL(header);
47

48
typedef struct
49 50 51 52 53 54 55 56 57 58 59
{
    INT     cxy;
    HBITMAP hbm;
    LPWSTR    pszText;
    INT     fmt;
    LPARAM    lParam;
    INT     iImage;
    INT     iOrder;		/* see documentation of HD_ITEM */

    BOOL    bDown;		/* is item pressed? (used for drawing) */
    RECT    rect;		/* bounding rectangle of the item */
60
    DWORD   callbackMask;       /* HDI_* flags for items that are callback */
61 62 63 64 65
} HEADER_ITEM;


typedef struct
{
66
    HWND      hwndSelf;		/* Control window */
67
    HWND      hwndNotify;	/* Owner window to send notifications to */
68
    INT       nNotifyFormat;	/* format used for WM_NOTIFY messages */
69 70
    UINT      uNumItem;		/* number of items (columns) */
    INT       nHeight;		/* height of the header (pixels) */
71 72 73 74 75
    HFONT     hFont;		/* handle to the current font */
    HCURSOR   hcurArrow;	/* handle to the arrow cursor */
    HCURSOR   hcurDivider;	/* handle to a cursor (used over dividers) <-|-> */
    HCURSOR   hcurDivopen;	/* handle to a cursor (used over dividers) <-||-> */
    BOOL      bCaptured;	/* Is the mouse captured? */
76
    BOOL      bPressed;		/* Is a header item pressed (down)? */
77
    BOOL      bDragging;        /* Are we dragging an item? */
78
    BOOL      bTracking;	/* Is in tracking mode? */
79
    POINT     ptLButtonDown;    /* The point where the left button was pressed */
80
    DWORD     dwStyle;		/* the cached window GWL_STYLE */
81 82 83
    INT       iMoveItem;	/* index of tracked item. (Tracking mode) */
    INT       xTrackOffset;	/* distance between the right side of the tracked item and the cursor */
    INT       xOldTrack;	/* track offset (see above) after the last WM_MOUSEMOVE */
84
    INT       iHotItem;		/* index of hot item (cursor is over this item) */
85
    INT       iHotDivider;      /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
86
    INT       iMargin;          /* width of the margin that surrounds a bitmap */
87

88
    HIMAGELIST  himl;		/* handle to an image list (may be 0) */
89
    HEADER_ITEM *items;		/* pointer to array of HEADER_ITEM's */
90
    INT         *order;         /* array of item IDs indexed by order */
91 92
    BOOL	bRectsValid;	/* validity flag for bounding rectangles */
} HEADER_INFO;
93

Alexandre Julliard's avatar
Alexandre Julliard committed
94

95
#define VERT_BORDER     4
Alexandre Julliard's avatar
Alexandre Julliard committed
96
#define DIVIDER_WIDTH  10
97
#define HOT_DIVIDER_WIDTH 2
98
#define MAX_HEADER_TEXT_LEN 260
99 100
#define HDN_UNICODE_OFFSET 20
#define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
Alexandre Julliard's avatar
Alexandre Julliard committed
101

102 103 104 105 106
#define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)
#define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)
#define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))
#define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)

Alexandre Julliard's avatar
Alexandre Julliard committed
107

108
static BOOL HEADER_PrepareCallbackItems(const HEADER_INFO *infoPtr, INT iItem, INT reqMask);
109
static void HEADER_FreeCallbackItems(HEADER_ITEM *lpItem);
110 111
static LRESULT HEADER_SendNotify(const HEADER_INFO *infoPtr, UINT code, NMHDR *hdr);
static LRESULT HEADER_SendCtrlCustomDraw(const HEADER_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, const RECT *rect);
112

113 114
static const WCHAR themeClass[] = {'H','e','a','d','e','r',0};

115
static void HEADER_StoreHDItemInHeader(HEADER_ITEM *lpItem, UINT mask, const HDITEMW *phdi, BOOL fUnicode)
116
{
117 118 119
    if (mask & HDI_UNSUPPORTED_FIELDS)
        FIXME("unsupported header fields %x\n", (mask & HDI_UNSUPPORTED_FIELDS));
    
120
    if (mask & HDI_BITMAP)
121 122
        lpItem->hbm = phdi->hbm;

123
    if (mask & HDI_FORMAT)
124 125
        lpItem->fmt = phdi->fmt;

126
    if (mask & HDI_LPARAM)
127 128
        lpItem->lParam = phdi->lParam;

129
    if (mask & HDI_WIDTH)
130 131
        lpItem->cxy = phdi->cxy;

132
    if (mask & HDI_IMAGE) 
133 134
    {
        lpItem->iImage = phdi->iImage;
135 136 137 138
        if (phdi->iImage == I_IMAGECALLBACK)
            lpItem->callbackMask |= HDI_IMAGE;
        else
            lpItem->callbackMask &= ~HDI_IMAGE;
139 140
    }

141
    if (mask & HDI_TEXT)
142
    {
143 144
        Free(lpItem->pszText);
        lpItem->pszText = NULL;
145

146 147
        if (phdi->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */
        {
148 149 150
            static const WCHAR emptyString[] = {0};

            LPCWSTR pszText = (phdi->pszText != NULL ? phdi->pszText : emptyString);
151 152 153
            if (fUnicode)
                Str_SetPtrW(&lpItem->pszText, pszText);
            else
154
                Str_SetPtrAtoW(&lpItem->pszText, (LPCSTR)pszText);
155
            lpItem->callbackMask &= ~HDI_TEXT;
156 157 158
        }
        else
        {
159 160
            lpItem->pszText = NULL;
            lpItem->callbackMask |= HDI_TEXT;
161 162 163 164
        }  
    }
}

165
static inline LRESULT
166
HEADER_IndexToOrder (const HEADER_INFO *infoPtr, INT iItem)
167
{
168
    HEADER_ITEM *lpItem = &infoPtr->items[iItem];
169 170 171 172
    return lpItem->iOrder;
}


173
static INT
174
HEADER_OrderToIndex(const HEADER_INFO *infoPtr, INT iorder)
175
{
176
    if ((iorder <0) || iorder >= infoPtr->uNumItem)
177
      return iorder;
178
    return infoPtr->order[iorder];
179 180
}

181
static void
182
HEADER_ChangeItemOrder(const HEADER_INFO *infoPtr, INT iItem, INT iNewOrder)
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
{
    HEADER_ITEM *lpItem = &infoPtr->items[iItem];
    INT i, nMin, nMax;

    TRACE("%d: %d->%d\n", iItem, lpItem->iOrder, iNewOrder);
    if (lpItem->iOrder < iNewOrder)
    {
        memmove(&infoPtr->order[lpItem->iOrder],
               &infoPtr->order[lpItem->iOrder + 1],
               (iNewOrder - lpItem->iOrder) * sizeof(INT));
    }
    if (iNewOrder < lpItem->iOrder)
    {
        memmove(&infoPtr->order[iNewOrder + 1],
                &infoPtr->order[iNewOrder],
                (lpItem->iOrder - iNewOrder) * sizeof(INT));
    }
    infoPtr->order[iNewOrder] = iItem;
    nMin = min(lpItem->iOrder, iNewOrder);
    nMax = max(lpItem->iOrder, iNewOrder);
    for (i = nMin; i <= nMax; i++)
        infoPtr->items[infoPtr->order[i]].iOrder = i;
}

207 208
/* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
static INT
209
HEADER_NextItem(const HEADER_INFO *infoPtr, INT iItem)
210
{
211
    return HEADER_OrderToIndex(infoPtr, HEADER_IndexToOrder(infoPtr, iItem)+1);
212 213
}

214
static INT
215
HEADER_PrevItem(const HEADER_INFO *infoPtr, INT iItem)
216
{
217
    return HEADER_OrderToIndex(infoPtr, HEADER_IndexToOrder(infoPtr, iItem)-1);
218 219
}

220 221 222 223 224 225 226 227
/* TRUE when item is not resizable with dividers,
   note that valid index should be supplied */
static inline BOOL
HEADER_IsItemFixed(const HEADER_INFO *infoPtr, INT iItem)
{
    return (infoPtr->dwStyle & HDS_NOSIZING) || (infoPtr->items[iItem].fmt & HDF_FIXEDWIDTH);
}

228
static void
229
HEADER_SetItemBounds (HEADER_INFO *infoPtr)
230 231 232
{
    HEADER_ITEM *phdi;
    RECT rect;
233 234
    unsigned int i;
    int x;
235 236 237 238 239 240

    infoPtr->bRectsValid = TRUE;

    if (infoPtr->uNumItem == 0)
        return;

241
    GetClientRect (infoPtr->hwndSelf, &rect);
242 243 244

    x = rect.left;
    for (i = 0; i < infoPtr->uNumItem; i++) {
245
        phdi = &infoPtr->items[HEADER_OrderToIndex(infoPtr,i)];
246 247 248
        phdi->rect.top = rect.top;
        phdi->rect.bottom = rect.bottom;
        phdi->rect.left = x;
249
        phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0);
250 251 252 253 254
        x = phdi->rect.right;
    }
}

static LRESULT
255
HEADER_Size (HEADER_INFO *infoPtr)
256
{
257
    HEADER_SetItemBounds(infoPtr);
258 259 260
    return 0;
}

261
static void HEADER_GetHotDividerRect(const HEADER_INFO *infoPtr, RECT *r)
262 263 264 265 266 267 268 269 270 271 272 273 274 275
{
    INT iDivider = infoPtr->iHotDivider;
    if (infoPtr->uNumItem > 0)
    {
        HEADER_ITEM *lpItem;
        
        if (iDivider < infoPtr->uNumItem)
        {
            lpItem = &infoPtr->items[iDivider];
            r->left  = lpItem->rect.left - HOT_DIVIDER_WIDTH/2;
            r->right = lpItem->rect.left + HOT_DIVIDER_WIDTH/2;
        }
        else
        {
276
            lpItem = &infoPtr->items[HEADER_OrderToIndex(infoPtr, infoPtr->uNumItem-1)];
277 278 279 280 281 282 283 284 285
            r->left  = lpItem->rect.right - HOT_DIVIDER_WIDTH/2;
            r->right = lpItem->rect.right + HOT_DIVIDER_WIDTH/2;
        }
        r->top    = lpItem->rect.top;
        r->bottom = lpItem->rect.bottom;
    }
    else
    {
        RECT clientRect;
286
        GetClientRect(infoPtr->hwndSelf, &clientRect);
287 288 289 290 291
        *r = clientRect;
        r->right = r->left + HOT_DIVIDER_WIDTH/2;
    }
}

292

293
static INT
294
HEADER_DrawItem (HEADER_INFO *infoPtr, HDC hdc, INT iItem, BOOL bHotTrack, LRESULT lCDFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
295
{
Alexandre Julliard's avatar
Alexandre Julliard committed
296
    HEADER_ITEM *phdi = &infoPtr->items[iItem];
297
    RECT r;
298
    INT  oldBkMode;
299
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
300
    NMCUSTOMDRAW nmcd;
Alexandre Julliard's avatar
Alexandre Julliard committed
301

302
    TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, (infoPtr->nNotifyFormat == NFR_UNICODE));
303

Alexandre Julliard's avatar
Alexandre Julliard committed
304 305 306 307
    r = phdi->rect;
    if (r.right - r.left == 0)
	return phdi->rect.right;

308 309
    /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
    SetTextColor(hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
310
    SetBkColor(hdc, comctl32_color.clr3dFace);
311 312 313 314 315 316 317 318 319 320 321 322

    if (lCDFlags & CDRF_NOTIFYITEMDRAW && !(phdi->fmt & HDF_OWNERDRAW))
    {
        LRESULT lCDItemFlags;

        nmcd.dwDrawStage  = CDDS_PREPAINT | CDDS_ITEM;
        nmcd.hdc          = hdc;
        nmcd.dwItemSpec   = iItem;
        nmcd.rc           = r;
        nmcd.uItemState   = phdi->bDown ? CDIS_SELECTED : 0;
        nmcd.lItemlParam  = phdi->lParam;

323
        lCDItemFlags = HEADER_SendNotify(infoPtr, NM_CUSTOMDRAW, (NMHDR *)&nmcd);
324 325 326 327
        if (lCDItemFlags & CDRF_SKIPDEFAULT)
            return phdi->rect.right;
    }

328 329 330 331 332 333 334 335 336
    if (theme != NULL) {
        int state = (phdi->bDown) ? HIS_PRESSED :
            (bHotTrack ? HIS_HOT : HIS_NORMAL);
        DrawThemeBackground (theme, hdc, HP_HEADERITEM, state,
            &r, NULL);
        GetThemeBackgroundContentRect (theme, hdc, HP_HEADERITEM, state,
            &r, &r);
    }
    else {
337
        HBRUSH hbr;
338 339 340 341 342 343 344 345 346 347 348

        if (!(infoPtr->dwStyle & HDS_FLAT))
        {
            if (infoPtr->dwStyle & HDS_BUTTONS) {
                if (phdi->bDown) {
                    DrawEdge (hdc, &r, BDR_RAISEDOUTER,
                                BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST);
                }
                else
                    DrawEdge (hdc, &r, EDGE_RAISED,
                                BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
349 350
            }
            else
351
                DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
352
        }
353 354 355 356

        hbr = CreateSolidBrush(GetBkColor(hdc));
        FillRect(hdc, &r, hbr);
        DeleteObject(hbr);
357 358 359 360
    }
    if (phdi->bDown) {
        r.left += 2;
        r.top  += 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
361 362 363
    }

    if (phdi->fmt & HDF_OWNERDRAW) {
364
	DRAWITEMSTRUCT dis;
365

Alexandre Julliard's avatar
Alexandre Julliard committed
366
	dis.CtlType    = ODT_HEADER;
367
	dis.CtlID      = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369 370
	dis.itemID     = iItem;
	dis.itemAction = ODA_DRAWENTIRE;
	dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
371
	dis.hwndItem   = infoPtr->hwndSelf;
Alexandre Julliard's avatar
Alexandre Julliard committed
372
	dis.hDC        = hdc;
373
	dis.rcItem     = phdi->rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
374
	dis.itemData   = phdi->lParam;
375
        oldBkMode = SetBkMode(hdc, TRANSPARENT);
376
        SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
377 378
        if (oldBkMode != TRANSPARENT)
            SetBkMode(hdc, oldBkMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
379 380
    }
    else {
381 382 383 384 385
	UINT rw, rh, /* width and height of r */
	     *x = NULL, *w = NULL; /* x and width of the pic (bmp or img) which is part of cnt */
	  /* cnt,txt,img,bmp */
	UINT cx, tx, ix, bx,
	     cw, tw, iw, bw;
386
        INT img_cx, img_cy;
387 388
	BITMAP bmp;

389
        HEADER_PrepareCallbackItems(infoPtr, iItem, HDI_TEXT|HDI_IMAGE);
390 391 392 393 394 395
	cw = tw = iw = bw = 0;
	rw = r.right - r.left;
	rh = r.bottom - r.top;

	if (phdi->fmt & HDF_STRING) {
	    RECT textRect;
Alexandre Julliard's avatar
Alexandre Julliard committed
396

397
            SetRectEmpty(&textRect);
398 399 400 401
	    DrawTextW (hdc, phdi->pszText, -1,
	               &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
	    cw = textRect.right - textRect.left + 2 * infoPtr->iMargin;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
402

403 404
	if ((phdi->fmt & HDF_IMAGE) && ImageList_GetIconSize( infoPtr->himl, &img_cx, &img_cy )) {
	    iw = img_cx + 2 * infoPtr->iMargin;
405 406 407
	    x = &ix;
	    w = &iw;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
408

409
	if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) {
410
            GetObjectW (phdi->hbm, sizeof(BITMAP), &bmp);
411 412 413 414
	    bw = bmp.bmWidth + 2 * infoPtr->iMargin;
	    if (!iw) {
		x = &bx;
		w = &bw;
Alexandre Julliard's avatar
Alexandre Julliard committed
415
	    }
416
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
417

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	if (bw || iw)
	    cw += *w; 

	/* align cx using the unclipped cw */
	if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT)
	    cx = r.left;
	else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
	    cx = r.left + rw / 2 - cw / 2;
	else /* HDF_RIGHT */
	    cx = r.right - cw;
        
	/* clip cx & cw */
	if (cx < r.left)
	    cx = r.left;
	if (cx + cw > r.right)
	    cw = r.right - cx;
	
	tx = cx + infoPtr->iMargin;
	/* since cw might have changed we have to recalculate tw */
	tw = cw - infoPtr->iMargin * 2;
			
	if (iw || bw) {
	    tw -= *w;
	    if (phdi->fmt & HDF_BITMAP_ON_RIGHT) {
		/* put pic behind text */
		*x = cx + tw + infoPtr->iMargin * 3;
	    } else {
		*x = cx + infoPtr->iMargin;
		/* move text behind pic */
		tx += *w;
Alexandre Julliard's avatar
Alexandre Julliard committed
448 449 450
	    }
	}

451 452 453 454 455 456 457
	if (iw && bw) {
	    /* since we're done with the layout we can
	       now calculate the position of bmp which
	       has no influence on alignment and layout
	       because of img */
	    if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
	        bx = cx - bw + infoPtr->iMargin;
458
	    else
459 460
	        bx = cx + cw + infoPtr->iMargin;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
461

462
	if (iw || bw) {
463
	    HDC hClipDC = GetDC(infoPtr->hwndSelf);
464 465 466 467 468 469 470 471 472
	    HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
	    SelectClipRgn(hClipDC, hClipRgn);
	    
	    if (bw) {
	        HDC hdcBitmap = CreateCompatibleDC (hClipDC);
	        SelectObject (hdcBitmap, phdi->hbm);
	        BitBlt (hClipDC, bx, r.top + ((INT)rh - bmp.bmHeight) / 2, 
		        bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
	        DeleteDC (hdcBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
473 474
	    }

475 476
	    if (iw) {
	        ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, 
477 478
	                          ix, r.top + ((INT)rh - img_cy) / 2,
	                          img_cx, img_cy, CLR_DEFAULT, CLR_DEFAULT, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
479 480
	    }

481
	    DeleteObject(hClipRgn);
482
	    ReleaseDC(infoPtr->hwndSelf, hClipDC);
Alexandre Julliard's avatar
Alexandre Julliard committed
483
	}
484 485
        
	if (((phdi->fmt & HDF_STRING)
486 487 488
		|| (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP|
				   HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */
	    && (phdi->pszText)) {
489 490 491
	    oldBkMode = SetBkMode(hdc, TRANSPARENT);
	    r.left  = tx;
	    r.right = tx + tw;
492
	    DrawTextW (hdc, phdi->pszText, -1,
493
	               &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE);
494 495
	    if (oldBkMode != TRANSPARENT)
	        SetBkMode(hdc, oldBkMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
496
        }
497
        HEADER_FreeCallbackItems(phdi);
498
    }/*Ownerdrawn*/
499

Alexandre Julliard's avatar
Alexandre Julliard committed
500 501 502
    return phdi->rect.right;
}

503
static void
504
HEADER_DrawHotDivider(const HEADER_INFO *infoPtr, HDC hdc)
505 506 507 508
{
    HBRUSH brush;
    RECT r;
    
509
    HEADER_GetHotDividerRect(infoPtr, &r);
510
    brush = CreateSolidBrush(comctl32_color.clrHighlight);
511 512 513
    FillRect(hdc, &r, brush);
    DeleteObject(brush);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
514

515
static void
516
HEADER_Refresh (HEADER_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
517
{
518
    HFONT hFont, hOldFont;
519
    RECT rect, rcRest;
520
    HBRUSH hbrBk;
521 522
    UINT i;
    INT x;
523
    LRESULT lCDFlags;
524
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
525

526
    if (!infoPtr->bRectsValid)
527
        HEADER_SetItemBounds(infoPtr);
528

Alexandre Julliard's avatar
Alexandre Julliard committed
529
    /* get rect for the bar, adjusted for the border */
530 531
    GetClientRect (infoPtr->hwndSelf, &rect);
    lCDFlags = HEADER_SendCtrlCustomDraw(infoPtr, CDDS_PREPAINT, hdc, &rect);
532 533 534
    
    if (infoPtr->bDragging)
	ImageList_DragShowNolock(FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
535

536 537
    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
    hOldFont = SelectObject (hdc, hFont);
Alexandre Julliard's avatar
Alexandre Julliard committed
538 539

    /* draw Background */
540
    if (infoPtr->uNumItem == 0 && theme == NULL) {
541 542 543
        hbrBk = GetSysColorBrush(COLOR_3DFACE);
        FillRect(hdc, &rect, hbrBk);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
544 545

    x = rect.left;
546
    for (i = 0; x <= rect.right && i < infoPtr->uNumItem; i++) {
547
        int idx = HEADER_OrderToIndex(infoPtr,i);
548
        if (RectVisible(hdc, &infoPtr->items[idx].rect))
549
            HEADER_DrawItem(infoPtr, hdc, idx, infoPtr->iHotItem == idx, lCDFlags);
550
        x = infoPtr->items[idx].rect.right;
Alexandre Julliard's avatar
Alexandre Julliard committed
551 552
    }

553 554 555
    rcRest = rect;
    rcRest.left = x;
    if ((x <= rect.right) && RectVisible(hdc, &rcRest) && (infoPtr->uNumItem > 0)) {
556
        if (theme != NULL) {
557
            DrawThemeBackground(theme, hdc, HP_HEADERITEM, HIS_NORMAL, &rcRest, NULL);
558
        }
559 560 561 562 563 564
        else if (infoPtr->dwStyle & HDS_FLAT) {
            hbrBk = GetSysColorBrush(COLOR_3DFACE);
            FillRect(hdc, &rcRest, hbrBk);
        }
        else
        {
565
            if (infoPtr->dwStyle & HDS_BUTTONS)
566
                DrawEdge (hdc, &rcRest, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT|BF_MIDDLE);
567
            else
568
                DrawEdge (hdc, &rcRest, EDGE_ETCHED, BF_BOTTOM|BF_MIDDLE);
569
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
570
    }
571

572
    if (infoPtr->iHotDivider != -1)
573
        HEADER_DrawHotDivider(infoPtr, hdc);
574 575 576

    if (infoPtr->bDragging)
	ImageList_DragShowNolock(TRUE);
577
    SelectObject (hdc, hOldFont);
578 579
    
    if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
580
        HEADER_SendCtrlCustomDraw(infoPtr, CDDS_POSTPAINT, hdc, &rect);
Alexandre Julliard's avatar
Alexandre Julliard committed
581 582 583 584
}


static void
585
HEADER_RefreshItem (HEADER_INFO *infoPtr, INT iItem)
Alexandre Julliard's avatar
Alexandre Julliard committed
586
{
587
    if (!infoPtr->bRectsValid)
588
        HEADER_SetItemBounds(infoPtr);
589

590
    InvalidateRect(infoPtr->hwndSelf, &infoPtr->items[iItem].rect, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
591 592 593 594
}


static void
595
HEADER_InternalHitTest (const HEADER_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pItem)
Alexandre Julliard's avatar
Alexandre Julliard committed
596
{
597
    RECT rect, rcTest;
598 599
    UINT iCount;
    INT width;
600
    BOOL bNoWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
601

602
    GetClientRect (infoPtr->hwndSelf, &rect);
Alexandre Julliard's avatar
Alexandre Julliard committed
603 604 605

    *pFlags = 0;
    bNoWidth = FALSE;
606
    if (PtInRect (&rect, *lpPt))
Alexandre Julliard's avatar
Alexandre Julliard committed
607 608 609 610
    {
	if (infoPtr->uNumItem == 0) {
	    *pFlags |= HHT_NOWHERE;
	    *pItem = 1;
611
	    TRACE("NOWHERE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
612 613 614 615 616 617 618 619 620 621 622
	    return;
	}
	else {
	    /* somewhere inside */
	    for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
		rect = infoPtr->items[iCount].rect;
		width = rect.right - rect.left;
		if (width == 0) {
		    bNoWidth = TRUE;
		    continue;
		}
623
		if (PtInRect (&rect, *lpPt)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
624 625 626
		    if (width <= 2 * DIVIDER_WIDTH) {
			*pFlags |= HHT_ONHEADER;
			*pItem = iCount;
627
			TRACE("ON HEADER %d\n", iCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
628 629
			return;
		    }
630
                    if (HEADER_IndexToOrder(infoPtr, iCount) > 0) {
Alexandre Julliard's avatar
Alexandre Julliard committed
631 632
			rcTest = rect;
			rcTest.right = rcTest.left + DIVIDER_WIDTH;
633
			if (PtInRect (&rcTest, *lpPt)) {
634
			    if (HEADER_IsItemFixed(infoPtr, HEADER_PrevItem(infoPtr, iCount)))
635 636 637 638 639 640
			    {
				*pFlags |= HHT_ONHEADER;
                                *pItem = iCount;
				TRACE("ON HEADER %d\n", *pItem);
				return;
			    }
Alexandre Julliard's avatar
Alexandre Julliard committed
641 642
			    if (bNoWidth) {
				*pFlags |= HHT_ONDIVOPEN;
643
                                *pItem = HEADER_PrevItem(infoPtr, iCount);
644
				TRACE("ON DIVOPEN %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
645 646 647 648
				return;
			    }
			    else {
				*pFlags |= HHT_ONDIVIDER;
649
                                *pItem = HEADER_PrevItem(infoPtr, iCount);
650
				TRACE("ON DIVIDER %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
651 652 653 654 655 656
				return;
			    }
			}
		    }
		    rcTest = rect;
		    rcTest.left = rcTest.right - DIVIDER_WIDTH;
657
		    if (!HEADER_IsItemFixed(infoPtr, iCount) && PtInRect (&rcTest, *lpPt))
658
		    {
Alexandre Julliard's avatar
Alexandre Julliard committed
659 660
			*pFlags |= HHT_ONDIVIDER;
			*pItem = iCount;
661
			TRACE("ON DIVIDER %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
662 663 664 665 666
			return;
		    }

		    *pFlags |= HHT_ONHEADER;
		    *pItem = iCount;
667
		    TRACE("ON HEADER %d\n", iCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
668 669 670 671 672
		    return;
		}
	    }

	    /* check for last divider part (on nowhere) */
673
	    if (!HEADER_IsItemFixed(infoPtr, infoPtr->uNumItem - 1))
674 675 676 677 678 679 680 681 682 683 684 685 686
	    {
		rect = infoPtr->items[infoPtr->uNumItem-1].rect;
		rect.left = rect.right;
		rect.right += DIVIDER_WIDTH;
		if (PtInRect (&rect, *lpPt)) {
		    if (bNoWidth) {
			*pFlags |= HHT_ONDIVOPEN;
			*pItem = infoPtr->uNumItem - 1;
			TRACE("ON DIVOPEN %d\n", *pItem);
			return;
		    }
		    else {
			*pFlags |= HHT_ONDIVIDER;
687
			*pItem = infoPtr->uNumItem - 1;
688 689 690
			TRACE("ON DIVIDER %d\n", *pItem);
			return;
		    }
Alexandre Julliard's avatar
Alexandre Julliard committed
691 692 693 694 695
		}
	    }

	    *pFlags |= HHT_NOWHERE;
	    *pItem = 1;
696
	    TRACE("NOWHERE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
697 698 699 700 701
	    return;
	}
    }
    else {
	if (lpPt->x < rect.left) {
702
	   TRACE("TO LEFT\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
703 704 705
	   *pFlags |= HHT_TOLEFT;
	}
	else if (lpPt->x > rect.right) {
Thuy Nguyen's avatar
Thuy Nguyen committed
706
	    TRACE("TO RIGHT\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
707 708 709 710
	    *pFlags |= HHT_TORIGHT;
	}

	if (lpPt->y < rect.top) {
711
	    TRACE("ABOVE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
712 713 714
	    *pFlags |= HHT_ABOVE;
	}
	else if (lpPt->y > rect.bottom) {
715
	    TRACE("BELOW\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
716 717 718 719 720
	    *pFlags |= HHT_BELOW;
	}
    }

    *pItem = 1;
721
    TRACE("flags=0x%X\n", *pFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
722 723 724 725 726
    return;
}


static void
727
HEADER_DrawTrackLine (const HEADER_INFO *infoPtr, HDC hdc, INT x)
Alexandre Julliard's avatar
Alexandre Julliard committed
728
{
729 730
    RECT rect;

731
    GetClientRect (infoPtr->hwndSelf, &rect);
732
    PatBlt( hdc, x, rect.top, 1, rect.bottom - rect.top, DSTINVERT );
Alexandre Julliard's avatar
Alexandre Julliard committed
733 734
}

735 736 737 738 739 740 741 742 743 744 745 746 747 748
/***
 * DESCRIPTION:
 * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
 *
 * PARAMETER(S):
 * [I] infoPtr : the header that wants to send the notify
 * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
 * [I] src  : The source HDITEM. It may be a HDITEMA or HDITEMW
 * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
 * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
 *                  the HDITEM is no longer in use or NULL if none was needed
 * 
 * NOTE: We depend on HDITEMA and HDITEMW having the same structure
 */
749 750
static void HEADER_CopyHDItemForNotify(const HEADER_INFO *infoPtr, HDITEMW *dest,
    const HDITEMW *src, BOOL fSourceUnicode, LPVOID *ppvScratch)
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
{
    *ppvScratch = NULL;
    *dest = *src;
    
    if (src->mask & HDI_TEXT && src->pszText != LPSTR_TEXTCALLBACKW) /* covers TEXTCALLBACKA as well */
    {
        if (fSourceUnicode && infoPtr->nNotifyFormat != NFR_UNICODE)
        {
            dest->pszText = NULL;
            Str_SetPtrWtoA((LPSTR *)&dest->pszText, src->pszText);
            *ppvScratch = dest->pszText;
        }
        
        if (!fSourceUnicode && infoPtr->nNotifyFormat == NFR_UNICODE)
        {
            dest->pszText = NULL;
            Str_SetPtrAtoW(&dest->pszText, (LPSTR)src->pszText);
            *ppvScratch = dest->pszText;
        }
    }
}

773 774 775 776 777 778 779 780
static UINT HEADER_NotifyCodeWtoA(UINT code)
{
    /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
    if (code >= HDN_LAST && code <= HDN_FIRST_UNICODE)
        return code + HDN_UNICODE_OFFSET;
    else
        return code;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
781

782
static LRESULT
783
HEADER_SendNotify(const HEADER_INFO *infoPtr, UINT code, NMHDR *nmhdr)
784
{
785 786
    nmhdr->hwndFrom = infoPtr->hwndSelf;
    nmhdr->idFrom   = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
787 788 789
    nmhdr->code     = code;

    return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
790
				   nmhdr->idFrom, (LPARAM)nmhdr);
791 792
}

793
static BOOL
794
HEADER_SendSimpleNotify (const HEADER_INFO *infoPtr, UINT code)
Alexandre Julliard's avatar
Alexandre Julliard committed
795 796
{
    NMHDR nmhdr;
797
    return (BOOL)HEADER_SendNotify(infoPtr, code, &nmhdr);
798
}
Alexandre Julliard's avatar
Alexandre Julliard committed
799

800
static LRESULT
801
HEADER_SendCtrlCustomDraw(const HEADER_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, const RECT *rect)
802 803 804 805 806 807 808 809 810
{
    NMCUSTOMDRAW nm;
    nm.dwDrawStage = dwDrawStage;
    nm.hdc = hdc;
    nm.rc = *rect;
    nm.dwItemSpec = 0;
    nm.uItemState = 0;
    nm.lItemlParam = 0;

811
    return HEADER_SendNotify(infoPtr, NM_CUSTOMDRAW, (NMHDR *)&nm);
Alexandre Julliard's avatar
Alexandre Julliard committed
812 813
}

814
static BOOL
815
HEADER_SendNotifyWithHDItemT(const HEADER_INFO *infoPtr, UINT code, INT iItem, HDITEMW *lpItem)
Alexandre Julliard's avatar
Alexandre Julliard committed
816
{
817 818
    NMHEADERW nmhdr;
    
819 820
    if (infoPtr->nNotifyFormat != NFR_UNICODE)
        code = HEADER_NotifyCodeWtoA(code);
Alexandre Julliard's avatar
Alexandre Julliard committed
821 822
    nmhdr.iItem = iItem;
    nmhdr.iButton = 0;
823
    nmhdr.pitem = lpItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
824

825
    return (BOOL)HEADER_SendNotify(infoPtr, code, (NMHDR *)&nmhdr);
826 827
}

828
static BOOL
829
HEADER_SendNotifyWithIntFieldT(const HEADER_INFO *infoPtr, UINT code, INT iItem, INT mask, INT iValue)
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
{
    HDITEMW nmitem;

    /* copying only the iValue should be ok but to make the code more robust we copy everything */
    nmitem.cxy = infoPtr->items[iItem].cxy;
    nmitem.hbm = infoPtr->items[iItem].hbm;
    nmitem.pszText = NULL;
    nmitem.cchTextMax = 0;
    nmitem.fmt = infoPtr->items[iItem].fmt;
    nmitem.lParam = infoPtr->items[iItem].lParam;
    nmitem.iOrder = infoPtr->items[iItem].iOrder;
    nmitem.iImage = infoPtr->items[iItem].iImage;

    nmitem.mask = mask;
    switch (mask)
    {
	case HDI_WIDTH:
	    nmitem.cxy = iValue;
	    break;
	case HDI_ORDER:
	    nmitem.iOrder = iValue;
	    break;
	default:
	    ERR("invalid mask value 0x%x\n", iValue);
    }

856
    return HEADER_SendNotifyWithHDItemT(infoPtr, code, iItem, &nmitem);
857 858
}

859
/**
860
 * Prepare callback items
861 862
 *   depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA 
 *   (so we handle the two cases only doing a specific cast for pszText).
863 864 865 866
 * Checks if any of the required field are callback. If there are sends a 
 * NMHDISPINFO notify to retrieve these items. The items are stored in the
 * HEADER_ITEM pszText and iImage fields. They should be freed with
 * HEADER_FreeCallbackItems.
867 868
 *
 * @param hwnd : hwnd header container handler
869 870 871 872
 * @param iItem : the header item id
 * @param reqMask : required fields. If any of them is callback this function will fetch it
 *
 * @return TRUE on success, else FALSE
873 874
 */
static BOOL
875
HEADER_PrepareCallbackItems(const HEADER_INFO *infoPtr, INT iItem, INT reqMask)
876
{
877 878
    HEADER_ITEM *lpItem = &infoPtr->items[iItem];
    DWORD mask = reqMask & lpItem->callbackMask;
879
    NMHDDISPINFOW dispInfo;
880
    void *pvBuffer = NULL;
881

882 883 884
    if (mask == 0)
        return TRUE;
    if (mask&HDI_TEXT && lpItem->pszText != NULL)
885
    {
886 887 888
        ERR("(): function called without a call to FreeCallbackItems\n");
        Free(lpItem->pszText);
        lpItem->pszText = NULL;
889 890 891
    }
    
    memset(&dispInfo, 0, sizeof(NMHDDISPINFOW));
892 893
    dispInfo.hdr.hwndFrom = infoPtr->hwndSelf;
    dispInfo.hdr.idFrom   = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
894
    if (infoPtr->nNotifyFormat == NFR_UNICODE)
895 896
    {
        dispInfo.hdr.code = HDN_GETDISPINFOW;
897 898
        if (mask & HDI_TEXT)
            pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(WCHAR));
899 900 901 902
    }
    else
    {
        dispInfo.hdr.code = HDN_GETDISPINFOA;
903 904
        if (mask & HDI_TEXT)
            pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(CHAR));
905
    }
906
    dispInfo.pszText      = pvBuffer;
907
    dispInfo.cchTextMax   = (pvBuffer!=NULL?MAX_HEADER_TEXT_LEN:0);
908 909
    dispInfo.iItem        = iItem;
    dispInfo.mask         = mask;
910 911 912
    dispInfo.lParam       = lpItem->lParam;
    
    TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr->nNotifyFormat == NFR_UNICODE?'W':'A');
913
    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, dispInfo.hdr.idFrom, (LPARAM)&dispInfo);
914 915 916

    TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n", 
          dispInfo.mask,
917
          (infoPtr->nNotifyFormat == NFR_UNICODE ? debugstr_w(dispInfo.pszText) : (LPSTR) dispInfo.pszText),
918
          (void*) dispInfo.lParam);
919 920 921 922
          
    if (mask & HDI_IMAGE)
        lpItem->iImage = dispInfo.iImage;
    if (mask & HDI_TEXT)
923
    {
924
        if (infoPtr->nNotifyFormat == NFR_UNICODE)
925
        {
926
            lpItem->pszText = pvBuffer;
927 928 929 930

            /* the user might have used his own buffer */
            if (dispInfo.pszText != lpItem->pszText)
                Str_GetPtrW(dispInfo.pszText, lpItem->pszText, MAX_HEADER_TEXT_LEN);
931
        }
932
        else
933
        {
934 935
            Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)dispInfo.pszText);
            Free(pvBuffer);
936
        }
937
    }
938
        
939 940 941 942
    if (dispInfo.mask & HDI_DI_SETITEM) 
    {
        /* make the items permanent */
        lpItem->callbackMask &= ~dispInfo.mask;
943 944
    }
    
945 946 947 948 949 950 951 952 953 954 955 956 957 958
    return TRUE;
}

/***
 * DESCRIPTION:
 * Free the items that might be allocated with HEADER_PrepareCallbackItems
 *
 * PARAMETER(S):
 * [I] lpItem : the item to free the data
 *
 */
static void
HEADER_FreeCallbackItems(HEADER_ITEM *lpItem)
{
959
    if (lpItem->callbackMask&HDI_TEXT)
960
    {
961 962
        Free(lpItem->pszText);
        lpItem->pszText = NULL;
963
    }
964

965 966
    if (lpItem->callbackMask&HDI_IMAGE)
        lpItem->iImage = I_IMAGECALLBACK;
Alexandre Julliard's avatar
Alexandre Julliard committed
967 968 969
}

static LRESULT
970
HEADER_CreateDragImage (HEADER_INFO *infoPtr, INT iItem)
Alexandre Julliard's avatar
Alexandre Julliard committed
971
{
972 973 974
    HEADER_ITEM *lpItem;
    HIMAGELIST himl;
    HBITMAP hMemory, hOldBitmap;
975 976
    LRESULT lCDFlags;
    RECT rc;
977 978 979
    HDC hMemoryDC;
    HDC hDeviceDC;
    int height, width;
980
    HFONT hFont;
981
    
982
    if (iItem >= infoPtr->uNumItem)
983
        return FALSE;
984 985

    if (!infoPtr->bRectsValid)
986
        HEADER_SetItemBounds(infoPtr);
987

988
    lpItem = &infoPtr->items[iItem];
989 990 991 992 993 994 995 996 997
    width = lpItem->rect.right - lpItem->rect.left;
    height = lpItem->rect.bottom - lpItem->rect.top;
    
    hDeviceDC = GetDC(NULL);
    hMemoryDC = CreateCompatibleDC(hDeviceDC);
    hMemory = CreateCompatibleBitmap(hDeviceDC, width, height);
    ReleaseDC(NULL, hDeviceDC);
    hOldBitmap = SelectObject(hMemoryDC, hMemory);
    SetViewportOrgEx(hMemoryDC, -lpItem->rect.left, -lpItem->rect.top, NULL);
998 999
    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject(SYSTEM_FONT);
    SelectObject(hMemoryDC, hFont);
1000

1001 1002
    GetClientRect(infoPtr->hwndSelf, &rc);
    lCDFlags = HEADER_SendCtrlCustomDraw(infoPtr, CDDS_PREPAINT, hMemoryDC, &rc);
1003
    HEADER_DrawItem(infoPtr, hMemoryDC, iItem, FALSE, lCDFlags);
1004
    if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
1005
        HEADER_SendCtrlCustomDraw(infoPtr, CDDS_POSTPAINT, hMemoryDC, &rc);
1006
    
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    hMemory = SelectObject(hMemoryDC, hOldBitmap);
    DeleteDC(hMemoryDC);
    
    if (hMemory == NULL)    /* if anything failed */
        return FALSE;
    
    himl = ImageList_Create(width, height, ILC_COLORDDB, 1, 1);
    ImageList_Add(himl, hMemory, NULL);
    DeleteObject(hMemory);
    return (LRESULT)himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1017 1018
}

1019
static LRESULT
1020
HEADER_SetHotDivider(HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
{
    INT iDivider;
    RECT r;
    
    if (wParam)
    {
        POINT pt;
        UINT flags;
        pt.x = (INT)(SHORT)LOWORD(lParam);
        pt.y = 0;
1031
        HEADER_InternalHitTest (infoPtr, &pt, &flags, &iDivider);
1032 1033 1034 1035 1036 1037 1038 1039 1040
        
        if (flags & HHT_TOLEFT)
            iDivider = 0;
        else if (flags & HHT_NOWHERE || flags & HHT_TORIGHT)
            iDivider = infoPtr->uNumItem;
        else
        {
            HEADER_ITEM *lpItem = &infoPtr->items[iDivider];
            if (pt.x > (lpItem->rect.left+lpItem->rect.right)/2)
1041
                iDivider = HEADER_NextItem(infoPtr, iDivider);
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
        }
    }
    else
        iDivider = (INT)lParam;
        
    /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */
    if (iDivider<-1 || iDivider>(int)infoPtr->uNumItem)
        return iDivider;

    if (iDivider != infoPtr->iHotDivider)
    {
        if (infoPtr->iHotDivider != -1)
        {
1055 1056
            HEADER_GetHotDividerRect(infoPtr, &r);
            InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
1057 1058 1059 1060
        }
        infoPtr->iHotDivider = iDivider;
        if (iDivider != -1)
        {
1061 1062
            HEADER_GetHotDividerRect(infoPtr, &r);
            InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
1063 1064 1065 1066
        }
    }
    return iDivider;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1067 1068

static LRESULT
1069
HEADER_DeleteItem (HEADER_INFO *infoPtr, INT iItem)
Alexandre Julliard's avatar
Alexandre Julliard committed
1070
{
1071
    INT iOrder;
1072
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1073

1074
    TRACE("[iItem=%d]\n", iItem);
1075

1076
    if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
Alexandre Julliard's avatar
Alexandre Julliard committed
1077 1078
        return FALSE;

1079 1080
    for (i = 0; i < infoPtr->uNumItem; i++)
       TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
1081

1082
    iOrder = infoPtr->items[iItem].iOrder;
1083
    Free(infoPtr->items[iItem].pszText);
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099

    infoPtr->uNumItem--;
    memmove(&infoPtr->items[iItem], &infoPtr->items[iItem + 1],
            (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM));
    memmove(&infoPtr->order[iOrder], &infoPtr->order[iOrder + 1],
            (infoPtr->uNumItem - iOrder) * sizeof(INT));
    infoPtr->items = ReAlloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem);
    infoPtr->order = ReAlloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem);
        
    /* Correct the orders */
    for (i = 0; i < infoPtr->uNumItem; i++)
    {
        if (infoPtr->order[i] > iItem)
            infoPtr->order[i]--;
        if (i >= iOrder)
            infoPtr->items[infoPtr->order[i]].iOrder = i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1100
    }
1101 1102
    for (i = 0; i < infoPtr->uNumItem; i++)
       TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
Alexandre Julliard's avatar
Alexandre Julliard committed
1103

1104 1105
    HEADER_SetItemBounds (infoPtr);
    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
1106

Alexandre Julliard's avatar
Alexandre Julliard committed
1107 1108 1109 1110 1111
    return TRUE;
}


static LRESULT
1112
HEADER_GetImageList (const HEADER_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1113 1114 1115 1116 1117 1118
{
    return (LRESULT)infoPtr->himl;
}


static LRESULT
1119
HEADER_GetItemT (const HEADER_INFO *infoPtr, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
1120
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1121
    HEADER_ITEM *lpItem;
1122
    UINT mask;
Alexandre Julliard's avatar
Alexandre Julliard committed
1123

Alexandre Julliard's avatar
Alexandre Julliard committed
1124
    if (!phdi)
Alexandre Julliard's avatar
Alexandre Julliard committed
1125
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1126

1127
    TRACE("[nItem=%d]\n", nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1128

1129
    mask = phdi->mask;
1130
    if (mask == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1131
	return TRUE;
1132

1133
    if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1134 1135
        return FALSE;

1136 1137 1138 1139 1140 1141
    if (mask & HDI_UNKNOWN_FIELDS)
    {
        TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask);
        mask &= HDI_COMCTL32_4_0_FIELDS;
    }
    
1142
    lpItem = &infoPtr->items[nItem];
1143
    HEADER_PrepareCallbackItems(infoPtr, nItem, mask);
1144

1145
    if (mask & HDI_BITMAP)
1146
        phdi->hbm = lpItem->hbm;
Alexandre Julliard's avatar
Alexandre Julliard committed
1147

1148
    if (mask & HDI_FORMAT)
1149
        phdi->fmt = lpItem->fmt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1150

1151
    if (mask & HDI_WIDTH)
1152
        phdi->cxy = lpItem->cxy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1153

1154
    if (mask & HDI_LPARAM)
1155
        phdi->lParam = lpItem->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1156

1157
    if (mask & HDI_IMAGE) 
1158
        phdi->iImage = lpItem->iImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
1159

1160
    if (mask & HDI_ORDER)
1161
        phdi->iOrder = lpItem->iOrder;
Alexandre Julliard's avatar
Alexandre Julliard committed
1162

1163
    if (mask & HDI_TEXT)
1164
    {
1165 1166
        if (bUnicode)
            Str_GetPtrW (lpItem->pszText, phdi->pszText, phdi->cchTextMax);
1167
        else
1168
            Str_GetPtrWtoA (lpItem->pszText, (LPSTR)phdi->pszText, phdi->cchTextMax);
1169 1170
    }

1171
    HEADER_FreeCallbackItems(lpItem);
1172 1173 1174 1175
    return TRUE;
}


1176
static inline LRESULT
1177
HEADER_GetItemCount (const HEADER_INFO *infoPtr)
1178 1179
{
    return infoPtr->uNumItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1180 1181 1182 1183
}


static LRESULT
1184
HEADER_GetItemRect (const HEADER_INFO *infoPtr, INT iItem, LPRECT lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1185
{
1186
    if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
Alexandre Julliard's avatar
Alexandre Julliard committed
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
        return FALSE;

    lpRect->left   = infoPtr->items[iItem].rect.left;
    lpRect->right  = infoPtr->items[iItem].rect.right;
    lpRect->top    = infoPtr->items[iItem].rect.top;
    lpRect->bottom = infoPtr->items[iItem].rect.bottom;

    return TRUE;
}


1198
static LRESULT
1199
HEADER_GetOrderArray(const HEADER_INFO *infoPtr, INT size, LPINT order)
1200
{
1201
    if ((UINT)size <infoPtr->uNumItem)
1202
      return FALSE;
1203 1204

    memcpy(order, infoPtr->order, infoPtr->uNumItem * sizeof(INT));
1205 1206 1207
    return TRUE;
}

1208 1209
/* Returns index of first duplicate 'value' from [0,to) range,
   or -1 if there isn't any */
1210
static INT has_duplicate(const INT *array, INT to, INT value)
1211 1212 1213 1214 1215 1216 1217 1218
{
    INT i;
    for(i = 0; i < to; i++)
        if (array[i] == value) return i;
    return -1;
}

/* returns next available value from [0,max] not to duplicate in [0,to) */
1219
static INT get_nextvalue(const INT *array, INT to, INT max)
1220 1221 1222 1223 1224 1225 1226
{
    INT i;
    for(i = 0; i < max; i++)
        if (has_duplicate(array, to, i) == -1) return i;
    return 0;
}

1227
static LRESULT
1228
HEADER_SetOrderArray(HEADER_INFO *infoPtr, INT size, const INT *order)
1229 1230
{
    HEADER_ITEM *lpItem;
1231
    INT i;
1232

1233
    if ((UINT)size != infoPtr->uNumItem)
1234
      return FALSE;
1235

1236 1237 1238 1239 1240 1241 1242 1243
    if (TRACE_ON(header))
    {
        TRACE("count=%d, order array={", size);
        for (i = 0; i < size; i++)
            TRACE("%d%c", order[i], i != size-1 ? ',' : '}');
        TRACE("\n");
    }

1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
    for (i=0; i<size; i++)
    {
        if (order[i] >= size || order[i] < 0)
           /* on invalid index get next available */
           /* FIXME: if i==0 array item is out of range behaviour is
                     different, see tests */
           infoPtr->order[i] = get_nextvalue(infoPtr->order, i, size);
        else
        {
           INT j, dup;

           infoPtr->order[i] = order[i];
           j = i;
           /* remove duplicates */
           while ((dup = has_duplicate(infoPtr->order, j, order[j])) != -1)
           {
               INT next;

               next = get_nextvalue(infoPtr->order, j, size);
               infoPtr->order[dup] = next;
               j--;
           }
        }
    }
    /* sync with item data */
1269
    for (i=0; i<size; i++)
1270 1271 1272 1273
    {
        lpItem = &infoPtr->items[infoPtr->order[i]];
        lpItem->iOrder = i;
    }
1274
    HEADER_SetItemBounds(infoPtr);
1275
    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
1276 1277
    return TRUE;
}
1278

1279
static inline LRESULT
1280
HEADER_GetUnicodeFormat (const HEADER_INFO *infoPtr)
1281
{
1282
    return (infoPtr->nNotifyFormat == NFR_UNICODE);
1283 1284 1285
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1286
static LRESULT
1287
HEADER_HitTest (const HEADER_INFO *infoPtr, LPHDHITTESTINFO phti)
Alexandre Julliard's avatar
Alexandre Julliard committed
1288
{
1289 1290
    UINT outside = HHT_NOWHERE | HHT_ABOVE | HHT_BELOW | HHT_TOLEFT | HHT_TORIGHT;

1291
    HEADER_InternalHitTest (infoPtr, &phti->pt, &phti->flags, &phti->iItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1292

1293 1294
    if (phti->flags & outside)
	return phti->iItem = -1;
1295 1296
    else
        return phti->iItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1297 1298 1299 1300
}


static LRESULT
1301
HEADER_InsertItemT (HEADER_INFO *infoPtr, INT nItem, const HDITEMW *phdi, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
1302
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1303
    HEADER_ITEM *lpItem;
1304
    INT       iOrder;
1305
    UINT      i;
1306
    UINT      copyMask;
Alexandre Julliard's avatar
Alexandre Julliard committed
1307

1308
    if ((phdi == NULL) || (nItem < 0) || (phdi->mask == 0))
Alexandre Julliard's avatar
Alexandre Julliard committed
1309 1310 1311 1312
	return -1;

    if (nItem > infoPtr->uNumItem)
        nItem = infoPtr->uNumItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1313

1314
    iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem;
1315 1316 1317 1318
    if (iOrder < 0)
        iOrder = 0;
    else if (infoPtr->uNumItem < iOrder)
        iOrder = infoPtr->uNumItem;
1319

1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
    infoPtr->uNumItem++;
    infoPtr->items = ReAlloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem);
    infoPtr->order = ReAlloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem);
    
    /* make space for the new item */
    memmove(&infoPtr->items[nItem + 1], &infoPtr->items[nItem],
            (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM));
    memmove(&infoPtr->order[iOrder + 1], &infoPtr->order[iOrder],
           (infoPtr->uNumItem - iOrder - 1) * sizeof(INT));

    /* update the order array */
    infoPtr->order[iOrder] = nItem;
1332
    for (i = 0; i < infoPtr->uNumItem; i++)
1333
    {
1334 1335
        if (i != iOrder && infoPtr->order[i] >= nItem)
            infoPtr->order[i]++;
1336
        infoPtr->items[infoPtr->order[i]].iOrder = i;
1337 1338
    }

1339
    lpItem = &infoPtr->items[nItem];
1340
    ZeroMemory(lpItem, sizeof(HEADER_ITEM));
1341 1342 1343
    /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
    copyMask = phdi->mask | HDI_WIDTH | HDI_FORMAT | HDI_LPARAM;
    HEADER_StoreHDItemInHeader(lpItem, copyMask, phdi, bUnicode);
1344
    lpItem->iOrder = iOrder;
1345

1346
    /* set automatically some format bits */
1347 1348
    if (phdi->mask & HDI_TEXT)
        lpItem->fmt |= HDF_STRING;
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
    else
        lpItem->fmt &= ~HDF_STRING;

    if (lpItem->hbm != NULL)
        lpItem->fmt |= HDF_BITMAP;
    else
        lpItem->fmt &= ~HDF_BITMAP;

    if (phdi->mask & HDI_IMAGE)
        lpItem->fmt |= HDF_IMAGE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1359

1360 1361
    HEADER_SetItemBounds (infoPtr);
    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1362

Alexandre Julliard's avatar
Alexandre Julliard committed
1363
    return nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1364 1365 1366 1367
}


static LRESULT
1368
HEADER_Layout (HEADER_INFO *infoPtr, LPHDLAYOUT lpLayout)
Alexandre Julliard's avatar
Alexandre Julliard committed
1369
{
1370
    lpLayout->pwpos->hwnd = infoPtr->hwndSelf;
Alexandre Julliard's avatar
Alexandre Julliard committed
1371 1372 1373 1374
    lpLayout->pwpos->hwndInsertAfter = 0;
    lpLayout->pwpos->x = lpLayout->prc->left;
    lpLayout->pwpos->y = lpLayout->prc->top;
    lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
1375
    if (infoPtr->dwStyle & HDS_HIDDEN)
Alexandre Julliard's avatar
Alexandre Julliard committed
1376
        lpLayout->pwpos->cy = 0;
1377
    else {
Alexandre Julliard's avatar
Alexandre Julliard committed
1378
        lpLayout->pwpos->cy = infoPtr->nHeight;
1379 1380
        lpLayout->prc->top += infoPtr->nHeight;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1381
    lpLayout->pwpos->flags = SWP_NOZORDER;
Alexandre Julliard's avatar
Alexandre Julliard committed
1382

1383
    TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1384 1385 1386
           lpLayout->pwpos->x, lpLayout->pwpos->y,
           lpLayout->pwpos->cx, lpLayout->pwpos->cy);

1387
    infoPtr->bRectsValid = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1388 1389 1390 1391 1392 1393

    return TRUE;
}


static LRESULT
1394
HEADER_SetImageList (HEADER_INFO *infoPtr, HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1395 1396 1397
{
    HIMAGELIST himlOld;

Frank Richter's avatar
Frank Richter committed
1398
    TRACE("(himl %p)\n", himl);
Alexandre Julliard's avatar
Alexandre Julliard committed
1399
    himlOld = infoPtr->himl;
1400
    infoPtr->himl = himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1401 1402 1403 1404 1405 1406 1407

    /* FIXME: Refresh needed??? */

    return (LRESULT)himlOld;
}


1408
static LRESULT
1409
HEADER_GetBitmapMargin(const HEADER_INFO *infoPtr)
1410 1411 1412 1413 1414
{
    return infoPtr->iMargin;
}

static LRESULT
1415
HEADER_SetBitmapMargin(HEADER_INFO *infoPtr, INT iMargin)
1416 1417 1418
{
    INT oldMargin = infoPtr->iMargin;

1419
    infoPtr->iMargin = iMargin;
1420 1421 1422 1423

    return oldMargin;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1424
static LRESULT
1425
HEADER_SetItemT (HEADER_INFO *infoPtr, INT nItem, const HDITEMW *phdi, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
1426
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1427
    HEADER_ITEM *lpItem;
1428 1429
    HDITEMW hdNotify;
    void *pvScratch;
Alexandre Julliard's avatar
Alexandre Julliard committed
1430

Alexandre Julliard's avatar
Alexandre Julliard committed
1431 1432
    if (phdi == NULL)
	return FALSE;
1433
    if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
Alexandre Julliard's avatar
Alexandre Julliard committed
1434 1435
        return FALSE;

1436
    TRACE("[nItem=%d]\n", nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1437

1438
    HEADER_CopyHDItemForNotify(infoPtr, &hdNotify, phdi, bUnicode, &pvScratch);
1439
    if (HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCHANGINGW, nItem, &hdNotify))
1440
    {
1441
        Free(pvScratch);
Alexandre Julliard's avatar
Alexandre Julliard committed
1442
	return FALSE;
1443
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1444

1445
    lpItem = &infoPtr->items[nItem];
1446
    HEADER_StoreHDItemInHeader(lpItem, phdi->mask, phdi, bUnicode);
Alexandre Julliard's avatar
Alexandre Julliard committed
1447

Alexandre Julliard's avatar
Alexandre Julliard committed
1448
    if (phdi->mask & HDI_ORDER)
1449 1450
        if (phdi->iOrder >= 0 && phdi->iOrder < infoPtr->uNumItem)
            HEADER_ChangeItemOrder(infoPtr, nItem, phdi->iOrder);
Alexandre Julliard's avatar
Alexandre Julliard committed
1451

1452
    HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCHANGEDW, nItem, &hdNotify);
Alexandre Julliard's avatar
Alexandre Julliard committed
1453

1454
    HEADER_SetItemBounds (infoPtr);
1455

1456
    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1457

1458
    Free(pvScratch);
Alexandre Julliard's avatar
Alexandre Julliard committed
1459 1460 1461
    return TRUE;
}

1462
static inline LRESULT
1463
HEADER_SetUnicodeFormat (HEADER_INFO *infoPtr, WPARAM wParam)
1464
{
1465
    BOOL bTemp = (infoPtr->nNotifyFormat == NFR_UNICODE);
1466

1467
    infoPtr->nNotifyFormat = ((BOOL)wParam ? NFR_UNICODE : NFR_ANSI);
1468 1469 1470 1471 1472

    return bTemp;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1473
static LRESULT
1474
HEADER_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1475 1476
{
    HEADER_INFO *infoPtr;
1477
    TEXTMETRICW tm;
1478 1479
    HFONT hOldFont;
    HDC   hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1480

1481
    infoPtr = Alloc (sizeof(HEADER_INFO));
1482
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1483

1484
    infoPtr->hwndSelf = hwnd;
1485
    infoPtr->hwndNotify = lpcs->hwndParent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1486 1487 1488
    infoPtr->uNumItem = 0;
    infoPtr->hFont = 0;
    infoPtr->items = 0;
1489
    infoPtr->order = 0;
1490
    infoPtr->bRectsValid = FALSE;
1491 1492 1493
    infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
    infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER));
    infoPtr->hcurDivopen = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDEROPEN));
Alexandre Julliard's avatar
Alexandre Julliard committed
1494 1495
    infoPtr->bPressed  = FALSE;
    infoPtr->bTracking = FALSE;
1496
    infoPtr->dwStyle = lpcs->style;
Alexandre Julliard's avatar
Alexandre Julliard committed
1497 1498 1499
    infoPtr->iMoveItem = 0;
    infoPtr->himl = 0;
    infoPtr->iHotItem = -1;
1500
    infoPtr->iHotDivider = -1;
1501
    infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE);
1502
    infoPtr->nNotifyFormat =
1503
	SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1504

1505 1506
    hdc = GetDC (0);
    hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1507
    GetTextMetricsW (hdc, &tm);
Alexandre Julliard's avatar
Alexandre Julliard committed
1508
    infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1509 1510
    SelectObject (hdc, hOldFont);
    ReleaseDC (0, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1511

1512
    OpenThemeData(hwnd, themeClass);
1513

Alexandre Julliard's avatar
Alexandre Julliard committed
1514 1515 1516 1517 1518
    return 0;
}


static LRESULT
1519
HEADER_Destroy (HEADER_INFO *infoPtr)
1520
{
1521
    HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
1522 1523 1524 1525 1526
    CloseThemeData(theme);
    return 0;
}

static LRESULT
1527
HEADER_NCDestroy (HEADER_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1529
    HEADER_ITEM *lpItem;
1530
    INT nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1531 1532

    if (infoPtr->items) {
1533
        lpItem = infoPtr->items;
Alexandre Julliard's avatar
Alexandre Julliard committed
1534
        for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
1535
            Free(lpItem->pszText);
Alexandre Julliard's avatar
Alexandre Julliard committed
1536
        }
1537
        Free (infoPtr->items);
Alexandre Julliard's avatar
Alexandre Julliard committed
1538 1539
    }

1540
    Free(infoPtr->order);
1541

1542
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1543
    Free (infoPtr);
1544

Alexandre Julliard's avatar
Alexandre Julliard committed
1545 1546 1547 1548
    return 0;
}


Patrik Stridvall's avatar
Patrik Stridvall committed
1549
static inline LRESULT
1550
HEADER_GetFont (const HEADER_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1551 1552 1553 1554 1555
{
    return (LRESULT)infoPtr->hFont;
}


1556
static BOOL
1557
HEADER_IsDragDistance(const HEADER_INFO *infoPtr, const POINT *pt)
1558 1559 1560 1561 1562 1563 1564 1565
{
    /* Windows allows for a mouse movement before starting the drag. We use the
     * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance.
     */
    return (abs(infoPtr->ptLButtonDown.x - pt->x)>GetSystemMetrics(SM_CXDOUBLECLK) ||
            abs(infoPtr->ptLButtonDown.y - pt->y)>GetSystemMetrics(SM_CYDOUBLECLK));
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1566
static LRESULT
1567
HEADER_LButtonDblClk (const HEADER_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1568
{
1569 1570 1571
    POINT pt;
    UINT  flags;
    INT   nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1572

1573 1574
    pt.x = x;
    pt.y = y;
1575
    HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1576

1577
    if ((infoPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER))
1578
        HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMDBLCLICKW, nItem, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1579
    else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
1580
        HEADER_SendNotifyWithHDItemT(infoPtr, HDN_DIVIDERDBLCLICKW, nItem, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1581 1582 1583 1584 1585 1586

    return 0;
}


static LRESULT
1587
HEADER_LButtonDown (HEADER_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1588
{
1589 1590 1591 1592
    POINT pt;
    UINT  flags;
    INT   nItem;
    HDC   hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1593

1594 1595
    pt.x = x;
    pt.y = y;
1596
    HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1597

1598
    if ((infoPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
1599
	SetCapture (infoPtr->hwndSelf);
1600
	infoPtr->bCaptured = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1601
	infoPtr->bPressed  = TRUE;
1602
	infoPtr->bDragging = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1603
	infoPtr->iMoveItem = nItem;
1604
	infoPtr->ptLButtonDown = pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1605

Alexandre Julliard's avatar
Alexandre Julliard committed
1606
	infoPtr->items[nItem].bDown = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1607 1608

	/* Send WM_CUSTOMDRAW */
1609 1610 1611
	hdc = GetDC (infoPtr->hwndSelf);
	HEADER_RefreshItem (infoPtr, nItem);
	ReleaseDC (infoPtr->hwndSelf, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1612

1613
	TRACE("Pressed item %d!\n", nItem);
1614
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1615
    else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
1616
        INT iCurrWidth = infoPtr->items[nItem].cxy;
1617
        if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_BEGINTRACKW, nItem, HDI_WIDTH, iCurrWidth))
1618
        {
1619
	    SetCapture (infoPtr->hwndSelf);
1620
	    infoPtr->bCaptured = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1621
	    infoPtr->bTracking = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1622 1623
	    infoPtr->iMoveItem = nItem;
	    infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
Alexandre Julliard's avatar
Alexandre Julliard committed
1624

1625
	    if (!(infoPtr->dwStyle & HDS_FULLDRAG)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1626
		infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
1627 1628 1629
		hdc = GetDC (infoPtr->hwndSelf);
		HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
		ReleaseDC (infoPtr->hwndSelf, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1630 1631
	    }

1632
	    TRACE("Begin tracking item %d!\n", nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1633 1634 1635 1636 1637 1638 1639 1640
	}
    }

    return 0;
}


static LRESULT
1641
HEADER_LButtonUp (HEADER_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1642
{
1643 1644
    POINT pt;
    UINT  flags;
1645
    INT   nItem;
1646
    HDC   hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1647

1648 1649
    pt.x = x;
    pt.y = y;
1650
    HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1651 1652

    if (infoPtr->bPressed) {
1653 1654 1655

	infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;

1656 1657
	if (infoPtr->bDragging)
	{
1658 1659 1660
            HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
            INT iNewOrder;
            
1661 1662
	    ImageList_DragShowNolock(FALSE);
	    ImageList_EndDrag();
1663

1664 1665 1666 1667 1668
            if (infoPtr->iHotDivider == -1)
                iNewOrder = -1;
            else if (infoPtr->iHotDivider == infoPtr->uNumItem)
                iNewOrder = infoPtr->uNumItem-1;
            else
1669
	    {
1670
                iNewOrder = HEADER_IndexToOrder(infoPtr, infoPtr->iHotDivider);
1671 1672 1673
                if (iNewOrder > lpItem->iOrder)
                    iNewOrder--;
            }
1674

1675
            if (iNewOrder != -1 &&
1676
                !HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ENDDRAG, infoPtr->iMoveItem, HDI_ORDER, iNewOrder))
1677 1678
            {
                HEADER_ChangeItemOrder(infoPtr, infoPtr->iMoveItem, iNewOrder);
1679
		infoPtr->bRectsValid = FALSE;
1680
		InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
1681 1682
	    }
	    else
1683
		InvalidateRect(infoPtr->hwndSelf, &infoPtr->items[infoPtr->iMoveItem].rect, FALSE);
1684 1685

            infoPtr->bDragging = FALSE;
1686
            HEADER_SetHotDivider(infoPtr, FALSE, -1);
1687
	}
1688
	else
1689
	{
1690 1691 1692
	    hdc = GetDC (infoPtr->hwndSelf);
	    HEADER_RefreshItem (infoPtr, infoPtr->iMoveItem);
	    ReleaseDC (infoPtr->hwndSelf, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1693

1694 1695
	    if (!(infoPtr->dwStyle & HDS_DRAGDROP) || !HEADER_IsDragDistance(infoPtr, &pt))
		HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCLICKW, infoPtr->iMoveItem, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1696
	}
1697

1698
	TRACE("Released item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1699 1700 1701
	infoPtr->bPressed = FALSE;
    }
    else if (infoPtr->bTracking) {
1702 1703 1704
        INT iNewWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
        if (iNewWidth < 0)
	    iNewWidth = 0;
1705
	TRACE("End tracking item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1706 1707
	infoPtr->bTracking = FALSE;

1708
        HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ENDTRACKW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
Alexandre Julliard's avatar
Alexandre Julliard committed
1709

1710
        if (!(infoPtr->dwStyle & HDS_FULLDRAG)) {
1711 1712 1713
	    hdc = GetDC (infoPtr->hwndSelf);
	    HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
            ReleaseDC (infoPtr->hwndSelf, hdc);
1714 1715
        }
          
1716
        if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth))
1717
        {
1718
            infoPtr->items[infoPtr->iMoveItem].cxy = iNewWidth;
1719
            HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
1720
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1721

1722 1723
	HEADER_SetItemBounds (infoPtr);
	InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1724 1725 1726 1727 1728
    }

    if (infoPtr->bCaptured) {
	infoPtr->bCaptured = FALSE;
	ReleaseCapture ();
1729
	HEADER_SendSimpleNotify (infoPtr, NM_RELEASEDCAPTURE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1730 1731 1732 1733 1734 1735
    }

    return 0;
}


1736
static LRESULT
1737
HEADER_NotifyFormat (HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1738 1739 1740 1741 1742 1743 1744 1745
{
    switch (lParam)
    {
	case NF_QUERY:
	    return infoPtr->nNotifyFormat;

	case NF_REQUERY:
	    infoPtr->nNotifyFormat =
1746
		SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT,
1747
                             (WPARAM)infoPtr->hwndSelf, NF_QUERY);
1748 1749 1750 1751 1752 1753
	    return infoPtr->nNotifyFormat;
    }

    return 0;
}

1754
static LRESULT
1755
HEADER_MouseLeave (HEADER_INFO *infoPtr)
1756 1757 1758
{
    /* Reset hot-tracked item when mouse leaves control. */
    INT oldHotItem = infoPtr->iHotItem;
1759
    HDC hdc = GetDC (infoPtr->hwndSelf);
1760 1761

    infoPtr->iHotItem = -1;
1762 1763
    if (oldHotItem != -1) HEADER_RefreshItem (infoPtr, oldHotItem);
    ReleaseDC (infoPtr->hwndSelf, hdc);
1764 1765 1766 1767 1768

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1769
static LRESULT
1770
HEADER_MouseMove (HEADER_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1771
{
1772 1773 1774 1775
    POINT pt;
    UINT  flags;
    INT   nItem, nWidth;
    HDC   hdc;
1776 1777
    /* With theming, hottracking is always enabled */
    BOOL  hotTrackEnabled =
1778
        ((infoPtr->dwStyle & HDS_BUTTONS) && (infoPtr->dwStyle & HDS_HOTTRACK))
1779
        || (GetWindowTheme (infoPtr->hwndSelf) != NULL);
1780
    INT oldHotItem = infoPtr->iHotItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1781

1782 1783
    pt.x = (INT)(SHORT)LOWORD(lParam);
    pt.y = (INT)(SHORT)HIWORD(lParam);
1784
    HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1785

1786
    if (hotTrackEnabled) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1787
	if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1788
	    infoPtr->iHotItem = nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1789 1790 1791 1792 1793
	else
	    infoPtr->iHotItem = -1;
    }

    if (infoPtr->bCaptured) {
1794
        /* check if we should drag the header */
1795
	if (infoPtr->bPressed && !infoPtr->bDragging && (infoPtr->dwStyle & HDS_DRAGDROP)
1796 1797
	    && HEADER_IsDragDistance(infoPtr, &pt))
	{
1798
            if (!HEADER_SendNotifyWithHDItemT(infoPtr, HDN_BEGINDRAG, infoPtr->iMoveItem, NULL))
1799
	    {
1800
		HIMAGELIST hDragItem = (HIMAGELIST)HEADER_CreateDragImage(infoPtr, infoPtr->iMoveItem);
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817
		if (hDragItem != NULL)
		{
		    HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
		    TRACE("Starting item drag\n");
		    ImageList_BeginDrag(hDragItem, 0, pt.x - lpItem->rect.left, 0);
		    ImageList_DragShowNolock(TRUE);
		    ImageList_Destroy(hDragItem);
		    infoPtr->bDragging = TRUE;
		}
	    }
	}
	
	if (infoPtr->bDragging)
	{
	    POINT drag;
	    drag.x = pt.x;
	    drag.y = 0;
1818
	    ClientToScreen(infoPtr->hwndSelf, &drag);
1819
	    ImageList_DragMove(drag.x, drag.y);
1820
	    HEADER_SetHotDivider(infoPtr, TRUE, lParam);
1821 1822 1823
	}
	
	if (infoPtr->bPressed && !infoPtr->bDragging) {
1824
            BOOL oldState = infoPtr->items[infoPtr->iMoveItem].bDown;
Alexandre Julliard's avatar
Alexandre Julliard committed
1825
	    if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
Alexandre Julliard's avatar
Alexandre Julliard committed
1826 1827 1828
		infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
	    else
		infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1829
            if (oldState != infoPtr->items[infoPtr->iMoveItem].bDown) {
1830 1831 1832
                hdc = GetDC (infoPtr->hwndSelf);
	        HEADER_RefreshItem (infoPtr, infoPtr->iMoveItem);
	        ReleaseDC (infoPtr->hwndSelf, hdc);
1833
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1834

1835
	    TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1836 1837
	}
	else if (infoPtr->bTracking) {
1838
	    if (infoPtr->dwStyle & HDS_FULLDRAG) {
1839 1840
                HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
                nWidth = pt.x - lpItem->rect.left + infoPtr->xTrackOffset;
1841
                if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, nWidth))
1842
		{
1843 1844 1845 1846 1847 1848
                    INT nOldWidth = lpItem->rect.right - lpItem->rect.left;
                    RECT rcClient;
                    RECT rcScroll;
                    
                    if (nWidth < 0) nWidth = 0;
                    infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1849
                    HEADER_SetItemBounds(infoPtr);
1850
                    
1851
                    GetClientRect(infoPtr->hwndSelf, &rcClient);
1852 1853
                    rcScroll = rcClient;
                    rcScroll.left = lpItem->rect.left + nOldWidth;
1854 1855 1856
                    ScrollWindowEx(infoPtr->hwndSelf, nWidth - nOldWidth, 0, &rcScroll, &rcClient, NULL, NULL, 0);
                    InvalidateRect(infoPtr->hwndSelf, &lpItem->rect, FALSE);
                    UpdateWindow(infoPtr->hwndSelf);
1857
                    
1858
                    HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, nWidth);
1859
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
1860 1861
	    }
	    else {
1862
                INT iTrackWidth;
1863 1864
		hdc = GetDC (infoPtr->hwndSelf);
		HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
Alexandre Julliard's avatar
Alexandre Julliard committed
1865 1866 1867
		infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
		if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
		    infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
1868 1869
		HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
		ReleaseDC (infoPtr->hwndSelf, hdc);
1870
                iTrackWidth = infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
1871
                /* FIXME: should stop tracking if HDN_TRACK returns TRUE */
1872
                HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_TRACKW, infoPtr->iMoveItem, HDI_WIDTH, iTrackWidth);
Alexandre Julliard's avatar
Alexandre Julliard committed
1873 1874
	    }

1875
	    TRACE("Tracking item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1876 1877 1878
	}
    }

1879 1880
    if (hotTrackEnabled) {
        TRACKMOUSEEVENT tme;
1881
        if (oldHotItem != infoPtr->iHotItem && !infoPtr->bDragging) {
1882 1883 1884 1885
	    hdc = GetDC (infoPtr->hwndSelf);
	    if (oldHotItem != -1) HEADER_RefreshItem (infoPtr, oldHotItem);
	    if (infoPtr->iHotItem != -1) HEADER_RefreshItem (infoPtr, infoPtr->iHotItem);
	    ReleaseDC (infoPtr->hwndSelf, hdc);
1886 1887 1888
        }
        tme.cbSize = sizeof( tme );
        tme.dwFlags = TME_LEAVE;
1889
        tme.hwndTrack = infoPtr->hwndSelf;
1890
        TrackMouseEvent( &tme );
Alexandre Julliard's avatar
Alexandre Julliard committed
1891 1892 1893 1894 1895 1896 1897
    }

    return 0;
}


static LRESULT
1898
HEADER_Paint (HEADER_INFO *infoPtr, HDC hdcParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1899
{
1900 1901
    HDC hdc;
    PAINTSTRUCT ps;
Alexandre Julliard's avatar
Alexandre Julliard committed
1902

1903
    hdc = hdcParam==0 ? BeginPaint (infoPtr->hwndSelf, &ps) : hdcParam;
1904
    HEADER_Refresh (infoPtr, hdc);
1905
    if(!hdcParam)
1906
	EndPaint (infoPtr->hwndSelf, &ps);
Alexandre Julliard's avatar
Alexandre Julliard committed
1907 1908 1909 1910 1911
    return 0;
}


static LRESULT
1912
HEADER_RButtonUp (HEADER_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1913
{
1914 1915 1916
    BOOL bRet;
    POINT pt;

1917 1918
    pt.x = x;
    pt.y = y;
1919 1920

    /* Send a Notify message */
1921
    bRet = HEADER_SendSimpleNotify (infoPtr, NM_RCLICK);
1922 1923

    /* Change to screen coordinate for WM_CONTEXTMENU */
1924
    ClientToScreen(infoPtr->hwndSelf, &pt);
1925 1926

    /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1927
    SendMessageW( infoPtr->hwndSelf, WM_CONTEXTMENU, (WPARAM) infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y));
1928

1929
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
1930 1931 1932 1933
}


static LRESULT
1934
HEADER_SetCursor (HEADER_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1935
{
1936 1937 1938
    POINT pt;
    UINT  flags;
    INT   nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1939

1940
    TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1941

1942
    GetCursorPos (&pt);
1943
    ScreenToClient (infoPtr->hwndSelf, &pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1944

1945
    HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1946 1947

    if (flags == HHT_ONDIVIDER)
1948
        SetCursor (infoPtr->hcurDivider);
Alexandre Julliard's avatar
Alexandre Julliard committed
1949
    else if (flags == HHT_ONDIVOPEN)
1950
        SetCursor (infoPtr->hcurDivopen);
Alexandre Julliard's avatar
Alexandre Julliard committed
1951
    else
1952
        SetCursor (infoPtr->hcurArrow);
Alexandre Julliard's avatar
Alexandre Julliard committed
1953 1954 1955 1956 1957 1958

    return 0;
}


static LRESULT
1959
HEADER_SetFont (HEADER_INFO *infoPtr, HFONT hFont, WORD Redraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1960
{
1961
    TEXTMETRICW tm;
1962
    HFONT hOldFont;
1963
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1964

1965
    infoPtr->hFont = hFont;
Alexandre Julliard's avatar
Alexandre Julliard committed
1966

1967
    hdc = GetDC (0);
1968
    hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT));
1969
    GetTextMetricsW (hdc, &tm);
Alexandre Julliard's avatar
Alexandre Julliard committed
1970
    infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1971 1972
    SelectObject (hdc, hOldFont);
    ReleaseDC (0, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1973

1974
    infoPtr->bRectsValid = FALSE;
1975

1976
    if (Redraw) {
1977
        InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1978 1979 1980 1981 1982
    }

    return 0;
}

1983
static LRESULT HEADER_SetRedraw(HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1984 1985 1986 1987 1988
{
    /* ignoring the InvalidateRect calls is handled by user32. But some apps expect
     * that we invalidate the header and this has to be done manually  */
    LRESULT ret;

1989
    ret = DefWindowProcW(infoPtr->hwndSelf, WM_SETREDRAW, wParam, lParam);
1990
    if (wParam)
1991
        InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
1992 1993 1994
    return ret;
}

1995
static INT HEADER_StyleChanged(HEADER_INFO *infoPtr, WPARAM wStyleType,
1996
                               const STYLESTRUCT *lpss)
1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
{
    TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
          wStyleType, lpss->styleOld, lpss->styleNew);

    if (wStyleType != GWL_STYLE) return 0;

    infoPtr->dwStyle = lpss->styleNew;

    return 0;
}

2008
/* Update the theme handle after a theme change */
2009
static LRESULT HEADER_ThemeChanged(const HEADER_INFO *infoPtr)
2010
{
2011
    HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
2012
    CloseThemeData(theme);
2013 2014
    OpenThemeData(infoPtr->hwndSelf, themeClass);
    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2015 2016 2017
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2018

2019
static LRESULT WINAPI
2020
HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2021
{
2022 2023
    HEADER_INFO *infoPtr = (HEADER_INFO *)GetWindowLongPtrW(hwnd, 0);

2024
    TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, msg, wParam, lParam);
2025
    if (!infoPtr && (msg != WM_CREATE))
2026
	return DefWindowProcW (hwnd, msg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2027
    switch (msg) {
2028 2029
/*	case HDM_CLEARFILTER: */

Alexandre Julliard's avatar
Alexandre Julliard committed
2030
	case HDM_CREATEDRAGIMAGE:
2031
	    return HEADER_CreateDragImage (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2032 2033

	case HDM_DELETEITEM:
2034
	    return HEADER_DeleteItem (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2035

2036 2037
/*	case HDM_EDITFILTER: */

2038
	case HDM_GETBITMAPMARGIN:
2039
	    return HEADER_GetBitmapMargin(infoPtr);
2040

Alexandre Julliard's avatar
Alexandre Julliard committed
2041
	case HDM_GETIMAGELIST:
2042
	    return HEADER_GetImageList (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2043

2044 2045
	case HDM_GETITEMA:
	case HDM_GETITEMW:
2046
	    return HEADER_GetItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_GETITEMW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2047

Alexandre Julliard's avatar
Alexandre Julliard committed
2048
	case HDM_GETITEMCOUNT:
2049
	    return HEADER_GetItemCount (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2050 2051

	case HDM_GETITEMRECT:
2052
	    return HEADER_GetItemRect (infoPtr, (INT)wParam, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2053

2054
	case HDM_GETORDERARRAY:
2055
	    return HEADER_GetOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
2056

2057
	case HDM_GETUNICODEFORMAT:
2058
	    return HEADER_GetUnicodeFormat (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2059

Alexandre Julliard's avatar
Alexandre Julliard committed
2060
	case HDM_HITTEST:
2061
	    return HEADER_HitTest (infoPtr, (LPHDHITTESTINFO)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2062

2063 2064
	case HDM_INSERTITEMA:
	case HDM_INSERTITEMW:
2065
	    return HEADER_InsertItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_INSERTITEMW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2066

Alexandre Julliard's avatar
Alexandre Julliard committed
2067
	case HDM_LAYOUT:
2068
	    return HEADER_Layout (infoPtr, (LPHDLAYOUT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2069

2070
	case HDM_ORDERTOINDEX:
2071
	    return HEADER_OrderToIndex(infoPtr, (INT)wParam);
2072

2073
	case HDM_SETBITMAPMARGIN:
2074
	    return HEADER_SetBitmapMargin(infoPtr, (INT)wParam);
2075 2076 2077

/*	case HDM_SETFILTERCHANGETIMEOUT: */

2078
        case HDM_SETHOTDIVIDER:
2079
            return HEADER_SetHotDivider(infoPtr, wParam, lParam);
2080

Alexandre Julliard's avatar
Alexandre Julliard committed
2081
	case HDM_SETIMAGELIST:
2082
	    return HEADER_SetImageList (infoPtr, (HIMAGELIST)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2083

2084 2085
	case HDM_SETITEMA:
	case HDM_SETITEMW:
2086
	    return HEADER_SetItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_SETITEMW);
2087

2088
	case HDM_SETORDERARRAY:
2089
	    return HEADER_SetOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
2090

2091
	case HDM_SETUNICODEFORMAT:
2092
	    return HEADER_SetUnicodeFormat (infoPtr, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2093

Alexandre Julliard's avatar
Alexandre Julliard committed
2094
        case WM_CREATE:
2095
            return HEADER_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2096 2097

        case WM_DESTROY:
2098
            return HEADER_Destroy (infoPtr);
2099 2100

        case WM_NCDESTROY:
2101
            return HEADER_NCDestroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2102 2103 2104 2105 2106 2107 2108 2109

        case WM_ERASEBKGND:
            return 1;

        case WM_GETDLGCODE:
            return DLGC_WANTTAB | DLGC_WANTARROWS;

        case WM_GETFONT:
2110
            return HEADER_GetFont (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2111 2112

        case WM_LBUTTONDBLCLK:
2113
            return HEADER_LButtonDblClk (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2114 2115

        case WM_LBUTTONDOWN:
2116
            return HEADER_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2117 2118

        case WM_LBUTTONUP:
2119
            return HEADER_LButtonUp (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2120

2121
        case WM_MOUSELEAVE:
2122
            return HEADER_MouseLeave (infoPtr);
2123

Alexandre Julliard's avatar
Alexandre Julliard committed
2124
        case WM_MOUSEMOVE:
2125
            return HEADER_MouseMove (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2126

2127
	case WM_NOTIFYFORMAT:
2128
            return HEADER_NotifyFormat (infoPtr, wParam, lParam);
2129

2130
	case WM_SIZE:
2131
	    return HEADER_Size (infoPtr);
2132

2133
        case WM_THEMECHANGED:
2134
            return HEADER_ThemeChanged (infoPtr);
2135

2136
        case WM_PRINTCLIENT:
Alexandre Julliard's avatar
Alexandre Julliard committed
2137
        case WM_PAINT:
2138
            return HEADER_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2139 2140

        case WM_RBUTTONUP:
2141
            return HEADER_RButtonUp (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2142 2143

        case WM_SETCURSOR:
2144
            return HEADER_SetCursor (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2145 2146

        case WM_SETFONT:
2147
            return HEADER_SetFont (infoPtr, (HFONT)wParam, (WORD)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2148

2149
        case WM_SETREDRAW:
2150
            return HEADER_SetRedraw(infoPtr, wParam, lParam);
2151

2152 2153 2154
        case WM_STYLECHANGED:
            return HEADER_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);

2155 2156 2157 2158
        case WM_SYSCOLORCHANGE:
            COMCTL32_RefreshSysColors();
            return 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
2159
        default:
2160
            if ((msg >= WM_USER) && (msg < WM_APP) && !COMCTL32_IsReflectedMessage(msg))
2161
		ERR("unknown msg %04x wp=%04lx lp=%08lx\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2162
		     msg, wParam, lParam );
2163
	    return DefWindowProcW(hwnd, msg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2164 2165 2166 2167
    }
}


2168
VOID
2169
HEADER_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2170
{
2171
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2172

2173
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
2174
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
2175
    wndClass.lpfnWndProc   = HEADER_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2176 2177
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
2178 2179
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
    wndClass.lpszClassName = WC_HEADERW;
2180

2181
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
2182 2183
}

2184 2185

VOID
2186
HEADER_Unregister (void)
2187
{
2188
    UnregisterClassW (WC_HEADERW, NULL);
2189
}