4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
8 * Listview control implementation.
11 * 1. No horizontal scrolling when header is larger than the client area.
12 * 2. Drawing optimizations.
13 * 3. Hot item handling.
16 * LISTVIEW_Notify : most notifications from children (editbox and header)
19 * LISTVIEW_SetItemCount : empty stub
22 * LISTVIEW_SetItemW : no unicode support
23 * LISTVIEW_InsertItemW : no unicode support
24 * LISTVIEW_InsertColumnW : no unicode support
25 * LISTVIEW_GetColumnW : no unicode support
26 * LISTVIEW_SetColumnW : no unicode support
28 * Advanced functionality:
29 * LISTVIEW_GetNumberOfWorkAreas : not implemented
30 * LISTVIEW_GetHotCursor : not implemented
31 * LISTVIEW_GetHoverTime : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_GetColumnOrderArray : not implemented
35 * LISTVIEW_SetColumnOrderArray : not implemented
36 * LISTVIEW_Arrange : empty stub
37 * LISTVIEW_ApproximateViewRect : incomplete
38 * LISTVIEW_Scroll : not implemented
39 * LISTVIEW_RedrawItems : empty stub
40 * LISTVIEW_Update : not completed
48 #include "debugtools.h"
50 DEFAULT_DEBUG_CHANNEL(listview)
56 /* maximum size of a label */
57 #define DISP_TEXT_SIZE 128
59 /* padding for items in list and small icon display modes */
60 #define WIDTH_PADDING 12
62 /* padding for items in list, report and small icon display modes */
63 #define HEIGHT_PADDING 1
65 /* offset of items in report display mode */
66 #define REPORT_MARGINX 2
68 /* padding for icon in large icon display mode */
69 #define ICON_TOP_PADDING 2
70 #define ICON_BOTTOM_PADDING 2
72 /* padding for label in large icon display mode */
73 #define LABEL_VERT_OFFSET 2
75 /* default label width for items in list and small icon display modes */
76 #define DEFAULT_LABEL_WIDTH 40
78 /* default column width for items in list display mode */
79 #define DEFAULT_COLUMN_WIDTH 96
81 /* Increment size of the horizontal scroll bar */
82 #define LISTVIEW_SCROLL_DIV_SIZE 10
87 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
88 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
89 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
90 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
91 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
92 /* retrieve the number of items in the listview */
93 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
95 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
96 INT width, INT height, HWND parent, HINSTANCE hinst,
97 EditlblCallback EditLblCb, DWORD param);
100 * forward declarations
102 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
103 static INT LISTVIEW_GetCountPerRow(HWND);
104 static INT LISTVIEW_GetCountPerColumn(HWND);
105 static VOID LISTVIEW_AlignLeft(HWND);
106 static VOID LISTVIEW_AlignTop(HWND);
107 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
108 static VOID LISTVIEW_AddSelection(HWND, INT);
109 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
110 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
111 static INT LISTVIEW_GetItemHeight(HWND);
112 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
113 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
114 static INT LISTVIEW_GetItemWidth(HWND);
115 static INT LISTVIEW_GetLabelWidth(HWND, INT);
116 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
117 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
118 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
119 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
120 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
121 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
122 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
123 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
124 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
125 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
126 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
127 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
128 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
129 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
130 static VOID LISTVIEW_UpdateScroll(HWND);
131 static VOID LISTVIEW_SetSelection(HWND, INT);
132 static VOID LISTVIEW_UpdateSize(HWND);
133 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
134 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
135 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
136 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
137 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
138 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
139 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
141 /*************************************************************************
142 * LISTVIEW_UpdateHeaderSize [Internal]
144 * Function to resize the header control
147 * hwnd [I] handle to a window
148 * nNewScrollPos [I] Scroll Pos to Set
155 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
157 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
161 GetWindowRect(infoPtr->hwndHeader, &winRect);
162 point[0].x = winRect.left;
163 point[0].y = winRect.top;
164 point[1].x = winRect.right;
165 point[1].y = winRect.bottom;
167 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
168 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
169 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
171 SetWindowPos(infoPtr->hwndHeader,0,
172 point[0].x,point[0].y,point[1].x,point[1].y,
173 SWP_NOZORDER | SWP_NOACTIVATE);
178 * Update the scrollbars. This functions should be called whenever
179 * the content, size or view changes.
182 * [I] HWND : window handle
187 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
189 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
190 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
191 UINT uView = lStyle & LVS_TYPEMASK;
192 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
193 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
194 SCROLLINFO scrollInfo;
196 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
197 scrollInfo.cbSize = sizeof(SCROLLINFO);
199 if (uView == LVS_LIST)
201 /* update horizontal scrollbar */
203 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
204 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
205 INT nCountPerPage = nCountPerRow * nCountPerColumn;
206 INT nNumOfItems = GETITEMCOUNT(infoPtr);
208 if (nCountPerPage < GETITEMCOUNT(infoPtr))
210 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
211 if((nNumOfItems % nCountPerColumn) == 0)
215 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
216 scrollInfo.nPage = nCountPerRow;
217 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
218 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
223 if (lStyle & WS_HSCROLL)
225 ShowScrollBar(hwnd, SB_HORZ, FALSE);
229 else if (uView == LVS_REPORT)
231 /* update vertical scrollbar */
233 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
234 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
235 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
236 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
237 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
239 /* update horizontal scrollbar */
240 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
245 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
246 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
247 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
248 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
250 /* Update the Header Control */
251 scrollInfo.fMask = SIF_POS;
252 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
253 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
260 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
262 INT nViewWidth = rcView.right - rcView.left;
263 INT nViewHeight = rcView.bottom - rcView.top;
265 if (nViewWidth > nListWidth)
267 scrollInfo.fMask = SIF_POS;
268 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
272 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
274 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
275 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
276 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
280 if (lStyle & WS_HSCROLL)
282 ShowScrollBar(hwnd, SB_HORZ, FALSE);
286 if (nViewHeight > nListHeight)
288 scrollInfo.fMask = SIF_POS;
289 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE)
293 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
295 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
296 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
297 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
301 if (lStyle & WS_VSCROLL)
303 ShowScrollBar(hwnd, SB_VERT, FALSE);
312 * Prints a message for unsupported window styles.
313 * A kind of TODO list for window styles.
316 * [I] LONG : window style
321 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
323 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
325 FIXME(" LVS_EDITLABELS\n");
328 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
330 FIXME(" LVS_NOLABELWRAP\n");
333 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
335 FIXME(" LVS_NOSCROLL\n");
338 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
340 FIXME(" LVS_NOSORTHEADER\n");
343 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
345 FIXME(" LVS_OWNERDRAWFIXED\n");
348 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
350 FIXME(" LVS_SHAREIMAGELISTS\n");
353 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
355 FIXME(" LVS_SORTASCENDING\n");
358 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
360 FIXME(" LVS_SORTDESCENDING\n");
366 * Aligns the items with the top edge of the window.
369 * [I] HWND : window handle
374 static VOID LISTVIEW_AlignTop(HWND hwnd)
376 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
377 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
378 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
383 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
385 ZeroMemory(&ptItem, sizeof(POINT));
386 ZeroMemory(&rcView, sizeof(RECT));
388 if (nListWidth > infoPtr->nItemWidth)
390 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
392 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
395 ptItem.y += infoPtr->nItemHeight;
398 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
399 ptItem.x += infoPtr->nItemWidth;
400 rcView.right = max(rcView.right, ptItem.x);
403 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
407 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
409 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
410 ptItem.y += infoPtr->nItemHeight;
413 rcView.right = infoPtr->nItemWidth;
414 rcView.bottom = ptItem.y;
417 LISTVIEW_SetViewRect(hwnd, &rcView);
423 * Aligns the items with the left edge of the window.
426 * [I] HWND : window handle
431 static VOID LISTVIEW_AlignLeft(HWND hwnd)
433 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
434 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
435 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
440 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
442 ZeroMemory(&ptItem, sizeof(POINT));
443 ZeroMemory(&rcView, sizeof(RECT));
445 if (nListHeight > infoPtr->nItemHeight)
447 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
449 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
452 ptItem.x += infoPtr->nItemWidth;
455 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
456 ptItem.y += infoPtr->nItemHeight;
457 rcView.bottom = max(rcView.bottom, ptItem.y);
460 rcView.right = ptItem.x + infoPtr->nItemWidth;
464 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
466 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
467 ptItem.x += infoPtr->nItemWidth;
470 rcView.bottom = infoPtr->nItemHeight;
471 rcView.right = ptItem.x;
474 LISTVIEW_SetViewRect(hwnd, &rcView);
480 * Set the bounding rectangle of all the items.
483 * [I] HWND : window handle
484 * [I] LPRECT : bounding rectangle
490 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
493 BOOL bResult = FALSE;
495 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
496 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
498 if (lprcView != NULL)
501 infoPtr->rcView.left = lprcView->left;
502 infoPtr->rcView.top = lprcView->top;
503 infoPtr->rcView.right = lprcView->right;
504 infoPtr->rcView.bottom = lprcView->bottom;
512 * Retrieves the bounding rectangle of all the items.
515 * [I] HWND : window handle
516 * [O] LPRECT : bounding rectangle
522 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
524 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
525 BOOL bResult = FALSE;
528 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
530 if (lprcView != NULL)
532 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
533 if (bResult != FALSE)
535 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
536 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
537 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
538 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
541 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
542 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
550 * Retrieves the subitem pointer associated with the subitem index.
553 * [I] HDPA : DPA handle for a specific item
554 * [I] INT : index of subitem
557 * SUCCESS : subitem pointer
560 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
563 LISTVIEW_SUBITEM *lpSubItem;
566 for (i = 1; i < hdpaSubItems->nItemCount; i++)
568 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
569 if (lpSubItem != NULL)
571 if (lpSubItem->iSubItem == nSubItem)
583 * Calculates the width of an item.
586 * [I] HWND : window handle
587 * [I] LONG : window style
590 * Returns item width.
592 static INT LISTVIEW_GetItemWidth(HWND hwnd)
594 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
595 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
596 INT nHeaderItemCount;
602 TRACE("(hwnd=%x)\n", hwnd);
604 if (uView == LVS_ICON)
606 nItemWidth = infoPtr->iconSpacing.cx;
608 else if (uView == LVS_REPORT)
610 /* calculate width of header */
611 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
612 for (i = 0; i < nHeaderItemCount; i++)
614 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
616 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
622 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
624 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
625 nItemWidth = max(nItemWidth, nLabelWidth);
628 /* default label size */
629 if (GETITEMCOUNT(infoPtr) == 0)
631 nItemWidth = DEFAULT_COLUMN_WIDTH;
637 nItemWidth = DEFAULT_LABEL_WIDTH;
642 nItemWidth += WIDTH_PADDING;
644 if (infoPtr->himlSmall != NULL)
646 nItemWidth += infoPtr->iconSize.cx;
649 if (infoPtr->himlState != NULL)
651 nItemWidth += infoPtr->iconSize.cx;
662 * Calculates the width of a specific item.
665 * [I] HWND : window handle
669 * Returns the width of an item width a specified string.
671 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
673 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
674 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
675 INT nHeaderItemCount;
680 TRACE("(hwnd=%x)\n", hwnd);
682 if (uView == LVS_ICON)
684 nItemWidth = infoPtr->iconSpacing.cx;
686 else if (uView == LVS_REPORT)
688 /* calculate width of header */
689 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
690 for (i = 0; i < nHeaderItemCount; i++)
692 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
694 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
700 /* get width of string */
701 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
703 /* default label size */
704 if (GETITEMCOUNT(infoPtr) == 0)
706 nItemWidth = DEFAULT_COLUMN_WIDTH;
712 nItemWidth = DEFAULT_LABEL_WIDTH;
717 nItemWidth += WIDTH_PADDING;
719 if (infoPtr->himlSmall != NULL)
721 nItemWidth += infoPtr->iconSize.cx;
724 if (infoPtr->himlState != NULL)
726 nItemWidth += infoPtr->iconSize.cx;
737 * Calculates the height of an item.
740 * [I] HWND : window handle
741 * [I] LONG : window style
744 * Returns item height.
746 static INT LISTVIEW_GetItemHeight(HWND hwnd)
748 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
749 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
752 if (uView == LVS_ICON)
754 nItemHeight = infoPtr->iconSpacing.cy;
759 HDC hdc = GetDC(hwnd);
760 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
761 GetTextMetricsA(hdc, &tm);
762 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
763 SelectObject(hdc, hOldFont);
764 ReleaseDC(hwnd, hdc);
772 * Adds a block of selections.
775 * [I] HWND : window handle
776 * [I] INT : item index
781 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
783 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
784 INT nFirst = min(infoPtr->nSelectionMark, nItem);
785 INT nLast = max(infoPtr->nSelectionMark, nItem);
789 lvItem.state = LVIS_SELECTED;
790 lvItem.stateMask= LVIS_SELECTED;
792 for (i = nFirst; i <= nLast; i++)
794 ListView_SetItemState(hwnd, i, &lvItem);
797 LISTVIEW_SetItemFocus(hwnd, nItem);
798 infoPtr->nSelectionMark = nItem;
803 * Adds a single selection.
806 * [I] HWND : window handle
807 * [I] INT : item index
812 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
814 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
817 lvItem.state = LVIS_SELECTED;
818 lvItem.stateMask= LVIS_SELECTED;
820 ListView_SetItemState(hwnd, nItem, &lvItem);
822 LISTVIEW_SetItemFocus(hwnd, nItem);
823 infoPtr->nSelectionMark = nItem;
828 * Selects or unselects an item.
831 * [I] HWND : window handle
832 * [I] INT : item index
838 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
840 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
844 lvItem.stateMask= LVIS_SELECTED;
846 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
849 ListView_SetItemState(hwnd, nItem, &lvItem);
854 lvItem.state = LVIS_SELECTED;
855 ListView_SetItemState(hwnd, nItem, &lvItem);
859 LISTVIEW_SetItemFocus(hwnd, nItem);
860 infoPtr->nSelectionMark = nItem;
867 * Selects items based on view coorddiantes.
870 * [I] HWND : window handle
871 * [I] RECT : selection rectangle
876 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
878 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
883 lvItem.stateMask = LVIS_SELECTED;
885 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
887 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
888 if (PtInRect(&rcSelRect, ptItem) != FALSE)
890 lvItem.state = LVIS_SELECTED;
897 ListView_SetItemState(hwnd, i, &lvItem);
903 * Sets a single group selection.
906 * [I] HWND : window handle
907 * [I] INT : item index
912 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
914 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
915 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
918 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
921 INT nFirst = min(infoPtr->nSelectionMark, nItem);
922 INT nLast = max(infoPtr->nSelectionMark, nItem);
923 lvItem.stateMask = LVIS_SELECTED;
925 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
927 if ((i < nFirst) || (i > nLast))
933 lvItem.state = LVIS_SELECTED;
936 ListView_SetItemState(hwnd, i, &lvItem);
944 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
945 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
946 rcSel.left = min(ptSelMark.x, ptItem.x);
947 rcSel.top = min(ptSelMark.y, ptItem.y);
948 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
949 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
950 LISTVIEW_SetSelectionRect(hwnd, rcSel);
953 LISTVIEW_SetItemFocus(hwnd, nItem);
958 * Manages the item focus.
961 * [I] HWND : window handle
962 * [I] INT : item index
965 * TRUE : focused item changed
966 * FALSE : focused item has NOT changed
968 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
970 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
971 BOOL bResult = FALSE;
974 if (infoPtr->nFocusedItem != nItem)
977 ZeroMemory(&lvItem, sizeof(LVITEMA));
978 lvItem.stateMask = LVIS_FOCUSED;
979 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
981 lvItem.state = LVIS_FOCUSED;
982 lvItem.stateMask = LVIS_FOCUSED;
983 ListView_SetItemState(hwnd, nItem, &lvItem);
985 infoPtr->nFocusedItem = nItem;
986 ListView_EnsureVisible(hwnd, nItem, FALSE);
994 * Sets a single selection.
997 * [I] HWND : window handle
998 * [I] INT : item index
1003 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1005 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1010 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
1013 if (nItem < GETITEMCOUNT(infoPtr))
1015 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
1018 ZeroMemory(&lvItem, sizeof(LVITEMA));
1019 lvItem.stateMask = LVIS_FOCUSED;
1020 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1022 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
1023 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1024 ListView_SetItemState(hwnd, nItem, &lvItem);
1026 infoPtr->nFocusedItem = nItem;
1027 infoPtr->nSelectionMark = nItem;
1032 * Set selection(s) with keyboard.
1035 * [I] HWND : window handle
1036 * [I] INT : item index
1039 * SUCCESS : TRUE (needs to be repainted)
1040 * FAILURE : FALSE (nothing has changed)
1042 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1044 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1045 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1046 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1047 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1048 BOOL bResult = FALSE;
1050 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1052 if (lStyle & LVS_SINGLESEL)
1055 LISTVIEW_SetSelection(hwnd, nItem);
1056 ListView_EnsureVisible(hwnd, nItem, FALSE);
1063 LISTVIEW_SetGroupSelection(hwnd, nItem);
1067 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1072 LISTVIEW_SetSelection(hwnd, nItem);
1073 ListView_EnsureVisible(hwnd, nItem, FALSE);
1083 * Selects an item based on coordinates.
1086 * [I] HWND : window handle
1087 * [I] POINT : mouse click ccordinates
1090 * SUCCESS : item index
1093 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1095 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1099 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1101 rcItem.left = LVIR_SELECTBOUNDS;
1102 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1104 if (PtInRect(&rcItem, pt) != FALSE)
1116 * Removes all selection states.
1119 * [I] HWND : window handle
1120 * [I] INT : item index
1126 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1132 lvItem.stateMask = LVIS_SELECTED;
1134 for (i = nFirst; i <= nLast; i++)
1136 ListView_SetItemState(hwnd, i, &lvItem);
1145 * [IO] HDPA : dynamic pointer array handle
1146 * [I] INT : column index (subitem index)
1152 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1154 BOOL bResult = TRUE;
1158 for (i = 0; i < hdpaItems->nItemCount; i++)
1160 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1161 if (hdpaSubItems != NULL)
1163 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1175 * Removes a subitem at a given position.
1178 * [IO] HDPA : dynamic pointer array handle
1179 * [I] INT : subitem index
1185 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1187 LISTVIEW_SUBITEM *lpSubItem;
1190 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1192 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1193 if (lpSubItem != NULL)
1195 if (lpSubItem->iSubItem == nSubItem)
1198 if ((lpSubItem->pszText != NULL) &&
1199 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1201 COMCTL32_Free(lpSubItem->pszText);
1205 COMCTL32_Free(lpSubItem);
1207 /* free dpa memory */
1208 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1213 else if (lpSubItem->iSubItem > nSubItem)
1225 * Compares the item information.
1228 * [I] LISTVIEW_ITEM *: destination item
1229 * [I] LPLVITEM : source item
1232 * SUCCCESS : TRUE (EQUAL)
1233 * FAILURE : FALSE (NOT EQUAL)
1235 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1239 if ((lpItem != NULL) && (lpLVItem != NULL))
1241 if (lpLVItem->mask & LVIF_STATE)
1243 if ((lpItem->state & lpLVItem->stateMask) !=
1244 (lpLVItem->state & lpLVItem->stateMask))
1246 uChanged |= LVIF_STATE;
1250 if (lpLVItem->mask & LVIF_IMAGE)
1252 if (lpItem->iImage != lpLVItem->iImage)
1254 uChanged |= LVIF_IMAGE;
1258 if (lpLVItem->mask & LVIF_PARAM)
1260 if (lpItem->lParam != lpLVItem->lParam)
1262 uChanged |= LVIF_PARAM;
1266 if (lpLVItem->mask & LVIF_INDENT)
1268 if (lpItem->iIndent != lpLVItem->iIndent)
1270 uChanged |= LVIF_INDENT;
1274 if (lpLVItem->mask & LVIF_TEXT)
1276 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1278 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1280 uChanged |= LVIF_TEXT;
1285 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1287 uChanged |= LVIF_TEXT;
1291 if (lpLVItem->pszText)
1293 if (lpItem->pszText)
1295 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1297 uChanged |= LVIF_TEXT;
1302 uChanged |= LVIF_TEXT;
1307 if (lpItem->pszText)
1309 uChanged |= LVIF_TEXT;
1321 * Initializes item attributes.
1324 * [I] HWND : window handle
1325 * [O] LISTVIEW_ITEM *: destination item
1326 * [I] LPLVITEM : source item
1332 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1335 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1336 BOOL bResult = FALSE;
1338 if ((lpItem != NULL) && (lpLVItem != NULL))
1342 if (lpLVItem->mask & LVIF_STATE)
1344 lpItem->state &= ~lpLVItem->stateMask;
1345 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1348 if (lpLVItem->mask & LVIF_IMAGE)
1350 lpItem->iImage = lpLVItem->iImage;
1353 if (lpLVItem->mask & LVIF_PARAM)
1355 lpItem->lParam = lpLVItem->lParam;
1358 if (lpLVItem->mask & LVIF_INDENT)
1360 lpItem->iIndent = lpLVItem->iIndent;
1363 if (lpLVItem->mask & LVIF_TEXT)
1365 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1367 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1372 if ((lpItem->pszText != NULL) &&
1373 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1375 COMCTL32_Free(lpItem->pszText);
1378 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1382 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1384 lpItem->pszText = NULL;
1387 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1397 * Initializes subitem attributes.
1399 * NOTE: The documentation specifies that the operation fails if the user
1400 * tries to set the indent of a subitem.
1403 * [I] HWND : window handle
1404 * [O] LISTVIEW_SUBITEM *: destination subitem
1405 * [I] LPLVITEM : source subitem
1411 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1414 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1415 BOOL bResult = FALSE;
1417 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1419 if (!(lpLVItem->mask & LVIF_INDENT))
1422 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1424 lpSubItem->iSubItem = lpLVItem->iSubItem;
1426 if (lpLVItem->mask & LVIF_IMAGE)
1428 lpSubItem->iImage = lpLVItem->iImage;
1431 if (lpLVItem->mask & LVIF_TEXT)
1433 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1435 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1440 if ((lpSubItem->pszText != NULL) &&
1441 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1443 COMCTL32_Free(lpSubItem->pszText);
1446 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1450 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1452 lpSubItem->pszText = NULL;
1455 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1466 * Adds a subitem at a given position (column index).
1469 * [I] HWND : window handle
1470 * [I] LPLVITEM : new subitem atttributes
1476 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1478 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1479 LISTVIEW_SUBITEM *lpSubItem = NULL;
1480 BOOL bResult = FALSE;
1482 INT nPosition, nItem;
1484 if (lpLVItem != NULL)
1486 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1487 if (hdpaSubItems != NULL)
1489 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1490 if (lpSubItem != NULL)
1492 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1494 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1495 lpSubItem->iSubItem);
1496 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1506 /* cleanup if unsuccessful */
1507 if ((bResult == FALSE) && (lpSubItem != NULL))
1509 COMCTL32_Free(lpSubItem);
1517 * Finds the dpa insert position (array index).
1520 * [I] HWND : window handle
1521 * [I] INT : subitem index
1527 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1529 LISTVIEW_SUBITEM *lpSubItem;
1532 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1534 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1535 if (lpSubItem != NULL)
1537 if (lpSubItem->iSubItem > nSubItem)
1544 return hdpaSubItems->nItemCount;
1549 * Retrieves a listview subitem at a given position (column index).
1552 * [I] HWND : window handle
1553 * [I] INT : subitem index
1559 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1561 LISTVIEW_SUBITEM *lpSubItem;
1564 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1566 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1567 if (lpSubItem != NULL)
1569 if (lpSubItem->iSubItem == nSubItem)
1573 else if (lpSubItem->iSubItem > nSubItem)
1585 * Sets item attributes.
1588 * [I] HWND : window handle
1589 * [I] LPLVITEM : new item atttributes
1595 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1597 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1598 BOOL bResult = FALSE;
1600 LISTVIEW_ITEM *lpItem;
1603 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1605 if (lpLVItem != NULL)
1607 if (lpLVItem->iSubItem == 0)
1609 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1610 if (hdpaSubItems != NULL)
1612 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1615 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1616 nmlv.hdr.hwndFrom = hwnd;
1617 nmlv.hdr.idFrom = lCtrlId;
1618 nmlv.hdr.code = LVN_ITEMCHANGING;
1619 nmlv.lParam = lpItem->lParam;
1620 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1623 if (uChanged & LVIF_STATE)
1625 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1626 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1629 nmlv.uChanged = uChanged;
1630 nmlv.iItem = lpLVItem->iItem;
1631 nmlv.lParam = lpItem->lParam;
1632 /* send LVN_ITEMCHANGING notification */
1633 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1635 /* copy information */
1636 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1638 /* send LVN_ITEMCHANGED notification */
1639 nmlv.hdr.code = LVN_ITEMCHANGED;
1640 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1647 InvalidateRect(hwnd, NULL, FALSE);
1658 * Sets subitem attributes.
1661 * [I] HWND : window handle
1662 * [I] LPLVITEM : new subitem atttributes
1668 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1670 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1671 BOOL bResult = FALSE;
1673 LISTVIEW_SUBITEM *lpSubItem;
1675 if (lpLVItem != NULL)
1677 if (lpLVItem->iSubItem > 0)
1679 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1680 if (hdpaSubItems != NULL)
1682 /* set subitem only if column is present */
1683 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1685 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1686 if (lpSubItem != NULL)
1688 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1692 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1695 InvalidateRect(hwnd, NULL, FALSE);
1706 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1709 * [I] HWND : window handle
1714 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1716 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1717 UINT uView = lStyle & LVS_TYPEMASK;
1719 SCROLLINFO scrollInfo;
1721 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1722 scrollInfo.cbSize = sizeof(SCROLLINFO);
1723 scrollInfo.fMask = SIF_POS;
1725 if (uView == LVS_LIST)
1727 if (lStyle & WS_HSCROLL)
1729 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1731 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1735 else if (uView == LVS_REPORT)
1737 if (lStyle & WS_VSCROLL)
1739 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1741 nItem = scrollInfo.nPos;
1754 * [I] HWND : window handle
1755 * [I] HDC : device context handle
1756 * [I] INT : item index
1757 * [I] INT : subitem index
1758 * [I] RECT * : clipping rectangle
1763 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1766 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1767 CHAR szDispText[DISP_TEXT_SIZE];
1770 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd, hdc,
1773 /* get information needed for drawing the item */
1774 ZeroMemory(&lvItem, sizeof(LVITEMA));
1775 lvItem.mask = LVIF_TEXT;
1776 lvItem.iItem = nItem;
1777 lvItem.iSubItem = nSubItem;
1778 lvItem.cchTextMax = DISP_TEXT_SIZE;
1779 lvItem.pszText = szDispText;
1780 ListView_GetItemA(hwnd, &lvItem);
1782 /* set item colors */
1783 SetBkColor(hdc, infoPtr->clrTextBk);
1784 SetTextColor(hdc, infoPtr->clrText);
1786 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1787 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1796 * [I] HWND : window handle
1797 * [I] HDC : device context handle
1798 * [I] INT : item index
1799 * [I] RECT * : clipping rectangle
1804 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1806 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1807 CHAR szDispText[DISP_TEXT_SIZE];
1814 TRACE("(hwnd=%x, hdc=%x, nItem=%d\n", hwnd, hdc, nItem);
1816 /* get information needed for drawing the item */
1817 ZeroMemory(&lvItem, sizeof(LVITEMA));
1818 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1819 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1820 lvItem.iItem = nItem;
1821 lvItem.iSubItem = 0;
1822 lvItem.cchTextMax = DISP_TEXT_SIZE;
1823 lvItem.pszText = szDispText;
1824 ListView_GetItemA(hwnd, &lvItem);
1827 if (infoPtr->himlState != NULL)
1829 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1830 if (uStateImage != 0)
1832 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1833 rcItem.top, ILD_NORMAL);
1836 rcItem.left += infoPtr->iconSize.cx;
1840 if (infoPtr->himlSmall != NULL)
1842 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1844 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1845 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1846 rcItem.top, ILD_SELECTED);
1850 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1851 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1852 rcItem.top, ILD_NORMAL);
1855 rcItem.left += infoPtr->iconSize.cx;
1858 /* Don't bother painting item being edited */
1859 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1862 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1864 /* set item colors */
1865 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1866 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1867 /* set raster mode */
1868 nMixMode = SetROP2(hdc, R2_XORPEN);
1870 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1871 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1873 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1874 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1875 /* set raster mode */
1876 nMixMode = SetROP2(hdc, R2_COPYPEN);
1880 /* set item colors */
1881 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1882 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1883 /* set raster mode */
1884 nMixMode = SetROP2(hdc, R2_COPYPEN);
1887 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1888 if (rcItem.left + nLabelWidth < rcItem.right)
1890 rcItem.right = rcItem.left + nLabelWidth;
1894 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1895 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1897 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1899 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1904 SetROP2(hdc, R2_COPYPEN);
1905 SetBkColor(hdc, infoPtr->clrTextBk);
1906 SetTextColor(hdc, infoPtr->clrText);
1912 * Draws an item when in large icon display mode.
1915 * [I] HWND : window handle
1916 * [I] HDC : device context handle
1917 * [I] LISTVIEW_ITEM * : item
1918 * [I] INT : item index
1919 * [I] RECT * : clipping rectangle
1924 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1926 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1927 CHAR szDispText[DISP_TEXT_SIZE];
1928 INT nDrawPosX = rcItem.left;
1933 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1934 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1937 /* get information needed for drawing the item */
1938 ZeroMemory(&lvItem, sizeof(LVITEMA));
1939 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1940 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1941 lvItem.iItem = nItem;
1942 lvItem.iSubItem = 0;
1943 lvItem.cchTextMax = DISP_TEXT_SIZE;
1944 lvItem.pszText = szDispText;
1945 ListView_GetItemA(hwnd, &lvItem);
1947 if (lvItem.state & LVIS_SELECTED)
1949 /* set item colors */
1950 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1951 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1952 /* set raster mode */
1953 SetROP2(hdc, R2_XORPEN);
1957 /* set item colors */
1958 SetBkColor(hdc, infoPtr->clrTextBk);
1959 SetTextColor(hdc, infoPtr->clrText);
1960 /* set raster mode */
1961 SetROP2(hdc, R2_COPYPEN);
1964 if (infoPtr->himlNormal != NULL)
1966 rcItem.top += ICON_TOP_PADDING;
1967 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
1968 if (lvItem.state & LVIS_SELECTED)
1970 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1971 rcItem.top, ILD_SELECTED);
1975 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1976 rcItem.top, ILD_NORMAL);
1980 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
1981 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1982 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
1985 rcItem.left += nDrawPosX / 2;
1986 rcItem.right = rcItem.left + nLabelWidth;
1991 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
1995 GetTextMetricsA(hdc, &tm);
1996 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
1997 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1998 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2000 if (lvItem.state & LVIS_FOCUSED)
2002 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2008 * Draws listview items when in report display mode.
2011 * [I] HWND : window handle
2012 * [I] HDC : device context handle
2017 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2019 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2020 SCROLLINFO scrollInfo;
2021 INT nDrawPosY = infoPtr->rcList.top;
2028 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2029 scrollInfo.cbSize = sizeof(SCROLLINFO);
2030 scrollInfo.fMask = SIF_POS;
2032 nItem = ListView_GetTopIndex(hwnd);
2034 /* add 1 for displaying a partial item at the bottom */
2035 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2036 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2037 for (; nItem < nLast; nItem++)
2039 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2040 for (j = 0; j < nColumnCount; j++)
2042 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2043 rcItem.left += REPORT_MARGINX;
2044 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2045 rcItem.top = nDrawPosY;
2046 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2048 /* Offset the Scroll Bar Pos */
2049 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2051 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2052 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2057 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2061 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2065 nDrawPosY += infoPtr->nItemHeight;
2071 * Retrieves the number of items that can fit vertically in the client area.
2074 * [I] HWND : window handle
2077 * Number of items per row.
2079 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2081 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2082 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2083 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2084 INT nCountPerRow = 1;
2088 if (uView == LVS_REPORT)
2094 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2095 if (nCountPerRow == 0)
2102 return nCountPerRow;
2107 * Retrieves the number of items that can fit horizontally in the client
2111 * [I] HWND : window handle
2114 * Number of items per column.
2116 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2118 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2119 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2120 INT nCountPerColumn = 1;
2122 if (nListHeight > 0)
2124 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2125 if (nCountPerColumn == 0)
2127 nCountPerColumn = 1;
2131 return nCountPerColumn;
2136 * Retrieves the number of columns needed to display all the items when in
2137 * list display mode.
2140 * [I] HWND : window handle
2143 * Number of columns.
2145 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2147 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2148 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2149 INT nColumnCount = 0;
2151 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2153 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2155 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2159 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2163 return nColumnCount;
2169 * Draws listview items when in list display mode.
2172 * [I] HWND : window handle
2173 * [I] HDC : device context handle
2178 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2180 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2185 INT nCountPerColumn;
2186 INT nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2187 INT nItemHeight = LISTVIEW_GetItemHeight(hwnd);
2189 /* get number of fully visible columns */
2190 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2191 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2192 nItem = ListView_GetTopIndex(hwnd);
2194 for (i = 0; i < nColumnCount; i++)
2196 for (j = 0; j < nCountPerColumn; j++, nItem++)
2198 if (nItem >= GETITEMCOUNT(infoPtr))
2201 rcItem.top = j * nItemHeight;
2202 rcItem.left = i * nItemWidth;
2203 rcItem.bottom = rcItem.top + nItemHeight;
2204 rcItem.right = rcItem.left + nItemWidth;
2205 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2212 * Draws listview items when in icon or small icon display mode.
2215 * [I] HWND : window handle
2216 * [I] HDC : device context handle
2221 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2223 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2229 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2230 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2232 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2233 ptPosition.x += ptOrigin.x;
2234 ptPosition.y += ptOrigin.y;
2236 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2238 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2240 if (ptPosition.y < infoPtr->rcList.bottom)
2242 if (ptPosition.x < infoPtr->rcList.right)
2244 rcItem.top = ptPosition.y;
2245 rcItem.left = ptPosition.x;
2246 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2247 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2248 if (bSmall == FALSE)
2250 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2254 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2265 * Draws listview items.
2268 * [I] HWND : window handle
2269 * [I] HDC : device context handle
2274 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2276 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2277 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2282 hOldFont = SelectObject(hdc, infoPtr->hFont);
2284 /* select the doted pen (for drawing the focus box) */
2285 hPen = CreatePen(PS_DOT, 1, 0);
2286 hOldPen = SelectObject(hdc, hPen);
2288 /* select transparent brush (for drawing the focus box) */
2289 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2291 if (uView == LVS_LIST)
2293 LISTVIEW_RefreshList(hwnd, hdc);
2295 else if (uView == LVS_REPORT)
2297 LISTVIEW_RefreshReport(hwnd, hdc);
2299 else if (uView == LVS_SMALLICON)
2301 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2303 else if (uView == LVS_ICON)
2305 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2308 /* unselect objects */
2309 SelectObject(hdc, hOldFont);
2310 SelectObject(hdc, hOldPen);
2319 * Calculates the approximate width and height of a given number of items.
2322 * [I] HWND : window handle
2323 * [I] INT : number of items
2328 * Returns a DWORD. The width in the low word and the height in high word.
2330 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2331 WORD wWidth, WORD wHeight)
2333 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2334 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2335 INT nItemCountPerColumn = 1;
2336 INT nColumnCount = 0;
2337 DWORD dwViewRect = 0;
2339 if (nItemCount == -1)
2341 nItemCount = GETITEMCOUNT(infoPtr);
2344 if (uView == LVS_LIST)
2346 if (wHeight == 0xFFFF)
2348 /* use current height */
2349 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2352 if (wHeight < infoPtr->nItemHeight)
2354 wHeight = infoPtr->nItemHeight;
2359 if (infoPtr->nItemHeight > 0)
2361 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2362 if (nItemCountPerColumn == 0)
2364 nItemCountPerColumn = 1;
2367 if (nItemCount % nItemCountPerColumn != 0)
2369 nColumnCount = nItemCount / nItemCountPerColumn;
2373 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2378 /* Microsoft padding magic */
2379 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2380 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2382 dwViewRect = MAKELONG(wWidth, wHeight);
2384 else if (uView == LVS_REPORT)
2388 else if (uView == LVS_SMALLICON)
2392 else if (uView == LVS_ICON)
2402 * Arranges listview items in icon display mode.
2405 * [I] HWND : window handle
2406 * [I] INT : alignment code
2412 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2414 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2415 BOOL bResult = FALSE;
2417 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2430 case LVA_SNAPTOGRID:
2439 /* << LISTVIEW_CreateDragImage >> */
2443 * Removes all listview items and subitems.
2446 * [I] HWND : window handle
2452 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2454 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2455 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2456 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2457 UINT uView = lStyle & LVS_TYPEMASK;
2458 LISTVIEW_ITEM *lpItem;
2459 LISTVIEW_SUBITEM *lpSubItem;
2462 BOOL bResult = FALSE;
2467 TRACE("(hwnd=%x,)\n", hwnd);
2469 if (GETITEMCOUNT(infoPtr) > 0)
2471 /* initialize memory */
2472 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2474 /* send LVN_DELETEALLITEMS notification */
2475 nmlv.hdr.hwndFrom = hwnd;
2476 nmlv.hdr.idFrom = lCtrlId;
2477 nmlv.hdr.code = LVN_DELETEALLITEMS;
2480 /* verify if subsequent LVN_DELETEITEM notifications should be
2482 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2484 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2486 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2487 if (hdpaSubItems != NULL)
2489 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2491 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2492 if (lpSubItem != NULL)
2494 /* free subitem string */
2495 if ((lpSubItem->pszText != NULL) &&
2496 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2498 COMCTL32_Free(lpSubItem->pszText);
2502 COMCTL32_Free(lpSubItem);
2506 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2509 if (bSuppress == FALSE)
2511 /* send LVN_DELETEITEM notification */
2512 nmlv.hdr.code = LVN_DELETEITEM;
2514 nmlv.lParam = lpItem->lParam;
2515 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2518 /* free item string */
2519 if ((lpItem->pszText != NULL) &&
2520 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2522 COMCTL32_Free(lpItem->pszText);
2526 COMCTL32_Free(lpItem);
2529 DPA_Destroy(hdpaSubItems);
2533 /* reinitialize listview memory */
2534 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2536 /* align items (set position of each item) */
2537 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2539 if (lStyle & LVS_ALIGNLEFT)
2541 LISTVIEW_AlignLeft(hwnd);
2545 LISTVIEW_AlignTop(hwnd);
2549 LISTVIEW_UpdateScroll(hwnd);
2551 /* invalidate client area (optimization needed) */
2552 InvalidateRect(hwnd, NULL, TRUE);
2560 * Removes a column from the listview control.
2563 * [I] HWND : window handle
2564 * [I] INT : column index
2570 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2572 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2573 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2574 BOOL bResult = FALSE;
2576 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2578 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2580 /* Need to reset the item width when deleting a column */
2581 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2583 /* reset scroll parameters */
2584 if (uView == LVS_REPORT)
2586 /* update scrollbar(s) */
2587 LISTVIEW_UpdateScroll(hwnd);
2589 /* refresh client area */
2590 InvalidateRect(hwnd, NULL, FALSE);
2599 * Removes an item from the listview control.
2602 * [I] HWND : window handle
2603 * [I] INT : item index
2609 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2611 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2612 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2613 UINT uView = lStyle & LVS_TYPEMASK;
2614 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2616 BOOL bResult = FALSE;
2618 LISTVIEW_ITEM *lpItem;
2619 LISTVIEW_SUBITEM *lpSubItem;
2622 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2624 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2626 /* initialize memory */
2627 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2629 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2630 if (hdpaSubItems != NULL)
2632 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2634 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2635 if (lpSubItem != NULL)
2637 /* free item string */
2638 if ((lpSubItem->pszText != NULL) &&
2639 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2641 COMCTL32_Free(lpSubItem->pszText);
2645 COMCTL32_Free(lpSubItem);
2649 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2652 /* send LVN_DELETEITEM notification */
2653 nmlv.hdr.hwndFrom = hwnd;
2654 nmlv.hdr.idFrom = lCtrlId;
2655 nmlv.hdr.code = LVN_DELETEITEM;
2657 nmlv.lParam = lpItem->lParam;
2658 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2661 /* free item string */
2662 if ((lpItem->pszText != NULL) &&
2663 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2665 COMCTL32_Free(lpItem->pszText);
2669 COMCTL32_Free(lpItem);
2672 bResult = DPA_Destroy(hdpaSubItems);
2675 /* align items (set position of each item) */
2676 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2678 if (lStyle & LVS_ALIGNLEFT)
2680 LISTVIEW_AlignLeft(hwnd);
2684 LISTVIEW_AlignTop(hwnd);
2688 /* If this item had focus change focus to next or previous item */
2689 if (GETITEMCOUNT(infoPtr) > 0)
2691 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
2692 if (infoPtr->nFocusedItem == nItem)
2693 LISTVIEW_SetItemFocus(hwnd, sItem);
2696 infoPtr->nFocusedItem = -1;
2698 LISTVIEW_UpdateScroll(hwnd);
2700 /* refresh client area */
2701 InvalidateRect(hwnd, NULL, TRUE);
2710 * Return edit control handle of current edit label
2713 * [I] HWND : window handle
2719 static LRESULT LISTVIEW_GetEditControl(hwnd)
2721 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2722 return infoPtr->hwndEdit;
2728 * Callback implementation for editlabel control
2731 * [I] HWND : window handle
2732 * [I] LPSTR : modified text
2733 * [I] DWORD : item index
2740 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
2742 NMLVDISPINFOA dispInfo;
2743 LISTVIEW_ITEM *lpItem;
2744 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2745 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2748 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2750 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2753 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2756 dispInfo.hdr.hwndFrom = hwnd;
2757 dispInfo.hdr.idFrom = nCtrlId;
2758 dispInfo.hdr.code = LVN_ENDLABELEDITA;
2759 dispInfo.item.mask = 0;
2760 dispInfo.item.iItem = nItem;
2761 dispInfo.item.state = lpItem->state;
2762 dispInfo.item.stateMask = 0;
2763 dispInfo.item.pszText = pszText;
2764 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
2765 dispInfo.item.iImage = lpItem->iImage;
2766 dispInfo.item.lParam = lpItem->lParam;
2768 ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
2769 infoPtr->hwndEdit = 0;
2776 * Begin in place editing of specified list view item
2779 * [I] HWND : window handle
2780 * [I] INT : item index
2787 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
2789 NMLVDISPINFOA dispInfo;
2791 LISTVIEW_ITEM *lpItem;
2793 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
2794 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2795 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2798 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
2801 LISTVIEW_SetSelection(hwnd, nItem);
2802 LISTVIEW_SetItemFocus(hwnd, nItem);
2804 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2805 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2808 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2811 dispInfo.hdr.hwndFrom = hwnd;
2812 dispInfo.hdr.idFrom = nCtrlId;
2813 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
2814 dispInfo.item.mask = 0;
2815 dispInfo.item.iItem = nItem;
2816 dispInfo.item.state = lpItem->state;
2817 dispInfo.item.stateMask = 0;
2818 dispInfo.item.pszText = lpItem->pszText;
2819 dispInfo.item.cchTextMax = strlen(lpItem->pszText);
2820 dispInfo.item.iImage = lpItem->iImage;
2821 dispInfo.item.lParam = lpItem->lParam;
2823 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
2826 rect.left = LVIR_LABEL;
2827 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
2830 if (!(hedit = CreateEditLabel(dispInfo.item.pszText , WS_VISIBLE,
2831 rect.left, rect.top, rect.right - rect.left + 15,
2832 rect.bottom - rect.top,
2833 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
2836 infoPtr->hwndEdit = hedit;
2838 SendMessageA(hedit, EM_SETSEL, 0, -1);
2846 * Ensures the specified item is visible, scrolling into view if necessary.
2849 * [I] HWND : window handle
2850 * [I] INT : item index
2851 * [I] BOOL : partially or entirely visible
2857 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2860 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2861 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2862 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2863 INT nScrollPosHeight = 0;
2864 INT nScrollPosWidth = 0;
2865 SCROLLINFO scrollInfo;
2868 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2869 scrollInfo.cbSize = sizeof(SCROLLINFO);
2870 scrollInfo.fMask = SIF_POS;
2872 /* ALWAYS bPartial == FALSE, FOR NOW! */
2874 rcItem.left = LVIR_BOUNDS;
2875 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2877 if (rcItem.left < infoPtr->rcList.left)
2879 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2882 if (uView == LVS_LIST)
2884 nScrollPosWidth = infoPtr->nItemWidth;
2885 rcItem.left += infoPtr->rcList.left;
2887 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2889 nScrollPosWidth = max(1, nListWidth / LISTVIEW_SCROLL_DIV_SIZE);
2890 rcItem.left += infoPtr->rcList.left;
2893 if (rcItem.left % nScrollPosWidth == 0)
2895 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
2899 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
2902 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2905 else if (rcItem.right > infoPtr->rcList.right)
2907 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2910 if (uView == LVS_LIST)
2912 rcItem.right -= infoPtr->rcList.right;
2913 nScrollPosWidth = infoPtr->nItemWidth;
2915 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2917 rcItem.right -= infoPtr->rcList.right;
2918 nScrollPosWidth = max(1, nListWidth / LISTVIEW_SCROLL_DIV_SIZE);
2921 if (rcItem.right % nScrollPosWidth == 0)
2923 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
2927 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
2930 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2934 if (rcItem.top < infoPtr->rcList.top)
2937 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2939 if (uView == LVS_REPORT)
2941 rcItem.top -= infoPtr->rcList.top;
2942 nScrollPosHeight = infoPtr->nItemHeight;
2944 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2946 nScrollPosHeight = max(1, nListHeight / LISTVIEW_SCROLL_DIV_SIZE);
2947 rcItem.top += infoPtr->rcList.top;
2950 if (rcItem.top % nScrollPosHeight == 0)
2952 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
2956 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
2959 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2962 else if (rcItem.bottom > infoPtr->rcList.bottom)
2965 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2967 if (uView == LVS_REPORT)
2969 rcItem.bottom -= infoPtr->rcList.bottom;
2970 nScrollPosHeight = infoPtr->nItemHeight;
2972 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2974 nScrollPosHeight = max(1, nListHeight / LISTVIEW_SCROLL_DIV_SIZE);
2975 rcItem.bottom -= infoPtr->rcList.bottom;
2978 if (rcItem.bottom % nScrollPosHeight == 0)
2980 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
2984 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
2987 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2997 * Retrieves the nearest item, given a position and a direction.
3000 * [I] HWND : window handle
3001 * [I] POINT : start position
3002 * [I] UINT : direction
3005 * Item index if successdful, -1 otherwise.
3007 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3009 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3010 LVHITTESTINFO lvHitTestInfo;
3014 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3016 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3017 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3018 lvHitTestInfo.pt.x += pt.x;
3019 lvHitTestInfo.pt.y += pt.y;
3023 if (vkDirection == VK_DOWN)
3025 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3027 else if (vkDirection == VK_UP)
3029 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3031 else if (vkDirection == VK_LEFT)
3033 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3035 else if (vkDirection == VK_RIGHT)
3037 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3040 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3046 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3050 while (nItem == -1);
3058 * Searches for an item with specific characteristics.
3061 * [I] HWND : window handle
3062 * [I] INT : base item index
3063 * [I] LPLVFINDINFO : item information to look for
3066 * SUCCESS : index of item
3069 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3070 LPLVFINDINFO lpFindInfo)
3072 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3074 CHAR szDispText[DISP_TEXT_SIZE];
3078 INT nLast = GETITEMCOUNT(infoPtr);
3080 if ((nItem >= -1) && (lpFindInfo != NULL))
3082 ZeroMemory(&lvItem, sizeof(LVITEMA));
3084 if (lpFindInfo->flags & LVFI_PARAM)
3086 lvItem.mask |= LVIF_PARAM;
3089 if (lpFindInfo->flags & LVFI_STRING)
3091 lvItem.mask |= LVIF_TEXT;
3092 lvItem.pszText = szDispText;
3093 lvItem.cchTextMax = DISP_TEXT_SIZE;
3096 if (lpFindInfo->flags & LVFI_PARTIAL)
3098 lvItem.mask |= LVIF_TEXT;
3099 lvItem.pszText = szDispText;
3100 lvItem.cchTextMax = DISP_TEXT_SIZE;
3103 if (lpFindInfo->flags & LVFI_WRAP)
3108 if (lpFindInfo->flags & LVFI_NEARESTXY)
3110 ptItem.x = lpFindInfo->pt.x;
3111 ptItem.y = lpFindInfo->pt.y;
3116 while (nItem < nLast)
3118 if (lpFindInfo->flags & LVFI_NEARESTXY)
3120 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3121 lpFindInfo->vkDirection);
3124 /* get position of the new item index */
3125 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3136 lvItem.iItem = nItem;
3137 lvItem.iSubItem = 0;
3138 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3140 if (lvItem.mask & LVIF_TEXT)
3142 if (lpFindInfo->flags & LVFI_PARTIAL)
3144 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3149 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3154 if (lvItem.mask & LVIF_PARAM)
3156 if (lpFindInfo->lParam != lvItem.lParam)
3182 * Retrieves the background color of the listview control.
3185 * [I] HWND : window handle
3188 * COLORREF associated with the background.
3190 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3192 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3194 return infoPtr->clrBk;
3199 * Retrieves the background image of the listview control.
3202 * [I] HWND : window handle
3203 * [O] LPLVMKBIMAGE : background image attributes
3209 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3211 /* FIXME (listview, "empty stub!\n"); */
3217 * Retrieves the callback mask.
3220 * [I] HWND : window handle
3225 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3229 return infoPtr->uCallbackMask;
3234 * Retrieves column attributes.
3237 * [I] HWND : window handle
3238 * [I] INT : column index
3239 * [IO] LPLVCOLUMNA : column information
3245 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3247 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3249 BOOL bResult = FALSE;
3251 if (lpColumn != NULL)
3253 /* initialize memory */
3254 ZeroMemory(&hdi, sizeof(HDITEMA));
3256 if (lpColumn->mask & LVCF_FMT)
3258 hdi.mask |= HDI_FORMAT;
3261 if (lpColumn->mask & LVCF_WIDTH)
3263 hdi.mask |= HDI_WIDTH;
3266 if (lpColumn->mask & LVCF_TEXT)
3268 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3271 if (lpColumn->mask & LVCF_IMAGE)
3273 hdi.mask |= HDI_IMAGE;
3276 if (lpColumn->mask & LVCF_ORDER)
3278 hdi.mask |= HDI_ORDER;
3281 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3282 if (bResult != FALSE)
3284 if (lpColumn->mask & LVCF_FMT)
3288 if (hdi.fmt & HDF_LEFT)
3290 lpColumn->fmt |= LVCFMT_LEFT;
3292 else if (hdi.fmt & HDF_RIGHT)
3294 lpColumn->fmt |= LVCFMT_RIGHT;
3296 else if (hdi.fmt & HDF_CENTER)
3298 lpColumn->fmt |= LVCFMT_CENTER;
3301 if (hdi.fmt & HDF_IMAGE)
3303 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3306 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3308 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3312 if (lpColumn->mask & LVCF_WIDTH)
3314 lpColumn->cx = hdi.cxy;
3317 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3319 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3322 if (lpColumn->mask & LVCF_IMAGE)
3324 lpColumn->iImage = hdi.iImage;
3327 if (lpColumn->mask & LVCF_ORDER)
3329 lpColumn->iOrder = hdi.iOrder;
3337 /* LISTVIEW_GetColumnW */
3338 /* LISTVIEW_GetColumnOrderArray */
3342 * Retrieves the column width.
3345 * [I] HWND : window handle
3346 * [I] int : column index
3349 * SUCCESS : column width
3352 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3354 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3355 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3356 INT nColumnWidth = 0;
3359 if (uView == LVS_LIST)
3361 nColumnWidth = infoPtr->nItemWidth;
3363 else if (uView == LVS_REPORT)
3365 /* get column width from header */
3366 ZeroMemory(&hdi, sizeof(HDITEMA));
3367 hdi.mask = HDI_WIDTH;
3368 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3370 nColumnWidth = hdi.cxy;
3374 return nColumnWidth;
3379 * In list or report display mode, retrieves the number of items that can fit
3380 * vertically in the visible area. In icon or small icon display mode,
3381 * retrieves the total number of visible items.
3384 * [I] HWND : window handle
3387 * Number of fully visible items.
3389 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3391 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3392 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3395 if (uView == LVS_LIST)
3397 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3399 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3400 LISTVIEW_GetCountPerColumn(hwnd);
3403 else if (uView == LVS_REPORT)
3405 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3409 nItemCount = GETITEMCOUNT(infoPtr);
3415 /* LISTVIEW_GetEditControl */
3419 * Retrieves the extended listview style.
3422 * [I] HWND : window handle
3425 * SUCCESS : previous style
3428 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3430 LISTVIEW_INFO *infoPtr;
3432 /* make sure we can get the listview info */
3433 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3436 return (infoPtr->dwExStyle);
3441 * Retrieves the handle to the header control.
3444 * [I] HWND : window handle
3449 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3451 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3453 return infoPtr->hwndHeader;
3456 /* LISTVIEW_GetHotCursor */
3457 /* LISTVIEW_GetHotItem */
3458 /* LISTVIEW_GetHoverTime */
3462 * Retrieves an image list handle.
3465 * [I] HWND : window handle
3466 * [I] INT : image list identifier
3469 * SUCCESS : image list handle
3472 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3474 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3475 HIMAGELIST himl = NULL;
3480 himl = infoPtr->himlNormal;
3483 himl = infoPtr->himlSmall;
3486 himl = infoPtr->himlState;
3490 return (LRESULT)himl;
3493 /* LISTVIEW_GetISearchString */
3497 * Retrieves item attributes.
3500 * [I] HWND : window handle
3501 * [IO] LPLVITEMA : item info
3507 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
3509 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3510 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3511 BOOL bResult = FALSE;
3512 NMLVDISPINFOA dispInfo;
3513 LISTVIEW_SUBITEM *lpSubItem;
3514 LISTVIEW_ITEM *lpItem;
3517 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3519 if (lpLVItem != NULL)
3521 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
3523 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3524 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3525 if (hdpaSubItems != NULL)
3527 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3531 if (lpLVItem->iSubItem == 0)
3533 if ((lpItem->iImage == I_IMAGECALLBACK) &&
3534 (lpLVItem->mask & LVIF_IMAGE))
3536 dispInfo.item.mask |= LVIF_IMAGE;
3539 if ((lpItem->pszText == LPSTR_TEXTCALLBACKA) &&
3540 (lpLVItem->mask & LVIF_TEXT))
3542 dispInfo.item.mask |= LVIF_TEXT;
3543 ZeroMemory(lpLVItem->pszText, sizeof(CHAR)*lpLVItem->cchTextMax);
3544 dispInfo.item.pszText = lpLVItem->pszText;
3545 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3548 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3550 dispInfo.item.mask |= LVIF_STATE;
3551 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3554 if (dispInfo.item.mask != 0)
3556 dispInfo.hdr.hwndFrom = hwnd;
3557 dispInfo.hdr.idFrom = lCtrlId;
3558 dispInfo.hdr.code = LVN_GETDISPINFOA;
3559 dispInfo.item.iItem = lpLVItem->iItem;
3560 dispInfo.item.iSubItem = 0;
3561 dispInfo.item.lParam = lpItem->lParam;
3562 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3565 if (dispInfo.item.mask & LVIF_IMAGE)
3567 lpLVItem->iImage = dispInfo.item.iImage;
3569 else if (lpLVItem->mask & LVIF_IMAGE)
3571 lpLVItem->iImage = lpItem->iImage;
3574 if (dispInfo.item.mask & LVIF_TEXT)
3576 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3578 Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
3580 strncpy(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
3582 else if (lpLVItem->mask & LVIF_TEXT)
3584 strncpy(lpLVItem->pszText, lpItem->pszText, lpLVItem->cchTextMax);
3587 if (dispInfo.item.mask & LVIF_STATE)
3589 lpLVItem->state = lpItem->state;
3590 lpLVItem->state &= ~dispInfo.item.stateMask;
3591 lpLVItem->state |= (dispInfo.item.state &
3592 dispInfo.item.stateMask);
3594 else if (lpLVItem->mask & LVIF_STATE)
3596 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3599 if (lpLVItem->mask & LVIF_PARAM)
3601 lpLVItem->lParam = lpItem->lParam;
3604 if (lpLVItem->mask & LVIF_INDENT)
3606 lpLVItem->iIndent = lpItem->iIndent;
3611 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems,
3612 lpLVItem->iSubItem);
3613 if (lpSubItem != NULL)
3615 if ((lpSubItem->iImage == I_IMAGECALLBACK) &&
3616 (lpLVItem->mask & LVIF_IMAGE))
3618 dispInfo.item.mask |= LVIF_IMAGE;
3621 if ((lpSubItem->pszText == LPSTR_TEXTCALLBACKA) &&
3622 (lpLVItem->mask & LVIF_TEXT))
3624 dispInfo.item.mask |= LVIF_TEXT;
3625 ZeroMemory(lpLVItem->pszText,
3626 sizeof(CHAR)*lpLVItem->cchTextMax);
3627 dispInfo.item.pszText = lpLVItem->pszText;
3628 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3633 if (lpLVItem->mask & LVIF_IMAGE)
3635 dispInfo.item.mask |= LVIF_IMAGE;
3638 if (lpLVItem->mask & LVIF_TEXT)
3640 dispInfo.item.mask |= LVIF_TEXT;
3641 ZeroMemory(lpLVItem->pszText,
3642 sizeof(CHAR)*lpLVItem->cchTextMax);
3643 dispInfo.item.pszText = lpLVItem->pszText;
3644 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3648 if (dispInfo.item.mask != 0)
3650 dispInfo.hdr.hwndFrom = hwnd;
3651 dispInfo.hdr.idFrom = lCtrlId;
3652 dispInfo.hdr.code = LVN_GETDISPINFOA;
3653 dispInfo.item.iItem = lpLVItem->iItem;
3654 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3655 dispInfo.item.lParam = lpItem->lParam;
3656 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3659 if (dispInfo.item.mask & LVIF_IMAGE)
3661 lpLVItem->iImage = dispInfo.item.iImage;
3663 else if (lpLVItem->mask & LVIF_IMAGE)
3665 lpLVItem->iImage = lpItem->iImage;
3668 if (dispInfo.item.mask & LVIF_TEXT)
3670 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3673 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
3675 strncpy(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
3677 else if (lpLVItem->mask & LVIF_TEXT)
3679 strncpy(lpLVItem->pszText, lpSubItem->pszText, lpLVItem->cchTextMax);
3690 /* LISTVIEW_GetItemW */
3691 /* LISTVIEW_GetHotCursor */
3695 * Retrieves the index of the hot item.
3698 * [I] HWND : window handle
3701 * SUCCESS : hot item index
3702 * FAILURE : -1 (no hot item)
3704 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3706 LISTVIEW_INFO *infoPtr;
3708 /* make sure we can get the listview info */
3709 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3712 return (infoPtr->nHotItem);
3715 /* LISTVIEW_GetHoverTime */
3719 * Retrieves the number of items in the listview control.
3722 * [I] HWND : window handle
3727 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3731 return GETITEMCOUNT(infoPtr);
3736 * Retrieves the position (upper-left) of the listview control item.
3739 * [I] HWND : window handle
3740 * [I] INT : item index
3741 * [O] LPPOINT : coordinate information
3747 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3748 LPPOINT lpptPosition)
3750 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3751 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3752 BOOL bResult = FALSE;
3754 LISTVIEW_ITEM *lpItem;
3755 INT nCountPerColumn;
3758 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3761 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3762 (lpptPosition != NULL))
3764 if (uView == LVS_LIST)
3767 nItem = nItem - ListView_GetTopIndex(hwnd);
3768 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3771 nRow = nItem % nCountPerColumn;
3774 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3775 lpptPosition->y = 0;
3779 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3780 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3785 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3786 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3789 else if (uView == LVS_REPORT)
3792 lpptPosition->x = REPORT_MARGINX;
3793 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3794 infoPtr->nItemHeight) + infoPtr->rcList.top;
3798 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3799 if (hdpaSubItems != NULL)
3801 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3805 lpptPosition->x = lpItem->ptPosition.x;
3806 lpptPosition->y = lpItem->ptPosition.y;
3817 * Retrieves the bounding rectangle for a listview control item.
3820 * [I] HWND : window handle
3821 * [I] INT : item index
3822 * [IO] LPRECT : bounding rectangle coordinates
3828 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3830 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3831 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3832 BOOL bResult = FALSE;
3841 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3843 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3845 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3850 if (uView == LVS_ICON)
3852 if (infoPtr->himlNormal != NULL)
3854 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3857 lprc->left = ptItem.x + ptOrigin.x;
3858 lprc->top = ptItem.y + ptOrigin.y;
3859 lprc->right = lprc->left + infoPtr->iconSize.cx;
3860 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3861 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3865 else if (uView == LVS_SMALLICON)
3867 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3870 lprc->left = ptItem.x + ptOrigin.x;
3871 lprc->top = ptItem.y + ptOrigin.y;
3872 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3874 if (infoPtr->himlState != NULL)
3875 lprc->left += infoPtr->iconSize.cx;
3877 if (infoPtr->himlSmall != NULL)
3878 lprc->right = lprc->left + infoPtr->iconSize.cx;
3880 lprc->right = lprc->left;
3886 lprc->left = ptItem.x;
3887 lprc->top = ptItem.y;
3888 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3890 if (infoPtr->himlState != NULL)
3892 lprc->left += infoPtr->iconSize.cx;
3895 if (infoPtr->himlSmall != NULL)
3897 lprc->right = lprc->left + infoPtr->iconSize.cx;
3901 lprc->right = lprc->left;
3907 if (uView == LVS_ICON)
3909 if (infoPtr->himlNormal != NULL)
3911 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3914 lprc->left = ptItem.x + ptOrigin.x;
3915 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3916 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3917 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3918 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3920 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3921 lprc->right = lprc->left + nLabelWidth;
3926 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3930 hOldFont = SelectObject(hdc, infoPtr->hFont);
3931 GetTextMetricsA(hdc, &tm);
3932 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3933 SelectObject(hdc, hOldFont);
3934 ReleaseDC(hwnd, hdc);
3938 else if (uView == LVS_SMALLICON)
3940 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3943 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
3944 lprc->top = ptItem.y + ptOrigin.y;
3945 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3947 if (infoPtr->himlState != NULL)
3949 lprc->left += infoPtr->iconSize.cx;
3952 if (infoPtr->himlSmall != NULL)
3954 lprc->left += infoPtr->iconSize.cx;
3957 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3958 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3960 lprc->right = lprc->left + nLabelWidth;
3964 lprc->right = nLeftPos + infoPtr->nItemWidth;
3971 nLeftPos = lprc->left = ptItem.x;
3972 lprc->top = ptItem.y;
3973 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3975 if (infoPtr->himlState != NULL)
3977 lprc->left += infoPtr->iconSize.cx;
3980 if (infoPtr->himlSmall != NULL)
3982 lprc->left += infoPtr->iconSize.cx;
3985 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3986 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3988 lprc->right = lprc->left + nLabelWidth;
3992 lprc->right = nLeftPos + infoPtr->nItemWidth;
3998 if (uView == LVS_ICON)
4000 if (infoPtr->himlNormal != NULL)
4002 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4005 lprc->left = ptItem.x + ptOrigin.x;
4006 lprc->top = ptItem.y + ptOrigin.y;
4007 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4008 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4012 else if (uView == LVS_SMALLICON)
4014 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4017 lprc->left = ptItem.x + ptOrigin.x;
4018 lprc->right = lprc->left;
4019 lprc->top = ptItem.y + ptOrigin.y;
4020 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4021 if (infoPtr->himlState != NULL)
4022 lprc->right += infoPtr->iconSize.cx;
4023 if (infoPtr->himlSmall != NULL)
4024 lprc->right += infoPtr->iconSize.cx;
4026 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4027 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4029 lprc->right += nLabelWidth;
4033 lprc->right = lprc->left + infoPtr->nItemWidth;
4040 lprc->left = ptItem.x;
4041 lprc->right = lprc->left;
4042 lprc->top = ptItem.y;
4043 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4045 if (infoPtr->himlState != NULL)
4047 lprc->right += infoPtr->iconSize.cx;
4050 if (infoPtr->himlSmall != NULL)
4052 lprc->right += infoPtr->iconSize.cx;
4055 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4056 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4058 lprc->right += nLabelWidth;
4062 lprc->right = lprc->left + infoPtr->nItemWidth;
4067 case LVIR_SELECTBOUNDS:
4068 if (uView == LVS_ICON)
4070 if (infoPtr->himlNormal != NULL)
4072 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4075 lprc->left = ptItem.x + ptOrigin.x;
4076 lprc->top = ptItem.y + ptOrigin.y;
4077 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4078 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4082 else if (uView == LVS_SMALLICON)
4084 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4087 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4088 lprc->top = ptItem.y + ptOrigin.y;
4089 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4091 if (infoPtr->himlState != NULL)
4093 lprc->left += infoPtr->iconSize.cx;
4096 lprc->right = lprc->left;
4098 if (infoPtr->himlSmall != NULL)
4100 lprc->right += infoPtr->iconSize.cx;
4103 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4104 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4106 lprc->right += nLabelWidth;
4110 lprc->right = nLeftPos + infoPtr->nItemWidth;
4117 nLeftPos = lprc->left = ptItem.x;
4118 lprc->top = ptItem.y;
4119 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4121 if (infoPtr->himlState != NULL)
4123 lprc->left += infoPtr->iconSize.cx;
4126 lprc->right = lprc->left;
4128 if (infoPtr->himlSmall != NULL)
4130 lprc->right += infoPtr->iconSize.cx;
4133 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4134 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4136 lprc->right += nLabelWidth;
4140 lprc->right = nLeftPos + infoPtr->nItemWidth;
4153 * Retrieves the width of a label.
4156 * [I] HWND : window handle
4159 * SUCCESS : string width (in pixels)
4162 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4164 CHAR szDispText[DISP_TEXT_SIZE];
4165 INT nLabelWidth = 0;
4168 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4170 ZeroMemory(&lvItem, sizeof(LVITEMA));
4171 lvItem.mask = LVIF_TEXT;
4172 lvItem.iItem = nItem;
4173 lvItem.cchTextMax = DISP_TEXT_SIZE;
4174 lvItem.pszText = szDispText;
4175 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
4177 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4185 * Retrieves the spacing between listview control items.
4188 * [I] HWND : window handle
4189 * [I] BOOL : flag for small or large icon
4192 * Horizontal + vertical spacing
4194 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4196 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4199 if (bSmall == FALSE)
4201 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4205 /* TODO: need to store width of smallicon item */
4206 lResult = MAKELONG(0, infoPtr->nItemHeight);
4214 * Retrieves the state of a listview control item.
4217 * [I] HWND : window handle
4218 * [I] INT : item index
4219 * [I] UINT : state mask
4222 * State specified by the mask.
4224 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4226 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4230 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4232 ZeroMemory(&lvItem, sizeof(LVITEMA));
4233 lvItem.iItem = nItem;
4234 lvItem.stateMask = uMask;
4235 lvItem.mask = LVIF_STATE;
4236 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
4238 uState = lvItem.state;
4247 * Retrieves the text of a listview control item or subitem.
4250 * [I] HWND : window handle
4251 * [I] INT : item index
4252 * [IO] LPLVITEMA : item information
4255 * SUCCESS : string length
4258 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4260 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4263 if (lpLVItem != NULL)
4265 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4267 lpLVItem->mask = LVIF_TEXT;
4268 lpLVItem->iItem = nItem;
4269 if (ListView_GetItemA(hwnd, lpLVItem) != FALSE)
4271 nLength = lstrlenA(lpLVItem->pszText);
4281 * Searches for an item based on properties + relationships.
4284 * [I] HWND : window handle
4285 * [I] INT : item index
4286 * [I] INT : relationship flag
4289 * SUCCESS : item index
4292 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4294 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4295 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4297 LVFINDINFO lvFindInfo;
4298 INT nCountPerColumn;
4301 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4303 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4305 if (uFlags & LVNI_CUT)
4308 if (uFlags & LVNI_DROPHILITED)
4309 uMask |= LVIS_DROPHILITED;
4311 if (uFlags & LVNI_FOCUSED)
4312 uMask |= LVIS_FOCUSED;
4314 if (uFlags & LVNI_SELECTED)
4315 uMask |= LVIS_SELECTED;
4317 if (uFlags & LVNI_ABOVE)
4319 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4324 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4330 lvFindInfo.flags = LVFI_NEARESTXY;
4331 lvFindInfo.vkDirection = VK_UP;
4332 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4333 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4335 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4340 else if (uFlags & LVNI_BELOW)
4342 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4344 while (nItem < GETITEMCOUNT(infoPtr))
4347 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4353 lvFindInfo.flags = LVFI_NEARESTXY;
4354 lvFindInfo.vkDirection = VK_DOWN;
4355 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4356 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4358 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4363 else if (uFlags & LVNI_TOLEFT)
4365 if (uView == LVS_LIST)
4367 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4368 while (nItem - nCountPerColumn >= 0)
4370 nItem -= nCountPerColumn;
4371 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4375 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4377 lvFindInfo.flags = LVFI_NEARESTXY;
4378 lvFindInfo.vkDirection = VK_LEFT;
4379 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4380 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4382 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4387 else if (uFlags & LVNI_TORIGHT)
4389 if (uView == LVS_LIST)
4391 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4392 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4394 nItem += nCountPerColumn;
4395 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4399 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4401 lvFindInfo.flags = LVFI_NEARESTXY;
4402 lvFindInfo.vkDirection = VK_RIGHT;
4403 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4404 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4406 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4415 /* search by index */
4416 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4418 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4427 /* LISTVIEW_GetNumberOfWorkAreas */
4431 * Retrieves the origin coordinates when in icon or small icon display mode.
4434 * [I] HWND : window handle
4435 * [O] LPPOINT : coordinate information
4441 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4443 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4444 UINT uView = lStyle & LVS_TYPEMASK;
4445 BOOL bResult = FALSE;
4447 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4449 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4451 SCROLLINFO scrollInfo;
4452 ZeroMemory(lpptOrigin, sizeof(POINT));
4453 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4454 scrollInfo.cbSize = sizeof(SCROLLINFO);
4456 if (lStyle & WS_HSCROLL)
4458 scrollInfo.fMask = SIF_POS;
4459 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4461 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4465 if (lStyle & WS_VSCROLL)
4467 scrollInfo.fMask = SIF_POS;
4468 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4470 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4482 * Retrieves the number of items that are marked as selected.
4485 * [I] HWND : window handle
4488 * Number of items selected.
4490 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4493 INT nSelectedCount = 0;
4496 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4498 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4504 return nSelectedCount;
4509 * Retrieves item index that marks the start of a multiple selection.
4512 * [I] HWND : window handle
4515 * Index number or -1 if there is no selection mark.
4517 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4519 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4521 return infoPtr->nSelectionMark;
4526 * Retrieves the width of a string.
4529 * [I] HWND : window handle
4532 * SUCCESS : string width (in pixels)
4535 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4537 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4538 HFONT hFont, hOldFont;
4542 ZeroMemory(&stringSize, sizeof(SIZE));
4543 if (lpszText != NULL)
4545 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4547 hOldFont = SelectObject(hdc, hFont);
4548 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4549 SelectObject(hdc, hOldFont);
4550 ReleaseDC(hwnd, hdc);
4553 return stringSize.cx;
4558 * Retrieves the text backgound color.
4561 * [I] HWND : window handle
4564 * COLORREF associated with the the background.
4566 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4568 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4570 return infoPtr->clrTextBk;
4575 * Retrieves the text color.
4578 * [I] HWND : window handle
4581 * COLORREF associated with the text.
4583 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4585 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4587 return infoPtr->clrText;
4592 * Determines which section of the item was selected (if any).
4595 * [I] HWND : window handle
4596 * [IO] LPLVHITTESTINFO : hit test information
4599 * SUCCESS : item index
4602 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4604 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4608 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4609 lpHitTestInfo->pt.y);
4611 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4613 rcItem.left = LVIR_BOUNDS;
4614 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4616 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4618 rcItem.left = LVIR_ICON;
4619 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4621 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4623 lpHitTestInfo->flags = LVHT_ONITEMICON;
4624 lpHitTestInfo->iItem = i;
4625 lpHitTestInfo->iSubItem = 0;
4630 rcItem.left = LVIR_LABEL;
4631 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4633 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4635 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4636 lpHitTestInfo->iItem = i;
4637 lpHitTestInfo->iSubItem = 0;
4642 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4643 lpHitTestInfo->iItem = i;
4644 lpHitTestInfo->iSubItem = 0;
4650 lpHitTestInfo->flags = LVHT_NOWHERE;
4657 * Determines which listview item is located at the specified position.
4660 * [I] HWND : window handle
4661 * [IO} LPLVHITTESTINFO : hit test information
4664 * SUCCESS : item index
4667 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4669 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4672 lpHitTestInfo->flags = 0;
4674 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4676 lpHitTestInfo->flags = LVHT_TOLEFT;
4678 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4680 lpHitTestInfo->flags = LVHT_TORIGHT;
4682 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4684 lpHitTestInfo->flags |= LVHT_ABOVE;
4686 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4688 lpHitTestInfo->flags |= LVHT_BELOW;
4691 if (lpHitTestInfo->flags == 0)
4693 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4701 * Inserts a new column.
4704 * [I] HWND : window handle
4705 * [I] INT : column index
4706 * [I] LPLVCOLUMNA : column information
4709 * SUCCESS : new column index
4712 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4713 LPLVCOLUMNA lpColumn)
4715 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4717 INT nNewColumn = -1;
4719 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4722 if (lpColumn != NULL)
4724 /* initialize memory */
4725 ZeroMemory(&hdi, sizeof(HDITEMA));
4727 if (lpColumn->mask & LVCF_FMT)
4729 /* format member is valid */
4730 hdi.mask |= HDI_FORMAT;
4732 /* set text alignment (leftmost column must be left-aligned) */
4735 hdi.fmt |= HDF_LEFT;
4739 if (lpColumn->fmt & LVCFMT_LEFT)
4741 hdi.fmt |= HDF_LEFT;
4743 else if (lpColumn->fmt & LVCFMT_RIGHT)
4745 hdi.fmt |= HDF_RIGHT;
4747 else if (lpColumn->fmt & LVCFMT_CENTER)
4749 hdi.fmt |= HDF_CENTER;
4753 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4755 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4759 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4764 if (lpColumn->fmt & LVCFMT_IMAGE)
4766 hdi.fmt |= HDF_IMAGE;
4767 hdi.iImage = I_IMAGECALLBACK;
4771 if (lpColumn->mask & LVCF_WIDTH)
4773 hdi.mask |= HDI_WIDTH;
4774 hdi.cxy = lpColumn->cx;
4777 if (lpColumn->mask & LVCF_TEXT)
4779 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4780 hdi.pszText = lpColumn->pszText;
4781 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4782 hdi.fmt |= HDF_STRING;
4785 if (lpColumn->mask & LVCF_IMAGE)
4787 hdi.mask |= HDI_IMAGE;
4788 hdi.iImage = lpColumn->iImage;
4791 if (lpColumn->mask & LVCF_ORDER)
4793 hdi.mask |= HDI_ORDER;
4794 hdi.iOrder = lpColumn->iOrder;
4797 /* insert item in header control */
4798 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4799 (WPARAM)nColumn, (LPARAM)&hdi);
4801 /* Need to reset the item width when inserting a new column */
4802 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4804 LISTVIEW_UpdateScroll(hwnd);
4805 InvalidateRect(hwnd, NULL, FALSE);
4811 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4812 LPLVCOLUMNW lpColumn)
4817 memcpy(&lvca,lpColumn,sizeof(lvca));
4818 if (lpColumn->mask & LVCF_TEXT)
4819 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4820 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4821 if (lpColumn->mask & LVCF_TEXT)
4822 HeapFree(GetProcessHeap(),0,lvca.pszText);
4829 * Inserts a new item in the listview control.
4832 * [I] HWND : window handle
4833 * [I] LPLVITEMA : item information
4836 * SUCCESS : new item index
4839 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4841 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4842 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4843 UINT uView = lStyle & LVS_TYPEMASK;
4844 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4849 LISTVIEW_ITEM *lpItem = NULL;
4851 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4853 if (lpLVItem != NULL)
4855 /* make sure it's not a subitem; cannot insert a subitem */
4856 if (lpLVItem->iSubItem == 0)
4858 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4861 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4862 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4864 /* insert item in listview control data structure */
4865 hdpaSubItems = DPA_Create(8);
4866 if (hdpaSubItems != NULL)
4868 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4871 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4875 /* manage item focus */
4876 if (lpLVItem->mask & LVIF_STATE)
4878 if (lpLVItem->stateMask & LVIS_FOCUSED)
4880 LISTVIEW_SetItemFocus(hwnd, nItem);
4884 /* send LVN_INSERTITEM notification */
4885 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4886 nmlv.hdr.hwndFrom = hwnd;
4887 nmlv.hdr.idFrom = lCtrlId;
4888 nmlv.hdr.code = LVN_INSERTITEM;
4890 nmlv.lParam = lpItem->lParam;;
4891 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4893 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
4895 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
4896 if (nItemWidth > infoPtr->nItemWidth)
4898 infoPtr->nItemWidth = nItemWidth;
4902 /* align items (set position of each item) */
4903 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4905 if (lStyle & LVS_ALIGNLEFT)
4907 LISTVIEW_AlignLeft(hwnd);
4911 LISTVIEW_AlignTop(hwnd);
4915 LISTVIEW_UpdateScroll(hwnd);
4916 /* refresh client area */
4917 InvalidateRect(hwnd, NULL, FALSE);
4926 /* free memory if unsuccessful */
4927 if ((nItem == -1) && (lpItem != NULL))
4929 COMCTL32_Free(lpItem);
4935 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
4939 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
4940 if (lvia.mask & LVIF_TEXT) {
4941 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
4942 lvia.pszText = LPSTR_TEXTCALLBACKA;
4944 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
4946 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
4947 if (lvia.mask & LVIF_TEXT) {
4948 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
4949 HeapFree(GetProcessHeap(),0,lvia.pszText);
4954 /* LISTVIEW_InsertItemW */
4958 * Redraws a range of items.
4961 * [I] HWND : window handle
4962 * [I] INT : first item
4963 * [I] INT : last item
4969 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4971 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4972 BOOL bResult = FALSE;
4975 if (nFirst <= nLast)
4977 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4979 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4982 InvalidateRect(hwnd, &rc, FALSE);
4990 /* LISTVIEW_Scroll */
4994 * Sets the background color.
4997 * [I] HWND : window handle
4998 * [I] COLORREF : background color
5004 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
5006 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5008 infoPtr->clrBk = clrBk;
5009 InvalidateRect(hwnd, NULL, TRUE);
5014 /* LISTVIEW_SetBkImage */
5018 * Sets the callback mask. This mask will be used when the parent
5019 * window stores state information (some or all).
5022 * [I] HWND : window handle
5023 * [I] UINT : state mask
5029 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5031 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5033 infoPtr->uCallbackMask = uMask;
5040 * Sets the attributes of a header item.
5043 * [I] HWND : window handle
5044 * [I] INT : column index
5045 * [I] LPLVCOLUMNA : column attributes
5051 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5052 LPLVCOLUMNA lpColumn)
5054 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5055 BOOL bResult = FALSE;
5056 HDITEMA hdi, hdiget;
5058 if ((lpColumn != NULL) && (nColumn >= 0) &&
5059 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5061 /* initialize memory */
5062 ZeroMemory(&hdi, sizeof(HDITEMA));
5064 if (lpColumn->mask & LVCF_FMT)
5066 /* format member is valid */
5067 hdi.mask |= HDI_FORMAT;
5069 /* get current format first */
5070 hdiget.mask = HDI_FORMAT;
5071 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5072 /* preserve HDF_STRING if present */
5073 hdi.fmt = hdiget.fmt & HDF_STRING;
5075 /* set text alignment (leftmost column must be left-aligned) */
5078 hdi.fmt |= HDF_LEFT;
5082 if (lpColumn->fmt & LVCFMT_LEFT)
5084 hdi.fmt |= HDF_LEFT;
5086 else if (lpColumn->fmt & LVCFMT_RIGHT)
5088 hdi.fmt |= HDF_RIGHT;
5090 else if (lpColumn->fmt & LVCFMT_CENTER)
5092 hdi.fmt |= HDF_CENTER;
5096 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5098 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5101 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5103 hdi.fmt |= HDF_IMAGE;
5106 if (lpColumn->fmt & LVCFMT_IMAGE)
5108 hdi.fmt |= HDF_IMAGE;
5109 hdi.iImage = I_IMAGECALLBACK;
5113 if (lpColumn->mask & LVCF_WIDTH)
5115 hdi.mask |= HDI_WIDTH;
5116 hdi.cxy = lpColumn->cx;
5119 if (lpColumn->mask & LVCF_TEXT)
5121 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5122 hdi.pszText = lpColumn->pszText;
5123 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5124 hdi.fmt |= HDF_STRING;
5127 if (lpColumn->mask & LVCF_IMAGE)
5129 hdi.mask |= HDI_IMAGE;
5130 hdi.iImage = lpColumn->iImage;
5133 if (lpColumn->mask & LVCF_ORDER)
5135 hdi.mask |= HDI_ORDER;
5136 hdi.iOrder = lpColumn->iOrder;
5139 /* set header item attributes */
5140 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5146 /* LISTVIEW_SetColumnW */
5147 /* LISTVIEW_SetColumnOrderArray */
5151 * Sets the width of a column
5154 * [I] HWND : window handle
5155 * [I] INT : column index
5156 * [I] INT : column width
5162 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5164 LISTVIEW_INFO *infoPtr;
5169 /* set column width only if in report mode */
5170 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5171 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
5174 /* make sure we can get the listview info */
5175 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5177 if (!infoPtr->hwndHeader) /* make sure we have a header */
5180 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5181 * LVSCV_AUTOSIZE_USEHEADER (-2)
5186 hdi.mask = HDI_WIDTH;
5189 /* call header to update the column change */
5190 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5192 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5194 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5201 * Sets the extended listview style.
5204 * [I] HWND : window handle
5209 * SUCCESS : previous style
5212 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5214 LISTVIEW_INFO *infoPtr;
5217 /* make sure we can get the listview info */
5218 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5221 /* store previous style */
5222 dwOldStyle = infoPtr->dwExStyle;
5225 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5227 return (dwOldStyle);
5230 /* LISTVIEW_SetHotCursor */
5234 * Sets the hot item index.
5237 * [I] HWND : window handle
5241 * SUCCESS : previous hot item index
5242 * FAILURE : -1 (no hot item)
5244 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5246 LISTVIEW_INFO *infoPtr;
5249 /* make sure we can get the listview info */
5250 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5253 /* store previous index */
5254 iOldIndex = infoPtr->nHotItem;
5257 infoPtr->nHotItem = iIndex;
5262 /* LISTVIEW_SetIconSpacing */
5269 * [I] HWND : window handle
5270 * [I] INT : image list type
5271 * [I] HIMAGELIST : image list handle
5274 * SUCCESS : old image list
5277 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5279 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5280 HIMAGELIST himlTemp = 0;
5285 himlTemp = infoPtr->himlNormal;
5286 infoPtr->himlNormal = himl;
5287 return (LRESULT)himlTemp;
5290 himlTemp = infoPtr->himlSmall;
5291 infoPtr->himlSmall = himl;
5292 return (LRESULT)himlTemp;
5295 himlTemp = infoPtr->himlState;
5296 infoPtr->himlState = himl;
5297 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5298 return (LRESULT)himlTemp;
5301 return (LRESULT)NULL;
5307 * Sets the attributes of an item.
5310 * [I] HWND : window handle
5311 * [I] LPLVITEM : item information
5317 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5319 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5320 BOOL bResult = FALSE;
5322 if (lpLVItem != NULL)
5324 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5326 if (lpLVItem->iSubItem == 0)
5328 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5332 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5341 /* LISTVIEW_SetItemW */
5345 * Preallocates memory.
5348 * [I] HWND : window handle
5349 * [I] INT : item count (prjected number of items)
5350 * [I] DWORD : update flags
5356 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5358 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5360 FIXME("(%d %08lx)empty stub!\n", nItems, dwFlags);
5363 return LISTVIEW_DeleteAllItems (hwnd);
5365 if (nItems > GETITEMCOUNT(infoPtr))
5368 FIXME("append items\n");
5371 else if (nItems < GETITEMCOUNT(infoPtr))
5374 FIXME("remove items\n");
5383 * Sets the position of an item.
5386 * [I] HWND : window handle
5387 * [I] INT : item index
5388 * [I] INT : x coordinate
5389 * [I] INT : y coordinate
5395 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5396 INT nPosX, INT nPosY)
5398 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5399 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5400 LISTVIEW_ITEM *lpItem;
5402 BOOL bResult = FALSE;
5404 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5406 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5408 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5410 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5411 if (hdpaSubItems != NULL)
5413 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5417 lpItem->ptPosition.x = nPosX;
5418 lpItem->ptPosition.y = nPosY;
5427 /* LISTVIEW_SetItemPosition32 */
5431 * Sets the state of one or many items.
5434 * [I] HWND : window handle
5435 * [I]INT : item index
5436 * [I] LPLVITEM : item or subitem info
5442 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5444 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5445 BOOL bResult = FALSE;
5452 ZeroMemory(&lvItem, sizeof(LVITEMA));
5453 lvItem.mask = LVIF_STATE;
5454 lvItem.state = lpLVItem->state;
5455 lvItem.stateMask = lpLVItem->stateMask ;
5457 /* apply to all items */
5458 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5461 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5469 ZeroMemory(&lvItem, sizeof(LVITEMA));
5470 lvItem.mask = LVIF_STATE;
5471 lvItem.state = lpLVItem->state;
5472 lvItem.stateMask = lpLVItem->stateMask;
5473 lvItem.iItem = nItem;
5474 bResult = ListView_SetItemA(hwnd, &lvItem);
5482 * Sets the text of an item or subitem.
5485 * [I] HWND : window handle
5486 * [I] INT : item index
5487 * [I] LPLVITEMA : item or subitem info
5493 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5495 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5496 BOOL bResult = FALSE;
5499 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5501 ZeroMemory(&lvItem, sizeof(LVITEMA));
5502 lvItem.mask = LVIF_TEXT;
5503 lvItem.pszText = lpLVItem->pszText;
5504 lvItem.iItem = nItem;
5505 lvItem.iSubItem = lpLVItem->iSubItem;
5506 bResult = ListView_SetItemA(hwnd, &lvItem);
5512 /* LISTVIEW_SetItemTextW */
5516 * Set item index that marks the start of a multiple selection.
5519 * [I] HWND : window handle
5523 * Index number or -1 if there is no selection mark.
5525 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5527 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5528 INT nOldIndex = infoPtr->nSelectionMark;
5530 infoPtr->nSelectionMark = nIndex;
5537 * Sets the text background color.
5540 * [I] HWND : window handle
5541 * [I] COLORREF : text background color
5547 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5549 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5551 infoPtr->clrTextBk = clrTextBk;
5552 InvalidateRect(hwnd, NULL, TRUE);
5559 * Sets the text foreground color.
5562 * [I] HWND : window handle
5563 * [I] COLORREF : text color
5569 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5571 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5573 infoPtr->clrText = clrText;
5574 InvalidateRect(hwnd, NULL, TRUE);
5579 /* LISTVIEW_SetToolTips */
5580 /* LISTVIEW_SetUnicodeFormat */
5581 /* LISTVIEW_SetWorkAreas */
5585 * Callback internally used by LISTVIEW_SortItems()
5588 * [I] LPVOID : first LISTVIEW_ITEM to compare
5589 * [I] LPVOID : second LISTVIEW_ITEM to compare
5590 * [I] LPARAM : HWND of control
5593 * if first comes before second : negative
5594 * if first comes after second : positive
5595 * if first and second are equivalent : zero
5597 static INT WINAPI LISTVIEW_CallBackCompare(
5602 /* Forward the call to the client defined callback */
5603 HWND hwnd = (HWND)lParam;
5604 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5606 return (infoPtr->pfnCompare)(
5607 ((LISTVIEW_ITEM *)first)->lParam,
5608 ((LISTVIEW_ITEM *)second)->lParam,
5609 infoPtr->lParamSort);
5614 * Sorts the listview items.
5617 * [I] HWND : window handle
5618 * [I] WPARAM : application-defined value
5619 * [I] LPARAM : pointer to comparision callback
5625 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5627 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5629 LISTVIEW_ITEM *lpItem;
5633 if (!infoPtr || !infoPtr->hdpaItems)
5636 nCount = GETITEMCOUNT(infoPtr);
5637 /* if there are 0 or 1 items, there is no need to sort */
5640 sortList = DPA_Create(nCount);
5642 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5643 infoPtr->lParamSort = (LPARAM)wParam;
5645 /* append pointers one by one to sortList */
5646 for (i = 0; i < nCount; i++)
5648 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5649 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5650 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5653 /* sort the sortList */
5654 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5656 /* copy the pointers back */
5657 for (i = 0; i < nCount; i++)
5659 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5660 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5661 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5664 DPA_Destroy(sortList);
5670 /* LISTVIEW_SubItemHitTest */
5674 * Updates an items or rearranges the listview control.
5677 * [I] HWND : window handle
5678 * [I] INT : item index
5684 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5686 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5687 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5688 BOOL bResult = FALSE;
5691 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5695 /* rearrange with default alignment style */
5696 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5697 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5699 ListView_Arrange(hwnd, 0);
5703 /* get item bounding rectangle */
5704 rc.left = LVIR_BOUNDS;
5705 ListView_GetItemRect(hwnd, nItem, &rc);
5706 InvalidateRect(hwnd, &rc, TRUE);
5715 * Creates the listview control.
5718 * [I] HWND : window handle
5723 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5725 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5726 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5727 UINT uView = lpcs->style & LVS_TYPEMASK;
5730 /* initialize info pointer */
5731 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5733 /* determine the type of structures to use */
5734 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5735 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5736 if (infoPtr->notifyFormat != NFR_ANSI)
5738 FIXME("ANSI notify format is NOT used\n");
5741 /* initialize color information */
5742 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5743 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5744 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5746 /* set default values */
5747 infoPtr->uCallbackMask = 0;
5748 infoPtr->nFocusedItem = -1;
5749 infoPtr->nSelectionMark = -1;
5750 infoPtr->nHotItem = -1;
5751 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5752 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5753 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5754 infoPtr->hwndEdit = 0;
5755 infoPtr->pedititem = NULL;
5757 /* get default font (icon title) */
5758 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5759 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5760 infoPtr->hFont = infoPtr->hDefaultFont;
5763 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5764 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5765 0, 0, 0, 0, hwnd, (HMENU)0,
5766 lpcs->hInstance, NULL);
5768 /* set header font */
5769 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5772 if (uView == LVS_ICON)
5774 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5775 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5777 else if (uView == LVS_REPORT)
5779 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5781 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5784 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5785 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5789 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5790 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5793 /* display unsupported listview window styles */
5794 LISTVIEW_UnsupportedStyles(lpcs->style);
5796 /* allocate memory for the data structure */
5797 infoPtr->hdpaItems = DPA_Create(10);
5799 /* initialize size of items */
5800 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5801 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
5808 * Erases the background of the listview control.
5811 * [I] HWND : window handle
5812 * [I] WPARAM : device context handle
5813 * [I] LPARAM : not used
5819 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5822 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5825 if (infoPtr->clrBk == CLR_NONE)
5827 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5832 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5833 GetClientRect(hwnd, &rc);
5834 FillRect((HDC)wParam, &rc, hBrush);
5835 DeleteObject(hBrush);
5844 * Retrieves the listview control font.
5847 * [I] HWND : window handle
5852 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5854 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5856 return infoPtr->hFont;
5861 * Performs vertical scrolling.
5864 * [I] HWND : window handle
5865 * [I] INT : scroll code
5866 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5868 * [I] HWND : scrollbar control window handle
5873 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5876 SCROLLINFO scrollInfo;
5878 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5879 scrollInfo.cbSize = sizeof(SCROLLINFO);
5880 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
5882 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5884 INT nOldScrollPos = scrollInfo.nPos;
5885 switch (nScrollCode)
5888 if (scrollInfo.nPos > scrollInfo.nMin)
5895 if (scrollInfo.nPos < scrollInfo.nMax)
5902 if (scrollInfo.nPos > scrollInfo.nMin)
5905 if (scrollInfo.nPos >= scrollInfo.nPage)
5907 scrollInfo.nPos -= scrollInfo.nPage;
5911 scrollInfo.nPos = scrollInfo.nMin;
5917 if (scrollInfo.nPos < scrollInfo.nMax)
5919 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
5921 scrollInfo.nPos += scrollInfo.nPage;
5925 scrollInfo.nPos = scrollInfo.nMax;
5931 scrollInfo.nPos = nCurrentPos;
5935 if (nOldScrollPos != scrollInfo.nPos)
5937 scrollInfo.fMask = SIF_POS;
5938 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
5939 InvalidateRect(hwnd, NULL, TRUE);
5948 * Performs horizontal scrolling.
5951 * [I] HWND : window handle
5952 * [I] INT : scroll code
5953 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5955 * [I] HWND : scrollbar control window handle
5960 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5963 SCROLLINFO scrollInfo;
5965 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5966 scrollInfo.cbSize = sizeof(SCROLLINFO);
5967 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
5969 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5971 INT nOldScrollPos = scrollInfo.nPos;
5973 switch (nScrollCode)
5976 if (scrollInfo.nPos > scrollInfo.nMin)
5983 if (scrollInfo.nPos < scrollInfo.nMax)
5990 if (scrollInfo.nPos > scrollInfo.nMin)
5992 if (scrollInfo.nPos >= scrollInfo.nPage)
5994 scrollInfo.nPos -= scrollInfo.nPage;
5998 scrollInfo.nPos = scrollInfo.nMin;
6004 if (scrollInfo.nPos < scrollInfo.nMax)
6006 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6008 scrollInfo.nPos += scrollInfo.nPage;
6012 scrollInfo.nPos = scrollInfo.nMax;
6018 scrollInfo.nPos = nCurrentPos;
6022 if (nOldScrollPos != scrollInfo.nPos)
6024 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6025 scrollInfo.fMask = SIF_POS;
6026 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6027 if(uView == LVS_REPORT)
6029 scrollInfo.fMask = SIF_POS;
6030 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6031 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6033 InvalidateRect(hwnd, NULL, TRUE);
6045 * [I] HWND : window handle
6046 * [I] INT : virtual key
6047 * [I] LONG : key data
6052 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6054 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6055 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6056 HWND hwndParent = GetParent(hwnd);
6057 NMLVKEYDOWN nmKeyDown;
6060 BOOL bRedraw = FALSE;
6062 /* send LVN_KEYDOWN notification */
6063 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6064 nmKeyDown.hdr.hwndFrom = hwnd;
6065 nmKeyDown.hdr.idFrom = nCtrlId;
6066 nmKeyDown.hdr.code = LVN_KEYDOWN;
6067 nmKeyDown.wVKey = nVirtualKey;
6068 nmKeyDown.flags = 0;
6069 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6072 nmh.hwndFrom = hwnd;
6073 nmh.idFrom = nCtrlId;
6075 switch (nVirtualKey)
6078 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6080 /* send NM_RETURN notification */
6081 nmh.code = NM_RETURN;
6082 ListView_Notify(hwndParent, nCtrlId, &nmh);
6084 /* send LVN_ITEMACTIVATE notification */
6085 nmh.code = LVN_ITEMACTIVATE;
6086 ListView_Notify(hwndParent, nCtrlId, &nmh);
6091 if (GETITEMCOUNT(infoPtr) > 0)
6098 if (GETITEMCOUNT(infoPtr) > 0)
6100 nItem = GETITEMCOUNT(infoPtr) - 1;
6105 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6109 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6113 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6117 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6129 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6131 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6132 if (bRedraw != FALSE)
6134 /* refresh client area */
6135 InvalidateRect(hwnd, NULL, TRUE);
6148 * [I] HWND : window handle
6153 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6155 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6156 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6159 TRACE("(hwnd=%x)\n", hwnd);
6161 /* send NM_KILLFOCUS notification */
6162 nmh.hwndFrom = hwnd;
6163 nmh.idFrom = nCtrlId;
6164 nmh.code = NM_KILLFOCUS;
6165 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6167 /* set window focus flag */
6168 infoPtr->bFocus = FALSE;
6170 /* NEED drawing optimization ; redraw the selected items */
6171 InvalidateRect(hwnd, NULL, FALSE);
6178 * Processes double click messages (left mouse button).
6181 * [I] HWND : window handle
6182 * [I] WORD : key flag
6183 * [I] WORD : x coordinate
6184 * [I] WORD : y coordinate
6189 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6192 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6195 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6197 /* send NM_DBLCLK notification */
6198 nmh.hwndFrom = hwnd;
6199 nmh.idFrom = nCtrlId;
6200 nmh.code = NM_DBLCLK;
6201 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6203 /* send LVN_ITEMACTIVATE notification */
6204 nmh.code = LVN_ITEMACTIVATE;
6205 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6212 * Processes mouse down messages (left mouse button).
6215 * [I] HWND : window handle
6216 * [I] WORD : key flag
6217 * [I] WORD : x coordinate
6218 * [I] WORD : y coordinate
6223 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6226 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6227 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6228 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6229 static BOOL bGroupSelect = TRUE;
6234 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6237 /* send NM_RELEASEDCAPTURE notification */
6238 nmh.hwndFrom = hwnd;
6239 nmh.idFrom = nCtrlId;
6240 nmh.code = NM_RELEASEDCAPTURE;
6241 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6243 if (infoPtr->bFocus == FALSE)
6248 /* set left button down flag */
6249 infoPtr->bLButtonDown = TRUE;
6251 ptPosition.x = wPosX;
6252 ptPosition.y = wPosY;
6253 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6254 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6256 if (lStyle & LVS_SINGLESEL)
6258 LISTVIEW_SetSelection(hwnd, nItem);
6262 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6264 if (bGroupSelect != FALSE)
6266 LISTVIEW_AddGroupSelection(hwnd, nItem);
6270 LISTVIEW_AddSelection(hwnd, nItem);
6273 else if (wKey & MK_CONTROL)
6275 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6277 else if (wKey & MK_SHIFT)
6279 LISTVIEW_SetGroupSelection(hwnd, nItem);
6283 LISTVIEW_SetSelection(hwnd, nItem);
6289 /* remove all selections */
6290 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6293 InvalidateRect(hwnd, NULL, TRUE);
6300 * Processes mouse up messages (left mouse button).
6303 * [I] HWND : window handle
6304 * [I] WORD : key flag
6305 * [I] WORD : x coordinate
6306 * [I] WORD : y coordinate
6311 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6314 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6316 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6318 if (infoPtr->bLButtonDown != FALSE)
6320 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6323 /* send NM_CLICK notification */
6324 nmh.hwndFrom = hwnd;
6325 nmh.idFrom = nCtrlId;
6326 nmh.code = NM_CLICK;
6327 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6329 /* set left button flag */
6330 infoPtr->bLButtonDown = FALSE;
6338 * Creates the listview control (called before WM_CREATE).
6341 * [I] HWND : window handle
6342 * [I] WPARAM : unhandled
6343 * [I] LPARAM : widow creation info
6348 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6350 LISTVIEW_INFO *infoPtr;
6352 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6354 /* allocate memory for info structure */
6355 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6356 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6357 if (infoPtr == NULL)
6359 ERR("could not allocate info memory!\n");
6363 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6365 ERR("pointer assignment error!\n");
6369 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6374 * Destroys the listview control (called after WM_DESTROY).
6377 * [I] HWND : window handle
6382 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6384 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6386 TRACE("(hwnd=%x)\n", hwnd);
6388 /* delete all items */
6389 LISTVIEW_DeleteAllItems(hwnd);
6391 /* destroy data structure */
6392 DPA_Destroy(infoPtr->hdpaItems);
6395 infoPtr->hFont = (HFONT)0;
6396 if (infoPtr->hDefaultFont)
6398 DeleteObject(infoPtr->hDefaultFont);
6401 /* free listview info pointer*/
6402 COMCTL32_Free(infoPtr);
6409 * Handles notifications from children.
6412 * [I] HWND : window handle
6413 * [I] INT : control identifier
6414 * [I] LPNMHDR : notification information
6419 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6421 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6423 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6425 /* handle notification from header control */
6426 if (lpnmh->code == HDN_ENDTRACKA)
6428 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6429 InvalidateRect(hwnd, NULL, TRUE);
6431 else if(lpnmh->code == HDN_ITEMCLICKA)
6433 /* Handle sorting by Header Column */
6435 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6436 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6438 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6439 nmlv.hdr.hwndFrom = hwnd;
6440 nmlv.hdr.idFrom = lCtrlId;
6441 nmlv.hdr.code = LVN_COLUMNCLICK;
6443 nmlv.iSubItem = pnmHeader->iItem;
6445 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6448 else if(lpnmh->code == NM_RELEASEDCAPTURE)
6450 /* Idealy this should be done in HDN_ENDTRACKA
6451 * but since SetItemBounds in Header.c is called after
6452 * the notification is sent, it is neccessary to handle the
6453 * update of the scroll bar here (Header.c works fine as it is,
6454 * no need to disturb it)
6456 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6457 LISTVIEW_UpdateScroll(hwnd);
6458 InvalidateRect(hwnd, NULL, TRUE);
6468 * Determines the type of structure to use.
6471 * [I] HWND : window handle of the sender
6472 * [I] HWND : listview window handle
6473 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6478 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6480 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6482 if (nCommand == NF_REQUERY)
6484 /* determine the type of structure to use */
6485 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6486 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6487 if (infoPtr->notifyFormat == NFR_UNICODE)
6489 FIXME("NO support for unicode structures");
6498 * Paints/Repaints the listview control.
6501 * [I] HWND : window handle
6502 * [I] HDC : device context handle
6507 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6511 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6515 hdc = BeginPaint(hwnd, &ps);
6516 LISTVIEW_Refresh(hwnd, hdc);
6517 EndPaint(hwnd, &ps);
6521 LISTVIEW_Refresh(hwnd, hdc);
6529 * Processes double click messages (right mouse button).
6532 * [I] HWND : window handle
6533 * [I] WORD : key flag
6534 * [I] WORD : x coordinate
6535 * [I] WORD : y coordinate
6540 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6543 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6546 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6548 /* send NM_RELEASEDCAPTURE notification */
6549 nmh.hwndFrom = hwnd;
6550 nmh.idFrom = nCtrlId;
6551 nmh.code = NM_RELEASEDCAPTURE;
6552 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6554 /* send NM_RDBLCLK notification */
6555 nmh.code = NM_RDBLCLK;
6556 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6563 * Processes mouse down messages (right mouse button).
6566 * [I] HWND : window handle
6567 * [I] WORD : key flag
6568 * [I] WORD : x coordinate
6569 * [I] WORD : y coordinate
6574 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6577 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6578 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6583 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6585 /* send NM_RELEASEDCAPTURE notification */
6586 nmh.hwndFrom = hwnd;
6587 nmh.idFrom = nCtrlId;
6588 nmh.code = NM_RELEASEDCAPTURE;
6589 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6591 /* make sure the listview control window has the focus */
6592 if (infoPtr->bFocus == FALSE)
6597 /* set right button down flag */
6598 infoPtr->bRButtonDown = TRUE;
6600 /* determine the index of the selected item */
6601 ptPosition.x = wPosX;
6602 ptPosition.y = wPosY;
6603 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6604 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6606 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6608 LISTVIEW_SetSelection(hwnd, nItem);
6613 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6621 * Processes mouse up messages (right mouse button).
6624 * [I] HWND : window handle
6625 * [I] WORD : key flag
6626 * [I] WORD : x coordinate
6627 * [I] WORD : y coordinate
6632 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6635 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6636 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6639 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6641 if (infoPtr->bRButtonDown != FALSE)
6643 /* send NM_RClICK notification */
6644 ZeroMemory(&nmh, sizeof(NMHDR));
6645 nmh.hwndFrom = hwnd;
6646 nmh.idFrom = nCtrlId;
6647 nmh.code = NM_RCLICK;
6648 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6650 /* set button flag */
6651 infoPtr->bRButtonDown = FALSE;
6662 * [I] HWND : window handle
6663 * [I] HWND : window handle of previously focused window
6668 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6670 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6671 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6674 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
6676 /* send NM_SETFOCUS notification */
6677 nmh.hwndFrom = hwnd;
6678 nmh.idFrom = nCtrlId;
6679 nmh.code = NM_SETFOCUS;
6680 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6682 /* set window focus flag */
6683 infoPtr->bFocus = TRUE;
6685 InvalidateRect(hwnd, NULL, TRUE);
6696 * [I] HWND : window handle
6697 * [I] HFONT : font handle
6698 * [I] WORD : redraw flag
6703 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6705 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6706 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6708 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6712 infoPtr->hFont = infoPtr->hDefaultFont;
6716 infoPtr->hFont = hFont;
6719 if (uView == LVS_REPORT)
6721 /* set header font */
6722 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6723 MAKELPARAM(fRedraw, 0));
6726 /* invalidate listview control client area */
6727 InvalidateRect(hwnd, NULL, TRUE);
6729 if (fRedraw != FALSE)
6739 * Resizes the listview control. This function processes WM_SIZE
6740 * messages. At this time, the width and height are not used.
6743 * [I] HWND : window handle
6744 * [I] WORD : new width
6745 * [I] WORD : new height
6750 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6752 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6753 UINT uView = lStyle & LVS_TYPEMASK;
6755 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
6757 LISTVIEW_UpdateSize(hwnd);
6759 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6761 if (lStyle & LVS_ALIGNLEFT)
6763 LISTVIEW_AlignLeft(hwnd);
6767 LISTVIEW_AlignTop(hwnd);
6771 LISTVIEW_UpdateScroll(hwnd);
6773 /* invalidate client area + erase background */
6774 InvalidateRect(hwnd, NULL, TRUE);
6781 * Sets the size information.
6784 * [I] HWND : window handle
6789 static VOID LISTVIEW_UpdateSize(HWND hwnd)
6791 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6792 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6793 UINT uView = lStyle & LVS_TYPEMASK;
6796 GetClientRect(hwnd, &rcList);
6797 infoPtr->rcList.left = 0;
6798 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
6799 infoPtr->rcList.top = 0;
6800 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
6802 if (uView == LVS_LIST)
6804 if ((lStyle & WS_HSCROLL) == 0)
6806 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6807 if (infoPtr->rcList.bottom > nHScrollHeight)
6809 infoPtr->rcList.bottom -= nHScrollHeight;
6813 else if (uView == LVS_REPORT)
6820 Header_Layout(infoPtr->hwndHeader, &hl);
6821 if (!(LVS_NOCOLUMNHEADER & lStyle))
6823 infoPtr->rcList.top = max(wp.cy, 0);
6830 * Processes WM_STYLECHANGED messages.
6833 * [I] HWND : window handle
6834 * [I] WPARAM : window style type (normal or extended)
6835 * [I] LPSTYLESTRUCT : window style information
6840 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6843 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6844 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
6845 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
6846 RECT rcList = infoPtr->rcList;
6848 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
6849 hwnd, wStyleType, lpss);
6851 if (wStyleType == GWL_STYLE)
6853 if (uOldView == LVS_REPORT)
6855 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6858 if ((lpss->styleOld & WS_HSCROLL) != 0)
6860 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6863 if ((lpss->styleOld & WS_VSCROLL) != 0)
6865 ShowScrollBar(hwnd, SB_VERT, FALSE);
6868 if (uNewView == LVS_ICON)
6870 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6871 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6872 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6873 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6874 if (lpss->styleNew & LVS_ALIGNLEFT)
6876 LISTVIEW_AlignLeft(hwnd);
6880 LISTVIEW_AlignTop(hwnd);
6883 else if (uNewView == LVS_REPORT)
6890 Header_Layout(infoPtr->hwndHeader, &hl);
6891 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
6893 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
6895 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6897 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6898 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6899 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6900 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6902 else if (uNewView == LVS_LIST)
6904 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6905 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6906 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6907 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6911 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6912 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6913 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6914 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6915 if (lpss->styleNew & LVS_ALIGNLEFT)
6917 LISTVIEW_AlignLeft(hwnd);
6921 LISTVIEW_AlignTop(hwnd);
6925 /* update the size of the client area */
6926 LISTVIEW_UpdateSize(hwnd);
6928 /* add scrollbars if needed */
6929 LISTVIEW_UpdateScroll(hwnd);
6931 /* invalidate client area + erase background */
6932 InvalidateRect(hwnd, NULL, TRUE);
6934 /* print the list of unsupported window styles */
6935 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6943 * Window procedure of the listview control.
6946 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6951 case LVM_APPROXIMATEVIEWRECT:
6952 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6953 LOWORD(lParam), HIWORD(lParam));
6955 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6957 /* case LVM_CREATEDRAGIMAGE: */
6959 case LVM_DELETEALLITEMS:
6960 return LISTVIEW_DeleteAllItems(hwnd);
6962 case LVM_DELETECOLUMN:
6963 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6965 case LVM_DELETEITEM:
6966 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6968 case LVM_EDITLABELW:
6969 case LVM_EDITLABELA:
6970 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
6972 case LVM_ENSUREVISIBLE:
6973 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6976 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6978 case LVM_GETBKCOLOR:
6979 return LISTVIEW_GetBkColor(hwnd);
6981 /* case LVM_GETBKIMAGE: */
6983 case LVM_GETCALLBACKMASK:
6984 return LISTVIEW_GetCallbackMask(hwnd);
6986 case LVM_GETCOLUMNA:
6987 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6989 /* case LVM_GETCOLUMNW: */
6991 case LVM_GETCOLUMNORDERARRAY:
6992 FIXME("Unimplemented msg LVM_GETCOLUMNORDERARRAY\n");
6995 case LVM_GETCOLUMNWIDTH:
6996 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
6998 case LVM_GETCOUNTPERPAGE:
6999 return LISTVIEW_GetCountPerPage(hwnd);
7001 case LVM_GETEDITCONTROL:
7002 return LISTVIEW_GetEditControl(hwnd);
7004 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7005 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7008 return LISTVIEW_GetHeader(hwnd);
7010 /* case LVM_GETHOTCURSOR: */
7012 case LVM_GETHOTITEM:
7013 return LISTVIEW_GetHotItem(hwnd);
7015 /* case LVM_GETHOVERTIME: */
7017 case LVM_GETIMAGELIST:
7018 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7020 /* case LVM_GETISEARCHSTRING: */
7023 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
7025 /* case LVM_GETITEMW: */
7027 case LVM_GETITEMCOUNT:
7028 return LISTVIEW_GetItemCount(hwnd);
7030 case LVM_GETITEMPOSITION:
7031 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7033 case LVM_GETITEMRECT:
7034 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7036 case LVM_GETITEMSPACING:
7037 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7039 case LVM_GETITEMSTATE:
7040 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7042 case LVM_GETITEMTEXTA:
7043 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7046 /* case LVM_GETITEMTEXTW: */
7048 case LVM_GETNEXTITEM:
7049 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7051 /* case LVM_GETNUMBEROFWORKAREAS: */
7054 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7056 case LVM_GETSELECTEDCOUNT:
7057 return LISTVIEW_GetSelectedCount(hwnd);
7059 case LVM_GETSELECTIONMARK:
7060 return LISTVIEW_GetSelectionMark(hwnd);
7062 case LVM_GETSTRINGWIDTHA:
7063 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7065 /* case LVM_GETSTRINGWIDTHW: */
7066 /* case LVM_GETSUBITEMRECT: */
7068 case LVM_GETTEXTBKCOLOR:
7069 return LISTVIEW_GetTextBkColor(hwnd);
7071 case LVM_GETTEXTCOLOR:
7072 return LISTVIEW_GetTextColor(hwnd);
7074 /* case LVM_GETTOOLTIPS: */
7076 case LVM_GETTOPINDEX:
7077 return LISTVIEW_GetTopIndex(hwnd);
7079 /* case LVM_GETUNICODEFORMAT: */
7081 case LVM_GETVIEWRECT:
7082 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7084 /* case LVM_GETWORKAREAS: */
7087 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7089 case LVM_INSERTCOLUMNA:
7090 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7092 case LVM_INSERTCOLUMNW:
7093 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7095 case LVM_INSERTITEMA:
7096 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7098 case LVM_INSERTITEMW:
7099 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7101 case LVM_REDRAWITEMS:
7102 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7104 /* case LVM_SCROLL: */
7105 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7107 case LVM_SETBKCOLOR:
7108 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7110 /* case LVM_SETBKIMAGE: */
7112 case LVM_SETCALLBACKMASK:
7113 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7115 case LVM_SETCOLUMNA:
7116 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7118 case LVM_SETCOLUMNW:
7119 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7122 case LVM_SETCOLUMNORDERARRAY:
7123 FIXME("Unimplemented msg LVM_SETCOLUMNORDERARRAY\n");
7126 case LVM_SETCOLUMNWIDTH:
7127 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
7129 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7130 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7132 /* case LVM_SETHOTCURSOR: */
7134 case LVM_SETHOTITEM:
7135 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7137 /* case LVM_SETHOVERTIME: */
7138 /* case LVM_SETICONSPACING: */
7140 case LVM_SETIMAGELIST:
7141 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7144 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7146 /* case LVM_SETITEMW: */
7148 case LVM_SETITEMCOUNT:
7149 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7151 case LVM_SETITEMPOSITION:
7152 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7153 (INT)HIWORD(lParam));
7155 /* case LVM_SETITEMPOSITION32: */
7157 case LVM_SETITEMSTATE:
7158 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7160 case LVM_SETITEMTEXTA:
7161 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7163 /* case LVM_SETITEMTEXTW: */
7165 case LVM_SETSELECTIONMARK:
7166 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7168 case LVM_SETTEXTBKCOLOR:
7169 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7171 case LVM_SETTEXTCOLOR:
7172 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7174 /* case LVM_SETTOOLTIPS: */
7175 /* case LVM_SETUNICODEFORMAT: */
7176 /* case LVM_SETWORKAREAS: */
7179 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7181 /* case LVM_SUBITEMHITTEST: */
7184 return LISTVIEW_Update(hwnd, (INT)wParam);
7188 return LISTVIEW_Command(hwnd, wParam, lParam);
7191 return LISTVIEW_Create(hwnd, wParam, lParam);
7194 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7197 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7200 return LISTVIEW_GetFont(hwnd);
7203 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7204 (INT)HIWORD(wParam), (HWND)lParam);
7207 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7210 return LISTVIEW_KillFocus(hwnd);
7212 case WM_LBUTTONDBLCLK:
7213 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7216 case WM_LBUTTONDOWN:
7217 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7220 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7223 /* case WM_MOUSEMOVE: */
7224 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
7227 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7230 return LISTVIEW_NCDestroy(hwnd);
7233 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7235 case WM_NOTIFYFORMAT:
7236 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7239 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7241 case WM_RBUTTONDBLCLK:
7242 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7245 case WM_RBUTTONDOWN:
7246 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7250 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7254 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7257 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7259 /* case WM_SETREDRAW: */
7262 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7264 case WM_STYLECHANGED:
7265 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7267 /* case WM_TIMER: */
7270 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7271 (INT)HIWORD(wParam), (HWND)lParam);
7273 /* case WM_WINDOWPOSCHANGED: */
7274 /* case WM_WININICHANGE: */
7277 if (uMsg >= WM_USER)
7279 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7283 /* call default window procedure */
7284 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7292 * Registers the window class.
7300 VOID LISTVIEW_Register(void)
7304 if (!GlobalFindAtomA(WC_LISTVIEWA))
7306 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7307 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7308 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7309 wndClass.cbClsExtra = 0;
7310 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7311 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7312 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7313 wndClass.lpszClassName = WC_LISTVIEWA;
7314 RegisterClassA(&wndClass);
7320 * Unregisters the window class.
7328 VOID LISTVIEW_Unregister(void)
7330 if (GlobalFindAtomA(WC_LISTVIEWA))
7332 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
7338 * Handle any WM_COMMAND messages
7344 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
7346 switch (HIWORD(wParam))
7351 * Adjust the edit window size
7354 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7355 HDC hdc = GetDC(infoPtr->hwndEdit);
7359 GetWindowTextA(infoPtr->hwndEdit, buffer, 1024);
7360 GetWindowRect(infoPtr->hwndEdit, &rect);
7361 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
7369 rect.bottom - rect.top,
7370 SWP_DRAWFRAME|SWP_NOMOVE);
7372 ReleaseDC(hwnd, hdc);
7378 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
7387 * Subclassed edit control windproc function
7393 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
7394 WPARAM wParam, LPARAM lParam)
7397 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
7398 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
7403 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
7410 WNDPROC editProc = einfo->EditWndProc;
7411 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
7412 COMCTL32_Free(einfo);
7413 infoPtr->pedititem = NULL;
7414 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
7418 if (VK_RETURN == (INT)wParam)
7423 else if (VK_ESCAPE == (INT)wParam)
7427 return CallWindowProcA(einfo->EditWndProc, hwnd,
7428 uMsg, wParam, lParam);
7431 if (einfo->EditLblCb)
7433 char *buffer = NULL;
7437 int len = 1 + GetWindowTextLengthA(hwnd);
7441 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
7443 GetWindowTextA(hwnd, buffer, len);
7448 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
7451 COMCTL32_Free(buffer);
7453 einfo->EditLblCb = NULL;
7456 SendMessageA(hwnd, WM_CLOSE, 0, 0);
7463 * Creates a subclassed edit cotrol
7469 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
7470 INT width, INT height, HWND parent, HINSTANCE hinst,
7471 EditlblCallback EditLblCb, DWORD param)
7474 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
7475 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
7478 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
7479 if (!(hedit = CreateWindowA("Edit", text, style, x, y, width, height,
7480 parent, 0, hinst, 0)))
7482 COMCTL32_Free(infoPtr->pedititem);
7486 infoPtr->pedititem->param = param;
7487 infoPtr->pedititem->EditLblCb = EditLblCb;
7488 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
7489 GWL_WNDPROC, (LONG) EditLblWndProc);