ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

header.c
Go to the documentation of this file.
00001 /*
00002  *  Header control
00003  *
00004  *  Copyright 1998 Eric Kohl
00005  *  Copyright 2000 Eric Kohl for CodeWeavers
00006  *  Copyright 2003 Maxime Bellenge
00007  *  Copyright 2006 Mikolaj Zalewski
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00022  *
00023  *  TODO:
00024  *   - Imagelist support (completed?)
00025  *   - Hottrack support (completed?)
00026  *   - Filters support (HDS_FILTER, HDI_FILTER, HDM_*FILTER*, HDN_*FILTER*)
00027  *   - New Windows Vista features
00028  */
00029 
00030 #include <stdarg.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 
00034 #include "windef.h"
00035 #include "winbase.h"
00036 #include "wine/unicode.h"
00037 #include "wingdi.h"
00038 #include "winuser.h"
00039 #include "winnls.h"
00040 #include "commctrl.h"
00041 #include "comctl32.h"
00042 #include "vssym32.h"
00043 #include "uxtheme.h"
00044 #include "wine/debug.h"
00045 
00046 WINE_DEFAULT_DEBUG_CHANNEL(header);
00047 
00048 typedef struct
00049 {
00050     INT     cxy;
00051     HBITMAP hbm;
00052     LPWSTR    pszText;
00053     INT     fmt;
00054     LPARAM    lParam;
00055     INT     iImage;
00056     INT     iOrder;     /* see documentation of HD_ITEM */
00057 
00058     BOOL    bDown;      /* is item pressed? (used for drawing) */
00059     RECT    rect;       /* bounding rectangle of the item */
00060     DWORD   callbackMask;       /* HDI_* flags for items that are callback */
00061 } HEADER_ITEM;
00062 
00063 
00064 typedef struct
00065 {
00066     HWND      hwndSelf;     /* Control window */
00067     HWND      hwndNotify;   /* Owner window to send notifications to */
00068     INT       nNotifyFormat;    /* format used for WM_NOTIFY messages */
00069     UINT      uNumItem;     /* number of items (columns) */
00070     INT       nHeight;      /* height of the header (pixels) */
00071     HFONT     hFont;        /* handle to the current font */
00072     HCURSOR   hcurArrow;    /* handle to the arrow cursor */
00073     HCURSOR   hcurDivider;  /* handle to a cursor (used over dividers) <-|-> */
00074     HCURSOR   hcurDivopen;  /* handle to a cursor (used over dividers) <-||-> */
00075     BOOL      bCaptured;    /* Is the mouse captured? */
00076     BOOL      bPressed;     /* Is a header item pressed (down)? */
00077     BOOL      bDragging;        /* Are we dragging an item? */
00078     BOOL      bTracking;    /* Is in tracking mode? */
00079     POINT     ptLButtonDown;    /* The point where the left button was pressed */
00080     DWORD     dwStyle;      /* the cached window GWL_STYLE */
00081     INT       iMoveItem;    /* index of tracked item. (Tracking mode) */
00082     INT       xTrackOffset; /* distance between the right side of the tracked item and the cursor */
00083     INT       xOldTrack;    /* track offset (see above) after the last WM_MOUSEMOVE */
00084     INT       iHotItem;     /* index of hot item (cursor is over this item) */
00085     INT       iHotDivider;      /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
00086     INT       iMargin;          /* width of the margin that surrounds a bitmap */
00087 
00088     HIMAGELIST  himl;       /* handle to an image list (may be 0) */
00089     HEADER_ITEM *items;     /* pointer to array of HEADER_ITEM's */
00090     INT         *order;         /* array of item IDs indexed by order */
00091     BOOL    bRectsValid;    /* validity flag for bounding rectangles */
00092 } HEADER_INFO;
00093 
00094 
00095 #define VERT_BORDER     4
00096 #define DIVIDER_WIDTH  10
00097 #define HOT_DIVIDER_WIDTH 2
00098 #define MAX_HEADER_TEXT_LEN 260
00099 #define HDN_UNICODE_OFFSET 20
00100 #define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
00101 
00102 #define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)
00103 #define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)
00104 #define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))
00105 #define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)
00106 
00107 
00108 static BOOL HEADER_PrepareCallbackItems(const HEADER_INFO *infoPtr, INT iItem, INT reqMask);
00109 static void HEADER_FreeCallbackItems(HEADER_ITEM *lpItem);
00110 static LRESULT HEADER_SendNotify(const HEADER_INFO *infoPtr, UINT code, NMHDR *hdr);
00111 static LRESULT HEADER_SendCtrlCustomDraw(const HEADER_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, const RECT *rect);
00112 
00113 static const WCHAR themeClass[] = {'H','e','a','d','e','r',0};
00114 
00115 static void HEADER_StoreHDItemInHeader(HEADER_ITEM *lpItem, UINT mask, const HDITEMW *phdi, BOOL fUnicode)
00116 {
00117     if (mask & HDI_UNSUPPORTED_FIELDS)
00118         FIXME("unsupported header fields %x\n", (mask & HDI_UNSUPPORTED_FIELDS));
00119     
00120     if (mask & HDI_BITMAP)
00121         lpItem->hbm = phdi->hbm;
00122 
00123     if (mask & HDI_FORMAT)
00124         lpItem->fmt = phdi->fmt;
00125 
00126     if (mask & HDI_LPARAM)
00127         lpItem->lParam = phdi->lParam;
00128 
00129     if (mask & HDI_WIDTH)
00130         lpItem->cxy = phdi->cxy;
00131 
00132     if (mask & HDI_IMAGE) 
00133     {
00134         lpItem->iImage = phdi->iImage;
00135         if (phdi->iImage == I_IMAGECALLBACK)
00136             lpItem->callbackMask |= HDI_IMAGE;
00137         else
00138             lpItem->callbackMask &= ~HDI_IMAGE;
00139     }
00140 
00141     if (mask & HDI_TEXT)
00142     {
00143         Free(lpItem->pszText);
00144         lpItem->pszText = NULL;
00145 
00146         if (phdi->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */
00147         {
00148             static const WCHAR emptyString[] = {0};
00149 
00150             LPCWSTR pszText = (phdi->pszText != NULL ? phdi->pszText : emptyString);
00151             if (fUnicode)
00152                 Str_SetPtrW(&lpItem->pszText, pszText);
00153             else
00154                 Str_SetPtrAtoW(&lpItem->pszText, (LPCSTR)pszText);
00155             lpItem->callbackMask &= ~HDI_TEXT;
00156         }
00157         else
00158         {
00159             lpItem->pszText = NULL;
00160             lpItem->callbackMask |= HDI_TEXT;
00161         }  
00162     }
00163 }
00164 
00165 static inline LRESULT
00166 HEADER_IndexToOrder (const HEADER_INFO *infoPtr, INT iItem)
00167 {
00168     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
00169     return lpItem->iOrder;
00170 }
00171 
00172 
00173 static INT
00174 HEADER_OrderToIndex(const HEADER_INFO *infoPtr, INT iorder)
00175 {
00176     if ((iorder <0) || iorder >= infoPtr->uNumItem)
00177       return iorder;
00178     return infoPtr->order[iorder];
00179 }
00180 
00181 static void
00182 HEADER_ChangeItemOrder(const HEADER_INFO *infoPtr, INT iItem, INT iNewOrder)
00183 {
00184     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
00185     INT i, nMin, nMax;
00186 
00187     TRACE("%d: %d->%d\n", iItem, lpItem->iOrder, iNewOrder);
00188     if (lpItem->iOrder < iNewOrder)
00189     {
00190         memmove(&infoPtr->order[lpItem->iOrder],
00191                &infoPtr->order[lpItem->iOrder + 1],
00192                (iNewOrder - lpItem->iOrder) * sizeof(INT));
00193     }
00194     if (iNewOrder < lpItem->iOrder)
00195     {
00196         memmove(&infoPtr->order[iNewOrder + 1],
00197                 &infoPtr->order[iNewOrder],
00198                 (lpItem->iOrder - iNewOrder) * sizeof(INT));
00199     }
00200     infoPtr->order[iNewOrder] = iItem;
00201     nMin = min(lpItem->iOrder, iNewOrder);
00202     nMax = max(lpItem->iOrder, iNewOrder);
00203     for (i = nMin; i <= nMax; i++)
00204         infoPtr->items[infoPtr->order[i]].iOrder = i;
00205 }
00206 
00207 /* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
00208 static INT
00209 HEADER_NextItem(const HEADER_INFO *infoPtr, INT iItem)
00210 {
00211     return HEADER_OrderToIndex(infoPtr, HEADER_IndexToOrder(infoPtr, iItem)+1);
00212 }
00213 
00214 static INT
00215 HEADER_PrevItem(const HEADER_INFO *infoPtr, INT iItem)
00216 {
00217     return HEADER_OrderToIndex(infoPtr, HEADER_IndexToOrder(infoPtr, iItem)-1);
00218 }
00219 
00220 /* TRUE when item is not resizable with dividers,
00221    note that valid index should be supplied */
00222 static inline BOOL
00223 HEADER_IsItemFixed(const HEADER_INFO *infoPtr, INT iItem)
00224 {
00225     return (infoPtr->dwStyle & HDS_NOSIZING) || (infoPtr->items[iItem].fmt & HDF_FIXEDWIDTH);
00226 }
00227 
00228 static void
00229 HEADER_SetItemBounds (HEADER_INFO *infoPtr)
00230 {
00231     HEADER_ITEM *phdi;
00232     RECT rect;
00233     unsigned int i;
00234     int x;
00235 
00236     infoPtr->bRectsValid = TRUE;
00237 
00238     if (infoPtr->uNumItem == 0)
00239         return;
00240 
00241     GetClientRect (infoPtr->hwndSelf, &rect);
00242 
00243     x = rect.left;
00244     for (i = 0; i < infoPtr->uNumItem; i++) {
00245         phdi = &infoPtr->items[HEADER_OrderToIndex(infoPtr,i)];
00246         phdi->rect.top = rect.top;
00247         phdi->rect.bottom = rect.bottom;
00248         phdi->rect.left = x;
00249         phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0);
00250         x = phdi->rect.right;
00251     }
00252 }
00253 
00254 static LRESULT
00255 HEADER_Size (HEADER_INFO *infoPtr)
00256 {
00257     HEADER_SetItemBounds(infoPtr);
00258     return 0;
00259 }
00260 
00261 static void HEADER_GetHotDividerRect(const HEADER_INFO *infoPtr, RECT *r)
00262 {
00263     INT iDivider = infoPtr->iHotDivider;
00264     if (infoPtr->uNumItem > 0)
00265     {
00266         HEADER_ITEM *lpItem;
00267         
00268         if (iDivider < infoPtr->uNumItem)
00269         {
00270             lpItem = &infoPtr->items[iDivider];
00271             r->left  = lpItem->rect.left - HOT_DIVIDER_WIDTH/2;
00272             r->right = lpItem->rect.left + HOT_DIVIDER_WIDTH/2;
00273         }
00274         else
00275         {
00276             lpItem = &infoPtr->items[HEADER_OrderToIndex(infoPtr, infoPtr->uNumItem-1)];
00277             r->left  = lpItem->rect.right - HOT_DIVIDER_WIDTH/2;
00278             r->right = lpItem->rect.right + HOT_DIVIDER_WIDTH/2;
00279         }
00280         r->top    = lpItem->rect.top;
00281         r->bottom = lpItem->rect.bottom;
00282     }
00283     else
00284     {
00285         RECT clientRect;
00286         GetClientRect(infoPtr->hwndSelf, &clientRect);
00287         *r = clientRect;
00288         r->right = r->left + HOT_DIVIDER_WIDTH/2;
00289     }
00290 }
00291 
00292 
00293 static INT
00294 HEADER_DrawItem (HEADER_INFO *infoPtr, HDC hdc, INT iItem, BOOL bHotTrack, LRESULT lCDFlags)
00295 {
00296     HEADER_ITEM *phdi = &infoPtr->items[iItem];
00297     RECT r;
00298     INT  oldBkMode;
00299     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
00300     NMCUSTOMDRAW nmcd;
00301 
00302     TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, (infoPtr->nNotifyFormat == NFR_UNICODE));
00303 
00304     r = phdi->rect;
00305     if (r.right - r.left == 0)
00306     return phdi->rect.right;
00307 
00308     /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
00309     SetTextColor(hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
00310     SetBkColor(hdc, comctl32_color.clr3dFace);
00311 
00312     if (lCDFlags & CDRF_NOTIFYITEMDRAW && !(phdi->fmt & HDF_OWNERDRAW))
00313     {
00314         LRESULT lCDItemFlags;
00315 
00316         nmcd.dwDrawStage  = CDDS_PREPAINT | CDDS_ITEM;
00317         nmcd.hdc          = hdc;
00318         nmcd.dwItemSpec   = iItem;
00319         nmcd.rc           = r;
00320         nmcd.uItemState   = phdi->bDown ? CDIS_SELECTED : 0;
00321         nmcd.lItemlParam  = phdi->lParam;
00322 
00323         lCDItemFlags = HEADER_SendNotify(infoPtr, NM_CUSTOMDRAW, (NMHDR *)&nmcd);
00324         if (lCDItemFlags & CDRF_SKIPDEFAULT)
00325             return phdi->rect.right;
00326     }
00327 
00328     if (theme != NULL) {
00329         int state = (phdi->bDown) ? HIS_PRESSED :
00330             (bHotTrack ? HIS_HOT : HIS_NORMAL);
00331         DrawThemeBackground (theme, hdc, HP_HEADERITEM, state,
00332             &r, NULL);
00333         GetThemeBackgroundContentRect (theme, hdc, HP_HEADERITEM, state,
00334             &r, &r);
00335     }
00336     else {
00337         HBRUSH hbr;
00338 
00339         if (!(infoPtr->dwStyle & HDS_FLAT))
00340         {
00341             if (infoPtr->dwStyle & HDS_BUTTONS) {
00342                 if (phdi->bDown) {
00343                     DrawEdge (hdc, &r, BDR_RAISEDOUTER,
00344                                 BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST);
00345                 }
00346                 else
00347                     DrawEdge (hdc, &r, EDGE_RAISED,
00348                                 BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
00349             }
00350             else
00351                 DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
00352         }
00353 
00354         hbr = CreateSolidBrush(GetBkColor(hdc));
00355         FillRect(hdc, &r, hbr);
00356         DeleteObject(hbr);
00357     }
00358     if (phdi->bDown) {
00359         r.left += 2;
00360         r.top  += 2;
00361     }
00362 
00363     if (phdi->fmt & HDF_OWNERDRAW) {
00364     DRAWITEMSTRUCT dis;
00365 
00366     dis.CtlType    = ODT_HEADER;
00367     dis.CtlID      = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
00368     dis.itemID     = iItem;
00369     dis.itemAction = ODA_DRAWENTIRE;
00370     dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
00371     dis.hwndItem   = infoPtr->hwndSelf;
00372     dis.hDC        = hdc;
00373     dis.rcItem     = phdi->rect;
00374     dis.itemData   = phdi->lParam;
00375         oldBkMode = SetBkMode(hdc, TRANSPARENT);
00376         SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
00377         if (oldBkMode != TRANSPARENT)
00378             SetBkMode(hdc, oldBkMode);
00379     }
00380     else {
00381     UINT rw, rh, /* width and height of r */
00382          *x = NULL, *w = NULL; /* x and width of the pic (bmp or img) which is part of cnt */
00383       /* cnt,txt,img,bmp */
00384     UINT cx, tx, ix, bx,
00385          cw, tw, iw, bw;
00386         INT img_cx, img_cy;
00387     BITMAP bmp;
00388 
00389         HEADER_PrepareCallbackItems(infoPtr, iItem, HDI_TEXT|HDI_IMAGE);
00390     cw = tw = iw = bw = 0;
00391     rw = r.right - r.left;
00392     rh = r.bottom - r.top;
00393 
00394     if (phdi->fmt & HDF_STRING) {
00395         RECT textRect;
00396 
00397             SetRectEmpty(&textRect);
00398         DrawTextW (hdc, phdi->pszText, -1,
00399                    &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
00400         cw = textRect.right - textRect.left + 2 * infoPtr->iMargin;
00401     }
00402 
00403     if ((phdi->fmt & HDF_IMAGE) && ImageList_GetIconSize( infoPtr->himl, &img_cx, &img_cy )) {
00404         iw = img_cx + 2 * infoPtr->iMargin;
00405         x = &ix;
00406         w = &iw;
00407     }
00408 
00409     if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) {
00410             GetObjectW (phdi->hbm, sizeof(BITMAP), &bmp);
00411         bw = bmp.bmWidth + 2 * infoPtr->iMargin;
00412         if (!iw) {
00413         x = &bx;
00414         w = &bw;
00415         }
00416     }
00417 
00418     if (bw || iw)
00419         cw += *w; 
00420 
00421     /* align cx using the unclipped cw */
00422     if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT)
00423         cx = r.left;
00424     else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
00425         cx = r.left + rw / 2 - cw / 2;
00426     else /* HDF_RIGHT */
00427         cx = r.right - cw;
00428         
00429     /* clip cx & cw */
00430     if (cx < r.left)
00431         cx = r.left;
00432     if (cx + cw > r.right)
00433         cw = r.right - cx;
00434     
00435     tx = cx + infoPtr->iMargin;
00436     /* since cw might have changed we have to recalculate tw */
00437     tw = cw - infoPtr->iMargin * 2;
00438             
00439     if (iw || bw) {
00440         tw -= *w;
00441         if (phdi->fmt & HDF_BITMAP_ON_RIGHT) {
00442         /* put pic behind text */
00443         *x = cx + tw + infoPtr->iMargin * 3;
00444         } else {
00445         *x = cx + infoPtr->iMargin;
00446         /* move text behind pic */
00447         tx += *w;
00448         }
00449     }
00450 
00451     if (iw && bw) {
00452         /* since we're done with the layout we can
00453            now calculate the position of bmp which
00454            has no influence on alignment and layout
00455            because of img */
00456         if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
00457             bx = cx - bw + infoPtr->iMargin;
00458         else
00459             bx = cx + cw + infoPtr->iMargin;
00460     }
00461 
00462     if (iw || bw) {
00463         HDC hClipDC = GetDC(infoPtr->hwndSelf);
00464         HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
00465         SelectClipRgn(hClipDC, hClipRgn);
00466         
00467         if (bw) {
00468             HDC hdcBitmap = CreateCompatibleDC (hClipDC);
00469             SelectObject (hdcBitmap, phdi->hbm);
00470             BitBlt (hClipDC, bx, r.top + ((INT)rh - bmp.bmHeight) / 2, 
00471                 bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
00472             DeleteDC (hdcBitmap);
00473         }
00474 
00475         if (iw) {
00476             ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, 
00477                               ix, r.top + ((INT)rh - img_cy) / 2,
00478                               img_cx, img_cy, CLR_DEFAULT, CLR_DEFAULT, 0);
00479         }
00480 
00481         DeleteObject(hClipRgn);
00482         ReleaseDC(infoPtr->hwndSelf, hClipDC);
00483     }
00484         
00485     if (((phdi->fmt & HDF_STRING)
00486         || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP|
00487                    HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */
00488         && (phdi->pszText)) {
00489         oldBkMode = SetBkMode(hdc, TRANSPARENT);
00490         r.left  = tx;
00491         r.right = tx + tw;
00492         DrawTextW (hdc, phdi->pszText, -1,
00493                    &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE);
00494         if (oldBkMode != TRANSPARENT)
00495             SetBkMode(hdc, oldBkMode);
00496         }
00497         HEADER_FreeCallbackItems(phdi);
00498     }/*Ownerdrawn*/
00499 
00500     return phdi->rect.right;
00501 }
00502 
00503 static void
00504 HEADER_DrawHotDivider(const HEADER_INFO *infoPtr, HDC hdc)
00505 {
00506     HBRUSH brush;
00507     RECT r;
00508     
00509     HEADER_GetHotDividerRect(infoPtr, &r);
00510     brush = CreateSolidBrush(comctl32_color.clrHighlight);
00511     FillRect(hdc, &r, brush);
00512     DeleteObject(brush);
00513 }
00514 
00515 static void
00516 HEADER_Refresh (HEADER_INFO *infoPtr, HDC hdc)
00517 {
00518     HFONT hFont, hOldFont;
00519     RECT rect, rcRest;
00520     HBRUSH hbrBk;
00521     UINT i;
00522     INT x;
00523     LRESULT lCDFlags;
00524     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
00525 
00526     if (!infoPtr->bRectsValid)
00527         HEADER_SetItemBounds(infoPtr);
00528 
00529     /* get rect for the bar, adjusted for the border */
00530     GetClientRect (infoPtr->hwndSelf, &rect);
00531     lCDFlags = HEADER_SendCtrlCustomDraw(infoPtr, CDDS_PREPAINT, hdc, &rect);
00532     
00533     if (infoPtr->bDragging)
00534     ImageList_DragShowNolock(FALSE);
00535 
00536     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
00537     hOldFont = SelectObject (hdc, hFont);
00538 
00539     /* draw Background */
00540     if (infoPtr->uNumItem == 0 && theme == NULL) {
00541         hbrBk = GetSysColorBrush(COLOR_3DFACE);
00542         FillRect(hdc, &rect, hbrBk);
00543     }
00544 
00545     x = rect.left;
00546     for (i = 0; x <= rect.right && i < infoPtr->uNumItem; i++) {
00547         int idx = HEADER_OrderToIndex(infoPtr,i);
00548         if (RectVisible(hdc, &infoPtr->items[idx].rect))
00549             HEADER_DrawItem(infoPtr, hdc, idx, infoPtr->iHotItem == idx, lCDFlags);
00550         x = infoPtr->items[idx].rect.right;
00551     }
00552 
00553     rcRest = rect;
00554     rcRest.left = x;
00555     if ((x <= rect.right) && RectVisible(hdc, &rcRest) && (infoPtr->uNumItem > 0)) {
00556         if (theme != NULL) {
00557             DrawThemeBackground(theme, hdc, HP_HEADERITEM, HIS_NORMAL, &rcRest, NULL);
00558         }
00559         else if (infoPtr->dwStyle & HDS_FLAT) {
00560             hbrBk = GetSysColorBrush(COLOR_3DFACE);
00561             FillRect(hdc, &rcRest, hbrBk);
00562         }
00563         else
00564         {
00565             if (infoPtr->dwStyle & HDS_BUTTONS)
00566                 DrawEdge (hdc, &rcRest, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT|BF_MIDDLE);
00567             else
00568                 DrawEdge (hdc, &rcRest, EDGE_ETCHED, BF_BOTTOM|BF_MIDDLE);
00569         }
00570     }
00571 
00572     if (infoPtr->iHotDivider != -1)
00573         HEADER_DrawHotDivider(infoPtr, hdc);
00574 
00575     if (infoPtr->bDragging)
00576     ImageList_DragShowNolock(TRUE);
00577     SelectObject (hdc, hOldFont);
00578     
00579     if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
00580         HEADER_SendCtrlCustomDraw(infoPtr, CDDS_POSTPAINT, hdc, &rect);
00581 }
00582 
00583 
00584 static void
00585 HEADER_RefreshItem (HEADER_INFO *infoPtr, INT iItem)
00586 {
00587     if (!infoPtr->bRectsValid)
00588         HEADER_SetItemBounds(infoPtr);
00589 
00590     InvalidateRect(infoPtr->hwndSelf, &infoPtr->items[iItem].rect, FALSE);
00591 }
00592 
00593 
00594 static void
00595 HEADER_InternalHitTest (const HEADER_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pItem)
00596 {
00597     RECT rect, rcTest;
00598     UINT iCount;
00599     INT width;
00600     BOOL bNoWidth;
00601 
00602     GetClientRect (infoPtr->hwndSelf, &rect);
00603 
00604     *pFlags = 0;
00605     bNoWidth = FALSE;
00606     if (PtInRect (&rect, *lpPt))
00607     {
00608     if (infoPtr->uNumItem == 0) {
00609         *pFlags |= HHT_NOWHERE;
00610         *pItem = 1;
00611         TRACE("NOWHERE\n");
00612         return;
00613     }
00614     else {
00615         /* somewhere inside */
00616         for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
00617         rect = infoPtr->items[iCount].rect;
00618         width = rect.right - rect.left;
00619         if (width == 0) {
00620             bNoWidth = TRUE;
00621             continue;
00622         }
00623         if (PtInRect (&rect, *lpPt)) {
00624             if (width <= 2 * DIVIDER_WIDTH) {
00625             *pFlags |= HHT_ONHEADER;
00626             *pItem = iCount;
00627             TRACE("ON HEADER %d\n", iCount);
00628             return;
00629             }
00630                     if (HEADER_IndexToOrder(infoPtr, iCount) > 0) {
00631             rcTest = rect;
00632             rcTest.right = rcTest.left + DIVIDER_WIDTH;
00633             if (PtInRect (&rcTest, *lpPt)) {
00634                 if (HEADER_IsItemFixed(infoPtr, HEADER_PrevItem(infoPtr, iCount)))
00635                 {
00636                 *pFlags |= HHT_ONHEADER;
00637                                 *pItem = iCount;
00638                 TRACE("ON HEADER %d\n", *pItem);
00639                 return;
00640                 }
00641                 if (bNoWidth) {
00642                 *pFlags |= HHT_ONDIVOPEN;
00643                                 *pItem = HEADER_PrevItem(infoPtr, iCount);
00644                 TRACE("ON DIVOPEN %d\n", *pItem);
00645                 return;
00646                 }
00647                 else {
00648                 *pFlags |= HHT_ONDIVIDER;
00649                                 *pItem = HEADER_PrevItem(infoPtr, iCount);
00650                 TRACE("ON DIVIDER %d\n", *pItem);
00651                 return;
00652                 }
00653             }
00654             }
00655             rcTest = rect;
00656             rcTest.left = rcTest.right - DIVIDER_WIDTH;
00657             if (!HEADER_IsItemFixed(infoPtr, iCount) && PtInRect (&rcTest, *lpPt))
00658             {
00659             *pFlags |= HHT_ONDIVIDER;
00660             *pItem = iCount;
00661             TRACE("ON DIVIDER %d\n", *pItem);
00662             return;
00663             }
00664 
00665             *pFlags |= HHT_ONHEADER;
00666             *pItem = iCount;
00667             TRACE("ON HEADER %d\n", iCount);
00668             return;
00669         }
00670         }
00671 
00672         /* check for last divider part (on nowhere) */
00673         if (!HEADER_IsItemFixed(infoPtr, infoPtr->uNumItem - 1))
00674         {
00675         rect = infoPtr->items[infoPtr->uNumItem-1].rect;
00676         rect.left = rect.right;
00677         rect.right += DIVIDER_WIDTH;
00678         if (PtInRect (&rect, *lpPt)) {
00679             if (bNoWidth) {
00680             *pFlags |= HHT_ONDIVOPEN;
00681             *pItem = infoPtr->uNumItem - 1;
00682             TRACE("ON DIVOPEN %d\n", *pItem);
00683             return;
00684             }
00685             else {
00686             *pFlags |= HHT_ONDIVIDER;
00687             *pItem = infoPtr->uNumItem - 1;
00688             TRACE("ON DIVIDER %d\n", *pItem);
00689             return;
00690             }
00691         }
00692         }
00693 
00694         *pFlags |= HHT_NOWHERE;
00695         *pItem = 1;
00696         TRACE("NOWHERE\n");
00697         return;
00698     }
00699     }
00700     else {
00701     if (lpPt->x < rect.left) {
00702        TRACE("TO LEFT\n");
00703        *pFlags |= HHT_TOLEFT;
00704     }
00705     else if (lpPt->x > rect.right) {
00706         TRACE("TO RIGHT\n");
00707         *pFlags |= HHT_TORIGHT;
00708     }
00709 
00710     if (lpPt->y < rect.top) {
00711         TRACE("ABOVE\n");
00712         *pFlags |= HHT_ABOVE;
00713     }
00714     else if (lpPt->y > rect.bottom) {
00715         TRACE("BELOW\n");
00716         *pFlags |= HHT_BELOW;
00717     }
00718     }
00719 
00720     *pItem = 1;
00721     TRACE("flags=0x%X\n", *pFlags);
00722     return;
00723 }
00724 
00725 
00726 static void
00727 HEADER_DrawTrackLine (const HEADER_INFO *infoPtr, HDC hdc, INT x)
00728 {
00729     RECT rect;
00730     HPEN hOldPen;
00731     INT  oldRop;
00732 
00733     GetClientRect (infoPtr->hwndSelf, &rect);
00734 
00735     hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN));
00736     oldRop = SetROP2 (hdc, R2_XORPEN);
00737     MoveToEx (hdc, x, rect.top, NULL);
00738     LineTo (hdc, x, rect.bottom);
00739     SetROP2 (hdc, oldRop);
00740     SelectObject (hdc, hOldPen);
00741 }
00742 
00743 /***
00744  * DESCRIPTION:
00745  * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
00746  *
00747  * PARAMETER(S):
00748  * [I] infoPtr : the header that wants to send the notify
00749  * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
00750  * [I] src  : The source HDITEM. It may be a HDITEMA or HDITEMW
00751  * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
00752  * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
00753  *                  the HDITEM is no longer in use or NULL if none was needed
00754  * 
00755  * NOTE: We depend on HDITEMA and HDITEMW having the same structure
00756  */
00757 static void HEADER_CopyHDItemForNotify(const HEADER_INFO *infoPtr, HDITEMW *dest,
00758     const HDITEMW *src, BOOL fSourceUnicode, LPVOID *ppvScratch)
00759 {
00760     *ppvScratch = NULL;
00761     *dest = *src;
00762     
00763     if (src->mask & HDI_TEXT && src->pszText != LPSTR_TEXTCALLBACKW) /* covers TEXTCALLBACKA as well */
00764     {
00765         if (fSourceUnicode && infoPtr->nNotifyFormat != NFR_UNICODE)
00766         {
00767             dest->pszText = NULL;
00768             Str_SetPtrWtoA((LPSTR *)&dest->pszText, src->pszText);
00769             *ppvScratch = dest->pszText;
00770         }
00771         
00772         if (!fSourceUnicode && infoPtr->nNotifyFormat == NFR_UNICODE)
00773         {
00774             dest->pszText = NULL;
00775             Str_SetPtrAtoW(&dest->pszText, (LPSTR)src->pszText);
00776             *ppvScratch = dest->pszText;
00777         }
00778     }
00779 }
00780 
00781 static UINT HEADER_NotifyCodeWtoA(UINT code)
00782 {
00783     /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
00784     if (code >= HDN_LAST && code <= HDN_FIRST_UNICODE)
00785         return code + HDN_UNICODE_OFFSET;
00786     else
00787         return code;
00788 }
00789 
00790 static LRESULT
00791 HEADER_SendNotify(const HEADER_INFO *infoPtr, UINT code, NMHDR *nmhdr)
00792 {
00793     nmhdr->hwndFrom = infoPtr->hwndSelf;
00794     nmhdr->idFrom   = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
00795     nmhdr->code     = code;
00796 
00797     return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
00798                    nmhdr->idFrom, (LPARAM)nmhdr);
00799 }
00800 
00801 static BOOL
00802 HEADER_SendSimpleNotify (const HEADER_INFO *infoPtr, UINT code)
00803 {
00804     NMHDR nmhdr;
00805     return (BOOL)HEADER_SendNotify(infoPtr, code, &nmhdr);
00806 }
00807 
00808 static LRESULT
00809 HEADER_SendCtrlCustomDraw(const HEADER_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, const RECT *rect)
00810 {
00811     NMCUSTOMDRAW nm;
00812     nm.dwDrawStage = dwDrawStage;
00813     nm.hdc = hdc;
00814     nm.rc = *rect;
00815     nm.dwItemSpec = 0;
00816     nm.uItemState = 0;
00817     nm.lItemlParam = 0;
00818 
00819     return HEADER_SendNotify(infoPtr, NM_CUSTOMDRAW, (NMHDR *)&nm);
00820 }
00821 
00822 static BOOL
00823 HEADER_SendNotifyWithHDItemT(const HEADER_INFO *infoPtr, UINT code, INT iItem, HDITEMW *lpItem)
00824 {
00825     NMHEADERW nmhdr;
00826     
00827     if (infoPtr->nNotifyFormat != NFR_UNICODE)
00828         code = HEADER_NotifyCodeWtoA(code);
00829     nmhdr.iItem = iItem;
00830     nmhdr.iButton = 0;
00831     nmhdr.pitem = lpItem;
00832 
00833     return (BOOL)HEADER_SendNotify(infoPtr, code, (NMHDR *)&nmhdr);
00834 }
00835 
00836 static BOOL
00837 HEADER_SendNotifyWithIntFieldT(const HEADER_INFO *infoPtr, UINT code, INT iItem, INT mask, INT iValue)
00838 {
00839     HDITEMW nmitem;
00840 
00841     /* copying only the iValue should be ok but to make the code more robust we copy everything */
00842     nmitem.cxy = infoPtr->items[iItem].cxy;
00843     nmitem.hbm = infoPtr->items[iItem].hbm;
00844     nmitem.pszText = NULL;
00845     nmitem.cchTextMax = 0;
00846     nmitem.fmt = infoPtr->items[iItem].fmt;
00847     nmitem.lParam = infoPtr->items[iItem].lParam;
00848     nmitem.iOrder = infoPtr->items[iItem].iOrder;
00849     nmitem.iImage = infoPtr->items[iItem].iImage;
00850 
00851     nmitem.mask = mask;
00852     switch (mask)
00853     {
00854     case HDI_WIDTH:
00855         nmitem.cxy = iValue;
00856         break;
00857     case HDI_ORDER:
00858         nmitem.iOrder = iValue;
00859         break;
00860     default:
00861         ERR("invalid mask value 0x%x\n", iValue);
00862     }
00863 
00864     return HEADER_SendNotifyWithHDItemT(infoPtr, code, iItem, &nmitem);
00865 }
00866 
00882 static BOOL
00883 HEADER_PrepareCallbackItems(const HEADER_INFO *infoPtr, INT iItem, INT reqMask)
00884 {
00885     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
00886     DWORD mask = reqMask & lpItem->callbackMask;
00887     NMHDDISPINFOW dispInfo;
00888     void *pvBuffer = NULL;
00889 
00890     if (mask == 0)
00891         return TRUE;
00892     if (mask&HDI_TEXT && lpItem->pszText != NULL)
00893     {
00894         ERR("(): function called without a call to FreeCallbackItems\n");
00895         Free(lpItem->pszText);
00896         lpItem->pszText = NULL;
00897     }
00898     
00899     memset(&dispInfo, 0, sizeof(NMHDDISPINFOW));
00900     dispInfo.hdr.hwndFrom = infoPtr->hwndSelf;
00901     dispInfo.hdr.idFrom   = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
00902     if (infoPtr->nNotifyFormat == NFR_UNICODE)
00903     {
00904         dispInfo.hdr.code = HDN_GETDISPINFOW;
00905         if (mask & HDI_TEXT)
00906             pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(WCHAR));
00907     }
00908     else
00909     {
00910         dispInfo.hdr.code = HDN_GETDISPINFOA;
00911         if (mask & HDI_TEXT)
00912             pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(CHAR));
00913     }
00914     dispInfo.pszText      = pvBuffer;
00915     dispInfo.cchTextMax   = (pvBuffer!=NULL?MAX_HEADER_TEXT_LEN:0);
00916     dispInfo.iItem        = iItem;
00917     dispInfo.mask         = mask;
00918     dispInfo.lParam       = lpItem->lParam;
00919     
00920     TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr->nNotifyFormat == NFR_UNICODE?'W':'A');
00921     SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, dispInfo.hdr.idFrom, (LPARAM)&dispInfo);
00922 
00923     TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n", 
00924           dispInfo.mask,
00925           (infoPtr->nNotifyFormat == NFR_UNICODE ? debugstr_w(dispInfo.pszText) : (LPSTR) dispInfo.pszText),
00926           (void*) dispInfo.lParam);
00927           
00928     if (mask & HDI_IMAGE)
00929         lpItem->iImage = dispInfo.iImage;
00930     if (mask & HDI_TEXT)
00931     {
00932         if (infoPtr->nNotifyFormat == NFR_UNICODE)
00933         {
00934             lpItem->pszText = pvBuffer;
00935 
00936             /* the user might have used his own buffer */
00937             if (dispInfo.pszText != lpItem->pszText)
00938                 Str_GetPtrW(dispInfo.pszText, lpItem->pszText, MAX_HEADER_TEXT_LEN);
00939         }
00940         else
00941         {
00942             Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)dispInfo.pszText);
00943             Free(pvBuffer);
00944         }
00945     }
00946         
00947     if (dispInfo.mask & HDI_DI_SETITEM) 
00948     {
00949         /* make the items permanent */
00950         lpItem->callbackMask &= ~dispInfo.mask;
00951     }
00952     
00953     return TRUE;
00954 }
00955 
00956 /***
00957  * DESCRIPTION:
00958  * Free the items that might be allocated with HEADER_PrepareCallbackItems
00959  *
00960  * PARAMETER(S):
00961  * [I] lpItem : the item to free the data
00962  *
00963  */
00964 static void
00965 HEADER_FreeCallbackItems(HEADER_ITEM *lpItem)
00966 {
00967     if (lpItem->callbackMask&HDI_TEXT)
00968     {
00969         Free(lpItem->pszText);
00970         lpItem->pszText = NULL;
00971     }
00972 
00973     if (lpItem->callbackMask&HDI_IMAGE)
00974         lpItem->iImage = I_IMAGECALLBACK;
00975 }
00976 
00977 static LRESULT
00978 HEADER_CreateDragImage (HEADER_INFO *infoPtr, INT iItem)
00979 {
00980     HEADER_ITEM *lpItem;
00981     HIMAGELIST himl;
00982     HBITMAP hMemory, hOldBitmap;
00983     LRESULT lCDFlags;
00984     RECT rc;
00985     HDC hMemoryDC;
00986     HDC hDeviceDC;
00987     int height, width;
00988     HFONT hFont;
00989     
00990     if (iItem >= infoPtr->uNumItem)
00991         return FALSE;
00992 
00993     if (!infoPtr->bRectsValid)
00994         HEADER_SetItemBounds(infoPtr);
00995 
00996     lpItem = &infoPtr->items[iItem];
00997     width = lpItem->rect.right - lpItem->rect.left;
00998     height = lpItem->rect.bottom - lpItem->rect.top;
00999     
01000     hDeviceDC = GetDC(NULL);
01001     hMemoryDC = CreateCompatibleDC(hDeviceDC);
01002     hMemory = CreateCompatibleBitmap(hDeviceDC, width, height);
01003     ReleaseDC(NULL, hDeviceDC);
01004     hOldBitmap = SelectObject(hMemoryDC, hMemory);
01005     SetViewportOrgEx(hMemoryDC, -lpItem->rect.left, -lpItem->rect.top, NULL);
01006     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject(SYSTEM_FONT);
01007     SelectObject(hMemoryDC, hFont);
01008 
01009     GetClientRect(infoPtr->hwndSelf, &rc);
01010     lCDFlags = HEADER_SendCtrlCustomDraw(infoPtr, CDDS_PREPAINT, hMemoryDC, &rc);
01011     HEADER_DrawItem(infoPtr, hMemoryDC, iItem, FALSE, lCDFlags);
01012     if (lCDFlags & CDRF_NOTIFYPOSTPAINT)
01013         HEADER_SendCtrlCustomDraw(infoPtr, CDDS_POSTPAINT, hMemoryDC, &rc);
01014     
01015     hMemory = SelectObject(hMemoryDC, hOldBitmap);
01016     DeleteDC(hMemoryDC);
01017     
01018     if (hMemory == NULL)    /* if anything failed */
01019         return FALSE;
01020     
01021     himl = ImageList_Create(width, height, ILC_COLORDDB, 1, 1);
01022     ImageList_Add(himl, hMemory, NULL);
01023     DeleteObject(hMemory);
01024     return (LRESULT)himl;
01025 }
01026 
01027 static LRESULT
01028 HEADER_SetHotDivider(HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
01029 {
01030     INT iDivider;
01031     RECT r;
01032     
01033     if (wParam)
01034     {
01035         POINT pt;
01036         UINT flags;
01037         pt.x = (INT)(SHORT)LOWORD(lParam);
01038         pt.y = 0;
01039         HEADER_InternalHitTest (infoPtr, &pt, &flags, &iDivider);
01040         
01041         if (flags & HHT_TOLEFT)
01042             iDivider = 0;
01043         else if (flags & HHT_NOWHERE || flags & HHT_TORIGHT)
01044             iDivider = infoPtr->uNumItem;
01045         else
01046         {
01047             HEADER_ITEM *lpItem = &infoPtr->items[iDivider];
01048             if (pt.x > (lpItem->rect.left+lpItem->rect.right)/2)
01049                 iDivider = HEADER_NextItem(infoPtr, iDivider);
01050         }
01051     }
01052     else
01053         iDivider = (INT)lParam;
01054         
01055     /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */
01056     if (iDivider<-1 || iDivider>(int)infoPtr->uNumItem)
01057         return iDivider;
01058 
01059     if (iDivider != infoPtr->iHotDivider)
01060     {
01061         if (infoPtr->iHotDivider != -1)
01062         {
01063             HEADER_GetHotDividerRect(infoPtr, &r);
01064             InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
01065         }
01066         infoPtr->iHotDivider = iDivider;
01067         if (iDivider != -1)
01068         {
01069             HEADER_GetHotDividerRect(infoPtr, &r);
01070             InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
01071         }
01072     }
01073     return iDivider;
01074 }
01075 
01076 static LRESULT
01077 HEADER_DeleteItem (HEADER_INFO *infoPtr, INT iItem)
01078 {
01079     INT iOrder;
01080     UINT i;
01081 
01082     TRACE("[iItem=%d]\n", iItem);
01083 
01084     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
01085         return FALSE;
01086 
01087     for (i = 0; i < infoPtr->uNumItem; i++)
01088        TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
01089 
01090     iOrder = infoPtr->items[iItem].iOrder;
01091     Free(infoPtr->items[iItem].pszText);
01092 
01093     infoPtr->uNumItem--;
01094     memmove(&infoPtr->items[iItem], &infoPtr->items[iItem + 1],
01095             (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM));
01096     memmove(&infoPtr->order[iOrder], &infoPtr->order[iOrder + 1],
01097             (infoPtr->uNumItem - iOrder) * sizeof(INT));
01098     infoPtr->items = ReAlloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem);
01099     infoPtr->order = ReAlloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem);
01100         
01101     /* Correct the orders */
01102     for (i = 0; i < infoPtr->uNumItem; i++)
01103     {
01104         if (infoPtr->order[i] > iItem)
01105             infoPtr->order[i]--;
01106         if (i >= iOrder)
01107             infoPtr->items[infoPtr->order[i]].iOrder = i;
01108     }
01109     for (i = 0; i < infoPtr->uNumItem; i++)
01110        TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
01111 
01112     HEADER_SetItemBounds (infoPtr);
01113     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
01114 
01115     return TRUE;
01116 }
01117 
01118 
01119 static LRESULT
01120 HEADER_GetImageList (const HEADER_INFO *infoPtr)
01121 {
01122     return (LRESULT)infoPtr->himl;
01123 }
01124 
01125 
01126 static LRESULT
01127 HEADER_GetItemT (const HEADER_INFO *infoPtr, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
01128 {
01129     HEADER_ITEM *lpItem;
01130     UINT mask;
01131 
01132     if (!phdi)
01133     return FALSE;
01134 
01135     TRACE("[nItem=%d]\n", nItem);
01136 
01137     mask = phdi->mask;
01138     if (mask == 0)
01139     return TRUE;
01140 
01141     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
01142         return FALSE;
01143 
01144     if (mask & HDI_UNKNOWN_FIELDS)
01145     {
01146         TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask);
01147         mask &= HDI_COMCTL32_4_0_FIELDS;
01148     }
01149     
01150     lpItem = &infoPtr->items[nItem];
01151     HEADER_PrepareCallbackItems(infoPtr, nItem, mask);
01152 
01153     if (mask & HDI_BITMAP)
01154         phdi->hbm = lpItem->hbm;
01155 
01156     if (mask & HDI_FORMAT)
01157         phdi->fmt = lpItem->fmt;
01158 
01159     if (mask & HDI_WIDTH)
01160         phdi->cxy = lpItem->cxy;
01161 
01162     if (mask & HDI_LPARAM)
01163         phdi->lParam = lpItem->lParam;
01164 
01165     if (mask & HDI_IMAGE) 
01166         phdi->iImage = lpItem->iImage;
01167 
01168     if (mask & HDI_ORDER)
01169         phdi->iOrder = lpItem->iOrder;
01170 
01171     if (mask & HDI_TEXT)
01172     {
01173         if (bUnicode)
01174             Str_GetPtrW (lpItem->pszText, phdi->pszText, phdi->cchTextMax);
01175         else
01176             Str_GetPtrWtoA (lpItem->pszText, (LPSTR)phdi->pszText, phdi->cchTextMax);
01177     }
01178 
01179     HEADER_FreeCallbackItems(lpItem);
01180     return TRUE;
01181 }
01182 
01183 
01184 static inline LRESULT
01185 HEADER_GetItemCount (const HEADER_INFO *infoPtr)
01186 {
01187     return infoPtr->uNumItem;
01188 }
01189 
01190 
01191 static LRESULT
01192 HEADER_GetItemRect (const HEADER_INFO *infoPtr, INT iItem, LPRECT lpRect)
01193 {
01194     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
01195         return FALSE;
01196 
01197     lpRect->left   = infoPtr->items[iItem].rect.left;
01198     lpRect->right  = infoPtr->items[iItem].rect.right;
01199     lpRect->top    = infoPtr->items[iItem].rect.top;
01200     lpRect->bottom = infoPtr->items[iItem].rect.bottom;
01201 
01202     return TRUE;
01203 }
01204 
01205 
01206 static LRESULT
01207 HEADER_GetOrderArray(const HEADER_INFO *infoPtr, INT size, LPINT order)
01208 {
01209     if ((UINT)size <infoPtr->uNumItem)
01210       return FALSE;
01211 
01212     memcpy(order, infoPtr->order, infoPtr->uNumItem * sizeof(INT));
01213     return TRUE;
01214 }
01215 
01216 /* Returns index of first duplicate 'value' from [0,to) range,
01217    or -1 if there isn't any */
01218 static INT has_duplicate(const INT *array, INT to, INT value)
01219 {
01220     INT i;
01221     for(i = 0; i < to; i++)
01222         if (array[i] == value) return i;
01223     return -1;
01224 }
01225 
01226 /* returns next available value from [0,max] not to duplicate in [0,to) */
01227 static INT get_nextvalue(const INT *array, INT to, INT max)
01228 {
01229     INT i;
01230     for(i = 0; i < max; i++)
01231         if (has_duplicate(array, to, i) == -1) return i;
01232     return 0;
01233 }
01234 
01235 static LRESULT
01236 HEADER_SetOrderArray(HEADER_INFO *infoPtr, INT size, const INT *order)
01237 {
01238     HEADER_ITEM *lpItem;
01239     INT i;
01240 
01241     if ((UINT)size != infoPtr->uNumItem)
01242       return FALSE;
01243 
01244     for (i=0; i<size; i++)
01245     {
01246         if (order[i] >= size || order[i] < 0)
01247            /* on invalid index get next available */
01248            /* FIXME: if i==0 array item is out of range behaviour is
01249                      different, see tests */
01250            infoPtr->order[i] = get_nextvalue(infoPtr->order, i, size);
01251         else
01252         {
01253            INT j, dup;
01254 
01255            infoPtr->order[i] = order[i];
01256            j = i;
01257            /* remove duplicates */
01258            while ((dup = has_duplicate(infoPtr->order, j, order[j])) != -1)
01259            {
01260                INT next;
01261 
01262                next = get_nextvalue(infoPtr->order, j, size);
01263                infoPtr->order[dup] = next;
01264                j--;
01265            }
01266         }
01267     }
01268     /* sync with item data */
01269     for (i=0; i<size; i++)
01270     {
01271         lpItem = &infoPtr->items[infoPtr->order[i]];
01272         lpItem->iOrder = i;
01273     }
01274     HEADER_SetItemBounds(infoPtr);
01275     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
01276     return TRUE;
01277 }
01278 
01279 static inline LRESULT
01280 HEADER_GetUnicodeFormat (const HEADER_INFO *infoPtr)
01281 {
01282     return (infoPtr->nNotifyFormat == NFR_UNICODE);
01283 }
01284 
01285 
01286 static LRESULT
01287 HEADER_HitTest (const HEADER_INFO *infoPtr, LPHDHITTESTINFO phti)
01288 {
01289     UINT outside = HHT_NOWHERE | HHT_ABOVE | HHT_BELOW | HHT_TOLEFT | HHT_TORIGHT;
01290 
01291     HEADER_InternalHitTest (infoPtr, &phti->pt, &phti->flags, &phti->iItem);
01292 
01293     if (phti->flags & outside)
01294     return phti->iItem = -1;
01295     else
01296         return phti->iItem;
01297 }
01298 
01299 
01300 static LRESULT
01301 HEADER_InsertItemT (HEADER_INFO *infoPtr, INT nItem, const HDITEMW *phdi, BOOL bUnicode)
01302 {
01303     HEADER_ITEM *lpItem;
01304     INT       iOrder;
01305     UINT      i;
01306     UINT      copyMask;
01307 
01308     if ((phdi == NULL) || (nItem < 0) || (phdi->mask == 0))
01309     return -1;
01310 
01311     if (nItem > infoPtr->uNumItem)
01312         nItem = infoPtr->uNumItem;
01313 
01314     iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem;
01315     if (iOrder < 0)
01316         iOrder = 0;
01317     else if (infoPtr->uNumItem < iOrder)
01318         iOrder = infoPtr->uNumItem;
01319 
01320     infoPtr->uNumItem++;
01321     infoPtr->items = ReAlloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem);
01322     infoPtr->order = ReAlloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem);
01323     
01324     /* make space for the new item */
01325     memmove(&infoPtr->items[nItem + 1], &infoPtr->items[nItem],
01326             (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM));
01327     memmove(&infoPtr->order[iOrder + 1], &infoPtr->order[iOrder],
01328            (infoPtr->uNumItem - iOrder - 1) * sizeof(INT));
01329 
01330     /* update the order array */
01331     infoPtr->order[iOrder] = nItem;
01332     for (i = 0; i < infoPtr->uNumItem; i++)
01333     {
01334         if (i != iOrder && infoPtr->order[i] >= nItem)
01335             infoPtr->order[i]++;
01336         infoPtr->items[infoPtr->order[i]].iOrder = i;
01337     }
01338 
01339     lpItem = &infoPtr->items[nItem];
01340     ZeroMemory(lpItem, sizeof(HEADER_ITEM));
01341     /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
01342     copyMask = phdi->mask | HDI_WIDTH | HDI_FORMAT | HDI_LPARAM;
01343     HEADER_StoreHDItemInHeader(lpItem, copyMask, phdi, bUnicode);
01344     lpItem->iOrder = iOrder;
01345 
01346     /* set automatically some format bits */
01347     if (phdi->mask & HDI_TEXT)
01348         lpItem->fmt |= HDF_STRING;
01349     else
01350         lpItem->fmt &= ~HDF_STRING;
01351 
01352     if (lpItem->hbm != NULL)
01353         lpItem->fmt |= HDF_BITMAP;
01354     else
01355         lpItem->fmt &= ~HDF_BITMAP;
01356 
01357     if (phdi->mask & HDI_IMAGE)
01358         lpItem->fmt |= HDF_IMAGE;
01359 
01360     HEADER_SetItemBounds (infoPtr);
01361     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
01362 
01363     return nItem;
01364 }
01365 
01366 
01367 static LRESULT
01368 HEADER_Layout (HEADER_INFO *infoPtr, LPHDLAYOUT lpLayout)
01369 {
01370     lpLayout->pwpos->hwnd = infoPtr->hwndSelf;
01371     lpLayout->pwpos->hwndInsertAfter = 0;
01372     lpLayout->pwpos->x = lpLayout->prc->left;
01373     lpLayout->pwpos->y = lpLayout->prc->top;
01374     lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
01375     if (infoPtr->dwStyle & HDS_HIDDEN)
01376         lpLayout->pwpos->cy = 0;
01377     else {
01378         lpLayout->pwpos->cy = infoPtr->nHeight;
01379         lpLayout->prc->top += infoPtr->nHeight;
01380     }
01381     lpLayout->pwpos->flags = SWP_NOZORDER;
01382 
01383     TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
01384            lpLayout->pwpos->x, lpLayout->pwpos->y,
01385            lpLayout->pwpos->cx, lpLayout->pwpos->cy);
01386 
01387     infoPtr->bRectsValid = FALSE;
01388 
01389     return TRUE;
01390 }
01391 
01392 
01393 static LRESULT
01394 HEADER_SetImageList (HEADER_INFO *infoPtr, HIMAGELIST himl)
01395 {
01396     HIMAGELIST himlOld;
01397 
01398     TRACE("(himl %p)\n", himl);
01399     himlOld = infoPtr->himl;
01400     infoPtr->himl = himl;
01401 
01402     /* FIXME: Refresh needed??? */
01403 
01404     return (LRESULT)himlOld;
01405 }
01406 
01407 
01408 static LRESULT
01409 HEADER_GetBitmapMargin(const HEADER_INFO *infoPtr)
01410 {
01411     return infoPtr->iMargin;
01412 }
01413 
01414 static LRESULT
01415 HEADER_SetBitmapMargin(HEADER_INFO *infoPtr, INT iMargin)
01416 {
01417     INT oldMargin = infoPtr->iMargin;
01418 
01419     infoPtr->iMargin = iMargin;
01420 
01421     return oldMargin;
01422 }
01423 
01424 static LRESULT
01425 HEADER_SetItemT (HEADER_INFO *infoPtr, INT nItem, const HDITEMW *phdi, BOOL bUnicode)
01426 {
01427     HEADER_ITEM *lpItem;
01428     HDITEMW hdNotify;
01429     void *pvScratch;
01430 
01431     if (phdi == NULL)
01432     return FALSE;
01433     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
01434         return FALSE;
01435 
01436     TRACE("[nItem=%d]\n", nItem);
01437 
01438     HEADER_CopyHDItemForNotify(infoPtr, &hdNotify, phdi, bUnicode, &pvScratch);
01439     if (HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCHANGINGW, nItem, &hdNotify))
01440     {
01441         Free(pvScratch);
01442     return FALSE;
01443     }
01444 
01445     lpItem = &infoPtr->items[nItem];
01446     HEADER_StoreHDItemInHeader(lpItem, phdi->mask, phdi, bUnicode);
01447 
01448     if (phdi->mask & HDI_ORDER)
01449         if (phdi->iOrder >= 0 && phdi->iOrder < infoPtr->uNumItem)
01450             HEADER_ChangeItemOrder(infoPtr, nItem, phdi->iOrder);
01451 
01452     HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCHANGEDW, nItem, &hdNotify);
01453 
01454     HEADER_SetItemBounds (infoPtr);
01455 
01456     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
01457 
01458     Free(pvScratch);
01459     return TRUE;
01460 }
01461 
01462 static inline LRESULT
01463 HEADER_SetUnicodeFormat (HEADER_INFO *infoPtr, WPARAM wParam)
01464 {
01465     BOOL bTemp = (infoPtr->nNotifyFormat == NFR_UNICODE);
01466 
01467     infoPtr->nNotifyFormat = ((BOOL)wParam ? NFR_UNICODE : NFR_ANSI);
01468 
01469     return bTemp;
01470 }
01471 
01472 
01473 static LRESULT
01474 HEADER_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
01475 {
01476     HEADER_INFO *infoPtr;
01477     TEXTMETRICW tm;
01478     HFONT hOldFont;
01479     HDC   hdc;
01480 
01481     infoPtr = Alloc (sizeof(HEADER_INFO));
01482     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
01483 
01484     infoPtr->hwndSelf = hwnd;
01485     infoPtr->hwndNotify = lpcs->hwndParent;
01486     infoPtr->uNumItem = 0;
01487     infoPtr->hFont = 0;
01488     infoPtr->items = 0;
01489     infoPtr->order = 0;
01490     infoPtr->bRectsValid = FALSE;
01491     infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
01492     infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER));
01493     infoPtr->hcurDivopen = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDEROPEN));
01494     infoPtr->bPressed  = FALSE;
01495     infoPtr->bTracking = FALSE;
01496     infoPtr->dwStyle = lpcs->style;
01497     infoPtr->iMoveItem = 0;
01498     infoPtr->himl = 0;
01499     infoPtr->iHotItem = -1;
01500     infoPtr->iHotDivider = -1;
01501     infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE);
01502     infoPtr->nNotifyFormat =
01503     SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
01504 
01505     hdc = GetDC (0);
01506     hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
01507     GetTextMetricsW (hdc, &tm);
01508     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
01509     SelectObject (hdc, hOldFont);
01510     ReleaseDC (0, hdc);
01511 
01512     OpenThemeData(hwnd, themeClass);
01513 
01514     return 0;
01515 }
01516 
01517 
01518 static LRESULT
01519 HEADER_Destroy (HEADER_INFO *infoPtr)
01520 {
01521     HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
01522     CloseThemeData(theme);
01523     return 0;
01524 }
01525 
01526 static LRESULT
01527 HEADER_NCDestroy (HEADER_INFO *infoPtr)
01528 {
01529     HEADER_ITEM *lpItem;
01530     INT nItem;
01531 
01532     if (infoPtr->items) {
01533         lpItem = infoPtr->items;
01534         for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
01535             Free(lpItem->pszText);
01536         }
01537         Free (infoPtr->items);
01538     }
01539 
01540     Free(infoPtr->order);
01541 
01542     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
01543     Free (infoPtr);
01544 
01545     return 0;
01546 }
01547 
01548 
01549 static inline LRESULT
01550 HEADER_GetFont (const HEADER_INFO *infoPtr)
01551 {
01552     return (LRESULT)infoPtr->hFont;
01553 }
01554 
01555 
01556 static BOOL
01557 HEADER_IsDragDistance(const HEADER_INFO *infoPtr, const POINT *pt)
01558 {
01559     /* Windows allows for a mouse movement before starting the drag. We use the
01560      * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance.
01561      */
01562     return (abs(infoPtr->ptLButtonDown.x - pt->x)>GetSystemMetrics(SM_CXDOUBLECLK) ||
01563             abs(infoPtr->ptLButtonDown.y - pt->y)>GetSystemMetrics(SM_CYDOUBLECLK));
01564 }
01565 
01566 static LRESULT
01567 HEADER_LButtonDblClk (const HEADER_INFO *infoPtr, INT x, INT y)
01568 {
01569     POINT pt;
01570     UINT  flags;
01571     INT   nItem;
01572 
01573     pt.x = x;
01574     pt.y = y;
01575     HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
01576 
01577     if ((infoPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER))
01578         HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMDBLCLICKW, nItem, NULL);
01579     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
01580         HEADER_SendNotifyWithHDItemT(infoPtr, HDN_DIVIDERDBLCLICKW, nItem, NULL);
01581 
01582     return 0;
01583 }
01584 
01585 
01586 static LRESULT
01587 HEADER_LButtonDown (HEADER_INFO *infoPtr, INT x, INT y)
01588 {
01589     POINT pt;
01590     UINT  flags;
01591     INT   nItem;
01592     HDC   hdc;
01593 
01594     pt.x = x;
01595     pt.y = y;
01596     HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
01597 
01598     if ((infoPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
01599     SetCapture (infoPtr->hwndSelf);
01600     infoPtr->bCaptured = TRUE;
01601     infoPtr->bPressed  = TRUE;
01602     infoPtr->bDragging = FALSE;
01603     infoPtr->iMoveItem = nItem;
01604     infoPtr->ptLButtonDown = pt;
01605 
01606     infoPtr->items[nItem].bDown = TRUE;
01607 
01608     /* Send WM_CUSTOMDRAW */
01609     hdc = GetDC (infoPtr->hwndSelf);
01610     HEADER_RefreshItem (infoPtr, nItem);
01611     ReleaseDC (infoPtr->hwndSelf, hdc);
01612 
01613     TRACE("Pressed item %d!\n", nItem);
01614     }
01615     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
01616         INT iCurrWidth = infoPtr->items[nItem].cxy;
01617         if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_BEGINTRACKW, nItem, HDI_WIDTH, iCurrWidth))
01618         {
01619         SetCapture (infoPtr->hwndSelf);
01620         infoPtr->bCaptured = TRUE;
01621         infoPtr->bTracking = TRUE;
01622         infoPtr->iMoveItem = nItem;
01623         infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
01624 
01625         if (!(infoPtr->dwStyle & HDS_FULLDRAG)) {
01626         infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
01627         hdc = GetDC (infoPtr->hwndSelf);
01628         HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
01629         ReleaseDC (infoPtr->hwndSelf, hdc);
01630         }
01631 
01632         TRACE("Begin tracking item %d!\n", nItem);
01633     }
01634     }
01635 
01636     return 0;
01637 }
01638 
01639 
01640 static LRESULT
01641 HEADER_LButtonUp (HEADER_INFO *infoPtr, INT x, INT y)
01642 {
01643     POINT pt;
01644     UINT  flags;
01645     INT   nItem;
01646     HDC   hdc;
01647 
01648     pt.x = x;
01649     pt.y = y;
01650     HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
01651 
01652     if (infoPtr->bPressed) {
01653 
01654     infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
01655 
01656     if (infoPtr->bDragging)
01657     {
01658             HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
01659             INT iNewOrder;
01660             
01661         ImageList_DragShowNolock(FALSE);
01662         ImageList_EndDrag();
01663 
01664             if (infoPtr->iHotDivider == -1)
01665                 iNewOrder = -1;
01666             else if (infoPtr->iHotDivider == infoPtr->uNumItem)
01667                 iNewOrder = infoPtr->uNumItem-1;
01668             else
01669         {
01670                 iNewOrder = HEADER_IndexToOrder(infoPtr, infoPtr->iHotDivider);
01671                 if (iNewOrder > lpItem->iOrder)
01672                     iNewOrder--;
01673             }
01674 
01675             if (iNewOrder != -1 &&
01676                 !HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ENDDRAG, infoPtr->iMoveItem, HDI_ORDER, iNewOrder))
01677             {
01678                 HEADER_ChangeItemOrder(infoPtr, infoPtr->iMoveItem, iNewOrder);
01679         infoPtr->bRectsValid = FALSE;
01680         InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
01681         }
01682         else
01683         InvalidateRect(infoPtr->hwndSelf, &infoPtr->items[infoPtr->iMoveItem].rect, FALSE);
01684 
01685             infoPtr->bDragging = FALSE;
01686             HEADER_SetHotDivider(infoPtr, FALSE, -1);
01687     }
01688     else
01689     {
01690         hdc = GetDC (infoPtr->hwndSelf);
01691         HEADER_RefreshItem (infoPtr, infoPtr->iMoveItem);
01692         ReleaseDC (infoPtr->hwndSelf, hdc);
01693 
01694         if (!(infoPtr->dwStyle & HDS_DRAGDROP) || !HEADER_IsDragDistance(infoPtr, &pt))
01695         HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCLICKW, infoPtr->iMoveItem, NULL);
01696     }
01697 
01698     TRACE("Released item %d!\n", infoPtr->iMoveItem);
01699     infoPtr->bPressed = FALSE;
01700     }
01701     else if (infoPtr->bTracking) {
01702         INT iNewWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
01703         if (iNewWidth < 0)
01704         iNewWidth = 0;
01705     TRACE("End tracking item %d!\n", infoPtr->iMoveItem);
01706     infoPtr->bTracking = FALSE;
01707 
01708         HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ENDTRACKW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
01709 
01710         if (!(infoPtr->dwStyle & HDS_FULLDRAG)) {
01711         hdc = GetDC (infoPtr->hwndSelf);
01712         HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
01713             ReleaseDC (infoPtr->hwndSelf, hdc);
01714         }
01715           
01716         if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth))
01717         {
01718             infoPtr->items[infoPtr->iMoveItem].cxy = iNewWidth;
01719             HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
01720         }
01721 
01722     HEADER_SetItemBounds (infoPtr);
01723     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
01724     }
01725 
01726     if (infoPtr->bCaptured) {
01727     infoPtr->bCaptured = FALSE;
01728     ReleaseCapture ();
01729     HEADER_SendSimpleNotify (infoPtr, NM_RELEASEDCAPTURE);
01730     }
01731 
01732     return 0;
01733 }
01734 
01735 
01736 static LRESULT
01737 HEADER_NotifyFormat (HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
01738 {
01739     switch (lParam)
01740     {
01741     case NF_QUERY:
01742         return infoPtr->nNotifyFormat;
01743 
01744     case NF_REQUERY:
01745         infoPtr->nNotifyFormat =
01746         SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT,
01747                              (WPARAM)infoPtr->hwndSelf, NF_QUERY);
01748         return infoPtr->nNotifyFormat;
01749     }
01750 
01751     return 0;
01752 }
01753 
01754 static LRESULT
01755 HEADER_MouseLeave (HEADER_INFO *infoPtr)
01756 {
01757     /* Reset hot-tracked item when mouse leaves control. */
01758     INT oldHotItem = infoPtr->iHotItem;
01759     HDC hdc = GetDC (infoPtr->hwndSelf);
01760 
01761     infoPtr->iHotItem = -1;
01762     if (oldHotItem != -1) HEADER_RefreshItem (infoPtr, oldHotItem);
01763     ReleaseDC (infoPtr->hwndSelf, hdc);
01764 
01765     return 0;
01766 }
01767 
01768 
01769 static LRESULT
01770 HEADER_MouseMove (HEADER_INFO *infoPtr, LPARAM lParam)
01771 {
01772     POINT pt;
01773     UINT  flags;
01774     INT   nItem, nWidth;
01775     HDC   hdc;
01776     /* With theming, hottracking is always enabled */
01777     BOOL  hotTrackEnabled =
01778         ((infoPtr->dwStyle & HDS_BUTTONS) && (infoPtr->dwStyle & HDS_HOTTRACK))
01779         || (GetWindowTheme (infoPtr->hwndSelf) != NULL);
01780     INT oldHotItem = infoPtr->iHotItem;
01781 
01782     pt.x = (INT)(SHORT)LOWORD(lParam);
01783     pt.y = (INT)(SHORT)HIWORD(lParam);
01784     HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
01785 
01786     if (hotTrackEnabled) {
01787     if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
01788         infoPtr->iHotItem = nItem;
01789     else
01790         infoPtr->iHotItem = -1;
01791     }
01792 
01793     if (infoPtr->bCaptured) {
01794         /* check if we should drag the header */
01795     if (infoPtr->bPressed && !infoPtr->bDragging && (infoPtr->dwStyle & HDS_DRAGDROP)
01796         && HEADER_IsDragDistance(infoPtr, &pt))
01797     {
01798             if (!HEADER_SendNotifyWithHDItemT(infoPtr, HDN_BEGINDRAG, infoPtr->iMoveItem, NULL))
01799         {
01800         HIMAGELIST hDragItem = (HIMAGELIST)HEADER_CreateDragImage(infoPtr, infoPtr->iMoveItem);
01801         if (hDragItem != NULL)
01802         {
01803             HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
01804             TRACE("Starting item drag\n");
01805             ImageList_BeginDrag(hDragItem, 0, pt.x - lpItem->rect.left, 0);
01806             ImageList_DragShowNolock(TRUE);
01807             ImageList_Destroy(hDragItem);
01808             infoPtr->bDragging = TRUE;
01809         }
01810         }
01811     }
01812     
01813     if (infoPtr->bDragging)
01814     {
01815         POINT drag;
01816         drag.x = pt.x;
01817         drag.y = 0;
01818         ClientToScreen(infoPtr->hwndSelf, &drag);
01819         ImageList_DragMove(drag.x, drag.y);
01820         HEADER_SetHotDivider(infoPtr, TRUE, lParam);
01821     }
01822     
01823     if (infoPtr->bPressed && !infoPtr->bDragging) {
01824             BOOL oldState = infoPtr->items[infoPtr->iMoveItem].bDown;
01825         if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
01826         infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
01827         else
01828         infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
01829             if (oldState != infoPtr->items[infoPtr->iMoveItem].bDown) {
01830                 hdc = GetDC (infoPtr->hwndSelf);
01831             HEADER_RefreshItem (infoPtr, infoPtr->iMoveItem);
01832             ReleaseDC (infoPtr->hwndSelf, hdc);
01833             }
01834 
01835         TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem);
01836     }
01837     else if (infoPtr->bTracking) {
01838         if (infoPtr->dwStyle & HDS_FULLDRAG) {
01839                 HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
01840                 nWidth = pt.x - lpItem->rect.left + infoPtr->xTrackOffset;
01841                 if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, nWidth))
01842         {
01843                     INT nOldWidth = lpItem->rect.right - lpItem->rect.left;
01844                     RECT rcClient;
01845                     RECT rcScroll;
01846                     
01847                     if (nWidth < 0) nWidth = 0;
01848                     infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
01849                     HEADER_SetItemBounds(infoPtr);
01850                     
01851                     GetClientRect(infoPtr->hwndSelf, &rcClient);
01852                     rcScroll = rcClient;
01853                     rcScroll.left = lpItem->rect.left + nOldWidth;
01854                     ScrollWindowEx(infoPtr->hwndSelf, nWidth - nOldWidth, 0, &rcScroll, &rcClient, NULL, NULL, 0);
01855                     InvalidateRect(infoPtr->hwndSelf, &lpItem->rect, FALSE);
01856                     UpdateWindow(infoPtr->hwndSelf);
01857                     
01858                     HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, nWidth);
01859         }
01860         }
01861         else {
01862                 INT iTrackWidth;
01863         hdc = GetDC (infoPtr->hwndSelf);
01864         HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
01865         infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
01866         if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
01867             infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
01868         HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack);
01869         ReleaseDC (infoPtr->hwndSelf, hdc);
01870                 iTrackWidth = infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
01871                 /* FIXME: should stop tracking if HDN_TRACK returns TRUE */
01872                 HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_TRACKW, infoPtr->iMoveItem, HDI_WIDTH, iTrackWidth);
01873         }
01874 
01875         TRACE("Tracking item %d!\n", infoPtr->iMoveItem);
01876     }
01877     }
01878 
01879     if (hotTrackEnabled) {
01880         TRACKMOUSEEVENT tme;
01881         if (oldHotItem != infoPtr->iHotItem && !infoPtr->bDragging) {
01882         hdc = GetDC (infoPtr->hwndSelf);
01883         if (oldHotItem != -1) HEADER_RefreshItem (infoPtr, oldHotItem);
01884         if (infoPtr->iHotItem != -1) HEADER_RefreshItem (infoPtr, infoPtr->iHotItem);
01885         ReleaseDC (infoPtr->hwndSelf, hdc);
01886         }
01887         tme.cbSize = sizeof( tme );
01888         tme.dwFlags = TME_LEAVE;
01889         tme.hwndTrack = infoPtr->hwndSelf;
01890         TrackMouseEvent( &tme );
01891     }
01892 
01893     return 0;
01894 }
01895 
01896 
01897 static LRESULT
01898 HEADER_Paint (HEADER_INFO *infoPtr, HDC hdcParam)
01899 {
01900     HDC hdc;
01901     PAINTSTRUCT ps;
01902 
01903     hdc = hdcParam==0 ? BeginPaint (infoPtr->hwndSelf, &ps) : hdcParam;
01904     HEADER_Refresh (infoPtr, hdc);
01905     if(!hdcParam)
01906     EndPaint (infoPtr->hwndSelf, &ps);
01907     return 0;
01908 }
01909 
01910 
01911 static LRESULT
01912 HEADER_RButtonUp (HEADER_INFO *infoPtr, INT x, INT y)
01913 {
01914     BOOL bRet;
01915     POINT pt;
01916 
01917     pt.x = x;
01918     pt.y = y;
01919 
01920     /* Send a Notify message */
01921     bRet = HEADER_SendSimpleNotify (infoPtr, NM_RCLICK);
01922 
01923     /* Change to screen coordinate for WM_CONTEXTMENU */
01924     ClientToScreen(infoPtr->hwndSelf, &pt);
01925 
01926     /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
01927     SendMessageW( infoPtr->hwndSelf, WM_CONTEXTMENU, (WPARAM) infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y));
01928 
01929     return bRet;
01930 }
01931 
01932 
01933 static LRESULT
01934 HEADER_SetCursor (HEADER_INFO *infoPtr, LPARAM lParam)
01935 {
01936     POINT pt;
01937     UINT  flags;
01938     INT   nItem;
01939 
01940     TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
01941 
01942     GetCursorPos (&pt);
01943     ScreenToClient (infoPtr->hwndSelf, &pt);
01944 
01945     HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
01946 
01947     if (flags == HHT_ONDIVIDER)
01948         SetCursor (infoPtr->hcurDivider);
01949     else if (flags == HHT_ONDIVOPEN)
01950         SetCursor (infoPtr->hcurDivopen);
01951     else
01952         SetCursor (infoPtr->hcurArrow);
01953 
01954     return 0;
01955 }
01956 
01957 
01958 static LRESULT
01959 HEADER_SetFont (HEADER_INFO *infoPtr, HFONT hFont, WORD Redraw)
01960 {
01961     TEXTMETRICW tm;
01962     HFONT hOldFont;
01963     HDC hdc;
01964 
01965     infoPtr->hFont = hFont;
01966 
01967     hdc = GetDC (0);
01968     hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT));
01969     GetTextMetricsW (hdc, &tm);
01970     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
01971     SelectObject (hdc, hOldFont);
01972     ReleaseDC (0, hdc);
01973 
01974     infoPtr->bRectsValid = FALSE;
01975 
01976     if (Redraw) {
01977         InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
01978     }
01979 
01980     return 0;
01981 }
01982 
01983 static LRESULT HEADER_SetRedraw(HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
01984 {
01985     /* ignoring the InvalidateRect calls is handled by user32. But some apps expect
01986      * that we invalidate the header and this has to be done manually  */
01987     LRESULT ret;
01988 
01989     ret = DefWindowProcW(infoPtr->hwndSelf, WM_SETREDRAW, wParam, lParam);
01990     if (wParam)
01991         InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
01992     return ret;
01993 }
01994 
01995 static INT HEADER_StyleChanged(HEADER_INFO *infoPtr, WPARAM wStyleType,
01996                                const STYLESTRUCT *lpss)
01997 {
01998     TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
01999           wStyleType, lpss->styleOld, lpss->styleNew);
02000 
02001     if (wStyleType != GWL_STYLE) return 0;
02002 
02003     infoPtr->dwStyle = lpss->styleNew;
02004 
02005     return 0;
02006 }
02007 
02008 /* Update the theme handle after a theme change */
02009 static LRESULT HEADER_ThemeChanged(const HEADER_INFO *infoPtr)
02010 {
02011     HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
02012     CloseThemeData(theme);
02013     OpenThemeData(infoPtr->hwndSelf, themeClass);
02014     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
02015     return 0;
02016 }
02017 
02018 
02019 static LRESULT WINAPI
02020 HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
02021 {
02022     HEADER_INFO *infoPtr = (HEADER_INFO *)GetWindowLongPtrW(hwnd, 0);
02023 
02024     TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, msg, wParam, lParam);
02025     if (!infoPtr && (msg != WM_CREATE))
02026     return DefWindowProcW (hwnd, msg, wParam, lParam);
02027     switch (msg) {
02028 /*  case HDM_CLEARFILTER: */
02029 
02030     case HDM_CREATEDRAGIMAGE:
02031         return HEADER_CreateDragImage (infoPtr, (INT)wParam);
02032 
02033     case HDM_DELETEITEM:
02034         return HEADER_DeleteItem (infoPtr, (INT)wParam);
02035 
02036 /*  case HDM_EDITFILTER: */
02037 
02038     case HDM_GETBITMAPMARGIN:
02039         return HEADER_GetBitmapMargin(infoPtr);
02040 
02041     case HDM_GETIMAGELIST:
02042         return HEADER_GetImageList (infoPtr);
02043 
02044     case HDM_GETITEMA:
02045     case HDM_GETITEMW:
02046         return HEADER_GetItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_GETITEMW);
02047 
02048     case HDM_GETITEMCOUNT:
02049         return HEADER_GetItemCount (infoPtr);
02050 
02051     case HDM_GETITEMRECT:
02052         return HEADER_GetItemRect (infoPtr, (INT)wParam, (LPRECT)lParam);
02053 
02054     case HDM_GETORDERARRAY:
02055         return HEADER_GetOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
02056 
02057     case HDM_GETUNICODEFORMAT:
02058         return HEADER_GetUnicodeFormat (infoPtr);
02059 
02060     case HDM_HITTEST:
02061         return HEADER_HitTest (infoPtr, (LPHDHITTESTINFO)lParam);
02062 
02063     case HDM_INSERTITEMA:
02064     case HDM_INSERTITEMW:
02065         return HEADER_InsertItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_INSERTITEMW);
02066 
02067     case HDM_LAYOUT:
02068         return HEADER_Layout (infoPtr, (LPHDLAYOUT)lParam);
02069 
02070     case HDM_ORDERTOINDEX:
02071         return HEADER_OrderToIndex(infoPtr, (INT)wParam);
02072 
02073     case HDM_SETBITMAPMARGIN:
02074         return HEADER_SetBitmapMargin(infoPtr, (INT)wParam);
02075 
02076 /*  case HDM_SETFILTERCHANGETIMEOUT: */
02077 
02078         case HDM_SETHOTDIVIDER:
02079             return HEADER_SetHotDivider(infoPtr, wParam, lParam);
02080 
02081     case HDM_SETIMAGELIST:
02082         return HEADER_SetImageList (infoPtr, (HIMAGELIST)lParam);
02083 
02084     case HDM_SETITEMA:
02085     case HDM_SETITEMW:
02086         return HEADER_SetItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_SETITEMW);
02087 
02088     case HDM_SETORDERARRAY:
02089         return HEADER_SetOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
02090 
02091     case HDM_SETUNICODEFORMAT:
02092         return HEADER_SetUnicodeFormat (infoPtr, wParam);
02093 
02094         case WM_CREATE:
02095             return HEADER_Create (hwnd, (LPCREATESTRUCTW)lParam);
02096 
02097         case WM_DESTROY:
02098             return HEADER_Destroy (infoPtr);
02099 
02100         case WM_NCDESTROY:
02101             return HEADER_NCDestroy (infoPtr);
02102 
02103         case WM_ERASEBKGND:
02104             return 1;
02105 
02106         case WM_GETDLGCODE:
02107             return DLGC_WANTTAB | DLGC_WANTARROWS;
02108 
02109         case WM_GETFONT:
02110             return HEADER_GetFont (infoPtr);
02111 
02112         case WM_LBUTTONDBLCLK:
02113             return HEADER_LButtonDblClk (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
02114 
02115         case WM_LBUTTONDOWN:
02116             return HEADER_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
02117 
02118         case WM_LBUTTONUP:
02119             return HEADER_LButtonUp (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
02120 
02121         case WM_MOUSELEAVE:
02122             return HEADER_MouseLeave (infoPtr);
02123 
02124         case WM_MOUSEMOVE:
02125             return HEADER_MouseMove (infoPtr, lParam);
02126 
02127     case WM_NOTIFYFORMAT:
02128             return HEADER_NotifyFormat (infoPtr, wParam, lParam);
02129 
02130     case WM_SIZE:
02131         return HEADER_Size (infoPtr);
02132 
02133         case WM_THEMECHANGED:
02134             return HEADER_ThemeChanged (infoPtr);
02135 
02136         case WM_PRINTCLIENT:
02137         case WM_PAINT:
02138             return HEADER_Paint (infoPtr, (HDC)wParam);
02139 
02140         case WM_RBUTTONUP:
02141             return HEADER_RButtonUp (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
02142 
02143         case WM_SETCURSOR:
02144             return HEADER_SetCursor (infoPtr, lParam);
02145 
02146         case WM_SETFONT:
02147             return HEADER_SetFont (infoPtr, (HFONT)wParam, (WORD)lParam);
02148 
02149         case WM_SETREDRAW:
02150             return HEADER_SetRedraw(infoPtr, wParam, lParam);
02151 
02152         case WM_STYLECHANGED:
02153             return HEADER_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
02154 
02155         case WM_SYSCOLORCHANGE:
02156             COMCTL32_RefreshSysColors();
02157             return 0;
02158 
02159         default:
02160             if ((msg >= WM_USER) && (msg < WM_APP) && !COMCTL32_IsReflectedMessage(msg))
02161         ERR("unknown msg %04x wp=%04lx lp=%08lx\n",
02162              msg, wParam, lParam );
02163         return DefWindowProcW(hwnd, msg, wParam, lParam);
02164     }
02165 }
02166 
02167 
02168 VOID
02169 HEADER_Register (void)
02170 {
02171     WNDCLASSW wndClass;
02172 
02173     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
02174     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
02175     wndClass.lpfnWndProc   = HEADER_WindowProc;
02176     wndClass.cbClsExtra    = 0;
02177     wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
02178     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
02179     wndClass.lpszClassName = WC_HEADERW;
02180 
02181     RegisterClassW (&wndClass);
02182 }
02183 
02184 
02185 VOID
02186 HEADER_Unregister (void)
02187 {
02188     UnregisterClassW (WC_HEADERW, NULL);
02189 }

Generated on Sun May 27 2012 04:22:59 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.