Listview L1

Dimitrie O. Paun dpaun at rogers.com
Sun Oct 6 16:39:58 CDT 2002


This one *almost* fixes all focus rectangle problems.

The only one left (that I know of), is that in Xnews,
the first item *only* gets the focus rectangle drawn
when it shouldn't. The even stranger thing is that
it so happens only after the first invalidate of
the first item when it loses the focus. All other
redraws proceed correctly. This has to be an app
problem, but I can't figure it out for the life of me,
any help would be more than appreciated.

Oh, BTW, this patch also breaks large item handling
in ICON mode. It will get fixed shortly.

Please let me know if you exprience any other focus
related problems.


ChangeLog
  Fix focus handling for a onwer draw listviews.

--- dlls/comctl32/listview.c.L0	Sun Oct  6 03:21:21 2002
+++ dlls/comctl32/listview.c	Sun Oct  6 17:30:03 2002
@@ -151,7 +151,6 @@
   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;
@@ -729,6 +728,7 @@
     InvalidateRect(infoPtr->hwndSelf, rect, TRUE); \
 } while (0)
 
+/* FIXME: what if we show the focus on a large item in ICON mode? */
 #define LISTVIEW_InvalidateItem(infoPtr, nItem) do { \
     RECT rcItem; \
     rcItem.left = LVIR_BOUNDS; \
@@ -1140,19 +1140,29 @@
 
 
 /***
- * Toggles (draws/erase) the focus rectangle. 
+ * DESCRIPTION:
+ * Shows/hides the focus rectangle. 
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] fShow : TRUE to show the focus, FALSE to hide it.
+ *
+ * RETURN:
+ * None
  */
-static inline void LISTVIEW_ToggleFocusRect(LISTVIEW_INFO *infoPtr)
+static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, INT nItem, BOOL fShow)
 {
-    TRACE("rcFocus=%s\n", debugrect(&infoPtr->rcFocus));
+    TRACE("fShow=%d, nItem=%d\n", fShow, nItem);
 
-    /* if we have a focus rectagle, draw it */
-    if (!IsRectEmpty(&infoPtr->rcFocus))
-    {
-	HDC hdc = GetDC(infoPtr->hwndSelf);
-	DrawFocusRect(hdc, &infoPtr->rcFocus);
-	ReleaseDC(infoPtr->hwndSelf, hdc);
-    }
+    /* 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);
 }
 
 /***
@@ -2810,18 +2820,7 @@
     if (bResult && !infoPtr->bIsDrawing && lpLVItem->iSubItem == 0)
     {
 	if (oldFocus != infoPtr->nFocusedItem && infoPtr->bFocus)
-	{
-	    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_ShowFocusRect(infoPtr, oldFocus, FALSE);
 	LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem);
     }
     /* restore text */
@@ -3236,7 +3235,6 @@
    * 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??? */
@@ -3247,7 +3245,6 @@
       DeleteObject(hBrush);
 
       /* Save size of item drawing for next InvalidateRect */
-      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
@@ -3378,7 +3375,7 @@
             dis.itemID = nItem;
             dis.itemAction = ODA_DRAWENTIRE;
             if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED;
-            if (item.state & LVIS_FOCUSED) dis.itemState |= ODS_FOCUS;
+            if (infoPtr->bFocus && (item.state & LVIS_FOCUSED)) dis.itemState |= ODS_FOCUS;
             dis.hwndItem = infoPtr->hwndSelf;
             dis.hDC = hdc;
             dis.rcItem.left = lpCols[0].rc.left;
@@ -3675,7 +3672,7 @@
 	LISTVIEW_RefreshIcon(infoPtr, hdc, uView == LVS_SMALLICON, cdmode);
 
     /* if we have a focus rect, draw it */
-    if (infoPtr->bFocus && !IsRectEmpty(&infoPtr->rcFocus))
+    if (infoPtr->bFocus && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED))
 	DrawFocusRect(hdc, &infoPtr->rcFocus);
 
     /* unselect objects */
@@ -5406,6 +5403,8 @@
     INT nCountPerColumn;
     INT i;
 
+    TRACE("nItem=%d, uFlags=%x\n", nItem, uFlags);
+
     if ((nItem < -1) || (nItem >= GETITEMCOUNT(infoPtr))) return -1;
 
     ZeroMemory(&lvFindInfo, sizeof(lvFindInfo));
@@ -7277,8 +7276,7 @@
     ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList, 
 		   &infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE);
     /* if we have focus, adjust rect */
-    if (infoPtr->bFocus && !IsRectEmpty(&infoPtr->rcFocus))
-	OffsetRect(&infoPtr->rcFocus, dx, dy);
+    OffsetRect(&infoPtr->rcFocus, dx, dy);
     UpdateWindow(infoPtr->hwndSelf);
 }
 
@@ -7646,7 +7644,7 @@
     notify_killfocus(infoPtr);
 
     /* if we have a focus rectagle, get rid of it */
-    LISTVIEW_ToggleFocusRect(infoPtr);
+    LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, FALSE);
     
     /* invalidate the selected items before reseting focus flag */
     LISTVIEW_InvalidateSelectedItems(infoPtr);
@@ -8175,7 +8173,7 @@
     notify_setfocus(infoPtr);
 
     /* put the focus rect back on */
-    LISTVIEW_ToggleFocusRect(infoPtr);
+    LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, TRUE);
 
     /* set window focus flag */
     infoPtr->bFocus = TRUE;




More information about the wine-patches mailing list