Listview W1

Dimitrie O. Paun dpaun at rogers.com
Mon Oct 21 21:25:52 CDT 2002


This one completely reworks item positioning it
ICON, and SMALLICON mode. I am interested if it
breaks anything, for anyone.

ChangeLog
  Rework SetItemPosition, bunch of bugs squashed in the process
  Complete icon alignment rewrite: cleaner, incremental, etc
  Completely avoid aligning all icons on every insert
    - icon placement is incrementally computed now: it's fast
  Small cleanups, docs update, etc.

--- dlls/comctl32/listview.c.W0	Mon Oct 21 16:38:20 2002
+++ dlls/comctl32/listview.c	Mon Oct 21 22:19:07 2002
@@ -38,6 +38,7 @@
  *   -- tilemode
  *   -- groups
  *   -- FIXMEs (search for them)
+ *   -- LVA_SNAPTOGRID not implemented
  *   
  * States
  *   -- LVIS_ACTIVATING (not currently supported by comctl32.dll version 6.0)
@@ -231,6 +232,7 @@
   HDPA hdpaPosX;		/* maintains the (X, Y) coordinates of the */
   HDPA hdpaPosY;		/* items in LVS_ICON, and LVS_SMALLICON modes */
   HDPA hdpaColumns;		/* array of COLUMN_INFO pointers */
+  POINT currIconPos;		/* this is the position next icon will be placed */
   PFNLVCOMPARE pfnCompare;
   LPARAM lParamSort;
   HWND hwndEdit;
@@ -341,7 +343,6 @@
 static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *, LPRECT);
 static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT);
 static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
-static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *, INT, POINT);
 static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *);
 static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT);
 static BOOL LISTVIEW_UpdateSize(LISTVIEW_INFO *);
@@ -1900,9 +1901,10 @@
     OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y);
 }
 
+
 /***
  * DESCRIPTION:
- * Aligns the items with the top edge of the window.
+ * Resets the current position to the origin.
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
@@ -1910,109 +1912,160 @@
  * RETURN:
  * None
  */
-static void LISTVIEW_AlignTop(LISTVIEW_INFO *infoPtr)
+static inline void LISTVIEW_ResetCurrentPosition(LISTVIEW_INFO *infoPtr)
 {
-  UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
-  INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
-  POINT ptItem;
-  INT i, off_x=0, off_y=0;
+    infoPtr->currIconPos.x = infoPtr->currIconPos.y = 0;
+}
 
-  if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
-  {
-    /* Since SetItemPosition uses upper-left of icon, and for
-       style=LVS_ICON the icon is not left adjusted, get the offset */
-    if (uView == LVS_ICON)
-    {
-      off_y = ICON_TOP_PADDING;
-      off_x = (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
-    }
-    ptItem.x = off_x;
-    ptItem.y = off_y;
-    TRACE("Icon  off.x=%d, off.y=%d, left=%d, right=%d\n",
-	  off_x, off_y,
-	  infoPtr->rcList.left, infoPtr->rcList.right);
+/***
+ * DESCRIPTION:
+ * Returns the current icon position, and advances it along the top.
+ * The returned position is not offset by Origin.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [O] lpPos : will get the current icon position
+ *
+ * RETURN:
+ * None
+ */
+static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
+{
+    INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
+    
+    *lpPos = infoPtr->currIconPos;
+    
+    infoPtr->currIconPos.x += infoPtr->nItemWidth;
+    if (infoPtr->currIconPos.x + infoPtr->nItemWidth <= nListWidth) return;
 
-    if (nListWidth > infoPtr->nItemWidth)
-    {
-      for (i = 0; i < infoPtr->nItemCount; i++)
-      {
-        if ((ptItem.x-off_x) + infoPtr->nItemWidth > nListWidth)
-        {
-          ptItem.x = off_x;
-          ptItem.y += infoPtr->nItemHeight;
-        }
+    infoPtr->currIconPos.x  = 0;
+    infoPtr->currIconPos.y += infoPtr->nItemHeight;
+}
 
-        LISTVIEW_SetItemPosition(infoPtr, i, ptItem);
-        ptItem.x += infoPtr->nItemWidth;
-      }
+    
+/***
+ * DESCRIPTION:
+ * Returns the current icon position, and advances it down the left edge.
+ * The returned position is not offset by Origin.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [O] lpPos : will get the current icon position
+ *
+ * RETURN:
+ * None
+ */
+static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos)
+{
+    INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
+    
+    *lpPos = infoPtr->currIconPos;
+    
+    infoPtr->currIconPos.y += infoPtr->nItemHeight;
+    if (infoPtr->currIconPos.y + infoPtr->nItemHeight <= nListHeight) return;
+
+    infoPtr->currIconPos.x += infoPtr->nItemWidth;
+    infoPtr->currIconPos.y  = 0;
+}
+
+    
+/***
+ * DESCRIPTION:
+ * Moves an icon to the specified position.
+ * It takes care of invalidating the item, etc.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] nItem : the item to move
+ * [I] lpPos : the new icon position
+ * [I] isNew : flags the item as being new
+ *
+ * RETURN:
+ *   Success: TRUE
+ *   Failure: FALSE
+ */
+static BOOL LISTVIEW_MoveIconTo(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lppt, BOOL isNew)
+{
+    POINT Origin, old;
+    RECT rcItem;
+    
+    if (!isNew)
+    { 
+        old.x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
+        old.y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
+    
+        if (lppt->x == old.x && lppt->y == old.y) return TRUE;
     }
-    else
+
+    /* Allocating a POINTER for every item is too resource intensive,
+     * so we'll keep the (x,y) in different arrays */
+    if (!DPA_SetPtr(infoPtr->hdpaPosX, nItem, (void *)lppt->x)) return FALSE;
+    if (!DPA_SetPtr(infoPtr->hdpaPosY, nItem, (void *)lppt->y)) return FALSE;
+
+    LISTVIEW_GetOrigin(infoPtr, &Origin);
+    if (!isNew)
     {
-      for (i = 0; i < infoPtr->nItemCount; i++)
-      {
-        LISTVIEW_SetItemPosition(infoPtr, i, ptItem);
-        ptItem.y += infoPtr->nItemHeight;
-      }
+	rcItem.left = old.x + Origin.x;
+	rcItem.top = old.y + Origin.y;
+	rcItem.right = rcItem.left + infoPtr->nItemWidth;
+	rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
+	LISTVIEW_InvalidateRect(infoPtr, &rcItem);
     }
-  }
+	
+    rcItem.left = lppt->x + Origin.x;
+    rcItem.top = lppt->y + Origin.y;
+    rcItem.right = rcItem.left + infoPtr->nItemWidth;
+    rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
+    LISTVIEW_InvalidateRect(infoPtr, &rcItem);
+
+    return TRUE;
 }
 
 /***
  * DESCRIPTION:
- * Aligns the items with the left edge of the window.
+ * Arranges listview items in icon display mode.
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
+ * [I] nAlignCode : alignment code
  *
  * RETURN:
- * None
+ *   SUCCESS : TRUE
+ *   FAILURE : FALSE
  */
-static void LISTVIEW_AlignLeft(LISTVIEW_INFO *infoPtr)
+static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
 {
-  UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
-  INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
-  POINT ptItem;
-  INT i, off_x=0, off_y=0;
+    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
+    void (*next_pos)(LISTVIEW_INFO *, LPPOINT);
+    POINT pos;
+    INT i;
 
-  if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
-  {
-    /* Since SetItemPosition uses upper-left of icon, and for
-       style=LVS_ICON the icon is not left adjusted, get the offset */
-    if (uView == LVS_ICON)
+    if (uView != LVS_ICON && uView != LVS_SMALLICON) return FALSE;
+  
+    if (nAlignCode == LVA_DEFAULT)
     {
-      off_y = ICON_TOP_PADDING;
-      off_x = (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
+	if (infoPtr->dwStyle & LVS_ALIGNLEFT) nAlignCode = LVA_ALIGNLEFT;
+        else nAlignCode = LVA_ALIGNTOP;
     }
-    ptItem.x = off_x;
-    ptItem.y = off_y;
-    TRACE("Icon  off.x=%d, off.y=%d\n", off_x, off_y);
-
-    if (nListHeight > infoPtr->nItemHeight)
+   
+    switch (nAlignCode)
     {
-      for (i = 0; i < infoPtr->nItemCount; i++)
-      {
-        if (ptItem.y + infoPtr->nItemHeight > nListHeight)
-        {
-          ptItem.y = off_y;
-          ptItem.x += infoPtr->nItemWidth;
-        }
-
-        LISTVIEW_SetItemPosition(infoPtr, i, ptItem);
-        ptItem.y += infoPtr->nItemHeight;
-      }
+    case LVA_ALIGNLEFT:  next_pos = LISTVIEW_NextIconPosLeft; break;
+    case LVA_ALIGNTOP:   next_pos = LISTVIEW_NextIconPosTop;  break;
+    case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosTop;  break; /* FIXME */
+    default: return FALSE;
     }
-    else
+
+    LISTVIEW_ResetCurrentPosition(infoPtr);
+    for (i = 0; i < infoPtr->nItemCount; i++)
     {
-      for (i = 0; i < infoPtr->nItemCount; i++)
-      {
-        LISTVIEW_SetItemPosition(infoPtr, i, ptItem);
-        ptItem.x += infoPtr->nItemWidth;
-      }
+	next_pos(infoPtr, &pos);
+	LISTVIEW_MoveIconTo(infoPtr, i, &pos, FALSE);
     }
-  }
-}
-
 
+    return TRUE;
+}
+  
 /***
  * DESCRIPTION:
  * Retrieves the bounding rectangle of all the items, not offset by Origin.
@@ -3772,40 +3825,6 @@
   return dwViewRect;
 }
 
-/***
- * DESCRIPTION:
- * Arranges listview items in icon display mode.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] nAlignCode : alignment code
- *
- * RETURN:
- *   SUCCESS : TRUE
- *   FAILURE : FALSE
- */
-static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
-{
-    UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
-
-    if (uView != LVS_ICON && uView != LVS_SMALLICON) return FALSE;
-  
-    if (nAlignCode == LVA_DEFAULT)
-    {
-	if (infoPtr->dwStyle & LVS_ALIGNLEFT) nAlignCode = LVA_ALIGNLEFT;
-        else nAlignCode = LVA_ALIGNTOP;
-    }
-    
-    switch (nAlignCode)
-    {
-    case LVA_ALIGNLEFT: LISTVIEW_AlignLeft(infoPtr); return TRUE;
-    case LVA_ALIGNTOP: LISTVIEW_AlignTop(infoPtr); return TRUE;
-    case LVA_SNAPTOGRID: FIXME("LVA_SNAPTOGRID: not implemented\n"); break;
-    }
-
-    return FALSE;
-}
-
 /* << LISTVIEW_CreateDragImage >> */
 
 
@@ -5725,12 +5744,14 @@
     /* align items (set position of each item) */
     if ((uView == LVS_SMALLICON || uView == LVS_ICON))
     {
-	RECT rcBox;
-	/* FIXME: compute X, Y here, inline */
-    	/*if (is_icon && (infoPtr->dwStyle & LVS_AUTOARRANGE))*/
-	    LISTVIEW_Arrange(infoPtr, LVA_DEFAULT);
-	LISTVIEW_GetItemBox(infoPtr, nItem, &rcBox);
-	LISTVIEW_InvalidateRect(infoPtr, &rcBox);
+	POINT pt;
+
+	if (infoPtr->dwStyle & LVS_ALIGNLEFT)
+	    LISTVIEW_NextIconPosLeft(infoPtr, &pt);
+        else
+	    LISTVIEW_NextIconPosTop(infoPtr, &pt);
+
+	LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, TRUE);
     }
 
     /* now is the invalidation fun */
@@ -6514,42 +6535,30 @@
 static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, POINT pt)
 {
     UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
-    POINT old;
+    POINT Origin;
 
     TRACE("(nItem=%d, &pt=%s\n", nItem, debugpoint(&pt));
 
     if (nItem < 0 || nItem >= infoPtr->nItemCount ||
 	!(uView == LVS_ICON || uView == LVS_SMALLICON)) return FALSE;
 
+    LISTVIEW_GetOrigin(infoPtr, &Origin);
+
     /* This point value seems to be an undocumented feature.
      * The best guess is that it means either at the origin, 
      * or at true beginning of the list. I will assume the origin. */
     if ((pt.x == -1) && (pt.y == -1))
-	LISTVIEW_GetOrigin(infoPtr, &pt);
-    else if (uView == LVS_ICON)
+	pt = Origin;
+    
+    if (uView == LVS_ICON)
     {
 	pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
 	pt.y -= ICON_TOP_PADDING;
     }
+    pt.x -= Origin.x;
+    pt.y -= Origin.y;
 
-    /* save the old position */
-    old.x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
-    old.y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
-    
-    /* Is the position changing? */
-    if (pt.x == old.x && pt.y == old.y) return TRUE;
-   
-    /* FIXME: shouldn't we invalidate, as the item moved? */
-    
-    /* Allocating a POINTER for every item is too resource intensive,
-     * so we'll keep the (x,y) in different arrays */
-    if (DPA_SetPtr(infoPtr->hdpaPosX, nItem, (void *)pt.x) &&
-        DPA_SetPtr(infoPtr->hdpaPosY, nItem, (void *)pt.y) )
-	return TRUE;
-    
-    ERR("We should never fail here (nItem=%d, pt=%s), please report.\n", 
-	nItem, debugpoint(&pt));
-    return FALSE;
+    return LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, FALSE);
 }
 
 /***
@@ -6792,9 +6801,6 @@
 	infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
     /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
 
-    /* align the items */
-    LISTVIEW_AlignTop(infoPtr);
-
     /* refresh the display */
     if (uView != LVS_ICON && uView != LVS_SMALLICON)
 	LISTVIEW_InvalidateList(infoPtr);




More information about the wine-patches mailing list