📄 listview.c
字号:
} 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);
return 0;
}
/*************************************************************************
* LISTVIEW_UpdateHeaderSize [Internal]
*
* Function to resize the header control
*
* PARAMS
* [I] hwnd : handle to a window
* [I] nNewScrollPos : scroll pos to set
*
* RETURNS
* None.
*/
static void LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
{
RECT winRect;
POINT point[2];
TRACE("nNewScrollPos=%d\n", nNewScrollPos);
GetWindowRect(infoPtr->hwndHeader, &winRect);
point[0].x = winRect.left;
point[0].y = winRect.top;
point[1].x = winRect.right;
point[1].y = winRect.bottom;
MapWindowPoints(HWND_DESKTOP, infoPtr->hwndSelf, point, 2);
point[0].x = -nNewScrollPos;
point[1].x += nNewScrollPos;
SetWindowPos(infoPtr->hwndHeader,0,
point[0].x,point[0].y,point[1].x,point[1].y,
SWP_NOZORDER | SWP_NOACTIVATE);
}
/***
* DESCRIPTION:
* Update the scrollbars. This functions should be called whenever
* the content, size or view changes.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
*
* RETURN:
* None
*/
static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr)
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
SCROLLINFO horzInfo, vertInfo;
INT dx, dy;
if ((infoPtr->dwStyle & LVS_NOSCROLL) || !is_redrawing(infoPtr)) return;
ZeroMemory(&horzInfo, sizeof(SCROLLINFO));
horzInfo.cbSize = sizeof(SCROLLINFO);
horzInfo.nPage = infoPtr->rcList.right - infoPtr->rcList.left;
/* for now, we'll set info.nMax to the _count_, and adjust it later */
if (uView == LVS_LIST)
{
INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
horzInfo.nMax = (infoPtr->nItemCount + nPerCol - 1) / nPerCol;
/* scroll by at least one column per page */
if(horzInfo.nPage < infoPtr->nItemWidth)
horzInfo.nPage = infoPtr->nItemWidth;
horzInfo.nPage /= infoPtr->nItemWidth;
}
else if (uView == LVS_REPORT)
{
horzInfo.nMax = infoPtr->nItemWidth;
}
else /* LVS_ICON, or LVS_SMALLICON */
{
RECT rcView;
if (LISTVIEW_GetViewRect(infoPtr, &rcView)) horzInfo.nMax = rcView.right - rcView.left;
}
horzInfo.fMask = SIF_RANGE | SIF_PAGE;
horzInfo.nMax = max(horzInfo.nMax - 1, 0);
dx = GetScrollPos(infoPtr->hwndSelf, SB_HORZ);
dx -= SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo, TRUE);
TRACE("horzInfo=%s\n", debugscrollinfo(&horzInfo));
/* Setting the horizontal scroll can change the listview size
* (and potentially everything else) so we need to recompute
* everything again for the vertical scroll
*/
ZeroMemory(&vertInfo, sizeof(SCROLLINFO));
vertInfo.cbSize = sizeof(SCROLLINFO);
vertInfo.nPage = infoPtr->rcList.bottom - infoPtr->rcList.top;
if (uView == LVS_REPORT)
{
vertInfo.nMax = infoPtr->nItemCount;
/* scroll by at least one page */
if(vertInfo.nPage < infoPtr->nItemHeight)
vertInfo.nPage = infoPtr->nItemHeight;
vertInfo.nPage /= infoPtr->nItemHeight;
}
else if (uView != LVS_LIST) /* LVS_ICON, or LVS_SMALLICON */
{
RECT rcView;
if (LISTVIEW_GetViewRect(infoPtr, &rcView)) vertInfo.nMax = rcView.bottom - rcView.top;
}
vertInfo.fMask = SIF_RANGE | SIF_PAGE;
vertInfo.nMax = max(vertInfo.nMax - 1, 0);
dy = GetScrollPos(infoPtr->hwndSelf, SB_VERT);
dy -= SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &vertInfo, TRUE);
TRACE("vertInfo=%s\n", debugscrollinfo(&vertInfo));
/* Change of the range may have changed the scroll pos. If so move the content */
if (dx != 0 || dy != 0)
{
RECT listRect;
listRect = infoPtr->rcList;
ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &listRect, &listRect, 0, 0,
SW_ERASE | SW_INVALIDATE);
}
/* Update the Header Control */
if (uView == LVS_REPORT)
{
horzInfo.fMask = SIF_POS;
GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo);
LISTVIEW_UpdateHeaderSize(infoPtr, horzInfo.nPos);
}
}
/***
* DESCRIPTION:
* Shows/hides the focus rectangle.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] fShow : TRUE to show the focus, FALSE to hide it.
*
* RETURN:
* None
*/
static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, BOOL fShow)
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
HDC hdc;
TRACE("fShow=%d, nItem=%d\n", fShow, infoPtr->nFocusedItem);
if (infoPtr->nFocusedItem < 0) return;
/* we need some gymnastics in ICON mode to handle large items */
if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON )
{
RECT rcBox;
LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox);
if ((rcBox.bottom - rcBox.top) > infoPtr->nItemHeight)
{
LISTVIEW_InvalidateRect(infoPtr, &rcBox);
return;
}
}
if (!(hdc = GetDC(infoPtr->hwndSelf))) return;
/* for some reason, owner draw should work only in report mode */
if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT))
{
DRAWITEMSTRUCT dis;
LVITEMW item;
item.iItem = infoPtr->nFocusedItem;
item.iSubItem = 0;
item.mask = LVIF_PARAM;
if (!LISTVIEW_GetItemW(infoPtr, &item)) goto done;
ZeroMemory(&dis, sizeof(dis));
dis.CtlType = ODT_LISTVIEW;
dis.CtlID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
dis.itemID = item.iItem;
dis.itemAction = ODA_FOCUS;
if (fShow) dis.itemState |= ODS_FOCUS;
dis.hwndItem = infoPtr->hwndSelf;
dis.hDC = hdc;
LISTVIEW_GetItemBox(infoPtr, dis.itemID, &dis.rcItem);
dis.itemData = item.lParam;
SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
}
else
{
DrawFocusRect(hdc, &infoPtr->rcFocus);
}
done:
ReleaseDC(infoPtr->hwndSelf, hdc);
}
/***
* Invalidates all visible selected items.
*/
static void LISTVIEW_InvalidateSelectedItems(LISTVIEW_INFO *infoPtr)
{
ITERATOR i;
iterator_frameditems(&i, infoPtr, &infoPtr->rcList);
while(iterator_next(&i))
{
if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED))
LISTVIEW_InvalidateItem(infoPtr, i.nItem);
}
iterator_destroy(&i);
}
/***
* DESCRIPTION: [INTERNAL]
* Computes an item's (left,top) corner, relative to rcView.
* That is, the position has NOT been made relative to the Origin.
* This is deliberate, to avoid computing the Origin over, and
* over again, when this function is call in a loop. Instead,
* one ca factor the computation of the Origin before the loop,
* and offset the value retured by this function, on every iteration.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] nItem : item number
* [O] lpptOrig : item top, left corner
*
* RETURN:
* None.
*/
static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
assert(nItem >= 0 && nItem < infoPtr->nItemCount);
if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
{
lpptPosition->x = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosX, nItem);
lpptPosition->y = (LONG_PTR)DPA_GetPtr(infoPtr->hdpaPosY, nItem);
}
else if (uView == LVS_LIST)
{
INT nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
}
else /* LVS_REPORT */
{
lpptPosition->x = 0;
lpptPosition->y = nItem * infoPtr->nItemHeight;
}
}
/***
* DESCRIPTION: [INTERNAL]
* Compute the rectangles of an item. This is to localize all
* the computations in one place. If you are not interested in some
* of these values, simply pass in a NULL -- the fucntion is smart
* enough to compute only what's necessary. The function computes
* the standard rectangles (BOUNDS, ICON, LABEL) plus a non-standard
* one, the BOX rectangle. This rectangle is very cheap to compute,
* and is guaranteed to contain all the other rectangles. Computing
* the ICON rect is also cheap, but all the others are potentaily
* expensive. This gives an easy and effective optimization when
* searching (like point inclusion, or rectangle intersection):
* first test against the BOX, and if TRUE, test agains the desired
* rectangle.
* If the function does not have all the necessary information
* to computed the requested rectangles, will crash with a
* failed assertion. This is done so we catch all programming
* errors, given that the function is called only from our code.
*
* We have the following 'special' meanings for a few fields:
* * If LVIS_FOCUSED is set, we assume the item has the focus
* This is important in ICON mode, where it might get a larger
* then usual rectange
*
* Please note that subitem support works only in REPORT mode.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] lpLVItem : item to compute the measures for
* [O] lprcBox : ptr to Box rectangle
* The internal LVIR_BOX rectangle
* [0] lprcState : ptr to State icon rectangle
* The internal LVIR_STATE rectangle
* [O] lprcIcon : ptr to Icon rectangle
* Same as LVM_GETITEMRECT with LVIR_ICON
* [O] lprcLabel : ptr to Label rectangle
* Same as LVM_GETITEMRECT with LVIR_LABEL
*
* RETURN:
* None.
*/
static void LISTVIEW_GetItemMetrics(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
LPRECT lprcBox, LPRECT lprcState,
LPRECT lprcIcon, LPRECT lprcLabel)
{
UINT uView = infoPtr->dwStyle & LVS_TYPEMASK;
BOOL doState = FALSE, doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE;
RECT Box, State, Icon, Label;
COLUMN_INFO *lpColumnInfo = NULL;
TRACE("(lpLVItem=%s)\n", debuglvitem_t(lpLVItem, TRUE));
/* Be smart and try to figure out the minimum we have to do */
if (lpLVItem->iSubItem) assert(uView == LVS_REPORT);
if (uView == LVS_ICON && (lprcBox || lprcLabel))
{
assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED));
if (lpLVItem->state & LVIS_FOCUSED) oversizedBox = doLabel = TRUE;
}
if (lprcLabel) doLabel = TRUE;
if (doLabel || lprcIcon) doIcon = TRUE;
if (doIcon || lprcState) doState = TRUE;
/************************************************************/
/* compute the box rectangle (it should be cheap to do) */
/************************************************************/
if (lpLVItem->iSubItem || uView == LVS_REPORT)
lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpLVItem->iSubItem);
if (lpLVItem->iSubItem)
{
Box = lpColumnInfo->rcHeader;
}
else
{
Box.left = 0;
Box.right = infoPtr->nItemWidth;
}
Box.top = 0;
Box.bottom = infoPtr->nItemHeight;
/************************************************************/
/* compute STATEICON bounding box */
/************************************************************/
if (doState)
{
if (uView == LVS_ICON)
{
State.left = Box.left - infoPtr->iconStateSize.cx - 2;
if (infoPtr->himlNormal)
State.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2;
State.top = Box.top + infoPtr->iconSize.cy - infoPtr->iconStateSize.cy + 4;
}
else
{
/* we need the ident in report mode, if we don't have it, we fail */
State.left = Box.left;
if (uView == LVS_REPORT)
{
if (lpLVItem->iSubItem == 0)
{
State.left += REPORT_MARGINX;
assert(lpLVItem->mask & LVIF_INDENT);
State.left += infoPtr->iconSize.cx * lpLVItem->iIndent;
}
}
State.top = Box.top;
}
State.right = State.left;
State.bottom = State.top;
if (infoPtr->himlState && lpLVItem->iSubItem == 0)
{
State.right += infoPtr->iconStateSize.cx;
State.bottom += infoPtr->iconStateSize.cy;
}
if (lprcState) *lprcState = State;
TRACE(" - state=%s\n", wine_dbgstr_rect(&State));
}
else S
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -