ChangeLog Fix large item focus handling for virtual listviews. Since at most _one_ item can have the focus at any time, we can maintain one such rectangle per list, rather than per item. This is both more efficient, and works for LVS_OWNERDATA listviews as well. --- dlls/comctl32/listview.c.K2 Thu Oct 3 23:51:46 2002 +++ dlls/comctl32/listview.c Fri Oct 4 00:22:58 2002 @@ -102,7 +102,6 @@ INT iIndent; POINT ptPosition; BOOL valid; - RECT rcLastDraw; } LISTVIEW_ITEM; typedef struct tagRANGE @@ -151,6 +150,7 @@ BOOL bFocus; INT nFocusedItem; RECT rcFocus; + RECT rcLargeFocus; /* non-empty when a large item in ICON mode has focus */ DWORD dwStyle; /* the cached window GWL_STYLE */ DWORD dwLvExStyle; /* extended listview style */ HDPA hdpaItems; @@ -2454,80 +2454,6 @@ } - /*** - * DESCRIPTION: [INTERNAL] - * Sets rectangle that the item was last drawn at. - * - * PARAMETER(S): - * [I] HWND : window handle - * [I] INT : item index - * [I] LPRECT : coordinate information - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetItemDrawRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lpRect) -{ - BOOL bResult = FALSE; - HDPA hdpaSubItems; - LISTVIEW_ITEM *lpItem; - - TRACE("(hwnd=%x,nItem=%d,rect=(%d,%d)-(%d,%d))\n", - infoPtr->hwndSelf, nItem, - lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); - - if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lpRect != NULL)) - { - if ((hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem))) - { - if ((lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0))) - { - bResult = TRUE; - lpItem->rcLastDraw = *lpRect; - } - } - } - return bResult; -} - - /*** - * DESCRIPTION: [INTERNAL] - * Gets rectangle that the item was last drawn at. - * - * PARAMETER(S): - * [I] HWND : window handle - * [I] INT : item index - * [O] LPRECT : coordinate information - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_GetItemDrawRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lpRect) -{ - BOOL bResult = FALSE; - HDPA hdpaSubItems; - LISTVIEW_ITEM *lpItem; - - if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lpRect != NULL)) - { - if ((hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem))) - { - if ((lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0))) - { - bResult = TRUE; - if (lpRect) *lpRect = lpItem->rcLastDraw; - TRACE("(hwnd=%x,nItem=%d,rect=(%d,%d)-(%d,%d))\n", - infoPtr->hwndSelf, nItem, - lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); - } - } - } - return bResult; -} - - /*** * Tests wheather the item is assignable to a list with style lStyle */ @@ -2827,30 +2753,18 @@ /* redraw item, if necessary */ if (bResult && !infoPtr->bIsDrawing) { - RECT rcOldItem={0,0,0,0}; - if (oldFocus != infoPtr->nFocusedItem && infoPtr->bFocus) - LISTVIEW_ToggleFocusRect(infoPtr); - - /* Note that ->rcLastDraw is normally all zero, so - * no second InvalidateRect is issued. - * - * However, when a large icon style is drawn (LVS_ICON), - * the rectangle drawn is saved in rcLastDraw. That way - * the InvalidateRect will invalidate the entire area drawn - * - * FIXME: this is not right. We have already a ton of rects, - * we have two functions to get to them (GetItemRect, - * and GetItemMeasurements), and we introduce yet - * another rectangle with setter/getter functions!!! - * This is too much. Besides, this does not work - * correctly for owner drawn control... - */ - if ((oldFocus >= 0) && (oldFocus < GETITEMCOUNT(infoPtr))) { - LISTVIEW_GetItemDrawRect(infoPtr, oldFocus, &rcOldItem); - if(!IsRectEmpty(&rcOldItem)) - LISTVIEW_InvalidateRect(infoPtr, &rcOldItem); + LISTVIEW_ToggleFocusRect(infoPtr); + /* Note that ->rcLargeFocus is normally all zero, so + * no second InvalidateRect is issued. + * + * However, when a large icon style is drawn (LVS_ICON), + * the rectangle drawn is saved in rcLastDraw. That way + * the InvalidateRect will invalidate the entire area drawn + */ + if (!IsRectEmpty(&infoPtr->rcLargeFocus)) + LISTVIEW_InvalidateRect(infoPtr, &infoPtr->rcLargeFocus); } LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem); } @@ -3266,6 +3180,7 @@ * that the background is complete */ rcFocus = rcLabel; /* save for focus */ + SetRectEmpty(&infoPtr->rcLargeFocus); if ((uFormat & DT_NOCLIP) || (lvItem.state & LVIS_SELECTED)) { /* FIXME: why do we need this??? */ @@ -3276,7 +3191,7 @@ DeleteObject(hBrush); /* Save size of item drawing for next InvalidateRect */ - LISTVIEW_SetItemDrawRect(infoPtr, nItem, &rcFullText); + infoPtr->rcLargeFocus = rcFullText; TRACE("focused/selected, rcFocus=%s\n", debugrect(&rcFocus)); } /* else ? What if we are losing the focus? will we not get a complete