[PATCH] Rework item selection with letter keys, fix some glitches
Nikolay Sivov
nsivov at codeweavers.com
Sat Apr 24 10:19:40 CDT 2010
---
dlls/comctl32/listview.c | 147 +++++++++++++++++++++++++---------------------
1 files changed, 80 insertions(+), 67 deletions(-)
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index 09c731a..5757c9f 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -1751,14 +1751,15 @@ static inline INT LISTVIEW_GetCountPerColumn(const LISTVIEW_INFO *infoPtr)
*/
static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
{
- INT nItem;
- INT endidx,idx;
- LVITEMW item;
WCHAR buffer[MAX_PATH];
- DWORD lastKeyPressTimestamp = infoPtr->lastKeyPressTimestamp;
+ INT endidx, startidx;
+ DWORD prevTime;
+ LVITEMW item;
+ INT nItem;
+ INT diff;
/* simple parameter checking */
- if (!charCode || !keyData) return 0;
+ if (!charCode || !keyData || infoPtr->nItemCount == 0) return 0;
/* only allow the valid WM_CHARs through */
if (!isalnumW(charCode) &&
@@ -1773,86 +1774,98 @@ static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, L
charCode != '<' && charCode != ',' && charCode != '~')
return 0;
- /* if there's one item or less, there is no where to go */
- if (infoPtr->nItemCount <= 1) return 0;
-
/* update the search parameters */
+ prevTime = infoPtr->lastKeyPressTimestamp;
infoPtr->lastKeyPressTimestamp = GetTickCount();
- if (infoPtr->lastKeyPressTimestamp - lastKeyPressTimestamp < KEY_DELAY) {
- if (infoPtr->nSearchParamLength < MAX_PATH-1)
- infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode;
+ diff = infoPtr->lastKeyPressTimestamp - prevTime;
+
+ /* handle overflow */
+ if (diff < 0) diff += 0xffffffff;
+
+ if (diff < KEY_DELAY)
+ {
+ if (infoPtr->nSearchParamLength < MAX_PATH - 1)
+ infoPtr->szSearchParam[infoPtr->nSearchParamLength++] = charCode;
+
if (infoPtr->charCode != charCode)
infoPtr->charCode = charCode = 0;
- } else {
- infoPtr->charCode=charCode;
- infoPtr->szSearchParam[0]=charCode;
- infoPtr->nSearchParamLength=1;
- /* Redundant with the 1 char string */
- charCode=0;
+ }
+ else
+ {
+ infoPtr->charCode = charCode;
+ infoPtr->szSearchParam[0] = charCode;
+ infoPtr->nSearchParamLength = 1;
+ /* redundant with the 1 char string */
+ charCode = 0;
}
/* and search from the current position */
- nItem=-1;
- if (infoPtr->nFocusedItem >= 0) {
- endidx=infoPtr->nFocusedItem;
- idx=endidx;
- /* if looking for single character match,
- * then we must always move forward
- */
- if (infoPtr->nSearchParamLength == 1)
- idx++;
- } else {
- endidx=infoPtr->nItemCount;
- idx=0;
- }
+ nItem = -1;
+ endidx = infoPtr->nItemCount;
+
+ /* should start from next after focused item, so next item that matches
+ will be selected, if there isn't any and focused matches it will be selected
+ on second search stage from beginning of the list */
+ if (infoPtr->nFocusedItem >= 0 && infoPtr->nItemCount > 1)
+ startidx = infoPtr->nFocusedItem + 1;
+ else
+ startidx = 0;
- /* Let application handle this for virtual listview */
+ /* let application handle this for virtual listview */
if (infoPtr->dwStyle & LVS_OWNERDATA)
{
NMLVFINDITEMW nmlv;
- LVFINDINFOW lvfi;
- ZeroMemory(&lvfi, sizeof(lvfi));
- lvfi.flags = (LVFI_WRAP | LVFI_PARTIAL);
- infoPtr->szSearchParam[infoPtr->nSearchParamLength] = '\0';
- lvfi.psz = infoPtr->szSearchParam;
- nmlv.iStart = idx;
- nmlv.lvfi = lvfi;
+ memset(&nmlv.lvfi, 0, sizeof(nmlv.lvfi));
+ nmlv.lvfi.flags = (LVFI_WRAP | LVFI_PARTIAL);
+ nmlv.lvfi.psz = infoPtr->szSearchParam;
+ nmlv.iStart = startidx;
+
+ infoPtr->szSearchParam[infoPtr->nSearchParamLength] = 0;
nItem = notify_hdr(infoPtr, LVN_ODFINDITEMW, (LPNMHDR)&nmlv.hdr);
+ }
+ else
+ {
+ INT i = startidx;
- if (nItem != -1)
- LISTVIEW_KeySelection(infoPtr, nItem, FALSE);
+ /* first search in [startidx, endidx), on failure continue in [0, startidx) */
+ while (1)
+ {
+ /* start from first item if not found with >= startidx */
+ if (i == infoPtr->nItemCount && startidx > 0)
+ {
+ endidx = startidx;
+ startidx = 0;
+ }
- return 0;
- }
+ for (i = startidx; i < endidx; i++)
+ {
+ /* retrieve text */
+ item.mask = LVIF_TEXT;
+ item.iItem = i;
+ item.iSubItem = 0;
+ item.pszText = buffer;
+ item.cchTextMax = MAX_PATH;
+ if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
+
+ if (lstrncmpiW(item.pszText, infoPtr->szSearchParam, infoPtr->nSearchParamLength) == 0)
+ {
+ nItem = i;
+ break;
+ }
+ else if (nItem == -1 && lstrncmpiW(item.pszText, infoPtr->szSearchParam, 1) == 0)
+ {
+ /* this would work but we must keep looking for a longer match */
+ nItem = i;
+ }
+ }
- do {
- if (idx == infoPtr->nItemCount) {
- if (endidx == infoPtr->nItemCount || endidx == 0)
+ /* found something or second search completed with any result */
+ if (nItem != -1 || endidx != infoPtr->nItemCount)
break;
- idx=0;
- }
-
- /* get item */
- item.mask = LVIF_TEXT;
- item.iItem = idx;
- item.iSubItem = 0;
- item.pszText = buffer;
- item.cchTextMax = MAX_PATH;
- if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0;
-
- /* check for a match */
- if (lstrncmpiW(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) {
- nItem=idx;
- break;
- } else if ( (charCode != 0) && (nItem == -1) && (nItem != infoPtr->nFocusedItem) &&
- (lstrncmpiW(item.pszText,infoPtr->szSearchParam,1) == 0) ) {
- /* This would work but we must keep looking for a longer match */
- nItem=idx;
- }
- idx++;
- } while (idx != endidx);
+ };
+ }
if (nItem != -1)
LISTVIEW_KeySelection(infoPtr, nItem, FALSE);
--
1.5.6.5
--=-kq4h8ZCUQPSXMkoGJyhN--
More information about the wine-patches
mailing list