header.c 60.2 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 "imagelist.h"
43 44
#include "tmschema.h"
#include "uxtheme.h"
45
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
46

47
WINE_DEFAULT_DEBUG_CHANNEL(header);
48

49
typedef struct
50 51 52 53 54 55 56 57 58 59 60
{
    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 */
61
    DWORD   callbackMask;       /* HDI_* flags for items that are callback */
62 63 64 65 66
} HEADER_ITEM;


typedef struct
{
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 81 82
    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 */
83
    INT       iHotItem;		/* index of hot item (cursor is over this item) */
84
    INT       iHotDivider;      /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
85
    INT       iMargin;          /* width of the margin that surrounds a bitmap */
86

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

Alexandre Julliard's avatar
Alexandre Julliard committed
93

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

101 102 103 104 105
#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)

106
#define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0))
Alexandre Julliard's avatar
Alexandre Julliard committed
107

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

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

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

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

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

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

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

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

147 148
        if (phdi->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */
        {
149
            LPWSTR pszText = (phdi->pszText != NULL ? phdi->pszText : emptyString);
150 151 152 153
            if (fUnicode)
                Str_SetPtrW(&lpItem->pszText, pszText);
            else
                Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)pszText);
154
            lpItem->callbackMask &= ~HDI_TEXT;
155 156 157
        }
        else
        {
158 159
            lpItem->pszText = NULL;
            lpItem->callbackMask |= HDI_TEXT;
160 161 162 163
        }  
    }
}

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


173
static INT
174 175 176
HEADER_OrderToIndex(HWND hwnd, WPARAM wParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
177
    INT iorder = (INT)wParam;
178

179
    if ((iorder <0) || iorder >= infoPtr->uNumItem)
180
      return iorder;
181
    return infoPtr->order[iorder];
182 183
}

184
static void
185
HEADER_ChangeItemOrder(const HEADER_INFO *infoPtr, INT iItem, INT iNewOrder)
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
{
    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;
}

210 211 212 213 214 215 216
/* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
static INT
HEADER_NextItem(HWND hwnd, INT iItem)
{
    return HEADER_OrderToIndex(hwnd, HEADER_IndexToOrder(hwnd, iItem)+1);
}

217 218 219 220 221 222
static INT
HEADER_PrevItem(HWND hwnd, INT iItem)
{
    return HEADER_OrderToIndex(hwnd, HEADER_IndexToOrder(hwnd, iItem)-1);
}

223 224 225 226 227 228
static void
HEADER_SetItemBounds (HWND hwnd)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
    HEADER_ITEM *phdi;
    RECT rect;
229 230
    unsigned int i;
    int x;
231 232 233 234 235 236 237 238 239 240

    infoPtr->bRectsValid = TRUE;

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

    GetClientRect (hwnd, &rect);

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

static LRESULT
HEADER_Size (HWND hwnd, WPARAM wParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);

    infoPtr->bRectsValid = FALSE;

    return 0;
}

260
static void HEADER_GetHotDividerRect(HWND hwnd, const HEADER_INFO *infoPtr, RECT *r)
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
{
    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
        {
            lpItem = &infoPtr->items[HEADER_OrderToIndex(hwnd, infoPtr->uNumItem-1)];
            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;
        GetClientRect(hwnd, &clientRect);
        *r = clientRect;
        r->right = r->left + HOT_DIVIDER_WIDTH/2;
    }
}

291

292
static INT
293
HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack, LRESULT lCDFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
294
{
295
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
296
    HEADER_ITEM *phdi = &infoPtr->items[iItem];
297
    RECT r;
298
    INT  oldBkMode;
299
    HTHEME theme = GetWindowTheme (hwnd);
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 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
    SetTextColor(hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
    SetBkColor(hdc, GetSysColor(COLOR_3DFACE));

    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;

        lCDItemFlags = HEADER_SendNotify(hwnd, NM_CUSTOMDRAW, (NMHDR *)&nmcd);
        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 338
        HBRUSH hbr;
    
339 340 341 342 343 344 345 346 347 348 349
        if (GetWindowLongW (hwnd, GWL_STYLE) & 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);
        }
        else
            DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
350 351 352 353

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

    if (phdi->fmt & HDF_OWNERDRAW) {
361
	DRAWITEMSTRUCT dis;
362

Alexandre Julliard's avatar
Alexandre Julliard committed
363
	dis.CtlType    = ODT_HEADER;
364
	dis.CtlID      = GetWindowLongPtrW (hwnd, GWLP_ID);
Alexandre Julliard's avatar
Alexandre Julliard committed
365 366 367
	dis.itemID     = iItem;
	dis.itemAction = ODA_DRAWENTIRE;
	dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
368
	dis.hwndItem   = hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
369
	dis.hDC        = hdc;
370
	dis.rcItem     = phdi->rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
371
	dis.itemData   = phdi->lParam;
372
        oldBkMode = SetBkMode(hdc, TRANSPARENT);
373
	SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM,
374
			(WPARAM)dis.CtlID, (LPARAM)&dis);
375 376
        if (oldBkMode != TRANSPARENT)
            SetBkMode(hdc, oldBkMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
377 378
    }
    else {
379 380 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;
	BITMAP bmp;

386
        HEADER_PrepareCallbackItems(hwnd, iItem, HDI_TEXT|HDI_IMAGE);
387 388 389 390 391 392
	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
393

394
            SetRectEmpty(&textRect);
395 396 397 398
	    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
399

400 401 402 403 404
	if ((phdi->fmt & HDF_IMAGE) && (infoPtr->himl)) {
	    iw = infoPtr->himl->cx + 2 * infoPtr->iMargin;
	    x = &ix;
	    w = &iw;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
405

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

415 416 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
	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
445 446 447
	    }
	}

448 449 450 451 452 453 454
	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;
455
	    else
456 457
	        bx = cx + cw + infoPtr->iMargin;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
458

459 460 461 462 463 464 465 466 467 468 469
	if (iw || bw) {
	    HDC hClipDC = GetDC(hwnd);
	    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
470 471
	    }

472 473 474 475
	    if (iw) {
	        ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, 
	                          ix, r.top + ((INT)rh - infoPtr->himl->cy) / 2,
	                          infoPtr->himl->cx, infoPtr->himl->cy, CLR_DEFAULT, CLR_DEFAULT, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
476 477
	    }

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

Alexandre Julliard's avatar
Alexandre Julliard committed
497 498 499
    return phdi->rect.right;
}

500 501 502 503 504 505 506 507 508 509 510 511
static void
HEADER_DrawHotDivider(HWND hwnd, HDC hdc)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
    HBRUSH brush;
    RECT r;
    
    HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
    brush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
    FillRect(hdc, &r, brush);
    DeleteObject(brush);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
512

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

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

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

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

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

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

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

    if (infoPtr->bDragging)
	ImageList_DragShowNolock(TRUE);
571
    SelectObject (hdc, hOldFont);
572 573 574
    
    if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
        HEADER_SendCtrlCustomDraw(hwnd, CDDS_POSTPAINT, hdc, &rect);
Alexandre Julliard's avatar
Alexandre Julliard committed
575 576 577 578
}


static void
579
HEADER_RefreshItem (HWND hwnd, HDC hdc, INT iItem)
Alexandre Julliard's avatar
Alexandre Julliard committed
580
{
581
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
582

583 584 585 586
    if (!infoPtr->bRectsValid)
        HEADER_SetItemBounds(hwnd);

    InvalidateRect(hwnd, &infoPtr->items[iItem].rect, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
587 588 589 590
}


static void
591
HEADER_InternalHitTest (HWND hwnd, const POINT *lpPt, UINT *pFlags, INT *pItem)
Alexandre Julliard's avatar
Alexandre Julliard committed
592
{
593
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
594
    RECT rect, rcTest;
595 596
    UINT iCount;
    INT width;
597
    BOOL bNoWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
598

599
    GetClientRect (hwnd, &rect);
Alexandre Julliard's avatar
Alexandre Julliard committed
600 601 602

    *pFlags = 0;
    bNoWidth = FALSE;
603
    if (PtInRect (&rect, *lpPt))
Alexandre Julliard's avatar
Alexandre Julliard committed
604 605 606 607
    {
	if (infoPtr->uNumItem == 0) {
	    *pFlags |= HHT_NOWHERE;
	    *pItem = 1;
608
	    TRACE("NOWHERE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
609 610 611 612 613 614 615 616 617 618 619
	    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;
		}
620
		if (PtInRect (&rect, *lpPt)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
621 622 623
		    if (width <= 2 * DIVIDER_WIDTH) {
			*pFlags |= HHT_ONHEADER;
			*pItem = iCount;
624
			TRACE("ON HEADER %d\n", iCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
625 626
			return;
		    }
627
                    if (HEADER_IndexToOrder(hwnd, iCount) > 0) {
Alexandre Julliard's avatar
Alexandre Julliard committed
628 629
			rcTest = rect;
			rcTest.right = rcTest.left + DIVIDER_WIDTH;
630
			if (PtInRect (&rcTest, *lpPt)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
631 632
			    if (bNoWidth) {
				*pFlags |= HHT_ONDIVOPEN;
633
                                *pItem = HEADER_PrevItem(hwnd, iCount);
634
				TRACE("ON DIVOPEN %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
635 636 637 638
				return;
			    }
			    else {
				*pFlags |= HHT_ONDIVIDER;
639
                                *pItem = HEADER_PrevItem(hwnd, iCount);
640
				TRACE("ON DIVIDER %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
641 642 643 644 645 646
				return;
			    }
			}
		    }
		    rcTest = rect;
		    rcTest.left = rcTest.right - DIVIDER_WIDTH;
647
		    if (PtInRect (&rcTest, *lpPt)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
648 649
			*pFlags |= HHT_ONDIVIDER;
			*pItem = iCount;
650
			TRACE("ON DIVIDER %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
651 652 653 654 655
			return;
		    }

		    *pFlags |= HHT_ONHEADER;
		    *pItem = iCount;
656
		    TRACE("ON HEADER %d\n", iCount);
Alexandre Julliard's avatar
Alexandre Julliard committed
657 658 659 660 661 662 663 664
		    return;
		}
	    }

	    /* check for last divider part (on nowhere) */
	    rect = infoPtr->items[infoPtr->uNumItem-1].rect;
	    rect.left = rect.right;
	    rect.right += DIVIDER_WIDTH;
665
	    if (PtInRect (&rect, *lpPt)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
666 667 668
		if (bNoWidth) {
		    *pFlags |= HHT_ONDIVOPEN;
		    *pItem = infoPtr->uNumItem - 1;
669
		    TRACE("ON DIVOPEN %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
670 671 672 673 674
		    return;
		}
		else {
		    *pFlags |= HHT_ONDIVIDER;
		    *pItem = infoPtr->uNumItem-1;
675
		    TRACE("ON DIVIDER %d\n", *pItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
676 677 678 679 680 681
		    return;
		}
	    }

	    *pFlags |= HHT_NOWHERE;
	    *pItem = 1;
682
	    TRACE("NOWHERE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
683 684 685 686 687
	    return;
	}
    }
    else {
	if (lpPt->x < rect.left) {
688
	   TRACE("TO LEFT\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
689 690 691
	   *pFlags |= HHT_TOLEFT;
	}
	else if (lpPt->x > rect.right) {
Thuy Nguyen's avatar
Thuy Nguyen committed
692
	    TRACE("TO RIGHT\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
693 694 695 696
	    *pFlags |= HHT_TORIGHT;
	}

	if (lpPt->y < rect.top) {
697
	    TRACE("ABOVE\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
698 699 700
	    *pFlags |= HHT_ABOVE;
	}
	else if (lpPt->y > rect.bottom) {
701
	    TRACE("BELOW\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
702 703 704 705 706
	    *pFlags |= HHT_BELOW;
	}
    }

    *pItem = 1;
707
    TRACE("flags=0x%X\n", *pFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
708 709 710 711 712
    return;
}


static void
713
HEADER_DrawTrackLine (HWND hwnd, HDC hdc, INT x)
Alexandre Julliard's avatar
Alexandre Julliard committed
714
{
715 716 717 718
    RECT rect;
    HPEN hOldPen;
    INT  oldRop;

719
    GetClientRect (hwnd, &rect);
720 721 722 723 724 725 726

    hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN));
    oldRop = SetROP2 (hdc, R2_XORPEN);
    MoveToEx (hdc, x, rect.top, NULL);
    LineTo (hdc, x, rect.bottom);
    SetROP2 (hdc, oldRop);
    SelectObject (hdc, hOldPen);
Alexandre Julliard's avatar
Alexandre Julliard committed
727 728
}

729 730 731 732 733 734 735 736 737 738 739 740 741 742
/***
 * 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
 */
743 744
static void HEADER_CopyHDItemForNotify(const HEADER_INFO *infoPtr, HDITEMW *dest,
    const HDITEMW *src, BOOL fSourceUnicode, LPVOID *ppvScratch)
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
{
    *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;
        }
    }
}

767 768 769 770 771 772 773 774
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
775

776 777 778 779 780 781 782 783 784 785 786 787 788
static LRESULT
HEADER_SendNotify(HWND hwnd, UINT code, NMHDR *nmhdr)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);

    nmhdr->hwndFrom = hwnd;
    nmhdr->idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
    nmhdr->code     = code;

    return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
				   (WPARAM)nmhdr->idFrom, (LPARAM)nmhdr);
}

789
static BOOL
790
HEADER_SendSimpleNotify (HWND hwnd, UINT code)
Alexandre Julliard's avatar
Alexandre Julliard committed
791 792
{
    NMHDR nmhdr;
793 794
    return (BOOL)HEADER_SendNotify(hwnd, code, &nmhdr);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
795

796
static LRESULT
797
HEADER_SendCtrlCustomDraw(HWND hwnd, DWORD dwDrawStage, HDC hdc, const RECT *rect)
798 799 800 801 802 803 804 805 806 807
{
    NMCUSTOMDRAW nm;
    nm.dwDrawStage = dwDrawStage;
    nm.hdc = hdc;
    nm.rc = *rect;
    nm.dwItemSpec = 0;
    nm.uItemState = 0;
    nm.lItemlParam = 0;

    return HEADER_SendNotify(hwnd, NM_CUSTOMDRAW, (NMHDR *)&nm);
Alexandre Julliard's avatar
Alexandre Julliard committed
808 809
}

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

822
    return (BOOL)HEADER_SendNotify(hwnd, code, (NMHDR *)&nmhdr);
823 824
}

825 826 827 828 829 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 856
static BOOL
HEADER_SendNotifyWithIntFieldT(HWND hwnd, UINT code, INT iItem, INT mask, INT iValue)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
    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);
    }

    return HEADER_SendNotifyWithHDItemT(hwnd, code, iItem, &nmitem);
}

857
/**
858
 * Prepare callback items
859 860
 *   depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA 
 *   (so we handle the two cases only doing a specific cast for pszText).
861 862 863 864
 * 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.
865 866
 *
 * @param hwnd : hwnd header container handler
867 868 869 870
 * @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
871 872
 */
static BOOL
873
HEADER_PrepareCallbackItems(HWND hwnd, INT iItem, INT reqMask)
874 875
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
876 877
    HEADER_ITEM *lpItem = &infoPtr->items[iItem];
    DWORD mask = reqMask & lpItem->callbackMask;
878
    NMHDDISPINFOW dispInfo;
879
    void *pvBuffer = NULL;
880

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

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

            /* the user might have used his own buffer */
            if (dispInfo.pszText != lpItem->pszText)
                Str_GetPtrW(dispInfo.pszText, lpItem->pszText, MAX_HEADER_TEXT_LEN);
932
        }
933
        else
934
        {
935 936
            Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)dispInfo.pszText);
            Free(pvBuffer);
937
        }
938
    }
939
        
940 941 942 943
    if (dispInfo.mask & HDI_DI_SETITEM) 
    {
        /* make the items permanent */
        lpItem->callbackMask &= ~dispInfo.mask;
944 945
    }
    
946 947 948 949 950 951 952 953 954 955 956 957 958 959
    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)
{
960
    if (lpItem->callbackMask&HDI_TEXT)
961
    {
962 963
        Free(lpItem->pszText);
        lpItem->pszText = NULL;
964
    }
965

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

static LRESULT
971
HEADER_CreateDragImage (HWND hwnd, WPARAM wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
972
{
973 974 975 976
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
    HEADER_ITEM *lpItem;
    HIMAGELIST himl;
    HBITMAP hMemory, hOldBitmap;
977 978
    LRESULT lCDFlags;
    RECT rc;
979 980 981
    HDC hMemoryDC;
    HDC hDeviceDC;
    int height, width;
982
    HFONT hFont;
983 984 985
    
    if (wParam < 0 || wParam >= infoPtr->uNumItem)
        return FALSE;
986 987 988 989

    if (!infoPtr->bRectsValid)
    	HEADER_SetItemBounds(hwnd);

990 991 992 993 994 995 996 997 998 999
    lpItem = &infoPtr->items[wParam];
    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);
1000 1001
    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject(SYSTEM_FONT);
    SelectObject(hMemoryDC, hFont);
1002 1003 1004 1005 1006 1007 1008

    GetClientRect(hwnd, &rc);
    lCDFlags = HEADER_SendCtrlCustomDraw(hwnd, CDDS_PREPAINT, hMemoryDC, &rc);
    HEADER_DrawItem(hwnd, hMemoryDC, wParam, FALSE, lCDFlags);
    if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
        HEADER_SendCtrlCustomDraw(hwnd, CDDS_POSTPAINT, hMemoryDC, &rc);
    
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
    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
1019 1020
}

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
static LRESULT
HEADER_SetHotDivider(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
    INT iDivider;
    RECT r;
    
    if (wParam)
    {
        POINT pt;
        UINT flags;
        pt.x = (INT)(SHORT)LOWORD(lParam);
        pt.y = 0;
        HEADER_InternalHitTest (hwnd, &pt, &flags, &iDivider);
        
        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)
                iDivider = HEADER_NextItem(hwnd, iDivider);
        }
    }
    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)
        {
            HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
            InvalidateRect(hwnd, &r, FALSE);
        }
        infoPtr->iHotDivider = iDivider;
        if (iDivider != -1)
        {
            HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
            InvalidateRect(hwnd, &r, FALSE);
        }
    }
    return iDivider;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1070 1071

static LRESULT
1072
HEADER_DeleteItem (HWND hwnd, WPARAM wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1073
{
1074
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1075
    INT iItem = (INT)wParam;
1076 1077
    INT iOrder;
    INT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1078

1079
    TRACE("[iItem=%d]\n", iItem);
1080

1081
    if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
Alexandre Julliard's avatar
Alexandre Julliard committed
1082 1083
        return FALSE;

1084 1085
    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);
1086

1087
    iOrder = infoPtr->items[iItem].iOrder;
1088
    Free(infoPtr->items[iItem].pszText);
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104

    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
1105
    }
1106 1107
    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
1108

1109
    HEADER_SetItemBounds (hwnd);
1110
    InvalidateRect(hwnd, NULL, FALSE);
1111

Alexandre Julliard's avatar
Alexandre Julliard committed
1112 1113 1114 1115 1116
    return TRUE;
}


static LRESULT
1117
HEADER_GetImageList (HWND hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1118
{
1119
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1120 1121 1122 1123 1124 1125

    return (LRESULT)infoPtr->himl;
}


static LRESULT
1126
HEADER_GetItemT (HWND hwnd, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
1127
{
1128
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1129
    HEADER_ITEM *lpItem;
1130
    UINT mask;
Alexandre Julliard's avatar
Alexandre Julliard committed
1131

Alexandre Julliard's avatar
Alexandre Julliard committed
1132
    if (!phdi)
Alexandre Julliard's avatar
Alexandre Julliard committed
1133
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1134

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

1137
    mask = phdi->mask;
1138
    if (mask == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1139
	return TRUE;
1140

1141
    if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1142 1143
        return FALSE;

1144 1145 1146 1147 1148 1149
    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;
    }
    
1150
    lpItem = &infoPtr->items[nItem];
1151
    HEADER_PrepareCallbackItems(hwnd, nItem, mask);
1152

1153
    if (mask & HDI_BITMAP)
1154
        phdi->hbm = lpItem->hbm;
Alexandre Julliard's avatar
Alexandre Julliard committed
1155

1156
    if (mask & HDI_FORMAT)
1157
        phdi->fmt = lpItem->fmt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1158

1159
    if (mask & HDI_WIDTH)
1160
        phdi->cxy = lpItem->cxy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1161

1162
    if (mask & HDI_LPARAM)
1163
        phdi->lParam = lpItem->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1164

1165
    if (mask & HDI_IMAGE) 
1166
        phdi->iImage = lpItem->iImage;
Alexandre Julliard's avatar
Alexandre Julliard committed
1167

1168
    if (mask & HDI_ORDER)
1169
        phdi->iOrder = lpItem->iOrder;
Alexandre Julliard's avatar
Alexandre Julliard committed
1170

1171
    if (mask & HDI_TEXT)
1172
    {
1173 1174
        if (bUnicode)
            Str_GetPtrW (lpItem->pszText, phdi->pszText, phdi->cchTextMax);
1175
        else
1176
            Str_GetPtrWtoA (lpItem->pszText, (LPSTR)phdi->pszText, phdi->cchTextMax);
1177 1178
    }

1179
    HEADER_FreeCallbackItems(lpItem);
1180 1181 1182 1183
    return TRUE;
}


1184
static inline LRESULT
1185
HEADER_GetItemCount (HWND hwnd)
1186
{
1187
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1188
    return infoPtr->uNumItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1189 1190 1191 1192
}


static LRESULT
1193
HEADER_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1194
{
1195
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1196 1197
    INT iItem = (INT)wParam;
    LPRECT lpRect = (LPRECT)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1198

1199
    if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
Alexandre Julliard's avatar
Alexandre Julliard committed
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
        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;
}


1211
static LRESULT
1212 1213 1214 1215
HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    LPINT order = (LPINT) lParam;
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1216

1217
    if ((unsigned int)wParam <infoPtr->uNumItem)
1218
      return FALSE;
1219 1220

    memcpy(order, infoPtr->order, infoPtr->uNumItem * sizeof(INT));
1221 1222 1223
    return TRUE;
}

1224
static LRESULT
1225 1226 1227 1228 1229 1230 1231
HEADER_SetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    int i;
    LPINT order = (LPINT) lParam;
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
    HEADER_ITEM *lpItem;

1232
    if ((unsigned int)wParam <infoPtr->uNumItem)
1233
      return FALSE;
1234
    memcpy(infoPtr->order, order, infoPtr->uNumItem * sizeof(INT));
1235 1236
    for (i=0; i<(int)wParam; i++)
      {
1237
        lpItem = &infoPtr->items[*order++];
1238 1239 1240 1241 1242 1243
	lpItem->iOrder=i;
      }
    infoPtr->bRectsValid=0;
    InvalidateRect(hwnd, NULL, FALSE);
    return TRUE;
}
1244

1245
static inline LRESULT
1246
HEADER_GetUnicodeFormat (HWND hwnd)
1247
{
1248
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1249
    return (infoPtr->nNotifyFormat == NFR_UNICODE);
1250 1251 1252
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1253
static LRESULT
1254
HEADER_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1255 1256 1257
{
    LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam;

1258
    HEADER_InternalHitTest (hwnd, &phti->pt, &phti->flags, &phti->iItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1259

1260
    if (phti->flags == HHT_NOWHERE)
1261
        return -1;
1262 1263
    else
        return phti->iItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1264 1265 1266 1267
}


static LRESULT
1268
HEADER_InsertItemT (HWND hwnd, INT nItem, const HDITEMW *phdi, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
1269
{
1270
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1271
    HEADER_ITEM *lpItem;
1272
    INT       iOrder;
1273
    UINT      i;
1274
    UINT      copyMask;
Alexandre Julliard's avatar
Alexandre Julliard committed
1275

1276
    if ((phdi == NULL) || (nItem < 0) || (phdi->mask == 0))
Alexandre Julliard's avatar
Alexandre Julliard committed
1277 1278 1279 1280
	return -1;

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

1282
    iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem;
1283 1284 1285 1286
    if (iOrder < 0)
        iOrder = 0;
    else if (infoPtr->uNumItem < iOrder)
        iOrder = infoPtr->uNumItem;
1287

1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
    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;
1300
    for (i = 0; i < infoPtr->uNumItem; i++)
1301
    {
1302 1303
        if (i != iOrder && infoPtr->order[i] >= nItem)
            infoPtr->order[i]++;
1304
        infoPtr->items[infoPtr->order[i]].iOrder = i;
1305 1306
    }

1307
    lpItem = &infoPtr->items[nItem];
1308
    ZeroMemory(lpItem, sizeof(HEADER_ITEM));
1309 1310 1311
    /* 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);
1312
    lpItem->iOrder = iOrder;
1313

1314
    /* set automatically some format bits */
1315 1316
    if (phdi->mask & HDI_TEXT)
        lpItem->fmt |= HDF_STRING;
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
    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
1327

1328
    HEADER_SetItemBounds (hwnd);
1329
    InvalidateRect(hwnd, NULL, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1330

Alexandre Julliard's avatar
Alexandre Julliard committed
1331
    return nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1332 1333 1334 1335
}


static LRESULT
1336
HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1337
{
1338
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1339 1340
    LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam;

1341
    lpLayout->pwpos->hwnd = hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
1342 1343 1344 1345
    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;
1346
    if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_HIDDEN)
Alexandre Julliard's avatar
Alexandre Julliard committed
1347
        lpLayout->pwpos->cy = 0;
1348
    else {
Alexandre Julliard's avatar
Alexandre Julliard committed
1349
        lpLayout->pwpos->cy = infoPtr->nHeight;
1350 1351
        lpLayout->prc->top += infoPtr->nHeight;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1352
    lpLayout->pwpos->flags = SWP_NOZORDER;
Alexandre Julliard's avatar
Alexandre Julliard committed
1353

1354
    TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1355 1356 1357
           lpLayout->pwpos->x, lpLayout->pwpos->y,
           lpLayout->pwpos->cx, lpLayout->pwpos->cy);

1358
    infoPtr->bRectsValid = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1359 1360 1361 1362 1363 1364

    return TRUE;
}


static LRESULT
1365
HEADER_SetImageList (HWND hwnd, HIMAGELIST himl)
Alexandre Julliard's avatar
Alexandre Julliard committed
1366
{
1367
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1368 1369
    HIMAGELIST himlOld;

Frank Richter's avatar
Frank Richter committed
1370
    TRACE("(himl %p)\n", himl);
Alexandre Julliard's avatar
Alexandre Julliard committed
1371
    himlOld = infoPtr->himl;
1372
    infoPtr->himl = himl;
Alexandre Julliard's avatar
Alexandre Julliard committed
1373 1374 1375 1376 1377 1378 1379

    /* FIXME: Refresh needed??? */

    return (LRESULT)himlOld;
}


1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
static LRESULT
HEADER_GetBitmapMargin(HWND hwnd)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
    
    return infoPtr->iMargin;
}

static LRESULT
HEADER_SetBitmapMargin(HWND hwnd, WPARAM wParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
    INT oldMargin = infoPtr->iMargin;

    infoPtr->iMargin = (INT)wParam;

    return oldMargin;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1399
static LRESULT
1400
HEADER_SetItemT (HWND hwnd, INT nItem, const HDITEMW *phdi, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
1401
{
1402
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1403
    HEADER_ITEM *lpItem;
1404 1405
    HDITEMW hdNotify;
    void *pvScratch;
Alexandre Julliard's avatar
Alexandre Julliard committed
1406

Alexandre Julliard's avatar
Alexandre Julliard committed
1407 1408
    if (phdi == NULL)
	return FALSE;
1409
    if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
Alexandre Julliard's avatar
Alexandre Julliard committed
1410 1411
        return FALSE;

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

1414
    HEADER_CopyHDItemForNotify(infoPtr, &hdNotify, phdi, bUnicode, &pvScratch);
1415
    if (HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMCHANGINGW, nItem, &hdNotify))
1416
    {
1417
        Free(pvScratch);
Alexandre Julliard's avatar
Alexandre Julliard committed
1418
	return FALSE;
1419
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1420

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1424
    if (phdi->mask & HDI_ORDER)
1425 1426
        if (phdi->iOrder >= 0 && phdi->iOrder < infoPtr->uNumItem)
            HEADER_ChangeItemOrder(infoPtr, nItem, phdi->iOrder);
Alexandre Julliard's avatar
Alexandre Julliard committed
1427

1428
    HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMCHANGEDW, nItem, &hdNotify);
Alexandre Julliard's avatar
Alexandre Julliard committed
1429

1430
    HEADER_SetItemBounds (hwnd);
1431 1432

    InvalidateRect(hwnd, NULL, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1433

1434
    Free(pvScratch);
Alexandre Julliard's avatar
Alexandre Julliard committed
1435 1436 1437
    return TRUE;
}

1438
static inline LRESULT
1439
HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
1440
{
1441
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1442
    BOOL bTemp = (infoPtr->nNotifyFormat == NFR_UNICODE);
1443

1444
    infoPtr->nNotifyFormat = ((BOOL)wParam ? NFR_UNICODE : NFR_ANSI);
1445 1446 1447 1448 1449

    return bTemp;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1450
static LRESULT
1451
HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1452 1453
{
    HEADER_INFO *infoPtr;
1454
    TEXTMETRICW tm;
1455 1456
    HFONT hOldFont;
    HDC   hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1457

1458
    infoPtr = (HEADER_INFO *)Alloc (sizeof(HEADER_INFO));
1459
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1460

1461
    infoPtr->hwndNotify = ((LPCREATESTRUCTA)lParam)->hwndParent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1462 1463 1464
    infoPtr->uNumItem = 0;
    infoPtr->hFont = 0;
    infoPtr->items = 0;
1465
    infoPtr->order = 0;
1466
    infoPtr->bRectsValid = FALSE;
1467 1468 1469
    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
1470 1471 1472 1473 1474
    infoPtr->bPressed  = FALSE;
    infoPtr->bTracking = FALSE;
    infoPtr->iMoveItem = 0;
    infoPtr->himl = 0;
    infoPtr->iHotItem = -1;
1475
    infoPtr->iHotDivider = -1;
1476
    infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE);
1477
    infoPtr->nNotifyFormat =
1478
	SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
Alexandre Julliard's avatar
Alexandre Julliard committed
1479

1480 1481
    hdc = GetDC (0);
    hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1482
    GetTextMetricsW (hdc, &tm);
Alexandre Julliard's avatar
Alexandre Julliard committed
1483
    infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1484 1485
    SelectObject (hdc, hOldFont);
    ReleaseDC (0, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1486

1487
    OpenThemeData(hwnd, themeClass);
1488

Alexandre Julliard's avatar
Alexandre Julliard committed
1489 1490 1491 1492 1493
    return 0;
}


static LRESULT
1494
HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1495 1496 1497 1498 1499 1500 1501 1502
{
    HTHEME theme = GetWindowTheme(hwnd);
    CloseThemeData(theme);
    return 0;
}

static LRESULT
HEADER_NCDestroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1503
{
1504
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1505
    HEADER_ITEM *lpItem;
1506
    INT nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1507 1508

    if (infoPtr->items) {
1509
        lpItem = infoPtr->items;
Alexandre Julliard's avatar
Alexandre Julliard committed
1510
        for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
1511
            Free(lpItem->pszText);
Alexandre Julliard's avatar
Alexandre Julliard committed
1512
        }
1513
        Free (infoPtr->items);
Alexandre Julliard's avatar
Alexandre Julliard committed
1514 1515
    }

1516
    Free(infoPtr->order);
1517

Alexandre Julliard's avatar
Alexandre Julliard committed
1518
    if (infoPtr->himl)
1519
      ImageList_Destroy (infoPtr->himl);
Alexandre Julliard's avatar
Alexandre Julliard committed
1520

1521
    SetWindowLongPtrW (hwnd, 0, 0);
1522
    Free (infoPtr);
1523

Alexandre Julliard's avatar
Alexandre Julliard committed
1524 1525 1526 1527
    return 0;
}


Patrik Stridvall's avatar
Patrik Stridvall committed
1528
static inline LRESULT
1529
HEADER_GetFont (HWND hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1530
{
1531
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1532 1533 1534 1535 1536

    return (LRESULT)infoPtr->hFont;
}


1537
static BOOL
1538
HEADER_IsDragDistance(const HEADER_INFO *infoPtr, const POINT *pt)
1539 1540 1541 1542 1543 1544 1545 1546
{
    /* 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
1547
static LRESULT
1548
HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1549
{
1550 1551 1552
    POINT pt;
    UINT  flags;
    INT   nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1553

1554 1555
    pt.x = (short)LOWORD(lParam);
    pt.y = (short)HIWORD(lParam);
1556
    HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1557

1558
    if ((GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER))
1559
        HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMDBLCLICKW, nItem, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1560
    else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
1561
        HEADER_SendNotifyWithHDItemT(hwnd, HDN_DIVIDERDBLCLICKW, nItem, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1562 1563 1564 1565 1566 1567

    return 0;
}


static LRESULT
1568
HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1569
{
1570
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1571
    DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1572 1573 1574 1575
    POINT pt;
    UINT  flags;
    INT   nItem;
    HDC   hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1576

1577 1578
    pt.x = (short)LOWORD(lParam);
    pt.y = (short)HIWORD(lParam);
1579
    HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1580

1581 1582
    if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
	SetCapture (hwnd);
1583
	infoPtr->bCaptured = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1584
	infoPtr->bPressed  = TRUE;
1585
	infoPtr->bDragging = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1586
	infoPtr->iMoveItem = nItem;
1587
	infoPtr->ptLButtonDown = pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1588

Alexandre Julliard's avatar
Alexandre Julliard committed
1589
	infoPtr->items[nItem].bDown = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1590 1591

	/* Send WM_CUSTOMDRAW */
1592 1593 1594
	hdc = GetDC (hwnd);
	HEADER_RefreshItem (hwnd, hdc, nItem);
	ReleaseDC (hwnd, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1595

1596
	TRACE("Pressed item %d!\n", nItem);
1597
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1598
    else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
1599 1600 1601
        INT iCurrWidth = infoPtr->items[nItem].cxy;
        if (!HEADER_SendNotifyWithIntFieldT(hwnd, HDN_BEGINTRACKW, nItem, HDI_WIDTH, iCurrWidth))
        {
1602
	    SetCapture (hwnd);
1603
	    infoPtr->bCaptured = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1604
	    infoPtr->bTracking = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1605 1606
	    infoPtr->iMoveItem = nItem;
	    infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
Alexandre Julliard's avatar
Alexandre Julliard committed
1607

1608
	    if (!(dwStyle & HDS_FULLDRAG)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1609
		infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
1610 1611 1612
		hdc = GetDC (hwnd);
		HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
		ReleaseDC (hwnd, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1613 1614
	    }

1615
	    TRACE("Begin tracking item %d!\n", nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1616 1617 1618 1619 1620 1621 1622 1623
	}
    }

    return 0;
}


static LRESULT
1624
HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1625
{
1626
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1627
    DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1628 1629
    POINT pt;
    UINT  flags;
1630
    INT   nItem;
1631
    HDC   hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1632

1633 1634
    pt.x = (INT)(SHORT)LOWORD(lParam);
    pt.y = (INT)(SHORT)HIWORD(lParam);
1635
    HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1636 1637

    if (infoPtr->bPressed) {
1638 1639
	if (infoPtr->bDragging)
	{
1640 1641 1642
            HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
            INT iNewOrder;
            
1643 1644
	    ImageList_DragShowNolock(FALSE);
	    ImageList_EndDrag();
1645 1646 1647 1648 1649 1650 1651
            lpItem->bDown=FALSE;
            
            if (infoPtr->iHotDivider == -1)
                iNewOrder = -1;
            else if (infoPtr->iHotDivider == infoPtr->uNumItem)
                iNewOrder = infoPtr->uNumItem-1;
            else
1652
	    {
1653 1654 1655 1656
                iNewOrder = HEADER_IndexToOrder(hwnd, infoPtr->iHotDivider);
                if (iNewOrder > lpItem->iOrder)
                    iNewOrder--;
            }
1657

1658
            if (iNewOrder != -1 &&
1659
                !HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ENDDRAG, infoPtr->iMoveItem, HDI_ORDER, iNewOrder))
1660 1661
            {
                HEADER_ChangeItemOrder(infoPtr, infoPtr->iMoveItem, iNewOrder);
1662 1663 1664 1665 1666
		infoPtr->bRectsValid = FALSE;
		InvalidateRect(hwnd, NULL, FALSE);
	    }
	    else
		InvalidateRect(hwnd, &infoPtr->items[infoPtr->iMoveItem].rect, FALSE);
1667 1668
                
            HEADER_SetHotDivider(hwnd, FALSE, -1);
1669 1670 1671
	}
	else if (!(dwStyle&HDS_DRAGDROP) || !HEADER_IsDragDistance(infoPtr, &pt))
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
1672
	    infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1673 1674 1675
	    hdc = GetDC (hwnd);
	    HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
	    ReleaseDC (hwnd, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1676

1677
	    HEADER_SendNotifyWithHDItemT(hwnd, HDN_ITEMCLICKW, infoPtr->iMoveItem, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1678
	}
1679

1680
	TRACE("Released item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1681 1682 1683
	infoPtr->bPressed = FALSE;
    }
    else if (infoPtr->bTracking) {
1684 1685 1686
        INT iNewWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
        if (iNewWidth < 0)
	    iNewWidth = 0;
1687
	TRACE("End tracking item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1688 1689
	infoPtr->bTracking = FALSE;

1690
        HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ENDTRACKW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
Alexandre Julliard's avatar
Alexandre Julliard committed
1691

1692
        if (!(dwStyle & HDS_FULLDRAG)) {
1693 1694
	    hdc = GetDC (hwnd);
	    HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1695
            ReleaseDC (hwnd, hdc);
1696 1697
        }
          
1698 1699
        if (!HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth))
        {
1700 1701
            infoPtr->items[infoPtr->iMoveItem].cxy = iNewWidth;
            HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
1702
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1703

1704 1705
	HEADER_SetItemBounds (hwnd);
	InvalidateRect(hwnd, NULL, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1706 1707 1708 1709 1710
    }

    if (infoPtr->bCaptured) {
	infoPtr->bCaptured = FALSE;
	ReleaseCapture ();
1711
	HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1712 1713 1714 1715 1716 1717
    }

    return 0;
}


1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729
static LRESULT
HEADER_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);

    switch (lParam)
    {
	case NF_QUERY:
	    return infoPtr->nNotifyFormat;

	case NF_REQUERY:
	    infoPtr->nNotifyFormat =
1730
		SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT,
1731 1732 1733 1734 1735 1736 1737
			      (WPARAM)hwnd, (LPARAM)NF_QUERY);
	    return infoPtr->nNotifyFormat;
    }

    return 0;
}

1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
static LRESULT
HEADER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
    /* Reset hot-tracked item when mouse leaves control. */
    INT oldHotItem = infoPtr->iHotItem;
    HDC hdc = GetDC (hwnd);

    infoPtr->iHotItem = -1;
    if (oldHotItem != -1) HEADER_RefreshItem (hwnd, hdc, oldHotItem);
    ReleaseDC (hwnd, hdc);

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1754
static LRESULT
1755
HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1756
{
1757
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1758
    DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1759 1760 1761 1762
    POINT pt;
    UINT  flags;
    INT   nItem, nWidth;
    HDC   hdc;
1763 1764 1765 1766 1767
    /* With theming, hottracking is always enabled */
    BOOL  hotTrackEnabled =
        ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK))
        || (GetWindowTheme (hwnd) != NULL);
    INT oldHotItem = infoPtr->iHotItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1768

1769 1770
    pt.x = (INT)(SHORT)LOWORD(lParam);
    pt.y = (INT)(SHORT)HIWORD(lParam);
1771
    HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1772

1773
    if (hotTrackEnabled) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1774
	if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
Alexandre Julliard's avatar
Alexandre Julliard committed
1775
	    infoPtr->iHotItem = nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1776 1777 1778 1779 1780
	else
	    infoPtr->iHotItem = -1;
    }

    if (infoPtr->bCaptured) {
1781 1782 1783 1784
        /* check if we should drag the header */
	if (infoPtr->bPressed && !infoPtr->bDragging && dwStyle&HDS_DRAGDROP
	    && HEADER_IsDragDistance(infoPtr, &pt))
	{
1785
            if (!HEADER_SendNotifyWithHDItemT(hwnd, HDN_BEGINDRAG, infoPtr->iMoveItem, NULL))
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810
	    {
		HIMAGELIST hDragItem = (HIMAGELIST)HEADER_CreateDragImage(hwnd, infoPtr->iMoveItem);
		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;
	    ClientToScreen(hwnd, &drag);
	    ImageList_DragMove(drag.x, drag.y);
	    HEADER_SetHotDivider(hwnd, TRUE, lParam);
	}
	
	if (infoPtr->bPressed && !infoPtr->bDragging) {
1811
            BOOL oldState = infoPtr->items[infoPtr->iMoveItem].bDown;
Alexandre Julliard's avatar
Alexandre Julliard committed
1812
	    if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
Alexandre Julliard's avatar
Alexandre Julliard committed
1813 1814 1815
		infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
	    else
		infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1816 1817 1818 1819 1820
            if (oldState != infoPtr->items[infoPtr->iMoveItem].bDown) {
                hdc = GetDC (hwnd);
	        HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
	        ReleaseDC (hwnd, hdc);
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1821

1822
	    TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1823 1824
	}
	else if (infoPtr->bTracking) {
1825
	    if (dwStyle & HDS_FULLDRAG) {
1826 1827 1828
                HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
                nWidth = pt.x - lpItem->rect.left + infoPtr->xTrackOffset;
                if (!HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, nWidth))
1829
		{
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844
                    INT nOldWidth = lpItem->rect.right - lpItem->rect.left;
                    RECT rcClient;
                    RECT rcScroll;
                    
                    if (nWidth < 0) nWidth = 0;
                    infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
                    HEADER_SetItemBounds(hwnd);
                    
                    GetClientRect(hwnd, &rcClient);
                    rcScroll = rcClient;
                    rcScroll.left = lpItem->rect.left + nOldWidth;
                    ScrollWindowEx(hwnd, nWidth - nOldWidth, 0, &rcScroll, &rcClient, NULL, NULL, 0);
                    InvalidateRect(hwnd, &lpItem->rect, FALSE);
                    UpdateWindow(hwnd);
                    
1845
                    HEADER_SendNotifyWithIntFieldT(hwnd, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, nWidth);
1846
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
1847 1848
	    }
	    else {
1849
                INT iTrackWidth;
1850 1851
		hdc = GetDC (hwnd);
		HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
Alexandre Julliard's avatar
Alexandre Julliard committed
1852 1853 1854
		infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
		if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
		    infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
1855 1856
		HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
		ReleaseDC (hwnd, hdc);
1857
                iTrackWidth = infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
1858
                /* FIXME: should stop tracking if HDN_TRACK returns TRUE */
1859
                HEADER_SendNotifyWithIntFieldT(hwnd, HDN_TRACKW, infoPtr->iMoveItem, HDI_WIDTH, iTrackWidth);
Alexandre Julliard's avatar
Alexandre Julliard committed
1860 1861
	    }

1862
	    TRACE("Tracking item %d!\n", infoPtr->iMoveItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1863 1864 1865
	}
    }

1866 1867
    if (hotTrackEnabled) {
        TRACKMOUSEEVENT tme;
1868
        if (oldHotItem != infoPtr->iHotItem && !infoPtr->bDragging) {
1869 1870 1871 1872 1873 1874 1875 1876 1877
	    hdc = GetDC (hwnd);
	    if (oldHotItem != -1) HEADER_RefreshItem (hwnd, hdc, oldHotItem);
	    if (infoPtr->iHotItem != -1) HEADER_RefreshItem (hwnd, hdc, infoPtr->iHotItem);
	    ReleaseDC (hwnd, hdc);
        }
        tme.cbSize = sizeof( tme );
        tme.dwFlags = TME_LEAVE;
        tme.hwndTrack = hwnd;
        TrackMouseEvent( &tme );
Alexandre Julliard's avatar
Alexandre Julliard committed
1878 1879 1880 1881 1882 1883 1884
    }

    return 0;
}


static LRESULT
1885
HEADER_Paint (HWND hwnd, WPARAM wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1886
{
1887 1888
    HDC hdc;
    PAINTSTRUCT ps;
Alexandre Julliard's avatar
Alexandre Julliard committed
1889

1890 1891
    hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
    HEADER_Refresh (hwnd, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1892
    if(!wParam)
1893
	EndPaint (hwnd, &ps);
Alexandre Julliard's avatar
Alexandre Julliard committed
1894 1895 1896 1897 1898
    return 0;
}


static LRESULT
1899
HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1900
{
1901 1902 1903
    BOOL bRet;
    POINT pt;

1904 1905
    pt.x = (short)LOWORD(lParam);
    pt.y = (short)HIWORD(lParam);
1906 1907 1908 1909 1910 1911 1912 1913

    /* Send a Notify message */
    bRet = HEADER_SendSimpleNotify (hwnd, NM_RCLICK);

    /* Change to screen coordinate for WM_CONTEXTMENU */
    ClientToScreen(hwnd, &pt);

    /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1914
    SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
1915

1916
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
1917 1918 1919 1920
}


static LRESULT
1921
HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1922
{
1923
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1924 1925 1926
    POINT pt;
    UINT  flags;
    INT   nItem;
Alexandre Julliard's avatar
Alexandre Julliard committed
1927

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

1930
    GetCursorPos (&pt);
1931
    ScreenToClient (hwnd, &pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1932

1933
    HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
Alexandre Julliard's avatar
Alexandre Julliard committed
1934 1935

    if (flags == HHT_ONDIVIDER)
1936
        SetCursor (infoPtr->hcurDivider);
Alexandre Julliard's avatar
Alexandre Julliard committed
1937
    else if (flags == HHT_ONDIVOPEN)
1938
        SetCursor (infoPtr->hcurDivopen);
Alexandre Julliard's avatar
Alexandre Julliard committed
1939
    else
1940
        SetCursor (infoPtr->hcurArrow);
Alexandre Julliard's avatar
Alexandre Julliard committed
1941 1942 1943 1944 1945 1946

    return 0;
}


static LRESULT
1947
HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1948
{
1949
    HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1950
    TEXTMETRICW tm;
1951 1952
    HFONT hFont, hOldFont;
    HDC hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1953

1954
    infoPtr->hFont = (HFONT)wParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1955

1956
    hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
Alexandre Julliard's avatar
Alexandre Julliard committed
1957

1958 1959
    hdc = GetDC (0);
    hOldFont = SelectObject (hdc, hFont);
1960
    GetTextMetricsW (hdc, &tm);
Alexandre Julliard's avatar
Alexandre Julliard committed
1961
    infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1962 1963
    SelectObject (hdc, hOldFont);
    ReleaseDC (0, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1964

1965
    infoPtr->bRectsValid = FALSE;
1966

Alexandre Julliard's avatar
Alexandre Julliard committed
1967
    if (lParam) {
1968
        InvalidateRect(hwnd, NULL, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1969 1970 1971 1972 1973
    }

    return 0;
}

1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985
static LRESULT HEADER_SetRedraw(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    /* 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;

    ret = DefWindowProcW(hwnd, WM_SETREDRAW, wParam, lParam);
    if (wParam)
        InvalidateRect(hwnd, NULL, TRUE);
    return ret;
}

1986 1987 1988 1989 1990 1991 1992 1993 1994 1995
/* Update the theme handle after a theme change */
static LRESULT HEADER_ThemeChanged(HWND hwnd)
{
    HTHEME theme = GetWindowTheme(hwnd);
    CloseThemeData(theme);
    OpenThemeData(hwnd, themeClass);
    InvalidateRect(hwnd, NULL, FALSE);
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1996

1997
static LRESULT WINAPI
1998
HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1999
{
2000
    TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, msg, wParam, lParam);
2001
    if (!HEADER_GetInfoPtr (hwnd) && (msg != WM_CREATE))
2002
	return DefWindowProcW (hwnd, msg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2003
    switch (msg) {
2004 2005
/*	case HDM_CLEARFILTER: */

Alexandre Julliard's avatar
Alexandre Julliard committed
2006
	case HDM_CREATEDRAGIMAGE:
2007
	    return HEADER_CreateDragImage (hwnd, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2008 2009

	case HDM_DELETEITEM:
2010
	    return HEADER_DeleteItem (hwnd, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2011

2012 2013
/*	case HDM_EDITFILTER: */

2014 2015
	case HDM_GETBITMAPMARGIN:
	    return HEADER_GetBitmapMargin(hwnd);
2016

Alexandre Julliard's avatar
Alexandre Julliard committed
2017
	case HDM_GETIMAGELIST:
2018
	    return HEADER_GetImageList (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2019

2020 2021
	case HDM_GETITEMA:
	case HDM_GETITEMW:
2022
	    return HEADER_GetItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_GETITEMW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2023

Alexandre Julliard's avatar
Alexandre Julliard committed
2024
	case HDM_GETITEMCOUNT:
2025
	    return HEADER_GetItemCount (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2026 2027

	case HDM_GETITEMRECT:
2028
	    return HEADER_GetItemRect (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2029

2030
	case HDM_GETORDERARRAY:
2031 2032
	    return HEADER_GetOrderArray(hwnd, wParam, lParam);

2033
	case HDM_GETUNICODEFORMAT:
2034
	    return HEADER_GetUnicodeFormat (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2035

Alexandre Julliard's avatar
Alexandre Julliard committed
2036
	case HDM_HITTEST:
2037
	    return HEADER_HitTest (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2038

2039 2040
	case HDM_INSERTITEMA:
	case HDM_INSERTITEMW:
2041
	    return HEADER_InsertItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_INSERTITEMW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2042

Alexandre Julliard's avatar
Alexandre Julliard committed
2043
	case HDM_LAYOUT:
2044
	    return HEADER_Layout (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2045

2046 2047 2048
	case HDM_ORDERTOINDEX:
	    return HEADER_OrderToIndex(hwnd, wParam);

2049 2050
	case HDM_SETBITMAPMARGIN:
	    return HEADER_SetBitmapMargin(hwnd, wParam);
2051 2052 2053

/*	case HDM_SETFILTERCHANGETIMEOUT: */

2054 2055
        case HDM_SETHOTDIVIDER:
            return HEADER_SetHotDivider(hwnd, wParam, lParam);
2056

Alexandre Julliard's avatar
Alexandre Julliard committed
2057
	case HDM_SETIMAGELIST:
2058
	    return HEADER_SetImageList (hwnd, (HIMAGELIST)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2059

2060 2061
	case HDM_SETITEMA:
	case HDM_SETITEMW:
2062
	    return HEADER_SetItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_SETITEMW);
2063

2064 2065 2066
	case HDM_SETORDERARRAY:
	    return HEADER_SetOrderArray(hwnd, wParam, lParam);

2067
	case HDM_SETUNICODEFORMAT:
2068
	    return HEADER_SetUnicodeFormat (hwnd, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2069

Alexandre Julliard's avatar
Alexandre Julliard committed
2070
        case WM_CREATE:
2071
            return HEADER_Create (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2072 2073

        case WM_DESTROY:
2074
            return HEADER_Destroy (hwnd, wParam, lParam);
2075 2076 2077

        case WM_NCDESTROY:
            return HEADER_NCDestroy (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2078 2079 2080 2081 2082 2083 2084 2085

        case WM_ERASEBKGND:
            return 1;

        case WM_GETDLGCODE:
            return DLGC_WANTTAB | DLGC_WANTARROWS;

        case WM_GETFONT:
2086
            return HEADER_GetFont (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2087 2088

        case WM_LBUTTONDBLCLK:
2089
            return HEADER_LButtonDblClk (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2090 2091

        case WM_LBUTTONDOWN:
2092
            return HEADER_LButtonDown (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2093 2094

        case WM_LBUTTONUP:
2095
            return HEADER_LButtonUp (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2096

2097 2098 2099
        case WM_MOUSELEAVE:
            return HEADER_MouseLeave (hwnd, wParam, lParam);

Alexandre Julliard's avatar
Alexandre Julliard committed
2100
        case WM_MOUSEMOVE:
2101
            return HEADER_MouseMove (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2102

2103 2104
	case WM_NOTIFYFORMAT:
            return HEADER_NotifyFormat (hwnd, wParam, lParam);
2105

2106 2107
	case WM_SIZE:
	    return HEADER_Size (hwnd, wParam);
2108

2109 2110 2111
        case WM_THEMECHANGED:
            return HEADER_ThemeChanged (hwnd);

2112
        case WM_PRINTCLIENT:
Alexandre Julliard's avatar
Alexandre Julliard committed
2113
        case WM_PAINT:
2114
            return HEADER_Paint (hwnd, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2115 2116

        case WM_RBUTTONUP:
2117
            return HEADER_RButtonUp (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2118 2119

        case WM_SETCURSOR:
2120
            return HEADER_SetCursor (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2121 2122

        case WM_SETFONT:
2123
            return HEADER_SetFont (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2124

2125 2126 2127
        case WM_SETREDRAW:
            return HEADER_SetRedraw(hwnd, wParam, lParam);

Alexandre Julliard's avatar
Alexandre Julliard committed
2128
        default:
2129
            if ((msg >= WM_USER) && (msg < WM_APP))
2130
		ERR("unknown msg %04x wp=%04lx lp=%08lx\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2131
		     msg, wParam, lParam );
2132
	    return DefWindowProcW(hwnd, msg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2133 2134 2135 2136
    }
}


2137
VOID
2138
HEADER_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2139
{
2140
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2141

2142
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
2143
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
2144
    wndClass.lpfnWndProc   = HEADER_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2145 2146
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
2147 2148
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
    wndClass.lpszClassName = WC_HEADERW;
2149

2150
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
2151 2152
}

2153 2154

VOID
2155
HEADER_Unregister (void)
2156
{
2157
    UnregisterClassW (WC_HEADERW, NULL);
2158
}