Reworked how selections are kept track of in the list view. Selections
are now listed as a sorted range of paired integers.
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index d62d690..0f7f441 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -998,8 +998,409 @@
return nItemHeight;
}
+
+static void LISTVIEW_PrintSelectionRanges(hwnd)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION *selection;
+ INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
+ INT i;
+
+ TRACE("Selections are:\n");
+ for (i = 0; i < topSelection; i++)
+ {
+ selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
+ TRACE(" %lu - %lu\n",selection->lower,selection->upper);
+ }
+}
+
/***
* DESCRIPTION:
+ * A compare function for selection ranges
+ *
+ *PARAMETER(S)
+ * [I] LPVOID : Item 1;
+ * [I] LPVOID : Item 2;
+ * [I] LPARAM : flags
+ *
+ *RETURNS:
+ * >0 : if Item 1 > Item 2
+ * <0 : if Item 2 > Item 1
+ * 0 : if Item 1 == Item 2
+ */
+static INT LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
+ LPARAM flags)
+{
+ int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
+ int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
+ int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
+ int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
+ int rc=0;
+
+ if (u1 < l2)
+ rc= -1;
+
+ if (u2 < l1)
+ rc= 1;
+
+ return rc;
+}
+
+/**
+* DESCRIPTION:
+* Adds a selection range.
+*
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : lower item index
+* [I] INT : upper item index
+*
+* RETURN:
+* None
+*/
+static VOID LISTVIEW_AddSelectionRange(HWND hwnd, INT lItem, INT uItem)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION *selection;
+ INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
+ BOOL lowerzero=FALSE;
+
+ selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
+ selection->lower = lItem;
+ selection->upper = uItem;
+
+ TRACE("Add range %i - %i\n",lItem,uItem);
+ if (topSelection)
+ {
+ LISTVIEW_SELECTION *checkselection,*checkselection2;
+ INT index,mergeindex;
+
+ /* find overlapping selections */
+ /* we want to catch adjacent ranges so expand our range by 1 */
+
+ selection->upper++;
+ if (selection->lower == 0)
+ lowerzero = TRUE;
+ else
+ selection->lower--;
+
+ index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
+ LISTVIEW_CompareSelectionRanges,
+ 0,0);
+ selection->upper --;
+ if (lowerzero)
+ lowerzero=FALSE;
+ else
+ selection->lower ++;
+
+ if (index >=0)
+ {
+ checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
+ TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
+ checkselection->upper);
+
+ checkselection->lower = min(selection->lower,checkselection->lower);
+ checkselection->upper = max(selection->upper,checkselection->upper);
+
+ TRACE("New range (%lu - %lu)\n", checkselection->lower,
+ checkselection->upper);
+
+ COMCTL32_Free(selection);
+
+ /* merge now common selection ranges in the lower group*/
+ do
+ {
+ checkselection->upper ++;
+ if (checkselection->lower == 0)
+ lowerzero = TRUE;
+ else
+ checkselection->lower --;
+
+ TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
+ checkselection->upper);
+
+ /* not sorted yet */
+ mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
+ LISTVIEW_CompareSelectionRanges, 0,
+ 0);
+
+ checkselection->upper --;
+ if (lowerzero)
+ lowerzero = FALSE;
+ else
+ checkselection->lower ++;
+
+ if (mergeindex >=0 && mergeindex != index)
+ {
+ TRACE("Merge with index %i\n",mergeindex);
+ checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
+ mergeindex);
+ checkselection->lower = min(checkselection->lower,
+ checkselection2->lower);
+ checkselection->upper = max(checkselection->upper,
+ checkselection2->upper);
+ COMCTL32_Free(checkselection2);
+ DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
+ index --;
+ }
+ }
+ while (mergeindex > -1 && mergeindex <index);
+
+ /* merge now common selection ranges in the upper group*/
+ do
+ {
+ checkselection->upper ++;
+ if (checkselection->lower == 0)
+ lowerzero = TRUE;
+ else
+ checkselection->lower --;
+
+ TRACE("search upper range %i (%lu - %lu)\n",index,
+ checkselection->lower, checkselection->upper);
+
+ /* not sorted yet */
+ mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
+ index+1,
+ LISTVIEW_CompareSelectionRanges, 0,
+ 0);
+
+ checkselection->upper --;
+ if (lowerzero)
+ lowerzero = FALSE;
+ else
+ checkselection->lower ++;
+
+ if (mergeindex >=0 && mergeindex !=index)
+ {
+ TRACE("Merge with index %i\n",mergeindex);
+ checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
+ mergeindex);
+ checkselection->lower = min(checkselection->lower,
+ checkselection2->lower);
+ checkselection->upper = max(checkselection->upper,
+ checkselection2->upper);
+ COMCTL32_Free(checkselection2);
+ DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
+ }
+ }
+ while (mergeindex > -1);
+ }
+ else
+ {
+
+ index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
+ LISTVIEW_CompareSelectionRanges, 0,
+ DPAS_INSERTAFTER);
+
+ TRACE("Insert before index %i\n",index);
+ if (index == -1)
+ index = 0;
+ DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
+ }
+ }
+ else
+ {
+ DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
+ }
+ /*
+ * Incase of error
+ */
+ DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
+ LISTVIEW_PrintSelectionRanges(hwnd);
+}
+
+/**
+* DESCRIPTION:
+* check if a specified index is selected.
+*
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : item index
+*
+* RETURN:
+* None
+*/
+static BOOL LISTVIEW_IsSelected(HWND hwnd, INT nItem)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION selection;
+ INT index;
+
+ selection.upper = nItem;
+ selection.lower = nItem;
+
+ index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
+ LISTVIEW_CompareSelectionRanges,
+ 0,DPAS_SORTED);
+ if (index != -1)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/***
+* DESCRIPTION:
+* Removes all selection ranges
+*
+* Parameters(s):
+* HWND: window handle
+*
+* RETURNS:
+* SUCCESS : TRUE
+* FAILURE : TRUE
+*/
+static LRESULT LISTVIEW_RemoveAllSelections(HWND hwnd)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION *selection;
+ INT i;
+
+ for (i = 0; i < infoPtr->hdpaSelectionRanges->nItemCount; i++)
+ {
+ selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,i);
+ if (selection)
+ COMCTL32_Free(selection);
+ }
+ return DPA_DeleteAllPtrs(infoPtr->hdpaSelectionRanges);
+}
+
+/**
+* DESCRIPTION:
+* Removes a range selections.
+*
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : lower item index
+* [I] INT : upper item index
+*
+* RETURN:
+* None
+*/
+static VOID LISTVIEW_RemoveSelectionRange(HWND hwnd, INT lItem, INT uItem)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION removeselection,*checkselection;
+ INT index;
+
+ removeselection.lower = lItem;
+ removeselection.upper = uItem;
+
+ TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
+ LISTVIEW_PrintSelectionRanges(hwnd);
+
+ index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
+ LISTVIEW_CompareSelectionRanges,
+ 0,0);
+
+ if (index == -1)
+ return;
+
+
+ checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
+ index);
+
+ TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
+ checkselection->upper);
+
+ /* case 1: Same */
+ if ((checkselection->upper == removeselection.upper) &&
+ (checkselection->lower == removeselection.lower))
+ {
+ DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
+ TRACE("Case 1\n");
+ }
+ /* case 2: engulf */
+ else if (((checkselection->upper < removeselection.upper) &&
+ (checkselection->lower > removeselection.lower))||
+ ((checkselection->upper <= removeselection.upper) &&
+ (checkselection->lower > removeselection.lower)) ||
+ ((checkselection->upper < removeselection.upper) &&
+ (checkselection->lower >= removeselection.lower)))
+
+ {
+ DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
+ /* do it again because others may also get caught */
+ TRACE("Case 2\n");
+ LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
+ }
+ /* case 3: overlap upper */
+ else if ((checkselection->upper < removeselection.upper) &&
+ (checkselection->lower < removeselection.lower))
+ {
+ checkselection->upper = removeselection.lower - 1;
+ TRACE("Case 3\n");
+ LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
+ }
+ /* case 4: overlap lower */
+ else if ((checkselection->upper > removeselection.upper) &&
+ (checkselection->lower > removeselection.lower))
+ {
+ checkselection->lower = removeselection.upper + 1;
+ TRACE("Case 4\n");
+ LISTVIEW_RemoveSelectionRange(hwnd,lItem,uItem);
+ }
+ /* case 5: fully internal */
+ else if (checkselection->upper == removeselection.upper)
+ checkselection->upper = removeselection.lower - 1;
+ else if (checkselection->lower == removeselection.lower)
+ checkselection->lower = removeselection.upper + 1;
+ else
+ {
+ /* bisect the range */
+ LISTVIEW_SELECTION *newselection;
+
+ newselection = (LISTVIEW_SELECTION *)
+ COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
+ newselection -> lower = checkselection->lower;
+ newselection -> upper = removeselection.lower - 1;
+ checkselection -> lower = removeselection.upper + 1;
+ DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
+ TRACE("Case 5\n");
+ DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
+ }
+ LISTVIEW_PrintSelectionRanges(hwnd);
+}
+
+/**
+* DESCRIPTION:
+* shifts all selection indexs starting with the indesx specified
+* in the direction specified.
+*
+* PARAMETER(S):
+* [I] HWND : window handle
+* [I] INT : item index
+* [I] INT : amount and direction of shift
+*
+* RETURN:
+* None
+*/
+static VOID LISTVIEW_ShiftSelections(HWND hwnd, INT nItem, INT direction)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ LISTVIEW_SELECTION selection,*checkselection;
+ INT index;
+
+ selection.upper = nItem;
+ selection.lower = nItem;
+
+ index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
+ LISTVIEW_CompareSelectionRanges,
+ 0,DPAS_SORTED|DPAS_INSERTAFTER);
+
+ while ((index < infoPtr->hdpaSelectionRanges->nItemCount)&&(index != -1))
+ {
+ checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
+ if (checkselection->lower >= nItem)
+ checkselection->lower += direction;
+ if (checkselection->upper >= nItem)
+ checkselection->upper += direction;
+ index ++;
+ }
+}
+
+
+/**
+ * DESCRIPTION:
* Adds a block of selections.
*
* PARAMETER(S):
@@ -1014,21 +1415,14 @@
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
INT nFirst = min(infoPtr->nSelectionMark, nItem);
INT nLast = max(infoPtr->nSelectionMark, nItem);
- LVITEMA lvItem;
- INT i;
- lvItem.state = LVIS_SELECTED;
- lvItem.stateMask= LVIS_SELECTED;
-
- for (i = nFirst; i <= nLast; i++)
- {
- ListView_SetItemState(hwnd, i, &lvItem);
- }
-
+ LISTVIEW_AddSelectionRange(hwnd,nFirst,nLast);
+
LISTVIEW_SetItemFocus(hwnd, nItem);
infoPtr->nSelectionMark = nItem;
}
+
/***
* DESCRIPTION:
* Adds a single selection.
@@ -1043,12 +1437,8 @@
static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
- LVITEMA lvItem;
- lvItem.state = LVIS_SELECTED;
- lvItem.stateMask= LVIS_SELECTED;
-
- ListView_SetItemState(hwnd, nItem, &lvItem);
+ LISTVIEW_AddSelectionRange(hwnd,nItem,nItem);
LISTVIEW_SetItemFocus(hwnd, nItem);
infoPtr->nSelectionMark = nItem;
@@ -1070,20 +1460,15 @@
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
BOOL bResult;
- LVITEMA lvItem;
- lvItem.stateMask= LVIS_SELECTED;
-
- if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ if (LISTVIEW_IsSelected(hwnd,nItem))
{
- lvItem.state = 0;
- ListView_SetItemState(hwnd, nItem, &lvItem);
+ LISTVIEW_RemoveSelections(hwnd,nItem,nItem);
bResult = FALSE;
}
else
{
- lvItem.state = LVIS_SELECTED;
- ListView_SetItemState(hwnd, nItem, &lvItem);
+ LISTVIEW_AddSelectionRange(hwnd,nItem,nItem);
bResult = TRUE;
}
@@ -1107,25 +1492,20 @@
static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
- LVITEMA lvItem;
POINT ptItem;
INT i;
- lvItem.stateMask = LVIS_SELECTED;
-
for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
{
LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
if (PtInRect(&rcSelRect, ptItem) != FALSE)
{
- lvItem.state = LVIS_SELECTED;
+ LISTVIEW_AddSelectionRange(hwnd,i,i);
}
else
{
- lvItem.state = 0;
+ LISTVIEW_RemoveSelections(hwnd,i,i);
}
-
- ListView_SetItemState(hwnd, i, &lvItem);
}
}
@@ -1144,27 +1524,23 @@
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
- LVITEMA lvItem;
if ((uView == LVS_LIST) || (uView == LVS_REPORT))
{
INT i;
INT nFirst = min(infoPtr->nSelectionMark, nItem);
INT nLast = max(infoPtr->nSelectionMark, nItem);
- lvItem.stateMask = LVIS_SELECTED;
-
+
for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
{
if ((i < nFirst) || (i > nLast))
{
- lvItem.state = 0;
+ LISTVIEW_RemoveSelections(hwnd,i,i);
}
else
{
- lvItem.state = LVIS_SELECTED;
+ LISTVIEW_AddSelectionRange(hwnd,i,i);
}
-
- ListView_SetItemState(hwnd, i, &lvItem);
}
}
else
@@ -1242,24 +1618,17 @@
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
LVITEMA lvItem;
- if (nItem > 0)
- {
- LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
- }
-
- if (nItem < GETITEMCOUNT(infoPtr))
- {
- LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
- }
-
ZeroMemory(&lvItem, sizeof(LVITEMA));
lvItem.stateMask = LVIS_FOCUSED;
ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
-
- lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
- lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
+
+ lvItem.state = LVIS_FOCUSED;
+ lvItem.stateMask = LVIS_FOCUSED;
ListView_SetItemState(hwnd, nItem, &lvItem);
+ LISTVIEW_RemoveAllSelections(hwnd);
+ LISTVIEW_AddSelectionRange(hwnd,nItem,nItem);
+
infoPtr->nFocusedItem = nItem;
infoPtr->nSelectionMark = nItem;
}
@@ -1404,9 +1773,22 @@
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
RECT rcItem;
- INT i;
-
- for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
+ INT i,topindex,bottomindex;
+ LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+ UINT uView = lStyle & LVS_TYPEMASK;
+
+ topindex = ListView_GetTopIndex(hwnd);
+ if (uView == LVS_REPORT)
+ {
+ bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
+ bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
+ }
+ else
+ {
+ bottomindex = GETITEMCOUNT(infoPtr);
+ }
+
+ for (i = topindex; i < bottomindex; i++)
{
rcItem.left = LVIR_SELECTBOUNDS;
if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
@@ -1435,16 +1817,7 @@
*/
static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
{
- LVITEMA lvItem;
- INT i;
-
- lvItem.state = 0;
- lvItem.stateMask = LVIS_SELECTED;
-
- for (i = nFirst; i <= nLast; i++)
- {
- ListView_SetItemState(hwnd, i, &lvItem);
- }
+ LISTVIEW_RemoveSelectionRange(hwnd,nFirst,nLast);
}
/***
@@ -1789,6 +2162,10 @@
BOOL bResult = FALSE;
HDPA hdpaSubItems;
INT nPosition, nItem;
+ LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+
+ if (lStyle & LVS_OWNERDATA)
+ return FALSE;
if (lpLVItem != NULL)
{
@@ -1918,18 +2295,23 @@
if (lStyle & LVS_OWNERDATA)
{
if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
+ {
+ if (lpLVItem->stateMask & LVIS_FOCUSED)
{
- hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
- if (hdpaSubItems != NULL)
- {
- lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
- if (lpItem != NULL)
- {
- lpItem->state = lpLVItem->state & lpLVItem->stateMask;
- return TRUE;
- }
- }
+ if (lpLVItem->state & LVIS_FOCUSED)
+ infoPtr->nFocusedItem = lpLVItem->iItem;
+ else if (infoPtr->nFocusedItem == lpLVItem->iItem)
+ infoPtr->nFocusedItem = -1;
}
+ if (lpLVItem->stateMask & LVIS_SELECTED)
+ {
+ if (lpLVItem->state & LVIS_SELECTED)
+ LISTVIEW_AddSelectionRange(hwnd,lpLVItem->iItem,lpLVItem->iItem);
+ else
+ LISTVIEW_RemoveSelections(hwnd,lpLVItem->iItem,lpLVItem->iItem);
+ }
+ return TRUE;
+ }
return FALSE;
}
@@ -1966,9 +2348,11 @@
*/
if (lStyle & LVS_SINGLESEL)
{
- LISTVIEW_RemoveSelections(hwnd, 0, lpLVItem->iItem-1);
- LISTVIEW_RemoveSelections(hwnd, lpLVItem->iItem + 1,
- GETITEMCOUNT(infoPtr));
+ LISTVIEW_SetSelection(hwnd,lpLVItem->iItem);
+ }
+ else
+ {
+ LISTVIEW_AddSelection(hwnd,lpLVItem->iItem);
}
}
else if (nmlv.uNewState & LVIS_FOCUSED)
@@ -2039,6 +2423,10 @@
BOOL bResult = FALSE;
HDPA hdpaSubItems;
LISTVIEW_SUBITEM *lpSubItem;
+ LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+
+ if (lStyle & LVS_OWNERDATA)
+ return FALSE;
if (lpLVItem != NULL)
{
@@ -2901,6 +3289,7 @@
/* << LISTVIEW_CreateDragImage >> */
+
/***
* DESCRIPTION:
* Removes all listview items and subitems.
@@ -2928,6 +3317,14 @@
HDPA hdpaSubItems;
TRACE("(hwnd=%x,)\n", hwnd);
+ LISTVIEW_RemoveAllSelections(hwnd);
+
+ if (lStyle & LVS_OWNERDATA)
+ {
+ infoPtr->hdpaItems->nItemCount = 0;
+ InvalidateRect(hwnd, NULL, TRUE);
+ return TRUE;
+ }
if (GETITEMCOUNT(infoPtr) > 0)
{
@@ -3035,7 +3432,7 @@
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
BOOL bResult = FALSE;
-
+
if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
{
bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
@@ -3084,6 +3481,15 @@
TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
+ LISTVIEW_ShiftSelections(hwnd,nItem,-1);
+
+ if (lStyle & LVS_OWNERDATA)
+ {
+ infoPtr->hdpaItems->nItemCount --;
+ InvalidateRect(hwnd, NULL, TRUE);
+ return TRUE;
+ }
+
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
{
/* initialize memory */
@@ -3209,14 +3615,32 @@
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
HDPA hdpaSubItems;
BOOL bUpdateItemText;
-
- ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
+ LISTVIEW_ITEM lvItemRef;
+ LVITEMA item;
- if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
+ ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
+
+ if (!(lStyle & LVS_OWNERDATA))
+ {
+ if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
return FALSE;
- if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
+ if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
return FALSE;
+ }
+ else
+ {
+ ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
+ ZeroMemory(&item,sizeof(LVITEMA));
+ item.iItem = nItem;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM | LVIF_STATE;
+ ListView_GetItemA(hwnd,&item);
+ lvItemRef.state = item.state;
+ lvItemRef.iImage = item.iImage;
+ lvItemRef.lParam = item.lParam;
+ lpItem = &lvItemRef;
+ }
dispInfo.hdr.hwndFrom = hwnd;
dispInfo.hdr.idFrom = nCtrlId;
@@ -3269,7 +3693,9 @@
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
HDPA hdpaSubItems;
CHAR szDispText[DISP_TEXT_SIZE];
- LVITEMA lvItem;
+ LVITEMA lvItem,item;
+ LISTVIEW_ITEM lvItemRef;
+ LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
return FALSE;
@@ -3284,12 +3710,27 @@
LISTVIEW_SetItemFocus(hwnd, nItem);
ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
- if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
- return 0;
-
- if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
+ if (!(lStyle & LVS_OWNERDATA))
+ {
+ if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
return 0;
+ if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
+ return 0;
+ }
+ else
+ {
+ ZeroMemory(&lvItemRef,sizeof(LISTVIEW_ITEM));
+ ZeroMemory(&item,sizeof(LVITEMA));
+ item.iItem = nItem;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM | LVIF_STATE;
+ ListView_GetItemA(hwnd,&item);
+ lvItemRef.iImage = item.iImage;
+ lvItemRef.state = item.state;
+ lvItemRef.lParam = item.lParam;
+ lpItem = &lvItemRef;
+ }
/* get information needed for drawing the item */
ZeroMemory(&lvItem, sizeof(LVITEMA));
@@ -4076,20 +4517,16 @@
if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
{
- hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
- if (hdpaSubItems == NULL)
- return FALSE;
-
- lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
- if (lpItem == NULL)
- return FALSE;
-
- lpLVItem->state = lpItem->state & lpLVItem->stateMask;
+ lpLVItem->state = 0;
+ if (infoPtr->nFocusedItem == lpLVItem->iItem)
+ lpLVItem->state |= LVIS_FOCUSED;
+ if (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem))
+ lpLVItem->state |= LVIS_SELECTED;
}
return TRUE;
}
-
+
hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
if (hdpaSubItems == NULL)
@@ -4194,10 +4631,20 @@
lpLVItem->state = lpItem->state;
lpLVItem->state &= ~dispInfo.item.stateMask;
lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
+
+ lpLVItem->state &= ~LVIS_SELECTED;
+ if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
+ (LISTVIEW_IsSelected(hwnd,dispInfo.item.iItem)))
+ lpLVItem->state |= LVIS_SELECTED;
}
else if (lpLVItem->mask & LVIF_STATE)
{
lpLVItem->state = lpItem->state & lpLVItem->stateMask;
+
+ lpLVItem->state &= ~LVIS_SELECTED;
+ if ((lpLVItem->stateMask & LVIS_SELECTED) &&
+ (LISTVIEW_IsSelected(hwnd,lpLVItem->iItem)))
+ lpLVItem->state |= LVIS_SELECTED;
}
if (lpLVItem->mask & LVIF_PARAM)
@@ -4284,7 +4731,7 @@
TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
lpptPosition);
-
+
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
(lpptPosition != NULL))
{
@@ -5037,6 +5484,7 @@
*/
static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
{
+/* REDO THIS */
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
INT nSelectedCount = 0;
INT i;
@@ -5151,12 +5599,26 @@
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
RECT rcItem;
- INT i;
-
+ INT i,topindex,bottomindex;
+ LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+ UINT uView = lStyle & LVS_TYPEMASK;
+
+
TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
lpHitTestInfo->pt.y);
- for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
+ topindex = ListView_GetTopIndex(hwnd);
+ if (uView == LVS_REPORT)
+ {
+ bottomindex = topindex + LISTVIEW_GetCountPerColumn(hwnd) + 1;
+ bottomindex = min(bottomindex,GETITEMCOUNT(infoPtr));
+ }
+ else
+ {
+ bottomindex = GETITEMCOUNT(infoPtr);
+ }
+
+ for (i = topindex; i < bottomindex; i++)
{
rcItem.left = LVIR_BOUNDS;
if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
@@ -5427,42 +5889,9 @@
if (lStyle & LVS_OWNERDATA)
{
- lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
- if (lpItem != NULL)
- {
- ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
- /* insert item in listview control data structure */
- hdpaSubItems = DPA_Create(8);
- if (hdpaSubItems != NULL)
- {
- nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
- if (nItem != -1)
- {
- nItem = DPA_InsertPtr(infoPtr->hdpaItems, 1,
- hdpaSubItems);
- /* manage item focus */
- if ((lpLVItem)&&(lpLVItem->mask & LVIF_STATE))
- {
- lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
- if (lpLVItem->stateMask & LVIS_SELECTED)
- {
- LISTVIEW_SetSelection(hwnd, nItem);
- }
- else if (lpLVItem->stateMask & LVIS_FOCUSED)
- {
- LISTVIEW_SetItemFocus(hwnd, nItem);
- }
- }
- }
- }
- }
- /* free memory if unsuccessful */
- if ((nItem == -1) && (lpItem != NULL))
- {
- COMCTL32_Free(lpItem);
- }
-
- return nItem;
+ nItem = infoPtr->hdpaItems->nItemCount;
+ infoPtr->hdpaItems->nItemCount ++;
+ return nItem;
}
if (lpLVItem != NULL)
@@ -5501,6 +5930,8 @@
}
if (nItem != -1)
{
+ LISTVIEW_ShiftSelections(hwnd,nItem,1);
+
/* manage item focus */
if (lpLVItem->mask & LVIF_STATE)
{
@@ -6118,19 +6549,19 @@
if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
{
- int i;
+ int precount,topvisible;
TRACE("LVS_OWNERDATA is set!\n");
- if (nItems > infoPtr->hdpaItems->nItemCount)
- {
- for (i = infoPtr->hdpaItems->nItemCount; i<nItems; i++)
- ListView_InsertItemA(hwnd,NULL);
- }
- else
- {
- for (i = nItems; i < infoPtr->hdpaItems->nItemCount; i++)
- ListView_DeleteItem(hwnd,1);
- }
- RedrawWindow(hwnd,0,0,RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
+
+ precount = infoPtr->hdpaItems->nItemCount;
+ topvisible = ListView_GetTopIndex(hwnd) +
+ LISTVIEW_GetCountPerColumn(hwnd) + 1;
+
+ infoPtr->hdpaItems->nItemCount = nItems;
+
+ LISTVIEW_UpdateSize(hwnd);
+ LISTVIEW_UpdateScroll(hwnd);
+ if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
+ InvalidateRect(hwnd, NULL, TRUE);
}
else
{
@@ -6410,12 +6841,12 @@
HDPA sortList;
UINT lStyle = GetWindowLongA(hwnd, GWL_STYLE);
+ if (lStyle & LVS_OWNERDATA)
+ return FALSE;
+
if (!infoPtr || !infoPtr->hdpaItems)
return FALSE;
- if (lStyle & LVS_OWNERDATA)
- return FALSE;
-
nCount = GETITEMCOUNT(infoPtr);
/* if there are 0 or 1 items, there is no need to sort */
if (nCount > 1)
@@ -6593,6 +7024,9 @@
/* allocate memory for the data structure */
infoPtr->hdpaItems = DPA_Create(10);
+ /* allocate memory for the selection ranges */
+ infoPtr->hdpaSelectionRanges = DPA_Create(10);
+
/* initialize size of items */
infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
@@ -7169,7 +7603,7 @@
else
{
/* remove all selections */
- LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
+ LISTVIEW_RemoveAllSelections(hwnd);
}
InvalidateRect(hwnd, NULL, TRUE);
@@ -7286,6 +7720,7 @@
/* destroy data structure */
DPA_Destroy(infoPtr->hdpaItems);
+ DPA_Destroy(infoPtr->hdpaSelectionRanges);
/* destroy font */
infoPtr->hFont = (HFONT)0;
@@ -7507,7 +7942,7 @@
}
else
{
- LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
+ LISTVIEW_RemoveAllSelections(hwnd);
}
return 0;
diff --git a/include/listview.h b/include/listview.h
index 36be26f..09572a8 100644
--- a/include/listview.h
+++ b/include/listview.h
@@ -40,6 +40,11 @@
} LISTVIEW_ITEM;
+typedef struct tagLISTVIEW_SELECTION
+{
+ DWORD lower;
+ DWORD upper;
+} LISTVIEW_SELECTION;
typedef struct tagLISTVIEW_INFO
{
@@ -52,6 +57,7 @@
BOOL bLButtonDown;
BOOL bRButtonDown;
INT nFocusedItem;
+ HDPA hdpaSelectionRanges;
INT nItemHeight;
INT nItemWidth;
INT nSelectionMark;