This one should not affect functionality; it's just cleanup. Ranges will be useful as separate entities, they don't have to be tied to selection ranges only. ChangeLog Separate range manipulation functions from selection ranges. --- dlls/comctl32/listview.c.M8 Tue Oct 8 20:49:21 2002 +++ dlls/comctl32/listview.c Tue Oct 8 21:31:10 2002 @@ -1825,34 +1825,38 @@ } #if 0 -static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr) +static void ranges_dump(HDPA ranges) { INT i; 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); } } +static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr) +{ + ranges_dump(infoPtr->hdpaSelectionRanges); +} #endif /*** * DESCRIPTION: - * A compare function for selection ranges + * A compare function for ranges * - *PARAMETER(S) - * [I] range1 : pointer to selection range 1; - * [I] range2 : pointer to selection range 2; + * PARAMETER(S) + * [I] range1 : pointer to range 1; + * [I] range2 : pointer to range 2; * [I] flags : flags * - *RETURNS: + * RETURNS: * >0 : if Item 1 > Item 2 * <0 : if Item 2 > Item 1 * 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) return -1; @@ -1861,66 +1865,88 @@ return 0; } -/*** - * Helper function for LISTVIEW_AddSelectionRange, and LISTVIEW_SetItem. - */ -static BOOL add_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only) +static inline BOOL ranges_contain(HDPA ranges, INT nItem) { - RANGE selection; - LVITEMW lvItem; - INT index, i; + RANGE srchrng = { nItem, nItem }; + + 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); - /* try find overlapping selections first */ - selection.lower = lower - 1; - selection.upper = upper + 1; - index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0, - LISTVIEW_CompareSelectionRanges, 0, 0); + /* try find overlapping regions first */ + srchrgn.lower = lower - 1; + srchrgn.upper = upper + 1; + index = DPA_Search(ranges, &srchrgn, 0, ranges_cmp, 0, 0); if (index == -1) { - RANGE *newsel; + RANGE *newrgn; - /* create the brand new selection to insert */ - newsel = (RANGE *)COMCTL32_Alloc(sizeof(RANGE)); - if(!newsel) return FALSE; - newsel->lower = lower; - newsel->upper = upper; + /* create the brand new range to insert */ + newrgn = (RANGE *)COMCTL32_Alloc(sizeof(RANGE)); + if(!newrgn) return FALSE; + newrgn->lower = lower; + newrgn->upper = upper; /* figure out where to insert it */ - index = DPA_Search(infoPtr->hdpaSelectionRanges, newsel, 0, - LISTVIEW_CompareSelectionRanges, 0, DPAS_INSERTAFTER); + index = DPA_Search(ranges, newrgn, 0, ranges_cmp, 0, DPAS_INSERTAFTER); if (index == -1) index = 0; /* and get it over with */ - DPA_InsertPtr(infoPtr->hdpaSelectionRanges, index, newsel); + DPA_InsertPtr(ranges, index, newrgn); } else { - RANGE *chksel, *mrgsel; + RANGE *chkrgn, *mrgrgn; INT fromindex, mergeindex; - chksel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, index); - if (!chksel) return FALSE; + chkrgn = DPA_GetPtr(ranges, index); + if (!chkrgn) return FALSE; TRACE("Merge with index %i (%d - %d)\n", - index, chksel->lower, chksel->upper); + index, chkrgn->lower, chkrgn->upper); - chksel->lower = min(lower, chksel->lower); - chksel->upper = max(upper, chksel->upper); + chkrgn->lower = min(lower, chkrgn->lower); + chkrgn->upper = max(upper, chkrgn->upper); 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; - selection.lower = chksel->lower - 1; - selection.upper = chksel->upper + 1; + srchrgn.lower = chkrgn->lower - 1; + srchrgn.upper = chkrgn->upper + 1; do { - mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, fromindex, - LISTVIEW_CompareSelectionRanges, 0, 0); + mergeindex = DPA_Search(ranges, &srchrgn, fromindex, ranges_cmp, 0, 0); if (mergeindex == -1) break; if (mergeindex == index) { @@ -1930,111 +1956,124 @@ TRACE("Merge with index %i\n", mergeindex); - mrgsel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, mergeindex); - if (!mrgsel) return FALSE; + mrgrgn = DPA_GetPtr(ranges, mergeindex); + if (!mrgrgn) return FALSE; - chksel->lower = min(chksel->lower, mrgsel->lower); - chksel->upper = max(chksel->upper, mrgsel->upper); - COMCTL32_Free(mrgsel); - DPA_DeletePtr(infoPtr->hdpaSelectionRanges, mergeindex); + chkrgn->lower = min(chkrgn->lower, mrgrgn->lower); + chkrgn->upper = max(chkrgn->upper, mrgrgn->upper); + COMCTL32_Free(mrgrgn); + DPA_DeletePtr(ranges, mergeindex); if (mergeindex < index) index --; } while(1); } - /*DPA_Sort(infoPtr->hdpaSelectionRanges, LISTVIEW_CompareSelectionRanges, 0);*/ - - if (adj_sel_only) return TRUE; - - /* set the selection on items */ - lvItem.state = LVIS_SELECTED; - lvItem.stateMask = LVIS_SELECTED; - for(i = lower; i <= upper; i++) - LISTVIEW_SetItemState(infoPtr, i, &lvItem); - return TRUE; } - -/*** - * Helper function for LISTVIEW_RemoveSelectionRange, and LISTVIEW_SetItem. - */ -static BOOL remove_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only) + +static BOOL ranges_del(HDPA ranges, INT lower, INT upper) { - RANGE remsel, tmpsel, *chksel; + RANGE remrgn, tmprgn, *chkrgn; BOOL done = FALSE; - LVITEMW lvItem; - INT index, i; + INT index; - lvItem.state = 0; - lvItem.stateMask = LVIS_SELECTED; - - remsel.lower = lower; - remsel.upper = upper; + remrgn.lower = lower; + remrgn.upper = upper; - TRACE("range: (%d - %d)\n", remsel.lower, remsel.upper); + TRACE("range: (%d - %d)\n", remrgn.lower, remrgn.upper); do { - index = DPA_Search(infoPtr->hdpaSelectionRanges, &remsel, 0, - LISTVIEW_CompareSelectionRanges, 0, 0); + index = DPA_Search(ranges, &remrgn, 0, ranges_cmp, 0, 0); if (index == -1) return TRUE; - chksel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, index); - if (!chksel) return FALSE; + chkrgn = DPA_GetPtr(ranges, index); + if (!chkrgn) return FALSE; TRACE("Matches range index %i (%d - %d)\n", - index, chksel->lower, chksel->upper); + index, chkrgn->lower, chkrgn->upper); /* case 1: Same range */ - if ( (chksel->upper == remsel.upper) && - (chksel->lower == remsel.lower) ) + if ( (chkrgn->upper == remrgn.upper) && + (chkrgn->lower == remrgn.lower) ) { - DPA_DeletePtr(infoPtr->hdpaSelectionRanges, index); + DPA_DeletePtr(ranges, index); done = TRUE; } /* case 2: engulf */ - else if ( (chksel->upper <= remsel.upper) && - (chksel->lower >= remsel.lower) ) + else if ( (chkrgn->upper <= remrgn.upper) && + (chkrgn->lower >= remrgn.lower) ) { - DPA_DeletePtr(infoPtr->hdpaSelectionRanges, index); + DPA_DeletePtr(ranges, index); } /* case 3: overlap upper */ - else if ( (chksel->upper < remsel.upper) && - (chksel->lower < remsel.lower) ) + else if ( (chkrgn->upper < remrgn.upper) && + (chkrgn->lower < remrgn.lower) ) { - chksel->upper = remsel.lower - 1; + chkrgn->upper = remrgn.lower - 1; } /* case 4: overlap lower */ - else if ( (chksel->upper > remsel.upper) && - (chksel->lower > remsel.lower) ) + else if ( (chkrgn->upper > remrgn.upper) && + (chkrgn->lower > remrgn.lower) ) { - chksel->lower = remsel.upper + 1; + chkrgn->lower = remrgn.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; + 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; } - - 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; } +/*** + * Helper function for LISTVIEW_RemoveSelectionRange, and LISTVIEW_SetItem. + */ +static BOOL remove_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only) +{ + LVITEMW lvItem; + 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.stateMask = LVIS_SELECTED; + for(i = lower; i <= upper; i++) + LISTVIEW_SetItemState(infoPtr, i, &lvItem); + + return TRUE; +} +/*** + * 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; + + if (!ranges_add(infoPtr->hdpaSelectionRanges, lower, upper)) return FALSE; + if (adj_sel_only) return TRUE; + + /* set the selection on items */ + lvItem.state = LVIS_SELECTED; + lvItem.stateMask = LVIS_SELECTED; + for(i = lower; i <= upper; i++) + LISTVIEW_SetItemState(infoPtr, i, &lvItem); + + return TRUE; +} + /** * DESCRIPTION: * Adds a selection range. @@ -2178,29 +2217,9 @@ */ static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction) { - RANGE selection,*checkselection; - INT index; - - TRACE("Shifting %iu, %i steps\n",nItem,direction); + TRACE("Shifting %iu, %i steps\n", 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 ++; - } + ranges_shift(infoPtr->hdpaSelectionRanges, nItem, direction); /* Note that the following will fail if direction != +1 and -1 */ if (infoPtr->nSelectionMark > nItem) @@ -4750,18 +4769,6 @@ /* 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: * Retrieves item attributes. * @@ -4863,7 +4870,7 @@ if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) { lpLVItem->state &= ~LVIS_SELECTED; - if (is_item_selected(infoPtr, lpLVItem->iItem)) + if (ranges_contain(infoPtr->hdpaSelectionRanges, lpLVItem->iItem)) lpLVItem->state |= LVIS_SELECTED; } @@ -4972,7 +4979,7 @@ if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) { lpLVItem->state &= ~LVIS_SELECTED; - if (is_item_selected(infoPtr, lpLVItem->iItem)) + if (ranges_contain(infoPtr->hdpaSelectionRanges, lpLVItem->iItem)) lpLVItem->state |= LVIS_SELECTED; } }