Listview updates (take 2)
Dimitrie O. Paun
dpaun at rogers.com
Sat Sep 14 02:53:46 CDT 2002
Alexandre, this patch obsoletes my previous "Listview updates".
I found a one liner bug which messed up callbacks completely
in the previous one, plus a lot more cleanups:
diffstat diffs/listview.diff
listview.c | 1876 +++++++++++++++++++++++--------------------------------------
1 files changed, 716 insertions(+), 1160 deletions(-)
ChangeLog
-- grand rewrite for {Get,Set,Insert}Item & Co.
-- many bugs fixed
-- callback items are better supported
-- improvements in rendering speed
-- change VOID to void
-- many code cleanups, and simplifications
-- documentation updates
Index: dlls/comctl32/listview.c
===================================================================
RCS file: /var/cvs/wine/dlls/comctl32/listview.c,v
retrieving revision 1.143
diff -u -r1.143 listview.c
--- dlls/comctl32/listview.c 13 Sep 2002 17:41:32 -0000 1.143
+++ dlls/comctl32/listview.c 14 Sep 2002 07:25:51 -0000
@@ -84,23 +84,26 @@
INT iDistItem; /* item number that is closest */
} LV_INTHIT, *LPLV_INTHIT;
-
-typedef struct tagLISTVIEW_SUBITEM
+typedef struct tagITEMHDR
{
LPWSTR pszText;
INT iImage;
+} ITEMHDR, *LPITEMHDR;
+
+typedef struct tagLISTVIEW_SUBITEM
+{
+ ITEMHDR hdr;
INT iSubItem;
} LISTVIEW_SUBITEM;
typedef struct tagLISTVIEW_ITEM
{
- LPWSTR pszText;
- INT iImage;
+ ITEMHDR hdr;
UINT state;
LPARAM lParam;
INT iIndent;
POINT ptPosition;
-
+ BOOL valid;
} LISTVIEW_ITEM;
typedef struct tagLISTVIEW_SELECTION
@@ -112,6 +115,7 @@
typedef struct tagLISTVIEW_INFO
{
HWND hwndSelf;
+ HBRUSH hBkBrush;
COLORREF clrBk;
COLORREF clrText;
COLORREF clrTextBk;
@@ -244,12 +248,10 @@
static INT LISTVIEW_HitTestItem(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL);
static INT LISTVIEW_GetCountPerRow(LISTVIEW_INFO *);
static INT LISTVIEW_GetCountPerColumn(LISTVIEW_INFO *);
-static VOID LISTVIEW_AlignLeft(LISTVIEW_INFO *);
-static VOID LISTVIEW_AlignTop(LISTVIEW_INFO *);
-static VOID LISTVIEW_AddGroupSelection(LISTVIEW_INFO *, INT);
-static VOID LISTVIEW_AddSelection(LISTVIEW_INFO *, INT);
-static BOOL LISTVIEW_AddSubItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
-static INT LISTVIEW_FindInsertPosition(HDPA, INT);
+static void LISTVIEW_AlignLeft(LISTVIEW_INFO *);
+static void LISTVIEW_AlignTop(LISTVIEW_INFO *);
+static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *, INT);
+static void LISTVIEW_AddSelection(LISTVIEW_INFO *, INT);
static INT LISTVIEW_GetItemHeight(LISTVIEW_INFO *);
static BOOL LISTVIEW_GetItemBoundBox(LISTVIEW_INFO *, INT, LPRECT);
static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT);
@@ -258,25 +260,19 @@
static INT LISTVIEW_GetItemWidth(LISTVIEW_INFO *);
static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *, INT);
static LRESULT LISTVIEW_GetOrigin(LISTVIEW_INFO *, LPPOINT);
-static INT LISTVIEW_CalculateWidth(LISTVIEW_INFO *, INT);
-static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
static LRESULT LISTVIEW_GetViewRect(LISTVIEW_INFO *, LPRECT);
-static BOOL LISTVIEW_InitItemT(LISTVIEW_INFO *, LISTVIEW_ITEM *, LPLVITEMW, BOOL);
-static BOOL LISTVIEW_InitSubItemT(LISTVIEW_INFO *, LISTVIEW_SUBITEM *, LPLVITEMW, BOOL);
static INT LISTVIEW_MouseSelection(LISTVIEW_INFO *, POINT);
static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
-static VOID LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT);
+static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT);
static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
static BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *, INT);
static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *, INT, LONG, LONG);
-static VOID LISTVIEW_UpdateScroll(LISTVIEW_INFO *);
-static VOID LISTVIEW_SetSelection(LISTVIEW_INFO *, INT);
+static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *);
+static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT);
static BOOL LISTVIEW_UpdateSize(LISTVIEW_INFO *);
-static BOOL LISTVIEW_SetSubItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
static LRESULT LISTVIEW_SetViewRect(LISTVIEW_INFO *, LPRECT);
-static BOOL LISTVIEW_ToggleSelection(LISTVIEW_INFO *, INT);
-static VOID LISTVIEW_UnsupportedStyles(LONG);
+static void LISTVIEW_UnsupportedStyles(LONG);
static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *, INT, BOOL);
static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM);
static LRESULT LISTVIEW_SortItems(LISTVIEW_INFO *, PFNLVCOMPARE, LPARAM);
@@ -285,11 +281,8 @@
static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT);
static LRESULT LISTVIEW_GetItemState(LISTVIEW_INFO *, INT, UINT);
static LRESULT LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, LPLVITEMW);
-static BOOL LISTVIEW_IsSelected(LISTVIEW_INFO *, INT);
-static VOID LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO *, INT, INT);
-static void LISTVIEW_FillBackground(LISTVIEW_INFO *, HDC, LPRECT);
+static void LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO *, INT, INT);
static void LISTVIEW_UpdateLargeItemLabelRect (LISTVIEW_INFO *, int, RECT*);
-static void LISTVIEW_SuperFillBackground(LISTVIEW_INFO *, HDC, LPRECT, COLORREF);
static LRESULT LISTVIEW_GetColumnT(LISTVIEW_INFO *, INT, LPLVCOLUMNW, BOOL);
static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND);
static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT, HWND);
@@ -366,16 +359,45 @@
* dest is a pointer to a Unicode string
* src is a pointer to a string (Unicode if isW, ANSI if !isW)
*/
-static inline BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW)
+static BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW)
{
- LPWSTR pszText = textdupTtoW(src, isW);
BOOL bResult = TRUE;
- if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL;
- bResult = Str_SetPtrW(dest, pszText);
- textfreeT(pszText, isW);
+
+ if (src == LPSTR_TEXTCALLBACKW)
+ {
+ if (is_textW(*dest)) COMCTL32_Free(*dest);
+ *dest = LPSTR_TEXTCALLBACKW;
+ }
+ else
+ {
+ LPWSTR pszText = textdupTtoW(src, isW);
+ if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL;
+ bResult = Str_SetPtrW(dest, pszText);
+ textfreeT(pszText, isW);
+ }
return bResult;
}
+/*
+ * compares a Unicode to a Unicode/ANSI text string
+ */
+static inline int textcmpWT(LPWSTR aw, LPWSTR bt, BOOL isW)
+{
+ if (!aw) return bt ? -1 : 0;
+ if (!bt) return aw ? 1 : 0;
+ if (aw == LPSTR_TEXTCALLBACKW)
+ return bt == LPSTR_TEXTCALLBACKW ? 0 : -1;
+ if (bt != LPSTR_TEXTCALLBACKW)
+ {
+ LPWSTR bw = textdupTtoW(bt, isW);
+ int r = bw ? lstrcmpW(aw, bw) : 1;
+ textfreeT(bw, isW);
+ return r;
+ }
+
+ return 1;
+}
+
static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL isW)
{
@@ -597,9 +619,9 @@
dwItemSpec=iItem;
uItemState=0;
- if (LISTVIEW_IsSelected(infoPtr,iItem)) uItemState|=CDIS_SELECTED;
- if (iItem==infoPtr->nFocusedItem) uItemState|=CDIS_FOCUS;
- if (iItem==infoPtr->nHotItem) uItemState|=CDIS_HOT;
+ if (LISTVIEW_GetItemState(infoPtr, iItem, LVIS_SELECTED)) uItemState |= CDIS_SELECTED;
+ if (LISTVIEW_GetItemState(infoPtr, iItem, LVIS_FOCUSED)) uItemState |= CDIS_FOCUS;
+ if (iItem == infoPtr->nHotItem) uItemState |= CDIS_HOT;
itemRect.left = LVIR_BOUNDS;
LISTVIEW_GetItemRect(infoPtr, iItem, &itemRect);
@@ -619,7 +641,7 @@
nmcd->lItemlParam= item.lParam;
nmcdhdr.clrText = infoPtr->clrText;
nmcdhdr.clrTextBk= infoPtr->clrBk;
- nmcdhdr.iSubItem =iSubItem;
+ nmcdhdr.iSubItem =iSubItem;
TRACE("drawstage=%lx hdc=%x item=%lx, itemstate=%x, lItemlParam=%lx\n",
nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
@@ -805,7 +827,7 @@
*
* NOTES
*/
-static VOID LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
+static void LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO *infoPtr, INT nNewScrollPos)
{
RECT winRect;
POINT point[2];
@@ -836,7 +858,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr)
+static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr)
{
LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
UINT uView = lStyle & LVS_TYPEMASK;
@@ -960,7 +982,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
+static void LISTVIEW_UnsupportedStyles(LONG lStyle)
{
if ((LVS_TYPESTYLEMASK & lStyle) == LVS_NOSCROLL)
FIXME(" LVS_NOSCROLL\n");
@@ -988,7 +1010,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_AlignTop(LISTVIEW_INFO *infoPtr)
+static void LISTVIEW_AlignTop(LISTVIEW_INFO *infoPtr)
{
UINT uView = get_listview_type(infoPtr);
INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
@@ -1056,7 +1078,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_AlignLeft(LISTVIEW_INFO *infoPtr)
+static void LISTVIEW_AlignLeft(LISTVIEW_INFO *infoPtr)
{
UINT uView = get_listview_type(infoPtr);
INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
@@ -1194,180 +1216,91 @@
static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
INT nSubItem)
{
- LISTVIEW_SUBITEM *lpSubItem;
- INT i;
+ LISTVIEW_SUBITEM *lpSubItem;
+ INT i;
- for (i = 1; i < hdpaSubItems->nItemCount; i++)
- {
- lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
- if (lpSubItem != NULL)
+ /* we should binary search here if need be */
+ for (i = 1; i < hdpaSubItems->nItemCount; i++)
{
- if (lpSubItem->iSubItem == nSubItem)
- {
- return lpSubItem;
- }
+ lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
+ if (lpSubItem && (lpSubItem->iSubItem == nSubItem))
+ return lpSubItem;
}
- }
- return NULL;
+ return NULL;
}
+
/***
* DESCRIPTION:
- * Calculates the width of an item.
+ * Calculates the width of a specific item.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
- * [I] LONG : window style
+ * [I] nItem : item to calculate width, or -1 for max of all
*
* RETURN:
- * Returns item width.
+ * Returns the width of an item width an item.
*/
-static INT LISTVIEW_GetItemWidth(LISTVIEW_INFO *infoPtr)
+static INT LISTVIEW_CalculateWidth(LISTVIEW_INFO *infoPtr, INT nItem)
{
- LONG style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
- UINT uView = style & LVS_TYPEMASK;
- INT nHeaderItemCount;
- RECT rcHeaderItem;
- INT nItemWidth = 0;
- INT nLabelWidth;
- INT i;
-
- TRACE("()\n");
-
- if (uView == LVS_ICON)
- {
- nItemWidth = infoPtr->iconSpacing.cx;
- }
- else if (uView == LVS_REPORT)
- {
- /* calculate width of header */
- nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
- for (i = 0; i < nHeaderItemCount; i++)
- {
- if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
- {
- nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
- }
- }
- }
- else /* for LVS_SMALLICON and LVS_LIST */
- {
- for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
- {
- nLabelWidth = LISTVIEW_GetLabelWidth(infoPtr, i);
- nItemWidth = max(nItemWidth, nLabelWidth);
- }
+ UINT uView = get_listview_type(infoPtr);
+ INT nItemWidth = 0, i;
- /* default label size */
- if (GETITEMCOUNT(infoPtr) == 0)
+ if (uView == LVS_ICON)
+ nItemWidth = infoPtr->iconSpacing.cx;
+ else if (uView == LVS_REPORT)
{
- nItemWidth = DEFAULT_COLUMN_WIDTH;
+ INT nHeaderItemCount;
+ RECT rcHeaderItem;
+
+ /* calculate width of header */
+ nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
+ for (i = 0; i < nHeaderItemCount; i++)
+ if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem))
+ nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
}
else
{
- if (nItemWidth == 0)
- {
- nItemWidth = DEFAULT_LABEL_WIDTH;
- }
- else
- {
- /* add padding */
+ INT nLabelWidth;
+
+ if (GETITEMCOUNT(infoPtr) == 0) return DEFAULT_COLUMN_WIDTH;
+
+ /* get width of string */
+ if (nItem == -1)
+ {
+ for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
+ {
+ nLabelWidth = LISTVIEW_GetLabelWidth(infoPtr, i);
+ nItemWidth = max(nItemWidth, nLabelWidth);
+ }
+ }
+ else
+ nItemWidth = LISTVIEW_GetLabelWidth(infoPtr, nItem);
+ if (!nItemWidth) return DEFAULT_COLUMN_WIDTH;
nItemWidth += WIDTH_PADDING;
-
- if (infoPtr->himlSmall != NULL)
- {
- nItemWidth += infoPtr->iconSize.cx;
- }
-
- if (infoPtr->himlState != NULL)
- {
- nItemWidth += infoPtr->iconSize.cx;
- }
- nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth);
- }
+ if (infoPtr->himlSmall) nItemWidth += infoPtr->iconSize.cx;
+ if (infoPtr->himlState) nItemWidth += infoPtr->iconSize.cx; /*FIXME: is this correct */
+ if (nItem == -1) nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth);
}
- }
- if(nItemWidth == 0)
- {
- /* nItemWidth Cannot be Zero */
- nItemWidth = 1;
- }
- return nItemWidth;
+
+ return max(nItemWidth, 1);
}
/***
* DESCRIPTION:
- * Calculates the width of a specific item.
+ * Calculates the max width of any item in the list.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
- * [I] LPSTR : string
+ * [I] LONG : window style
*
* RETURN:
- * Returns the width of an item width a specified string.
+ * Returns item width.
*/
-static INT LISTVIEW_CalculateWidth(LISTVIEW_INFO *infoPtr, INT nItem)
+static inline INT LISTVIEW_GetItemWidth(LISTVIEW_INFO *infoPtr)
{
- UINT uView = get_listview_type(infoPtr);
- INT nHeaderItemCount;
- RECT rcHeaderItem;
- INT nItemWidth = 0;
- INT i;
-
- TRACE("()\n");
-
- if (uView == LVS_ICON)
- {
- nItemWidth = infoPtr->iconSpacing.cx;
- }
- else if (uView == LVS_REPORT)
- {
- /* calculate width of header */
- nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
- for (i = 0; i < nHeaderItemCount; i++)
- {
- if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
- {
- nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
- }
- }
- }
- else
- {
- /* get width of string */
- nItemWidth = LISTVIEW_GetLabelWidth(infoPtr, nItem);
-
- /* default label size */
- if (GETITEMCOUNT(infoPtr) == 0)
- {
- nItemWidth = DEFAULT_COLUMN_WIDTH;
- }
- else
- {
- if (nItemWidth == 0)
- {
- nItemWidth = DEFAULT_LABEL_WIDTH;
- }
- else
- {
- /* add padding */
- nItemWidth += WIDTH_PADDING;
-
- if (infoPtr->himlSmall != NULL)
- {
- nItemWidth += infoPtr->iconSize.cx;
- }
-
- if (infoPtr->himlState != NULL)
- {
- nItemWidth += infoPtr->iconSize.cx;
- }
- }
- }
- }
-
- return nItemWidth;
+ return LISTVIEW_CalculateWidth(infoPtr, -1);
}
/***
@@ -1379,7 +1312,7 @@
* [I] infoPtr : valid pointer to the listview structure
*
*/
-static VOID LISTVIEW_SaveTextMetrics(LISTVIEW_INFO *infoPtr)
+static void LISTVIEW_SaveTextMetrics(LISTVIEW_INFO *infoPtr)
{
TEXTMETRICW tm;
HDC hdc = GetDC(infoPtr->hwndSelf);
@@ -1489,7 +1422,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_AddSelectionRange(LISTVIEW_INFO *infoPtr, INT lItem, INT uItem)
+static void LISTVIEW_AddSelectionRange(LISTVIEW_INFO *infoPtr, INT lItem, INT uItem)
{
LISTVIEW_SELECTION *selection;
INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
@@ -1639,34 +1572,6 @@
LISTVIEW_PrintSelectionRanges(infoPtr);
}
-/**
-* DESCRIPTION:
-* check if a specified index is selected.
-*
-* PARAMETER(S):
-* [I] infoPtr : valid pointer to the listview structure
-* [I] INT : item index
-*
-* RETURN:
-* None
-*/
-static BOOL LISTVIEW_IsSelected(LISTVIEW_INFO *infoPtr, INT nItem)
-{
- LISTVIEW_SELECTION selection;
- INT index;
-
- selection.upper = nItem;
- selection.lower = nItem;
-
- index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
- LISTVIEW_CompareSelectionRanges,
- 0,DPAS_SORTED);
- if (index != -1)
- return TRUE;
- else
- return FALSE;
-}
-
/***
* DESCRIPTION:
* Removes all selection ranges
@@ -1718,7 +1623,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO *infoPtr, INT lItem, INT uItem)
+static void LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO *infoPtr, INT lItem, INT uItem)
{
LISTVIEW_SELECTION removeselection,*checkselection;
INT index;
@@ -1802,6 +1707,30 @@
LISTVIEW_PrintSelectionRanges(infoPtr);
}
+/***
+ * DESCRIPTION:
+ * Manages the item focus.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] INT : item index
+ *
+ * RETURN:
+ * TRUE : focused item changed
+ * FALSE : focused item has NOT changed
+ */
+static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
+{
+ INT oldFocus = infoPtr->nFocusedItem;
+ LVITEMW lvItem;
+
+ lvItem.state = LVIS_FOCUSED;
+ lvItem.stateMask = LVIS_FOCUSED;
+ LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
+
+ return oldFocus != infoPtr->nFocusedItem;
+}
+
/**
* DESCRIPTION:
* Updates the various indices after an item has been inserted or deleted.
@@ -1814,7 +1743,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
+static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction)
{
LISTVIEW_SELECTION selection,*checkselection;
INT index;
@@ -1880,7 +1809,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
+static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
{
INT nFirst = min(infoPtr->nSelectionMark, nItem);
INT nLast = max(infoPtr->nSelectionMark, nItem);
@@ -1894,6 +1823,9 @@
item.stateMask = LVIS_SELECTED;
item.state = LVIS_SELECTED;
+ /* FIXME: this is not correct LVS_OWNERDATA
+ * See docu for LVN_ITEMCHANGED
+ */
for (i = nFirst; i <= nLast; i++)
LISTVIEW_SetItemState(infoPtr,i,&item);
@@ -1913,7 +1845,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_AddSelection(LISTVIEW_INFO *infoPtr, INT nItem)
+static void LISTVIEW_AddSelection(LISTVIEW_INFO *infoPtr, INT nItem)
{
LVITEMW item;
@@ -1929,44 +1861,6 @@
/***
* DESCRIPTION:
- * Selects or unselects an item.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] INT : item index
- *
- * RETURN:
- * SELECT: TRUE
- * UNSELECT : FALSE
- */
-static BOOL LISTVIEW_ToggleSelection(LISTVIEW_INFO *infoPtr, INT nItem)
-{
- BOOL bResult;
- LVITEMW item;
-
- ZeroMemory(&item,sizeof(item));
- item.stateMask = LVIS_SELECTED;
-
- if (LISTVIEW_IsSelected(infoPtr,nItem))
- {
- LISTVIEW_SetItemState(infoPtr,nItem,&item);
- bResult = FALSE;
- }
- else
- {
- item.state = LVIS_SELECTED;
- LISTVIEW_SetItemState(infoPtr,nItem,&item);
- bResult = TRUE;
- }
-
- LISTVIEW_SetItemFocus(infoPtr, nItem);
- infoPtr->nSelectionMark = nItem;
-
- return bResult;
-}
-
-/***
- * DESCRIPTION:
* Selects items based on view coordinates.
*
* PARAMETER(S):
@@ -1976,7 +1870,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_SetSelectionRect(LISTVIEW_INFO *infoPtr, RECT rcSelRect)
+static void LISTVIEW_SetSelectionRect(LISTVIEW_INFO *infoPtr, RECT rcSelRect)
{
POINT ptItem;
INT i;
@@ -2008,7 +1902,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
+static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
{
UINT uView = get_listview_type(infoPtr);
LVITEMW item;
@@ -2065,47 +1959,6 @@
/***
* DESCRIPTION:
- * Manages the item focus.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] INT : item index
- *
- * RETURN:
- * TRUE : focused item changed
- * FALSE : focused item has NOT changed
- */
-static BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem)
-{
- BOOL bResult = FALSE;
- LVITEMW lvItem;
-
- if (infoPtr->nFocusedItem != nItem)
- {
- if (infoPtr->nFocusedItem >= 0)
- {
- INT oldFocus = infoPtr->nFocusedItem;
- bResult = TRUE;
- infoPtr->nFocusedItem = -1;
- ZeroMemory(&lvItem, sizeof(lvItem));
- lvItem.stateMask = LVIS_FOCUSED;
- LISTVIEW_SetItemState(infoPtr, oldFocus, &lvItem);
-
- }
-
- lvItem.state = LVIS_FOCUSED;
- lvItem.stateMask = LVIS_FOCUSED;
- LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
-
- infoPtr->nFocusedItem = nItem;
- LISTVIEW_EnsureVisible(infoPtr, nItem, FALSE);
- }
-
- return bResult;
-}
-
-/***
- * DESCRIPTION:
* Sets a single selection.
*
* PARAMETER(S):
@@ -2115,7 +1968,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
+static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem)
{
LVITEMW lvItem;
@@ -2129,7 +1982,6 @@
lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
- infoPtr->nFocusedItem = nItem;
infoPtr->nSelectionMark = nItem;
}
@@ -2347,8 +2199,8 @@
if (lpSubItem->iSubItem == nSubItem)
{
/* free string */
- if (is_textW(lpSubItem->pszText))
- COMCTL32_Free(lpSubItem->pszText);
+ if (is_textW(lpSubItem->hdr.pszText))
+ COMCTL32_Free(lpSubItem->hdr.pszText);
/* free item */
COMCTL32_Free(lpSubItem);
@@ -2365,549 +2217,283 @@
return TRUE;
}
+
+/***
+ * Tests wheather the item is assignable to a list with style lStyle
+ */
+static inline BOOL is_assignable_item(LPLVITEMW lpLVItem, LONG lStyle)
+{
+ if ( (lpLVItem->mask & LVIF_TEXT) &&
+ (lpLVItem->pszText == LPSTR_TEXTCALLBACKW) &&
+ (lStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) ) return FALSE;
+
+ return TRUE;
+}
+
/***
* DESCRIPTION:
- * Compares the item information.
+ * Helper for LISTVIEW_SetItemT *only*: sets item attributes.
*
* PARAMETER(S):
- * [I] LISTVIEW_ITEM *: destination item
- * [I] LPLVITEM : source item
- * [I] isW : TRUE if lpLVItem is Unicode, FALSE it it's ANSI
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] lpLVItem : valid pointer to new item atttributes
+ * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
*
* RETURN:
- * SUCCCESS : TRUE (EQUAL)
- * FAILURE : FALSE (NOT EQUAL)
+ * SUCCESS : TRUE
+ * FAILURE : FALSE
*/
-static UINT LISTVIEW_GetItemChangesT(LISTVIEW_ITEM *lpItem, LPLVITEMW lpLVItem, BOOL isW)
+static BOOL set_main_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
{
- UINT uChanged = 0;
+ LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
+ UINT uView = lStyle & LVS_TYPEMASK;
+ HDPA hdpaSubItems;
+ LISTVIEW_ITEM *lpItem;
+ NMLISTVIEW nmlv;
+ UINT uChanged = 0;
+ RECT rcItem;
- if ((lpItem != NULL) && (lpLVItem != NULL))
- {
- if (lpLVItem->mask & LVIF_STATE)
- {
- if ((lpItem->state & lpLVItem->stateMask) !=
- (lpLVItem->state & lpLVItem->stateMask))
- uChanged |= LVIF_STATE;
- }
+ TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
- if (lpLVItem->mask & LVIF_IMAGE)
+
+ if (lStyle & LVS_OWNERDATA)
{
- if (lpItem->iImage != lpLVItem->iImage)
- uChanged |= LVIF_IMAGE;
- }
+ INT oldState, oldFocus;
- if (lpLVItem->mask & LVIF_PARAM)
- {
- if (lpItem->lParam != lpLVItem->lParam)
- uChanged |= LVIF_PARAM;
- }
+ /* a virtual livst view stores only state for the mai item */
+ if (lpLVItem->iSubItem || !(lpLVItem->mask & LVIF_STATE)) return FALSE;
- if (lpLVItem->mask & LVIF_INDENT)
- {
- if (lpItem->iIndent != lpLVItem->iIndent)
- uChanged |= LVIF_INDENT;
- }
+ oldState = LISTVIEW_GetItemState(infoPtr, lpLVItem->iItem, LVIS_FOCUSED | LVIS_SELECTED);
- if (lpLVItem->mask & LVIF_TEXT)
- {
- if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
- {
- if (lpItem->pszText != LPSTR_TEXTCALLBACKW)
- uChanged |= LVIF_TEXT;
- }
- else
- {
- if (lpItem->pszText == LPSTR_TEXTCALLBACKW)
- {
- uChanged |= LVIF_TEXT;
- }
- else
+ /* we're done if we don't need to change anything we handle */
+ if ( (oldState ^ lpLVItem->state) & lpLVItem->stateMask &
+ ~infoPtr->uCallbackMask & (LVIS_FOCUSED | LVIS_SELECTED)) return FALSE;
+
+ /*
+ * As per MSDN LVN_ITEMCHANGING notifications are _NOT_ sent for
+ * by LVS_OWERNDATA list controls
+ */
+
+ /* if we handle the focus, and we're asked to change it, do it now */
+ oldFocus = infoPtr->nFocusedItem;
+ if ( lpLVItem->stateMask & LVIS_FOCUSED )
{
- if (lpLVItem->pszText)
- {
- if (lpItem->pszText)
+ if (lpLVItem->state & LVIS_FOCUSED)
+ infoPtr->nFocusedItem = lpLVItem->iItem;
+ else if (infoPtr->nFocusedItem == lpLVItem->iItem)
+ infoPtr->nFocusedItem = -1;
+ }
+
+ /* and the selection is the only other state a virtual list may hold */
+ if (lpLVItem->stateMask & LVIS_SELECTED)
+ {
+ if (lpLVItem->state & LVIS_SELECTED)
{
- LPWSTR pszText = textdupTtoW(lpLVItem->pszText, isW);
- if (pszText && strcmpW(pszText, lpItem->pszText))
- uChanged |= LVIF_TEXT;
- textfreeT(pszText, isW);
+ if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr);
+ LISTVIEW_AddSelectionRange(infoPtr, lpLVItem->iItem, lpLVItem->iItem);
}
else
- {
- uChanged |= LVIF_TEXT;
- }
- }
- else
- {
- if (lpItem->pszText)
- uChanged |= LVIF_TEXT;
- }
+ LISTVIEW_RemoveSelectionRange(infoPtr, lpLVItem->iItem, lpLVItem->iItem);
}
- }
- }
- }
- return uChanged;
-}
-
-/***
- * DESCRIPTION:
- * Initializes item attributes.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [O] LISTVIEW_ITEM *: destination item
- * [I] LPLVITEM : source item
- * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
- *
- * RETURN:
- * SUCCCESS : TRUE
- * FAILURE : FALSE
- */
-static BOOL LISTVIEW_InitItemT(LISTVIEW_INFO *infoPtr, LISTVIEW_ITEM *lpItem,
- LPLVITEMW lpLVItem, BOOL isW)
-{
- LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
- BOOL bResult = FALSE;
-
- if ((lpItem != NULL) && (lpLVItem != NULL))
- {
- bResult = TRUE;
-
- if (lpLVItem->mask & LVIF_STATE)
- {
- lpItem->state &= ~lpLVItem->stateMask;
- lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
- }
-
- if (lpLVItem->mask & LVIF_IMAGE)
- lpItem->iImage = lpLVItem->iImage;
-
- if (lpLVItem->mask & LVIF_PARAM)
- lpItem->lParam = lpLVItem->lParam;
-
- if (lpLVItem->mask & LVIF_INDENT)
- lpItem->iIndent = lpLVItem->iIndent;
-
- if (lpLVItem->mask & LVIF_TEXT)
- {
- if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
- {
- if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
- return FALSE;
-
- if (is_textW(lpItem->pszText))
- COMCTL32_Free(lpItem->pszText);
-
- lpItem->pszText = LPSTR_TEXTCALLBACKW;
- }
- else
- bResult = textsetptrT(&lpItem->pszText, lpLVItem->pszText, isW);
- }
- }
-
- return bResult;
-}
-
-/***
- * DESCRIPTION:
- * Initializes subitem attributes.
- *
- * NOTE: The documentation specifies that the operation fails if the user
- * tries to set the indent of a subitem.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [O] LISTVIEW_SUBITEM *: destination subitem
- * [I] LPLVITEM : source subitem
- * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
- *
- * RETURN:
- * SUCCCESS : TRUE
- * FAILURE : FALSE
- */
-static BOOL LISTVIEW_InitSubItemT(LISTVIEW_INFO *infoPtr, LISTVIEW_SUBITEM *lpSubItem,
- LPLVITEMW lpLVItem, BOOL isW)
-{
- LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
- BOOL bResult = FALSE;
-
- TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
- if ((lpSubItem != NULL) && (lpLVItem != NULL))
- {
- if (!(lpLVItem->mask & LVIF_INDENT))
- {
- bResult = TRUE;
+ /* notify the parent now that things have changed */
+ ZeroMemory(&nmlv, sizeof(nmlv));
+ nmlv.iItem = lpLVItem->iItem;
+ nmlv.uNewState = lpLVItem->state;
+ nmlv.uOldState = oldState;
+ nmlv.uChanged = LVIF_STATE;
+ listview_notify(infoPtr, LVN_ITEMCHANGED, &nmlv);
- lpSubItem->iSubItem = lpLVItem->iSubItem;
-
- if (lpLVItem->mask & LVIF_IMAGE)
- lpSubItem->iImage = lpLVItem->iImage;
-
- if (lpLVItem->mask & LVIF_TEXT)
- {
- if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
- {
- if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
- return FALSE;
-
- if (is_textW(lpSubItem->pszText))
- COMCTL32_Free(lpSubItem->pszText);
-
- lpSubItem->pszText = LPSTR_TEXTCALLBACKW;
- }
- else
- bResult = textsetptrT(&lpSubItem->pszText, lpLVItem->pszText, isW);
- }
+ /* Redraw items that have changed */
+ if (!infoPtr->bIsDrawing)
+ {
+ if (oldFocus != infoPtr->nFocusedItem)
+ {
+ rcItem.left = LVIR_BOUNDS;
+ LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
+ InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
+ }
+ /* FIXME: shouldn't the selection changes invaidated those rects? */
+ rcItem.left = LVIR_BOUNDS;
+ LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
+ InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
+ }
+
+ return TRUE;
}
- }
-
- return bResult;
-}
-/***
- * DESCRIPTION:
- * Adds a subitem at a given position (column index).
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] LPLVITEM : new subitem atttributes
- * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
- *
- * RETURN:
- * SUCCESS : TRUE
- * FAILURE : FALSE
- */
-static BOOL LISTVIEW_AddSubItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
-{
- LISTVIEW_SUBITEM *lpSubItem = NULL;
- BOOL bResult = FALSE;
- HDPA hdpaSubItems;
- INT nPosition, nItem;
- LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
-
- TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
-
- if (lStyle & LVS_OWNERDATA)
- return FALSE;
-
- if (lpLVItem != NULL)
- {
+ /* sanity checks first */
+ if (!is_assignable_item(lpLVItem, lStyle)) return FALSE;
+
hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
- if (hdpaSubItems != NULL)
- {
- lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
- if (lpSubItem != NULL)
- {
- ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
- if (LISTVIEW_InitSubItemT(infoPtr, lpSubItem, lpLVItem, isW))
- {
- nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
- lpSubItem->iSubItem);
- nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
- if (nItem != -1) bResult = TRUE;
- }
- }
- }
- }
-
- /* cleanup if unsuccessful */
- if (!bResult && lpSubItem) COMCTL32_Free(lpSubItem);
-
- return bResult;
-}
-
-/***
- * DESCRIPTION:
- * Finds the dpa insert position (array index).
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] INT : subitem index
- *
- * RETURN:
- * SUCCESS : TRUE
- * FAILURE : FALSE
- */
-static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
-{
- LISTVIEW_SUBITEM *lpSubItem;
- INT i;
-
- for (i = 1; i < hdpaSubItems->nItemCount; i++)
- {
- lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
- if (lpSubItem && lpSubItem->iSubItem > nSubItem)
- return i;
- }
-
- return hdpaSubItems->nItemCount;
-}
-
-/***
- * DESCRIPTION:
- * Retrieves a listview subitem at a given position (column index).
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] INT : subitem index
- *
- * RETURN:
- * SUCCESS : TRUE
- * FAILURE : FALSE
- */
-static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
-{
- LISTVIEW_SUBITEM *lpSubItem;
- INT i;
+ if (!hdpaSubItems && hdpaSubItems != (HDPA)-1) return FALSE;
+
+ lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
+ if (!lpItem) return FALSE;
- for (i = 1; i < hdpaSubItems->nItemCount; i++)
- {
- lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
- if (lpSubItem != NULL)
- {
- if (lpSubItem->iSubItem == nSubItem)
- return lpSubItem;
- else if (lpSubItem->iSubItem > nSubItem)
- return NULL;
- }
- }
+ /* determine what fields will change */
+ if ((lpLVItem->mask & LVIF_STATE) &&
+ ((lpItem->state ^ lpLVItem->state) & lpLVItem->stateMask))
+ uChanged |= LVIF_STATE;
- return NULL;
-}
+ if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage))
+ uChanged |= LVIF_IMAGE;
-/***
- * DESCRIPTION:
- * Sets item attributes.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] LPLVITEM : new item atttributes
- * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
- *
- * RETURN:
- * SUCCESS : TRUE
- * FAILURE : FALSE
- */
-static BOOL LISTVIEW_SetMainItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
-{
- BOOL bResult = FALSE;
- HDPA hdpaSubItems;
- LISTVIEW_ITEM *lpItem;
- NMLISTVIEW nmlv;
- LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
- UINT uChanged;
- UINT uView = lStyle & LVS_TYPEMASK;
- INT item_width;
- RECT rcItem;
+ if ((lpLVItem->mask & LVIF_PARAM) && (lpItem->lParam != lpLVItem->lParam))
+ uChanged |= LVIF_PARAM;
- TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
+ if ((lpLVItem->mask & LVIF_INDENT) && (lpItem->iIndent != lpLVItem->iIndent))
+ uChanged |= LVIF_INDENT;
- if (lStyle & LVS_OWNERDATA)
- {
- if ((lpLVItem->iSubItem == 0)&&(lpLVItem->mask == LVIF_STATE))
- {
- LVITEMW itm;
+ if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpItem->hdr.pszText, lpLVItem->pszText, isW))
+ uChanged |= LVIF_TEXT;
+
+ if (!uChanged) return TRUE;
+
+ ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
+ nmlv.iItem = lpLVItem->iItem;
+ nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
+ nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
+ nmlv.uChanged = uChanged;
+ nmlv.lParam = lpItem->lParam;
+
+ /* send LVN_ITEMCHANGING notification, if the item is not being inserted */
+ if(lpItem->valid && listview_notify(infoPtr, LVN_ITEMCHANGING, &nmlv))
+ return FALSE;
- ZeroMemory(&itm, sizeof(itm));
- itm.mask = LVIF_STATE | LVIF_PARAM;
- itm.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
- itm.iItem = lpLVItem->iItem;
- itm.iSubItem = 0;
- ListView_GetItemW(infoPtr->hwndSelf, &itm);
-
-
- ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
- nmlv.uNewState = lpLVItem->state;
- nmlv.uOldState = itm.state;
- nmlv.uChanged = LVIF_STATE;
- nmlv.lParam = itm.lParam;
- nmlv.iItem = lpLVItem->iItem;
+ /* copy information */
+ if (lpLVItem->mask & LVIF_TEXT)
+ textsetptrT(&lpItem->hdr.pszText, lpLVItem->pszText, isW);
- if ((itm.state & lpLVItem->stateMask) !=
- (lpLVItem->state & lpLVItem->stateMask))
- {
- /*
- * As per MSDN LVN_ITEMCHANGING notifications are _NOT_ sent
- * by LVS_OWERNDATA list controls
- */
- if (lpLVItem->stateMask & LVIS_FOCUSED)
- {
- if (lpLVItem->state & LVIS_FOCUSED)
- infoPtr->nFocusedItem = lpLVItem->iItem;
- else if (infoPtr->nFocusedItem == lpLVItem->iItem)
- infoPtr->nFocusedItem = -1;
- }
- if (lpLVItem->stateMask & LVIS_SELECTED)
- {
- if (lpLVItem->state & LVIS_SELECTED)
- {
- if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr);
- LISTVIEW_AddSelectionRange(infoPtr,lpLVItem->iItem,lpLVItem->iItem);
- }
- else
- LISTVIEW_RemoveSelectionRange(infoPtr,lpLVItem->iItem,
- lpLVItem->iItem);
- }
+ if (lpLVItem->mask & LVIF_IMAGE)
+ lpItem->hdr.iImage = lpLVItem->iImage;
- listview_notify(infoPtr, LVN_ITEMCHANGED, &nmlv);
+ if (lpLVItem->mask & LVIF_PARAM)
+ lpItem->lParam = lpLVItem->lParam;
- rcItem.left = LVIR_BOUNDS;
- LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
- if (!infoPtr->bIsDrawing)
- InvalidateRect(infoPtr->hwndSelf, &rcItem, TRUE);
- }
- return TRUE;
- }
- return FALSE;
- }
+ if (lpLVItem->mask & LVIF_INDENT)
+ lpItem->iIndent = lpLVItem->iIndent;
- if (lpLVItem != NULL)
- {
- if (lpLVItem->iSubItem == 0)
+ if (uChanged & LVIF_STATE)
{
- hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
- if (hdpaSubItems != NULL && hdpaSubItems != (HDPA)-1)
- {
- lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
- if (lpItem != NULL)
- {
- ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
- nmlv.lParam = lpItem->lParam;
- uChanged = LISTVIEW_GetItemChangesT(lpItem, lpLVItem, isW);
- if (uChanged != 0)
- {
- if (uChanged & LVIF_STATE)
- {
- nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
- nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
-
- if (nmlv.uNewState & LVIS_SELECTED)
- {
- /*
- * This is redundant if called through SetSelection
- *
- * however is required if the used directly calls SetItem
- * to set the selection.
- */
- if (lStyle & LVS_SINGLESEL)
- LISTVIEW_RemoveAllSelections(infoPtr);
-
- LISTVIEW_AddSelectionRange(infoPtr,lpLVItem->iItem,
- lpLVItem->iItem);
- }
- else if (lpLVItem->stateMask & LVIS_SELECTED)
- {
- LISTVIEW_RemoveSelectionRange(infoPtr,lpLVItem->iItem,
- lpLVItem->iItem);
- }
- if (nmlv.uNewState & LVIS_FOCUSED)
- {
- /*
- * This is a fun hoop to jump to try to catch if
- * the user is calling us directly to call focus or if
- * this function is being called as a result of a
- * SetItemFocus call.
- */
- if (infoPtr->nFocusedItem >= 0)
- LISTVIEW_SetItemFocus(infoPtr, lpLVItem->iItem);
- }
- }
-
- nmlv.uChanged = uChanged;
- nmlv.iItem = lpLVItem->iItem;
- nmlv.lParam = lpItem->lParam;
- /* send LVN_ITEMCHANGING notification */
- listview_notify(infoPtr, LVN_ITEMCHANGING, &nmlv);
-
- /* copy information */
- bResult = LISTVIEW_InitItemT(infoPtr, lpItem, lpLVItem, isW);
-
- /* if LVS_LIST or LVS_SMALLICON, update the width of the items
- based on the width of the items text */
- if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
- {
- item_width = LISTVIEW_GetStringWidthT(infoPtr, lpItem->pszText, TRUE);
-
- if(item_width > infoPtr->nItemWidth)
- infoPtr->nItemWidth = item_width;
- }
-
- /* send LVN_ITEMCHANGED notification */
- listview_notify(infoPtr, LVN_ITEMCHANGED, &nmlv);
- }
- else
- {
- bResult = TRUE;
- }
-
- if (uChanged)
- {
- rcItem.left = LVIR_BOUNDS;
- LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
- if (!infoPtr->bIsDrawing)
- InvalidateRect(infoPtr->hwndSelf, &rcItem, TRUE);
- }
- }
- }
+ lpItem->state &= ~lpLVItem->stateMask;
+ lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
+ if (nmlv.uNewState & LVIS_SELECTED)
+ {
+ if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr);
+ LISTVIEW_AddSelectionRange(infoPtr,lpLVItem->iItem, lpLVItem->iItem);
+ }
+ else if (lpLVItem->stateMask & LVIS_SELECTED)
+ LISTVIEW_RemoveSelectionRange(infoPtr,lpLVItem->iItem, lpLVItem->iItem);
+
+ /* if we are asked to change focus, and we manage it, do it */
+ if (nmlv.uNewState & ~infoPtr->uCallbackMask & LVIS_FOCUSED)
+ {
+ if (lpLVItem->state & LVIS_FOCUSED)
+ {
+ infoPtr->nFocusedItem = lpLVItem->iItem;
+ LISTVIEW_EnsureVisible(infoPtr, lpLVItem->iItem, FALSE);
+ }
+ else if (infoPtr->nFocusedItem == lpLVItem->iItem)
+ infoPtr->nFocusedItem = -1;
+ }
}
- }
- return bResult;
+ /* if LVS_LIST or LVS_SMALLICON, update the width of the items */
+ if((uChanged & LVIF_TEXT) && ((uView == LVS_LIST) || (uView == LVS_SMALLICON)))
+ {
+ int item_width = LISTVIEW_CalculateWidth(infoPtr, lpLVItem->iItem);
+ if(item_width > infoPtr->nItemWidth) infoPtr->nItemWidth = item_width;
+ }
+
+ /* if we're inserting the item, we're done */
+ if (!lpItem->valid) return TRUE;
+
+ /* send LVN_ITEMCHANGED notification */
+ nmlv.lParam = lpItem->lParam;
+ listview_notify(infoPtr, LVN_ITEMCHANGED, &nmlv);
+
+ rcItem.left = LVIR_BOUNDS;
+ LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
+ if (!infoPtr->bIsDrawing)
+ InvalidateRect(infoPtr->hwndSelf, &rcItem, TRUE);
+
+ return TRUE;
}
/***
* DESCRIPTION:
- * Sets subitem attributes.
+ * Helper for LISTVIEW_SetItemT *only*: sets subitem attributes.
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
- * [I] LPLVITEM : new subitem atttributes
+ * [I] lpLVItem : valid pointer to new subitem atttributes
* [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI
*
* RETURN:
* SUCCESS : TRUE
* FAILURE : FALSE
*/
-static BOOL LISTVIEW_SetSubItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
+static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
{
- LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
- BOOL bResult = FALSE;
- HDPA hdpaSubItems;
- LISTVIEW_SUBITEM *lpSubItem;
- RECT rcItem;
+ LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
+ HDPA hdpaSubItems;
+ LISTVIEW_SUBITEM *lpSubItem;
+ RECT rcItem;
- TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
+ TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
- if (lStyle & LVS_OWNERDATA)
- return FALSE;
+ if (lStyle & LVS_OWNERDATA) return FALSE;
- if (lpLVItem != NULL)
- {
- if (lpLVItem->iSubItem > 0)
+ /* set subitem only if column is present */
+ if (Header_GetItemCount(infoPtr->hwndHeader) <= lpLVItem->iSubItem)
+ return FALSE;
+
+ /* First do some sanity checks */
+ if (lpLVItem->mask & ~(LVIF_TEXT | LVIF_IMAGE)) return FALSE;
+
+ if (!is_assignable_item(lpLVItem, lStyle)) return FALSE;
+
+ /* get the subitem structure, and create it if not there */
+ hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
+ if (!hdpaSubItems) return FALSE;
+
+ lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
+ if (!lpSubItem)
{
- hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
- if (hdpaSubItems != NULL)
- {
- /* set subitem only if column is present */
- if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
- {
- lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
- if (lpSubItem != NULL)
- bResult = LISTVIEW_InitSubItemT(infoPtr, lpSubItem, lpLVItem, isW);
- else
- bResult = LISTVIEW_AddSubItemT(infoPtr, lpLVItem, isW);
+ LISTVIEW_SUBITEM *tmpSubItem;
+ INT i;
- rcItem.left = LVIR_BOUNDS;
- LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
- InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
- }
- }
+ lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
+ if (!lpSubItem) return FALSE;
+ ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
+
+ /* we could binary search here, if need be...*/
+ for (i = 1; i < hdpaSubItems->nItemCount; i++)
+ {
+ tmpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
+ if (tmpSubItem && tmpSubItem->iSubItem > lpLVItem->iSubItem) break;
+ }
+ if (DPA_InsertPtr(hdpaSubItems, i, lpSubItem) == -1)
+ {
+ COMCTL32_Free(lpSubItem);
+ return FALSE;
+ }
}
- }
- return bResult;
+ lpSubItem->iSubItem = lpLVItem->iSubItem;
+
+ if (lpLVItem->mask & LVIF_IMAGE)
+ lpSubItem->hdr.iImage = lpLVItem->iImage;
+
+ if (lpLVItem->mask & LVIF_TEXT)
+ textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW);
+
+ rcItem.left = LVIR_BOUNDS;
+ LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
+ InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
+
+ return TRUE;
}
/***
@@ -2925,14 +2511,20 @@
*/
static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
{
+ BOOL bResult;
+ LPWSTR pszText = lpLVItem->pszText;
+
+ if (!lpLVItem || lpLVItem->iItem < 0 ||
+ lpLVItem->iItem>=GETITEMCOUNT(infoPtr))
+ return FALSE;
+
+ /* For efficiency, we transform the lpLVItem->pszText to Unicode here */
+ lpLVItem->pszText = textdupTtoW(lpLVItem->pszText, isW);
+ bResult = (lpLVItem->iSubItem ? set_sub_item : set_main_item)(infoPtr, lpLVItem, TRUE);
+ textfreeT(lpLVItem->pszText, isW);
+ lpLVItem->pszText = pszText;
- if (!lpLVItem || lpLVItem->iItem < 0 ||
- lpLVItem->iItem>=GETITEMCOUNT(infoPtr))
- return FALSE;
- if (lpLVItem->iSubItem == 0)
- return LISTVIEW_SetMainItemT(infoPtr, lpLVItem, isW);
- else
- return LISTVIEW_SetSubItemT(infoPtr, lpLVItem, isW);
+ return bResult;
}
/***
@@ -2984,7 +2576,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_DrawSubItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nSubItem,
+static void LISTVIEW_DrawSubItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nSubItem,
RECT rcItem, BOOL Selected)
{
WCHAR szDispText[DISP_TEXT_SIZE];
@@ -3033,7 +2625,7 @@
else
rcTemp.right += WIDTH_PADDING;
- LISTVIEW_FillBackground(infoPtr, hdc, &rcTemp);
+ if (infoPtr->clrBk != CLR_NONE) FillRect(hdc, &rcTemp, infoPtr->hBkBrush);
/* set item colors */
if (ListView_GetItemState(infoPtr->hwndSelf,nItem,LVIS_SELECTED) && Selected)
@@ -3105,7 +2697,7 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
+static void LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
{
WCHAR szDispText[DISP_TEXT_SIZE];
INT nLabelWidth;
@@ -3140,7 +2732,7 @@
else
rcTemp.right+=WIDTH_PADDING;
- LISTVIEW_FillBackground(infoPtr, hdc, &rcTemp);
+ if (infoPtr->clrBk != CLR_NONE) FillRect(hdc, &rcTemp, infoPtr->hBkBrush);
/* do indent */
if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
@@ -3290,13 +2882,12 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem,
+static void LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem,
RECT *SuggestedFocus)
{
WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
LVITEMW lvItem;
UINT uFormat = LISTVIEW_DTFLAGS;
- COLORREF clrFill;
RECT rcFill;
TRACE("(hdc=%x, nItem=%d, left=%d, top=%d, right=%d, bottom=%d)\n",
@@ -3319,10 +2910,7 @@
TRACE("background rect (%d,%d)-(%d,%d)\n",
rcFill.left, rcFill.top, rcFill.right, rcFill.bottom);
- /* Paint background of icon and basic text area */
- clrFill = infoPtr->clrBk;
- LISTVIEW_SuperFillBackground(infoPtr, hdc, &rcFill, clrFill);
-
+ if (infoPtr->clrBk != CLR_NONE) FillRect(hdc, &rcFill, infoPtr->hBkBrush);
/* Figure out text colours etc. depending on state
* At least the following states exist; there may be more.
@@ -3478,12 +3066,12 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
+static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
{
SCROLLINFO scrollInfo;
INT nDrawPosY = infoPtr->rcList.top;
INT nColumnCount;
- RECT rcItem, rcTemp;
+ RECT rcItem;
INT j;
INT nItem;
INT nLast;
@@ -3518,10 +3106,6 @@
infoPtr->nColumnCount = nColumnCount; /* update nColumnCount */
FullSelected = infoPtr->dwExStyle & LVS_EX_FULLROWSELECT;
- /* clear the background of any part of the control that doesn't contain items */
- SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
- LISTVIEW_FillBackground(infoPtr, hdc, &rcTemp);
-
/* nothing to draw */
if(GETITEMCOUNT(infoPtr) == 0)
return;
@@ -3552,8 +3136,10 @@
dis.itemAction = ODA_DRAWENTIRE;
dis.itemState = 0;
- if (LISTVIEW_IsSelected(infoPtr,nItem)) dis.itemState|=ODS_SELECTED;
- if (nItem==infoPtr->nFocusedItem) dis.itemState|=ODS_FOCUS;
+ if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
+ dis.itemState |= ODS_SELECTED;
+ if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
+ dis.itemState |= ODS_FOCUS;
dis.hwndItem = infoPtr->hwndSelf;
dis.hDC = hdc;
@@ -3631,6 +3217,7 @@
* Draw Focus Rect
*/
if (LISTVIEW_GetItemState(infoPtr,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
+
{
BOOL rop=FALSE;
if (FullSelected && LISTVIEW_GetItemState(infoPtr,nItem,LVIS_SELECTED))
@@ -3732,9 +3319,9 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
+static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
{
- RECT rcItem, FocusRect, rcTemp;
+ RECT rcItem, FocusRect;
INT i, j;
INT nItem;
INT nColumnCount;
@@ -3751,10 +3338,6 @@
TRACE("nColumnCount=%d, nCountPerColumn=%d, start item=%d\n",
nColumnCount, nCountPerColumn, nItem);
- /* paint the background of the control that doesn't contain any items */
- SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
- LISTVIEW_FillBackground(infoPtr, hdc, &rcTemp);
-
/* nothing to draw, return here */
if(GETITEMCOUNT(infoPtr) == 0)
return;
@@ -3803,27 +3386,18 @@
* RETURN:
* None
*/
-static VOID LISTVIEW_RefreshIcon(LISTVIEW_INFO *infoPtr, HDC hdc, BOOL bSmall, DWORD cdmode)
+static void LISTVIEW_RefreshIcon(LISTVIEW_INFO *infoPtr, HDC hdc, BOOL bSmall, DWORD cdmode)
{
POINT ptPosition;
POINT ptOrigin;
- RECT rcItem, SuggestedFocus, rcTemp;
+ RECT rcItem, SuggestedFocus;
INT i;
DWORD cditemmode = CDRF_DODEFAULT;
- COLORREF clrFill;
TRACE("\n");
infoPtr->nColumnCount = 1; /* set this to an arbitrary value to prevent */
/* DrawItem from erasing the incorrect background area */
- /* paint the background of the control that doesn't contain any items */
- SubtractRect(&rcTemp, &infoPtr->rcList, &infoPtr->rcView);
-
- TRACE("filling viewable area (%d,%d)-(%d,%d)\n",
- rcTemp.left, rcTemp.top, rcTemp.right, rcTemp.bottom);
- clrFill = infoPtr->clrBk;
- LISTVIEW_SuperFillBackground(infoPtr, hdc, &rcTemp, clrFill);
-
/* nothing to draw, return here */
if(GETITEMCOUNT(infoPtr) == 0)
return;
@@ -3885,13 +3459,13 @@
* RETURN:
* NoneX
*/
-static VOID LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
+static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
{
UINT uView = get_listview_type(infoPtr);
HFONT hOldFont;
HPEN hPen, hOldPen;
DWORD cdmode;
- RECT rect;
+ RECT rect, rcTemp;
LISTVIEW_DUMP(infoPtr);
@@ -3912,15 +3486,16 @@
/* select transparent brush (for drawing the focus box) */
SelectObject(hdc, GetStockObject(NULL_BRUSH));
- TRACE("\n");
+ /* 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);
+
if (uView == LVS_LIST)
LISTVIEW_RefreshList(infoPtr, hdc, cdmode);
else if (uView == LVS_REPORT)
LISTVIEW_RefreshReport(infoPtr, hdc, cdmode);
- else if (uView == LVS_SMALLICON)
- LISTVIEW_RefreshIcon(infoPtr, hdc, TRUE, cdmode);
- else if (uView == LVS_ICON)
- LISTVIEW_RefreshIcon(infoPtr, hdc, FALSE, cdmode);
+ else
+ LISTVIEW_RefreshIcon(infoPtr, hdc, uView == LVS_SMALLICON, cdmode);
/* unselect objects */
SelectObject(hdc, hOldFont);
@@ -4102,8 +3677,8 @@
if (lpSubItem != NULL)
{
/* free subitem string */
- if (is_textW(lpSubItem->pszText))
- COMCTL32_Free(lpSubItem->pszText);
+ if (is_textW(lpSubItem->hdr.pszText))
+ COMCTL32_Free(lpSubItem->hdr.pszText);
/* free subitem */
COMCTL32_Free(lpSubItem);
@@ -4122,8 +3697,8 @@
}
/* free item string */
- if (is_textW(lpItem->pszText))
- COMCTL32_Free(lpItem->pszText);
+ if (is_textW(lpItem->hdr.pszText))
+ COMCTL32_Free(lpItem->hdr.pszText);
/* free item */
COMCTL32_Free(lpItem);
@@ -4261,8 +3836,8 @@
if (lpSubItem != NULL)
{
/* free item string */
- if (is_textW(lpSubItem->pszText))
- COMCTL32_Free(lpSubItem->pszText);
+ if (is_textW(lpSubItem->hdr.pszText))
+ COMCTL32_Free(lpSubItem->hdr.pszText);
/* free item */
COMCTL32_Free(lpSubItem);
@@ -4273,8 +3848,8 @@
if (lpItem != NULL)
{
/* free item string */
- if (is_textW(lpItem->pszText))
- COMCTL32_Free(lpItem->pszText);
+ if (is_textW(lpItem->hdr.pszText))
+ COMCTL32_Free(lpItem->hdr.pszText);
/* free item */
COMCTL32_Free(lpItem);
@@ -4347,8 +3922,8 @@
item.iSubItem = 0;
item.mask = LVIF_PARAM | LVIF_STATE;
ListView_GetItemW(infoPtr->hwndSelf, &item);
+ lvItemRef.hdr.iImage = item.iImage;
lvItemRef.state = item.state;
- lvItemRef.iImage = item.iImage;
lvItemRef.lParam = item.lParam;
lpItem = &lvItemRef;
}
@@ -4360,13 +3935,13 @@
dispInfo.item.stateMask = 0;
dispInfo.item.pszText = pszText;
dispInfo.item.cchTextMax = textlenT(pszText, isW);
- dispInfo.item.iImage = lpItem->iImage;
+ dispInfo.item.iImage = lpItem->hdr.iImage;
dispInfo.item.lParam = lpItem->lParam;
/* Do we need to update the Item Text */
if(dispinfo_notifyT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW))
- if (lpItem->pszText != LPSTR_TEXTCALLBACKW && !(lStyle & LVS_OWNERDATA))
- bResult = textsetptrT(&lpItem->pszText, pszText, isW);
+ if (lpItem->hdr.pszText != LPSTR_TEXTCALLBACKW && !(lStyle & LVS_OWNERDATA))
+ bResult = textsetptrT(&lpItem->hdr.pszText, pszText, isW);
return bResult;
}
@@ -4430,7 +4005,7 @@
item.iSubItem = 0;
item.mask = LVIF_PARAM | LVIF_STATE;
ListView_GetItemW(infoPtr->hwndSelf, &item);
- lvItemRef.iImage = item.iImage;
+ lvItemRef.hdr.iImage = item.iImage;
lvItemRef.state = item.state;
lvItemRef.lParam = item.lParam;
lpItem = &lvItemRef;
@@ -4453,7 +4028,7 @@
dispInfo.item.stateMask = 0;
dispInfo.item.pszText = lvItem.pszText;
dispInfo.item.cchTextMax = lstrlenW(lvItem.pszText);
- dispInfo.item.iImage = lpItem->iImage;
+ dispInfo.item.iImage = lpItem->hdr.iImage;
dispInfo.item.lParam = lpItem->lParam;
if (dispinfo_notifyT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW))
@@ -4483,8 +4058,8 @@
*
* PARAMETER(S):
* [I] infoPtr : valid pointer to the listview structure
- * [I] INT : item index
- * [I] BOOL : partially or entirely visible
+ * [I] nItem : item index
+ * [I] bPartial : partially or entirely visible
*
* RETURN:
* SUCCESS : TRUE
@@ -5046,6 +4621,18 @@
/* LISTVIEW_GetISearchString */
/***
+ * Helper function for LISTVIEW_GetItemT *only*. Tests if an item is selected.
+ * It is important that no other functions call this because of callbacks.
+ */
+static inline BOOL is_item_selected(LISTVIEW_INFO *infoPtr, INT nItem)
+{
+ LISTVIEW_SELECTION selection = { nItem, nItem };
+
+ return DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
+ LISTVIEW_CompareSelectionRanges, 0, DPAS_SORTED) != -1;
+}
+
+/***
* DESCRIPTION:
* Retrieves item attributes.
*
@@ -5063,182 +4650,199 @@
*/
static LRESULT LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL internal, BOOL isW)
{
- LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
- NMLVDISPINFOW dispInfo;
- LISTVIEW_SUBITEM *lpSubItem;
- LISTVIEW_ITEM *lpItem;
- HDPA hdpaSubItems;
- void* null = NULL;
- INT* piImage = (INT*)&null;
- LPWSTR* ppszText= (LPWSTR*)&null;
- LPARAM* plParam = (LPARAM*)&null;
-
- if (internal && !isW)
- {
- ERR("We can't have internal non-Unicode GetItem!\n");
- return FALSE;
- }
+ NMLVDISPINFOW dispInfo;
+ LISTVIEW_ITEM *lpItem;
+ ITEMHDR* pItemHdr;
+ HDPA hdpaSubItems;
- /* In the following:
- * lpLVItem describes the information requested by the user
- * lpItem/lpSubItem is what we have
- * dispInfo is a structure we use to request the missing
- * information from the application
- */
+ if (internal && !isW)
+ {
+ ERR("We can't have internal non-Unicode GetItem!\n");
+ return FALSE;
+ }
- TRACE("(lpLVItem=%s, internal=%d, isW=%d)\n",
- debuglvitem_t(lpLVItem, isW), internal, isW);
+ /* In the following:
+ * lpLVItem describes the information requested by the user
+ * lpItem is what we have
+ * dispInfo is a structure we use to request the missing
+ * information from the application
+ */
- if ((lpLVItem == NULL) || (lpLVItem->iItem < 0) ||
- (lpLVItem->iItem >= GETITEMCOUNT(infoPtr)))
- return FALSE;
+ TRACE("(lpLVItem=%s, internal=%d, isW=%d)\n",
+ debuglvitem_t(lpLVItem, isW), internal, isW);
- ZeroMemory(&dispInfo, sizeof(dispInfo));
+ if (!lpLVItem || (lpLVItem->iItem < 0) ||
+ (lpLVItem->iItem >= GETITEMCOUNT(infoPtr)))
+ return FALSE;
- if (lStyle & LVS_OWNERDATA)
- {
- if (lpLVItem->mask & ~LVIF_STATE)
+ /* a quick optimization if all we're asked is the focus state
+ * these queries are worth optimising since they are common,
+ * and can be answered in constant time, without the heavy accesses */
+ if ( (lpLVItem->mask == LVIF_STATE) && (lpLVItem->stateMask == LVIF_STATE) &&
+ !(infoPtr->uCallbackMask & LVIS_FOCUSED) )
{
- memcpy(&dispInfo.item, lpLVItem, sizeof(LVITEMW));
- dispinfo_notifyT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
- memcpy(lpLVItem, &dispInfo.item, sizeof(LVITEMW));
- TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
+ lpLVItem->state = 0;
+ if (infoPtr->nFocusedItem == lpLVItem->iItem)
+ lpLVItem->state |= LVIS_FOCUSED;
+ return TRUE;
}
- if ((lpLVItem->mask & LVIF_STATE)&&(lpLVItem->iSubItem == 0))
+ ZeroMemory(&dispInfo, sizeof(dispInfo));
+
+ /* if the app stores all the data, handle it separately */
+ if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & LVS_OWNERDATA)
{
- lpLVItem->state = 0;
- if (infoPtr->nFocusedItem == lpLVItem->iItem)
- lpLVItem->state |= LVIS_FOCUSED;
- if (LISTVIEW_IsSelected(infoPtr,lpLVItem->iItem))
- lpLVItem->state |= LVIS_SELECTED;
- }
+ dispInfo.item.state = 0;
- return TRUE;
- }
+ /* if we need to callback, do it now */
+ if ((lpLVItem->mask & ~LVIF_STATE) || infoPtr->uCallbackMask)
+ {
+ memcpy(&dispInfo.item, lpLVItem, sizeof(LVITEMW));
+ dispInfo.item.stateMask &= infoPtr->uCallbackMask;
+ dispinfo_notifyT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
+ memcpy(lpLVItem, &dispInfo.item, sizeof(LVITEMW));
+ TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW));
+ }
- hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
- if (hdpaSubItems == NULL) return FALSE;
+ /* we store only a little state, so if we're not asked, we're done */
+ if (!(lpLVItem->mask & LVIF_STATE) || lpLVItem->iSubItem) return FALSE;
- if ( (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)) == NULL)
- return FALSE;
+ /* if focus is handled by us, report it */
+ if ( !(infoPtr->uCallbackMask & LVIS_FOCUSED) )
+ {
+ lpLVItem->state &= ~LVIS_FOCUSED;
+ if (infoPtr->nFocusedItem == lpLVItem->iItem)
+ lpLVItem->state |= LVIS_FOCUSED;
+ }
- ZeroMemory(&dispInfo.item, sizeof(LVITEMW));
- if (lpLVItem->iSubItem == 0)
- {
- piImage=&lpItem->iImage;
- ppszText=&lpItem->pszText;
- plParam=&lpItem->lParam;
- if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask)
- {
- dispInfo.item.mask |= LVIF_STATE;
- dispInfo.item.stateMask = infoPtr->uCallbackMask;
- }
- }
- else
- {
- lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
- if (lpSubItem != NULL)
- {
- piImage=&lpSubItem->iImage;
- ppszText=&lpSubItem->pszText;
+ /* and do the same for selection, if we handle it */
+ if ( !(infoPtr->uCallbackMask & LVIS_SELECTED) )
+ {
+ lpLVItem->state &= ~LVIS_SELECTED;
+ if ((lpLVItem->stateMask & LVIS_SELECTED) &&
+ is_item_selected(infoPtr, lpLVItem->iItem))
+ lpLVItem->state |= LVIS_SELECTED;
+ }
+
+ return TRUE;
}
- }
-
- if ((lpLVItem->mask & LVIF_IMAGE) && (*piImage==I_IMAGECALLBACK))
- {
- dispInfo.item.mask |= LVIF_IMAGE;
- }
- if ((lpLVItem->mask & LVIF_TEXT) && !is_textW(*ppszText))
- {
- dispInfo.item.mask |= LVIF_TEXT;
- dispInfo.item.pszText = lpLVItem->pszText;
- dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
- if (dispInfo.item.pszText && lpLVItem->cchTextMax > 0)
- *dispInfo.item.pszText = '\0';
- if (dispInfo.item.pszText && (*ppszText == NULL))
- *dispInfo.item.pszText = '\0';
- }
+ /* find the item and subitem structures before we proceed */
+ hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
+ if (hdpaSubItems == NULL) return FALSE;
- if (dispInfo.item.mask != 0)
- {
- /* We don't have all the requested info, query the application */
- dispInfo.item.iItem = lpLVItem->iItem;
- dispInfo.item.iSubItem = lpLVItem->iSubItem;
- dispInfo.item.lParam = lpItem->lParam;
- dispinfo_notifyT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
- TRACE(" getdispinfo(2):lpLVItem=%s\n", debuglvitem_t(&dispInfo.item, isW));
- }
+ if ( !(lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)) )
+ return FALSE;
- if (dispInfo.item.mask & LVIF_IMAGE)
- {
- lpLVItem->iImage = dispInfo.item.iImage;
- if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (*piImage==I_IMAGECALLBACK))
- *piImage = dispInfo.item.iImage;
- }
- else if (lpLVItem->mask & LVIF_IMAGE)
- {
- lpLVItem->iImage = *piImage;
- }
+ if (lpLVItem->iSubItem)
+ {
+ LISTVIEW_SUBITEM *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
+ if(!lpSubItem) return FALSE;
+ pItemHdr = &lpSubItem->hdr;
+ }
+ else
+ pItemHdr = &lpItem->hdr;
- if (dispInfo.item.mask & LVIF_PARAM)
- {
- lpLVItem->lParam = dispInfo.item.lParam;
- if (dispInfo.item.mask & LVIF_DI_SETITEM)
- *plParam = dispInfo.item.lParam;
- }
- else if (lpLVItem->mask & LVIF_PARAM)
- lpLVItem->lParam = lpItem->lParam;
+ /* Do we need to query the state from the app? */
+ if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && lpLVItem->iSubItem == 0)
+ {
+ dispInfo.item.mask |= LVIF_STATE;
+ dispInfo.item.stateMask = infoPtr->uCallbackMask;
+ }
+
+ /* Do we need to enquire about the image? */
+ if ((lpLVItem->mask & LVIF_IMAGE) && (pItemHdr->iImage==I_IMAGECALLBACK))
+ dispInfo.item.mask |= LVIF_IMAGE;
- if (dispInfo.item.mask & LVIF_TEXT)
- {
- if ((dispInfo.item.mask & LVIF_DI_SETITEM) && *ppszText)
- textsetptrT(ppszText, dispInfo.item.pszText, isW);
+ /* Do we need to enquire about the text? */
+ if ((lpLVItem->mask & LVIF_TEXT) && !is_textW(pItemHdr->pszText))
+ {
+ dispInfo.item.mask |= LVIF_TEXT;
+ dispInfo.item.pszText = lpLVItem->pszText;
+ dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
+ if (dispInfo.item.pszText && dispInfo.item.cchTextMax > 0)
+ *dispInfo.item.pszText = '\0';
+ }
- /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
- /* some apps give a new pointer in ListView_Notify so we can't be sure. */
- if (lpLVItem->pszText != dispInfo.item.pszText)
- textcpynT(lpLVItem->pszText, isW, dispInfo.item.pszText, isW, lpLVItem->cchTextMax);
+ /* If we don't have all the requested info, query the application */
+ if (dispInfo.item.mask != 0)
+ {
+ dispInfo.item.iItem = lpLVItem->iItem;
+ dispInfo.item.iSubItem = lpLVItem->iSubItem;
+ dispInfo.item.lParam = lpItem->lParam;
+ dispinfo_notifyT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW);
+ TRACE(" getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW));
+ }
- }
- else if (lpLVItem->mask & LVIF_TEXT)
- {
- if (internal) lpLVItem->pszText = *ppszText;
- else textcpynT(lpLVItem->pszText, isW, *ppszText, TRUE, lpLVItem->cchTextMax);
- }
+ /* Now, handle the iImage field */
+ if (dispInfo.item.mask & LVIF_IMAGE)
+ {
+ lpLVItem->iImage = dispInfo.item.iImage;
+ if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (pItemHdr->iImage==I_IMAGECALLBACK))
+ pItemHdr->iImage = dispInfo.item.iImage;
+ }
+ else if (lpLVItem->mask & LVIF_IMAGE)
+ lpLVItem->iImage = pItemHdr->iImage;
- if (lpLVItem->iSubItem == 0)
- {
- if (dispInfo.item.mask & LVIF_STATE)
+ /* The pszText field */
+ if (dispInfo.item.mask & LVIF_TEXT)
{
- lpLVItem->state = lpItem->state;
- lpLVItem->state &= ~dispInfo.item.stateMask;
- lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
+ if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->pszText)
+ textsetptrT(&pItemHdr->pszText, dispInfo.item.pszText, isW);
- lpLVItem->state &= ~LVIS_SELECTED;
- if ((dispInfo.item.stateMask & LVIS_SELECTED) &&
- LISTVIEW_IsSelected(infoPtr,dispInfo.item.iItem))
- lpLVItem->state |= LVIS_SELECTED;
+ /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
+ /* some apps give a new pointer in ListView_Notify so we can't be sure. */
+ if (lpLVItem->pszText != dispInfo.item.pszText)
+ textcpynT(lpLVItem->pszText, isW, dispInfo.item.pszText, isW, lpLVItem->cchTextMax);
}
- else if (lpLVItem->mask & LVIF_STATE)
+ else if (lpLVItem->mask & LVIF_TEXT)
{
- lpLVItem->state = lpItem->state & lpLVItem->stateMask;
+ if (internal) lpLVItem->pszText = pItemHdr->pszText;
+ else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax);
+ }
- lpLVItem->state &= ~LVIS_SELECTED;
- if ((lpLVItem->stateMask & LVIS_SELECTED) &&
- LISTVIEW_IsSelected(infoPtr,lpLVItem->iItem))
- lpLVItem->state |= LVIS_SELECTED;
+ /* if this is a subitem, we're done*/
+ if (lpLVItem->iSubItem) return TRUE;
+
+ /* Next is the lParam field */
+ if (dispInfo.item.mask & LVIF_PARAM)
+ {
+ lpLVItem->lParam = dispInfo.item.lParam;
+ if ((dispInfo.item.mask & LVIF_DI_SETITEM))
+ lpItem->lParam = dispInfo.item.lParam;
}
+ else if (lpLVItem->mask & LVIF_PARAM)
+ lpLVItem->lParam = lpItem->lParam;
- if (lpLVItem->mask & LVIF_PARAM)
- lpLVItem->lParam = lpItem->lParam;
+ /* ... the state field (this one is different due to uCallbackmask) */
+ if (lpLVItem->mask & LVIF_STATE)
+ {
+ lpLVItem->state = lpItem->state;
+ if (dispInfo.item.mask & LVIF_STATE)
+ {
+ lpLVItem->state &= ~dispInfo.item.stateMask;
+ lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
+ }
+ if ( !(infoPtr->uCallbackMask & LVIS_FOCUSED) )
+ {
+ lpLVItem->state &= ~LVIS_FOCUSED;
+ if (infoPtr->nFocusedItem == lpLVItem->iItem)
+ lpLVItem->state |= LVIS_FOCUSED;
+ }
+ if ( !(infoPtr->uCallbackMask & LVIS_SELECTED) )
+ {
+ lpLVItem->state &= ~LVIS_SELECTED;
+ if ((lpLVItem->stateMask & LVIS_SELECTED) &&
+ is_item_selected(infoPtr, lpLVItem->iItem))
+ lpLVItem->state |= LVIS_SELECTED;
+ }
+ }
+ /* and last, but not least, the indent field */
if (lpLVItem->mask & LVIF_INDENT)
- lpLVItem->iIndent = lpItem->iIndent;
- }
+ lpLVItem->iIndent = lpItem->iIndent;
- return TRUE;
+ return TRUE;
}
@@ -5432,7 +5036,7 @@
infoPtr->nFocusedItem, nItem);
- focused = (infoPtr->bFocus && infoPtr->nFocusedItem == nItem);
+ focused = infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED);
selected = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED);
uFormat |= (focused) ? DT_NOCLIP : DT_WORD_ELLIPSIS | DT_END_ELLIPSIS;
@@ -6063,7 +5667,7 @@
lvItem.stateMask = uMask;
lvItem.mask = LVIF_STATE;
if (LISTVIEW_GetItemW(infoPtr, &lvItem, TRUE))
- uState = lvItem.state;
+ uState = lvItem.state & uMask;
}
return uState;
@@ -6754,12 +6358,13 @@
*/
static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
{
- LONG lStyle = GetWindowLongW((HWND) lParam, GWL_STYLE);
- LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)first, 0 );
- LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)second, 0 );
- INT cmpv = lstrcmpW( lv_first->pszText, lv_second->pszText );
- /* if we're sorting descending, negate the return value */
- return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
+ LONG lStyle = GetWindowLongW((HWND) lParam, GWL_STYLE);
+ LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)first, 0 );
+ LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( (HDPA)second, 0 );
+ INT cmpv = textcmpWT(lv_first->hdr.pszText, lv_second->hdr.pszText, TRUE);
+
+ /* if we're sorting descending, negate the return value */
+ return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
}
/***
@@ -6777,108 +6382,84 @@
*/
static LRESULT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
{
- LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
- UINT uView = lStyle & LVS_TYPEMASK;
- INT nItem = -1;
- HDPA hdpaSubItems;
- INT nItemWidth = 0;
- LISTVIEW_ITEM *lpItem = NULL;
+ LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
+ UINT uView = lStyle & LVS_TYPEMASK;
+ INT nItem = -1;
+ HDPA hdpaSubItems;
+ NMLISTVIEW nmlv;
+ LISTVIEW_ITEM *lpItem;
+ BOOL is_sorted;
- TRACE("(lpLVItem=%s, isW=%d)\n",
- debuglvitem_t(lpLVItem, isW), isW);
+ TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
- if (lStyle & LVS_OWNERDATA)
- {
- nItem = infoPtr->hdpaItems->nItemCount;
- infoPtr->hdpaItems->nItemCount ++;
- return nItem;
- }
+ if (lStyle & LVS_OWNERDATA)
+ {
+ nItem = infoPtr->hdpaItems->nItemCount;
+ infoPtr->hdpaItems->nItemCount++;
+ return nItem;
+ }
- if (lpLVItem != NULL)
- {
- /* make sure it's not a subitem; cannot insert a subitem */
- if (lpLVItem->iSubItem == 0)
+ /* make sure it's an item, and not a subitem; cannot insert a subitem */
+ if (!lpLVItem || lpLVItem->iSubItem) return -1;
+
+ if (!is_assignable_item(lpLVItem, lStyle)) return -1;
+
+ if ( !(lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM))) )
+ return -1;
+
+ ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
+
+ /* insert item in listview control data structure */
+ if ( (hdpaSubItems = DPA_Create(8)) )
+ nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
+ if (nItem == -1) goto fail;
+
+ is_sorted = (lStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) &&
+ !(lStyle & LVS_OWNERDRAWFIXED) && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText);
+
+ nItem = DPA_InsertPtr( infoPtr->hdpaItems,
+ is_sorted ? GETITEMCOUNT( infoPtr ) + 1 : lpLVItem->iItem,
+ hdpaSubItems );
+ if (nItem == -1) goto fail;
+
+ if (!LISTVIEW_SetItemT(infoPtr, lpLVItem, isW)) goto fail;
+
+ /* if we're sorted, sort the list, and update the index */
+ if (is_sorted)
{
- if ( (lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM))) )
- {
- ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
- if (LISTVIEW_InitItemT(infoPtr, lpItem, lpLVItem, isW))
- {
- /* insert item in listview control data structure */
- if ( (hdpaSubItems = DPA_Create(8)) )
- {
- if ( (nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem)) != -1)
- {
- if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
- && !(lStyle & LVS_OWNERDRAWFIXED)
- && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText) )
- {
- /* Insert the item in the proper sort order based on the pszText
- member. See comments for LISTVIEW_InsertCompare() for greater detail */
- nItem = DPA_InsertPtr( infoPtr->hdpaItems,
- GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
- DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, (LPARAM)infoPtr->hwndSelf );
- nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
- }
- else
- {
- nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
- hdpaSubItems);
- }
- if (nItem != -1)
- {
- NMLISTVIEW nmlv;
+ DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, (LPARAM)infoPtr->hwndSelf );
+ nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
+ if (nItem == -1) goto fail;
+ }
- LISTVIEW_ShiftIndices(infoPtr,nItem,1);
+ LISTVIEW_ShiftIndices(infoPtr, nItem, 1);
+
+ lpItem->valid = TRUE;
- /* manage item focus */
- if (lpLVItem->mask & LVIF_STATE)
- {
- lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
- if (lpLVItem->stateMask & LVIS_SELECTED)
- LISTVIEW_SetSelection(infoPtr, nItem);
- else if (lpLVItem->stateMask & LVIS_FOCUSED)
- LISTVIEW_SetItemFocus(infoPtr, nItem);
- }
-
- /* send LVN_INSERTITEM notification */
- ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
- nmlv.iItem = nItem;
- nmlv.lParam = lpItem->lParam;
- listview_notify(infoPtr, LVN_INSERTITEM, &nmlv);
-
- if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
- {
- nItemWidth = LISTVIEW_CalculateWidth(infoPtr, lpLVItem->iItem);
- if (nItemWidth > infoPtr->nItemWidth)
- infoPtr->nItemWidth = nItemWidth;
- }
-
- /* align items (set position of each item) */
- if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
- {
- if (lStyle & LVS_ALIGNLEFT)
- LISTVIEW_AlignLeft(infoPtr);
- else
- LISTVIEW_AlignTop(infoPtr);
- }
-
- LISTVIEW_UpdateScroll(infoPtr);
- /* refresh client area */
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- }
- }
- }
- }
- }
+ /* send LVN_INSERTITEM notification */
+ ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
+ nmlv.iItem = nItem;
+ nmlv.lParam = lpItem->lParam;
+ listview_notify(infoPtr, LVN_INSERTITEM, &nmlv);
+
+ /* align items (set position of each item) */
+ if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
+ {
+ if (lStyle & LVS_ALIGNLEFT) LISTVIEW_AlignLeft(infoPtr);
+ else LISTVIEW_AlignTop(infoPtr);
}
- }
- /* free memory if unsuccessful */
- if ((nItem == -1) && (lpItem != NULL))
- COMCTL32_Free(lpItem);
+ LISTVIEW_UpdateScroll(infoPtr);
+
+ /* FIXME: refresh client area */
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- return nItem;
+ return nItem;
+
+fail:
+ DPA_Destroy (hdpaSubItems);
+ COMCTL32_Free (lpItem);
+ return -1;
}
/***
@@ -6981,12 +6562,14 @@
*/
static LRESULT LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrBk)
{
- if(infoPtr->clrBk != clrBk){
- infoPtr->clrBk = clrBk;
- InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
- }
+ if(infoPtr->clrBk != clrBk) {
+ infoPtr->clrBk = clrBk;
+ if (infoPtr->hBkBrush) DeleteObject(infoPtr->hBkBrush);
+ infoPtr->hBkBrush = CreateSolidBrush(clrBk);
+ InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
+ }
- return TRUE;
+ return TRUE;
}
/* LISTVIEW_SetBkImage */
@@ -7857,6 +7440,11 @@
if (nCount < 2)
return TRUE;
+ if (infoPtr->nFocusedItem >= 0)
+ {
+ /* FIXME: set the LVIS_FOCUSED in pLVItem->state*/
+ }
+
infoPtr->pfnCompare = pfnCompare;
infoPtr->lParamSort = lParamSort;
DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, (LPARAM)infoPtr->hwndSelf);
@@ -7877,7 +7465,7 @@
else
LISTVIEW_RemoveSelectionRange(infoPtr, i, i);
if (pLVItem->state & LVIS_FOCUSED)
- infoPtr->nFocusedItem=i;
+ infoPtr->nFocusedItem = i;
}
if (selectionMarkItem != NULL)
infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
@@ -7971,6 +7559,7 @@
infoPtr->clrBk = comctl32_color.clrWindow;
infoPtr->clrText = comctl32_color.clrWindowText;
infoPtr->clrTextBk = CLR_DEFAULT;
+ infoPtr->hBkBrush = CreateSolidBrush(infoPtr->clrBk);
/* set default values */
infoPtr->uCallbackMask = 0;
@@ -8066,61 +7655,20 @@
static LRESULT LISTVIEW_EraseBackground(LISTVIEW_INFO *infoPtr, WPARAM wParam,
LPARAM lParam)
{
- BOOL bResult;
-
- TRACE("(wParam=%x, lParam=%lx)\n", wParam, lParam);
-
- if (infoPtr->clrBk == CLR_NONE)
- {
- bResult = SendMessageW(GetParent(infoPtr->hwndSelf), WM_ERASEBKGND, wParam, lParam);
- TRACE("erase CLR_NONE result=%d\n", bResult);
- }
- else
- {
RECT rc;
- HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
- GetClientRect(infoPtr->hwndSelf, &rc);
- FillRect((HDC)wParam, &rc, hBrush);
- DeleteObject(hBrush);
- TRACE("erase rect=(%d,%d)-(%d,%d), clrBk=0x%08lx\n",
- rc.left, rc.top, rc.right, rc.bottom, infoPtr->clrBk);
- bResult = TRUE;
- }
-
- return bResult;
-}
+ TRACE("(wParam=%x, lParam=%lx)\n", wParam, lParam);
-static void LISTVIEW_FillBackground(LISTVIEW_INFO *infoPtr, HDC hdc, LPRECT rc)
-{
- TRACE("(hwnd=%x, hdc=%x, clrBk=0x%08lx, rc=(%d,%d)-(%d,%d))\n",
- infoPtr->hwndSelf, hdc, infoPtr->clrBk,
- rc->left, rc->top, rc->right, rc->bottom);
+ /* FIXME: whu erase background, if we're doing it individually for every item? */
+ if (infoPtr->clrBk == CLR_NONE)
+ return SendMessageW(GetParent(infoPtr->hwndSelf), WM_ERASEBKGND, wParam, lParam);
+
+ GetClientRect(infoPtr->hwndSelf, &rc);
+ FillRect((HDC)wParam, &rc, infoPtr->hBkBrush);
- if (infoPtr->clrBk != CLR_NONE)
- {
- COLORREF clrbrsh = infoPtr->clrBk;
- HBRUSH hBrush = CreateSolidBrush(clrbrsh);
- FillRect(hdc, rc, hBrush);
- DeleteObject(hBrush);
- }
+ return 0;
}
-static void LISTVIEW_SuperFillBackground(LISTVIEW_INFO *infoPtr, HDC hdc,
- LPRECT rc, COLORREF clrbrsh)
-{
- TRACE("(hwnd=%x, hdc=%x, clrBk=0x%08lx, rc=(%d,%d)-(%d,%d))\n",
- infoPtr->hwndSelf, hdc, infoPtr->clrBk,
- rc->left, rc->top, rc->right, rc->bottom);
-
- if (infoPtr->clrBk != CLR_NONE)
- {
- HBRUSH hBrush = CreateSolidBrush(clrbrsh);
- FillRect(hdc, rc, hBrush);
- DeleteObject(hBrush);
- }
-}
-
/***
* DESCRIPTION:
* Performs vertical scrolling.
@@ -8509,7 +8057,7 @@
}
for (i = nTop; i<nBottom; i++)
{
- if (LISTVIEW_IsSelected(infoPtr,i))
+ if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED))
{
RECT rcItem;
rcItem.left = LVIR_BOUNDS;
@@ -8618,7 +8166,17 @@
}
else if (wKey & MK_CONTROL)
{
- bGroupSelect = LISTVIEW_ToggleSelection(infoPtr, nItem);
+ LVITEMW item;
+
+ bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0);
+
+ ZeroMemory(&item, sizeof(item));
+ item.stateMask = LVIS_SELECTED;
+ if(bGroupSelect) item.state = LVIS_SELECTED;
+ LISTVIEW_SetItemState(infoPtr, nItem, &item);
+
+ LISTVIEW_SetItemFocus(infoPtr, nItem);
+ infoPtr->nSelectionMark = nItem;
}
else if (wKey & MK_SHIFT)
{
@@ -8748,12 +8306,10 @@
#endif
}
- /* destroy font */
- infoPtr->hFont = (HFONT)0;
- if (infoPtr->hDefaultFont)
- {
- DeleteObject(infoPtr->hDefaultFont);
- }
+ /* destroy font, bkgnd brush */
+ infoPtr->hFont = 0;
+ if (infoPtr->hDefaultFont) DeleteObject(infoPtr->hDefaultFont);
+ if (infoPtr->hBkBrush) DeleteObject(infoPtr->hBkBrush);
/* free listview info pointer*/
COMCTL32_Free(infoPtr);
@@ -8933,7 +8489,7 @@
{
LISTVIEW_SetItemFocus(infoPtr,nItem);
if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) &&
- !LISTVIEW_IsSelected(infoPtr,nItem))
+ !LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED))
LISTVIEW_SetSelection(infoPtr, nItem);
}
else
@@ -9823,7 +9379,7 @@
* RETURN:
* None
*/
-VOID LISTVIEW_Register(void)
+void LISTVIEW_Register(void)
{
WNDCLASSW wndClass;
@@ -9848,7 +9404,7 @@
* RETURN:
* None
*/
-VOID LISTVIEW_Unregister(void)
+void LISTVIEW_Unregister(void)
{
UnregisterClassW(WC_LISTVIEWW, (HINSTANCE)NULL);
}
More information about the wine-patches
mailing list