diff --git a/reactos/dll/win32/comctl32/comctl32undoc.c b/reactos/dll/win32/comctl32/comctl32undoc.c index 54d5ca8a643..bdf20f554c8 100644 --- a/reactos/dll/win32/comctl32/comctl32undoc.c +++ b/reactos/dll/win32/comctl32/comctl32undoc.c @@ -147,8 +147,8 @@ DWORD WINAPI GetSize (LPVOID lpMem) * MRU-Functions {COMCTL32} * * NOTES - * The MRU-Api is a set of functions to manipulate lists of M.R.U. (Most Recently - * Used) items. It is an undocumented Api that is used (at least) by the shell + * The MRU-API is a set of functions to manipulate lists of M.R.U. (Most Recently + * Used) items. It is an undocumented API that is used (at least) by the shell * and explorer to implement their recent documents feature. * * Since these functions are undocumented, they are unsupported by MS and diff --git a/reactos/dll/win32/comctl32/datetime.c b/reactos/dll/win32/comctl32/datetime.c index ff2edede88f..825b4427d1e 100644 --- a/reactos/dll/win32/comctl32/datetime.c +++ b/reactos/dll/win32/comctl32/datetime.c @@ -205,16 +205,16 @@ DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, const SYSTEMTIME *sy systime->wHour, systime->wMinute, systime->wSecond); if (flag == GDT_VALID) { - if (systime->wYear == 0 || - systime->wMonth < 1 || systime->wMonth > 12 || - systime->wDay < 1 || - systime->wDay > MONTHCAL_MonthLength(systime->wMonth, systime->wYear) || - systime->wHour > 23 || - systime->wMinute > 59 || - systime->wSecond > 59 || - systime->wMilliseconds > 999 - ) - return FALSE; + if (systime->wYear == 0 || + systime->wMonth < 1 || systime->wMonth > 12 || + systime->wDay < 1 || + systime->wDay > MONTHCAL_MonthLength(systime->wMonth, systime->wYear) || + systime->wHour > 23 || + systime->wMinute > 59 || + systime->wSecond > 59 || + systime->wMilliseconds > 999 + ) + return FALSE; /* Windows returns true if the date is valid but outside the limits set */ if (DATETIME_IsDateInValidRange(infoPtr, systime) == FALSE) diff --git a/reactos/dll/win32/comctl32/dpa.c b/reactos/dll/win32/comctl32/dpa.c index 9566c610658..eceabca1ef4 100644 --- a/reactos/dll/win32/comctl32/dpa.c +++ b/reactos/dll/win32/comctl32/dpa.c @@ -459,7 +459,7 @@ BOOL WINAPI DPA_Grow (HDPA hdpa, INT nGrow) /************************************************************************** * DPA_Clone [COMCTL32.331] * - * Copies a pointer array to an other one or creates a copy + * Copies a pointer array to another one or creates a copy * * PARAMS * hdpa [I] handle (pointer) to the existing (source) pointer array diff --git a/reactos/dll/win32/comctl32/imagelist.c b/reactos/dll/win32/comctl32/imagelist.c index 75825764618..dfce617c3bb 100644 --- a/reactos/dll/win32/comctl32/imagelist.c +++ b/reactos/dll/win32/comctl32/imagelist.c @@ -118,6 +118,7 @@ typedef struct { HWND hwnd; HIMAGELIST himl; + HIMAGELIST himlNoCursor; /* position of the drag image relative to the window */ INT x; INT y; @@ -130,7 +131,7 @@ typedef struct HBITMAP hbmBg; } INTERNALDRAG; -static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 }; +static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, 0, FALSE, 0 }; static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count); static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv); @@ -611,7 +612,7 @@ ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack, cx = himlTrack->cx; cy = himlTrack->cy; - InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1); + InternalDrag.himlNoCursor = InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1); if (InternalDrag.himl == NULL) { WARN("Error creating drag image list!\n"); return FALSE; @@ -1639,8 +1640,10 @@ ImageList_EndDrag (void) { /* cleanup the InternalDrag struct */ InternalDrag.hwnd = 0; + if (InternalDrag.himl != InternalDrag.himlNoCursor) + ImageList_Destroy (InternalDrag.himlNoCursor); ImageList_Destroy (InternalDrag.himl); - InternalDrag.himl = 0; + InternalDrag.himlNoCursor = InternalDrag.himl = 0; InternalDrag.x= 0; InternalDrag.y= 0; InternalDrag.dxHotspot = 0; @@ -2083,6 +2086,7 @@ ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2, INT cxDst, cyDst; INT xOff1, yOff1, xOff2, yOff2; POINT pt1, pt2; + INT newFlags; TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2, i2, dx, dy); @@ -2122,7 +2126,10 @@ ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2, yOff2 = 0; } - himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1); + newFlags = (himl1->flags > himl2->flags ? himl1->flags : himl2->flags) & ILC_COLORDDB; + if (newFlags == ILC_COLORDDB && (himl1->flags & ILC_COLORDDB) == ILC_COLOR16) + newFlags = ILC_COLOR16; /* this is what native (at least v5) does, don't know why */ + himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | newFlags, 1, 1); if (himlDst) { @@ -2135,8 +2142,13 @@ ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2, BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, pt1.x, pt1.y, SRCCOPY); if (i2 >= 0 && i2 < himl2->cCurImage) { - BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND); - BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT); + if (himl2->flags & ILC_MASK) + { + BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , pt2.x, pt2.y, SRCAND); + BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCPAINT); + } + else + BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, pt2.x, pt2.y, SRCCOPY); } /* copy mask */ @@ -2239,7 +2251,7 @@ HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm) void *image_bits, *mask_bits = NULL; ILHEAD ilHead; HIMAGELIST himl; - int i; + unsigned int i; TRACE("%p\n", pstm); @@ -2703,7 +2715,7 @@ ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag, visible = InternalDrag.bShow; - himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, + himlTemp = ImageList_Merge (InternalDrag.himlNoCursor, 0, himlDrag, iDrag, dxHotspot, dyHotspot); if (visible) { @@ -2717,7 +2729,8 @@ ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag, InternalDrag.hbmBg = 0; } - ImageList_Destroy (InternalDrag.himl); + if (InternalDrag.himl != InternalDrag.himlNoCursor) + ImageList_Destroy (InternalDrag.himl); InternalDrag.himl = himlTemp; if (visible) { diff --git a/reactos/dll/win32/comctl32/listview.c b/reactos/dll/win32/comctl32/listview.c index c2869528c0e..675169b326c 100644 --- a/reactos/dll/win32/comctl32/listview.c +++ b/reactos/dll/win32/comctl32/listview.c @@ -6,8 +6,9 @@ * Copyright 2000 Jason Mawdsley * Copyright 2001 CodeWeavers Inc. * Copyright 2002 Dimitrie O. Paun - * Copyright 2009-2012 Nikolay Sivov + * Copyright 2009-2013 Nikolay Sivov * Copyright 2009 Owen Rudge for CodeWeavers + * Copyright 2012-2013 Daniel Jelinski * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -54,7 +55,6 @@ * -- LVA_SNAPTOGRID not implemented * -- LISTVIEW_ApproximateViewRect partially implemented * -- LISTVIEW_SetColumnWidth ignores header images & bitmap - * -- LISTVIEW_SetIconSpacing is incomplete * -- LISTVIEW_StyleChanged doesn't handle some changes too well * * Speedups @@ -75,7 +75,6 @@ * States * -- LVIS_ACTIVATING (not currently supported by comctl32.dll version 6.0) * -- LVIS_DROPHILITED - * -- LVIS_OVERLAYMASK * * Styles * -- LVS_NOLABELWRAP @@ -99,7 +98,6 @@ * -- LVN_GETINFOTIP * -- LVN_HOTTRACK * -- LVN_SETDISPINFO - * -- LVN_BEGINRDRAG * * Messages: * -- LVM_ENABLEGROUPVIEW @@ -290,6 +288,7 @@ typedef struct tagLISTVIEW_INFO HIMAGELIST himlSmall; HIMAGELIST himlState; SIZE iconSize; + BOOL autoSpacing; SIZE iconSpacing; SIZE iconStateSize; POINT currIconPos; /* this is the position next icon will be placed */ @@ -326,12 +325,12 @@ typedef struct tagLISTVIEW_INFO /* mouse operation */ BOOL bLButtonDown; - BOOL bRButtonDown; BOOL bDragging; POINT ptClickPos; /* point where the user clicked */ INT nLButtonDownItem; /* tracks item to reset multiselection on WM_LBUTTONUP */ DWORD dwHoverTime; HCURSOR hHotCursor; + INT cWheelRemainder; /* keyboard operation */ DWORD lastKeyPressTimestamp; @@ -775,13 +774,11 @@ static int get_ansi_notification(UINT unicodeNotificationCode) } /* forwards header notifications to listview parent */ -static LRESULT notify_forward_header(const LISTVIEW_INFO *infoPtr, const NMHEADERW *lpnmh) +static LRESULT notify_forward_header(const LISTVIEW_INFO *infoPtr, NMHEADERW *lpnmhW) { - NMHEADERA nmhA; - HDITEMA hditema; - HD_TEXTFILTERA textfilter; - LPSTR text = NULL, filter = NULL; + LPCWSTR text = NULL, filter = NULL; LRESULT ret; + NMHEADERA *lpnmh = (NMHEADERA*) lpnmhW; /* on unicode format exit earlier */ if (infoPtr->notifyFormat == NFR_UNICODE) @@ -790,37 +787,38 @@ static LRESULT notify_forward_header(const LISTVIEW_INFO *infoPtr, const NMHEADE /* header always supplies unicode notifications, all we have to do is to convert strings to ANSI */ - nmhA = *(const NMHEADERA*)lpnmh; if (lpnmh->pitem) { - hditema = *(HDITEMA*)lpnmh->pitem; - nmhA.pitem = &hditema; /* convert item text */ if (lpnmh->pitem->mask & HDI_TEXT) { - hditema.pszText = NULL; - Str_SetPtrWtoA(&hditema.pszText, lpnmh->pitem->pszText); - text = hditema.pszText; + text = (LPCWSTR)lpnmh->pitem->pszText; + Str_SetPtrWtoA(&lpnmh->pitem->pszText, text); } /* convert filter text */ if ((lpnmh->pitem->mask & HDI_FILTER) && (lpnmh->pitem->type == HDFT_ISSTRING) && lpnmh->pitem->pvFilter) { - hditema.pvFilter = &textfilter; - textfilter = *(HD_TEXTFILTERA*)(lpnmh->pitem->pvFilter); - textfilter.pszText = NULL; - Str_SetPtrWtoA(&textfilter.pszText, ((HD_TEXTFILTERW*)lpnmh->pitem->pvFilter)->pszText); - filter = textfilter.pszText; + filter = (LPCWSTR)((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText; + Str_SetPtrWtoA(&((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText, filter); } } - nmhA.hdr.code = get_ansi_notification(lpnmh->hdr.code); + lpnmh->hdr.code = get_ansi_notification(lpnmh->hdr.code); - ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhA.hdr.idFrom, - (LPARAM)&nmhA); + ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmh->hdr.idFrom, + (LPARAM)lpnmh); /* cleanup */ - Free(text); - Free(filter); + if(text) + { + Free(lpnmh->pitem->pszText); + lpnmh->pitem->pszText = (LPSTR)text; + } + if(filter) + { + Free(((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText); + ((HD_TEXTFILTERA*)lpnmh->pitem->pvFilter)->pszText = (LPSTR)filter; + } return ret; } @@ -888,11 +886,13 @@ static inline LRESULT notify_listview(const LISTVIEW_INFO *infoPtr, INT code, LP return notify_hdr(infoPtr, code, (LPNMHDR)plvnm); } +/* Handles NM_DBLCLK, NM_CLICK, NM_RDBLCLK, NM_RCLICK. Only NM_RCLICK return value is used. */ static BOOL notify_click(const LISTVIEW_INFO *infoPtr, INT code, const LVHITTESTINFO *lvht) { NMITEMACTIVATE nmia; LVITEMW item; HWND hwnd = infoPtr->hwndSelf; + LRESULT ret; TRACE("code=%d, lvht=%s\n", code, debuglvhittestinfo(lvht)); ZeroMemory(&nmia, sizeof(nmia)); @@ -903,8 +903,8 @@ static BOOL notify_click(const LISTVIEW_INFO *infoPtr, INT code, const LVHITTEST item.iItem = lvht->iItem; item.iSubItem = 0; if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmia.lParam = item.lParam; - notify_hdr(infoPtr, code, (LPNMHDR)&nmia); - return IsWindow(hwnd); + ret = notify_hdr(infoPtr, code, (NMHDR*)&nmia); + return IsWindow(hwnd) && (code == NM_RCLICK ? !ret : TRUE); } static BOOL notify_deleteitem(const LISTVIEW_INFO *infoPtr, INT nItem) @@ -1672,6 +1672,10 @@ static INT LISTVIEW_CreateHeader(LISTVIEW_INFO *infoPtr) /* set header font */ SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, TRUE); + /* set header image list */ + if (infoPtr->himlSmall) + SendMessageW(infoPtr->hwndHeader, HDM_SETIMAGELIST, 0, (LPARAM)infoPtr->himlSmall); + LISTVIEW_UpdateSize(infoPtr); return 0; @@ -1847,9 +1851,9 @@ static inline INT LISTVIEW_GetCountPerColumn(const LISTVIEW_INFO *infoPtr) static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData) { WCHAR buffer[MAX_PATH]; - INT endidx, startidx; DWORD prevTime; LVITEMW item; + int startidx; INT nItem; INT diff; @@ -1889,15 +1893,16 @@ static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, L infoPtr->nSearchParamLength = 1; } - /* and search from the current position */ - nItem = -1; - endidx = infoPtr->nItemCount; - /* should start from next after focused item, so next item that matches will be selected, if there isn't any and focused matches it will be selected on second search stage from beginning of the list */ if (infoPtr->nFocusedItem >= 0 && infoPtr->nItemCount > 1) - startidx = infoPtr->nFocusedItem + 1; + { + /* with some accumulated search data available start with current focus, otherwise + it's excluded from search */ + startidx = infoPtr->nSearchParamLength > 1 ? infoPtr->nFocusedItem : infoPtr->nFocusedItem + 1; + if (startidx == infoPtr->nItemCount) startidx = 0; + } else startidx = 0; @@ -1917,7 +1922,11 @@ static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, L } else { - INT i = startidx; + int i = startidx, endidx; + + /* and search from the current position */ + nItem = -1; + endidx = infoPtr->nItemCount; /* first search in [startidx, endidx), on failure continue in [0, startidx) */ while (1) @@ -1939,12 +1948,15 @@ static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, L item.cchTextMax = MAX_PATH; if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0; - if (lstrncmpiW(item.pszText, infoPtr->szSearchParam, infoPtr->nSearchParamLength) == 0) + if (!lstrncmpiW(item.pszText, infoPtr->szSearchParam, infoPtr->nSearchParamLength)) { nItem = i; break; } - else if (nItem == -1 && lstrncmpiW(item.pszText, infoPtr->szSearchParam, 1) == 0) + /* this is used to find first char match when search string is not available yet, + otherwise every WM_CHAR will search to next item by first char, ignoring that we're + already waiting for user to complete a string */ + else if (nItem == -1 && infoPtr->nSearchParamLength == 1 && !lstrncmpiW(item.pszText, infoPtr->szSearchParam, 1)) { /* this would work but we must keep looking for a longer match */ nItem = i; @@ -2376,7 +2388,7 @@ static void LISTVIEW_GetItemMetrics(const LISTVIEW_INFO *infoPtr, const LVITEMW Icon.top = Box.top; Icon.right = Icon.left; if (infoPtr->himlSmall && - (!lpColumnInfo || lpLVItem->iSubItem == 0 || (lpColumnInfo->fmt & LVCFMT_IMAGE) || + (!lpColumnInfo || lpLVItem->iSubItem == 0 || ((infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES) && lpLVItem->iImage != I_IMAGECALLBACK))) Icon.right += infoPtr->iconSize.cx; Icon.bottom = Icon.top + infoPtr->iconSize.cy; @@ -2967,15 +2979,12 @@ static INT LISTVIEW_CalculateItemHeight(const LISTVIEW_INFO *infoPtr) nItemHeight = infoPtr->iconSpacing.cy; else { - nItemHeight = infoPtr->ntmHeight; - if (infoPtr->uView == LV_VIEW_DETAILS && infoPtr->dwLvExStyle & LVS_EX_GRIDLINES) - nItemHeight++; + nItemHeight = infoPtr->ntmHeight; if (infoPtr->himlState) nItemHeight = max(nItemHeight, infoPtr->iconStateSize.cy); if (infoPtr->himlSmall) nItemHeight = max(nItemHeight, infoPtr->iconSize.cy); - if (infoPtr->himlState || infoPtr->himlSmall) - nItemHeight += HEIGHT_PADDING; + nItemHeight += HEIGHT_PADDING; if (infoPtr->nMeasureItemHeight > 0) nItemHeight = infoPtr->nMeasureItemHeight; } @@ -3459,7 +3468,6 @@ static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem) return oldFocus != infoPtr->nFocusedItem; } -/* Helper function for LISTVIEW_ShiftIndices *only* */ static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction) { if (nShiftItem < nItem) return nShiftItem; @@ -3471,6 +3479,24 @@ static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, I return min(nShiftItem, infoPtr->nItemCount - 1); } +/* This function updates focus index. + +Parameters: + focus : current focus index + item : index of item to be added/removed + direction : add/remove flag +*/ +static void LISTVIEW_ShiftFocus(LISTVIEW_INFO *infoPtr, INT focus, INT item, INT direction) +{ + BOOL old_change = infoPtr->bDoChangeNotify; + + infoPtr->bDoChangeNotify = FALSE; + focus = shift_item(infoPtr, focus, item, direction); + if (focus != infoPtr->nFocusedItem) + LISTVIEW_SetItemFocus(infoPtr, focus); + infoPtr->bDoChangeNotify = old_change; +} + /** * DESCRIPTION: * Updates the various indices after an item has been inserted or deleted. @@ -3485,31 +3511,15 @@ static INT shift_item(const LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, I */ static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction) { - INT nNewFocus; - BOOL bOldChange; - - /* temporarily disable change notification while shifting items */ - bOldChange = infoPtr->bDoChangeNotify; - infoPtr->bDoChangeNotify = FALSE; - - TRACE("Shifting %iu, %i steps\n", nItem, direction); + TRACE("Shifting %i, %i steps\n", nItem, direction); ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount); - assert(abs(direction) == 1); - infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction); - nNewFocus = shift_item(infoPtr, infoPtr->nFocusedItem, nItem, direction); - if (nNewFocus != infoPtr->nFocusedItem) - LISTVIEW_SetItemFocus(infoPtr, nNewFocus); - /* But we are not supposed to modify nHotItem! */ - - infoPtr->bDoChangeNotify = bOldChange; } - /** * DESCRIPTION: * Adds a block of selections. @@ -3550,8 +3560,8 @@ static BOOL LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) ZeroMemory(&nmlv, sizeof(nmlv)); nmlv.iFrom = nFirst; nmlv.iTo = nLast; - nmlv.uNewState = 0; - nmlv.uOldState = item.state; + nmlv.uOldState = 0; + nmlv.uNewState = item.state; notify_hdr(infoPtr, LVN_ODSTATECHANGED, (LPNMHDR)&nmlv); if (!IsWindow(hwndSelf)) @@ -3606,9 +3616,15 @@ static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) POINT ptItem; rcItem.left = LVIR_BOUNDS; - if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return; + if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) { + ranges_destroy (selection); + return; + } rcSelMark.left = LVIR_BOUNDS; - if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return; + if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) { + ranges_destroy (selection); + return; + } UnionRect(&rcSel, &rcItem, &rcSelMark); iterator_frameditems(&i, infoPtr, &rcSel); while(iterator_next(&i)) @@ -3989,17 +4005,23 @@ static VOID CALLBACK LISTVIEW_ScrollTimer(HWND hWnd, UINT uMsg, UINT_PTR idEvent */ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y) { + LVHITTESTINFO ht; + RECT rect; + POINT pt; + if (!(fwKeys & MK_LBUTTON)) infoPtr->bLButtonDown = FALSE; if (infoPtr->bLButtonDown) { - POINT tmp; - RECT rect; - LVHITTESTINFO lvHitTestInfo; - WORD wDragWidth = GetSystemMetrics(SM_CXDRAG); - WORD wDragHeight= GetSystemMetrics(SM_CYDRAG); + rect.left = rect.right = infoPtr->ptClickPos.x; + rect.top = rect.bottom = infoPtr->ptClickPos.y; + InflateRect(&rect, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG)); + } + + if (infoPtr->bLButtonDown) + { if (infoPtr->bMarqueeSelect) { POINT coords_orig; @@ -4042,22 +4064,17 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN return 0; } - rect.left = infoPtr->ptClickPos.x - wDragWidth; - rect.right = infoPtr->ptClickPos.x + wDragWidth; - rect.top = infoPtr->ptClickPos.y - wDragHeight; - rect.bottom = infoPtr->ptClickPos.y + wDragHeight; + pt.x = x; + pt.y = y; - tmp.x = x; - tmp.y = y; - - lvHitTestInfo.pt = tmp; - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); + ht.pt = pt; + LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE); /* reset item marker */ - if (infoPtr->nLButtonDownItem != lvHitTestInfo.iItem) + if (infoPtr->nLButtonDownItem != ht.iItem) infoPtr->nLButtonDownItem = -1; - if (!PtInRect(&rect, tmp)) + if (!PtInRect(&rect, pt)) { /* this path covers the following: 1. WM_LBUTTONDOWN over selected item (sets focus on it) @@ -4077,12 +4094,12 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN if (!infoPtr->bDragging) { - lvHitTestInfo.pt = infoPtr->ptClickPos; - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); + ht.pt = infoPtr->ptClickPos; + LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE); /* If the click is outside the range of an item, begin a highlight. If not, begin an item drag. */ - if (lvHitTestInfo.iItem == -1) + if (ht.iItem == -1) { NMHDR hdr; @@ -4107,7 +4124,7 @@ static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, IN NMLISTVIEW nmlv; ZeroMemory(&nmlv, sizeof(nmlv)); - nmlv.iItem = lvHitTestInfo.iItem; + nmlv.iItem = ht.iItem; nmlv.ptAction = infoPtr->ptClickPos; notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv); @@ -4158,7 +4175,7 @@ static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle) /*** * DESCRIPTION: - * Helper for LISTVIEW_SetItemT *only*: sets item attributes. + * Helper for LISTVIEW_SetItemT and LISTVIEW_InsertItemT: sets item attributes. * * PARAMETER(S): * [I] infoPtr : valid pointer to the listview structure @@ -4227,20 +4244,19 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpItem->hdr.pszText, lpLVItem->pszText, isW)) uChanged |= LVIF_TEXT; - TRACE("uChanged=0x%x\n", uChanged); - if (!uChanged) return TRUE; - *bChanged = TRUE; + TRACE("change mask=0x%x\n", uChanged); - ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); + memset(&nmlv, 0, sizeof(NMLISTVIEW)); nmlv.iItem = lpLVItem->iItem; nmlv.uNewState = (item.state & ~stateMask) | (lpLVItem->state & stateMask); nmlv.uOldState = item.state; - nmlv.uChanged = uChanged; + nmlv.uChanged = uChanged ? uChanged : lpLVItem->mask; nmlv.lParam = item.lParam; - - /* send LVN_ITEMCHANGING notification, if the item is not being inserted */ - /* and we are _NOT_ virtual (LVS_OWNERDATA), and change notifications */ - /* are enabled */ + + /* Send LVN_ITEMCHANGING notification, if the item is not being inserted + and we are _NOT_ virtual (LVS_OWNERDATA), and change notifications + are enabled. Even nothing really changed we still need to send this, + in this case uChanged mask is just set to passed item mask. */ if(lpItem && !isNew && infoPtr->bDoChangeNotify) { HWND hwndSelf = infoPtr->hwndSelf; @@ -4251,6 +4267,18 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL return FALSE; } + /* When item is inserted we need to shift existing focus index if new item has lower index. */ + if (isNew && (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED) && + /* this means we won't hit a focus change path later */ + ((uChanged & LVIF_STATE) == 0 || (!(lpLVItem->state & LVIS_FOCUSED) && (infoPtr->nFocusedItem != lpLVItem->iItem)))) + { + if (infoPtr->nFocusedItem != -1 && (lpLVItem->iItem <= infoPtr->nFocusedItem)) + infoPtr->nFocusedItem++; + } + + if (!uChanged) return TRUE; + *bChanged = TRUE; + /* copy information */ if (lpLVItem->mask & LVIF_TEXT) textsetptrT(&lpItem->hdr.pszText, lpLVItem->pszText, isW); @@ -4280,7 +4308,14 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL { ranges_delitem(infoPtr->selectionRanges, lpLVItem->iItem); } - /* if we are asked to change focus, and we manage it, do it */ + /* If we are asked to change focus, and we manage it, do it. + It's important to have all new item data stored at this point, + because changing existing focus could result in a redrawing operation, + which in turn could ask for disp data, application should see all data + for inserted item when processing LVN_GETDISPINFO. + + The way this works application will see nested item change notifications - + changed item notifications interrupted by ones from item losing focus. */ if (stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED) { if (lpLVItem->state & LVIS_FOCUSED) @@ -4312,7 +4347,7 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL /* if we're inserting the item, we're done */ if (isNew) return TRUE; - + /* send LVN_ITEMCHANGED notification */ if (lpLVItem->mask & LVIF_PARAM) nmlv.lParam = lpLVItem->lParam; if (infoPtr->bDoChangeNotify) notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv); @@ -4554,7 +4589,6 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS NMLVCUSTOMDRAW nmlvcd; HIMAGELIST himl; LVITEMW lvItem; - HFONT hOldFont; TRACE("(hdc=%p, nItem=%d, nSubItem=%d, pos=%s)\n", hdc, nItem, nSubItem, wine_dbgstr_point(&pos)); @@ -4562,7 +4596,7 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; if (nSubItem == 0) lvItem.mask |= LVIF_STATE; if (infoPtr->uView == LV_VIEW_DETAILS) lvItem.mask |= LVIF_INDENT; - lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK | LVIS_CUT; + lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK | LVIS_CUT | LVIS_OVERLAYMASK; lvItem.iItem = nItem; lvItem.iSubItem = nSubItem; lvItem.state = 0; @@ -4592,7 +4626,6 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS /* fill in the custom draw structure */ customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem); - hOldFont = GetCurrentObject(hdc, OBJ_FONT); if (nSubItem > 0) cdmode = infoPtr->cditemmode; if (cdmode & CDRF_SKIPDEFAULT) goto postpaint; if (cdmode & CDRF_NOTIFYITEMDRAW) @@ -4600,7 +4633,7 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS if (nSubItem == 0) infoPtr->cditemmode = cdsubitemmode; if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; /* we have to send a CDDS_SUBITEM customdraw explicitly for subitem 0 */ - if (nSubItem == 0 && cdsubitemmode == CDRF_NOTIFYITEMDRAW) + if (nSubItem == 0 && (cdsubitemmode & CDRF_NOTIFYITEMDRAW) != 0) { cdsubitemmode = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPREPAINT, &nmlvcd); if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; @@ -4610,21 +4643,25 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS else if ((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) == FALSE) prepaint_setup(infoPtr, hdc, &nmlvcd, TRUE); - /* in full row select, subitems, will just use main item's colors */ - if (nSubItem && infoPtr->uView == LV_VIEW_DETAILS && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) - nmlvcd.clrTextBk = CLR_NONE; - /* FIXME: temporary hack */ rcSelect.left = rcLabel.left; - /* draw the selection background, if we're drawing the main item */ - if (nSubItem == 0) - { - /* in icon mode, the label rect is really what we want to draw the - * background for */ - if (infoPtr->uView == LV_VIEW_ICON) - rcSelect = rcLabel; + /* in icon mode, the label rect is really what we want to draw the + * background for */ + /* in detail mode, we want to paint background for label rect when + * item is not selected or listview has full row select; otherwise paint + * background for text only */ + if (infoPtr->uView == LV_VIEW_ICON || + (infoPtr->uView == LV_VIEW_DETAILS && + (!(lvItem.state & LVIS_SELECTED) || + (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) != 0))) + rcSelect = rcLabel; + if (nmlvcd.clrTextBk != CLR_NONE) + ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, NULL, 0, NULL); + + if(nSubItem == 0 && infoPtr->nFocusedItem == nItem) + { if (infoPtr->uView == LV_VIEW_DETAILS && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) { /* we have to update left focus bound too if item isn't in leftmost column @@ -4647,10 +4684,8 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS rcSelect.right = rcBox.right; } - if (nmlvcd.clrTextBk != CLR_NONE) - ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, NULL, 0, NULL); /* store new focus rectangle */ - if (infoPtr->nFocusedItem == nItem) infoPtr->rcFocus = rcSelect; + infoPtr->rcFocus = rcSelect; } /* state icons */ @@ -4681,7 +4716,7 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS ImageList_DrawEx(himl, lvItem.iImage, hdc, rcIcon.left, rcIcon.top, rcIcon.right - rcIcon.left, rcIcon.bottom - rcIcon.top, infoPtr->clrBk, lvItem.state & LVIS_CUT ? RGB(255, 255, 255) : CLR_DEFAULT, - style); + style | (lvItem.state & LVIS_OVERLAYMASK)); } /* Don't bother painting item being edited */ @@ -4719,8 +4754,6 @@ static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nS postpaint: if (cdsubitemmode & CDRF_NOTIFYPOSTPAINT) notify_postpaint(infoPtr, &nmlvcd); - if (cdsubitemmode & CDRF_NEWFONT) - SelectObject(hdc, hOldFont); return TRUE; } @@ -4847,6 +4880,7 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, /* iterate through the invalidated rows */ while(iterator_next(i)) { + SelectObject(hdc, infoPtr->hFont); LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); Position.y += Origin.y; @@ -4969,6 +5003,8 @@ static void LISTVIEW_RefreshReportGrid(LISTVIEW_INFO *infoPtr, HDC hdc) SelectObject( hdc, hOldPen ); DeleteObject( hPen ); } + else + ranges_destroy(colRanges); } /*** @@ -4992,6 +5028,7 @@ static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, D while(iterator_prev(i)) { + SelectObject(hdc, infoPtr->hFont); LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); Position.x += Origin.x; Position.y += Origin.y; @@ -5015,7 +5052,7 @@ static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, D */ static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *prcErase) { - COLORREF oldTextColor = 0, oldBkColor = 0, oldClrTextBk, oldClrText; + COLORREF oldTextColor = 0, oldBkColor = 0; NMLVCUSTOMDRAW nmlvcd; HFONT hOldFont = 0; DWORD cdmode; @@ -5072,21 +5109,12 @@ static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *prcEra hdcOrig, infoPtr->rcList.left, infoPtr->rcList.top, SRCCOPY); } - /* FIXME: Shouldn't need to do this */ - oldClrTextBk = infoPtr->clrTextBk; - oldClrText = infoPtr->clrText; - infoPtr->cditemmode = CDRF_DODEFAULT; GetClientRect(infoPtr->hwndSelf, &rcClient); customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, 0); cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); if (cdmode & CDRF_SKIPDEFAULT) goto enddraw; - prepaint_setup(infoPtr, hdc, &nmlvcd, FALSE); - - /* Use these colors to draw the items */ - infoPtr->clrTextBk = nmlvcd.clrTextBk; - infoPtr->clrText = nmlvcd.clrText; /* nothing to draw */ if(infoPtr->nItemCount == 0) goto enddraw; @@ -5139,9 +5167,6 @@ enddraw: if (cdmode & CDRF_NOTIFYPOSTPAINT) notify_postpaint(infoPtr, &nmlvcd); - infoPtr->clrTextBk = oldClrTextBk; - infoPtr->clrText = oldClrText; - if(hbmp) { BitBlt(hdcOrig, infoPtr->rcList.left, infoPtr->rcList.top, infoPtr->rcList.right - infoPtr->rcList.left, @@ -5322,6 +5347,7 @@ static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LP POINT pos; HDC hdc, hdcOrig; HBITMAP hbmp, hOldbmp; + HFONT hOldFont; HIMAGELIST dragList = 0; TRACE("iItem=%d Count=%d\n", iItem, infoPtr->nItemCount); @@ -5342,6 +5368,7 @@ static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LP hdc = CreateCompatibleDC(hdcOrig); hbmp = CreateCompatibleBitmap(hdcOrig, size.cx, size.cy); hOldbmp = SelectObject(hdc, hbmp); + hOldFont = SelectObject(hdc, infoPtr->hFont); rcItem.left = rcItem.top = 0; rcItem.right = size.cx; @@ -5358,6 +5385,7 @@ static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LP else SelectObject(hdc, hOldbmp); + SelectObject(hdc, hOldFont); DeleteObject(hbmp); DeleteDC(hdc); ReleaseDC(infoPtr->hwndSelf, hdcOrig); @@ -5642,9 +5670,8 @@ static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir) TRACE("rcScroll=%s, dx=%d\n", wine_dbgstr_rect(&rcScroll), dir * infoPtr->nItemHeight); if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList)) { - TRACE("Scrolling rcScroll=%s, rcList=%s\n", wine_dbgstr_rect(&rcScroll), wine_dbgstr_rect(&infoPtr->rcList)); - ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight, - &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE); + TRACE("Invalidating rcScroll=%s, rcList=%s\n", wine_dbgstr_rect(&rcScroll), wine_dbgstr_rect(&infoPtr->rcList)); + InvalidateRect(infoPtr->hwndSelf, &rcScroll, TRUE); } /* report has only that column, so we're done */ @@ -5657,8 +5684,7 @@ static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir) rcScroll.bottom = nPerCol * infoPtr->nItemHeight; OffsetRect(&rcScroll, Origin.x, Origin.y); if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList)) - ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight, - &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE); + InvalidateRect(infoPtr->hwndSelf, &rcScroll, TRUE); } /*** @@ -5677,6 +5703,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) { LVITEMW item; const BOOL is_icon = (infoPtr->uView == LV_VIEW_SMALLICON || infoPtr->uView == LV_VIEW_ICON); + INT focus = infoPtr->nFocusedItem; TRACE("(nItem=%d)\n", nItem); @@ -5686,7 +5713,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) item.state = 0; item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; LISTVIEW_SetItemState(infoPtr, nItem, &item); - + /* send LVN_DELETEITEM notification. */ if (!notify_deleteitem(infoPtr, nItem)) return FALSE; @@ -5727,6 +5754,7 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) infoPtr->nItemCount--; LISTVIEW_ShiftIndices(infoPtr, nItem, -1); + LISTVIEW_ShiftFocus(infoPtr, focus, nItem, -1); /* now is the invalidation fun */ if (!is_icon) @@ -6554,7 +6582,7 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, HDPA hdpaSubItems; INT isubitem; - TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); + TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) return FALSE; @@ -7045,65 +7073,61 @@ static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT * * NOTE: for subItem = 0, we should return the bounds of the _entire_ item, * not only those of the first column. - * Fortunately, LISTVIEW_GetItemMetrics does the right thing. * * RETURN: * TRUE: success * FALSE: failure */ -static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc) +static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT item, LPRECT lprc) { - POINT Position, Origin; - LVITEMW lvItem; - INT nColumn; + RECT rect = { 0, 0, 0, 0 }; + POINT origin; + INT y; if (!lprc) return FALSE; - nColumn = lprc->top; - - TRACE("(nItem=%d, nSubItem=%d, type=%d)\n", nItem, lprc->top, lprc->left); - /* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */ + TRACE("(item=%d, subitem=%d, type=%d)\n", item, lprc->top, lprc->left); + /* Subitem of '0' means item itself, and this works for all control view modes */ if (lprc->top == 0) - return LISTVIEW_GetItemRect(infoPtr, nItem, lprc); + return LISTVIEW_GetItemRect(infoPtr, item, lprc); if (infoPtr->uView != LV_VIEW_DETAILS) return FALSE; - /* special case for header items */ - if (nItem == -1) - { - if (lprc->left != LVIR_BOUNDS) - { - FIXME("Only LVIR_BOUNDS is implemented for header, got %d\n", lprc->left); - return FALSE; - } + LISTVIEW_GetOrigin(infoPtr, &origin); + /* this works for any item index, no matter if it exists or not */ + y = item * infoPtr->nItemHeight + origin.y; - if (infoPtr->hwndHeader) - return SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)lprc); - else - { - memset(lprc, 0, sizeof(RECT)); - return TRUE; - } + if (infoPtr->hwndHeader && SendMessageW(infoPtr->hwndHeader, HDM_GETITEMRECT, lprc->top, (LPARAM)&rect)) + { + rect.top = 0; + rect.bottom = infoPtr->nItemHeight; + } + else + { + /* Native implementation is broken for this case and garbage is left for left and right fields, + we zero them to get predictable output */ + lprc->left = lprc->right = lprc->top = 0; + lprc->bottom = infoPtr->nItemHeight; + OffsetRect(lprc, origin.x, y); + TRACE("return rect %s\n", wine_dbgstr_rect(lprc)); + return TRUE; } - if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE; - LISTVIEW_GetOrigin(infoPtr, &Origin); - - if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; - - lvItem.mask = 0; - lvItem.iItem = nItem; - lvItem.iSubItem = nColumn; - - switch(lprc->left) + switch (lprc->left) { case LVIR_ICON: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL, NULL); - break; + { + /* it doesn't matter if main item actually has an icon, if imagelist is set icon width is returned */ + if (infoPtr->himlSmall) + rect.right = rect.left + infoPtr->iconSize.cx; + else + rect.right = rect.left; + rect.bottom = rect.top + infoPtr->iconSize.cy; + break; + } case LVIR_LABEL: case LVIR_BOUNDS: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL, NULL); break; default: @@ -7111,7 +7135,8 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR return FALSE; } - OffsetRect(lprc, Origin.x, Position.y); + OffsetRect(&rect, origin.x, y); + *lprc = rect; TRACE("return rect %s\n", wine_dbgstr_rect(lprc)); return TRUE; @@ -7680,7 +7705,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, LVITEMW item; HWND hwndSelf = infoPtr->hwndSelf; - TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); + TRACE("(item=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++; @@ -7730,7 +7755,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, else nItem = min(lpLVItem->iItem, infoPtr->nItemCount); - TRACE(" inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem); + TRACE("inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem); nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems ); if (nItem == -1) goto fail; infoPtr->nItemCount++; @@ -7762,6 +7787,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, item.state &= ~LVIS_STATEIMAGEMASK; item.state |= INDEXTOSTATEIMAGEMASK(1); } + if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo; /* make room for the position, if we are in the right mode */ @@ -7775,9 +7801,9 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, goto undo; } } - + /* send LVN_INSERTITEM notification */ - ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); + memset(&nmlv, 0, sizeof(NMLISTVIEW)); nmlv.iItem = nItem; nmlv.lParam = lpItem->lParam; notify_listview(infoPtr, LVN_INSERTITEM, &nmlv); @@ -7803,6 +7829,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, undo: LISTVIEW_ShiftIndices(infoPtr, nItem, -1); + LISTVIEW_ShiftFocus(infoPtr, infoPtr->nFocusedItem, nItem, -1); DPA_DeletePtr(infoPtr->hdpaItems, nItem); infoPtr->nItemCount--; fail: @@ -8283,10 +8310,10 @@ static BOOL LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn, INT cx) lvItem.mask = LVIF_TEXT; lvItem.iItem = 0; lvItem.iSubItem = nColumn; - lvItem.pszText = szDispText; lvItem.cchTextMax = DISP_TEXT_SIZE; for (; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++) { + lvItem.pszText = szDispText; if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); if (max_cx < nLabelWidth) max_cx = nLabelWidth; @@ -8570,36 +8597,33 @@ static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime) */ static DWORD LISTVIEW_SetIconSpacing(LISTVIEW_INFO *infoPtr, INT cx, INT cy) { + INT iconWidth = 0, iconHeight = 0; DWORD oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy); TRACE("requested=(%d,%d)\n", cx, cy); - - /* this is supported only for LVS_ICON style */ - if (infoPtr->uView != LV_VIEW_ICON) return oldspacing; - + /* set to defaults, if instructed to */ - if (cx == -1) cx = GetSystemMetrics(SM_CXICONSPACING); - if (cy == -1) cy = GetSystemMetrics(SM_CYICONSPACING); - - /* if 0 then compute width - * FIXME: computed cx and cy is not matching native behaviour */ - if (cx == 0) { - cx = GetSystemMetrics(SM_CXICONSPACING); - if (infoPtr->iconSize.cx + ICON_LR_PADDING > cx) - cx = infoPtr->iconSize.cx + ICON_LR_PADDING; + if (cx == -1 && cy == -1) + { + infoPtr->autoSpacing = TRUE; + if (infoPtr->himlNormal) + ImageList_GetIconSize(infoPtr->himlNormal, &iconWidth, &iconHeight); + cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON) + iconWidth; + cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON) + iconHeight; } + else + infoPtr->autoSpacing = FALSE; - /* if 0 then compute height */ - if (cy == 0) - cy = infoPtr->iconSize.cy + 2 * infoPtr->ntmHeight + - ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_PADDING; - + /* if 0 then keep width */ + if (cx != 0) + infoPtr->iconSpacing.cx = cx; - infoPtr->iconSpacing.cx = cx; - infoPtr->iconSpacing.cy = cy; + /* if 0 then keep height */ + if (cy != 0) + infoPtr->iconSpacing.cy = cy; TRACE("old=(%d,%d), new=(%d,%d), iconSize=(%d,%d), ntmH=%d\n", - LOWORD(oldspacing), HIWORD(oldspacing), cx, cy, + LOWORD(oldspacing), HIWORD(oldspacing), infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy, infoPtr->iconSize.cx, infoPtr->iconSize.cy, infoPtr->ntmHeight); @@ -8651,13 +8675,16 @@ static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *infoPtr, INT nType, HIMAG himlOld = infoPtr->himlNormal; infoPtr->himlNormal = himl; if (infoPtr->uView == LV_VIEW_ICON) set_icon_size(&infoPtr->iconSize, himl, FALSE); - LISTVIEW_SetIconSpacing(infoPtr, 0, 0); + if (infoPtr->autoSpacing) + LISTVIEW_SetIconSpacing(infoPtr, -1, -1); break; case LVSIL_SMALL: himlOld = infoPtr->himlSmall; infoPtr->himlSmall = himl; if (infoPtr->uView != LV_VIEW_ICON) set_icon_size(&infoPtr->iconSize, himl, TRUE); + if (infoPtr->hwndHeader) + SendMessageW(infoPtr->hwndHeader, HDM_SETIMAGELIST, 0, (LPARAM)himl); break; case LVSIL_STATE: @@ -8854,6 +8881,10 @@ static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *infoPtr, INT nItem, const LVITE UINT oldstate = 0; BOOL notify; + /* special case optimization for recurring attempt to deselect all */ + if (lvItem.state == 0 && lvItem.stateMask == LVIS_SELECTED && !LISTVIEW_GetSelectedCount(infoPtr)) + return TRUE; + /* select all isn't allowed in LVS_SINGLESEL */ if ((lvItem.state & lvItem.stateMask & LVIS_SELECTED) && (infoPtr->dwStyle & LVS_SINGLESEL)) return FALSE; @@ -9039,7 +9070,6 @@ static BOOL LISTVIEW_SetUnicodeFormat( LISTVIEW_INFO *infoPtr, BOOL unicode) */ static INT LISTVIEW_SetView(LISTVIEW_INFO *infoPtr, DWORD nView) { - SIZE oldIconSize = infoPtr->iconSize; HIMAGELIST himl; if (infoPtr->uView == nView) return 1; @@ -9065,14 +9095,6 @@ static INT LISTVIEW_SetView(LISTVIEW_INFO *infoPtr, DWORD nView) switch (nView) { case LV_VIEW_ICON: - if ((infoPtr->iconSize.cx != oldIconSize.cx) || (infoPtr->iconSize.cy != oldIconSize.cy)) - { - TRACE("icon old size=(%d,%d), new size=(%d,%d)\n", - oldIconSize.cx, oldIconSize.cy, infoPtr->iconSize.cx, infoPtr->iconSize.cy); - LISTVIEW_SetIconSpacing(infoPtr, 0, 0); - } - LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); - break; case LV_VIEW_SMALLICON: LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); break; @@ -9369,11 +9391,13 @@ static LRESULT LISTVIEW_NCCreate(HWND hwnd, const CREATESTRUCTW *lpcs) infoPtr->bRedraw = TRUE; infoPtr->bNoItemMetrics = TRUE; infoPtr->bDoChangeNotify = TRUE; - infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING); - infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING); + infoPtr->autoSpacing = TRUE; + infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING) - GetSystemMetrics(SM_CXICON); + infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON); infoPtr->nEditLabelItem = -1; infoPtr->nLButtonDownItem = -1; infoPtr->dwHoverTime = HOVER_DEFAULT; /* default system hover time */ + infoPtr->cWheelRemainder = 0; infoPtr->nMeasureItemHeight = 0; infoPtr->xTrackLine = -1; /* no track line */ infoPtr->itemEdit.fEnabled = FALSE; @@ -9774,14 +9798,10 @@ static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode, static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta) { - INT gcWheelDelta = 0; - INT pulScrollLines = 3; + UINT pulScrollLines = 3; TRACE("(wheelDelta=%d)\n", wheelDelta); - SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); - gcWheelDelta -= wheelDelta; - switch(infoPtr->uView) { case LV_VIEW_ICON: @@ -9790,21 +9810,31 @@ static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta) * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number * should be fixed in the future. */ - LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (gcWheelDelta < 0) ? + LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (wheelDelta > 0) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : LISTVIEW_SCROLL_ICON_LINE_SIZE); break; case LV_VIEW_DETAILS: - if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) + SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); + + /* if scrolling changes direction, ignore left overs */ + if ((wheelDelta < 0 && infoPtr->cWheelRemainder < 0) || + (wheelDelta > 0 && infoPtr->cWheelRemainder > 0)) + infoPtr->cWheelRemainder += wheelDelta; + else + infoPtr->cWheelRemainder = wheelDelta; + if (infoPtr->cWheelRemainder && pulScrollLines) { - int cLineScroll = min(LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines); - cLineScroll *= (gcWheelDelta / WHEEL_DELTA); - LISTVIEW_VScroll(infoPtr, SB_INTERNAL, cLineScroll); + int cLineScroll; + pulScrollLines = min((UINT)LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines); + cLineScroll = pulScrollLines * (float)infoPtr->cWheelRemainder / WHEEL_DELTA; + infoPtr->cWheelRemainder -= WHEEL_DELTA * cLineScroll / (int)pulScrollLines; + LISTVIEW_VScroll(infoPtr, SB_INTERNAL, -cLineScroll); } break; case LV_VIEW_LIST: - LISTVIEW_HScroll(infoPtr, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0); + LISTVIEW_HScroll(infoPtr, (wheelDelta > 0) ? SB_LINELEFT : SB_LINERIGHT, 0); break; } return 0; @@ -9931,7 +9961,10 @@ static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr) { TRACE("()\n"); - /* if we did not have the focus, there's nothing to do */ + /* drop any left over scroll amount */ + infoPtr->cWheelRemainder = 0; + + /* if we did not have the focus, there's nothing more to do */ if (!infoPtr->bFocus) return 0; /* send NM_KILLFOCUS notification */ @@ -10004,6 +10037,52 @@ static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, return 0; } +static LRESULT LISTVIEW_TrackMouse(const LISTVIEW_INFO *infoPtr, POINT pt) +{ + MSG msg; + RECT r; + + r.top = r.bottom = pt.y; + r.left = r.right = pt.x; + + InflateRect(&r, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG)); + + SetCapture(infoPtr->hwndSelf); + + while (1) + { + if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) + { + if (msg.message == WM_MOUSEMOVE) + { + pt.x = (short)LOWORD(msg.lParam); + pt.y = (short)HIWORD(msg.lParam); + if (PtInRect(&r, pt)) + continue; + else + { + ReleaseCapture(); + return 1; + } + } + else if (msg.message >= WM_LBUTTONDOWN && + msg.message <= WM_RBUTTONDBLCLK) + { + break; + } + + DispatchMessageW(&msg); + } + + if (GetCapture() != infoPtr->hwndSelf) + return 0; + } + + ReleaseCapture(); + return 0; +} + + /*** * DESCRIPTION: * Processes mouse down messages (left mouse button). @@ -10257,9 +10336,9 @@ static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr) * RETURN: * Zero */ -static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, const NMHDR *lpnmhdr) +static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, NMHDR *lpnmhdr) { - const NMHEADERW *lpnmh; + NMHEADERW *lpnmh; TRACE("(lpnmhdr=%p)\n", lpnmhdr); @@ -10267,7 +10346,7 @@ static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, const NMHDR *lpnmhdr) /* remember: HDN_LAST < HDN_FIRST */ if (lpnmhdr->code > HDN_FIRST || lpnmhdr->code < HDN_LAST) return 0; - lpnmh = (const NMHEADERW *)lpnmhdr; + lpnmh = (NMHEADERW *)lpnmhdr; if (lpnmh->iItem < 0 || lpnmh->iItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0; @@ -10292,26 +10371,25 @@ static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, const NMHDR *lpnmhdr) LISTVIEW_GetOrigin(infoPtr, &ptOrigin); infoPtr->xTrackLine = x + ptOrigin.x; LISTVIEW_DrawTrackLine(infoPtr); - break; + return notify_forward_header(infoPtr, lpnmh); } - + case HDN_ENDTRACKA: case HDN_ENDTRACKW: /* remove the track line (if any) */ LISTVIEW_DrawTrackLine(infoPtr); infoPtr->xTrackLine = -1; - break; + return notify_forward_header(infoPtr, lpnmh); case HDN_BEGINDRAG: - notify_forward_header(infoPtr, lpnmh); - return (infoPtr->dwLvExStyle & LVS_EX_HEADERDRAGDROP) == 0; + if ((infoPtr->dwLvExStyle & LVS_EX_HEADERDRAGDROP) == 0) return 1; + return notify_forward_header(infoPtr, lpnmh); case HDN_ENDDRAG: infoPtr->colRectsDirty = TRUE; LISTVIEW_InvalidateList(infoPtr); - notify_forward_header(infoPtr, lpnmh); - return FALSE; - + return notify_forward_header(infoPtr, lpnmh); + case HDN_ITEMCHANGEDW: case HDN_ITEMCHANGEDA: { @@ -10391,8 +10469,8 @@ static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, const NMHDR *lpnmhdr) LISTVIEW_InvalidateRect(infoPtr, &rcCol); } } - } - break; + break; + } case HDN_ITEMCLICKW: case HDN_ITEMCLICKA: @@ -10404,9 +10482,8 @@ static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, const NMHDR *lpnmhdr) nmlv.iItem = -1; nmlv.iSubItem = lpnmh->iItem; notify_listview(infoPtr, LVN_COLUMNCLICK, &nmlv); - notify_forward_header(infoPtr, lpnmh); + return notify_forward_header(infoPtr, lpnmh); } - break; case HDN_DIVIDERDBLCLICKW: case HDN_DIVIDERDBLCLICKA: @@ -10414,10 +10491,8 @@ static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, const NMHDR *lpnmhdr) we should use LVSCW_AUTOSIZE_USEHEADER, helper rework or split needed for that */ LISTVIEW_SetColumnWidth(infoPtr, lpnmh->iItem, LVSCW_AUTOSIZE); - notify_forward_header(infoPtr, lpnmh); - break; + return notify_forward_header(infoPtr, lpnmh); } - return 0; } @@ -10612,94 +10687,76 @@ static LRESULT LISTVIEW_RButtonDblClk(const LISTVIEW_INFO *infoPtr, WORD wKey, I /*** * DESCRIPTION: - * Processes mouse down messages (right mouse button). + * Processes WM_RBUTTONDOWN message and corresponding drag operation. * * PARAMETER(S): * [I] infoPtr : valid pointer to the listview structure * [I] wKey : key flag - * [I] x,y : mouse coordinate + * [I] x, y : mouse coordinate * * RETURN: * Zero */ static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) { - LVHITTESTINFO lvHitTestInfo; - INT nItem; + LVHITTESTINFO ht; + INT item; - TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y); + TRACE("(key=%hu, x=%d, y=%d)\n", wKey, x, y); /* send NM_RELEASEDCAPTURE notification */ if (!notify(infoPtr, NM_RELEASEDCAPTURE)) return 0; + /* determine the index of the selected item */ + ht.pt.x = x; + ht.pt.y = y; + item = LISTVIEW_HitTest(infoPtr, &ht, TRUE, TRUE); + /* make sure the listview control window has the focus */ if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); - /* set right button down flag */ - infoPtr->bRButtonDown = TRUE; - - /* determine the index of the selected item */ - lvHitTestInfo.pt.x = x; - lvHitTestInfo.pt.y = y; - nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); - - if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) + if ((item >= 0) && (item < infoPtr->nItemCount)) { - LISTVIEW_SetItemFocus(infoPtr, nItem); + LISTVIEW_SetItemFocus(infoPtr, item); if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) && - !LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) - LISTVIEW_SetSelection(infoPtr, nItem); + !LISTVIEW_GetItemState(infoPtr, item, LVIS_SELECTED)) + LISTVIEW_SetSelection(infoPtr, item); + } + else + LISTVIEW_DeselectAll(infoPtr); + + if (LISTVIEW_TrackMouse(infoPtr, ht.pt)) + { + if (ht.iItem != -1) + { + NMLISTVIEW nmlv; + + memset(&nmlv, 0, sizeof(nmlv)); + nmlv.iItem = ht.iItem; + nmlv.ptAction = ht.pt; + + notify_listview(infoPtr, LVN_BEGINRDRAG, &nmlv); + } } else { - LISTVIEW_DeselectAll(infoPtr); + SetFocus(infoPtr->hwndSelf); + + ht.pt.x = x; + ht.pt.y = y; + LISTVIEW_HitTest(infoPtr, &ht, TRUE, FALSE); + + if (notify_click(infoPtr, NM_RCLICK, &ht)) + { + /* Send a WM_CONTEXTMENU message in response to the WM_RBUTTONUP */ + SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU, + (WPARAM)infoPtr->hwndSelf, (LPARAM)GetMessagePos()); + } } return 0; } -/*** - * DESCRIPTION: - * Processes mouse up messages (right mouse button). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wKey : key flag - * [I] x,y : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - LVHITTESTINFO lvHitTestInfo; - POINT pt; - - TRACE("(key=%hu,X=%u,Y=%u)\n", wKey, x, y); - - if (!infoPtr->bRButtonDown) return 0; - - /* set button flag */ - infoPtr->bRButtonDown = FALSE; - - /* Send NM_RCLICK notification */ - lvHitTestInfo.pt.x = x; - lvHitTestInfo.pt.y = y; - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); - if (!notify_click(infoPtr, NM_RCLICK, &lvHitTestInfo)) return 0; - - /* Change to screen coordinate for WM_CONTEXTMENU */ - pt = lvHitTestInfo.pt; - 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 0; -} - - /*** * DESCRIPTION: * Sets the cursor. @@ -10782,6 +10839,7 @@ static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus) static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw) { HFONT oldFont = infoPtr->hFont; + INT oldHeight = infoPtr->nItemHeight; TRACE("(hfont=%p,redraw=%hu)\n", hFont, fRedraw); @@ -10790,12 +10848,16 @@ static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedra LISTVIEW_SaveTextMetrics(infoPtr); + infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr); + if (infoPtr->uView == LV_VIEW_DETAILS) { SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0)); LISTVIEW_UpdateSize(infoPtr); LISTVIEW_UpdateScroll(infoPtr); } + else if (infoPtr->nItemHeight != oldHeight) + LISTVIEW_UpdateScroll(infoPtr); if (fRedraw) LISTVIEW_InvalidateList(infoPtr); @@ -10973,7 +11035,6 @@ static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType, if (uNewView != uOldView) { - SIZE oldIconSize = infoPtr->iconSize; HIMAGELIST himl; SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); @@ -10984,17 +11045,8 @@ static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType, himl = (uNewView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); set_icon_size(&infoPtr->iconSize, himl, uNewView != LVS_ICON); - - if (uNewView == LVS_ICON) - { - if ((infoPtr->iconSize.cx != oldIconSize.cx) || (infoPtr->iconSize.cy != oldIconSize.cy)) - { - TRACE("icon old size=(%d,%d), new size=(%d,%d)\n", - oldIconSize.cx, oldIconSize.cy, infoPtr->iconSize.cx, infoPtr->iconSize.cy); - LISTVIEW_SetIconSpacing(infoPtr, 0, 0); - } - } - else if (uNewView == LVS_REPORT) + + if (uNewView == LVS_REPORT) { HDLAYOUT hl; WINDOWPOS wp; @@ -11425,7 +11477,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return LISTVIEW_SetHoverTime(infoPtr, (DWORD)lParam); case LVM_SETICONSPACING: - return LISTVIEW_SetIconSpacing(infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam)); + if(lParam == -1) + return LISTVIEW_SetIconSpacing(infoPtr, -1, -1); + return LISTVIEW_SetIconSpacing(infoPtr, LOWORD(lParam), HIWORD(lParam)); case LVM_SETIMAGELIST: return (LRESULT)LISTVIEW_SetImageList(infoPtr, (INT)wParam, (HIMAGELIST)lParam); @@ -11588,9 +11642,6 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_RBUTTONDOWN: return LISTVIEW_RButtonDown(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - case WM_RBUTTONUP: - return LISTVIEW_RButtonUp(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - case WM_SETCURSOR: return LISTVIEW_SetCursor(infoPtr, wParam, lParam); diff --git a/reactos/dll/win32/comctl32/monthcal.c b/reactos/dll/win32/comctl32/monthcal.c index a9b76d47627..3dba5401b3d 100644 --- a/reactos/dll/win32/comctl32/monthcal.c +++ b/reactos/dll/win32/comctl32/monthcal.c @@ -1076,7 +1076,8 @@ static void MONTHCAL_PaintFocusAndCircle(const MONTHCAL_INFO *infoPtr, HDC hdc, /* months before first calendar month and after last calendar month */ static void MONTHCAL_PaintLeadTrailMonths(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps) { - INT mask, length, index; + INT mask, index; + UINT length; SYSTEMTIME st_max, st; if (infoPtr->dwStyle & MCS_NOTRAILINGDATES) return; @@ -1116,7 +1117,8 @@ static void MONTHCAL_PaintLeadTrailMonths(const MONTHCAL_INFO *infoPtr, HDC hdc, static void MONTHCAL_PaintCalendar(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx) { const SYSTEMTIME *date = &infoPtr->calendars[calIdx].month; - INT i, j, length; + INT i, j; + UINT length; RECT r, fill_bk_rect; SYSTEMTIME st; WCHAR buf[80]; diff --git a/reactos/dll/win32/comctl32/propsheet.c b/reactos/dll/win32/comctl32/propsheet.c index a1c5673e58f..03b275f8033 100644 --- a/reactos/dll/win32/comctl32/propsheet.c +++ b/reactos/dll/win32/comctl32/propsheet.c @@ -168,7 +168,7 @@ static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, int index, int skipdir, HPROPSHEETPAGE hpage); -static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, const PropSheetInfo* psInfo); +static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, const PropSheetInfo* psInfo, int original_index); static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo); static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID); static BOOL PROPSHEET_RemovePage(HWND hwndDlg, int index, HPROPSHEETPAGE hpage); @@ -1998,9 +1998,8 @@ static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage); - /* hpage takes precedence over index */ - if (hpage != NULL) - index = PROPSHEET_GetPageIndex(hpage, psInfo); + + index = PROPSHEET_GetPageIndex(hpage, psInfo, index); if (index < 0 || index >= psInfo->nPages) { @@ -2331,13 +2330,8 @@ static BOOL PROPSHEET_RemovePage(HWND hwndDlg, if (!psInfo) { return FALSE; } - /* - * hpage takes precedence over index. - */ - if (hpage != 0) - { - index = PROPSHEET_GetPageIndex(hpage, psInfo); - } + + index = PROPSHEET_GetPageIndex(hpage, psInfo, index); /* Make sure that index is within range */ if (index < 0 || index >= psInfo->nPages) @@ -2575,16 +2569,11 @@ static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex) */ static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage) { - int index; PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); TRACE("(%p, %p)\n", hwndDlg, hPage); - for (index = 0; index < psInfo->nPages; index++) - if (psInfo->proppage[index].hpage == hPage) - return index; - WARN("%p not found\n", hPage); - return -1; + return PROPSHEET_GetPageIndex(hPage, psInfo, -1); } /****************************************************************************** @@ -2660,26 +2649,20 @@ static BOOL PROPSHEET_RecalcPageSizes(HWND hwndDlg) * PROPSHEET_GetPageIndex * * Given a HPROPSHEETPAGE, returns the index of the corresponding page from - * the array of PropPageInfo. + * the array of PropPageInfo. If page is not found original index is used + * (page takes precedence over index). */ -static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, const PropSheetInfo* psInfo) +static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE page, const PropSheetInfo* psInfo, int original_index) { - BOOL found = FALSE; - int index = 0; + int index; - TRACE("hpage %p\n", hpage); - while ((index < psInfo->nPages) && (found == FALSE)) - { - if (psInfo->proppage[index].hpage == hpage) - found = TRUE; - else - index++; - } + TRACE("page %p index %d\n", page, original_index); - if (found == FALSE) - index = -1; + for (index = 0; index < psInfo->nPages; index++) + if (psInfo->proppage[index].hpage == page) + return index; - return index; + return original_index; } /****************************************************************************** diff --git a/reactos/dll/win32/comctl32/rebar.c b/reactos/dll/win32/comctl32/rebar.c index 2dc99cd784f..592e382cd15 100644 --- a/reactos/dll/win32/comctl32/rebar.c +++ b/reactos/dll/win32/comctl32/rebar.c @@ -1123,7 +1123,7 @@ REBAR_MoveChildWindows (const REBAR_INFO *infoPtr, UINT start, UINT endplus) * or infoPtr->uNumBands if none */ static int next_visible(const REBAR_INFO *infoPtr, int i) { - int n; + unsigned int n; for (n = i + 1; n < infoPtr->uNumBands; n++) if (!HIDDENBAND(REBAR_GetBand(infoPtr, n))) break; diff --git a/reactos/dll/win32/comctl32/status.c b/reactos/dll/win32/comctl32/status.c index d16e16372a0..45df80305ea 100644 --- a/reactos/dll/win32/comctl32/status.c +++ b/reactos/dll/win32/comctl32/status.c @@ -285,7 +285,6 @@ STATUSBAR_RefreshPart (const STATUS_INFO *infoPtr, HDC hdc, const STATUSWINDOWPA static LRESULT STATUSBAR_Refresh (STATUS_INFO *infoPtr, HDC hdc) { - int i; RECT rect; HBRUSH hbrBk; HFONT hOldFont; @@ -319,6 +318,8 @@ STATUSBAR_Refresh (STATUS_INFO *infoPtr, HDC hdc) if (infoPtr->simple) { STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->part0, 0); } else { + unsigned int i; + for (i = 0; i < infoPtr->numParts; i++) { STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->parts[i], i); } @@ -336,7 +337,8 @@ STATUSBAR_Refresh (STATUS_INFO *infoPtr, HDC hdc) static int STATUSBAR_InternalHitTest(const STATUS_INFO *infoPtr, const POINT *pt) { - int i; + unsigned int i; + if (infoPtr->simple) return 255; @@ -352,7 +354,7 @@ STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr) { STATUSWINDOWPART *part; RECT rect, *r; - int i; + UINT i; /* get our window size */ GetClientRect (infoPtr->Self, &rect); @@ -883,7 +885,7 @@ STATUSBAR_Simple (STATUS_INFO *infoPtr, BOOL simple) static LRESULT STATUSBAR_WMDestroy (STATUS_INFO *infoPtr) { - int i; + unsigned int i; TRACE("\n"); for (i = 0; i < infoPtr->numParts; i++) { diff --git a/reactos/dll/win32/comctl32/toolbar.c b/reactos/dll/win32/comctl32/toolbar.c index 9923cdb76ef..702694fbafd 100644 --- a/reactos/dll/win32/comctl32/toolbar.c +++ b/reactos/dll/win32/comctl32/toolbar.c @@ -5212,9 +5212,9 @@ TOOLBAR_Destroy (TOOLBAR_INFO *infoPtr) if (infoPtr->himlInt) ImageList_Destroy (infoPtr->himlInt); - TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef); - TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis); - TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot); + TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef); + TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis); + TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot); /* delete default font */ DeleteObject (infoPtr->hDefaultFont); diff --git a/reactos/dll/win32/comctl32/tooltips.c b/reactos/dll/win32/comctl32/tooltips.c index 34da653c05f..a51fa35483a 100644 --- a/reactos/dll/win32/comctl32/tooltips.c +++ b/reactos/dll/win32/comctl32/tooltips.c @@ -991,9 +991,17 @@ TOOLTIPS_CheckTool (const TOOLTIPS_INFO *infoPtr, BOOL bShowTest) if (nTool == -1) return -1; - if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) { - if (!TOOLTIPS_IsWindowActive (GetWindow (infoPtr->hwndSelf, GW_OWNER))) - return -1; + if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) + { + TTTOOL_INFO *ti = &infoPtr->tools[nTool]; + HWND hwnd = (ti->uFlags & TTF_IDISHWND) ? (HWND)ti->uId : ti->hwnd; + + if (!TOOLTIPS_IsWindowActive(hwnd)) + { + TRACE("not active: hwnd %p, parent %p, active %p\n", + hwnd, GetParent(hwnd), GetActiveWindow()); + return -1; + } } TRACE("tool %d\n", nTool); diff --git a/reactos/dll/win32/comctl32/treeview.c b/reactos/dll/win32/comctl32/treeview.c index 8dd0dcabee4..d8a36ce2290 100644 --- a/reactos/dll/win32/comctl32/treeview.c +++ b/reactos/dll/win32/comctl32/treeview.c @@ -102,6 +102,7 @@ typedef struct tagTREEVIEW_INFO BOOL insertBeforeorAfter; /* flag used by TVM_SETINSERTMARK */ HIMAGELIST dragList; /* Bitmap of dragged item */ LONG scrollX; + INT wheelRemainder; COLORREF clrBk; COLORREF clrText; COLORREF clrLine; @@ -110,6 +111,7 @@ typedef struct tagTREEVIEW_INFO HFONT hDefaultFont; HFONT hBoldFont; HFONT hUnderlineFont; + HFONT hBoldUnderlineFont; HCURSOR hcurHand; HWND hwndToolTip; @@ -303,11 +305,22 @@ TREEVIEW_CreateUnderlineFont(HFONT hOrigFont) return CreateFontIndirectW(&font); } +static HFONT +TREEVIEW_CreateBoldUnderlineFont(HFONT hfont) +{ + LOGFONTW font; + + GetObjectW(hfont, sizeof(font), &font); + font.lfWeight = FW_BOLD; + font.lfUnderline = TRUE; + return CreateFontIndirectW(&font); +} + static inline HFONT TREEVIEW_FontForItem(const TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *item) { if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (item == infoPtr->hotItem)) - return infoPtr->hUnderlineFont; + return item->state & TVIS_BOLD ? infoPtr->hBoldUnderlineFont : infoPtr->hUnderlineFont; if (item->state & TVIS_BOLD) return infoPtr->hBoldFont; return infoPtr->hFont; @@ -1562,7 +1575,7 @@ TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, HTREEITEM item) newFirstVisible = item->prevSibling; else if (item->parent != infoPtr->root) newFirstVisible = item->parent; - TREEVIEW_SetFirstVisible(infoPtr, NULL, TRUE); + TREEVIEW_SetFirstVisible(infoPtr, NULL, TRUE); } else newFirstVisible = infoPtr->firstVisible; @@ -1903,8 +1916,10 @@ TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, HFONT hFont, BOOL bRedraw) DeleteObject(infoPtr->hBoldFont); DeleteObject(infoPtr->hUnderlineFont); + DeleteObject(infoPtr->hBoldUnderlineFont); infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont); + infoPtr->hBoldUnderlineFont = TREEVIEW_CreateBoldUnderlineFont(infoPtr->hFont); if (!infoPtr->bHeightSet) infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); @@ -3155,10 +3170,10 @@ TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, HTREEITEM parent, { int visOrder = infoPtr->firstVisible->visibleOrder; - if (parent == infoPtr->root) - TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); - else - TREEVIEW_RecalculateVisibleOrder(infoPtr, parent); + if (parent == infoPtr->root) + TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); + else + TREEVIEW_RecalculateVisibleOrder(infoPtr, parent); if (TREEVIEW_IsChildOf(parent, infoPtr->firstVisible)) { @@ -4916,7 +4931,7 @@ scroll: static LRESULT TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) { - short gcWheelDelta; + short wheelDelta; UINT pulScrollLines = 3; if (wParam & (MK_SHIFT | MK_CONTROL)) @@ -4927,13 +4942,25 @@ TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &pulScrollLines, 0); - gcWheelDelta = -(short)HIWORD(wParam); - pulScrollLines *= (gcWheelDelta / WHEEL_DELTA); + wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam); + /* if scrolling changes direction, ignore left overs */ + if ((wheelDelta < 0 && infoPtr->wheelRemainder < 0) || + (wheelDelta > 0 && infoPtr->wheelRemainder > 0)) + infoPtr->wheelRemainder += wheelDelta; + else + infoPtr->wheelRemainder = wheelDelta; - if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) + if (infoPtr->wheelRemainder && pulScrollLines) { - int newDy = infoPtr->firstVisible->visibleOrder + pulScrollLines; - int maxDy = infoPtr->maxVisibleOrder; + int newDy; + int maxDy; + int lineScroll; + + lineScroll = pulScrollLines * (float)infoPtr->wheelRemainder / WHEEL_DELTA; + infoPtr->wheelRemainder -= WHEEL_DELTA * lineScroll / (int)pulScrollLines; + + newDy = infoPtr->firstVisible->visibleOrder - lineScroll; + maxDy = infoPtr->maxVisibleOrder; if (newDy > maxDy) newDy = maxDy; @@ -5038,6 +5065,7 @@ TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs) /* dragList */ infoPtr->scrollX = 0; + infoPtr->wheelRemainder = 0; infoPtr->clrBk = CLR_NONE; /* use system color */ infoPtr->clrText = CLR_NONE; /* use system color */ @@ -5064,6 +5092,7 @@ TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs) infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW(&lf); infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont); + infoPtr->hBoldUnderlineFont = TREEVIEW_CreateBoldUnderlineFont(infoPtr->hFont); infoPtr->hcurHand = LoadCursorW(NULL, (LPWSTR)IDC_HAND); infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); @@ -5123,6 +5152,7 @@ TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr) DeleteObject(infoPtr->hDefaultFont); DeleteObject(infoPtr->hBoldFont); DeleteObject(infoPtr->hUnderlineFont); + DeleteObject(infoPtr->hBoldUnderlineFont); Free(infoPtr); return 0; diff --git a/reactos/dll/win32/comctl32/updown.c b/reactos/dll/win32/comctl32/updown.c index d3be2898c54..32162267a9f 100644 --- a/reactos/dll/win32/comctl32/updown.c +++ b/reactos/dll/win32/comctl32/updown.c @@ -1026,10 +1026,10 @@ static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, L if (TRACE_ON(updown)) { - INT i; + UINT i; for (i = 0; i < wParam; i++) - TRACE("%d: nSec %u nInc %u\n", i, + TRACE("%u: nSec %u nInc %u\n", i, infoPtr->AccelVect[i].nSec, infoPtr->AccelVect[i].nInc); } diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index e2e8e019ac0..f1b19369251 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -48,7 +48,7 @@ reactos/dll/win32/browseui # Out of sync reactos/dll/win32/cabinet # Synced to Wine-1.5.19 reactos/dll/win32/clusapi # Synced to Wine-1.5.19 reactos/dll/win32/comcat # Synced to Wine-1.5.4 -reactos/dll/win32/comctl32 # Synced to Wine 1.5.19 +reactos/dll/win32/comctl32 # Synced to Wine 1.5.26 reactos/dll/win32/comdlg32 # Synced to Wine 1.3.37 reactos/dll/win32/compstui # Synced to Wine-1.5.19 reactos/dll/win32/credui # Synced to Wine-1.5.4