- Better implementation for GetTopindex/GetOrigin/SetIconSpacing.

- Drawing optimizations, better scrolling.
- A few more bugs squashed without mercy.
- Many cleanups, simplifications, doc updates.
This commit is contained in:
Dimitrie O. Paun 2002-09-18 18:29:28 +00:00 committed by Alexandre Julliard
parent 7677eb6ec5
commit df28ddf309

View file

@ -25,9 +25,8 @@
* Listview control implementation.
*
* TODO:
* 1. No horizontal scrolling when header is larger than the client area.
* 2. Drawing optimizations.
* 3. Hot item handling.
* -- Drawing optimizations.
* -- Hot item handling.
*
* Notifications:
* LISTVIEW_Notify : most notifications from children (editbox and header)
@ -651,6 +650,11 @@ static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg,
/******** Internal API functions ************************************/
static inline void LISTVIEW_Invalidate(LISTVIEW_INFO *infoPtr)
{
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
}
static inline BOOL LISTVIEW_GetItemW(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL internal)
{
return LISTVIEW_GetItemT(infoPtr, lpLVItem, internal, TRUE);
@ -1101,9 +1105,6 @@ static void LISTVIEW_UnsupportedStyles(LONG lStyle)
if (lStyle & LVS_NOLABELWRAP)
FIXME(" LVS_NOLABELWRAP\n");
if (!(lStyle & LVS_SHAREIMAGELISTS))
FIXME(" !LVS_SHAREIMAGELISTS\n");
if (lStyle & LVS_SORTASCENDING)
FIXME(" LVS_SORTASCENDING\n");
@ -2464,7 +2465,7 @@ static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
LISTVIEW_ToggleFocusRect(infoPtr);
rcItem.left = LVIR_BOUNDS;
LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
InvalidateRect(infoPtr->hwndSelf, &rcItem, TRUE);
InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
}
/* restore text */
if (pszText)
@ -2507,10 +2508,37 @@ static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *infoPtr)
if ((lStyle & WS_VSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
nItem = scrollInfo.nPos;
}
else
{
if ((lStyle & WS_VSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
nItem = LISTVIEW_GetCountPerRow(infoPtr) * (scrollInfo.nPos / infoPtr->nItemHeight);
}
TRACE("nItem=%d\n", nItem);
return nItem;
}
/***
* DESCRIPTION:
* Erases the background of the given rectangle
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] hdc : device context handle
* [I] lprcBox : clipping rectangle
*
* RETURN:
* Success: TRUE
* Failure: FALSE
*/
static inline BOOL LISTVIEW_FillBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT* lprcBox)
{
if (!infoPtr->hBkBrush) return FALSE;
FillRect(hdc, lprcBox, infoPtr->hBkBrush);
return TRUE;
}
/***
* DESCRIPTION:
@ -2574,7 +2602,7 @@ static void LISTVIEW_DrawSubItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT
else
rcTemp.right += WIDTH_PADDING;
if (infoPtr->clrBk != CLR_NONE) FillRect(hdc, &rcTemp, infoPtr->hBkBrush);
LISTVIEW_FillBkgnd(infoPtr, hdc, &rcTemp);
/* set item colors */
if (ListView_GetItemState(infoPtr->hwndSelf,nItem,LVIS_SELECTED) && Selected)
@ -2682,7 +2710,7 @@ static void LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT r
else
rcTemp.right+=WIDTH_PADDING;
if (infoPtr->clrBk != CLR_NONE) FillRect(hdc, &rcTemp, infoPtr->hBkBrush);
LISTVIEW_FillBkgnd(infoPtr, hdc, &rcTemp);
/* do indent */
if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
@ -2862,7 +2890,7 @@ static void LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, R
TRACE("background rect (%d,%d)-(%d,%d)\n",
rcFill.left, rcFill.top, rcFill.right, rcFill.bottom);
if (infoPtr->clrBk != CLR_NONE) FillRect(hdc, &rcFill, infoPtr->hBkBrush);
LISTVIEW_FillBkgnd(infoPtr, hdc, &rcFill);
/* Figure out text colours etc. depending on state
* At least the following states exist; there may be more.
@ -3016,8 +3044,7 @@ static void LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, R
*/
static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
{
SCROLLINFO scrollInfo;
INT rgntype, scrollOffset, nDrawPosY, j;
INT rgntype, nDrawPosY, j;
INT nTop, nItem, nLast, nUpdateHeight, nUpdateWidth;
INT nColumnCount, nFirstCol, nLastCol;
RECT rcItem, rcClip, *lprcFocus, *lprcCols;
@ -3025,6 +3052,7 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode
DWORD cditemmode = CDRF_DODEFAULT;
LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
UINT uID = GetWindowLongW(infoPtr->hwndSelf, GWL_ID);
POINT ptOrig;
TRACE("\n");
@ -3053,19 +3081,15 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode
for (j = 0; j < nColumnCount; j++)
Header_GetItemRect(infoPtr->hwndHeader, j, &lprcCols[j]);
/* Get scroll bar info once before loop */
ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
scrollInfo.cbSize = sizeof(SCROLLINFO);
scrollInfo.fMask = SIF_POS;
GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo);
scrollOffset = scrollInfo.nPos;
/* Get scroll info once before loop */
LISTVIEW_GetOrigin(infoPtr, &ptOrig);
/* we now narrow the columns as well */
nLastCol = nColumnCount - 1;
for(nFirstCol = 0; nFirstCol < nColumnCount; nFirstCol++)
if (lprcCols[nFirstCol].right - scrollOffset >= rcClip.left) break;
if (lprcCols[nFirstCol].right + ptOrig.x >= rcClip.left) break;
for(nLastCol = nColumnCount - 1; nLastCol >= 0; nLastCol--)
if (lprcCols[nLastCol].left - scrollOffset < rcClip.right) break;
if (lprcCols[nLastCol].left + ptOrig.x < rcClip.right) break;
/* a last few bits before we start drawing */
TRACE("nTop=%d, nItem=%d, nLast=%d, nFirstCol=%d, nLastCol=%d\n",
@ -3101,7 +3125,7 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode
dis.rcItem.right = lprcCols[nColumnCount - 1].right;
dis.rcItem.top = nDrawPosY;
dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight;
OffsetRect(&dis.rcItem, -scrollOffset, 0);
OffsetRect(&dis.rcItem, ptOrig.x, 0);
item.iItem = nItem;
item.iSubItem = 0;
@ -3133,7 +3157,7 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode
rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
/* Offset the Scroll Bar Pos */
OffsetRect(&rcItem, -scrollOffset, 0);
OffsetRect(&rcItem, ptOrig.x, 0);
if (j == 0)
LISTVIEW_DrawItem(infoPtr, hdc, nItem, rcItem, bFullSelected, lprcFocus);
@ -3201,8 +3225,7 @@ static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
return;
if (cdmode & CDRF_NOTIFYITEMDRAW)
cditemmode = notify_customdrawitem (infoPtr, hdc, nItem, 0,
CDDS_ITEMPREPAINT);
cditemmode = notify_customdrawitem (infoPtr, hdc, nItem, 0, CDDS_ITEMPREPAINT);
if (cditemmode & CDRF_SKIPDEFAULT)
continue;
@ -3220,8 +3243,7 @@ static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
LISTVIEW_DrawItem(infoPtr, hdc, nItem, rcItem, FALSE, lprcFocus);
if (cditemmode & CDRF_NOTIFYPOSTPAINT)
notify_customdrawitem(infoPtr, hdc, nItem, 0,
CDDS_ITEMPOSTPAINT);
notify_customdrawitem(infoPtr, hdc, nItem, 0, CDDS_ITEMPOSTPAINT);
}
}
@ -3258,8 +3280,7 @@ static void LISTVIEW_RefreshIcon(LISTVIEW_INFO *infoPtr, HDC hdc, BOOL bSmall, D
for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
{
if (cdmode & CDRF_NOTIFYITEMDRAW)
cditemmode = notify_customdrawitem (infoPtr, hdc, i, 0,
CDDS_ITEMPREPAINT);
cditemmode = notify_customdrawitem (infoPtr, hdc, i, 0, CDDS_ITEMPREPAINT);
if (cditemmode & CDRF_SKIPDEFAULT)
continue;
@ -3295,11 +3316,74 @@ static void LISTVIEW_RefreshIcon(LISTVIEW_INFO *infoPtr, HDC hdc, BOOL bSmall, D
}
}
if (cditemmode & CDRF_NOTIFYPOSTPAINT)
notify_customdrawitem(infoPtr, hdc, i, 0,
CDDS_ITEMPOSTPAINT);
notify_customdrawitem(infoPtr, hdc, i, 0, CDDS_ITEMPOSTPAINT);
}
}
/***
* Computes the region occupied by items on the screen.
*/
static void set_visible_items_rgn(LISTVIEW_INFO *infoPtr, HRGN hRgn)
{
UINT uView = LISTVIEW_GetType(infoPtr);
INT nTop = LISTVIEW_GetTopIndex(infoPtr);
INT nPerRow = LISTVIEW_GetCountPerRow(infoPtr);
INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr);
INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
INT nVisItems = max(GETITEMCOUNT(infoPtr) - nTop, 1);
INT nRows, nCols;
HRGN hEmptyRgn;
RECT rcTmp;
/* adjust in case we have potentially partial items showing */
if (uView == LVS_LIST)
nPerRow += (nListWidth % infoPtr->nItemWidth) ? 1 : 0;
else
nPerCol += (nListHeight % infoPtr->nItemHeight) ? 1 : 0;
/* determine the actual amount of _full_ rows and columns */
if (uView == LVS_LIST)
{
nRows = min(nVisItems, nPerCol);
nCols = min(nVisItems / nRows, nPerRow);
}
else
{
nCols = min(nVisItems, nPerRow);
nRows = min(nVisItems / nCols, nPerCol);
}
/* this are items we have visible, so set it in the region */
rcTmp.left = rcTmp.top = 0;
rcTmp.right = nCols * infoPtr->nItemWidth;
rcTmp.bottom = nRows * infoPtr->nItemHeight;
OffsetRect(&rcTmp, infoPtr->rcList.left, infoPtr->rcList.top);
SetRectRgn(hRgn, rcTmp.left, rcTmp.top, rcTmp.right, rcTmp.bottom);
/* we may still have a incomplete row or column unaccounted for */
if (nCols * nRows <= nVisItems) return;
/* determine the origin of the incomplete row/column */
if (uView == LVS_LIST)
{
rcTmp.left = (nCols - 1) * infoPtr->nItemWidth;
rcTmp.top = (nVisItems - (nCols - 1) * nRows) * infoPtr->nItemHeight;
}
else
{
rcTmp.left = (nVisItems - nCols * (nRows - 1)) * infoPtr->nItemWidth;
rcTmp.top = (nRows - 1) * infoPtr->nItemHeight;
}
/* substract it from the item region, as there are no items there */
hEmptyRgn = CreateRectRgn(infoPtr->rcList.left + rcTmp.left,
infoPtr->rcList.top + rcTmp.top,
infoPtr->rcList.right, infoPtr->rcList.bottom);
CombineRgn(hRgn, hRgn, hEmptyRgn, RGN_DIFF);
DeleteObject(hEmptyRgn);
}
/***
* DESCRIPTION:
* Draws listview items.
@ -3316,7 +3400,7 @@ static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
UINT uView = LISTVIEW_GetType(infoPtr);
HFONT hOldFont;
DWORD cdmode;
RECT rcClient, rcTemp;
RECT rcClient;
LISTVIEW_DUMP(infoPtr);
@ -3330,12 +3414,30 @@ static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
/* select font */
hOldFont = SelectObject(hdc, infoPtr->hFont);
/* select transparent brush (for drawing the focus box) */
SelectObject(hdc, GetStockObject(NULL_BRUSH));
/* draw background around items */
/* this is a fancy way to avoid flicker:
* we compute exactly there the items are being draw,
* and we fill the remaining space. This is however
* complicated, and since we're erasing the background
* anyway on WM_ERASEBKGND and WM_PAINT, it's not
* worse doing. The code is here in case we want to pursue
* the idea further, but it is disabled.
*/
if (0 && infoPtr->hBkBrush)
{
HRGN hBkgndRgn = CreateRectRgn(0, 0, 0, 0);
HRGN hItemsRgn = CreateRectRgn(0, 0, 0, 0);
/* paint the background of the control that doesn't contain any items */
SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
if (infoPtr->clrBk != CLR_NONE) FillRect(hdc, &rcTemp, infoPtr->hBkBrush);
ERR("disabled code!\n");
SetRectRgn(hBkgndRgn, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
set_visible_items_rgn(infoPtr, hItemsRgn);
CombineRgn(hBkgndRgn, hBkgndRgn, hItemsRgn, RGN_DIFF);
FillRgn(hdc, hBkgndRgn, infoPtr->hBkBrush);
DeleteObject(hItemsRgn);
DeleteObject(hBkgndRgn);
}
if (uView == LVS_LIST)
LISTVIEW_RefreshList(infoPtr, hdc, cdmode);
@ -3498,7 +3600,7 @@ static LRESULT LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr)
if (lStyle & LVS_OWNERDATA)
{
infoPtr->hdpaItems->nItemCount = 0;
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
return TRUE;
}
@ -3574,7 +3676,7 @@ static LRESULT LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr)
LISTVIEW_UpdateScroll(infoPtr);
/* invalidate client area (optimization needed) */
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
}
return bResult;
@ -3592,31 +3694,23 @@ static LRESULT LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr)
* SUCCESS : TRUE
* FAILURE : FALSE
*/
static LRESULT LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
static BOOL LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
{
UINT uView = LISTVIEW_GetType(infoPtr);
UINT uOwnerData = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & LVS_OWNERDATA;
BOOL bResult = FALSE;
if (!Header_DeleteItem(infoPtr->hwndHeader, nColumn)) return FALSE;
if (Header_DeleteItem(infoPtr->hwndHeader, nColumn))
{
bResult = uOwnerData ? TRUE : LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & LVS_OWNERDATA))
LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
/* Need to reset the item width when deleting a column */
infoPtr->nItemWidth = LISTVIEW_GetItemWidth(infoPtr);
/* reset scroll parameters */
if (uView == LVS_REPORT)
{
/* update scrollbar(s) */
LISTVIEW_UpdateScroll(infoPtr);
/* refresh client area */
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
}
}
/* FIXME: invalidate only fromthe deleted column to the right */
LISTVIEW_Invalidate(infoPtr);
return bResult;
return TRUE;
}
/***
@ -3665,7 +3759,7 @@ static LRESULT LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
if (lStyle & LVS_OWNERDATA)
{
infoPtr->hdpaItems->nItemCount --;
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
return TRUE;
}
@ -3718,8 +3812,8 @@ static LRESULT LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
LISTVIEW_UpdateScroll(infoPtr);
/* refresh client area */
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
/* FIXME: optimizartion refresh client area */
LISTVIEW_Invalidate(infoPtr);
}
return bResult;
@ -4043,8 +4137,8 @@ static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPart
}
}
if(bRedraw)
InvalidateRect(infoPtr->hwndSelf,NULL,TRUE);
if(bRedraw) LISTVIEW_Invalidate(infoPtr);
return TRUE;
}
@ -5717,38 +5811,40 @@ static BOOL LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin)
{
LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
UINT uView = lStyle & LVS_TYPEMASK;
BOOL bResult = FALSE;
TRACE("(lpptOrigin=%p)\n", lpptOrigin);
if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
{
INT nHorzPos = 0, nVertPos = 0;
SCROLLINFO scrollInfo;
ZeroMemory(lpptOrigin, sizeof(POINT));
if (!lpptOrigin) return FALSE;
ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
scrollInfo.cbSize = sizeof(SCROLLINFO);
if (lStyle & WS_HSCROLL)
{
scrollInfo.fMask = SIF_POS;
if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
lpptOrigin->x = -scrollInfo.nPos;
if ((lStyle & WS_HSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo))
nHorzPos = scrollInfo.nPos;
if ((lStyle & WS_VSCROLL) && GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
nVertPos = scrollInfo.nPos;
TRACE("nHorzPos=%d, nVertPos=%d\n", nHorzPos, nVertPos);
lpptOrigin->x = infoPtr->rcList.left;
lpptOrigin->y = infoPtr->rcList.top;
if (uView == LVS_LIST)
{
nHorzPos *= LISTVIEW_GetCountPerColumn(infoPtr);
nVertPos = 0;
}
else if (uView == LVS_REPORT)
{
nVertPos *= infoPtr->nItemHeight;
}
if (lStyle & WS_VSCROLL)
{
scrollInfo.fMask = SIF_POS;
if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo))
lpptOrigin->y = -scrollInfo.nPos;
}
bResult = TRUE;
lpptOrigin->x -= nHorzPos;
lpptOrigin->y -= nVertPos;
TRACE("(pt=(%ld,%ld))\n", lpptOrigin->x, lpptOrigin->y);
}
return bResult;
return TRUE;
}
/***
@ -6181,7 +6277,9 @@ static LRESULT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn,
infoPtr->nItemWidth = LISTVIEW_GetItemWidth(infoPtr);
LISTVIEW_UpdateScroll(infoPtr);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
/* FIXME: invalidate from inserted column to right */
LISTVIEW_Invalidate(infoPtr);
}
return nNewColumn;
@ -6299,7 +6397,7 @@ static LRESULT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
LISTVIEW_UpdateScroll(infoPtr);
/* FIXME: refresh client area */
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
LISTVIEW_Invalidate(infoPtr);
return nItem;
@ -6335,7 +6433,7 @@ static LRESULT LISTVIEW_RedrawItems(LISTVIEW_INFO *infoPtr, INT nFirst, INT nLas
{
rcItem.left = LVIR_BOUNDS;
LISTVIEW_GetItemRect(infoPtr, i, &rcItem);
InvalidateRect(infoPtr->hwndSelf, &rcItem, TRUE);
InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
}
return TRUE;
@ -6410,10 +6508,13 @@ static LRESULT LISTVIEW_Scroll(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
static LRESULT LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrBk)
{
if(infoPtr->clrBk != clrBk) {
if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
infoPtr->clrBk = clrBk;
if (infoPtr->hBkBrush) DeleteObject(infoPtr->hBkBrush);
infoPtr->hBkBrush = clrBk == CLR_NONE ? 0 : CreateSolidBrush(clrBk);
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
if (clrBk == CLR_NONE)
infoPtr->hBkBrush = GetClassLongW(infoPtr->hwndSelf, GCL_HBRBACKGROUND);
else
infoPtr->hBkBrush = CreateSolidBrush(clrBk);
LISTVIEW_Invalidate(infoPtr);
}
return TRUE;
@ -6596,7 +6697,7 @@ static LRESULT LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT iCol, INT cx)
/* resize all columns if in LVS_LIST mode */
if(uView == LVS_LIST) {
infoPtr->nItemWidth = cx;
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); /* force redraw of the listview */
LISTVIEW_Invalidate(infoPtr);
return TRUE;
}
@ -6711,7 +6812,7 @@ static LRESULT LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT iCol, INT cx)
hdi.cxy = cx;
lret = Header_SetItemW(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); /* force redraw of the listview */
LISTVIEW_Invalidate(infoPtr);
return lret;
}
@ -6812,46 +6913,37 @@ static LRESULT LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime)
*/
static LRESULT LISTVIEW_SetIconSpacing(LISTVIEW_INFO *infoPtr, DWORD spacing)
{
INT cy = HIWORD(spacing);
INT cx = LOWORD(spacing);
DWORD oldspacing;
INT cy = HIWORD(spacing), cx = LOWORD(spacing);
DWORD oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
LONG lStyle = GetWindowLongA(infoPtr->hwndSelf, GWL_STYLE);
UINT uView = lStyle & LVS_TYPEMASK;
oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
if (cx == -1) /* set to default */
cx = GetSystemMetrics(SM_CXICONSPACING);
if (cy == -1) /* set to default */
cy = GetSystemMetrics(SM_CYICONSPACING);
TRACE("requested=(%d,%d)\n", cx, cy);
/* this is supported only for LVS_ICON style */
if (uView != LVS_ICON) return oldspacing;
/* set to defaults, if instructed to */
if (cx == -1) cx = GetSystemMetrics(SM_CXICONSPACING);
if (cy == -1) cy = GetSystemMetrics(SM_CYICONSPACING);
/* if 0 then compute width
* FIXME: Should scan each item and determine max width of
* icon or label, then make that the width */
if (cx == 0)
cx = infoPtr->iconSpacing.cx;
/* if 0 then compute height */
if (cy == 0)
cy = infoPtr->iconSize.cy + 2 * infoPtr->ntmHeight +
ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_PADDING;
if (cx)
infoPtr->iconSpacing.cx = cx;
else
{ /* if 0 then compute width */
if (uView == LVS_ICON)
FIXME("width computation not yet done\n");
/*
* Should scan each item and determine max width of
* icon or label, then make that the width
*/
else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
infoPtr->iconSpacing.cx = LISTVIEW_GetItemWidth(infoPtr);
}
if (cy)
infoPtr->iconSpacing.cy = cy;
else
{ /* if 0 then compute height */
if (uView == LVS_ICON)
infoPtr->iconSpacing.cy = infoPtr->iconSize.cy + 2 * infoPtr->ntmHeight
+ ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_PADDING;
else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
infoPtr->iconSpacing.cy = LISTVIEW_GetItemHeight(infoPtr);
}
TRACE("old=(%d,%d), new=(%ld,%ld), iconSize=(%ld,%ld), ntmH=%d\n",
LOWORD(oldspacing), HIWORD(oldspacing),
infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy,
TRACE("old=(%d,%d), new=(%d,%d), iconSize=(%ld,%ld), ntmH=%d\n",
LOWORD(oldspacing), HIWORD(oldspacing), cx, cy,
infoPtr->iconSize.cx, infoPtr->iconSize.cy,
infoPtr->ntmHeight);
@ -6972,7 +7064,7 @@ static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFl
LISTVIEW_UpdateScroll(infoPtr);
if (min(precount,infoPtr->hdpaItems->nItemCount)<topvisible)
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
}
else
{
@ -7196,7 +7288,7 @@ static LRESULT LISTVIEW_SetTextBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrTextB
if (infoPtr->clrTextBk != clrTextBk)
{
infoPtr->clrTextBk = clrTextBk;
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
}
return TRUE;
@ -7221,7 +7313,7 @@ static LRESULT LISTVIEW_SetTextColor (LISTVIEW_INFO *infoPtr, COLORREF clrText)
if (infoPtr->clrText != clrText)
{
infoPtr->clrText = clrText;
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
}
return TRUE;
@ -7325,7 +7417,7 @@ static LRESULT LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompar
LISTVIEW_AlignTop(infoPtr);
/* refresh the display */
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
return TRUE;
}
@ -7344,35 +7436,34 @@ static LRESULT LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompar
* SUCCESS : TRUE
* FAILURE : FALSE
*/
static LRESULT LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem)
static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem)
{
LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
BOOL bResult = FALSE;
UINT uView = lStyle & LVS_TYPEMASK;
RECT rc;
TRACE("(nItem=%d)\n", nItem);
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
{
bResult = TRUE;
if ((nItem < 0) && (nItem >= GETITEMCOUNT(infoPtr))) return FALSE;
/* rearrange with default alignment style */
if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
if ((lStyle & LVS_AUTOARRANGE) &&
((uView == LVS_ICON) ||(uView == LVS_SMALLICON)))
{
ListView_Arrange(infoPtr->hwndSelf, 0);
LISTVIEW_Arrange(infoPtr, 0);
}
else
{
/* get item bounding rectangle */
ListView_GetItemRect(infoPtr->hwndSelf, nItem, &rc, LVIR_BOUNDS);
InvalidateRect(infoPtr->hwndSelf, &rc, TRUE);
}
rc.left = LVIR_BOUNDS;
LISTVIEW_GetItemRect(infoPtr, nItem, &rc);
InvalidateRect(infoPtr->hwndSelf, &rc, FALSE);
}
return bResult;
return TRUE;
}
/***
* DESCRIPTION:
* Creates the listview control.
@ -7406,22 +7497,18 @@ static LRESULT LISTVIEW_Create(HWND hwnd, LPCREATESTRUCTW lpcs)
(WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY);
/* initialize color information */
infoPtr->clrBk = comctl32_color.clrWindow;
infoPtr->clrBk = CLR_NONE;
infoPtr->clrText = comctl32_color.clrWindowText;
infoPtr->clrTextBk = CLR_DEFAULT;
infoPtr->hBkBrush = CreateSolidBrush(infoPtr->clrBk);
LISTVIEW_SetBkColor(infoPtr, comctl32_color.clrWindow);
/* set default values */
infoPtr->uCallbackMask = 0;
infoPtr->nFocusedItem = -1;
infoPtr->nSelectionMark = -1;
infoPtr->nHotItem = -1;
infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
infoPtr->hwndEdit = 0;
infoPtr->bEditing = FALSE;
infoPtr->nEditLabelItem = -1;
infoPtr->bIsDrawing = FALSE;
/* get default font (icon title) */
SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
@ -7495,29 +7582,24 @@ static LRESULT LISTVIEW_Create(HWND hwnd, LPCREATESTRUCTW lpcs)
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
* [I] WPARAM : device context handle
* [I] LPARAM : not used
* [I] hdc : device context handle
*
* RETURN:
* SUCCESS : TRUE
* FAILURE : FALSE
*/
static LRESULT LISTVIEW_EraseBackground(LISTVIEW_INFO *infoPtr, WPARAM wParam,
LPARAM lParam)
static inline BOOL LISTVIEW_EraseBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc)
{
RECT rc;
TRACE("(wParam=%x, lParam=%lx)\n", wParam, lParam);
TRACE("(hdc=%x)\n", hdc);
if (infoPtr->clrBk == CLR_NONE)
return SendMessageW(GetParent(infoPtr->hwndSelf), WM_ERASEBKGND, wParam, lParam);
if (!GetClipBox(hdc, &rc)) return FALSE;
GetClientRect(infoPtr->hwndSelf, &rc);
FillRect((HDC)wParam, &rc, infoPtr->hBkBrush);
return 0;
return LISTVIEW_FillBkgnd(infoPtr, hdc, &rc);
}
/***
* DESCRIPTION:
* Helper function for LISTVIEW_[HV]Scroll *only*.
@ -7530,19 +7612,10 @@ static LRESULT LISTVIEW_EraseBackground(LISTVIEW_INFO *infoPtr, WPARAM wParam,
*/
static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
{
/* if we have a focus rectagle, we have to erase it before we scroll */
if (infoPtr->bFocus) LISTVIEW_ToggleFocusRect(infoPtr);
/* now we can scroll the list */
ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList,
&infoPtr->rcList, 0, 0, SW_INVALIDATE);
/* if we have focus, adjust rect, and redraw the rectangle */
if (infoPtr->bFocus)
{
OffsetRect(&infoPtr->rcFocus, dx, dy);
LISTVIEW_ToggleFocusRect(infoPtr);
}
UpdateWindow(infoPtr->hwndSelf);
}
/***
@ -8056,7 +8129,8 @@ static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
}
/* redraw if we could have possibly selected something */
if(!GETITEMCOUNT(infoPtr)) InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
/* FIXME: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
if(!GETITEMCOUNT(infoPtr)) LISTVIEW_Invalidate(infoPtr);
return 0;
}
@ -8142,7 +8216,6 @@ static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
/* destroy image lists */
if (!(lStyle & LVS_SHAREIMAGELISTS))
{
#if 0
/* FIXME: If the caller does a ImageList_Destroy and then we
* do this code the area will be freed twice. Currently
* this generates an "err:heap:HEAP_ValidateInUseArena
@ -8157,13 +8230,12 @@ static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
ImageList_Destroy(infoPtr->himlSmall);
if (infoPtr->himlState)
ImageList_Destroy(infoPtr->himlState);
#endif
}
/* destroy font, bkgnd brush */
infoPtr->hFont = 0;
if (infoPtr->hDefaultFont) DeleteObject(infoPtr->hDefaultFont);
if (infoPtr->hBkBrush) DeleteObject(infoPtr->hBkBrush);
if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush);
/* free listview info pointer*/
COMCTL32_Free(infoPtr);
@ -8194,7 +8266,7 @@ static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, INT nCtrlId, LPNMHDR lpnm
if (lpnmh->code == HDN_ENDTRACKW)
{
infoPtr->nItemWidth = LISTVIEW_GetItemWidth(infoPtr);
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
}
else if(lpnmh->code == HDN_ITEMCLICKW || lpnmh->code == HDN_ITEMCLICKA)
{
@ -8216,7 +8288,7 @@ static LRESULT LISTVIEW_Notify(LISTVIEW_INFO *infoPtr, INT nCtrlId, LPNMHDR lpnm
*/
infoPtr->nItemWidth = LISTVIEW_GetItemWidth(infoPtr);
LISTVIEW_UpdateScroll(infoPtr);
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
}
}
@ -8259,24 +8331,19 @@ static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT
*/
static LRESULT LISTVIEW_Paint(LISTVIEW_INFO *infoPtr, HDC hdc)
{
PAINTSTRUCT ps;
TRACE("(hdc=%x)\n", hdc);
if (hdc == 0)
{
hdc = BeginPaint(infoPtr->hwndSelf, &ps);
TRACE("ps erase=%s, rect=(%d,%d)-(%d,%d)\n",
ps.fErase ? "TRUE" : "FALSE",
ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
if (ps.fErase)
LISTVIEW_EraseBackground(infoPtr, (WPARAM)hdc, 0);
if (hdc)
LISTVIEW_Refresh(infoPtr, hdc);
EndPaint(infoPtr->hwndSelf, &ps);
}
else
{
PAINTSTRUCT ps;
hdc = BeginPaint(infoPtr->hwndSelf, &ps);
if (!hdc) return 1;
if (ps.fErase) LISTVIEW_FillBkgnd(infoPtr, hdc, &ps.rcPaint);
LISTVIEW_Refresh(infoPtr, hdc);
EndPaint(infoPtr->hwndSelf, &ps);
}
return 0;
@ -8387,11 +8454,11 @@ static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pt
*/
static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
{
POINT pt = { pts.x, pts.y };
TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, pts.x, pts.y);
if (infoPtr->bRButtonDown)
{
POINT pt = { pts.x, pts.y };
if (!infoPtr->bRButtonDown) return 0;
/* set button flag */
infoPtr->bRButtonDown = FALSE;
@ -8402,7 +8469,6 @@ static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, POINTS pts)
/* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU,
(WPARAM)infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y));
}
return 0;
}
@ -8485,24 +8551,15 @@ static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
*/
static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw)
{
UINT uView = LISTVIEW_GetType(infoPtr);
TRACE("(hfont=%x,redraw=%hu)\n", hFont, fRedraw);
infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
LISTVIEW_SaveTextMetrics(infoPtr);
if (uView == LVS_REPORT)
{
/* set header font */
SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
MAKELPARAM(fRedraw, 0));
}
if (LISTVIEW_GetType(infoPtr) == LVS_REPORT)
SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0));
/* invalidate listview control client area */
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
if (fRedraw) UpdateWindow(infoPtr->hwndSelf);
if (fRedraw) LISTVIEW_Invalidate(infoPtr);
return 0;
}
@ -8521,6 +8578,7 @@ static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedra
*/
static LRESULT LISTVIEW_SetRedraw(LISTVIEW_INFO *infoPtr, BOOL bRedraw)
{
/* FIXME: this is bogus */
LRESULT lResult = DefWindowProcW(infoPtr->hwndSelf, WM_SETREDRAW, bRedraw, 0);
if(bRedraw)
RedrawWindow(infoPtr->hwndSelf, NULL, 0,
@ -8560,8 +8618,8 @@ static LRESULT LISTVIEW_Size(LISTVIEW_INFO *infoPtr, int Width, int Height)
LISTVIEW_UpdateScroll(infoPtr);
/* invalidate client area + erase background */
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
/* FIXME: be smarter here */
LISTVIEW_Invalidate(infoPtr);
}
return 0;
@ -8746,7 +8804,7 @@ static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType,
LISTVIEW_UpdateScroll(infoPtr);
/* invalidate client area + erase background */
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
LISTVIEW_Invalidate(infoPtr);
/* print the list of unsupported window styles */
LISTVIEW_UnsupportedStyles(lpss->styleNew);
@ -9125,7 +9183,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return LISTVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam);
case WM_ERASEBKGND:
return LISTVIEW_EraseBackground(infoPtr, wParam, lParam);
return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam);
case WM_GETDLGCODE:
return DLGC_WANTCHARS | DLGC_WANTARROWS;
@ -9179,7 +9237,9 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return LISTVIEW_RButtonUp(infoPtr, (WORD)wParam, MAKEPOINTS(lParam));
case WM_SETCURSOR:
return LISTVIEW_SetCursor(infoPtr, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
if(LISTVIEW_SetCursor(infoPtr, (HWND)wParam, LOWORD(lParam), HIWORD(lParam)))
return TRUE;
goto fwd_msg;
case WM_SETFOCUS:
return LISTVIEW_SetFocus(infoPtr, (HWND)wParam);
@ -9225,6 +9285,7 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if ((uMsg >= WM_USER) && (uMsg < WM_APP))
ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
fwd_msg:
/* call default window procedure */
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}