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