ChangeLog Fix iterators to properly deal with LVS_{,SMALL}ICON modes Unify the Refresh{List,Icon} functions Simplify HitTest to make full use of the iterators Fix selection bounds in HitTest Avoid empty default to silence warning in gcc 3.2. --- dlls/comctl32/listview.c.Q0 Sat Oct 12 11:42:11 2002 +++ dlls/comctl32/listview.c Mon Oct 14 13:55:47 2002 @@ -882,8 +882,8 @@ static BOOL iterator_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT* lprc) { UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT lower, upper; - RECT frame = *lprc; + RECT frame = *lprc, rcItem, rcTemp; + INT lower, upper, nItem; POINT Origin; /* in case we fail, we want to return an empty iterator */ @@ -895,9 +895,25 @@ if (uView == LVS_ICON || uView == LVS_SMALLICON) { - /* FIXME: we got to do better then this */ - i->range.lower = 0; - i->range.upper = infoPtr->nItemCount - 1; + if (uView == LVS_ICON) + { + if (LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem) && IntersectRect(&rcTemp, &rcItem, lprc)) + i->nSpecial = infoPtr->nFocusedItem; + } + if (!(i->ranges = DPA_Create(50))) return FALSE; + /* to do better here, we need to have PosX, and PosY sorted */ + for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) + { + rcItem.left = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); + rcItem.top = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem); + rcItem.right = rcItem.left + infoPtr->nItemWidth; + rcItem.bottom = rcItem.top + infoPtr->nItemHeight; + if (IntersectRect(&rcTemp, &rcItem, &frame)) + { + RANGE item_range = { nItem, nItem }; + ranges_add(i->ranges, item_range); + } + } return TRUE; } else if (uView == LVS_REPORT) @@ -933,37 +949,45 @@ { POINT Origin, Position; RECT rcItem, rcClip; - INT nItem, rgntype; + INT rgntype; rgntype = GetClipBox(hdc, &rcClip); if (rgntype == NULLREGION) return iterator_empty(i); if (!iterator_frameditems(i, infoPtr, &rcClip)) return FALSE; if (rgntype == SIMPLEREGION) return TRUE; + /* first deal with the special item */ + if (LISTVIEW_GetItemBox(infoPtr, i->nSpecial, &rcItem) && !RectVisible(hdc, &rcItem)) + i->nSpecial = -1; + /* if we can't deal with the region, we'll just go with the simple range */ if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return TRUE; - if (!(i->ranges = DPA_Create(10))) return TRUE; - if (!ranges_add(i->ranges, i->range)) + if (!i->ranges) { - DPA_Destroy(i->ranges); - i->ranges = 0; - return TRUE; + if (!(i->ranges = DPA_Create(50))) return TRUE; + if (!ranges_add(i->ranges, i->range)) + { + DPA_Destroy(i->ranges); + i->ranges = 0; + return TRUE; + } } /* now delete the invisible items from the list */ - for (nItem = i->range.lower; nItem <= i->range.upper; nItem++) + while(iterator_next(i)) { - if (!LISTVIEW_GetItemListOrigin(infoPtr, nItem, &Position)) continue; + if (!LISTVIEW_GetItemListOrigin(infoPtr, i->nItem, &Position)) continue; rcItem.left = Position.x + Origin.x; rcItem.top = Position.y + Origin.y; rcItem.right = rcItem.left + infoPtr->nItemWidth; rcItem.bottom = rcItem.top + infoPtr->nItemHeight; if (!RectVisible(hdc, &rcItem)) { - RANGE item_range = { nItem, nItem }; + RANGE item_range = { i->nItem, i->nItem }; ranges_del(i->ranges, item_range); } } + /* the iterator should restart on the next iterator_next */ return TRUE; } @@ -1461,6 +1485,8 @@ { UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; + if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) { lpptPosition->x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); @@ -3538,54 +3564,6 @@ iterator_destroy(&i); } -/*** - * DESCRIPTION: - * Draws listview items when in icon or small icon display mode. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * [I] cdmode : custom draw mode - * - * RETURN: - * None - */ -static void LISTVIEW_RefreshIcon(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode) -{ - POINT Origin, Position; - RECT rcBox; - ITERATOR i; - - /* Get scroll info once before loop */ - if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return; - - /* figure out what we need to draw */ - iterator_visibleitems(&i, infoPtr, hdc); - - while(iterator_prev(&i)) - { - if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_FOCUSED)) - continue; - - if (!LISTVIEW_GetItemListOrigin(infoPtr, i.nItem, &Position)) continue; - Position.x += Origin.x; - Position.y += Origin.y; - LISTVIEW_DrawItem(infoPtr, hdc, i.nItem, Position, cdmode); - } - iterator_destroy(&i); - - /* draw the focused item last, in case it's oversized */ - if (LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox) && - RectVisible(hdc, &rcBox)) - { - if (LISTVIEW_GetItemListOrigin(infoPtr, infoPtr->nFocusedItem, &Position)) - { - Position.x += Origin.x; - Position.y += Origin.y; - LISTVIEW_DrawItem(infoPtr, hdc, infoPtr->nFocusedItem, Position, cdmode); - } - } -} /*** * DESCRIPTION: @@ -3630,11 +3608,9 @@ LISTVIEW_RefreshOwnerDraw(infoPtr, hdc); else { - if (uView == LVS_ICON) - LISTVIEW_RefreshIcon(infoPtr, hdc, cdmode); - else if (uView == LVS_REPORT) + if (uView == LVS_REPORT) LISTVIEW_RefreshReport(infoPtr, hdc, cdmode); - else /* LVS_LIST or LVS_SMALLICON */ + else /* LVS_LIST, LVS_ICON or LVS_SMALLICON */ LISTVIEW_RefreshList(infoPtr, hdc, cdmode); /* if we have a focus rect, draw it */ @@ -4576,6 +4552,7 @@ TRACE("nColumn=%d\n", nColumn); + /* we have a 'column' in LIST and REPORT mode only */ switch(infoPtr->dwStyle & LVS_TYPEMASK) { case LVS_LIST: @@ -4586,8 +4563,6 @@ if (Header_GetItemW(infoPtr->hwndHeader, nColumn, &hdi)) nColumnWidth = hdi.cxy; break; - default: - /* we don't have a 'column' in [SMALL]ICON mode */ } TRACE("nColumnWidth=%d\n", nColumnWidth); @@ -5524,9 +5499,10 @@ { WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - RECT rcBounds, rcState, rcIcon, rcLabel; + RECT rcBounds, rcState, rcIcon, rcLabel, rcSearch; POINT Origin, Position, opt; LVITEMW lvItem; + ITERATOR i; TRACE("(pt=%s, subitem=%d, select=%d)\n", debugpoint(&lpht->pt), subitem, select); @@ -5551,49 +5527,16 @@ if (!LISTVIEW_GetOrigin(infoPtr, &Origin)) return -1; /* first deal with the large items */ - if (uView == LVS_ICON && PtInRect (&infoPtr->rcFocus, lpht->pt)) - { - lpht->iItem = infoPtr->nFocusedItem; - } - else - { - if (uView == LVS_ICON || uView == LVS_SMALLICON) - { - RECT rcSearch; - ITERATOR i; - - rcSearch.left = lpht->pt.x - infoPtr->nItemWidth; - rcSearch.top = lpht->pt.y - infoPtr->nItemHeight; - rcSearch.right = lpht->pt.x + 1; - rcSearch.bottom = lpht->pt.y + 1; - - iterator_frameditems(&i, infoPtr, &rcSearch); - while(iterator_next(&i)) - { - if (!LISTVIEW_GetItemBox(infoPtr, i.nItem, &rcBounds)) continue; - if (PtInRect(&rcBounds, lpht->pt)) break; - } - lpht->iItem = i.nItem; - iterator_destroy(&i); - } - else - { - INT nPerCol = (uView == LVS_REPORT) ? infoPtr->nItemCount : LISTVIEW_GetCountPerColumn(infoPtr); - - Position.x = lpht->pt.x - Origin.x; - Position.y = lpht->pt.y - Origin.y; - TRACE("Position=%s, nPerCol=%d, nItemHeight=%d, nColHeight=%d\n", - debugpoint(&Position), nPerCol, infoPtr->nItemHeight, nPerCol * infoPtr->nItemHeight); - - if (Position.y < nPerCol * infoPtr->nItemHeight) - { - lpht->iItem = (Position.x / infoPtr->nItemWidth) * nPerCol + (Position.y / infoPtr->nItemHeight); - TRACE("iItem=%d\n", lpht->iItem); - if (lpht->iItem < 0 || lpht->iItem >= infoPtr->nItemCount) lpht->iItem = -1; - } - } - } - + rcSearch.left = lpht->pt.x; + rcSearch.top = lpht->pt.y; + rcSearch.right = rcSearch.left + 1; + rcSearch.bottom = rcSearch.top + 1; + + iterator_frameditems(&i, infoPtr, &rcSearch); + iterator_next(&i); /* go to first item in the sequence */ + lpht->iItem = i.nItem; + iterator_destroy(&i); + if (lpht->iItem == -1) return -1; lvItem.mask = LVIF_STATE | LVIF_TEXT; @@ -5641,8 +5584,9 @@ if (!select || lpht->iItem == -1) return lpht->iItem; if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) return lpht->iItem; - - return lpht->flags & (LVHT_ONITEMICON | LVHT_ONITEMLABEL) ? lpht->iItem : -1; + + if (uView == LVS_REPORT) UnionRect(&rcBounds, &rcIcon, &rcLabel); + return PtInRect(&rcBounds, opt) ? lpht->iItem : -1; }