Instrument SetItemT to avoid repainting if nothing changed.

Teach RemoveAllSelections to skip an item, so we can eliminate the
flicker when we click on a selected item.
This commit is contained in:
Dimitrie O. Paun 2002-10-16 19:04:07 +00:00 committed by Alexandre Julliard
parent 3c9591b413
commit 8d2f7224f1
1 changed files with 37 additions and 44 deletions

View File

@ -2365,12 +2365,13 @@ static BOOL ranges_del(HDPA ranges, RANGE range)
* *
* Parameters(s): * Parameters(s):
* [I] infoPtr : valid pointer to the listview structure * [I] infoPtr : valid pointer to the listview structure
* [I] nSkipItem : item to skip removing the selection
* *
* RETURNS: * RETURNS:
* SUCCESS : TRUE * SUCCESS : TRUE
* FAILURE : TRUE * FAILURE : TRUE
*/ */
static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr) static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr, INT nSkipItem)
{ {
LVITEMW lvItem; LVITEMW lvItem;
RANGE *sel; RANGE *sel;
@ -2389,8 +2390,10 @@ static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr)
{ {
sel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, 0); sel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, 0);
if (!sel) continue; if (!sel) continue;
if (infoPtr->hdpaSelectionRanges->nItemCount == 1 &&
sel->lower == nSkipItem && sel->upper == nSkipItem) break;
for(i = sel->lower; i <= sel->upper; i++) for(i = sel->lower; i <= sel->upper; i++)
LISTVIEW_SetItemState(infoPtr, i, &lvItem); if (i != nSkipItem) LISTVIEW_SetItemState(infoPtr, i, &lvItem);
} }
while (infoPtr->hdpaSelectionRanges->nItemCount > 0); while (infoPtr->hdpaSelectionRanges->nItemCount > 0);
@ -2558,7 +2561,7 @@ static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
POINT ptItem; POINT ptItem;
RECT rcSel; RECT rcSel;
LISTVIEW_RemoveAllSelections(infoPtr); LISTVIEW_RemoveAllSelections(infoPtr, -1);
item.state = LVIS_SELECTED; item.state = LVIS_SELECTED;
item.stateMask = LVIS_SELECTED; item.stateMask = LVIS_SELECTED;
@ -2617,7 +2620,7 @@ static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
TRACE("nItem=%d\n", nItem); TRACE("nItem=%d\n", nItem);
LISTVIEW_RemoveAllSelections(infoPtr); LISTVIEW_RemoveAllSelections(infoPtr, nItem);
lvItem.state = LVIS_FOCUSED | LVIS_SELECTED; lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED; lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
@ -2764,12 +2767,13 @@ static inline BOOL is_assignable_item(LPLVITEMW lpLVItem, LONG lStyle)
* [I] infoPtr : valid pointer to the listview structure * [I] infoPtr : valid pointer to the listview structure
* [I] lpLVItem : valid pointer to new item atttributes * [I] lpLVItem : valid pointer to new item atttributes
* [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
* [O] bChanged : will be set to TRUE if the item really changed
* *
* RETURN: * RETURN:
* SUCCESS : TRUE * SUCCESS : TRUE
* FAILURE : FALSE * FAILURE : FALSE
*/ */
static BOOL set_owner_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) static BOOL set_owner_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW, BOOL *bChanged)
{ {
LONG lStyle = infoPtr->dwStyle; LONG lStyle = infoPtr->dwStyle;
NMLISTVIEW nmlv; NMLISTVIEW nmlv;
@ -2786,6 +2790,8 @@ static BOOL set_owner_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
if ( !((oldState ^ lpLVItem->state) & lpLVItem->stateMask & if ( !((oldState ^ lpLVItem->state) & lpLVItem->stateMask &
~infoPtr->uCallbackMask & (LVIS_FOCUSED | LVIS_SELECTED))) return TRUE; ~infoPtr->uCallbackMask & (LVIS_FOCUSED | LVIS_SELECTED))) return TRUE;
*bChanged = TRUE;
/* /*
* As per MSDN LVN_ITEMCHANGING notifications are _NOT_ sent for * As per MSDN LVN_ITEMCHANGING notifications are _NOT_ sent for
* by LVS_OWERNDATA list controls * by LVS_OWERNDATA list controls
@ -2807,7 +2813,7 @@ static BOOL set_owner_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
if (lpLVItem->state & LVIS_SELECTED) if (lpLVItem->state & LVIS_SELECTED)
{ {
if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr); if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr, lpLVItem->iItem);
ranges_add(infoPtr->hdpaSelectionRanges, range); ranges_add(infoPtr->hdpaSelectionRanges, range);
} }
else else
@ -2833,18 +2839,19 @@ static BOOL set_owner_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
* [I] infoPtr : valid pointer to the listview structure * [I] infoPtr : valid pointer to the listview structure
* [I] lpLVItem : valid pointer to new item atttributes * [I] lpLVItem : valid pointer to new item atttributes
* [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
* [O] bChanged : will be set to TRUE if the item really changed
* *
* RETURN: * RETURN:
* SUCCESS : TRUE * SUCCESS : TRUE
* FAILURE : FALSE * FAILURE : FALSE
*/ */
static BOOL set_main_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) static BOOL set_main_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW, BOOL *bChanged)
{ {
LONG lStyle = infoPtr->dwStyle; LONG lStyle = infoPtr->dwStyle;
HDPA hdpaSubItems; HDPA hdpaSubItems;
LISTVIEW_ITEM *lpItem; LISTVIEW_ITEM *lpItem;
NMLISTVIEW nmlv; NMLISTVIEW nmlv;
UINT uChanged = 0; UINT uChanged = 0, oldState;
hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
if (!hdpaSubItems && hdpaSubItems != (HDPA)-1) return FALSE; if (!hdpaSubItems && hdpaSubItems != (HDPA)-1) return FALSE;
@ -2853,22 +2860,11 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
if (!lpItem) return FALSE; if (!lpItem) return FALSE;
/* we need to handle the focus, and selection differently */ /* we need to handle the focus, and selection differently */
lpItem->state &= ~(LVIS_FOCUSED | LVIS_SELECTED); oldState = LISTVIEW_GetItemState(infoPtr, lpLVItem->iItem, LVIS_FOCUSED | LVIS_SELECTED);
if (~infoPtr->uCallbackMask & LVIS_FOCUSED)
{
if (lpLVItem->iItem == infoPtr->nFocusedItem)
lpItem->state |= LVIS_FOCUSED;
}
if (~infoPtr->uCallbackMask & LVIS_SELECTED)
{
if (ranges_contain(infoPtr->hdpaSelectionRanges, lpLVItem->iItem))
lpItem->state |= LVIS_SELECTED;
}
TRACE("lpItem->state=0x%x\n", lpItem->state); TRACE("lpItem->state=0x%x\n", lpItem->state);
/* determine what fields will change */ /* determine what fields will change */
if ((lpLVItem->mask & LVIF_STATE) && if ((lpLVItem->mask & LVIF_STATE) && ((oldState ^ lpLVItem->state) & lpLVItem->stateMask & ~infoPtr->uCallbackMask))
((lpItem->state ^ lpLVItem->state) & lpLVItem->stateMask & ~infoPtr->uCallbackMask))
uChanged |= LVIF_STATE; uChanged |= LVIF_STATE;
if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage)) if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage))
@ -2885,6 +2881,7 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
TRACE("uChanged=0x%x\n", uChanged); TRACE("uChanged=0x%x\n", uChanged);
if (!uChanged) return TRUE; if (!uChanged) return TRUE;
*bChanged = TRUE;
ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
nmlv.iItem = lpLVItem->iItem; nmlv.iItem = lpLVItem->iItem;
@ -2918,7 +2915,7 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
lpItem->state |= (lpLVItem->state & lpLVItem->stateMask); lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
if (lpLVItem->state & lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED) if (lpLVItem->state & lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED)
{ {
if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr); if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr, lpLVItem->iItem);
ranges_add(infoPtr->hdpaSelectionRanges, range); ranges_add(infoPtr->hdpaSelectionRanges, range);
} }
else if (lpLVItem->stateMask & LVIS_SELECTED) else if (lpLVItem->stateMask & LVIS_SELECTED)
@ -2955,17 +2952,16 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
* [I] infoPtr : valid pointer to the listview structure * [I] infoPtr : valid pointer to the listview structure
* [I] lpLVItem : valid pointer to new subitem atttributes * [I] lpLVItem : valid pointer to new subitem atttributes
* [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
* [O] bChanged : will be set to TRUE if the item really changed
* *
* RETURN: * RETURN:
* SUCCESS : TRUE * SUCCESS : TRUE
* FAILURE : FALSE * FAILURE : FALSE
*/ */
static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW, BOOL *bChanged)
{ {
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
HDPA hdpaSubItems; HDPA hdpaSubItems;
LISTVIEW_SUBITEM *lpSubItem; LISTVIEW_SUBITEM *lpSubItem;
BOOL bModified = FALSE;
/* set subitem only if column is present */ /* set subitem only if column is present */
if (Header_GetItemCount(infoPtr->hwndHeader) <= lpLVItem->iSubItem) if (Header_GetItemCount(infoPtr->hwndHeader) <= lpLVItem->iSubItem)
@ -2999,26 +2995,23 @@ static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
return FALSE; return FALSE;
} }
lpSubItem->iSubItem = lpLVItem->iSubItem; lpSubItem->iSubItem = lpLVItem->iSubItem;
bModified = TRUE; *bChanged = TRUE;
} }
if (lpLVItem->mask & LVIF_IMAGE) if (lpLVItem->mask & LVIF_IMAGE)
if (lpSubItem->hdr.iImage != lpLVItem->iImage) if (lpSubItem->hdr.iImage != lpLVItem->iImage)
{ {
lpSubItem->hdr.iImage = lpLVItem->iImage; lpSubItem->hdr.iImage = lpLVItem->iImage;
bModified = TRUE; *bChanged = TRUE;
} }
if (lpLVItem->mask & LVIF_TEXT) if (lpLVItem->mask & LVIF_TEXT)
if (lpSubItem->hdr.pszText != lpLVItem->pszText) if (lpSubItem->hdr.pszText != lpLVItem->pszText)
{ {
textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW); textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW);
bModified = TRUE; *bChanged = TRUE;
} }
if (bModified && !infoPtr->bIsDrawing && uView == LVS_REPORT)
LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem);
return TRUE; return TRUE;
} }
@ -3037,9 +3030,10 @@ static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
*/ */
static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
{ {
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
INT nOldFocus = infoPtr->nFocusedItem; INT nOldFocus = infoPtr->nFocusedItem;
LPWSTR pszText = NULL; LPWSTR pszText = NULL;
BOOL bResult; BOOL bResult, bChanged = FALSE;
TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
@ -3055,28 +3049,27 @@ static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
/* actually set the fields */ /* actually set the fields */
if (infoPtr->dwStyle & LVS_OWNERDATA) if (infoPtr->dwStyle & LVS_OWNERDATA)
bResult = set_owner_item(infoPtr, lpLVItem, TRUE); bResult = set_owner_item(infoPtr, lpLVItem, TRUE, &bChanged);
else else
{ {
/* sanity checks first */ /* sanity checks first */
if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return FALSE; if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return FALSE;
if (lpLVItem->iSubItem) if (lpLVItem->iSubItem)
bResult = set_sub_item(infoPtr, lpLVItem, TRUE); bResult = set_sub_item(infoPtr, lpLVItem, TRUE, &bChanged);
else else
bResult = set_main_item(infoPtr, lpLVItem, TRUE); bResult = set_main_item(infoPtr, lpLVItem, TRUE, &bChanged);
} }
/* redraw item, if necessary */ /* redraw item, if necessary */
if (bResult && !infoPtr->bIsDrawing && lpLVItem->iSubItem == 0) if (bChanged && !infoPtr->bIsDrawing)
{ {
if (nOldFocus != infoPtr->nFocusedItem && infoPtr->bFocus) if (nOldFocus != infoPtr->nFocusedItem && infoPtr->bFocus)
LISTVIEW_InvalidateRect(infoPtr, &infoPtr->rcFocus); LISTVIEW_InvalidateRect(infoPtr, &infoPtr->rcFocus);
/* this little optimization eliminates some nasty flicker */ /* this little optimization eliminates some nasty flicker */
if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT && if ( uView == LVS_REPORT && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) &&
!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && (!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || lpLVItem->iSubItem) )
!(infoPtr->dwStyle & LVS_OWNERDRAWFIXED))
LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem); LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem);
else else
LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem); LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem);
@ -3661,7 +3654,7 @@ static LRESULT LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr)
TRACE("()\n"); TRACE("()\n");
LISTVIEW_RemoveAllSelections(infoPtr); LISTVIEW_RemoveAllSelections(infoPtr, -1);
infoPtr->nSelectionMark=-1; infoPtr->nSelectionMark=-1;
infoPtr->nFocusedItem=-1; infoPtr->nFocusedItem=-1;
SetRectEmpty(&infoPtr->rcFocus); SetRectEmpty(&infoPtr->rcFocus);
@ -6454,7 +6447,7 @@ static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFl
: "", : "",
(dwFlags & LVSICF_NOSCROLL) ? "LVSICF_NOSCROLL" : ""); (dwFlags & LVSICF_NOSCROLL) ? "LVSICF_NOSCROLL" : "");
LISTVIEW_RemoveAllSelections(infoPtr); LISTVIEW_RemoveAllSelections(infoPtr, -1);
precount = infoPtr->nItemCount; precount = infoPtr->nItemCount;
topvisible = LISTVIEW_GetTopIndex(infoPtr) + topvisible = LISTVIEW_GetTopIndex(infoPtr) +
@ -7479,7 +7472,7 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
else else
{ {
/* remove all selections */ /* remove all selections */
LISTVIEW_RemoveAllSelections(infoPtr); LISTVIEW_RemoveAllSelections(infoPtr, -1);
} }
return 0; return 0;
@ -7753,7 +7746,7 @@ static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
} }
else else
{ {
LISTVIEW_RemoveAllSelections(infoPtr); LISTVIEW_RemoveAllSelections(infoPtr, -1);
} }
return 0; return 0;