Fixes important bug for virtual listbox. And other goodies. ChangeLog Fixes bug which rendered virtual listboxes always empty Smarter focus rectangle drawing Fix focus handling when we add/delete a column Fix silly bug in GetSubItemRect Elimiante flicker in Report mode. --- dlls/comctl32/listview.c.L3 Sun Oct 6 19:03:39 2002 +++ dlls/comctl32/listview.c Mon Oct 7 00:12:41 2002 @@ -1139,17 +1139,66 @@ */ static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, INT nItem, BOOL fShow) { + RECT rcItem; + TRACE("fShow=%d, nItem=%d\n", fShow, nItem); - /* Here we are inneficient. We could, in theory, simply DrawFocusRect - * to erase/show the focus, without all this heavy duty redraw. However, - * note that there are cases where we can not do that: when the list is - * in ICON mode, and the item is large, we must to invalidate it. - * Moreover, in the vast majority of cases, the selection status of - * the item changes anyway, and so the item is invalidated already, - * so not too much harm is done. If we do notice any flicker, we should - * refine this method. */ - LISTVIEW_InvalidateItem(infoPtr, nItem); + if (nItem < 0 || nItem >= infoPtr->nItemCount) return; + + rcItem.left = LVIR_BOUNDS; + rcItem.top = 0; + if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT && + !(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && + !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED)) + { + /* this little optimization eliminates some nasty flicker */ + if (!LISTVIEW_GetSubItemRect(infoPtr, nItem, &rcItem)) return; + } + else + { + if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return; + } + + if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED) + { + DRAWITEMSTRUCT dis; + LVITEMW item; + HDC hdc; + + item.iItem = nItem; + item.iSubItem = 0; + item.mask = LVIF_PARAM; + if (!LISTVIEW_GetItemW(infoPtr, &item)) goto invalidate; + + if (!(hdc = GetDC(infoPtr->hwndSelf))) goto invalidate; + ZeroMemory(&dis, sizeof(dis)); + dis.CtlType = ODT_LISTVIEW; + dis.CtlID = GetWindowLongW(infoPtr->hwndSelf, GWL_ID); + dis.itemID = nItem; + dis.itemAction = ODA_FOCUS; + if (fShow) dis.itemState |= ODS_FOCUS; + dis.hwndItem = infoPtr->hwndSelf; + dis.hDC = hdc; + dis.rcItem = rcItem; + dis.itemData = item.lParam; + + SendMessageW(GetParent(infoPtr->hwndSelf), WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); + ReleaseDC(infoPtr->hwndSelf, hdc); + return; + } + else + { + /* Here we are inneficient. We could, in theory, simply DrawFocusRect + * to erase/show the focus, without all this heavy duty redraw. + * Note that there are cases where we can not do that: when the list + * is in ICON mode, and the item is large, we must to invalidate it. + * Moreover, in the vast majority of cases, the selection status of + * the item changes anyway, and so the item is invalidated already, + * so not too much harm is done. If we do notice any flicker, we should + * refine this method. */ +invalidate: + LISTVIEW_InvalidateRect(infoPtr, &rcItem); + } } /*** @@ -2729,8 +2778,8 @@ { RECT rect; - rect.top = lpLVItem->iSubItem; rect.left = LVIR_BOUNDS; + rect.top = lpLVItem->iSubItem; /* GetSubItemRect will fail in non-report mode, so there's * gonna be no invalidation then, yay! */ if (LISTVIEW_GetSubItemRect(infoPtr, lpLVItem->iItem, &rect)) @@ -2790,7 +2839,21 @@ { if (oldFocus != infoPtr->nFocusedItem && infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, oldFocus, FALSE); - LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem); + + /* this little optimization eliminates some nasty flicker */ + if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT && + !(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && + !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED)) + { + RECT rect; + + rect.left = LVIR_BOUNDS; + rect.top = 0; + if (LISTVIEW_GetSubItemRect(infoPtr, lpLVItem->iItem, &rect)) + LISTVIEW_InvalidateRect(infoPtr, &rect); + } + else + LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem); } /* restore text */ if (pszText) @@ -3935,6 +3998,9 @@ /* we need to worry about display issues in report mode only */ if (uView != LVS_REPORT) return TRUE; + /* if we have a focus, must first erase the focus rect */ + if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, FALSE); + /* Need to reset the item width when deleting a column */ infoPtr->nItemWidth -= rcCol.right - rcCol.left; @@ -3947,6 +4013,9 @@ ScrollWindowEx(infoPtr->hwndSelf, -(rcCol.right - rcCol.left), 0, &rcOld, &rcOld, 0, 0, SW_ERASE | SW_INVALIDATE); + /* we can restore focus now */ + if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, TRUE); + return TRUE; } @@ -5179,17 +5248,21 @@ static BOOL LISTVIEW_GetSubItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc) { POINT ptPosition; + INT nSubItem, flags; if (!lprc || LISTVIEW_GetType(infoPtr) != LVS_REPORT) return FALSE; - TRACE("(nItem=%d, nSubItem=%d)\n", nItem, lprc->top); + nSubItem = lprc->top; + flags = lprc->left; + + TRACE("(nItem=%d, nSubItem=%d)\n", nItem, nSubItem); - if (!Header_GetItemRect(infoPtr->hwndHeader, lprc->top, lprc)) return FALSE; + if (!Header_GetItemRect(infoPtr->hwndHeader, nSubItem, lprc)) return FALSE; if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &ptPosition)) return FALSE; lprc->top = ptPosition.y; lprc->bottom = lprc->top + infoPtr->nItemHeight; - switch(lprc->left) + switch(flags) { case LVIR_ICON: FIXME("Unimplemented LVIR_ICON\n"); @@ -5876,6 +5949,9 @@ /* we don't have to worry abiut display issues in non-report mode */ if ((infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return nNewColumn; + + /* if we have a focus, must first erase the focus rect */ + if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, FALSE); /* Need to reset the item width when inserting a new column */ infoPtr->nItemWidth += rcCol.right - rcCol.left; @@ -5888,6 +5964,9 @@ ScrollWindowEx(infoPtr->hwndSelf, rcCol.right - rcCol.left, 0, &rcOld, &rcOld, 0, 0, SW_ERASE | SW_INVALIDATE); + /* we can restore focus now */ + if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, TRUE); + return nNewColumn; } @@ -6666,18 +6745,14 @@ topvisible = LISTVIEW_GetTopIndex(infoPtr) + LISTVIEW_GetCountPerColumn(infoPtr) + 1; - /* Grow the hdpaItems array if necessary */ - if (nItems > infoPtr->hdpaItems->nMaxCount) - if (!DPA_SetPtr(infoPtr->hdpaItems, nItems - 1, NULL)) - return FALSE; - + infoPtr->nItemCount = nItems; infoPtr->nItemWidth = max(LISTVIEW_CalculateMaxWidth(infoPtr), DEFAULT_COLUMN_WIDTH); LISTVIEW_UpdateSize(infoPtr); LISTVIEW_UpdateScroll(infoPtr); - if (min(precount,infoPtr->nItemCount)<topvisible) + if (min(precount,infoPtr->nItemCount) < topvisible) LISTVIEW_InvalidateList(infoPtr); /* FIXME: optimize */ } else