CW's Listview changes
Dimitrie O. Paun
dimi at cs.toronto.edu
Tue Feb 5 01:11:21 CST 2002
OK people,
This one was a !@#$% pain in the neck to integrate. At times I simplified
the code at bit, and reindented it to fit with the overall style of the
file (even though I like the style in the patch much better :P)
This clears up my queue of patches that I was supposed to extract from
CW's office.tgz patch set.
Here it is, completely untested, but at least it compiles.
ChangeLog:
Codeweavers
Misc Listview fixes
-- cache text metrics for the font we're using
-- improved item hit detection
-- more debugging output
-- implement LVM_SETICONSPACING
-- lots of bugs squashed
--
Dimi.
Index: dlls/comctl32/listview.c
===================================================================
RCS file: /var/cvs/wine/dlls/comctl32/listview.c,v
retrieving revision 1.114
diff -u -r1.114 listview.c
--- dlls/comctl32/listview.c 4 Feb 2002 18:44:16 -0000 1.114
+++ dlls/comctl32/listview.c 5 Feb 2002 05:53:35 -0000
@@ -4,6 +4,7 @@
* Copyright 1998, 1999 Eric Kohl
* Copyright 1999 Luc Tourangeau
* Copyright 2000 Jason Mawdsley
+ * Copyright 2001 Codeweavers Inc.
* Copyright 2002 Dimitrie O. Paun
*
* NOTES
@@ -32,6 +33,16 @@
* LISTVIEW_ApproximateViewRect : incomplete
* LISTVIEW_Scroll : not implemented
* LISTVIEW_Update : not completed
+ *
+ * Known differences in message stream from native control (not known if
+ * these differences cause problems):
+ * LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases.
+ * LVM_SETITEM does not always issue LVN_ITEMCHANGING/LVN_ITEMCHANGED.
+ * WM_PAINT does LVN_GETDISPINFO in item order 0->n, native does n->0.
+ * WM_SETREDRAW(True) native does LVN_GETDISPINFO for all items and
+ * does *not* invoke DefWindowProc
+ * WM_CREATE does not issue WM_QUERYUISTATE and associated registry
+ * processing for "USEDOUBLECLICKTIME".
*/
#include <ctype.h>
@@ -40,6 +51,7 @@
#include <stdio.h>
#include "winbase.h"
+#include "winnt.h"
#include "heap.h"
#include "commctrl.h"
#include "debugtools.h"
@@ -50,6 +62,14 @@
typedef BOOL (*EditlblCallbackW)(HWND, LPWSTR, DWORD);
typedef BOOL (*EditlblCallbackA)(HWND, LPWSTR, DWORD);
+typedef struct tagLV_INTHIT
+{
+ LVHITTESTINFO ht;
+ DWORD distance; /* distance to closest item */
+ INT iDistItem; /* item number that is closest */
+} LV_INTHIT, *LPLV_INTHIT;
+
+
typedef struct tagEDITLABEL_ITEM
{
WNDPROC EditWndProc;
@@ -83,6 +103,7 @@
typedef struct tagLISTVIEW_INFO
{
+ HWND hwndSelf;
COLORREF clrBk;
COLORREF clrText;
COLORREF clrTextBk;
@@ -106,8 +127,10 @@
HWND hwndHeader;
HFONT hDefaultFont;
HFONT hFont;
+ INT ntmHeight; /* from GetTextMetrics from above font */
+ INT ntmAveCharWidth; /* from GetTextMetrics from above font */
BOOL bFocus;
- DWORD dwExStyle; /* extended listview style */
+ DWORD dwExStyle; /* extended listview style */
HDPA hdpaItems;
PFNLVCOMPARE pfnCompare;
LPARAM lParamSort;
@@ -115,11 +138,11 @@
INT nEditLabelItem;
EDITLABEL_ITEM *pedititem;
DWORD dwHoverTime;
- INT nColumnCount; /* the number of columns in this control */
+ INT nColumnCount; /* the number of columns in this control */
DWORD lastKeyPressTimestamp; /* Added */
- WPARAM charCode; /* Added */
- INT nSearchParamLength; /* Added */
+ WPARAM charCode; /* Added */
+ INT nSearchParamLength; /* Added */
WCHAR szSearchParam[ MAX_PATH ]; /* Added */
} LISTVIEW_INFO;
@@ -139,12 +162,19 @@
/* offset of items in report display mode */
#define REPORT_MARGINX 2
-/* padding for icon in large icon display mode */
-#define ICON_TOP_PADDING 2
-#define ICON_BOTTOM_PADDING 2
-
-/* padding for label in large icon display mode */
-#define LABEL_VERT_OFFSET 2
+/* padding for icon in large icon display mode
+ * ICON_TOP_PADDING_NOTHITABLE - space between top of box and area
+ * that HITTEST will see.
+ * ICON_TOP_PADDING_HITABLE - spacing between above and icon.
+ * ICON_TOP_PADDING - sum of the two above.
+ * ICON_BOTTOM_PADDING - between bottom of icon and top of text
+ * LABEL_VERT_OFFSET - between bottom of text and end of box
+ */
+#define ICON_TOP_PADDING_NOTHITABLE 2
+#define ICON_TOP_PADDING_HITABLE 2
+#define ICON_TOP_PADDING ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE
+#define ICON_BOTTOM_PADDING 4
+#define LABEL_VERT_OFFSET 10
/* default label width for items in list and small icon display modes */
#define DEFAULT_LABEL_WIDTH 40
@@ -178,6 +208,7 @@
* forward declarations
*/
static LRESULT LISTVIEW_GetItemT(HWND hwnd, LPLVITEMW lpLVItem, BOOL internal, BOOL isW);
+static INT LISTVIEW_SuperHitTestItem(HWND, LPLV_INTHIT, BOOL);
static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO, BOOL);
static INT LISTVIEW_GetCountPerRow(HWND);
static INT LISTVIEW_GetCountPerColumn(HWND);
@@ -188,6 +219,7 @@
static BOOL LISTVIEW_AddSubItemT(HWND, LPLVITEMW, BOOL);
static INT LISTVIEW_FindInsertPosition(HDPA, INT);
static INT LISTVIEW_GetItemHeight(HWND);
+static BOOL LISTVIEW_GetItemBoundBox(HWND, INT, LPRECT);
static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
static INT LISTVIEW_GetItemWidth(HWND);
@@ -229,6 +261,7 @@
/******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
#define KEY_DELAY 450
+#define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
static inline BOOL is_textW(LPCWSTR text)
{
@@ -460,6 +493,17 @@
return buf;
}
+static void LISTVIEW_DumpListview(LISTVIEW_INFO *iP, INT line)
+{
+ DWORD dwStyle = GetWindowLongW (iP->hwndSelf, GWL_STYLE);
+ TRACE("listview %08x at line %d, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n",
+ iP->hwndSelf, line, iP->clrBk, iP->clrText, iP->clrTextBk,
+ iP->nItemHeight, iP->nItemWidth, dwStyle);
+ TRACE("listview %08x at line %d, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx\n",
+ iP->hwndSelf, line, iP->himlNormal, iP->himlSmall, iP->himlState,
+ iP->nFocusedItem, iP->nHotItem, iP->dwExStyle);
+}
+
static BOOL
LISTVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc,
RECT rc)
@@ -639,7 +683,7 @@
/* update the search parameters */
infoPtr->lastKeyPressTimestamp=timestamp;
if (elapsed < KEY_DELAY) {
- if (infoPtr->nSearchParamLength < sizeof(infoPtr->szSearchParam)) {
+ if (infoPtr->nSearchParamLength < COUNTOF(infoPtr->szSearchParam)) {
infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode;
}
if (infoPtr->charCode != charCode) {
@@ -680,7 +724,7 @@
item.iItem = idx;
item.iSubItem = 0;
item.pszText = buffer;
- item.cchTextMax = sizeof(buffer);
+ item.cchTextMax = COUNTOF(buffer);
ListView_GetItemW( hwnd, &item );
/* check for a match */
@@ -761,6 +805,8 @@
INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
SCROLLINFO scrollInfo;
+ if (lStyle & LVS_NOSCROLL) return;
+
ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
scrollInfo.cbSize = sizeof(SCROLLINFO);
@@ -864,28 +910,28 @@
*/
static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
{
- if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
- FIXME(" LVS_EDITLABELS\n");
-
- if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
- FIXME(" LVS_NOLABELWRAP\n");
-
- if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
+ if ((LVS_TYPESTYLEMASK & lStyle) == LVS_NOSCROLL)
FIXME(" LVS_NOSCROLL\n");
- if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
+ if ((LVS_TYPESTYLEMASK & lStyle) == LVS_NOSORTHEADER)
FIXME(" LVS_NOSORTHEADER\n");
- if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
+ if ((LVS_TYPESTYLEMASK & lStyle) == LVS_OWNERDRAWFIXED)
FIXME(" LVS_OWNERDRAWFIXED\n");
- if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
+ if (lStyle & LVS_EDITLABELS)
+ FIXME(" LVS_EDITLABELS\n");
+
+ if (lStyle & LVS_NOLABELWRAP)
+ FIXME(" LVS_NOLABELWRAP\n");
+
+ if (lStyle & LVS_SHAREIMAGELISTS)
FIXME(" LVS_SHAREIMAGELISTS\n");
- if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
+ if (lStyle & LVS_SORTASCENDING)
FIXME(" LVS_SORTASCENDING\n");
- if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
+ if (lStyle & LVS_SORTDESCENDING)
FIXME(" LVS_SORTDESCENDING\n");
}
@@ -906,24 +952,32 @@
INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
POINT ptItem;
RECT rcView;
- INT i;
+ INT i, off_x=0, off_y=0;
if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
{
- ZeroMemory(&ptItem, sizeof(POINT));
+ /* Since SetItemPosition uses upper-left of icon, and for
+ style=LVS_ICON the icon is not left adjusted, get the offset */
+ if (uView == LVS_ICON)
+ {
+ off_y = ICON_TOP_PADDING;
+ off_x = (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
+ }
+ ptItem.x = off_x;
+ ptItem.y = off_y;
ZeroMemory(&rcView, sizeof(RECT));
-
+
if (nListWidth > infoPtr->nItemWidth)
{
for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
{
if (ptItem.x + infoPtr->nItemWidth > nListWidth)
{
- ptItem.x = 0;
+ ptItem.x = off_x;
ptItem.y += infoPtr->nItemHeight;
}
- ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
+ LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
ptItem.x += infoPtr->nItemWidth;
rcView.right = max(rcView.right, ptItem.x);
}
@@ -934,7 +988,7 @@
{
for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
{
- ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
+ LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
ptItem.y += infoPtr->nItemHeight;
}
@@ -963,11 +1017,19 @@
INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
POINT ptItem;
RECT rcView;
- INT i;
+ INT i, off_x=0, off_y=0;
if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
{
- ZeroMemory(&ptItem, sizeof(POINT));
+ /* Since SetItemPosition uses upper-left of icon, and for
+ style=LVS_ICON the icon is not left adjusted, get the offset */
+ if (uView == LVS_ICON)
+ {
+ off_y = ICON_TOP_PADDING;
+ off_x = (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
+ }
+ ptItem.x = off_x;
+ ptItem.y = off_y;
ZeroMemory(&rcView, sizeof(RECT));
if (nListHeight > infoPtr->nItemHeight)
@@ -976,11 +1038,11 @@
{
if (ptItem.y + infoPtr->nItemHeight > nListHeight)
{
- ptItem.y = 0;
+ ptItem.y = off_y;
ptItem.x += infoPtr->nItemWidth;
}
- ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
+ LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
ptItem.y += infoPtr->nItemHeight;
rcView.bottom = max(rcView.bottom, ptItem.y);
}
@@ -991,7 +1053,7 @@
{
for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
{
- ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
+ LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
ptItem.x += infoPtr->nItemWidth;
}
@@ -1267,11 +1329,41 @@
/***
* DESCRIPTION:
+ * Retrieves and saves important text metrics info for the current
+ * Listview font.
+ *
+ * PARAMETER(S):
+ * [I] HWND : window handle
+ *
+ */
+static VOID LISTVIEW_SaveTextMetrics(HWND hwnd)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
+ TEXTMETRICW tm;
+ HDC hdc = GetDC(hwnd);
+ HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
+ INT oldHeight, oldACW;
+
+ GetTextMetricsW(hdc, &tm);
+
+ oldHeight = infoPtr->ntmHeight;
+ oldACW = infoPtr->ntmAveCharWidth;
+ infoPtr->ntmHeight = tm.tmHeight;
+ infoPtr->ntmAveCharWidth = tm.tmAveCharWidth;
+
+ SelectObject(hdc, hOldFont);
+ ReleaseDC(hwnd, hdc);
+ TRACE("tmHeight old=%d,new=%d; tmAveCharWidth old=%d,new=%d\n",
+ oldHeight, infoPtr->ntmHeight, oldACW, infoPtr->ntmAveCharWidth);
+}
+
+
+/***
+ * DESCRIPTION:
* Calculates the height of an item.
*
* PARAMETER(S):
* [I] HWND : window handle
- * [I] LONG : window style
*
* RETURN:
* Returns item height.
@@ -1288,18 +1380,10 @@
}
else
{
- TEXTMETRICW tm;
- HDC hdc = GetDC(hwnd);
- HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
- GetTextMetricsW(hdc, &tm);
-
if(infoPtr->himlState || infoPtr->himlSmall)
- nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
+ nItemHeight = max(infoPtr->ntmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
else
- nItemHeight = tm.tmHeight;
-
- SelectObject(hdc, hOldFont);
- ReleaseDC(hwnd, hdc);
+ nItemHeight = infoPtr->ntmHeight;
}
return nItemHeight;
@@ -1928,16 +2012,22 @@
}
else
{
- POINT ptItem;
- POINT ptSelMark;
+ RECT rcItem;
+ RECT rcSelMark;
RECT rcSel;
- LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
- LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
- rcSel.left = min(ptSelMark.x, ptItem.x);
- rcSel.top = min(ptSelMark.y, ptItem.y);
- rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
- rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
+ LISTVIEW_GetItemBoundBox(hwnd, nItem, &rcItem);
+ LISTVIEW_GetItemBoundBox(hwnd, infoPtr->nSelectionMark, &rcSelMark);
+ rcSel.left = min(rcSelMark.left, rcItem.left);
+ rcSel.top = min(rcSelMark.top, rcItem.top);
+ rcSel.right = max(rcSelMark.right, rcItem.right);
+ rcSel.bottom = max(rcSelMark.bottom, rcItem.bottom);
LISTVIEW_SetSelectionRect(hwnd, rcSel);
+ TRACE("item %d (%d,%d)-(%d,%d), mark %d (%d,%d)-(%d,%d), sel (%d,%d)-(%d,%d)\n",
+ nItem, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
+ infoPtr->nSelectionMark,
+ rcSelMark.left, rcSelMark.top, rcSelMark.right, rcSelMark.bottom,
+ rcSel.left, rcSel.top, rcSel.right, rcSel.bottom);
+
}
LISTVIEW_SetItemFocus(hwnd, nItem);
@@ -3171,9 +3261,7 @@
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
UINT textoutOptions = ETO_CLIPPED | ETO_OPAQUE;
WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
- INT nDrawPosX = rcItem.left;
- INT nLabelWidth, rcWidth;
- TEXTMETRICW tm;
+ INT nDrawPosX, nLabelWidth, rcWidth;
LVITEMW lvItem;
RECT rcTemp;
@@ -3189,7 +3277,7 @@
lvItem.cchTextMax = DISP_TEXT_SIZE;
lvItem.pszText = szDispText;
*lvItem.pszText = '\0';
- LISTVIEW_GetItemW(hwnd, &lvItem, TRUE);
+ LISTVIEW_GetItemW(hwnd, &lvItem, FALSE);
TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE));
/* redraw the background of the item */
@@ -3198,7 +3286,10 @@
rcTemp.right = infoPtr->rcList.right;
else
rcTemp.right+=WIDTH_PADDING;
-
+
+ TRACE("background rect (%d,%d)-(%d,%d)\n",
+ rcTemp.left, rcTemp.top, rcTemp.right, rcTemp.bottom);
+
LISTVIEW_FillBackground(hwnd, hdc, &rcTemp);
if (lvItem.state & LVIS_SELECTED)
@@ -3228,18 +3319,17 @@
SetROP2(hdc, R2_COPYPEN);
}
+ /* draw the icon */
if (infoPtr->himlNormal != NULL)
{
- rcItem.top += ICON_TOP_PADDING;
- nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
if ((lvItem.state & LVIS_SELECTED) && (lvItem.iImage>=0))
{
- ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
+ ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, rcItem.left,
rcItem.top, ILD_SELECTED);
}
else if (lvItem.iImage>=0)
{
- ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
+ ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, rcItem.left,
rcItem.top, ILD_NORMAL);
}
}
@@ -3248,17 +3338,33 @@
if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
return;
+ /* Since rcItem.left is left point of icon, compute left point of item box */
+ rcItem.left -= ((infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2);
+ rcItem.right = rcItem.left + infoPtr->nItemWidth;
+ rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
+ TRACE("bound box for text+icon (%d,%d)-(%d,%d), iS.cx=%ld, nItemWidth=%d\n",
+ rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
+ infoPtr->iconSize.cx, infoPtr->nItemWidth);
+ TRACE("rcList (%d,%d)-(%d,%d), rcView (%d,%d)-(%d,%d)\n",
+ infoPtr->rcList.left, infoPtr->rcList.top,
+ infoPtr->rcList.right, infoPtr->rcList.bottom,
+ infoPtr->rcView.left, infoPtr->rcView.top,
+ infoPtr->rcView.right, infoPtr->rcView.bottom);
+
InflateRect(&rcItem, -(2*CAPTION_BORDER), 0);
rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
nLabelWidth = ListView_GetStringWidthW(hwnd, lvItem.pszText);
- GetTextMetricsW(hdc, &tm);
-
+ TRACE("rect for text sizing (%d,%d)-(%d,%d), text width %d\n",
+ rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
+ nLabelWidth);
+
/* append an ellipse ('...') if the caption won't fit in the rect */
rcWidth = max(0, rcItem.right - rcItem.left);
if (nLabelWidth > rcWidth)
{
/* give or take a couple, how many average sized chars would fit? */
- INT nCharsFit = tm.tmAveCharWidth > 0 ? rcWidth/tm.tmAveCharWidth+2 : 0;
+ INT nCharsFit = infoPtr->ntmAveCharWidth > 0 ?
+ rcWidth/infoPtr->ntmAveCharWidth + 2 : 0;
INT eos = min(strlenW(lvItem.pszText), nCharsFit);
if (eos > 0) lvItem.pszText[eos-1] = '.';
if (eos > 1) lvItem.pszText[eos-2] = '.';
@@ -3285,13 +3391,18 @@
}
/* draw label */
- rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
-
- ExtTextOutW(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
- &rcItem, lvItem.pszText, lstrlenW(lvItem.pszText), NULL);
-
+ rcItem.bottom = rcItem.top + infoPtr->ntmHeight + HEIGHT_PADDING;
+ TRACE("rect for text (%d,%d)-(%d,%d)\n",
+ rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
+ if (lstrlenW(lvItem.pszText))
+ {
+ ExtTextOutW(hdc, rcItem.left + CAPTION_BORDER, rcItem.top, textoutOptions,
+ &rcItem, lvItem.pszText, lstrlenW(lvItem.pszText), NULL);
- CopyRect(SuggestedFocus,&rcItem);
+ CopyRect(SuggestedFocus, &rcItem);
+ }
+ else
+ SetRectEmpty(SuggestedFocus);
}
/***
@@ -3690,7 +3801,7 @@
* Draw Focus Rect
*/
if (LISTVIEW_GetItemState(hwnd,i,LVIS_FOCUSED) &&
- infoPtr->bFocus)
+ infoPtr->bFocus && !IsRectEmpty(&SuggestedFocus))
Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
SuggestedFocus.right,SuggestedFocus.bottom);
}
@@ -3723,6 +3834,8 @@
DWORD cdmode;
RECT rect;
+ LISTVIEW_DumpListview (infoPtr, __LINE__);
+
GetClientRect(hwnd, &rect);
cdmode = LISTVIEW_SendCustomDrawNotify(hwnd,CDDS_PREPAINT,hdc,rect);
@@ -4520,35 +4633,38 @@
static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
- LVHITTESTINFO lvHitTestInfo;
+ LV_INTHIT lvIntHit;
INT nItem = -1;
RECT rcView;
+ TRACE("point %ld,%ld, direction %s\n", pt.x, pt.y,
+ (vkDirection == VK_DOWN) ? "VK_DOWN" :
+ ((vkDirection == VK_UP) ? "VK_UP" :
+ ((vkDirection == VK_LEFT) ? "VK_LEFT" : "VK_RIGHT")));
+
if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
{
- ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
- LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
- lvHitTestInfo.pt.x += pt.x;
- lvHitTestInfo.pt.y += pt.y;
-
- do
- {
- if (vkDirection == VK_DOWN)
- lvHitTestInfo.pt.y += infoPtr->nItemHeight;
- else if (vkDirection == VK_UP)
- lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
- else if (vkDirection == VK_LEFT)
- lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
- else if (vkDirection == VK_RIGHT)
- lvHitTestInfo.pt.x += infoPtr->nItemWidth;
-
- if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
- return -1;
- else
- nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE);
+ ZeroMemory(&lvIntHit, sizeof(lvIntHit));
+ LISTVIEW_GetOrigin(hwnd, &lvIntHit.ht.pt);
+ lvIntHit.ht.pt.x += pt.x;
+ lvIntHit.ht.pt.y += pt.y;
+
+ if (vkDirection == VK_DOWN)
+ lvIntHit.ht.pt.y += infoPtr->nItemHeight;
+ else if (vkDirection == VK_UP)
+ lvIntHit.ht.pt.y -= infoPtr->nItemHeight;
+ else if (vkDirection == VK_LEFT)
+ lvIntHit.ht.pt.x -= infoPtr->nItemWidth;
+ else if (vkDirection == VK_RIGHT)
+ lvIntHit.ht.pt.x += infoPtr->nItemWidth;
+ if (PtInRect(&rcView, lvIntHit.ht.pt) == FALSE)
+ return -1;
+ else
+ {
+ nItem = LISTVIEW_SuperHitTestItem(hwnd, &lvIntHit, TRUE);
+ return nItem == -1 ? lvIntHit.iDistItem : nItem;
}
- while (nItem == -1);
}
return nItem;
@@ -5256,32 +5372,32 @@
/***
* DESCRIPTION:
- * Retrieves the position (upper-left) of the listview control item.
+ * Retrieves the rectangle enclosing the item icon and text.
*
* PARAMETER(S):
* [I] HWND : window handle
* [I] INT : item index
- * [O] LPPOINT : coordinate information
+ * [O] LPRECT : coordinate information
*
* RETURN:
* SUCCESS : TRUE
* FAILURE : FALSE
*/
-static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
- LPPOINT lpptPosition)
+static BOOL LISTVIEW_GetItemBoundBox(HWND hwnd, INT nItem, LPRECT lpRect)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
- UINT uView = GetWindowLongW(hwnd, GWL_STYLE) & LVS_TYPEMASK;
+ LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
+ UINT uView = lStyle & LVS_TYPEMASK;
BOOL bResult = FALSE;
HDPA hdpaSubItems;
LISTVIEW_ITEM *lpItem;
INT nCountPerColumn;
INT nRow;
- TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem, lpptPosition);
+ TRACE("(hwnd=%x,nItem=%d,lpRect=%p)\n", hwnd, nItem, lpRect);
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
- (lpptPosition != NULL))
+ (lpRect != NULL))
{
if (uView == LVS_LIST)
{
@@ -5293,56 +5409,103 @@
nRow = nItem % nCountPerColumn;
if (nRow == 0)
{
- lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
- lpptPosition->y = 0;
+ lpRect->left = nItem / nCountPerColumn * infoPtr->nItemWidth;
+ lpRect->top = 0;
}
else
{
- lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
- lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
+ lpRect->left = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
+ lpRect->top = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
}
}
else
{
- lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
- lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
+ lpRect->left = nItem / nCountPerColumn * infoPtr->nItemWidth;
+ lpRect->top = nItem % nCountPerColumn * infoPtr->nItemHeight;
}
}
else if (uView == LVS_REPORT)
{
- SCROLLINFO scrollInfo;
bResult = TRUE;
- lpptPosition->x = REPORT_MARGINX;
- lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
+ lpRect->left = REPORT_MARGINX;
+ lpRect->top = ((nItem - ListView_GetTopIndex(hwnd)) *
infoPtr->nItemHeight) + infoPtr->rcList.top;
- /* Adjust position by scrollbar offset */
- ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
- scrollInfo.cbSize = sizeof(SCROLLINFO);
- scrollInfo.fMask = SIF_POS;
- GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
- lpptPosition->x -= scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
+ if (!(lStyle & LVS_NOSCROLL))
+ {
+ SCROLLINFO scrollInfo;
+ /* Adjust position by scrollbar offset */
+ ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
+ scrollInfo.cbSize = sizeof(SCROLLINFO);
+ scrollInfo.fMask = SIF_POS;
+ GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
+ lpRect->left -= scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
+ }
}
- else
+ else /* either LVS_ICON or LVS_SMALLICON */
{
- hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
- if (hdpaSubItems != NULL)
+ if ((hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
{
- lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
- if (lpItem != NULL)
+ if ((lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
{
bResult = TRUE;
- lpptPosition->x = lpItem->ptPosition.x;
- lpptPosition->y = lpItem->ptPosition.y;
+ lpRect->left = lpItem->ptPosition.x;
+ lpRect->top = lpItem->ptPosition.y;
}
}
}
}
+ lpRect->right = lpRect->left + infoPtr->nItemWidth;
+ lpRect->bottom = lpRect->top + infoPtr->nItemHeight;
+ TRACE("result %s: (%d,%d)-(%d,%d)\n", bResult ? "TRUE" : "FALSE",
+ lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
return bResult;
}
/***
* DESCRIPTION:
+ * Retrieves the position (upper-left) of the listview control item.
+ * Note that for LVS_ICON style, the upper-left is that of the icon
+ * and not the bounding box.
+ *
+ * PARAMETER(S):
+ * [I] HWND : window handle
+ * [I] INT : item index
+ * [O] LPPOINT : coordinate information
+ *
+ * RETURN:
+ * SUCCESS : TRUE
+ * FAILURE : FALSE
+ */
+static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem, LPPOINT lpptPosition)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
+ BOOL bResult = FALSE;
+ RECT rcBounding;
+
+ TRACE("(hwnd=%x, nItem=%d, lpptPosition=%p)\n", hwnd, nItem, lpptPosition);
+
+ if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
+ (lpptPosition != NULL))
+ {
+ bResult = LISTVIEW_GetItemBoundBox(hwnd, nItem, &rcBounding);
+ lpptPosition->x = rcBounding.left;
+ lpptPosition->y = rcBounding.top;
+ if (uView == LVS_ICON)
+ {
+ lpptPosition->y += ICON_TOP_PADDING;
+ lpptPosition->x += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
+ }
+ TRACE("result %s (%ld,%ld)\n", bResult ? "TRUE" : "FALSE",
+ lpptPosition->x, lpptPosition->y);
+ }
+ return bResult;
+}
+
+
+/***
+ * DESCRIPTION:
* Retrieves the bounding rectangle for a listview control item.
*
* PARAMETER(S):
@@ -5370,13 +5533,11 @@
BOOL bResult = FALSE;
POINT ptOrigin;
POINT ptItem;
- HDC hdc;
- HFONT hOldFont;
INT nLeftPos;
INT nLabelWidth;
INT nIndent;
- TEXTMETRICW tm;
LVITEMW lvItem;
+ RECT rcInternal;
TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
@@ -5399,11 +5560,10 @@
if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
{
- if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
- {
switch(lprc->left)
{
- case LVIR_ICON:
+ case LVIR_ICON:
+ if (!ListView_GetItemPosition(hwnd, nItem, &ptItem)) break;
if (uView == LVS_ICON)
{
if (infoPtr->himlNormal != NULL)
@@ -5456,7 +5616,8 @@
}
break;
- case LVIR_LABEL:
+ case LVIR_LABEL:
+ if (!ListView_GetItemPosition(hwnd, nItem, &ptItem)) break;
if (uView == LVS_ICON)
{
if (infoPtr->himlNormal != NULL)
@@ -5466,7 +5627,7 @@
bResult = TRUE;
lprc->left = ptItem.x + ptOrigin.x;
lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
- ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
+ ICON_BOTTOM_PADDING);
nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
{
@@ -5478,13 +5639,8 @@
lprc->left += 1;
lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
}
-
- hdc = GetDC(hwnd);
- hOldFont = SelectObject(hdc, infoPtr->hFont);
- GetTextMetricsW(hdc, &tm);
- lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
- SelectObject(hdc, hOldFont);
- ReleaseDC(hwnd, hdc);
+
+ lprc->bottom = lprc->top + infoPtr->ntmHeight + HEIGHT_PADDING;
}
}
}
@@ -5539,17 +5695,53 @@
break;
case LVIR_BOUNDS:
+ if (!LISTVIEW_GetItemBoundBox(hwnd, nItem, &rcInternal)) break;
+ ptItem.x = rcInternal.left;
+ ptItem.y = rcInternal.top;
if (uView == LVS_ICON)
{
if (infoPtr->himlNormal != NULL)
{
if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
{
+ INT text_left, text_right, icon_left, text_pos_x;
+ /* for style LVS_ICON bounds
+ * left = min(icon.left, text.left)
+ * right = max(icon.right, text.right)
+ * top = boundbox.top + NOTHITABLE
+ * bottom = text.bottom + 1
+ */
bResult = TRUE;
- lprc->left = ptItem.x + ptOrigin.x;
- lprc->top = ptItem.y + ptOrigin.y;
- lprc->right = lprc->left + infoPtr->iconSpacing.cx;
- lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
+ icon_left = text_left = ptItem.x;
+
+ /* Correct ptItem to icon upper-left */
+ icon_left += (infoPtr->nItemWidth - infoPtr->iconSize.cx)/2;
+ ptItem.y += ICON_TOP_PADDING;
+
+ /* Compute the label left and right */
+ nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
+ text_pos_x = infoPtr->iconSpacing.cx - 2*CAPTION_BORDER - nLabelWidth;
+ if (text_pos_x > 1)
+ {
+ text_left += text_pos_x / 2;
+ text_right = text_left + nLabelWidth + 2*CAPTION_BORDER;
+ }
+ else
+ {
+ text_left += 1;
+ text_right = text_left + infoPtr->iconSpacing.cx - 1;
+ }
+
+ /* Compute rectangle w/o the text height */
+ lprc->left = min(icon_left, text_left) + ptOrigin.x;
+ lprc->right = max(icon_left + infoPtr->iconSize.cx,
+ text_right) + ptOrigin.x;
+ lprc->top = ptItem.y + ptOrigin.y - ICON_TOP_PADDING_HITABLE;
+ lprc->bottom = lprc->top + ICON_TOP_PADDING_HITABLE
+ + infoPtr->iconSize.cy + 1
+ + ICON_BOTTOM_PADDING;
+
+ lprc->bottom += (infoPtr->ntmHeight + HEIGHT_PADDING);
}
}
}
@@ -5614,6 +5806,7 @@
break;
case LVIR_SELECTBOUNDS:
+ if (!ListView_GetItemPosition(hwnd, nItem, &ptItem)) break;
if (uView == LVS_ICON)
{
if (infoPtr->himlNormal != NULL)
@@ -5693,8 +5886,11 @@
}
break;
}
- }
}
+
+ TRACE("result %s (%d,%d)-(%d,%d)\n", bResult ? "TRUE" : "FALSE",
+ lprc->left, lprc->top, lprc->right, lprc->bottom);
+
return bResult;
}
@@ -6134,29 +6330,27 @@
/***
* DESCRIPTION:
- * Determines which section of the item was selected (if any).
+ * Determines item if a hit or closest if not
*
* PARAMETER(S):
* [I] HWND : window handle
- * [IO] LPLVHITTESTINFO : hit test information
+ * [IO] LPLV_INTHIT : hit test information
* [I] subitem : fill out iSubItem.
*
* RETURN:
- * SUCCESS : item index
+ * SUCCESS : item index of hit
* FAILURE : -1
*/
-static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo,
- BOOL subitem)
+static INT LISTVIEW_SuperHitTestItem(HWND hwnd, LPLV_INTHIT lpInt, BOOL subitem)
{
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
LONG lStyle = GetWindowLongW(hwnd, GWL_STYLE);
UINT uView = lStyle & LVS_TYPEMASK;
INT i,topindex,bottomindex;
RECT rcItem;
+ DWORD xterm, yterm, dist;
-
- TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
- lpHitTestInfo->pt.y);
+ TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpInt->ht.pt.x, lpInt->ht.pt.y);
topindex = ListView_GetTopIndex(hwnd);
if (uView == LVS_REPORT)
@@ -6169,50 +6363,97 @@
bottomindex = GETITEMCOUNT(infoPtr);
}
+ lpInt->distance = 0x7fffffff;
+ lpInt->iDistItem = -1;
+
for (i = topindex; i < bottomindex; i++)
{
rcItem.left = LVIR_BOUNDS;
- if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
+ if (LISTVIEW_GetItemRect(hwnd, i, &rcItem))
{
- if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
+ if (PtInRect(&rcItem, lpInt->ht.pt))
{
rcItem.left = LVIR_ICON;
- if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
+ if (LISTVIEW_GetItemRect(hwnd, i, &rcItem))
{
- if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
+ if (PtInRect(&rcItem, lpInt->ht.pt))
{
- lpHitTestInfo->flags = LVHT_ONITEMICON;
- lpHitTestInfo->iItem = i;
- if (subitem) lpHitTestInfo->iSubItem = 0;
+ lpInt->ht.flags = LVHT_ONITEMICON;
+ lpInt->ht.iItem = i;
+ if (subitem) lpInt->ht.iSubItem = 0;
return i;
}
}
rcItem.left = LVIR_LABEL;
- if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
+ if (LISTVIEW_GetItemRect(hwnd, i, &rcItem))
{
- if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
+ if (PtInRect(&rcItem, lpInt->ht.pt))
{
- lpHitTestInfo->flags = LVHT_ONITEMLABEL;
- lpHitTestInfo->iItem = i;
- if (subitem) lpHitTestInfo->iSubItem = 0;
+ lpInt->ht.flags = LVHT_ONITEMLABEL;
+ lpInt->ht.iItem = i;
+ if (subitem) lpInt->ht.iSubItem = 0;
return i;
}
}
- lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
- lpHitTestInfo->iItem = i;
- if (subitem) lpHitTestInfo->iSubItem = 0;
+ lpInt->ht.flags = LVHT_ONITEMSTATEICON;
+ lpInt->ht.iItem = i;
+ if (subitem) lpInt->ht.iSubItem = 0;
return i;
}
+ else
+ {
+ /*
+ * Now compute distance from point to center of boundary
+ * box. Since we are only interested in the relative
+ * distance, we can skip the nasty square root operation
+ */
+ xterm = rcItem.left + (rcItem.right - rcItem.left)/2 - lpInt->ht.pt.x;
+ yterm = rcItem.top + (rcItem.bottom - rcItem.top)/2 - lpInt->ht.pt.y;
+ dist = xterm * xterm + yterm * yterm;
+ if (dist < lpInt->distance)
+ {
+ lpInt->distance = dist;
+ lpInt->iDistItem = i;
+ }
+ }
}
}
- lpHitTestInfo->flags = LVHT_NOWHERE;
+ lpInt->ht.flags = LVHT_NOWHERE;
+ TRACE("no hit, closest item %d, distance %ld\n", lpInt->iDistItem, lpInt->distance);
return -1;
}
+ /***
+ * DESCRIPTION:
+ * Determines which section of the item was selected (if any).
+ *
+ * PARAMETER(S):
+ * [I] HWND : window handle
+ * [IO] LPLVHITTESTINFO : hit test information
+ * [I] subitem : fill out iSubItem.
+ *
+ * RETURN:
+ * SUCCESS : item index
+ * FAILURE : -1
+ */
+static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo, BOOL subitem)
+{
+ INT ret;
+ LV_INTHIT lv_inthit;
+
+ TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
+ lpHitTestInfo->pt.y);
+
+ memcpy(&lv_inthit, lpHitTestInfo, sizeof(LVHITTESTINFO));
+ ret = LISTVIEW_SuperHitTestItem(hwnd, &lv_inthit, subitem);
+ memcpy(lpHitTestInfo, &lv_inthit, sizeof(LVHITTESTINFO));
+ return ret;
+}
+
/***
* DESCRIPTION:
* Determines which listview item is located at the specified position.
@@ -6917,7 +7158,65 @@
return oldHoverTime;
}
-/* LISTVIEW_SetIconSpacing */
+/***
+ * DESCRIPTION:
+ * Sets spacing for icons of LVS_ICON style.
+ *
+ * PARAMETER(S):
+ * [I] HWND : window handle
+ * [I] DWORD : MAKELONG(cx, cy)
+ *
+ * RETURN:
+ * MAKELONG(oldcx, oldcy)
+ */
+static LRESULT LISTVIEW_SetIconSpacing(HWND hwnd, DWORD spacing)
+{
+ LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
+ INT cy = HIWORD(spacing);
+ INT cx = LOWORD(spacing);
+ DWORD oldspacing;
+ LONG lStyle = GetWindowLongA(hwnd, 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);
+
+ 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(hwnd);
+ }
+ if (cy)
+ infoPtr->iconSpacing.cy = cy;
+ else
+ { /* if 0 then compute height */
+ if (uView == LVS_ICON)
+ infoPtr->iconSpacing.cy = infoPtr->iconSize.cy + infoPtr->ntmHeight
+ + ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_OFFSET;
+ else /* FIXME: unknown computation for non LVS_ICON - this is a guess */
+ infoPtr->iconSpacing.cy = LISTVIEW_GetItemHeight(hwnd);
+ }
+
+ TRACE("old=(%d,%d), new=(%ld,%ld)\n", LOWORD(oldspacing), HIWORD(oldspacing),
+ infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
+
+ /* these depend on the iconSpacing */
+ infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
+ infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
+
+ return oldspacing;
+}
/***
* DESCRIPTION:
@@ -6988,6 +7287,13 @@
{
int precount,topvisible;
+ TRACE("LVS_OWNERDATA is set!\n");
+ if (dwFlags & (LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL))
+ FIXME("flags %s %s not implemented\n",
+ (dwFlags & LVSICF_NOINVALIDATEALL) ? "LVSICF_NOINVALIDATEALL"
+ : "",
+ (dwFlags & LVSICF_NOSCROLL) ? "LVSICF_NOSCROLL" : "");
+
/*
* Internally remove all the selections.
*/
@@ -7014,7 +7320,13 @@
}
else
{
- FIXME("setitemcount not done for non-ownerdata\n");
+ /* According to MSDN for non-LVS_OWNERDATA this is just
+ * a performance issue. The control allocates its internal
+ * data structures for the number of items specified. It
+ * cuts down on the number of memory allocations. Therefore
+ * we will just issue a WARN here
+ */
+ WARN("for non-ownerdata performance option not implemented.\n");
}
return TRUE;
@@ -7057,9 +7369,54 @@
{
if ( (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)) )
{
+ POINT orig;
bResult = TRUE;
+ orig = lpItem->ptPosition;
+ if ((nPosX == -1) && (nPosY == -1))
+ {
+ /* This point value seems to be an undocumented feature. The
+ * best guess is that it means either at the origin, or at
+ * the true beginning of the list. I will assume the origin.
+ */
+ POINT pt1;
+ if (!LISTVIEW_GetOrigin(hwnd, &pt1))
+ {
+ pt1.x = 0;
+ pt1.y = 0;
+ }
+ nPosX = pt1.x;
+ nPosY = pt1.y;
+ if (uView == LVS_ICON)
+ {
+ nPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
+ nPosY += ICON_TOP_PADDING;
+ }
+ TRACE("requested special (-1,-1), set to origin (%ld,%ld)\n",
+ nPosX, nPosY);
+ }
+
lpItem->ptPosition.x = nPosX;
lpItem->ptPosition.y = nPosY;
+ if (uView == LVS_ICON)
+ {
+ lpItem->ptPosition.y -= ICON_TOP_PADDING;
+ lpItem->ptPosition.x -= (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
+ if ((lpItem->ptPosition.y < 0) || (lpItem->ptPosition.x < 0))
+ {
+ FIXME("failed orig (%ld,%ld), intent (%ld,%ld), is (%ld, %ld), setting neg to 0\n",
+ orig.x, orig.y, nPosX, nPosY, lpItem->ptPosition.x, lpItem->ptPosition.y);
+
+ /*
+ if (lpItem->ptPosition.x < 0) lpItem->ptPosition.x = 0;
+ if (lpItem->ptPosition.y < 0) lpItem->ptPosition.y = 0;
+ */
+ }
+ else
+ {
+ TRACE("orig (%ld,%ld), intent (%ld,%ld), is (%ld,%ld)\n",
+ orig.x, orig.y, nPosX, nPosY, lpItem->ptPosition.x, lpItem->ptPosition.y);
+ }
+ }
}
}
}
@@ -7387,6 +7744,7 @@
infoPtr->clrTextBk = CLR_DEFAULT;
/* set default values */
+ infoPtr->hwndSelf = hwnd;
infoPtr->uCallbackMask = 0;
infoPtr->nFocusedItem = -1;
infoPtr->nSelectionMark = -1;
@@ -7402,6 +7760,7 @@
SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
infoPtr->hDefaultFont = CreateFontIndirectW(&logFont);
infoPtr->hFont = infoPtr->hDefaultFont;
+ LISTVIEW_SaveTextMetrics(hwnd);
/* create header */
infoPtr->hwndHeader = CreateWindowW(WC_HEADERW, (LPCWSTR)NULL,
@@ -8333,6 +8692,8 @@
LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongW(hwnd, 0);
POINT ptPosition;
INT nItem;
+ NMLISTVIEW nmlv;
+ LVHITTESTINFO lvHitTestInfo;
TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
@@ -8361,6 +8722,25 @@
{
LISTVIEW_RemoveAllSelections(hwnd);
}
+
+ lvHitTestInfo.pt.x = wPosX;
+ lvHitTestInfo.pt.y = wPosY;
+
+ /* Send NM_RClICK notification */
+ ZeroMemory(&nmlv, sizeof(nmlv));
+ if (LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE) != -1)
+ {
+ nmlv.iItem = lvHitTestInfo.iItem;
+ nmlv.iSubItem = lvHitTestInfo.iSubItem;
+ }
+ else
+ {
+ nmlv.iItem = -1;
+ nmlv.iSubItem = 0;
+ }
+ nmlv.ptAction.x = wPosX;
+ nmlv.ptAction.y = wPosY;
+ listview_notify(hwnd, NM_RCLICK, &nmlv);
return 0;
}
@@ -8387,29 +8767,8 @@
if (infoPtr->bRButtonDown)
{
- LVHITTESTINFO lvHitTestInfo;
- NMLISTVIEW nmlv;
POINT pt;
- lvHitTestInfo.pt.x = wPosX;
- lvHitTestInfo.pt.y = wPosY;
-
- /* Send NM_RClICK notification */
- ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
- if (LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo, TRUE) != -1)
- {
- nmlv.iItem = lvHitTestInfo.iItem;
- nmlv.iSubItem = lvHitTestInfo.iSubItem;
- }
- else
- {
- nmlv.iItem = -1;
- nmlv.iSubItem = 0;
- }
- nmlv.ptAction.x = wPosX;
- nmlv.ptAction.y = wPosY;
- listview_notify(hwnd, NM_RCLICK, &nmlv);
-
pt.x = wPosX;
pt.y = wPosY;
@@ -8474,6 +8833,7 @@
TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
+ LISTVIEW_SaveTextMetrics(hwnd);
if (uView == LVS_REPORT)
{
@@ -8786,7 +9146,9 @@
case LVM_GETHEADER:
return LISTVIEW_GetHeader(hwnd);
-/* case LVM_GETHOTCURSOR: */
+ case LVM_GETHOTCURSOR:
+ FIXME("LVM_GETHOTCURSOR: unimplemented\n");
+ return FALSE;
case LVM_GETHOTITEM:
return LISTVIEW_GetHotItem(hwnd);
@@ -8797,7 +9159,10 @@
case LVM_GETIMAGELIST:
return LISTVIEW_GetImageList(hwnd, (INT)wParam);
-/* case LVM_GETISEARCHSTRING: */
+ case LVM_GETISEARCHSTRINGA:
+ case LVM_GETISEARCHSTRINGW:
+ FIXME("LVM_GETISEARCHSTRING: unimplemented\n");
+ return FALSE;
case LVM_GETITEMA:
return LISTVIEW_GetItemT(hwnd, (LPLVITEMW)lParam, FALSE, FALSE);
@@ -8821,17 +9186,17 @@
return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
case LVM_GETITEMTEXTA:
- LISTVIEW_GetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, FALSE);
- break;
+ return LISTVIEW_GetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, FALSE);
case LVM_GETITEMTEXTW:
- LISTVIEW_GetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, TRUE);
- break;
+ return LISTVIEW_GetItemTextT(hwnd, (INT)wParam, (LPLVITEMW)lParam, TRUE);
case LVM_GETNEXTITEM:
return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
-/* case LVM_GETNUMBEROFWORKAREAS: */
+ case LVM_GETNUMBEROFWORKAREAS:
+ FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n");
+ return 1;
case LVM_GETORIGIN:
return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
@@ -8848,7 +9213,9 @@
case LVM_GETSTRINGWIDTHW:
return LISTVIEW_GetStringWidthT(hwnd, (LPCWSTR)lParam, TRUE);
-/* case LVM_GETSUBITEMRECT: */
+ case LVM_GETSUBITEMRECT:
+ FIXME("LVM_GETSUBITEMRECT: unimplemented\n");
+ return FALSE;
case LVM_GETTEXTBKCOLOR:
return LISTVIEW_GetTextBkColor(hwnd);
@@ -8856,17 +9223,23 @@
case LVM_GETTEXTCOLOR:
return LISTVIEW_GetTextColor(hwnd);
-/* case LVM_GETTOOLTIPS: */
+ case LVM_GETTOOLTIPS:
+ FIXME("LVM_GETTOOLTIPS: unimplemented\n");
+ return FALSE;
case LVM_GETTOPINDEX:
return LISTVIEW_GetTopIndex(hwnd);
-/* case LVM_GETUNICODEFORMAT: */
+ /*case LVM_GETUNICODEFORMAT:
+ FIXME("LVM_GETUNICODEFORMAT: unimplemented\n");
+ return FALSE;*/
case LVM_GETVIEWRECT:
return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
-/* case LVM_GETWORKAREAS: */
+ case LVM_GETWORKAREAS:
+ FIXME("LVM_GETWORKAREAS: unimplemented\n");
+ return FALSE;
case LVM_HITTEST:
return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
@@ -8920,7 +9293,8 @@
case LVM_SETHOVERTIME:
return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
-/* case LVM_SETICONSPACING: */
+ case LVM_SETICONSPACING:
+ return LISTVIEW_SetIconSpacing(hwnd, (DWORD)lParam);
case LVM_SETIMAGELIST:
return (LRESULT)LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
@@ -9245,15 +9619,15 @@
if (einfo->EditLblCb)
{
- WCHAR *buffer = NULL;
+ LPWSTR buffer = NULL;
if (!cancel)
{
- int len = 1 + isW ? GetWindowTextLengthW(hwnd) : GetWindowTextLengthA(hwnd);
+ DWORD len = 1 + isW ? GetWindowTextLengthW(hwnd) : GetWindowTextLengthA(hwnd);
- if (len > 1)
+ if (len)
{
- if ( (buffer = COMCTL32_Alloc(len*(isW ? sizeof(WCHAR) : sizeof(CHAR)))) )
+ if ( (buffer = COMCTL32_Alloc((len+1) * (isW ? sizeof(WCHAR) : sizeof(CHAR)))) )
{
if (isW) GetWindowTextW(hwnd, buffer, len);
else GetWindowTextA(hwnd, (CHAR*)buffer, len);
More information about the wine-patches
mailing list