Listview L4

Dimitrie O. Paun dpaun at rogers.com
Sun Oct 6 23:23:45 CDT 2002


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




More information about the wine-patches mailing list