ChangeLog Complete rewrite of the rcView implementation Lots of bugs fixed in rcView computation Assorted cleanups, and simplifications. --- dlls/comctl32/listview.c.V16 Mon Oct 21 12:10:30 2002 +++ dlls/comctl32/listview.c Mon Oct 21 14:25:37 2002 @@ -211,7 +211,6 @@ * LISTVIEW_UpdateSize. This rectangle offset * by the LISTVIEW_GetOrigin value is in * client coordinates */ - RECT rcView; /* This rectangle contains all items */ SIZE iconSize; SIZE iconSpacing; SIZE iconStateSize; @@ -319,17 +318,13 @@ TRACE("hwndSelf=%08x, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n", \ iP->hwndSelf, iP->clrBk, iP->clrText, iP->clrTextBk, \ iP->nItemHeight, iP->nItemWidth, infoPtr->dwStyle); \ - TRACE("hwndSelf=%08x, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx, Focus=%s\n", \ + TRACE("hwndSelf=%08x, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx, Focus=%d\n", \ iP->hwndSelf, iP->himlNormal, iP->himlSmall, iP->himlState, \ - iP->nFocusedItem, iP->nHotItem, iP->dwLvExStyle, \ - (iP->bFocus) ? "true" : "false"); \ + iP->nFocusedItem, iP->nHotItem, iP->dwLvExStyle, iP->bFocus ); \ TRACE("hwndSelf=%08x, ntmH=%d, icSz.cx=%ld, icSz.cy=%ld, icSp.cx=%ld, icSp.cy=%ld, notifyFmt=%d\n", \ iP->hwndSelf, iP->ntmHeight, iP->iconSize.cx, iP->iconSize.cy, \ iP->iconSpacing.cx, iP->iconSpacing.cy, iP->notifyFormat); \ - TRACE("hwndSelf=%08x, rcList=(%d,%d)-(%d,%d), rcView=(%d,%d)-(%d,%d)\n", \ - iP->hwndSelf, \ - iP->rcList.left, iP->rcList.top, iP->rcList.right, iP->rcList.bottom, \ - iP->rcView.left, iP->rcView.top, iP->rcView.right, iP->rcView.bottom); \ + TRACE("hwndSelf=%08x, rcList=%s\n", iP->hwndSelf, debugrect(&iP->rcList)); \ } while(0) @@ -338,7 +333,6 @@ */ static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL); static void LISTVIEW_GetItemBox(LISTVIEW_INFO *, INT, LPRECT); -static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *, INT); static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *, INT, LPPOINT); static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT); static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *, INT, LPRECT); @@ -351,7 +345,6 @@ static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *); static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT); static BOOL LISTVIEW_UpdateSize(LISTVIEW_INFO *); -static void LISTVIEW_UnsupportedStyles(LONG); static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *, INT, BOOL); static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM); static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *, PFNLVCOMPARE, LPARAM); @@ -1581,33 +1574,6 @@ /*** - * DESCRIPTION: - * Prints a message for unsupported window styles. - * A kind of TODO list for window styles. - * - * PARAMETER(S): - * [I] lStyle : window style - * - * RETURN: - * None - */ -static void LISTVIEW_UnsupportedStyles(LONG lStyle) -{ - if ((LVS_TYPESTYLEMASK & lStyle) == LVS_NOSCROLL) - FIXME(" LVS_NOSCROLL\n"); - - if (lStyle & LVS_NOLABELWRAP) - FIXME(" LVS_NOLABELWRAP\n"); - - if (lStyle & LVS_SORTASCENDING) - FIXME(" LVS_SORTASCENDING\n"); - - if (lStyle & LVS_SORTDESCENDING) - FIXME(" LVS_SORTDESCENDING\n"); -} - - -/*** * DESCRIPTION: [INTERNAL] * Computes an item's (left,top) corner, relative to rcView. * That is, the position has NOT been made relative to the Origin. @@ -1949,7 +1915,6 @@ UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; POINT ptItem; - RECT rcView; INT i, off_x=0, off_y=0; if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) @@ -1963,7 +1928,6 @@ } ptItem.x = off_x; ptItem.y = off_y; - ZeroMemory(&rcView, sizeof(RECT)); TRACE("Icon off.x=%d, off.y=%d, left=%d, right=%d\n", off_x, off_y, infoPtr->rcList.left, infoPtr->rcList.right); @@ -1980,11 +1944,7 @@ LISTVIEW_SetItemPosition(infoPtr, i, ptItem); ptItem.x += infoPtr->nItemWidth; - rcView.right = max(rcView.right, ptItem.x); } - - rcView.right -= off_x; - rcView.bottom = (ptItem.y-off_y) + infoPtr->nItemHeight; } else { @@ -1993,12 +1953,7 @@ LISTVIEW_SetItemPosition(infoPtr, i, ptItem); ptItem.y += infoPtr->nItemHeight; } - - rcView.right = infoPtr->nItemWidth; - rcView.bottom = ptItem.y-off_y; } - - infoPtr->rcView = rcView; } } @@ -2017,7 +1972,6 @@ UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; POINT ptItem; - RECT rcView; INT i, off_x=0, off_y=0; if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) @@ -2031,7 +1985,6 @@ } ptItem.x = off_x; ptItem.y = off_y; - ZeroMemory(&rcView, sizeof(RECT)); TRACE("Icon off.x=%d, off.y=%d\n", off_x, off_y); if (nListHeight > infoPtr->nItemHeight) @@ -2046,10 +1999,7 @@ LISTVIEW_SetItemPosition(infoPtr, i, ptItem); ptItem.y += infoPtr->nItemHeight; - rcView.bottom = max(rcView.bottom, ptItem.y); } - - rcView.right = ptItem.x + infoPtr->nItemWidth; } else { @@ -2058,18 +2008,64 @@ LISTVIEW_SetItemPosition(infoPtr, i, ptItem); ptItem.x += infoPtr->nItemWidth; } - - rcView.bottom = infoPtr->nItemHeight; - rcView.right = ptItem.x; } - - infoPtr->rcView = rcView; } } /*** * DESCRIPTION: + * Retrieves the bounding rectangle of all the items, not offset by Origin. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [O] lprcView : bounding rectangle + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static void LISTVIEW_GetAreaRect(LISTVIEW_INFO *infoPtr, LPRECT lprcView) +{ + INT i, x, y; + + SetRectEmpty(lprcView); + + switch (infoPtr->dwStyle & LVS_TYPEMASK) + { + case LVS_ICON: + case LVS_SMALLICON: + for (i = 0; i < infoPtr->nItemCount; i++) + { + x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, i); + y = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, i); + lprcView->right = max(lprcView->right, x); + lprcView->bottom = max(lprcView->bottom, y); + } + if (infoPtr->nItemCount > 0) + { + lprcView->right += infoPtr->nItemWidth; + lprcView->bottom += infoPtr->nItemHeight; + } + break; + + case LVS_LIST: + y = LISTVIEW_GetCountPerColumn(infoPtr); + x = infoPtr->nItemCount / y; + if (infoPtr->nItemCount % y) x++; + lprcView->right = x * infoPtr->nItemWidth; + lprcView->bottom = y * infoPtr->nItemHeight; + break; + + case LVS_REPORT: + lprcView->right = infoPtr->nItemWidth; + lprcView->bottom = infoPtr->nItemCount * infoPtr->nItemHeight; + break; + } +} + +/*** + * DESCRIPTION: * Retrieves the bounding rectangle of all the items. * * PARAMETER(S): @@ -2087,10 +2083,9 @@ TRACE("(lprcView=%p)\n", lprcView); if (!lprcView) return FALSE; - + LISTVIEW_GetOrigin(infoPtr, &ptOrigin); - - *lprcView = infoPtr->rcView; + LISTVIEW_GetAreaRect(infoPtr, lprcView); OffsetRect(lprcView, ptOrigin.x, ptOrigin.y); TRACE("lprcView=%s\n", debugrect(lprcView)); @@ -2736,26 +2731,24 @@ */ static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) { - INT nFirst = min(infoPtr->nSelectionMark, nItem); - INT nLast = max(infoPtr->nSelectionMark, nItem); - INT i; - LVITEMW item; - - if (nFirst == -1) - nFirst = nItem; - - item.state = LVIS_SELECTED; - item.stateMask = LVIS_SELECTED; - - /* FIXME: this is not correct LVS_OWNERDATA - * See docu for LVN_ITEMCHANGED. Is there something similar for - * RemoveGroupSelection (is there such a thing?)? - */ - for (i = nFirst; i <= nLast; i++) - LISTVIEW_SetItemState(infoPtr,i,&item); + INT nFirst = min(infoPtr->nSelectionMark, nItem); + INT nLast = max(infoPtr->nSelectionMark, nItem); + INT i; + LVITEMW item; + + if (nFirst == -1) nFirst = nItem; + + item.state = LVIS_SELECTED; + item.stateMask = LVIS_SELECTED; - LISTVIEW_SetItemFocus(infoPtr, nItem); - infoPtr->nSelectionMark = nItem; + /* FIXME: this is not correct LVS_OWNERDATA + * setting the item states individually will generate + * a LVN_ITEMCHANGED notification for each one. Instead, + * we have to send a LVN_ODSTATECHANGED notification. + * See MSDN documentation for LVN_ITEMCHANGED. + */ + for (i = nFirst; i <= nLast; i++) + LISTVIEW_SetItemState(infoPtr,i,&item); } @@ -4378,6 +4371,7 @@ (uView == LVS_ICON || uView ==LVS_SMALLICON)) { POINT Origin; + RECT rcArea; FIXME("LVFI_NEARESTXY is slow.\n"); LISTVIEW_GetOrigin(infoPtr, &Origin); @@ -4390,9 +4384,13 @@ case VK_RIGHT: Destination.x += infoPtr->nItemWidth; break; case VK_LEFT: Destination.x -= infoPtr->nItemWidth; break; case VK_HOME: Destination.x = Destination.y = 0; break; - case VK_END: Destination.x = infoPtr->rcView.right; Destination.y = infoPtr->rcView.bottom; break; case VK_NEXT: Destination.y += infoPtr->rcList.bottom - infoPtr->rcList.top; break; case VK_PRIOR: Destination.y -= infoPtr->rcList.bottom - infoPtr->rcList.top; break; + case VK_END: + LISTVIEW_GetAreaRect(infoPtr, &rcArea); + Destination.x = rcArea.right; + Destination.y = rcArea.bottom; + break; default: ERR("Unknown vkDirection=%d\n", lpFindInfo->vkDirection); } bNearest = TRUE; @@ -4474,15 +4472,15 @@ static INT LISTVIEW_FindItemA(LISTVIEW_INFO *infoPtr, INT nStart, LPLVFINDINFOA lpFindInfo) { - BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL); - LVFINDINFOW fiw; - INT res; - - memcpy(&fiw, lpFindInfo, sizeof(fiw)); - if (hasText) fiw.psz = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE); - res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw); - if (hasText) textfreeT((LPWSTR)fiw.psz, FALSE); - return res; + BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL); + LVFINDINFOW fiw; + INT res; + + memcpy(&fiw, lpFindInfo, sizeof(fiw)); + if (hasText) fiw.psz = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE); + res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw); + if (hasText) textfreeT((LPWSTR)fiw.psz, FALSE); + return res; } /*** @@ -4624,30 +4622,19 @@ */ static INT LISTVIEW_GetCountPerPage(LISTVIEW_INFO *infoPtr) { - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nItemCount = 0; - - if (uView == LVS_LIST) - { - if (infoPtr->rcList.right > infoPtr->nItemWidth) + switch (infoPtr->dwStyle & LVS_TYPEMASK) { - nItemCount = LISTVIEW_GetCountPerRow(infoPtr) * - LISTVIEW_GetCountPerColumn(infoPtr); + case LVS_ICON: + case LVS_SMALLICON: + return infoPtr->nItemCount; + case LVS_REPORT: + return LISTVIEW_GetCountPerColumn(infoPtr); + case LVS_LIST: + return LISTVIEW_GetCountPerRow(infoPtr) * LISTVIEW_GetCountPerColumn(infoPtr); } - } - else if (uView == LVS_REPORT) - { - nItemCount = LISTVIEW_GetCountPerColumn(infoPtr); - } - else - { - nItemCount = infoPtr->nItemCount; - } - - return nItemCount; + assert(FALSE); } - /*** * DESCRIPTION: * Retrieves an image list handle. @@ -6945,9 +6932,6 @@ infoPtr->iconStateSize.cx = GetSystemMetrics(SM_CXSMICON); infoPtr->iconStateSize.cy = GetSystemMetrics(SM_CYSMICON); - /* display unsupported listview window styles */ - LISTVIEW_UnsupportedStyles(lpcs->style); - /* allocate memory for the data structure */ infoPtr->hdpaItems = DPA_Create(10); infoPtr->hdpaPosX = DPA_Create(10); @@ -7465,7 +7449,11 @@ if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT)) { if (bGroupSelect) + { LISTVIEW_AddGroupSelection(infoPtr, nItem); + LISTVIEW_SetItemFocus(infoPtr, nItem); + infoPtr->nSelectionMark = nItem; + } else { LVITEMW item; @@ -8135,9 +8123,6 @@ /* invalidate client area + erase background */ LISTVIEW_InvalidateList(infoPtr); - /* print the list of unsupported window styles */ - LISTVIEW_UnsupportedStyles(lpss->styleNew); - return 0; }