Listview M8

Dimitrie O. Paun dpaun at rogers.com
Tue Oct 8 19:52:25 CDT 2002


Yeah, I know, *I*'ve added a big comment saying it's not worth it,
but I couldn't resist. This one (I think) minimizes redraw on focus
change as much as possible.

ChangeLog
  Fix large item label calculation when not focused
  Fancy focus rectangle handling.

--- dlls/comctl32/listview.c.M7	Tue Oct  8 20:07:23 2002
+++ dlls/comctl32/listview.c	Tue Oct  8 20:45:55 2002
@@ -262,6 +262,7 @@
  */
 static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
 static INT LISTVIEW_SuperHitTestItem(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL);
+static BOOL LISTVIEW_GetItemMeasures(LISTVIEW_INFO *, INT, LPRECT, LPRECT, LPRECT, LPRECT);
 static void LISTVIEW_AlignLeft(LISTVIEW_INFO *);
 static void LISTVIEW_AlignTop(LISTVIEW_INFO *);
 static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *, INT);
@@ -1142,67 +1143,57 @@
  */
 static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, BOOL fShow)
 {
-    RECT rcItem;
-    INT nItem = infoPtr->nFocusedItem;
+    HDC hdc;
 
-    TRACE("fShow=%d, nItem=%d\n", fShow, nItem);
+    TRACE("fShow=%d, nItem=%d\n", fShow, infoPtr->nFocusedItem);
 
-    if (nItem < 0 || nItem >= infoPtr->nItemCount) return;
+    if (infoPtr->nFocusedItem < 0) return;
 
-    rcItem.left = LVIR_BOUNDS;
-    rcItem.top = 0;
-    if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT &&
-	 !(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) &&
-	 !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED))
+    /* we need some gymnastics in ICON mode to handle large items */
+    if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON )
     {
-	/* this little optimization eliminates some nasty flicker */
-	if (!LISTVIEW_GetSubItemRect(infoPtr, nItem, &rcItem)) return;
-    }
-    else
-    {
-	if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return;
+	RECT rcBox;
+
+	if (!LISTVIEW_GetItemMeasures(infoPtr, infoPtr->nFocusedItem, &rcBox, 0, 0, 0)) 
+	    return;
+	if ((rcBox.bottom - rcBox.top) > infoPtr->nItemHeight)
+	{
+	    LISTVIEW_InvalidateRect(infoPtr, &rcBox);
+	    return;
+	}
     }
-    
+
+    if (!(hdc = GetDC(infoPtr->hwndSelf))) return;
+
     if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)
     {
 	DRAWITEMSTRUCT dis;
 	LVITEMW item;
-	HDC hdc;
 
-        item.iItem = nItem;
+        item.iItem = infoPtr->nFocusedItem;
 	item.iSubItem = 0;
         item.mask = LVIF_PARAM;
-	if (!LISTVIEW_GetItemW(infoPtr, &item)) goto invalidate;
+	if (!LISTVIEW_GetItemW(infoPtr, &item)) goto done;
 	   
-	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.itemID = item.iItem;
 	dis.itemAction = ODA_FOCUS;
 	if (fShow) dis.itemState |= ODS_FOCUS;
 	dis.hwndItem = infoPtr->hwndSelf;
 	dis.hDC = hdc;
-	dis.rcItem = rcItem;
+	if (!LISTVIEW_GetItemMeasures(infoPtr, dis.itemID, &dis.rcItem, 0, 0, 0)) goto done;
 	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);
+	DrawFocusRect(hdc, &infoPtr->rcFocus);
     }
+done:
+    ReleaseDC(infoPtr->hwndSelf, hdc);
 }
 
 /***
@@ -1451,8 +1442,6 @@
 
 	if (uView == LVS_ICON)
 	{
-	    if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight)
-		labelSize.cy = (labelSize.cy / infoPtr->ntmHeight) * infoPtr->ntmHeight;
 	    Label.left = Box.left + (infoPtr->iconSpacing.cx - labelSize.cx) / 2;
 	    Label.top  = Box.top + ICON_TOP_PADDING_HITABLE +
 		         infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
@@ -1460,7 +1449,16 @@
 	    if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)
 	        Label.bottom = Label.top + infoPtr->nItemHeight;
 	    else
+	    {
+		if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight)
+		{
+		    labelSize.cy = min(Box.bottom - Label.top, labelSize.cy);
+		    labelSize.cy /= infoPtr->ntmHeight;
+		    labelSize.cy = max(labelSize.cy, 1);
+		    labelSize.cy *= infoPtr->ntmHeight;
+		}
 	        Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING;
+	    }
 	}
 	else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */
 	{




More information about the wine-patches mailing list