Fix focus handling for owner draw listviews.

This commit is contained in:
Dimitrie O. Paun 2002-10-07 18:38:17 +00:00 committed by Alexandre Julliard
parent d308a8d4fe
commit 1c7bf6229f
1 changed files with 29 additions and 31 deletions

View File

@ -151,7 +151,6 @@ typedef struct tagLISTVIEW_INFO
BOOL bFocus; BOOL bFocus;
INT nFocusedItem; INT nFocusedItem;
RECT rcFocus; RECT rcFocus;
RECT rcLargeFocus; /* non-empty when a large item in ICON mode has focus */
DWORD dwStyle; /* the cached window GWL_STYLE */ DWORD dwStyle; /* the cached window GWL_STYLE */
DWORD dwLvExStyle; /* extended listview style */ DWORD dwLvExStyle; /* extended listview style */
HDPA hdpaItems; HDPA hdpaItems;
@ -729,6 +728,7 @@ static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg,
InvalidateRect(infoPtr->hwndSelf, rect, TRUE); \ InvalidateRect(infoPtr->hwndSelf, rect, TRUE); \
} while (0) } while (0)
/* FIXME: what if we show the focus on a large item in ICON mode? */
#define LISTVIEW_InvalidateItem(infoPtr, nItem) do { \ #define LISTVIEW_InvalidateItem(infoPtr, nItem) do { \
RECT rcItem; \ RECT rcItem; \
rcItem.left = LVIR_BOUNDS; \ rcItem.left = LVIR_BOUNDS; \
@ -1140,19 +1140,29 @@ static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr)
/*** /***
* Toggles (draws/erase) the focus rectangle. * 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 inline void LISTVIEW_ToggleFocusRect(LISTVIEW_INFO *infoPtr) static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, INT nItem, BOOL fShow)
{ {
TRACE("rcFocus=%s\n", debugrect(&infoPtr->rcFocus)); TRACE("fShow=%d, nItem=%d\n", fShow, nItem);
/* if we have a focus rectagle, draw it */ /* Here we are inneficient. We could, in theory, simply DrawFocusRect
if (!IsRectEmpty(&infoPtr->rcFocus)) * to erase/show the focus, without all this heavy duty redraw. However,
{ * note that there are cases where we can not do that: when the list is
HDC hdc = GetDC(infoPtr->hwndSelf); * in ICON mode, and the item is large, we must to invalidate it.
DrawFocusRect(hdc, &infoPtr->rcFocus); * Moreover, in the vast majority of cases, the selection status of
ReleaseDC(infoPtr->hwndSelf, hdc); * the item changes anyway, and so the item is invalidated already,
} * so not too much harm is done. If we do notice any flicker, we should
* refine this method. */
LISTVIEW_InvalidateItem(infoPtr, nItem);
} }
/*** /***
@ -2810,18 +2820,7 @@ static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL i
if (bResult && !infoPtr->bIsDrawing && lpLVItem->iSubItem == 0) if (bResult && !infoPtr->bIsDrawing && lpLVItem->iSubItem == 0)
{ {
if (oldFocus != infoPtr->nFocusedItem && infoPtr->bFocus) if (oldFocus != infoPtr->nFocusedItem && infoPtr->bFocus)
{ LISTVIEW_ShowFocusRect(infoPtr, oldFocus, FALSE);
LISTVIEW_ToggleFocusRect(infoPtr);
/* Note that ->rcLargeFocus is normally all zero, so
* no second InvalidateRect is issued.
*
* However, when a large icon style is drawn (LVS_ICON),
* the rectangle drawn is saved in rcLastDraw. That way
* the InvalidateRect will invalidate the entire area drawn
*/
if (!IsRectEmpty(&infoPtr->rcLargeFocus))
LISTVIEW_InvalidateRect(infoPtr, &infoPtr->rcLargeFocus);
}
LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem); LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem);
} }
/* restore text */ /* restore text */
@ -3236,7 +3235,6 @@ static BOOL LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, R
* that the background is complete * that the background is complete
*/ */
rcFocus = rcLabel; /* save for focus */ rcFocus = rcLabel; /* save for focus */
SetRectEmpty(&infoPtr->rcLargeFocus);
if ((uFormat & DT_NOCLIP) || (lvItem.state & LVIS_SELECTED)) if ((uFormat & DT_NOCLIP) || (lvItem.state & LVIS_SELECTED))
{ {
/* FIXME: why do we need this??? */ /* FIXME: why do we need this??? */
@ -3247,7 +3245,6 @@ static BOOL LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, R
DeleteObject(hBrush); DeleteObject(hBrush);
/* Save size of item drawing for next InvalidateRect */ /* Save size of item drawing for next InvalidateRect */
infoPtr->rcLargeFocus = rcFullText;
TRACE("focused/selected, rcFocus=%s\n", debugrect(&rcFocus)); TRACE("focused/selected, rcFocus=%s\n", debugrect(&rcFocus));
} }
/* else ? What if we are losing the focus? will we not get a complete /* else ? What if we are losing the focus? will we not get a complete
@ -3378,7 +3375,7 @@ static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode
dis.itemID = nItem; dis.itemID = nItem;
dis.itemAction = ODA_DRAWENTIRE; dis.itemAction = ODA_DRAWENTIRE;
if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED; if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED;
if (item.state & LVIS_FOCUSED) dis.itemState |= ODS_FOCUS; if (infoPtr->bFocus && (item.state & LVIS_FOCUSED)) dis.itemState |= ODS_FOCUS;
dis.hwndItem = infoPtr->hwndSelf; dis.hwndItem = infoPtr->hwndSelf;
dis.hDC = hdc; dis.hDC = hdc;
dis.rcItem.left = lpCols[0].rc.left; dis.rcItem.left = lpCols[0].rc.left;
@ -3675,7 +3672,7 @@ static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
LISTVIEW_RefreshIcon(infoPtr, hdc, uView == LVS_SMALLICON, cdmode); LISTVIEW_RefreshIcon(infoPtr, hdc, uView == LVS_SMALLICON, cdmode);
/* if we have a focus rect, draw it */ /* if we have a focus rect, draw it */
if (infoPtr->bFocus && !IsRectEmpty(&infoPtr->rcFocus)) if (infoPtr->bFocus && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED))
DrawFocusRect(hdc, &infoPtr->rcFocus); DrawFocusRect(hdc, &infoPtr->rcFocus);
/* unselect objects */ /* unselect objects */
@ -5406,6 +5403,8 @@ static LRESULT LISTVIEW_GetNextItem(LISTVIEW_INFO *infoPtr, INT nItem, UINT uFla
INT nCountPerColumn; INT nCountPerColumn;
INT i; INT i;
TRACE("nItem=%d, uFlags=%x\n", nItem, uFlags);
if ((nItem < -1) || (nItem >= GETITEMCOUNT(infoPtr))) return -1; if ((nItem < -1) || (nItem >= GETITEMCOUNT(infoPtr))) return -1;
ZeroMemory(&lvFindInfo, sizeof(lvFindInfo)); ZeroMemory(&lvFindInfo, sizeof(lvFindInfo));
@ -7277,8 +7276,7 @@ static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList, ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList,
&infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE); &infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE);
/* if we have focus, adjust rect */ /* if we have focus, adjust rect */
if (infoPtr->bFocus && !IsRectEmpty(&infoPtr->rcFocus)) OffsetRect(&infoPtr->rcFocus, dx, dy);
OffsetRect(&infoPtr->rcFocus, dx, dy);
UpdateWindow(infoPtr->hwndSelf); UpdateWindow(infoPtr->hwndSelf);
} }
@ -7646,7 +7644,7 @@ static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr)
notify_killfocus(infoPtr); notify_killfocus(infoPtr);
/* if we have a focus rectagle, get rid of it */ /* if we have a focus rectagle, get rid of it */
LISTVIEW_ToggleFocusRect(infoPtr); LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, FALSE);
/* invalidate the selected items before reseting focus flag */ /* invalidate the selected items before reseting focus flag */
LISTVIEW_InvalidateSelectedItems(infoPtr); LISTVIEW_InvalidateSelectedItems(infoPtr);
@ -8175,7 +8173,7 @@ static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
notify_setfocus(infoPtr); notify_setfocus(infoPtr);
/* put the focus rect back on */ /* put the focus rect back on */
LISTVIEW_ToggleFocusRect(infoPtr); LISTVIEW_ShowFocusRect(infoPtr, infoPtr->nFocusedItem, TRUE);
/* set window focus flag */ /* set window focus flag */
infoPtr->bFocus = TRUE; infoPtr->bFocus = TRUE;