Separate range manipulation functions from selection ranges.

This commit is contained in:
Dimitrie O. Paun 2002-10-10 03:05:28 +00:00 committed by Alexandre Julliard
parent 764607d931
commit 00e3435f54
1 changed files with 173 additions and 166 deletions

View File

@ -1825,34 +1825,38 @@ static INT LISTVIEW_GetItemHeight(LISTVIEW_INFO *infoPtr)
} }
#if 0 #if 0
static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr) static void ranges_dump(HDPA ranges)
{ {
INT i; INT i;
ERR("Selections are:\n"); ERR("Selections are:\n");
for (i = 0; i < infoPtr->hdpaSelectionRanges->nItemCount; i++) for (i = 0; i < ranges->nItemCount; i++)
{ {
RANGE *selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges, i); RANGE *selection = DPA_GetPtr(ranges, i);
ERR(" [%d - %d]\n", selection->lower, selection->upper); ERR(" [%d - %d]\n", selection->lower, selection->upper);
} }
} }
static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr)
{
ranges_dump(infoPtr->hdpaSelectionRanges);
}
#endif #endif
/*** /***
* DESCRIPTION: * DESCRIPTION:
* A compare function for selection ranges * A compare function for ranges
* *
*PARAMETER(S) * PARAMETER(S)
* [I] range1 : pointer to selection range 1; * [I] range1 : pointer to range 1;
* [I] range2 : pointer to selection range 2; * [I] range2 : pointer to range 2;
* [I] flags : flags * [I] flags : flags
* *
*RETURNS: * RETURNS:
* >0 : if Item 1 > Item 2 * >0 : if Item 1 > Item 2
* <0 : if Item 2 > Item 1 * <0 : if Item 2 > Item 1
* 0 : if Item 1 == Item 2 * 0 : if Item 1 == Item 2
*/ */
static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2, LPARAM flags) static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags)
{ {
if (((RANGE*)range1)->upper < ((RANGE*)range2)->lower) if (((RANGE*)range1)->upper < ((RANGE*)range2)->lower)
return -1; return -1;
@ -1861,66 +1865,88 @@ static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2
return 0; return 0;
} }
/*** static inline BOOL ranges_contain(HDPA ranges, INT nItem)
* Helper function for LISTVIEW_AddSelectionRange, and LISTVIEW_SetItem.
*/
static BOOL add_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only)
{ {
RANGE selection; RANGE srchrng = { nItem, nItem };
LVITEMW lvItem;
INT index, i; return DPA_Search(ranges, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED) != -1;
}
static BOOL ranges_shift(HDPA ranges, INT nItem, INT delta)
{
RANGE srchrng, *chkrng;
INT index;
srchrng.upper = nItem;
srchrng.lower = nItem;
index = DPA_Search(ranges, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER);
if (index == -1) return TRUE;
for (;index < ranges->nItemCount; index++)
{
chkrng = DPA_GetPtr(ranges, index);
if (chkrng->lower >= nItem && chkrng->lower + delta >= 0)
chkrng->lower += delta;
if (chkrng->upper >= nItem && chkrng->upper + delta >= 0)
chkrng->upper += delta;
}
return TRUE;
}
static BOOL ranges_add(HDPA ranges, INT lower, INT upper)
{
RANGE srchrgn;
INT index;
TRACE("range (%i - %i)\n", lower, upper); TRACE("range (%i - %i)\n", lower, upper);
/* try find overlapping selections first */ /* try find overlapping regions first */
selection.lower = lower - 1; srchrgn.lower = lower - 1;
selection.upper = upper + 1; srchrgn.upper = upper + 1;
index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0, index = DPA_Search(ranges, &srchrgn, 0, ranges_cmp, 0, 0);
LISTVIEW_CompareSelectionRanges, 0, 0);
if (index == -1) if (index == -1)
{ {
RANGE *newsel; RANGE *newrgn;
/* create the brand new selection to insert */ /* create the brand new range to insert */
newsel = (RANGE *)COMCTL32_Alloc(sizeof(RANGE)); newrgn = (RANGE *)COMCTL32_Alloc(sizeof(RANGE));
if(!newsel) return FALSE; if(!newrgn) return FALSE;
newsel->lower = lower; newrgn->lower = lower;
newsel->upper = upper; newrgn->upper = upper;
/* figure out where to insert it */ /* figure out where to insert it */
index = DPA_Search(infoPtr->hdpaSelectionRanges, newsel, 0, index = DPA_Search(ranges, newrgn, 0, ranges_cmp, 0, DPAS_INSERTAFTER);
LISTVIEW_CompareSelectionRanges, 0, DPAS_INSERTAFTER);
if (index == -1) index = 0; if (index == -1) index = 0;
/* and get it over with */ /* and get it over with */
DPA_InsertPtr(infoPtr->hdpaSelectionRanges, index, newsel); DPA_InsertPtr(ranges, index, newrgn);
} }
else else
{ {
RANGE *chksel, *mrgsel; RANGE *chkrgn, *mrgrgn;
INT fromindex, mergeindex; INT fromindex, mergeindex;
chksel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, index); chkrgn = DPA_GetPtr(ranges, index);
if (!chksel) return FALSE; if (!chkrgn) return FALSE;
TRACE("Merge with index %i (%d - %d)\n", TRACE("Merge with index %i (%d - %d)\n",
index, chksel->lower, chksel->upper); index, chkrgn->lower, chkrgn->upper);
chksel->lower = min(lower, chksel->lower); chkrgn->lower = min(lower, chkrgn->lower);
chksel->upper = max(upper, chksel->upper); chkrgn->upper = max(upper, chkrgn->upper);
TRACE("New range %i (%d - %d)\n", TRACE("New range %i (%d - %d)\n",
index, chksel->lower, chksel->upper); index, chkrgn->lower, chkrgn->upper);
/* merge now common selection ranges */ /* merge now common anges */
fromindex = 0; fromindex = 0;
selection.lower = chksel->lower - 1; srchrgn.lower = chkrgn->lower - 1;
selection.upper = chksel->upper + 1; srchrgn.upper = chkrgn->upper + 1;
do do
{ {
mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, fromindex, mergeindex = DPA_Search(ranges, &srchrgn, fromindex, ranges_cmp, 0, 0);
LISTVIEW_CompareSelectionRanges, 0, 0);
if (mergeindex == -1) break; if (mergeindex == -1) break;
if (mergeindex == index) if (mergeindex == index)
{ {
@ -1930,26 +1956,81 @@ static BOOL add_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BO
TRACE("Merge with index %i\n", mergeindex); TRACE("Merge with index %i\n", mergeindex);
mrgsel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, mergeindex); mrgrgn = DPA_GetPtr(ranges, mergeindex);
if (!mrgsel) return FALSE; if (!mrgrgn) return FALSE;
chksel->lower = min(chksel->lower, mrgsel->lower); chkrgn->lower = min(chkrgn->lower, mrgrgn->lower);
chksel->upper = max(chksel->upper, mrgsel->upper); chkrgn->upper = max(chkrgn->upper, mrgrgn->upper);
COMCTL32_Free(mrgsel); COMCTL32_Free(mrgrgn);
DPA_DeletePtr(infoPtr->hdpaSelectionRanges, mergeindex); DPA_DeletePtr(ranges, mergeindex);
if (mergeindex < index) index --; if (mergeindex < index) index --;
} while(1); } while(1);
} }
/*DPA_Sort(infoPtr->hdpaSelectionRanges, LISTVIEW_CompareSelectionRanges, 0);*/ return TRUE;
}
if (adj_sel_only) return TRUE; static BOOL ranges_del(HDPA ranges, INT lower, INT upper)
{
RANGE remrgn, tmprgn, *chkrgn;
BOOL done = FALSE;
INT index;
/* set the selection on items */ remrgn.lower = lower;
lvItem.state = LVIS_SELECTED; remrgn.upper = upper;
lvItem.stateMask = LVIS_SELECTED;
for(i = lower; i <= upper; i++) TRACE("range: (%d - %d)\n", remrgn.lower, remrgn.upper);
LISTVIEW_SetItemState(infoPtr, i, &lvItem);
do
{
index = DPA_Search(ranges, &remrgn, 0, ranges_cmp, 0, 0);
if (index == -1) return TRUE;
chkrgn = DPA_GetPtr(ranges, index);
if (!chkrgn) return FALSE;
TRACE("Matches range index %i (%d - %d)\n",
index, chkrgn->lower, chkrgn->upper);
/* case 1: Same range */
if ( (chkrgn->upper == remrgn.upper) &&
(chkrgn->lower == remrgn.lower) )
{
DPA_DeletePtr(ranges, index);
done = TRUE;
}
/* case 2: engulf */
else if ( (chkrgn->upper <= remrgn.upper) &&
(chkrgn->lower >= remrgn.lower) )
{
DPA_DeletePtr(ranges, index);
}
/* case 3: overlap upper */
else if ( (chkrgn->upper < remrgn.upper) &&
(chkrgn->lower < remrgn.lower) )
{
chkrgn->upper = remrgn.lower - 1;
}
/* case 4: overlap lower */
else if ( (chkrgn->upper > remrgn.upper) &&
(chkrgn->lower > remrgn.lower) )
{
chkrgn->lower = remrgn.upper + 1;
}
/* case 5: fully internal */
else
{
RANGE *newrgn = (RANGE *)COMCTL32_Alloc(sizeof(RANGE));
if (!newrgn) return FALSE;
tmprgn = *chkrgn;
newrgn->lower = chkrgn->lower;
newrgn->upper = remrgn.lower - 1;
chkrgn->lower = remrgn.upper + 1;
DPA_InsertPtr(ranges, index, newrgn);
chkrgn = &tmprgn;
}
}
while(!done);
return TRUE; return TRUE;
} }
@ -1959,78 +2040,36 @@ static BOOL add_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BO
*/ */
static BOOL remove_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only) static BOOL remove_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only)
{ {
RANGE remsel, tmpsel, *chksel;
BOOL done = FALSE;
LVITEMW lvItem; LVITEMW lvItem;
INT index, i; INT i;
if (!ranges_del(infoPtr->hdpaSelectionRanges, lower, upper)) return FALSE;
if (adj_sel_only) return TRUE;
/* reset the selection on items */
lvItem.state = 0; lvItem.state = 0;
lvItem.stateMask = LVIS_SELECTED; lvItem.stateMask = LVIS_SELECTED;
for(i = lower; i <= upper; i++)
LISTVIEW_SetItemState(infoPtr, i, &lvItem);
remsel.lower = lower; return TRUE;
remsel.upper = upper; }
/***
* Helper function for LISTVIEW_AddSelectionRange, and LISTVIEW_SetItem.
*/
static BOOL add_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only)
{
LVITEMW lvItem;
INT i;
TRACE("range: (%d - %d)\n", remsel.lower, remsel.upper); if (!ranges_add(infoPtr->hdpaSelectionRanges, lower, upper)) return FALSE;
if (adj_sel_only) return TRUE;
do /* set the selection on items */
{ lvItem.state = LVIS_SELECTED;
index = DPA_Search(infoPtr->hdpaSelectionRanges, &remsel, 0, lvItem.stateMask = LVIS_SELECTED;
LISTVIEW_CompareSelectionRanges, 0, 0); for(i = lower; i <= upper; i++)
if (index == -1) return TRUE; LISTVIEW_SetItemState(infoPtr, i, &lvItem);
chksel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, index);
if (!chksel) return FALSE;
TRACE("Matches range index %i (%d - %d)\n",
index, chksel->lower, chksel->upper);
/* case 1: Same range */
if ( (chksel->upper == remsel.upper) &&
(chksel->lower == remsel.lower) )
{
DPA_DeletePtr(infoPtr->hdpaSelectionRanges, index);
done = TRUE;
}
/* case 2: engulf */
else if ( (chksel->upper <= remsel.upper) &&
(chksel->lower >= remsel.lower) )
{
DPA_DeletePtr(infoPtr->hdpaSelectionRanges, index);
}
/* case 3: overlap upper */
else if ( (chksel->upper < remsel.upper) &&
(chksel->lower < remsel.lower) )
{
chksel->upper = remsel.lower - 1;
}
/* case 4: overlap lower */
else if ( (chksel->upper > remsel.upper) &&
(chksel->lower > remsel.lower) )
{
chksel->lower = remsel.upper + 1;
}
/* case 5: fully internal */
else
{
RANGE *newsel =
(RANGE *)COMCTL32_Alloc(sizeof(RANGE));
if (!newsel) return FALSE;
tmpsel = *chksel;
newsel->lower = chksel->lower;
newsel->upper = remsel.lower - 1;
chksel->lower = remsel.upper + 1;
DPA_InsertPtr(infoPtr->hdpaSelectionRanges, index, newsel);
/*DPA_Sort(infoPtr->hdpaSelectionRanges, LISTVIEW_CompareSelectionRanges, 0);*/
chksel = &tmpsel;
}
if (adj_sel_only) continue;
/* here, chksel holds the selection to delete */
for (i = chksel->lower; i <= chksel->upper; i++)
LISTVIEW_SetItemState(infoPtr, i, &lvItem);
}
while(!done);
return TRUE; return TRUE;
} }
@ -2178,29 +2217,9 @@ static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
*/ */
static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction) static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
{ {
RANGE selection,*checkselection; TRACE("Shifting %iu, %i steps\n", nItem, direction);
INT index;
TRACE("Shifting %iu, %i steps\n",nItem,direction); ranges_shift(infoPtr->hdpaSelectionRanges, nItem, direction);
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)&&
((int)(checkselection->lower + direction) >= 0))
checkselection->lower += direction;
if ((checkselection->upper >= nItem)&&
((int)(checkselection->upper + direction) >= 0))
checkselection->upper += direction;
index ++;
}
/* Note that the following will fail if direction != +1 and -1 */ /* Note that the following will fail if direction != +1 and -1 */
if (infoPtr->nSelectionMark > nItem) if (infoPtr->nSelectionMark > nItem)
@ -4749,18 +4768,6 @@ static LRESULT LISTVIEW_GetImageList(LISTVIEW_INFO *infoPtr, INT nImageList)
/* LISTVIEW_GetISearchString */ /* LISTVIEW_GetISearchString */
/***
* Helper function for LISTVIEW_GetItemT *only*. Tests if an item is selected.
* It is important that no other functions call this because of callbacks.
*/
static inline BOOL is_item_selected(LISTVIEW_INFO *infoPtr, INT nItem)
{
RANGE selection = { nItem, nItem };
return DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
LISTVIEW_CompareSelectionRanges, 0, DPAS_SORTED) != -1;
}
/*** /***
* DESCRIPTION: * DESCRIPTION:
* Retrieves item attributes. * Retrieves item attributes.
@ -4863,7 +4870,7 @@ static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
{ {
lpLVItem->state &= ~LVIS_SELECTED; lpLVItem->state &= ~LVIS_SELECTED;
if (is_item_selected(infoPtr, lpLVItem->iItem)) if (ranges_contain(infoPtr->hdpaSelectionRanges, lpLVItem->iItem))
lpLVItem->state |= LVIS_SELECTED; lpLVItem->state |= LVIS_SELECTED;
} }
@ -4972,7 +4979,7 @@ static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED )
{ {
lpLVItem->state &= ~LVIS_SELECTED; lpLVItem->state &= ~LVIS_SELECTED;
if (is_item_selected(infoPtr, lpLVItem->iItem)) if (ranges_contain(infoPtr->hdpaSelectionRanges, lpLVItem->iItem))
lpLVItem->state |= LVIS_SELECTED; lpLVItem->state |= LVIS_SELECTED;
} }
} }