Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308/* * Header control * * Copyright 1998 Eric Kohl * Copyright 2000 Eric Kohl for CodeWeavers * Copyright 2003 Maxime Bellenge * Copyright 2006 Mikolaj Zalewski * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: * - Imagelist support (completed?) * - Hottrack support (completed?) * - Filters support (HDS_FILTER, HDI_FILTER, HDM_*FILTER*, HDN_*FILTER*) * - New Windows Vista features */
#include <stdarg.h>#include <stdlib.h>#include <string.h>
#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "winnls.h"#include "commctrl.h"#include "comctl32.h"#include "vssym32.h"#include "uxtheme.h"#include "wine/debug.h"#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(header);
typedef struct{ INT cxy; HBITMAP hbm; LPWSTR pszText; INT fmt; LPARAM lParam; INT iImage; INT iOrder; /* see documentation of HD_ITEM */
BOOL bDown; /* is item pressed? (used for drawing) */ RECT rect; /* bounding rectangle of the item */ DWORD callbackMask; /* HDI_* flags for items that are callback */} HEADER_ITEM;
typedef struct{ HWND hwndSelf; /* Control window */ HWND hwndNotify; /* Owner window to send notifications to */ INT nNotifyFormat; /* format used for WM_NOTIFY messages */ UINT uNumItem; /* number of items (columns) */ INT nHeight; /* height of the header (pixels) */ HFONT hFont; /* handle to the current font */ HCURSOR hcurArrow; /* handle to the arrow cursor */ HCURSOR hcurDivider; /* handle to a cursor (used over dividers) <-|-> */ HCURSOR hcurDivopen; /* handle to a cursor (used over dividers) <-||-> */ BOOL bCaptured; /* Is the mouse captured? */ BOOL bPressed; /* Is a header item pressed (down)? */ BOOL bDragging; /* Are we dragging an item? */ BOOL bTracking; /* Is in tracking mode? */ POINT ptLButtonDown; /* The point where the left button was pressed */ DWORD dwStyle; /* the cached window GWL_STYLE */ INT iMoveItem; /* index of tracked item. (Tracking mode) */ INT xTrackOffset; /* distance between the right side of the tracked item and the cursor */ INT xOldTrack; /* track offset (see above) after the last WM_MOUSEMOVE */ INT iHotItem; /* index of hot item (cursor is over this item) */ INT iHotDivider; /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */ INT iMargin; /* width of the margin that surrounds a bitmap */ INT filter_change_timeout; /* change timeout set with HDM_SETFILTERCHANGETIMEOUT */
HIMAGELIST himl; /* handle to an image list (may be 0) */ HEADER_ITEM *items; /* pointer to array of HEADER_ITEM's */ INT *order; /* array of item IDs indexed by order */ BOOL bRectsValid; /* validity flag for bounding rectangles */} HEADER_INFO;
#define VERT_BORDER 4#define DIVIDER_WIDTH 10#define HOT_DIVIDER_WIDTH 2#define MAX_HEADER_TEXT_LEN 260#define HDN_UNICODE_OFFSET 20#define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
#define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)#define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)#define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))#define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)
static BOOL HEADER_PrepareCallbackItems(const HEADER_INFO *infoPtr, INT iItem, INT reqMask);static void HEADER_FreeCallbackItems(HEADER_ITEM *lpItem);static LRESULT HEADER_SendNotify(const HEADER_INFO *infoPtr, UINT code, NMHDR *hdr);static LRESULT HEADER_SendCtrlCustomDraw(const HEADER_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, const RECT *rect);
static const WCHAR themeClass[] = {'H','e','a','d','e','r',0};
static void HEADER_StoreHDItemInHeader(HEADER_ITEM *lpItem, UINT mask, const HDITEMW *phdi, BOOL fUnicode){ if (mask & HDI_UNSUPPORTED_FIELDS) FIXME("unsupported header fields %x\n", (mask & HDI_UNSUPPORTED_FIELDS)); if (mask & HDI_BITMAP) lpItem->hbm = phdi->hbm;
if (mask & HDI_FORMAT) lpItem->fmt = phdi->fmt;
if (mask & HDI_LPARAM) lpItem->lParam = phdi->lParam;
if (mask & HDI_WIDTH) lpItem->cxy = phdi->cxy;
if (mask & HDI_IMAGE) { lpItem->iImage = phdi->iImage; if (phdi->iImage == I_IMAGECALLBACK) lpItem->callbackMask |= HDI_IMAGE; else lpItem->callbackMask &= ~HDI_IMAGE; }
if (mask & HDI_TEXT) { heap_free(lpItem->pszText); lpItem->pszText = NULL;
if (phdi->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */ { static const WCHAR emptyString[] = {0};
LPCWSTR pszText = (phdi->pszText != NULL ? phdi->pszText : emptyString); if (fUnicode) Str_SetPtrW(&lpItem->pszText, pszText); else Str_SetPtrAtoW(&lpItem->pszText, (LPCSTR)pszText); lpItem->callbackMask &= ~HDI_TEXT; } else { lpItem->pszText = NULL; lpItem->callbackMask |= HDI_TEXT; } }}
static inline LRESULTHEADER_IndexToOrder (const HEADER_INFO *infoPtr, INT iItem){ HEADER_ITEM *lpItem = &infoPtr->items[iItem]; return lpItem->iOrder;}
static INTHEADER_OrderToIndex(const HEADER_INFO *infoPtr, INT iorder){ if ((iorder <0) || iorder >= infoPtr->uNumItem) return iorder; return infoPtr->order[iorder];}
static voidHEADER_ChangeItemOrder(const HEADER_INFO *infoPtr, INT iItem, INT iNewOrder){ HEADER_ITEM *lpItem = &infoPtr->items[iItem]; INT i, nMin, nMax;
TRACE("%d: %d->%d\n", iItem, lpItem->iOrder, iNewOrder); if (lpItem->iOrder < iNewOrder) { memmove(&infoPtr->order[lpItem->iOrder], &infoPtr->order[lpItem->iOrder + 1], (iNewOrder - lpItem->iOrder) * sizeof(INT)); } if (iNewOrder < lpItem->iOrder) { memmove(&infoPtr->order[iNewOrder + 1], &infoPtr->order[iNewOrder], (lpItem->iOrder - iNewOrder) * sizeof(INT)); } infoPtr->order[iNewOrder] = iItem; nMin = min(lpItem->iOrder, iNewOrder); nMax = max(lpItem->iOrder, iNewOrder); for (i = nMin; i <= nMax; i++) infoPtr->items[infoPtr->order[i]].iOrder = i;}
/* Note: if iItem is the last item then this function returns infoPtr->uNumItem */static INTHEADER_NextItem(const HEADER_INFO *infoPtr, INT iItem){ return HEADER_OrderToIndex(infoPtr, HEADER_IndexToOrder(infoPtr, iItem)+1);}
static INTHEADER_PrevItem(const HEADER_INFO *infoPtr, INT iItem){ return HEADER_OrderToIndex(infoPtr, HEADER_IndexToOrder(infoPtr, iItem)-1);}
/* TRUE when item is not resizable with dividers, note that valid index should be supplied */static inline BOOLHEADER_IsItemFixed(const HEADER_INFO *infoPtr, INT iItem){ return (infoPtr->dwStyle & HDS_NOSIZING) || (infoPtr->items[iItem].fmt & HDF_FIXEDWIDTH);}
static voidHEADER_SetItemBounds (HEADER_INFO *infoPtr){ HEADER_ITEM *phdi; RECT rect; unsigned int i; int x;
infoPtr->bRectsValid = TRUE;
if (infoPtr->uNumItem == 0) return;
GetClientRect (infoPtr->hwndSelf, &rect);
x = rect.left; for (i = 0; i < infoPtr->uNumItem; i++) { phdi = &infoPtr->items[HEADER_OrderToIndex(infoPtr,i)]; phdi->rect.top = rect.top; phdi->rect.bottom = rect.bottom; phdi->rect.left = x; phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0); x = phdi->rect.right; }}
static LRESULTHEADER_Size (HEADER_INFO *infoPtr){ HEADER_SetItemBounds(infoPtr); return 0;}
static void HEADER_GetHotDividerRect(const HEADER_INFO *infoPtr, RECT *r){ INT iDivider = infoPtr->iHotDivider; if (infoPtr->uNumItem > 0) { HEADER_ITEM *lpItem; if (iDivider < infoPtr->uNumItem) { lpItem = &infoPtr->items[iDivider]; r->left = lpItem->rect.left - HOT_DIVIDER_WIDTH/2; r->right = lpItem->rect.left + HOT_DIVIDER_WIDTH/2; } else { lpItem = &infoPtr->items[HEADER_OrderToIndex(infoPtr, infoPtr->uNumItem-1)]; r->left = lpItem->rect.right - HOT_DIVIDER_WIDTH/2; r->right = lpItem->rect.right + HOT_DIVIDER_WIDTH/2; } r->top = lpItem->rect.top; r->bottom = lpItem->rect.bottom; } else { RECT clientRect; GetClientRect(infoPtr->hwndSelf, &clientRect); *r = clientRect; r->right = r->left + HOT_DIVIDER_WIDTH/2; }}
static voidHEADER_FillItemFrame(HEADER_INFO *infoPtr, HDC hdc, RECT *r, const HEADER_ITEM *item, BOOL hottrack){ HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
if (theme) { int state = (item->bDown) ? HIS_PRESSED : (hottrack ? HIS_HOT : HIS_NORMAL); DrawThemeBackground (theme, hdc, HP_HEADERITEM, state, r, NULL); GetThemeBackgroundContentRect (theme, hdc, HP_HEADERITEM, state, r, r); } else { HBRUSH hbr = CreateSolidBrush(GetBkColor(hdc)); FillRect(hdc, r, hbr); DeleteObject(hbr); }}
static voidHEADER_DrawItemFrame(HEADER_INFO *infoPtr, HDC hdc, RECT *r, const HEADER_ITEM *item){ if (GetWindowTheme(infoPtr->hwndSelf)) return;
if (!(infoPtr->dwStyle & HDS_FLAT)) { if (infoPtr->dwStyle & HDS_BUTTONS) { if (item->bDown) DrawEdge (hdc, r, BDR_RAISEDOUTER, BF_RECT | BF_FLAT | BF_ADJUST); else DrawEdge (hdc, r, EDGE_RAISED, BF_RECT | BF_SOFT | BF_ADJUST); } else DrawEdge (hdc, r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST); }}
/* Create a region for the sort arrow with its bounding rect's top-left co-ord x,y and its height h. */static HRGN create_sort_arrow( INT x, INT y, INT h, BOOL is_up ){ char buffer[256]; RGNDATA *data = (RGNDATA *)buffer; DWORD size = FIELD_OFFSET(RGNDATA, Buffer[h * sizeof(RECT)]); INT i, yinc = 1; HRGN rgn;
if (size > sizeof(buffer)) { data = heap_alloc( size ); if (!data) return NULL; } data->rdh.dwSize = sizeof(data->rdh); data->rdh.iType = RDH_RECTANGLES; data->rdh.nCount = 0; data->rdh.nRgnSize = h * sizeof(RECT);
if (!is_up) { y += h - 1; yinc = -1; }
x += h - 1; /* set x to the centre */
for (i = 0; i < h; i++, y += yinc) { RECT *rect = (RECT *)data->Buffer + data->rdh.nCount; rect->left = x - i; rect->top = y; rect->right = x + i + 1; rect->bottom = y + 1; data->rdh.nCount++; } rgn = ExtCreateRegion( NULL, size, data ); if (data != (RGNDATA *)buffer) heap_free( data ); return rgn;}
static INTHEADER_DrawItem (HEADER_INFO *infoPtr, HDC hdc, INT iItem, BOOL bHotTrack, LRESULT lCDFlags){ HEADER_ITEM *phdi = &infoPtr->items[iItem]; RECT r; INT oldBkMode; HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); NMCUSTOMDRAW nmcd; int state = 0;
TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, (infoPtr->nNotifyFormat == NFR_UNICODE));
r = phdi->rect; if (r.right - r.left == 0) return phdi->rect.right;
if (theme) state = (phdi->bDown) ? HIS_PRESSED : (bHotTrack ? HIS_HOT : HIS_NORMAL);
/* Set the colors before sending NM_CUSTOMDRAW so that it can change them */ SetTextColor(hdc, (bHotTrack && !theme) ? comctl32_color.clrHighlight : comctl32_color.clrBtnText); SetBkColor(hdc, comctl32_color.clr3dFace);
if (lCDFlags & CDRF_NOTIFYITEMDRAW && !(phdi->fmt & HDF_OWNERDRAW)) { LRESULT lCDItemFlags;
nmcd.dwDrawStage = CDDS_PREPAINT | CDDS_ITEM; nmcd.hdc = hdc; nmcd.dwItemSpec = iItem; nmcd.rc = r; nmcd.uItemState = phdi->bDown ? CDIS_SELECTED : 0; nmcd.lItemlParam = phdi->lParam;
lCDItemFlags = HEADER_SendNotify(infoPtr, NM_CUSTOMDRAW, (NMHDR *)&nmcd); if (lCDItemFlags & CDRF_SKIPDEFAULT) return phdi->rect.right; }
/* Fill background, owner could draw over it. */ HEADER_FillItemFrame(infoPtr, hdc, &r, phdi, bHotTrack);
if (phdi->fmt & HDF_OWNERDRAW) { DRAWITEMSTRUCT dis; BOOL ret;
dis.CtlType = ODT_HEADER; dis.CtlID = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); dis.itemID = iItem; dis.itemAction = ODA_DRAWENTIRE; dis.itemState = phdi->bDown ? ODS_SELECTED : 0; dis.hwndItem = infoPtr->hwndSelf; dis.hDC = hdc; dis.rcItem = phdi->rect; dis.itemData = phdi->lParam; oldBkMode = SetBkMode(hdc, TRANSPARENT); ret = SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); if (oldBkMode != TRANSPARENT) SetBkMode(hdc, oldBkMode);
if (!ret) HEADER_FillItemFrame(infoPtr, hdc, &r, phdi, bHotTrack);
/* Edges are always drawn if we don't have attached theme. */ HEADER_DrawItemFrame(infoPtr, hdc, &r, phdi); /* If application processed WM_DRAWITEM we should skip label painting, edges are drawn no matter what. */ if (ret) return phdi->rect.right; } else HEADER_DrawItemFrame(infoPtr, hdc, &r, phdi);
if (phdi->bDown) { r.left += 2; r.top += 2; }
/* Now text and image */ { INT rw, rh; /* width and height of r */ INT *x = NULL; /* x and ... */ UINT *w = NULL; /* ... width of the pic (bmp or img) which is part of cnt */ /* cnt,txt,img,bmp */ INT cx, tx, ix, bx; UINT cw, tw, iw, bw; INT img_cx, img_cy; INT sort_w, sort_x, sort_h; BITMAP bmp;
HEADER_PrepareCallbackItems(infoPtr, iItem, HDI_TEXT|HDI_IMAGE); cw = iw = bw = sort_w = sort_h = 0; rw = r.right - r.left; rh = r.bottom - r.top;
if (phdi->fmt & HDF_STRING) { RECT textRect;
SetRectEmpty(&textRect);
if (theme) { GetThemeTextExtent(theme, hdc, HP_HEADERITEM, state, phdi->pszText, -1, DT_LEFT|DT_VCENTER|DT_SINGLELINE, NULL, &textRect); } else { DrawTextW (hdc, phdi->pszText, -1, &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT); } cw = textRect.right - textRect.left + 2 * infoPtr->iMargin; }
if (phdi->fmt & (HDF_SORTUP | HDF_SORTDOWN)) { sort_h = MulDiv( infoPtr->nHeight - VERT_BORDER, 4, 13 ); sort_w = 2 * sort_h - 1 + infoPtr->iMargin * 2; cw += sort_w; } else { /* sort arrows take precedent over images/bitmaps */ if ((phdi->fmt & HDF_IMAGE) && ImageList_GetIconSize( infoPtr->himl, &img_cx, &img_cy )) { iw = img_cx + 2 * infoPtr->iMargin; x = &ix; w = &iw; }
if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) { GetObjectW (phdi->hbm, sizeof(BITMAP), &bmp); bw = bmp.bmWidth + 2 * infoPtr->iMargin; if (!iw) { x = &bx; w = &bw; } } if (bw || iw) cw += *w; }
/* align cx using the unclipped cw */ if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT) cx = r.left; else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER) cx = r.left + rw / 2 - cw / 2; else /* HDF_RIGHT */ cx = r.right - cw; /* clip cx & cw */ if (cx < r.left) cx = r.left; if (cx + cw > r.right) cw = r.right - cx; tx = cx + infoPtr->iMargin; /* since cw might have changed we have to recalculate tw */ tw = cw - infoPtr->iMargin * 2;
tw -= sort_w; sort_x = cx + tw + infoPtr->iMargin * 3;
if (iw || bw) { tw -= *w; if (phdi->fmt & HDF_BITMAP_ON_RIGHT) { /* put pic behind text */ *x = cx + tw + infoPtr->iMargin * 3; } else { *x = cx + infoPtr->iMargin; /* move text behind pic */ tx += *w; } }
if (iw && bw) { /* since we're done with the layout we can now calculate the position of bmp which has no influence on alignment and layout because of img */ if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT) bx = cx - bw + infoPtr->iMargin; else bx = cx + cw + infoPtr->iMargin; }
if (sort_w || iw || bw) { HDC hClipDC = GetDC(infoPtr->hwndSelf); HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom); SelectClipRgn(hClipDC, hClipRgn); if (sort_w) { HRGN arrow = create_sort_arrow( sort_x, r.top + (rh - sort_h) / 2, sort_h, phdi->fmt & HDF_SORTUP ); if (arrow) { FillRgn( hClipDC, arrow, GetSysColorBrush( COLOR_GRAYTEXT ) ); DeleteObject( arrow ); } }
if (bw) { HDC hdcBitmap = CreateCompatibleDC (hClipDC); SelectObject (hdcBitmap, phdi->hbm); BitBlt (hClipDC, bx, r.top + (rh - bmp.bmHeight) / 2, bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY); DeleteDC (hdcBitmap); }
if (iw) { ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, ix, r.top + (rh - img_cy) / 2, img_cx, img_cy, CLR_DEFAULT, CLR_DEFAULT, 0); }
DeleteObject(hClipRgn); ReleaseDC(infoPtr->hwndSelf, hClipDC); } if (((phdi->fmt & HDF_STRING) || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP| HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */ && (phdi->pszText)) { oldBkMode = SetBkMode(hdc, TRANSPARENT); r.left = tx; r.right = tx + tw; if (theme) { DrawThemeText(theme, hdc, HP_HEADERITEM, state, phdi->pszText, -1, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE, 0, &r); } else { DrawTextW (hdc, phdi->pszText, -1, &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE); } if (oldBkMode != TRANSPARENT) SetBkMode(hdc, oldBkMode); } HEADER_FreeCallbackItems(phdi); }
return phdi->rect.right;}
static voidHEADER_DrawHotDivider(const HEADER_INFO *infoPtr, HDC hdc){ HBRUSH brush; RECT r; HEADER_GetHotDividerRect(infoPtr, &r); brush = CreateSolidBrush(comctl32_color.clrHighlight); FillRect(hdc, &r, brush); DeleteObject(brush);}
static voidHEADER_Refresh (HEADER_INFO *infoPtr, HDC hdc){ HFONT hFont, hOldFont; RECT rect, rcRest; HBRUSH hbrBk; UINT i; INT x; LRESULT lCDFlags; HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
if (!infoPtr->bRectsValid) HEADER_SetItemBounds(infoPtr);
/* get rect for the bar, adjusted for the border */ GetClientRect (infoPtr->hwndSelf, &rect); lCDFlags = HEADER_SendCtrlCustomDraw(infoPtr, CDDS_PREPAINT, hdc, &rect); if (infoPtr->bDragging) ImageList_DragShowNolock(FALSE);
hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); hOldFont = SelectObject (hdc, hFont);
/* draw Background */ if (infoPtr->uNumItem == 0 && theme == NULL) { hbrBk = GetSysColorBrush(COLOR_3DFACE); FillRect(hdc, &rect, hbrBk); }
x = rect.left; for (i = 0; x <= rect.right && i < infoPtr->uNumItem; i++) { int idx = HEADER_OrderToIndex(infoPtr,i); if (RectVisible(hdc, &infoPtr->items[idx].rect)) HEADER_DrawItem(infoPtr, hdc, idx, infoPtr->iHotItem == idx, lCDFlags); x = infoPtr->items[idx].rect.right; }
rcRest = rect; rcRest.left = x; if ((x <= rect.right) && RectVisible(hdc, &rcRest) && (infoPtr->uNumItem > 0)) { if (theme != NULL) { DrawThemeBackground(theme, hdc, HP_HEADERITEM, HIS_NORMAL, &rcRest, NULL); } else if (infoPtr->dwStyle & HDS_FLAT) { hbrBk = GetSysColorBrush(COLOR_3DFACE); FillRect(hdc, &rcRest, hbrBk); } else { if (infoPtr->dwStyle & HDS_BUTTONS) DrawEdge (hdc, &rcRest, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT|BF_MIDDLE); else DrawEdge (hdc, &rcRest, EDGE_ETCHED, BF_BOTTOM|BF_MIDDLE); } }
if (infoPtr->iHotDivider != -1) HEADER_DrawHotDivider(infoPtr, hdc);
if (infoPtr->bDragging) ImageList_DragShowNolock(TRUE); SelectObject (hdc, hOldFont); if (lCDFlags & CDRF_NOTIFYPOSTPAINT) HEADER_SendCtrlCustomDraw(infoPtr, CDDS_POSTPAINT, hdc, &rect);}
static voidHEADER_RefreshItem (HEADER_INFO *infoPtr, INT iItem){ if (!infoPtr->bRectsValid) HEADER_SetItemBounds(infoPtr);
InvalidateRect(infoPtr->hwndSelf, &infoPtr->items[iItem].rect, FALSE);}
static voidHEADER_InternalHitTest (const HEADER_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pItem){ RECT rect, rcTest; UINT iCount; INT width; BOOL bNoWidth;
GetClientRect (infoPtr->hwndSelf, &rect);
*pFlags = 0; bNoWidth = FALSE; if (PtInRect (&rect, *lpPt)) { if (infoPtr->uNumItem == 0) { *pFlags |= HHT_NOWHERE; *pItem = 1; TRACE("NOWHERE\n"); return; } else { /* somewhere inside */ for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) { rect = infoPtr->items[iCount].rect; width = rect.right - rect.left; if (width == 0) { bNoWidth = TRUE; continue; } if (PtInRect (&rect, *lpPt)) { if (width <= 2 * DIVIDER_WIDTH) { *pFlags |= HHT_ONHEADER; *pItem = iCount; TRACE("ON HEADER %d\n", iCount); return; } if (HEADER_IndexToOrder(infoPtr, iCount) > 0) { rcTest = rect; rcTest.right = rcTest.left + DIVIDER_WIDTH; if (PtInRect (&rcTest, *lpPt)) { if (HEADER_IsItemFixed(infoPtr, HEADER_PrevItem(infoPtr, iCount))) { *pFlags |= HHT_ONHEADER; *pItem = iCount; TRACE("ON HEADER %d\n", *pItem); return; } if (bNoWidth) { *pFlags |= HHT_ONDIVOPEN; *pItem = HEADER_PrevItem(infoPtr, iCount); TRACE("ON DIVOPEN %d\n", *pItem); return; } else { *pFlags |= HHT_ONDIVIDER; *pItem = HEADER_PrevItem(infoPtr, iCount); TRACE("ON DIVIDER %d\n", *pItem); return; } } } rcTest = rect; rcTest.left = rcTest.right - DIVIDER_WIDTH; if (!HEADER_IsItemFixed(infoPtr, iCount) && PtInRect (&rcTest, *lpPt)) { *pFlags |= HHT_ONDIVIDER; *pItem = iCount; TRACE("ON DIVIDER %d\n", *pItem); return; }
*pFlags |= HHT_ONHEADER; *pItem = iCount; TRACE("ON HEADER %d\n", iCount); return; } }
/* check for last divider part (on nowhere) */ if (!HEADER_IsItemFixed(infoPtr, infoPtr->uNumItem - 1)) { rect = infoPtr->items[infoPtr->uNumItem-1].rect; rect.left = rect.right; rect.right += DIVIDER_WIDTH; if (PtInRect (&rect, *lpPt)) { if (bNoWidth) { *pFlags |= HHT_ONDIVOPEN; *pItem = infoPtr->uNumItem - 1; TRACE("ON DIVOPEN %d\n", *pItem); return; } else { *pFlags |= HHT_ONDIVIDER; *pItem = infoPtr->uNumItem - 1; TRACE("ON DIVIDER %d\n", *pItem); return; } } }
*pFlags |= HHT_NOWHERE; *pItem = 1; TRACE("NOWHERE\n"); return; } } else { if (lpPt->x < rect.left) { TRACE("TO LEFT\n"); *pFlags |= HHT_TOLEFT; } else if (lpPt->x > rect.right) { TRACE("TO RIGHT\n"); *pFlags |= HHT_TORIGHT; }
if (lpPt->y < rect.top) { TRACE("ABOVE\n"); *pFlags |= HHT_ABOVE; } else if (lpPt->y > rect.bottom) { TRACE("BELOW\n"); *pFlags |= HHT_BELOW; } }
*pItem = 1; TRACE("flags=0x%X\n", *pFlags); return;}
static voidHEADER_DrawTrackLine (const HEADER_INFO *infoPtr, HDC hdc, INT x){ RECT rect;
GetClientRect (infoPtr->hwndSelf, &rect); PatBlt( hdc, x, rect.top, 1, rect.bottom - rect.top, DSTINVERT );}
/*** * DESCRIPTION: * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify * * PARAMETER(S): * [I] infoPtr : the header that wants to send the notify * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW * [I] src : The source HDITEM. It may be a HDITEMA or HDITEMW * [I] fSourceUnicode : is src a HDITEMW or HDITEMA * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after * the HDITEM is no longer in use or NULL if none was needed * * NOTE: We depend on HDITEMA and HDITEMW having the same structure */static void HEADER_CopyHDItemForNotify(const HEADER_INFO *infoPtr, HDITEMW *dest, const HDITEMW *src, BOOL fSourceUnicode, LPVOID *ppvScratch){ *ppvScratch = NULL; *dest = *src; if (src->mask & HDI_TEXT && src->pszText != LPSTR_TEXTCALLBACKW) /* covers TEXTCALLBACKA as well */ { if (fSourceUnicode && infoPtr->nNotifyFormat != NFR_UNICODE) { dest->pszText = NULL; Str_SetPtrWtoA((LPSTR *)&dest->pszText, src->pszText); *ppvScratch = dest->pszText; } if (!fSourceUnicode && infoPtr->nNotifyFormat == NFR_UNICODE) { dest->pszText = NULL; Str_SetPtrAtoW(&dest->pszText, (LPSTR)src->pszText); *ppvScratch = dest->pszText; } }}
static UINT HEADER_NotifyCodeWtoA(UINT code){ /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/ if (code >= HDN_LAST && code <= HDN_FIRST_UNICODE) return code + HDN_UNICODE_OFFSET; else return code;}
static LRESULTHEADER_SendNotify(const HEADER_INFO *infoPtr, UINT code, NMHDR *nmhdr){ nmhdr->hwndFrom = infoPtr->hwndSelf; nmhdr->idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); nmhdr->code = code;
return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr);}
static BOOLHEADER_SendSimpleNotify (const HEADER_INFO *infoPtr, UINT code){ NMHDR nmhdr; return (BOOL)HEADER_SendNotify(infoPtr, code, &nmhdr);}
static LRESULTHEADER_SendCtrlCustomDraw(const HEADER_INFO *infoPtr, DWORD dwDrawStage, HDC hdc, const RECT *rect){ NMCUSTOMDRAW nm; nm.dwDrawStage = dwDrawStage; nm.hdc = hdc; nm.rc = *rect; nm.dwItemSpec = 0; nm.uItemState = 0; nm.lItemlParam = 0;
return HEADER_SendNotify(infoPtr, NM_CUSTOMDRAW, (NMHDR *)&nm);}
static BOOLHEADER_SendNotifyWithHDItemT(const HEADER_INFO *infoPtr, UINT code, INT iItem, HDITEMW *lpItem){ NMHEADERW nmhdr; if (infoPtr->nNotifyFormat != NFR_UNICODE) code = HEADER_NotifyCodeWtoA(code); nmhdr.iItem = iItem; nmhdr.iButton = 0; nmhdr.pitem = lpItem;
return (BOOL)HEADER_SendNotify(infoPtr, code, (NMHDR *)&nmhdr);}
static BOOLHEADER_SendNotifyWithIntFieldT(const HEADER_INFO *infoPtr, UINT code, INT iItem, INT mask, INT iValue){ HDITEMW nmitem;
/* copying only the iValue should be ok but to make the code more robust we copy everything */ nmitem.cxy = infoPtr->items[iItem].cxy; nmitem.hbm = infoPtr->items[iItem].hbm; nmitem.pszText = NULL; nmitem.cchTextMax = 0; nmitem.fmt = infoPtr->items[iItem].fmt; nmitem.lParam = infoPtr->items[iItem].lParam; nmitem.iOrder = infoPtr->items[iItem].iOrder; nmitem.iImage = infoPtr->items[iItem].iImage;
nmitem.mask = mask; switch (mask) { case HDI_WIDTH: nmitem.cxy = iValue; break; case HDI_ORDER: nmitem.iOrder = iValue; break; default: ERR("invalid mask value 0x%x\n", iValue); }
return HEADER_SendNotifyWithHDItemT(infoPtr, code, iItem, &nmitem);}
/** * Prepare callback items * depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA * (so we handle the two cases only doing a specific cast for pszText). * Checks if any of the required fields is a callback. If this is the case sends a * NMHDISPINFO notify to retrieve these items. The items are stored in the * HEADER_ITEM pszText and iImage fields. They should be freed with * HEADER_FreeCallbackItems. * * @param hwnd : hwnd header container handler * @param iItem : the header item id * @param reqMask : required fields. If any of them is callback this function will fetch it * * @return TRUE on success, else FALSE */static BOOLHEADER_PrepareCallbackItems(const HEADER_INFO *infoPtr, INT iItem, INT reqMask){ HEADER_ITEM *lpItem = &infoPtr->items[iItem]; DWORD mask = reqMask & lpItem->callbackMask; NMHDDISPINFOW dispInfo; void *pvBuffer = NULL;
if (mask == 0) return TRUE; if (mask&HDI_TEXT && lpItem->pszText != NULL) { ERR("(): function called without a call to FreeCallbackItems\n"); heap_free(lpItem->pszText); lpItem->pszText = NULL; } memset(&dispInfo, 0, sizeof(NMHDDISPINFOW)); dispInfo.hdr.hwndFrom = infoPtr->hwndSelf; dispInfo.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); if (infoPtr->nNotifyFormat == NFR_UNICODE) { dispInfo.hdr.code = HDN_GETDISPINFOW; if (mask & HDI_TEXT) pvBuffer = heap_alloc_zero(MAX_HEADER_TEXT_LEN * sizeof(WCHAR)); } else { dispInfo.hdr.code = HDN_GETDISPINFOA; if (mask & HDI_TEXT) pvBuffer = heap_alloc_zero(MAX_HEADER_TEXT_LEN * sizeof(CHAR)); } dispInfo.pszText = pvBuffer; dispInfo.cchTextMax = (pvBuffer!=NULL?MAX_HEADER_TEXT_LEN:0); dispInfo.iItem = iItem; dispInfo.mask = mask; dispInfo.lParam = lpItem->lParam; TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr->nNotifyFormat == NFR_UNICODE?'W':'A'); SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, dispInfo.hdr.idFrom, (LPARAM)&dispInfo);
TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n", dispInfo.mask, (infoPtr->nNotifyFormat == NFR_UNICODE ? debugstr_w(dispInfo.pszText) : (LPSTR) dispInfo.pszText), (void*) dispInfo.lParam); if (mask & HDI_IMAGE) lpItem->iImage = dispInfo.iImage; if (mask & HDI_TEXT) { if (infoPtr->nNotifyFormat == NFR_UNICODE) { lpItem->pszText = pvBuffer;
/* the user might have used his own buffer */ if (dispInfo.pszText != lpItem->pszText) Str_GetPtrW(dispInfo.pszText, lpItem->pszText, MAX_HEADER_TEXT_LEN); } else { Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)dispInfo.pszText); heap_free(pvBuffer); } } if (dispInfo.mask & HDI_DI_SETITEM) { /* make the items permanent */ lpItem->callbackMask &= ~dispInfo.mask; } return TRUE;}
/*** * DESCRIPTION: * Free the items that might be allocated with HEADER_PrepareCallbackItems * * PARAMETER(S): * [I] lpItem : the item to free the data * */static voidHEADER_FreeCallbackItems(HEADER_ITEM *lpItem){ if (lpItem->callbackMask&HDI_TEXT) { heap_free(lpItem->pszText); lpItem->pszText = NULL; }
if (lpItem->callbackMask&HDI_IMAGE) lpItem->iImage = I_IMAGECALLBACK;}
static HIMAGELISTHEADER_CreateDragImage (HEADER_INFO *infoPtr, INT iItem){ HEADER_ITEM *lpItem; HIMAGELIST himl; HBITMAP hMemory, hOldBitmap; LRESULT lCDFlags; RECT rc; HDC hMemoryDC; HDC hDeviceDC; int height, width; HFONT hFont; if (iItem >= infoPtr->uNumItem) return NULL;
if (!infoPtr->bRectsValid) HEADER_SetItemBounds(infoPtr);
lpItem = &infoPtr->items[iItem]; width = lpItem->rect.right - lpItem->rect.left; height = lpItem->rect.bottom - lpItem->rect.top; hDeviceDC = GetDC(NULL); hMemoryDC = CreateCompatibleDC(hDeviceDC); hMemory = CreateCompatibleBitmap(hDeviceDC, width, height); ReleaseDC(NULL, hDeviceDC); hOldBitmap = SelectObject(hMemoryDC, hMemory); SetViewportOrgEx(hMemoryDC, -lpItem->rect.left, -lpItem->rect.top, NULL); hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject(SYSTEM_FONT); SelectObject(hMemoryDC, hFont);
GetClientRect(infoPtr->hwndSelf, &rc); lCDFlags = HEADER_SendCtrlCustomDraw(infoPtr, CDDS_PREPAINT, hMemoryDC, &rc); HEADER_DrawItem(infoPtr, hMemoryDC, iItem, FALSE, lCDFlags); if (lCDFlags & CDRF_NOTIFYPOSTPAINT) HEADER_SendCtrlCustomDraw(infoPtr, CDDS_POSTPAINT, hMemoryDC, &rc); hMemory = SelectObject(hMemoryDC, hOldBitmap); DeleteDC(hMemoryDC); if (hMemory == NULL) /* if anything failed */ return NULL;
himl = ImageList_Create(width, height, ILC_COLORDDB, 1, 1); ImageList_Add(himl, hMemory, NULL); DeleteObject(hMemory); return himl;}
static LRESULTHEADER_SetHotDivider(HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam){ INT iDivider; RECT r; if (wParam) { POINT pt; UINT flags; pt.x = (INT)(SHORT)LOWORD(lParam); pt.y = 0; HEADER_InternalHitTest (infoPtr, &pt, &flags, &iDivider); if (flags & HHT_TOLEFT) iDivider = 0; else if (flags & HHT_NOWHERE || flags & HHT_TORIGHT) iDivider = infoPtr->uNumItem; else { HEADER_ITEM *lpItem = &infoPtr->items[iDivider]; if (pt.x > (lpItem->rect.left+lpItem->rect.right)/2) iDivider = HEADER_NextItem(infoPtr, iDivider); } } else iDivider = (INT)lParam; /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */ if (iDivider<-1 || iDivider>(int)infoPtr->uNumItem) return iDivider;
if (iDivider != infoPtr->iHotDivider) { if (infoPtr->iHotDivider != -1) { HEADER_GetHotDividerRect(infoPtr, &r); InvalidateRect(infoPtr->hwndSelf, &r, FALSE); } infoPtr->iHotDivider = iDivider; if (iDivider != -1) { HEADER_GetHotDividerRect(infoPtr, &r); InvalidateRect(infoPtr->hwndSelf, &r, FALSE); } } return iDivider;}
static LRESULTHEADER_DeleteItem (HEADER_INFO *infoPtr, INT iItem){ INT iOrder; UINT i;
TRACE("[iItem=%d]\n", iItem);
if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem)) return FALSE;
for (i = 0; i < infoPtr->uNumItem; i++) TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
iOrder = infoPtr->items[iItem].iOrder; heap_free(infoPtr->items[iItem].pszText);
infoPtr->uNumItem--; memmove(&infoPtr->items[iItem], &infoPtr->items[iItem + 1], (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM)); memmove(&infoPtr->order[iOrder], &infoPtr->order[iOrder + 1], (infoPtr->uNumItem - iOrder) * sizeof(INT)); infoPtr->items = heap_realloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem); infoPtr->order = heap_realloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem); /* Correct the orders */ for (i = 0; i < infoPtr->uNumItem; i++) { if (infoPtr->order[i] > iItem) infoPtr->order[i]--; if (i >= iOrder) infoPtr->items[infoPtr->order[i]].iOrder = i; } for (i = 0; i < infoPtr->uNumItem; i++) TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
HEADER_SetItemBounds (infoPtr); InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return TRUE;}
static LRESULTHEADER_GetImageList (const HEADER_INFO *infoPtr){ return (LRESULT)infoPtr->himl;}
static LRESULTHEADER_GetItemT (const HEADER_INFO *infoPtr, INT nItem, LPHDITEMW phdi, BOOL bUnicode){ HEADER_ITEM *lpItem; UINT mask;
if (!phdi) return FALSE;
TRACE("[nItem=%d]\n", nItem);
mask = phdi->mask; if (mask == 0) return TRUE;
if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) return FALSE;
if (mask & HDI_UNKNOWN_FIELDS) { TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask); mask &= HDI_COMCTL32_4_0_FIELDS; } lpItem = &infoPtr->items[nItem]; HEADER_PrepareCallbackItems(infoPtr, nItem, mask);
if (mask & HDI_BITMAP) phdi->hbm = lpItem->hbm;
if (mask & HDI_FORMAT) phdi->fmt = lpItem->fmt;
if (mask & HDI_WIDTH) phdi->cxy = lpItem->cxy;
if (mask & HDI_LPARAM) phdi->lParam = lpItem->lParam;
if (mask & HDI_IMAGE) phdi->iImage = lpItem->iImage;
if (mask & HDI_ORDER) phdi->iOrder = lpItem->iOrder;
if (mask & HDI_TEXT) { if (bUnicode) Str_GetPtrW (lpItem->pszText, phdi->pszText, phdi->cchTextMax); else Str_GetPtrWtoA (lpItem->pszText, (LPSTR)phdi->pszText, phdi->cchTextMax); }
HEADER_FreeCallbackItems(lpItem); return TRUE;}
static inline LRESULTHEADER_GetItemCount (const HEADER_INFO *infoPtr){ return infoPtr->uNumItem;}
static LRESULTHEADER_GetItemRect (const HEADER_INFO *infoPtr, INT iItem, LPRECT lpRect){ if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem)) return FALSE;
lpRect->left = infoPtr->items[iItem].rect.left; lpRect->right = infoPtr->items[iItem].rect.right; lpRect->top = infoPtr->items[iItem].rect.top; lpRect->bottom = infoPtr->items[iItem].rect.bottom;
return TRUE;}
static LRESULTHEADER_GetOrderArray(const HEADER_INFO *infoPtr, INT size, LPINT order){ if ((UINT)size <infoPtr->uNumItem) return FALSE;
memcpy(order, infoPtr->order, infoPtr->uNumItem * sizeof(INT)); return TRUE;}
/* Returns index of first duplicate 'value' from [0,to) range, or -1 if there isn't any */static INT has_duplicate(const INT *array, INT to, INT value){ INT i; for(i = 0; i < to; i++) if (array[i] == value) return i; return -1;}
/* returns next available value from [0,max] not to duplicate in [0,to) */static INT get_nextvalue(const INT *array, INT to, INT max){ INT i; for(i = 0; i < max; i++) if (has_duplicate(array, to, i) == -1) return i; return 0;}
static LRESULTHEADER_SetOrderArray(HEADER_INFO *infoPtr, INT size, const INT *order){ HEADER_ITEM *lpItem; INT i;
if ((UINT)size != infoPtr->uNumItem) return FALSE;
if (TRACE_ON(header)) { TRACE("count=%d, order array={", size); for (i = 0; i < size; i++) TRACE("%d%c", order[i], i != size-1 ? ',' : '}'); TRACE("\n"); }
for (i=0; i<size; i++) { if (order[i] >= size || order[i] < 0) /* on invalid index get next available */ /* FIXME: if i==0 array item is out of range behaviour is different, see tests */ infoPtr->order[i] = get_nextvalue(infoPtr->order, i, size); else { INT j, dup;
infoPtr->order[i] = order[i]; j = i; /* remove duplicates */ while ((dup = has_duplicate(infoPtr->order, j, order[j])) != -1) { INT next;
next = get_nextvalue(infoPtr->order, j, size); infoPtr->order[dup] = next; j--; } } } /* sync with item data */ for (i=0; i<size; i++) { lpItem = &infoPtr->items[infoPtr->order[i]]; lpItem->iOrder = i; } HEADER_SetItemBounds(infoPtr); InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); return TRUE;}
static inline LRESULTHEADER_GetUnicodeFormat (const HEADER_INFO *infoPtr){ return (infoPtr->nNotifyFormat == NFR_UNICODE);}
static LRESULTHEADER_HitTest (const HEADER_INFO *infoPtr, LPHDHITTESTINFO phti){ UINT outside = HHT_NOWHERE | HHT_ABOVE | HHT_BELOW | HHT_TOLEFT | HHT_TORIGHT;
HEADER_InternalHitTest (infoPtr, &phti->pt, &phti->flags, &phti->iItem);
if (phti->flags & outside) return phti->iItem = -1; else return phti->iItem;}
static LRESULTHEADER_InsertItemT (HEADER_INFO *infoPtr, INT nItem, const HDITEMW *phdi, BOOL bUnicode){ HEADER_ITEM *lpItem; INT iOrder; UINT i; UINT copyMask;
if ((phdi == NULL) || (nItem < 0) || (phdi->mask == 0)) return -1;
if (nItem > infoPtr->uNumItem) nItem = infoPtr->uNumItem;
iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem; if (iOrder < 0) iOrder = 0; else if (infoPtr->uNumItem < iOrder) iOrder = infoPtr->uNumItem;
infoPtr->uNumItem++; infoPtr->items = heap_realloc(infoPtr->items, sizeof(HEADER_ITEM) * infoPtr->uNumItem); infoPtr->order = heap_realloc(infoPtr->order, sizeof(INT) * infoPtr->uNumItem); /* make space for the new item */ memmove(&infoPtr->items[nItem + 1], &infoPtr->items[nItem], (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM)); memmove(&infoPtr->order[iOrder + 1], &infoPtr->order[iOrder], (infoPtr->uNumItem - iOrder - 1) * sizeof(INT));
/* update the order array */ infoPtr->order[iOrder] = nItem; for (i = 0; i < infoPtr->uNumItem; i++) { if (i != iOrder && infoPtr->order[i] >= nItem) infoPtr->order[i]++; infoPtr->items[infoPtr->order[i]].iOrder = i; }
lpItem = &infoPtr->items[nItem]; ZeroMemory(lpItem, sizeof(HEADER_ITEM)); /* cxy, fmt and lParam are copied even if not in the HDITEM mask */ copyMask = phdi->mask | HDI_WIDTH | HDI_FORMAT | HDI_LPARAM; HEADER_StoreHDItemInHeader(lpItem, copyMask, phdi, bUnicode); lpItem->iOrder = iOrder;
/* set automatically some format bits */ if (phdi->mask & HDI_TEXT) lpItem->fmt |= HDF_STRING; else lpItem->fmt &= ~HDF_STRING;
if (lpItem->hbm != NULL) lpItem->fmt |= HDF_BITMAP; else lpItem->fmt &= ~HDF_BITMAP;
if (phdi->mask & HDI_IMAGE) lpItem->fmt |= HDF_IMAGE;
HEADER_SetItemBounds (infoPtr); InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return nItem;}
static LRESULTHEADER_Layout (HEADER_INFO *infoPtr, LPHDLAYOUT lpLayout){ lpLayout->pwpos->hwnd = infoPtr->hwndSelf; lpLayout->pwpos->hwndInsertAfter = 0; lpLayout->pwpos->x = lpLayout->prc->left; lpLayout->pwpos->y = lpLayout->prc->top; lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left; if (infoPtr->dwStyle & HDS_HIDDEN) lpLayout->pwpos->cy = 0; else { lpLayout->pwpos->cy = infoPtr->nHeight; lpLayout->prc->top += infoPtr->nHeight; } lpLayout->pwpos->flags = SWP_NOZORDER;
TRACE("Layout x=%d y=%d cx=%d cy=%d\n", lpLayout->pwpos->x, lpLayout->pwpos->y, lpLayout->pwpos->cx, lpLayout->pwpos->cy);
infoPtr->bRectsValid = FALSE;
return TRUE;}
static LRESULTHEADER_SetImageList (HEADER_INFO *infoPtr, HIMAGELIST himl){ HIMAGELIST himlOld;
TRACE("(himl %p)\n", himl); himlOld = infoPtr->himl; infoPtr->himl = himl;
/* FIXME: Refresh needed??? */
return (LRESULT)himlOld;}
static LRESULTHEADER_GetBitmapMargin(const HEADER_INFO *infoPtr){ return infoPtr->iMargin;}
static LRESULTHEADER_SetBitmapMargin(HEADER_INFO *infoPtr, INT iMargin){ INT oldMargin = infoPtr->iMargin;
infoPtr->iMargin = iMargin;
return oldMargin;}
static LRESULTHEADER_SetItemT (HEADER_INFO *infoPtr, INT nItem, const HDITEMW *phdi, BOOL bUnicode){ HEADER_ITEM *lpItem; HDITEMW hdNotify; void *pvScratch;
if (phdi == NULL) return FALSE; if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) return FALSE;
TRACE("[nItem=%d]\n", nItem);
HEADER_CopyHDItemForNotify(infoPtr, &hdNotify, phdi, bUnicode, &pvScratch); if (HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCHANGINGW, nItem, &hdNotify)) { heap_free(pvScratch); return FALSE; }
lpItem = &infoPtr->items[nItem]; HEADER_StoreHDItemInHeader(lpItem, phdi->mask, phdi, bUnicode);
if (phdi->mask & HDI_ORDER) if (phdi->iOrder >= 0 && phdi->iOrder < infoPtr->uNumItem) HEADER_ChangeItemOrder(infoPtr, nItem, phdi->iOrder);
HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCHANGEDW, nItem, &hdNotify);
HEADER_SetItemBounds (infoPtr);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
heap_free(pvScratch); return TRUE;}
static inline LRESULTHEADER_SetUnicodeFormat (HEADER_INFO *infoPtr, WPARAM wParam){ BOOL bTemp = (infoPtr->nNotifyFormat == NFR_UNICODE);
infoPtr->nNotifyFormat = ((BOOL)wParam ? NFR_UNICODE : NFR_ANSI);
return bTemp;}
static LRESULTHEADER_Create (HWND hwnd, const CREATESTRUCTW *lpcs){ HEADER_INFO *infoPtr; TEXTMETRICW tm; HFONT hOldFont; HDC hdc;
infoPtr = heap_alloc_zero (sizeof(*infoPtr)); SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
infoPtr->hwndSelf = hwnd; infoPtr->hwndNotify = lpcs->hwndParent; infoPtr->uNumItem = 0; infoPtr->hFont = 0; infoPtr->items = 0; infoPtr->order = 0; infoPtr->bRectsValid = FALSE; infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER)); infoPtr->hcurDivopen = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDEROPEN)); infoPtr->bPressed = FALSE; infoPtr->bTracking = FALSE; infoPtr->dwStyle = lpcs->style; infoPtr->iMoveItem = 0; infoPtr->himl = 0; infoPtr->iHotItem = -1; infoPtr->iHotDivider = -1; infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE); infoPtr->nNotifyFormat = SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); infoPtr->filter_change_timeout = 1000;
hdc = GetDC (0); hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT)); GetTextMetricsW (hdc, &tm); infoPtr->nHeight = tm.tmHeight + VERT_BORDER; SelectObject (hdc, hOldFont); ReleaseDC (0, hdc);
OpenThemeData(hwnd, themeClass);
return 0;}
static LRESULTHEADER_Destroy (HEADER_INFO *infoPtr){ HTHEME theme = GetWindowTheme(infoPtr->hwndSelf); CloseThemeData(theme); return 0;}
static LRESULTHEADER_NCDestroy (HEADER_INFO *infoPtr){ HEADER_ITEM *lpItem; INT nItem;
if (infoPtr->items) { lpItem = infoPtr->items; for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) heap_free(lpItem->pszText); heap_free(infoPtr->items); }
heap_free(infoPtr->order);
SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); heap_free(infoPtr);
return 0;}
static inline LRESULTHEADER_GetFont (const HEADER_INFO *infoPtr){ return (LRESULT)infoPtr->hFont;}
static BOOLHEADER_IsDragDistance(const HEADER_INFO *infoPtr, const POINT *pt){ /* Windows allows for a mouse movement before starting the drag. We use the * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance. */ return (abs(infoPtr->ptLButtonDown.x - pt->x)>GetSystemMetrics(SM_CXDOUBLECLK) || abs(infoPtr->ptLButtonDown.y - pt->y)>GetSystemMetrics(SM_CYDOUBLECLK));}
static LRESULTHEADER_LButtonDblClk (const HEADER_INFO *infoPtr, INT x, INT y){ POINT pt; UINT flags; INT nItem;
pt.x = x; pt.y = y; HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
if ((infoPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMDBLCLICKW, nItem, NULL); else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) HEADER_SendNotifyWithHDItemT(infoPtr, HDN_DIVIDERDBLCLICKW, nItem, NULL);
return 0;}
static LRESULTHEADER_LButtonDown (HEADER_INFO *infoPtr, INT x, INT y){ POINT pt; UINT flags; INT nItem; HDC hdc;
pt.x = x; pt.y = y; HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
if ((infoPtr->dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) { SetCapture (infoPtr->hwndSelf); infoPtr->bCaptured = TRUE; infoPtr->bPressed = TRUE; infoPtr->bDragging = FALSE; infoPtr->iMoveItem = nItem; infoPtr->ptLButtonDown = pt;
infoPtr->items[nItem].bDown = TRUE;
/* Send WM_CUSTOMDRAW */ hdc = GetDC (infoPtr->hwndSelf); HEADER_RefreshItem (infoPtr, nItem); ReleaseDC (infoPtr->hwndSelf, hdc);
TRACE("Pressed item %d.\n", nItem); } else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) { INT iCurrWidth = infoPtr->items[nItem].cxy; if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_BEGINTRACKW, nItem, HDI_WIDTH, iCurrWidth)) { SetCapture (infoPtr->hwndSelf); infoPtr->bCaptured = TRUE; infoPtr->bTracking = TRUE; infoPtr->iMoveItem = nItem; infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
if (!(infoPtr->dwStyle & HDS_FULLDRAG)) { infoPtr->xOldTrack = infoPtr->items[nItem].rect.right; hdc = GetDC (infoPtr->hwndSelf); HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack); ReleaseDC (infoPtr->hwndSelf, hdc); }
TRACE("Begin tracking item %d.\n", nItem); } }
return 0;}
static LRESULTHEADER_LButtonUp (HEADER_INFO *infoPtr, INT x, INT y){ POINT pt; UINT flags; INT nItem; HDC hdc;
pt.x = x; pt.y = y; HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
if (infoPtr->bPressed) {
infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
if (infoPtr->bDragging) { HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem]; INT iNewOrder; ImageList_DragShowNolock(FALSE); ImageList_EndDrag();
if (infoPtr->iHotDivider == -1) iNewOrder = -1; else if (infoPtr->iHotDivider == infoPtr->uNumItem) iNewOrder = infoPtr->uNumItem-1; else { iNewOrder = HEADER_IndexToOrder(infoPtr, infoPtr->iHotDivider); if (iNewOrder > lpItem->iOrder) iNewOrder--; }
if (iNewOrder != -1 && !HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ENDDRAG, infoPtr->iMoveItem, HDI_ORDER, iNewOrder)) { HEADER_ChangeItemOrder(infoPtr, infoPtr->iMoveItem, iNewOrder); infoPtr->bRectsValid = FALSE; InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); } else InvalidateRect(infoPtr->hwndSelf, &infoPtr->items[infoPtr->iMoveItem].rect, FALSE);
infoPtr->bDragging = FALSE; HEADER_SetHotDivider(infoPtr, FALSE, -1); } else { hdc = GetDC (infoPtr->hwndSelf); HEADER_RefreshItem (infoPtr, infoPtr->iMoveItem); ReleaseDC (infoPtr->hwndSelf, hdc);
if (!(infoPtr->dwStyle & HDS_DRAGDROP) || !HEADER_IsDragDistance(infoPtr, &pt)) HEADER_SendNotifyWithHDItemT(infoPtr, HDN_ITEMCLICKW, infoPtr->iMoveItem, NULL); }
TRACE("Released item %d.\n", infoPtr->iMoveItem); infoPtr->bPressed = FALSE; } else if (infoPtr->bTracking) { INT iNewWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset; if (iNewWidth < 0) iNewWidth = 0; TRACE("End tracking item %d.\n", infoPtr->iMoveItem); infoPtr->bTracking = FALSE;
HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ENDTRACKW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth);
if (!(infoPtr->dwStyle & HDS_FULLDRAG)) { hdc = GetDC (infoPtr->hwndSelf); HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack); ReleaseDC (infoPtr->hwndSelf, hdc); } if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth)) { infoPtr->items[infoPtr->iMoveItem].cxy = iNewWidth; HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, iNewWidth); }
HEADER_SetItemBounds (infoPtr); InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); }
if (infoPtr->bCaptured) { infoPtr->bCaptured = FALSE; ReleaseCapture (); HEADER_SendSimpleNotify (infoPtr, NM_RELEASEDCAPTURE); }
return 0;}
static LRESULTHEADER_NotifyFormat (HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam){ switch (lParam) { case NF_QUERY: return infoPtr->nNotifyFormat;
case NF_REQUERY: infoPtr->nNotifyFormat = SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); return infoPtr->nNotifyFormat; }
return 0;}
static LRESULTHEADER_MouseLeave (HEADER_INFO *infoPtr){ /* Reset hot-tracked item when mouse leaves control. */ INT oldHotItem = infoPtr->iHotItem; HDC hdc = GetDC (infoPtr->hwndSelf);
infoPtr->iHotItem = -1; if (oldHotItem != -1) HEADER_RefreshItem (infoPtr, oldHotItem); ReleaseDC (infoPtr->hwndSelf, hdc);
return 0;}
static LRESULTHEADER_MouseMove (HEADER_INFO *infoPtr, LPARAM lParam){ POINT pt; UINT flags; INT nItem, nWidth; HDC hdc; /* With theming, hottracking is always enabled */ BOOL hotTrackEnabled = ((infoPtr->dwStyle & HDS_BUTTONS) && (infoPtr->dwStyle & HDS_HOTTRACK)) || (GetWindowTheme (infoPtr->hwndSelf) != NULL); INT oldHotItem = infoPtr->iHotItem;
pt.x = (INT)(SHORT)LOWORD(lParam); pt.y = (INT)(SHORT)HIWORD(lParam); HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
if (hotTrackEnabled) { if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN)) infoPtr->iHotItem = nItem; else infoPtr->iHotItem = -1; }
if (infoPtr->bCaptured) { /* check if we should drag the header */ if (infoPtr->bPressed && !infoPtr->bDragging && (infoPtr->dwStyle & HDS_DRAGDROP) && HEADER_IsDragDistance(infoPtr, &pt)) { if (!HEADER_SendNotifyWithHDItemT(infoPtr, HDN_BEGINDRAG, infoPtr->iMoveItem, NULL)) { HIMAGELIST hDragItem = HEADER_CreateDragImage(infoPtr, infoPtr->iMoveItem); if (hDragItem != NULL) { HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem]; TRACE("Starting item drag\n"); ImageList_BeginDrag(hDragItem, 0, pt.x - lpItem->rect.left, 0); ImageList_DragShowNolock(TRUE); ImageList_Destroy(hDragItem); infoPtr->bDragging = TRUE; } } } if (infoPtr->bDragging) { POINT drag; drag.x = pt.x; drag.y = 0; ClientToScreen(infoPtr->hwndSelf, &drag); ImageList_DragMove(drag.x, drag.y); HEADER_SetHotDivider(infoPtr, TRUE, lParam); } if (infoPtr->bPressed && !infoPtr->bDragging) { BOOL oldState = infoPtr->items[infoPtr->iMoveItem].bDown; if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) infoPtr->items[infoPtr->iMoveItem].bDown = TRUE; else infoPtr->items[infoPtr->iMoveItem].bDown = FALSE; if (oldState != infoPtr->items[infoPtr->iMoveItem].bDown) { hdc = GetDC (infoPtr->hwndSelf); HEADER_RefreshItem (infoPtr, infoPtr->iMoveItem); ReleaseDC (infoPtr->hwndSelf, hdc); }
TRACE("Moving pressed item %d.\n", infoPtr->iMoveItem); } else if (infoPtr->bTracking) { if (infoPtr->dwStyle & HDS_FULLDRAG) { HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem]; nWidth = pt.x - lpItem->rect.left + infoPtr->xTrackOffset; if (!HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, nWidth)) { INT nOldWidth = lpItem->rect.right - lpItem->rect.left; RECT rcClient; RECT rcScroll; if (nWidth < 0) nWidth = 0; infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;#ifdef __REACTOS__ InvalidateRect(infoPtr->hwndSelf, &lpItem->rect, FALSE);#endif HEADER_SetItemBounds(infoPtr); GetClientRect(infoPtr->hwndSelf, &rcClient); rcScroll = rcClient; rcScroll.left = lpItem->rect.left + nOldWidth;#ifdef __REACTOS__ ScrollWindowEx(infoPtr->hwndSelf, nWidth - nOldWidth, 0, &rcScroll, &rcClient, NULL, NULL, SW_INVALIDATE);#else ScrollWindowEx(infoPtr->hwndSelf, nWidth - nOldWidth, 0, &rcScroll, &rcClient, NULL, NULL, 0); InvalidateRect(infoPtr->hwndSelf, &lpItem->rect, FALSE);#endif UpdateWindow(infoPtr->hwndSelf); HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, nWidth); } } else { INT iTrackWidth; hdc = GetDC (infoPtr->hwndSelf); HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack); infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset; if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left) infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left; HEADER_DrawTrackLine (infoPtr, hdc, infoPtr->xOldTrack); ReleaseDC (infoPtr->hwndSelf, hdc); iTrackWidth = infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left; /* FIXME: should stop tracking if HDN_TRACK returns TRUE */ HEADER_SendNotifyWithIntFieldT(infoPtr, HDN_TRACKW, infoPtr->iMoveItem, HDI_WIDTH, iTrackWidth); }
TRACE("Tracking item %d.\n", infoPtr->iMoveItem); } }
if (hotTrackEnabled) { TRACKMOUSEEVENT tme; if (oldHotItem != infoPtr->iHotItem && !infoPtr->bDragging) { hdc = GetDC (infoPtr->hwndSelf); if (oldHotItem != -1) HEADER_RefreshItem (infoPtr, oldHotItem); if (infoPtr->iHotItem != -1) HEADER_RefreshItem (infoPtr, infoPtr->iHotItem); ReleaseDC (infoPtr->hwndSelf, hdc); } tme.cbSize = sizeof( tme ); tme.dwFlags = TME_LEAVE; tme.hwndTrack = infoPtr->hwndSelf; TrackMouseEvent( &tme ); }
return 0;}
static LRESULTHEADER_Paint (HEADER_INFO *infoPtr, HDC hdcParam){ HDC hdc; PAINTSTRUCT ps;
hdc = hdcParam==0 ? BeginPaint (infoPtr->hwndSelf, &ps) : hdcParam; HEADER_Refresh (infoPtr, hdc); if(!hdcParam) EndPaint (infoPtr->hwndSelf, &ps); return 0;}
static LRESULTHEADER_RButtonUp (HEADER_INFO *infoPtr, INT x, INT y){ BOOL bRet; POINT pt;
pt.x = x; pt.y = y;
/* Send a Notify message */ bRet = HEADER_SendSimpleNotify (infoPtr, NM_RCLICK);
/* Change to screen coordinate for WM_CONTEXTMENU */ ClientToScreen(infoPtr->hwndSelf, &pt);
/* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */ SendMessageW( infoPtr->hwndSelf, WM_CONTEXTMENU, (WPARAM) infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y));
return bRet;}
static LRESULTHEADER_SetCursor (HEADER_INFO *infoPtr, LPARAM lParam){ POINT pt; UINT flags; INT nItem;
TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
GetCursorPos (&pt); ScreenToClient (infoPtr->hwndSelf, &pt);
HEADER_InternalHitTest (infoPtr, &pt, &flags, &nItem);
if (flags == HHT_ONDIVIDER) SetCursor (infoPtr->hcurDivider); else if (flags == HHT_ONDIVOPEN) SetCursor (infoPtr->hcurDivopen); else SetCursor (infoPtr->hcurArrow);
return 0;}
static LRESULTHEADER_SetFont (HEADER_INFO *infoPtr, HFONT hFont, WORD Redraw){ TEXTMETRICW tm; HFONT hOldFont; HDC hdc;
infoPtr->hFont = hFont;
hdc = GetDC (0); hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT)); GetTextMetricsW (hdc, &tm); infoPtr->nHeight = tm.tmHeight + VERT_BORDER; SelectObject (hdc, hOldFont); ReleaseDC (0, hdc);
infoPtr->bRectsValid = FALSE;
if (Redraw) { InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); }
return 0;}
static LRESULT HEADER_SetRedraw(HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam){ /* ignoring the InvalidateRect calls is handled by user32. But some apps expect * that we invalidate the header and this has to be done manually */ LRESULT ret;
ret = DefWindowProcW(infoPtr->hwndSelf, WM_SETREDRAW, wParam, lParam); if (wParam) InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); return ret;}
static INT HEADER_StyleChanged(HEADER_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss){ TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n", wStyleType, lpss->styleOld, lpss->styleNew);
if (wStyleType != GWL_STYLE) return 0;
infoPtr->dwStyle = lpss->styleNew;
return 0;}
/* Update the theme handle after a theme change */static LRESULT HEADER_ThemeChanged(const HEADER_INFO *infoPtr){ HTHEME theme = GetWindowTheme(infoPtr->hwndSelf); CloseThemeData(theme); OpenThemeData(infoPtr->hwndSelf, themeClass); InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); return 0;}
static INT HEADER_SetFilterChangeTimeout(HEADER_INFO *infoPtr, INT timeout){ INT old_timeout = infoPtr->filter_change_timeout;
if (timeout != 0) infoPtr->filter_change_timeout = timeout; return old_timeout;}
static LRESULT WINAPIHEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ HEADER_INFO *infoPtr = (HEADER_INFO *)GetWindowLongPtrW(hwnd, 0);
TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, msg, wParam, lParam); if (!infoPtr && (msg != WM_CREATE)) return DefWindowProcW (hwnd, msg, wParam, lParam); switch (msg) {/* case HDM_CLEARFILTER: */
case HDM_CREATEDRAGIMAGE: return (LRESULT)HEADER_CreateDragImage (infoPtr, (INT)wParam);
case HDM_DELETEITEM: return HEADER_DeleteItem (infoPtr, (INT)wParam);
/* case HDM_EDITFILTER: */
case HDM_GETBITMAPMARGIN: return HEADER_GetBitmapMargin(infoPtr);
case HDM_GETIMAGELIST: return HEADER_GetImageList (infoPtr);
case HDM_GETITEMA: case HDM_GETITEMW: return HEADER_GetItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_GETITEMW);
case HDM_GETITEMCOUNT: return HEADER_GetItemCount (infoPtr);
case HDM_GETITEMRECT: return HEADER_GetItemRect (infoPtr, (INT)wParam, (LPRECT)lParam);
case HDM_GETORDERARRAY: return HEADER_GetOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
case HDM_GETUNICODEFORMAT: return HEADER_GetUnicodeFormat (infoPtr);
case HDM_HITTEST: return HEADER_HitTest (infoPtr, (LPHDHITTESTINFO)lParam);
case HDM_INSERTITEMA: case HDM_INSERTITEMW: return HEADER_InsertItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_INSERTITEMW);
case HDM_LAYOUT: return HEADER_Layout (infoPtr, (LPHDLAYOUT)lParam);
case HDM_ORDERTOINDEX: return HEADER_OrderToIndex(infoPtr, (INT)wParam);
case HDM_SETBITMAPMARGIN: return HEADER_SetBitmapMargin(infoPtr, (INT)wParam);
case HDM_SETFILTERCHANGETIMEOUT: return HEADER_SetFilterChangeTimeout(infoPtr, (INT)lParam);
case HDM_SETHOTDIVIDER: return HEADER_SetHotDivider(infoPtr, wParam, lParam);
case HDM_SETIMAGELIST: return HEADER_SetImageList (infoPtr, (HIMAGELIST)lParam);
case HDM_SETITEMA: case HDM_SETITEMW: return HEADER_SetItemT (infoPtr, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_SETITEMW);
case HDM_SETORDERARRAY: return HEADER_SetOrderArray(infoPtr, (INT)wParam, (LPINT)lParam);
case HDM_SETUNICODEFORMAT: return HEADER_SetUnicodeFormat (infoPtr, wParam);
case WM_CREATE: return HEADER_Create (hwnd, (LPCREATESTRUCTW)lParam);
case WM_DESTROY: return HEADER_Destroy (infoPtr);
case WM_NCDESTROY: return HEADER_NCDestroy (infoPtr);
case WM_ERASEBKGND: return 1;
case WM_GETDLGCODE: return DLGC_WANTTAB | DLGC_WANTARROWS;
case WM_GETFONT: return HEADER_GetFont (infoPtr);
case WM_LBUTTONDBLCLK: return HEADER_LButtonDblClk (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
case WM_LBUTTONDOWN: return HEADER_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
case WM_LBUTTONUP: return HEADER_LButtonUp (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
case WM_MOUSELEAVE: return HEADER_MouseLeave (infoPtr);
case WM_MOUSEMOVE: return HEADER_MouseMove (infoPtr, lParam);
case WM_NOTIFYFORMAT: return HEADER_NotifyFormat (infoPtr, wParam, lParam);
case WM_SIZE: return HEADER_Size (infoPtr);
case WM_THEMECHANGED: return HEADER_ThemeChanged (infoPtr);
case WM_PRINTCLIENT: case WM_PAINT: return HEADER_Paint (infoPtr, (HDC)wParam);
case WM_RBUTTONUP: return HEADER_RButtonUp (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
case WM_SETCURSOR: return HEADER_SetCursor (infoPtr, lParam);
case WM_SETFONT: return HEADER_SetFont (infoPtr, (HFONT)wParam, (WORD)lParam);
case WM_SETREDRAW: return HEADER_SetRedraw(infoPtr, wParam, lParam);
case WM_STYLECHANGED: return HEADER_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
case WM_SYSCOLORCHANGE: COMCTL32_RefreshSysColors(); return 0;
default: if ((msg >= WM_USER) && (msg < WM_APP) && !COMCTL32_IsReflectedMessage(msg)) ERR("unknown msg %04x wp=%04lx lp=%08lx\n", msg, wParam, lParam ); return DefWindowProcW(hwnd, msg, wParam, lParam); }}
VOIDHEADER_Register (void){ WNDCLASSW wndClass;
ZeroMemory (&wndClass, sizeof(WNDCLASSW)); wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; wndClass.lpfnWndProc = HEADER_WindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = sizeof(HEADER_INFO *); wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); wndClass.lpszClassName = WC_HEADERW;
RegisterClassW (&wndClass);}
VOIDHEADER_Unregister (void){ UnregisterClassW (WC_HEADERW, NULL);}