Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenheader.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
1.7.6.1
|