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 : not completed
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 : simple hack only
35 * LISTVIEW_SetColumnOrderArray : simple hack only
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 512
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 LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
103 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
104 static INT LISTVIEW_GetCountPerRow(HWND);
105 static INT LISTVIEW_GetCountPerColumn(HWND);
106 static VOID LISTVIEW_AlignLeft(HWND);
107 static VOID LISTVIEW_AlignTop(HWND);
108 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
109 static VOID LISTVIEW_AddSelection(HWND, INT);
110 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
111 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
112 static INT LISTVIEW_GetItemHeight(HWND);
113 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
114 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
115 static INT LISTVIEW_GetItemWidth(HWND);
116 static INT LISTVIEW_GetLabelWidth(HWND, INT);
117 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
118 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
119 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
120 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
121 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
122 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
123 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
124 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
125 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
126 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
127 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
128 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
129 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
130 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
131 static VOID LISTVIEW_UpdateScroll(HWND);
132 static VOID LISTVIEW_SetSelection(HWND, INT);
133 static VOID LISTVIEW_UpdateSize(HWND);
134 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
135 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
136 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
137 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
138 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
139 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
140 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
141 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
143 /*************************************************************************
144 * LISTVIEW_UpdateHeaderSize [Internal]
146 * Function to resize the header control
149 * hwnd [I] handle to a window
150 * nNewScrollPos [I] Scroll Pos to Set
157 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
159 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
163 GetWindowRect(infoPtr->hwndHeader, &winRect);
164 point[0].x = winRect.left;
165 point[0].y = winRect.top;
166 point[1].x = winRect.right;
167 point[1].y = winRect.bottom;
169 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
170 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
171 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
173 SetWindowPos(infoPtr->hwndHeader,0,
174 point[0].x,point[0].y,point[1].x,point[1].y,
175 SWP_NOZORDER | SWP_NOACTIVATE);
180 * Update the scrollbars. This functions should be called whenever
181 * the content, size or view changes.
184 * [I] HWND : window handle
189 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
191 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
192 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
193 UINT uView = lStyle & LVS_TYPEMASK;
194 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
195 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
196 SCROLLINFO scrollInfo;
198 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
199 scrollInfo.cbSize = sizeof(SCROLLINFO);
201 if (uView == LVS_LIST)
203 /* update horizontal scrollbar */
205 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
206 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
207 INT nNumOfItems = GETITEMCOUNT(infoPtr);
209 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
210 if((nNumOfItems % nCountPerColumn) == 0)
214 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
215 scrollInfo.nPage = nCountPerRow;
216 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
217 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
219 else if (uView == LVS_REPORT)
221 /* update vertical scrollbar */
223 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
224 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
225 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
226 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
227 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
229 /* update horizontal scrollbar */
230 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
231 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
232 || GETITEMCOUNT(infoPtr) == 0)
237 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
238 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
239 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
240 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
242 /* Update the Header Control */
243 scrollInfo.fMask = SIF_POS;
244 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
245 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
252 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
254 INT nViewWidth = rcView.right - rcView.left;
255 INT nViewHeight = rcView.bottom - rcView.top;
257 /* Update Horizontal Scrollbar */
258 scrollInfo.fMask = SIF_POS;
259 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
260 || GETITEMCOUNT(infoPtr) == 0)
264 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
266 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
267 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
268 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
270 /* Update Vertical Scrollbar */
271 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
272 scrollInfo.fMask = SIF_POS;
273 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
274 || GETITEMCOUNT(infoPtr) == 0)
278 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
280 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
281 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
282 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
289 * Prints a message for unsupported window styles.
290 * A kind of TODO list for window styles.
293 * [I] LONG : window style
298 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
300 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
302 FIXME(" LVS_EDITLABELS\n");
305 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
307 FIXME(" LVS_NOLABELWRAP\n");
310 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
312 FIXME(" LVS_NOSCROLL\n");
315 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
317 FIXME(" LVS_NOSORTHEADER\n");
320 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
322 FIXME(" LVS_OWNERDRAWFIXED\n");
325 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
327 FIXME(" LVS_SHAREIMAGELISTS\n");
330 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
332 FIXME(" LVS_SORTASCENDING\n");
335 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
337 FIXME(" LVS_SORTDESCENDING\n");
343 * Aligns the items with the top edge of the window.
346 * [I] HWND : window handle
351 static VOID LISTVIEW_AlignTop(HWND hwnd)
353 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
354 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
355 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
360 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
362 ZeroMemory(&ptItem, sizeof(POINT));
363 ZeroMemory(&rcView, sizeof(RECT));
365 if (nListWidth > infoPtr->nItemWidth)
367 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
369 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
372 ptItem.y += infoPtr->nItemHeight;
375 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
376 ptItem.x += infoPtr->nItemWidth;
377 rcView.right = max(rcView.right, ptItem.x);
380 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
384 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
386 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
387 ptItem.y += infoPtr->nItemHeight;
390 rcView.right = infoPtr->nItemWidth;
391 rcView.bottom = ptItem.y;
394 LISTVIEW_SetViewRect(hwnd, &rcView);
400 * Aligns the items with the left edge of the window.
403 * [I] HWND : window handle
408 static VOID LISTVIEW_AlignLeft(HWND hwnd)
410 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
411 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
412 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
417 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
419 ZeroMemory(&ptItem, sizeof(POINT));
420 ZeroMemory(&rcView, sizeof(RECT));
422 if (nListHeight > infoPtr->nItemHeight)
424 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
426 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
429 ptItem.x += infoPtr->nItemWidth;
432 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
433 ptItem.y += infoPtr->nItemHeight;
434 rcView.bottom = max(rcView.bottom, ptItem.y);
437 rcView.right = ptItem.x + infoPtr->nItemWidth;
441 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
443 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
444 ptItem.x += infoPtr->nItemWidth;
447 rcView.bottom = infoPtr->nItemHeight;
448 rcView.right = ptItem.x;
451 LISTVIEW_SetViewRect(hwnd, &rcView);
457 * Set the bounding rectangle of all the items.
460 * [I] HWND : window handle
461 * [I] LPRECT : bounding rectangle
467 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
469 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
470 BOOL bResult = FALSE;
472 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
473 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
475 if (lprcView != NULL)
478 infoPtr->rcView.left = lprcView->left;
479 infoPtr->rcView.top = lprcView->top;
480 infoPtr->rcView.right = lprcView->right;
481 infoPtr->rcView.bottom = lprcView->bottom;
489 * Retrieves the bounding rectangle of all the items.
492 * [I] HWND : window handle
493 * [O] LPRECT : bounding rectangle
499 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
501 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
502 BOOL bResult = FALSE;
505 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
507 if (lprcView != NULL)
509 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
510 if (bResult != FALSE)
512 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
513 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
514 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
515 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
518 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
519 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
527 * Retrieves the subitem pointer associated with the subitem index.
530 * [I] HDPA : DPA handle for a specific item
531 * [I] INT : index of subitem
534 * SUCCESS : subitem pointer
537 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
540 LISTVIEW_SUBITEM *lpSubItem;
543 for (i = 1; i < hdpaSubItems->nItemCount; i++)
545 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
546 if (lpSubItem != NULL)
548 if (lpSubItem->iSubItem == nSubItem)
560 * Calculates the width of an item.
563 * [I] HWND : window handle
564 * [I] LONG : window style
567 * Returns item width.
569 static INT LISTVIEW_GetItemWidth(HWND hwnd)
571 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
572 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
573 INT nHeaderItemCount;
579 TRACE("(hwnd=%x)\n", hwnd);
581 if (uView == LVS_ICON)
583 nItemWidth = infoPtr->iconSpacing.cx;
585 else if (uView == LVS_REPORT)
587 /* calculate width of header */
588 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
589 for (i = 0; i < nHeaderItemCount; i++)
591 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
593 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
599 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
601 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
602 nItemWidth = max(nItemWidth, nLabelWidth);
605 /* default label size */
606 if (GETITEMCOUNT(infoPtr) == 0)
608 nItemWidth = DEFAULT_COLUMN_WIDTH;
614 nItemWidth = DEFAULT_LABEL_WIDTH;
619 nItemWidth += WIDTH_PADDING;
621 if (infoPtr->himlSmall != NULL)
623 nItemWidth += infoPtr->iconSize.cx;
626 if (infoPtr->himlState != NULL)
628 nItemWidth += infoPtr->iconSize.cx;
635 /* nItemWidth Cannot be Zero */
643 * Calculates the width of a specific item.
646 * [I] HWND : window handle
650 * Returns the width of an item width a specified string.
652 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
654 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
655 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
656 INT nHeaderItemCount;
661 TRACE("(hwnd=%x)\n", hwnd);
663 if (uView == LVS_ICON)
665 nItemWidth = infoPtr->iconSpacing.cx;
667 else if (uView == LVS_REPORT)
669 /* calculate width of header */
670 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
671 for (i = 0; i < nHeaderItemCount; i++)
673 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
675 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
681 /* get width of string */
682 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
684 /* default label size */
685 if (GETITEMCOUNT(infoPtr) == 0)
687 nItemWidth = DEFAULT_COLUMN_WIDTH;
693 nItemWidth = DEFAULT_LABEL_WIDTH;
698 nItemWidth += WIDTH_PADDING;
700 if (infoPtr->himlSmall != NULL)
702 nItemWidth += infoPtr->iconSize.cx;
705 if (infoPtr->himlState != NULL)
707 nItemWidth += infoPtr->iconSize.cx;
718 * Calculates the height of an item.
721 * [I] HWND : window handle
722 * [I] LONG : window style
725 * Returns item height.
727 static INT LISTVIEW_GetItemHeight(HWND hwnd)
729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
730 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
733 if (uView == LVS_ICON)
735 nItemHeight = infoPtr->iconSpacing.cy;
740 HDC hdc = GetDC(hwnd);
741 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
742 GetTextMetricsA(hdc, &tm);
743 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
744 SelectObject(hdc, hOldFont);
745 ReleaseDC(hwnd, hdc);
753 * Adds a block of selections.
756 * [I] HWND : window handle
757 * [I] INT : item index
762 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
764 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
765 INT nFirst = min(infoPtr->nSelectionMark, nItem);
766 INT nLast = max(infoPtr->nSelectionMark, nItem);
770 lvItem.state = LVIS_SELECTED;
771 lvItem.stateMask= LVIS_SELECTED;
773 for (i = nFirst; i <= nLast; i++)
775 ListView_SetItemState(hwnd, i, &lvItem);
778 LISTVIEW_SetItemFocus(hwnd, nItem);
779 infoPtr->nSelectionMark = nItem;
784 * Adds a single selection.
787 * [I] HWND : window handle
788 * [I] INT : item index
793 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
795 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
798 lvItem.state = LVIS_SELECTED;
799 lvItem.stateMask= LVIS_SELECTED;
801 ListView_SetItemState(hwnd, nItem, &lvItem);
803 LISTVIEW_SetItemFocus(hwnd, nItem);
804 infoPtr->nSelectionMark = nItem;
809 * Selects or unselects an item.
812 * [I] HWND : window handle
813 * [I] INT : item index
819 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
821 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
825 lvItem.stateMask= LVIS_SELECTED;
827 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
830 ListView_SetItemState(hwnd, nItem, &lvItem);
835 lvItem.state = LVIS_SELECTED;
836 ListView_SetItemState(hwnd, nItem, &lvItem);
840 LISTVIEW_SetItemFocus(hwnd, nItem);
841 infoPtr->nSelectionMark = nItem;
848 * Selects items based on view coorddiantes.
851 * [I] HWND : window handle
852 * [I] RECT : selection rectangle
857 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
864 lvItem.stateMask = LVIS_SELECTED;
866 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
868 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
869 if (PtInRect(&rcSelRect, ptItem) != FALSE)
871 lvItem.state = LVIS_SELECTED;
878 ListView_SetItemState(hwnd, i, &lvItem);
884 * Sets a single group selection.
887 * [I] HWND : window handle
888 * [I] INT : item index
893 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
895 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
896 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
899 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
902 INT nFirst = min(infoPtr->nSelectionMark, nItem);
903 INT nLast = max(infoPtr->nSelectionMark, nItem);
904 lvItem.stateMask = LVIS_SELECTED;
906 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
908 if ((i < nFirst) || (i > nLast))
914 lvItem.state = LVIS_SELECTED;
917 ListView_SetItemState(hwnd, i, &lvItem);
925 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
926 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
927 rcSel.left = min(ptSelMark.x, ptItem.x);
928 rcSel.top = min(ptSelMark.y, ptItem.y);
929 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
930 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
931 LISTVIEW_SetSelectionRect(hwnd, rcSel);
934 LISTVIEW_SetItemFocus(hwnd, nItem);
939 * Manages the item focus.
942 * [I] HWND : window handle
943 * [I] INT : item index
946 * TRUE : focused item changed
947 * FALSE : focused item has NOT changed
949 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
951 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
952 BOOL bResult = FALSE;
955 if (infoPtr->nFocusedItem != nItem)
958 ZeroMemory(&lvItem, sizeof(LVITEMA));
959 lvItem.stateMask = LVIS_FOCUSED;
960 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
962 lvItem.state = LVIS_FOCUSED;
963 lvItem.stateMask = LVIS_FOCUSED;
964 ListView_SetItemState(hwnd, nItem, &lvItem);
966 infoPtr->nFocusedItem = nItem;
967 ListView_EnsureVisible(hwnd, nItem, FALSE);
975 * Sets a single selection.
978 * [I] HWND : window handle
979 * [I] INT : item index
984 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
986 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
991 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
994 if (nItem < GETITEMCOUNT(infoPtr))
996 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
999 ZeroMemory(&lvItem, sizeof(LVITEMA));
1000 lvItem.stateMask = LVIS_FOCUSED;
1001 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1003 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
1004 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1005 ListView_SetItemState(hwnd, nItem, &lvItem);
1007 infoPtr->nFocusedItem = nItem;
1008 infoPtr->nSelectionMark = nItem;
1013 * Set selection(s) with keyboard.
1016 * [I] HWND : window handle
1017 * [I] INT : item index
1020 * SUCCESS : TRUE (needs to be repainted)
1021 * FAILURE : FALSE (nothing has changed)
1023 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1025 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1026 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1027 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1028 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1029 BOOL bResult = FALSE;
1031 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1033 if (lStyle & LVS_SINGLESEL)
1036 LISTVIEW_SetSelection(hwnd, nItem);
1037 ListView_EnsureVisible(hwnd, nItem, FALSE);
1044 LISTVIEW_SetGroupSelection(hwnd, nItem);
1048 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1053 LISTVIEW_SetSelection(hwnd, nItem);
1054 ListView_EnsureVisible(hwnd, nItem, FALSE);
1064 * Selects an item based on coordinates.
1067 * [I] HWND : window handle
1068 * [I] POINT : mouse click ccordinates
1071 * SUCCESS : item index
1074 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1076 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1080 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1082 rcItem.left = LVIR_SELECTBOUNDS;
1083 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1085 if (PtInRect(&rcItem, pt) != FALSE)
1097 * Removes all selection states.
1100 * [I] HWND : window handle
1101 * [I] INT : item index
1107 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1113 lvItem.stateMask = LVIS_SELECTED;
1115 for (i = nFirst; i <= nLast; i++)
1117 ListView_SetItemState(hwnd, i, &lvItem);
1126 * [IO] HDPA : dynamic pointer array handle
1127 * [I] INT : column index (subitem index)
1133 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1135 BOOL bResult = TRUE;
1139 for (i = 0; i < hdpaItems->nItemCount; i++)
1141 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1142 if (hdpaSubItems != NULL)
1144 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1156 * Removes a subitem at a given position.
1159 * [IO] HDPA : dynamic pointer array handle
1160 * [I] INT : subitem index
1166 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1168 LISTVIEW_SUBITEM *lpSubItem;
1171 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1173 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1174 if (lpSubItem != NULL)
1176 if (lpSubItem->iSubItem == nSubItem)
1179 if ((lpSubItem->pszText != NULL) &&
1180 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1182 COMCTL32_Free(lpSubItem->pszText);
1186 COMCTL32_Free(lpSubItem);
1188 /* free dpa memory */
1189 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1194 else if (lpSubItem->iSubItem > nSubItem)
1206 * Compares the item information.
1209 * [I] LISTVIEW_ITEM *: destination item
1210 * [I] LPLVITEM : source item
1213 * SUCCCESS : TRUE (EQUAL)
1214 * FAILURE : FALSE (NOT EQUAL)
1216 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1220 if ((lpItem != NULL) && (lpLVItem != NULL))
1222 if (lpLVItem->mask & LVIF_STATE)
1224 if ((lpItem->state & lpLVItem->stateMask) !=
1225 (lpLVItem->state & lpLVItem->stateMask))
1227 uChanged |= LVIF_STATE;
1231 if (lpLVItem->mask & LVIF_IMAGE)
1233 if (lpItem->iImage != lpLVItem->iImage)
1235 uChanged |= LVIF_IMAGE;
1239 if (lpLVItem->mask & LVIF_PARAM)
1241 if (lpItem->lParam != lpLVItem->lParam)
1243 uChanged |= LVIF_PARAM;
1247 if (lpLVItem->mask & LVIF_INDENT)
1249 if (lpItem->iIndent != lpLVItem->iIndent)
1251 uChanged |= LVIF_INDENT;
1255 if (lpLVItem->mask & LVIF_TEXT)
1257 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1259 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1261 uChanged |= LVIF_TEXT;
1266 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1268 uChanged |= LVIF_TEXT;
1272 if (lpLVItem->pszText)
1274 if (lpItem->pszText)
1276 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1278 uChanged |= LVIF_TEXT;
1283 uChanged |= LVIF_TEXT;
1288 if (lpItem->pszText)
1290 uChanged |= LVIF_TEXT;
1302 * Initializes item attributes.
1305 * [I] HWND : window handle
1306 * [O] LISTVIEW_ITEM *: destination item
1307 * [I] LPLVITEM : source item
1313 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1316 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1317 BOOL bResult = FALSE;
1319 if ((lpItem != NULL) && (lpLVItem != NULL))
1323 if (lpLVItem->mask & LVIF_STATE)
1325 lpItem->state &= ~lpLVItem->stateMask;
1326 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1329 if (lpLVItem->mask & LVIF_IMAGE)
1331 lpItem->iImage = lpLVItem->iImage;
1334 if (lpLVItem->mask & LVIF_PARAM)
1336 lpItem->lParam = lpLVItem->lParam;
1339 if (lpLVItem->mask & LVIF_INDENT)
1341 lpItem->iIndent = lpLVItem->iIndent;
1344 if (lpLVItem->mask & LVIF_TEXT)
1346 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1348 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1353 if ((lpItem->pszText != NULL) &&
1354 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1356 COMCTL32_Free(lpItem->pszText);
1359 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1363 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1365 lpItem->pszText = NULL;
1368 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1378 * Initializes subitem attributes.
1380 * NOTE: The documentation specifies that the operation fails if the user
1381 * tries to set the indent of a subitem.
1384 * [I] HWND : window handle
1385 * [O] LISTVIEW_SUBITEM *: destination subitem
1386 * [I] LPLVITEM : source subitem
1392 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1395 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1396 BOOL bResult = FALSE;
1398 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1400 if (!(lpLVItem->mask & LVIF_INDENT))
1403 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1405 lpSubItem->iSubItem = lpLVItem->iSubItem;
1407 if (lpLVItem->mask & LVIF_IMAGE)
1409 lpSubItem->iImage = lpLVItem->iImage;
1412 if (lpLVItem->mask & LVIF_TEXT)
1414 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1416 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1421 if ((lpSubItem->pszText != NULL) &&
1422 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1424 COMCTL32_Free(lpSubItem->pszText);
1427 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1431 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1433 lpSubItem->pszText = NULL;
1436 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1447 * Adds a subitem at a given position (column index).
1450 * [I] HWND : window handle
1451 * [I] LPLVITEM : new subitem atttributes
1457 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1459 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1460 LISTVIEW_SUBITEM *lpSubItem = NULL;
1461 BOOL bResult = FALSE;
1463 INT nPosition, nItem;
1465 if (lpLVItem != NULL)
1467 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1468 if (hdpaSubItems != NULL)
1470 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1471 if (lpSubItem != NULL)
1473 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1475 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1476 lpSubItem->iSubItem);
1477 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1487 /* cleanup if unsuccessful */
1488 if ((bResult == FALSE) && (lpSubItem != NULL))
1490 COMCTL32_Free(lpSubItem);
1498 * Finds the dpa insert position (array index).
1501 * [I] HWND : window handle
1502 * [I] INT : subitem index
1508 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1510 LISTVIEW_SUBITEM *lpSubItem;
1513 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1515 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1516 if (lpSubItem != NULL)
1518 if (lpSubItem->iSubItem > nSubItem)
1525 return hdpaSubItems->nItemCount;
1530 * Retrieves a listview subitem at a given position (column index).
1533 * [I] HWND : window handle
1534 * [I] INT : subitem index
1540 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1542 LISTVIEW_SUBITEM *lpSubItem;
1545 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1547 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1548 if (lpSubItem != NULL)
1550 if (lpSubItem->iSubItem == nSubItem)
1554 else if (lpSubItem->iSubItem > nSubItem)
1566 * Sets item attributes.
1569 * [I] HWND : window handle
1570 * [I] LPLVITEM : new item atttributes
1576 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1578 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1579 BOOL bResult = FALSE;
1581 LISTVIEW_ITEM *lpItem;
1584 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1586 if (lpLVItem != NULL)
1588 if (lpLVItem->iSubItem == 0)
1590 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1591 if (hdpaSubItems != NULL)
1593 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1596 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1597 nmlv.hdr.hwndFrom = hwnd;
1598 nmlv.hdr.idFrom = lCtrlId;
1599 nmlv.hdr.code = LVN_ITEMCHANGING;
1600 nmlv.lParam = lpItem->lParam;
1601 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1604 if (uChanged & LVIF_STATE)
1606 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1607 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1610 nmlv.uChanged = uChanged;
1611 nmlv.iItem = lpLVItem->iItem;
1612 nmlv.lParam = lpItem->lParam;
1613 /* send LVN_ITEMCHANGING notification */
1614 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1616 /* copy information */
1617 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1619 /* send LVN_ITEMCHANGED notification */
1620 nmlv.hdr.code = LVN_ITEMCHANGED;
1621 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1628 InvalidateRect(hwnd, NULL, FALSE);
1639 * Sets subitem attributes.
1642 * [I] HWND : window handle
1643 * [I] LPLVITEM : new subitem atttributes
1649 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1651 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1652 BOOL bResult = FALSE;
1654 LISTVIEW_SUBITEM *lpSubItem;
1656 if (lpLVItem != NULL)
1658 if (lpLVItem->iSubItem > 0)
1660 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1661 if (hdpaSubItems != NULL)
1663 /* set subitem only if column is present */
1664 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1666 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1667 if (lpSubItem != NULL)
1669 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1673 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1676 InvalidateRect(hwnd, NULL, FALSE);
1687 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1690 * [I] HWND : window handle
1695 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1697 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1698 UINT uView = lStyle & LVS_TYPEMASK;
1700 SCROLLINFO scrollInfo;
1702 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1703 scrollInfo.cbSize = sizeof(SCROLLINFO);
1704 scrollInfo.fMask = SIF_POS;
1706 if (uView == LVS_LIST)
1708 if (lStyle & WS_HSCROLL)
1710 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1712 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1716 else if (uView == LVS_REPORT)
1718 if (lStyle & WS_VSCROLL)
1720 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1722 nItem = scrollInfo.nPos;
1735 * [I] HWND : window handle
1736 * [I] HDC : device context handle
1737 * [I] INT : item index
1738 * [I] INT : subitem index
1739 * [I] RECT * : clipping rectangle
1744 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1747 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1748 CHAR szDispText[DISP_TEXT_SIZE];
1751 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
1754 /* get information needed for drawing the item */
1755 ZeroMemory(&lvItem, sizeof(LVITEMA));
1756 lvItem.mask = LVIF_TEXT;
1757 lvItem.iItem = nItem;
1758 lvItem.iSubItem = nSubItem;
1759 lvItem.cchTextMax = DISP_TEXT_SIZE;
1760 lvItem.pszText = szDispText;
1761 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1763 /* set item colors */
1764 SetBkColor(hdc, infoPtr->clrTextBk);
1765 SetTextColor(hdc, infoPtr->clrText);
1767 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1768 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1777 * [I] HWND : window handle
1778 * [I] HDC : device context handle
1779 * [I] INT : item index
1780 * [I] RECT * : clipping rectangle
1785 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1787 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1788 CHAR szDispText[DISP_TEXT_SIZE];
1795 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
1797 /* get information needed for drawing the item */
1798 ZeroMemory(&lvItem, sizeof(LVITEMA));
1799 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1800 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1801 lvItem.iItem = nItem;
1802 lvItem.iSubItem = 0;
1803 lvItem.cchTextMax = DISP_TEXT_SIZE;
1804 lvItem.pszText = szDispText;
1805 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1808 if (infoPtr->himlState != NULL)
1810 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1811 if (uStateImage != 0)
1813 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1814 rcItem.top, ILD_NORMAL);
1817 rcItem.left += infoPtr->iconSize.cx;
1821 if (infoPtr->himlSmall != NULL)
1823 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1825 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1826 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1827 rcItem.top, ILD_SELECTED);
1831 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1832 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1833 rcItem.top, ILD_NORMAL);
1836 rcItem.left += infoPtr->iconSize.cx;
1839 /* Don't bother painting item being edited */
1840 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1843 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1845 /* set item colors */
1846 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1847 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1848 /* set raster mode */
1849 nMixMode = SetROP2(hdc, R2_XORPEN);
1851 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1852 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1854 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1855 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1856 /* set raster mode */
1857 nMixMode = SetROP2(hdc, R2_COPYPEN);
1861 /* set item colors */
1862 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1863 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1864 /* set raster mode */
1865 nMixMode = SetROP2(hdc, R2_COPYPEN);
1868 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1869 if (rcItem.left + nLabelWidth < rcItem.right)
1871 rcItem.right = rcItem.left + nLabelWidth;
1875 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1876 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1878 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1880 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1885 SetROP2(hdc, R2_COPYPEN);
1886 SetBkColor(hdc, infoPtr->clrTextBk);
1887 SetTextColor(hdc, infoPtr->clrText);
1893 * Draws an item when in large icon display mode.
1896 * [I] HWND : window handle
1897 * [I] HDC : device context handle
1898 * [I] LISTVIEW_ITEM * : item
1899 * [I] INT : item index
1900 * [I] RECT * : clipping rectangle
1905 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1907 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1908 CHAR szDispText[DISP_TEXT_SIZE];
1909 INT nDrawPosX = rcItem.left;
1914 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1915 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1918 /* get information needed for drawing the item */
1919 ZeroMemory(&lvItem, sizeof(LVITEMA));
1920 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1921 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1922 lvItem.iItem = nItem;
1923 lvItem.iSubItem = 0;
1924 lvItem.cchTextMax = DISP_TEXT_SIZE;
1925 lvItem.pszText = szDispText;
1926 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1928 if (lvItem.state & LVIS_SELECTED)
1930 /* set item colors */
1931 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1932 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1933 /* set raster mode */
1934 SetROP2(hdc, R2_XORPEN);
1938 /* set item colors */
1939 SetBkColor(hdc, infoPtr->clrTextBk);
1940 SetTextColor(hdc, infoPtr->clrText);
1941 /* set raster mode */
1942 SetROP2(hdc, R2_COPYPEN);
1945 if (infoPtr->himlNormal != NULL)
1947 rcItem.top += ICON_TOP_PADDING;
1948 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
1949 if (lvItem.state & LVIS_SELECTED)
1951 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1952 rcItem.top, ILD_SELECTED);
1956 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1957 rcItem.top, ILD_NORMAL);
1961 /* Don't bother painting item being edited */
1962 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1965 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
1966 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1967 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
1970 rcItem.left += nDrawPosX / 2;
1971 rcItem.right = rcItem.left + nLabelWidth;
1976 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
1980 GetTextMetricsA(hdc, &tm);
1981 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
1982 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1983 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1985 if (lvItem.state & LVIS_FOCUSED)
1987 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1993 * Draws listview items when in report display mode.
1996 * [I] HWND : window handle
1997 * [I] HDC : device context handle
2002 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2004 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2005 SCROLLINFO scrollInfo;
2006 INT nDrawPosY = infoPtr->rcList.top;
2013 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2014 scrollInfo.cbSize = sizeof(SCROLLINFO);
2015 scrollInfo.fMask = SIF_POS;
2017 nItem = ListView_GetTopIndex(hwnd);
2019 /* add 1 for displaying a partial item at the bottom */
2020 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2021 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2023 /* send cache hint notification */
2024 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
2028 nmlv.hdr.hwndFrom = hwnd;
2029 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
2030 nmlv.hdr.code = LVN_ODCACHEHINT;
2034 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
2038 for (; nItem < nLast; nItem++)
2040 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2041 for (j = 0; j < nColumnCount; j++)
2043 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2044 rcItem.left += REPORT_MARGINX;
2045 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2046 rcItem.top = nDrawPosY;
2047 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2049 /* Offset the Scroll Bar Pos */
2050 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2052 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2053 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2058 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2062 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2066 nDrawPosY += infoPtr->nItemHeight;
2072 * Retrieves the number of items that can fit vertically in the client area.
2075 * [I] HWND : window handle
2078 * Number of items per row.
2080 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2082 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2083 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2084 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2085 INT nCountPerRow = 1;
2089 if (uView == LVS_REPORT)
2095 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2096 if (nCountPerRow == 0)
2103 return nCountPerRow;
2108 * Retrieves the number of items that can fit horizontally in the client
2112 * [I] HWND : window handle
2115 * Number of items per column.
2117 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2119 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2120 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2121 INT nCountPerColumn = 1;
2123 if (nListHeight > 0)
2125 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2126 if (nCountPerColumn == 0)
2128 nCountPerColumn = 1;
2132 return nCountPerColumn;
2137 * Retrieves the number of columns needed to display all the items when in
2138 * list display mode.
2141 * [I] HWND : window handle
2144 * Number of columns.
2146 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2148 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2149 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2150 INT nColumnCount = 0;
2152 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2154 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2156 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2160 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2164 return nColumnCount;
2170 * Draws listview items when in list display mode.
2173 * [I] HWND : window handle
2174 * [I] HDC : device context handle
2179 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2181 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2186 INT nCountPerColumn;
2187 INT nItemWidth = infoPtr->nItemWidth;
2188 INT nItemHeight = infoPtr->nItemHeight;
2190 /* get number of fully visible columns */
2191 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2192 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2193 nItem = ListView_GetTopIndex(hwnd);
2195 for (i = 0; i < nColumnCount; i++)
2197 for (j = 0; j < nCountPerColumn; j++, nItem++)
2199 if (nItem >= GETITEMCOUNT(infoPtr))
2202 rcItem.top = j * nItemHeight;
2203 rcItem.left = i * nItemWidth;
2204 rcItem.bottom = rcItem.top + nItemHeight;
2205 rcItem.right = rcItem.left + nItemWidth;
2206 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2213 * Draws listview items when in icon or small icon display mode.
2216 * [I] HWND : window handle
2217 * [I] HDC : device context handle
2222 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2224 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2230 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2231 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2233 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2234 ptPosition.x += ptOrigin.x;
2235 ptPosition.y += ptOrigin.y;
2237 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2239 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2241 if (ptPosition.y < infoPtr->rcList.bottom)
2243 if (ptPosition.x < infoPtr->rcList.right)
2245 rcItem.top = ptPosition.y;
2246 rcItem.left = ptPosition.x;
2247 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2248 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2249 if (bSmall == FALSE)
2251 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2255 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2266 * Draws listview items.
2269 * [I] HWND : window handle
2270 * [I] HDC : device context handle
2275 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2277 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2278 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2283 hOldFont = SelectObject(hdc, infoPtr->hFont);
2285 /* select the doted pen (for drawing the focus box) */
2286 hPen = CreatePen(PS_DOT, 1, 0);
2287 hOldPen = SelectObject(hdc, hPen);
2289 /* select transparent brush (for drawing the focus box) */
2290 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2292 if (uView == LVS_LIST)
2294 LISTVIEW_RefreshList(hwnd, hdc);
2296 else if (uView == LVS_REPORT)
2298 LISTVIEW_RefreshReport(hwnd, hdc);
2300 else if (uView == LVS_SMALLICON)
2302 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2304 else if (uView == LVS_ICON)
2306 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2309 /* unselect objects */
2310 SelectObject(hdc, hOldFont);
2311 SelectObject(hdc, hOldPen);
2320 * Calculates the approximate width and height of a given number of items.
2323 * [I] HWND : window handle
2324 * [I] INT : number of items
2329 * Returns a DWORD. The width in the low word and the height in high word.
2331 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2332 WORD wWidth, WORD wHeight)
2334 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2335 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2336 INT nItemCountPerColumn = 1;
2337 INT nColumnCount = 0;
2338 DWORD dwViewRect = 0;
2340 if (nItemCount == -1)
2342 nItemCount = GETITEMCOUNT(infoPtr);
2345 if (uView == LVS_LIST)
2347 if (wHeight == 0xFFFF)
2349 /* use current height */
2350 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2353 if (wHeight < infoPtr->nItemHeight)
2355 wHeight = infoPtr->nItemHeight;
2360 if (infoPtr->nItemHeight > 0)
2362 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2363 if (nItemCountPerColumn == 0)
2365 nItemCountPerColumn = 1;
2368 if (nItemCount % nItemCountPerColumn != 0)
2370 nColumnCount = nItemCount / nItemCountPerColumn;
2374 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2379 /* Microsoft padding magic */
2380 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2381 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2383 dwViewRect = MAKELONG(wWidth, wHeight);
2385 else if (uView == LVS_REPORT)
2389 else if (uView == LVS_SMALLICON)
2393 else if (uView == LVS_ICON)
2403 * Arranges listview items in icon display mode.
2406 * [I] HWND : window handle
2407 * [I] INT : alignment code
2413 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2415 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2416 BOOL bResult = FALSE;
2418 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2431 case LVA_SNAPTOGRID:
2440 /* << LISTVIEW_CreateDragImage >> */
2444 * Removes all listview items and subitems.
2447 * [I] HWND : window handle
2453 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2455 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2456 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2457 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2458 UINT uView = lStyle & LVS_TYPEMASK;
2459 LISTVIEW_ITEM *lpItem;
2460 LISTVIEW_SUBITEM *lpSubItem;
2463 BOOL bResult = FALSE;
2468 TRACE("(hwnd=%x,)\n", hwnd);
2470 if (GETITEMCOUNT(infoPtr) > 0)
2472 /* initialize memory */
2473 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2475 /* send LVN_DELETEALLITEMS notification */
2476 nmlv.hdr.hwndFrom = hwnd;
2477 nmlv.hdr.idFrom = lCtrlId;
2478 nmlv.hdr.code = LVN_DELETEALLITEMS;
2481 /* verify if subsequent LVN_DELETEITEM notifications should be
2483 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2485 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2487 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2488 if (hdpaSubItems != NULL)
2490 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2492 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2493 if (lpSubItem != NULL)
2495 /* free subitem string */
2496 if ((lpSubItem->pszText != NULL) &&
2497 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2499 COMCTL32_Free(lpSubItem->pszText);
2503 COMCTL32_Free(lpSubItem);
2507 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2510 if (bSuppress == FALSE)
2512 /* send LVN_DELETEITEM notification */
2513 nmlv.hdr.code = LVN_DELETEITEM;
2515 nmlv.lParam = lpItem->lParam;
2516 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2519 /* free item string */
2520 if ((lpItem->pszText != NULL) &&
2521 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2523 COMCTL32_Free(lpItem->pszText);
2527 COMCTL32_Free(lpItem);
2530 DPA_Destroy(hdpaSubItems);
2534 /* reinitialize listview memory */
2535 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2537 /* align items (set position of each item) */
2538 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2540 if (lStyle & LVS_ALIGNLEFT)
2542 LISTVIEW_AlignLeft(hwnd);
2546 LISTVIEW_AlignTop(hwnd);
2550 LISTVIEW_UpdateScroll(hwnd);
2552 /* invalidate client area (optimization needed) */
2553 InvalidateRect(hwnd, NULL, TRUE);
2561 * Removes a column from the listview control.
2564 * [I] HWND : window handle
2565 * [I] INT : column index
2571 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2573 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2574 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2575 BOOL bResult = FALSE;
2577 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2579 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2581 /* Need to reset the item width when deleting a column */
2582 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2584 /* reset scroll parameters */
2585 if (uView == LVS_REPORT)
2587 /* update scrollbar(s) */
2588 LISTVIEW_UpdateScroll(hwnd);
2590 /* refresh client area */
2591 InvalidateRect(hwnd, NULL, FALSE);
2600 * Removes an item from the listview control.
2603 * [I] HWND : window handle
2604 * [I] INT : item index
2610 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2612 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2613 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2614 UINT uView = lStyle & LVS_TYPEMASK;
2615 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2617 BOOL bResult = FALSE;
2619 LISTVIEW_ITEM *lpItem;
2620 LISTVIEW_SUBITEM *lpSubItem;
2623 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2625 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2627 /* initialize memory */
2628 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2630 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2631 if (hdpaSubItems != NULL)
2633 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2635 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2636 if (lpSubItem != NULL)
2638 /* free item string */
2639 if ((lpSubItem->pszText != NULL) &&
2640 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2642 COMCTL32_Free(lpSubItem->pszText);
2646 COMCTL32_Free(lpSubItem);
2650 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2653 /* send LVN_DELETEITEM notification */
2654 nmlv.hdr.hwndFrom = hwnd;
2655 nmlv.hdr.idFrom = lCtrlId;
2656 nmlv.hdr.code = LVN_DELETEITEM;
2658 nmlv.lParam = lpItem->lParam;
2659 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2662 /* free item string */
2663 if ((lpItem->pszText != NULL) &&
2664 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2666 COMCTL32_Free(lpItem->pszText);
2670 COMCTL32_Free(lpItem);
2673 bResult = DPA_Destroy(hdpaSubItems);
2676 /* align items (set position of each item) */
2677 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2679 if (lStyle & LVS_ALIGNLEFT)
2681 LISTVIEW_AlignLeft(hwnd);
2685 LISTVIEW_AlignTop(hwnd);
2689 /* If this item had focus change focus to next or previous item */
2690 if (GETITEMCOUNT(infoPtr) > 0)
2692 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
2693 if (infoPtr->nFocusedItem == nItem)
2694 LISTVIEW_SetItemFocus(hwnd, sItem);
2697 infoPtr->nFocusedItem = -1;
2699 LISTVIEW_UpdateScroll(hwnd);
2701 /* refresh client area */
2702 InvalidateRect(hwnd, NULL, TRUE);
2711 * Return edit control handle of current edit label
2714 * [I] HWND : window handle
2720 static LRESULT LISTVIEW_GetEditControl(hwnd)
2722 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2723 return infoPtr->hwndEdit;
2729 * Callback implementation for editlabel control
2732 * [I] HWND : window handle
2733 * [I] LPSTR : modified text
2734 * [I] DWORD : item index
2741 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
2743 NMLVDISPINFOA dispInfo;
2744 LISTVIEW_ITEM *lpItem;
2745 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2746 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2748 BOOL bUpdateItemText;
2750 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2752 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2755 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2758 dispInfo.hdr.hwndFrom = hwnd;
2759 dispInfo.hdr.idFrom = nCtrlId;
2760 dispInfo.hdr.code = LVN_ENDLABELEDITA;
2761 dispInfo.item.mask = 0;
2762 dispInfo.item.iItem = nItem;
2763 dispInfo.item.state = lpItem->state;
2764 dispInfo.item.stateMask = 0;
2765 dispInfo.item.pszText = pszText;
2766 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
2767 dispInfo.item.iImage = lpItem->iImage;
2768 dispInfo.item.lParam = lpItem->lParam;
2769 infoPtr->hwndEdit = 0;
2771 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
2773 /* Do we need to update the Item Text */
2776 if(lpItem->pszText != LPSTR_TEXTCALLBACKA)
2778 Str_SetPtrA(&lpItem->pszText, pszText);
2787 * Begin in place editing of specified list view item
2790 * [I] HWND : window handle
2791 * [I] INT : item index
2798 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
2800 NMLVDISPINFOA dispInfo;
2802 LISTVIEW_ITEM *lpItem;
2804 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
2805 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2806 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2808 CHAR szDispText[DISP_TEXT_SIZE];
2811 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
2814 /* Is the EditBox still there, if so remove it */
2815 if(infoPtr->hwndEdit != 0)
2820 LISTVIEW_SetSelection(hwnd, nItem);
2821 LISTVIEW_SetItemFocus(hwnd, nItem);
2823 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2824 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2827 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2831 /* get information needed for drawing the item */
2832 ZeroMemory(&lvItem, sizeof(LVITEMA));
2833 lvItem.mask = LVIF_TEXT;
2834 lvItem.iItem = nItem;
2835 lvItem.iSubItem = 0;
2836 lvItem.cchTextMax = DISP_TEXT_SIZE;
2837 lvItem.pszText = szDispText;
2838 ListView_GetItemA(hwnd, &lvItem);
2840 dispInfo.hdr.hwndFrom = hwnd;
2841 dispInfo.hdr.idFrom = nCtrlId;
2842 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
2843 dispInfo.item.mask = 0;
2844 dispInfo.item.iItem = nItem;
2845 dispInfo.item.state = lpItem->state;
2846 dispInfo.item.stateMask = 0;
2847 dispInfo.item.pszText = lvItem.pszText;
2848 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
2849 dispInfo.item.iImage = lpItem->iImage;
2850 dispInfo.item.lParam = lpItem->lParam;
2852 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
2855 rect.left = LVIR_LABEL;
2856 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
2859 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
2860 rect.left-2, rect.top-1, 0,
2861 rect.bottom - rect.top+2,
2862 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
2865 infoPtr->hwndEdit = hedit;
2867 SendMessageA(hedit, EM_SETSEL, 0, -1);
2875 * Ensures the specified item is visible, scrolling into view if necessary.
2878 * [I] HWND : window handle
2879 * [I] INT : item index
2880 * [I] BOOL : partially or entirely visible
2886 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2888 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2889 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2890 INT nScrollPosHeight = 0;
2891 INT nScrollPosWidth = 0;
2892 SCROLLINFO scrollInfo;
2895 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2896 scrollInfo.cbSize = sizeof(SCROLLINFO);
2897 scrollInfo.fMask = SIF_POS;
2899 /* ALWAYS bPartial == FALSE, FOR NOW! */
2901 rcItem.left = LVIR_BOUNDS;
2902 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2904 if (rcItem.left < infoPtr->rcList.left)
2906 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2909 if (uView == LVS_LIST)
2911 nScrollPosWidth = infoPtr->nItemWidth;
2912 rcItem.left += infoPtr->rcList.left;
2914 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2916 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
2917 rcItem.left += infoPtr->rcList.left;
2920 /* When in LVS_REPORT view, the scroll position should
2922 if (nScrollPosWidth != 0)
2924 if (rcItem.left % nScrollPosWidth == 0)
2926 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
2930 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
2933 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2937 else if (rcItem.right > infoPtr->rcList.right)
2939 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2942 if (uView == LVS_LIST)
2944 rcItem.right -= infoPtr->rcList.right;
2945 nScrollPosWidth = infoPtr->nItemWidth;
2947 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2949 rcItem.right -= infoPtr->rcList.right;
2950 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
2953 /* When in LVS_REPORT view, the scroll position should
2955 if (nScrollPosWidth != 0)
2957 if (rcItem.right % nScrollPosWidth == 0)
2959 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
2963 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
2966 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2971 if (rcItem.top < infoPtr->rcList.top)
2974 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2976 if (uView == LVS_REPORT)
2978 rcItem.top -= infoPtr->rcList.top;
2979 nScrollPosHeight = infoPtr->nItemHeight;
2981 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2983 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
2984 rcItem.top += infoPtr->rcList.top;
2987 if (rcItem.top % nScrollPosHeight == 0)
2989 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
2993 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
2996 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2999 else if (rcItem.bottom > infoPtr->rcList.bottom)
3002 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3004 if (uView == LVS_REPORT)
3006 rcItem.bottom -= infoPtr->rcList.bottom;
3007 nScrollPosHeight = infoPtr->nItemHeight;
3009 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3011 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3012 rcItem.bottom -= infoPtr->rcList.bottom;
3015 if (rcItem.bottom % nScrollPosHeight == 0)
3017 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
3021 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
3024 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3034 * Retrieves the nearest item, given a position and a direction.
3037 * [I] HWND : window handle
3038 * [I] POINT : start position
3039 * [I] UINT : direction
3042 * Item index if successdful, -1 otherwise.
3044 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3046 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3047 LVHITTESTINFO lvHitTestInfo;
3051 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3053 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3054 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3055 lvHitTestInfo.pt.x += pt.x;
3056 lvHitTestInfo.pt.y += pt.y;
3060 if (vkDirection == VK_DOWN)
3062 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3064 else if (vkDirection == VK_UP)
3066 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3068 else if (vkDirection == VK_LEFT)
3070 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3072 else if (vkDirection == VK_RIGHT)
3074 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3077 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3083 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3087 while (nItem == -1);
3095 * Searches for an item with specific characteristics.
3098 * [I] HWND : window handle
3099 * [I] INT : base item index
3100 * [I] LPLVFINDINFO : item information to look for
3103 * SUCCESS : index of item
3106 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3107 LPLVFINDINFO lpFindInfo)
3109 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3111 CHAR szDispText[DISP_TEXT_SIZE];
3115 INT nLast = GETITEMCOUNT(infoPtr);
3117 if ((nItem >= -1) && (lpFindInfo != NULL))
3119 ZeroMemory(&lvItem, sizeof(LVITEMA));
3121 if (lpFindInfo->flags & LVFI_PARAM)
3123 lvItem.mask |= LVIF_PARAM;
3126 if (lpFindInfo->flags & LVFI_STRING)
3128 lvItem.mask |= LVIF_TEXT;
3129 lvItem.pszText = szDispText;
3130 lvItem.cchTextMax = DISP_TEXT_SIZE;
3133 if (lpFindInfo->flags & LVFI_PARTIAL)
3135 lvItem.mask |= LVIF_TEXT;
3136 lvItem.pszText = szDispText;
3137 lvItem.cchTextMax = DISP_TEXT_SIZE;
3140 if (lpFindInfo->flags & LVFI_WRAP)
3145 if (lpFindInfo->flags & LVFI_NEARESTXY)
3147 ptItem.x = lpFindInfo->pt.x;
3148 ptItem.y = lpFindInfo->pt.y;
3153 while (nItem < nLast)
3155 if (lpFindInfo->flags & LVFI_NEARESTXY)
3157 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3158 lpFindInfo->vkDirection);
3161 /* get position of the new item index */
3162 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3173 lvItem.iItem = nItem;
3174 lvItem.iSubItem = 0;
3175 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
3177 if (lvItem.mask & LVIF_TEXT)
3179 if (lpFindInfo->flags & LVFI_PARTIAL)
3181 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3186 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3191 if (lvItem.mask & LVIF_PARAM)
3193 if (lpFindInfo->lParam != lvItem.lParam)
3219 * Retrieves the background color of the listview control.
3222 * [I] HWND : window handle
3225 * COLORREF associated with the background.
3227 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3229 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3231 return infoPtr->clrBk;
3236 * Retrieves the background image of the listview control.
3239 * [I] HWND : window handle
3240 * [O] LPLVMKBIMAGE : background image attributes
3246 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3248 /* FIXME (listview, "empty stub!\n"); */
3254 * Retrieves the callback mask.
3257 * [I] HWND : window handle
3262 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3264 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3266 return infoPtr->uCallbackMask;
3271 * Retrieves column attributes.
3274 * [I] HWND : window handle
3275 * [I] INT : column index
3276 * [IO] LPLVCOLUMNA : column information
3282 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3284 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3286 BOOL bResult = FALSE;
3288 if (lpColumn != NULL)
3290 /* initialize memory */
3291 ZeroMemory(&hdi, sizeof(HDITEMA));
3293 if (lpColumn->mask & LVCF_FMT)
3295 hdi.mask |= HDI_FORMAT;
3298 if (lpColumn->mask & LVCF_WIDTH)
3300 hdi.mask |= HDI_WIDTH;
3303 if (lpColumn->mask & LVCF_TEXT)
3305 hdi.mask |= HDI_TEXT;
3306 hdi.cchTextMax = lpColumn->cchTextMax;
3307 hdi.pszText = lpColumn->pszText;
3310 if (lpColumn->mask & LVCF_IMAGE)
3312 hdi.mask |= HDI_IMAGE;
3315 if (lpColumn->mask & LVCF_ORDER)
3317 hdi.mask |= HDI_ORDER;
3320 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3321 if (bResult != FALSE)
3323 if (lpColumn->mask & LVCF_FMT)
3327 if (hdi.fmt & HDF_LEFT)
3329 lpColumn->fmt |= LVCFMT_LEFT;
3331 else if (hdi.fmt & HDF_RIGHT)
3333 lpColumn->fmt |= LVCFMT_RIGHT;
3335 else if (hdi.fmt & HDF_CENTER)
3337 lpColumn->fmt |= LVCFMT_CENTER;
3340 if (hdi.fmt & HDF_IMAGE)
3342 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3345 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3347 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3351 if (lpColumn->mask & LVCF_WIDTH)
3353 lpColumn->cx = hdi.cxy;
3356 if (lpColumn->mask & LVCF_IMAGE)
3358 lpColumn->iImage = hdi.iImage;
3361 if (lpColumn->mask & LVCF_ORDER)
3363 lpColumn->iOrder = hdi.iOrder;
3371 /* LISTVIEW_GetColumnW */
3374 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
3376 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3383 for (i = 0; i < iCount; i++)
3391 * Retrieves the column width.
3394 * [I] HWND : window handle
3395 * [I] int : column index
3398 * SUCCESS : column width
3401 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3403 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3404 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3405 INT nColumnWidth = 0;
3408 if (uView == LVS_LIST)
3410 nColumnWidth = infoPtr->nItemWidth;
3412 else if (uView == LVS_REPORT)
3414 /* get column width from header */
3415 ZeroMemory(&hdi, sizeof(HDITEMA));
3416 hdi.mask = HDI_WIDTH;
3417 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3419 nColumnWidth = hdi.cxy;
3423 return nColumnWidth;
3428 * In list or report display mode, retrieves the number of items that can fit
3429 * vertically in the visible area. In icon or small icon display mode,
3430 * retrieves the total number of visible items.
3433 * [I] HWND : window handle
3436 * Number of fully visible items.
3438 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3440 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3441 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3444 if (uView == LVS_LIST)
3446 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3448 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3449 LISTVIEW_GetCountPerColumn(hwnd);
3452 else if (uView == LVS_REPORT)
3454 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3458 nItemCount = GETITEMCOUNT(infoPtr);
3464 /* LISTVIEW_GetEditControl */
3468 * Retrieves the extended listview style.
3471 * [I] HWND : window handle
3474 * SUCCESS : previous style
3477 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3479 LISTVIEW_INFO *infoPtr;
3481 /* make sure we can get the listview info */
3482 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3485 return (infoPtr->dwExStyle);
3490 * Retrieves the handle to the header control.
3493 * [I] HWND : window handle
3498 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3500 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3502 return infoPtr->hwndHeader;
3505 /* LISTVIEW_GetHotCursor */
3506 /* LISTVIEW_GetHotItem */
3507 /* LISTVIEW_GetHoverTime */
3511 * Retrieves an image list handle.
3514 * [I] HWND : window handle
3515 * [I] INT : image list identifier
3518 * SUCCESS : image list handle
3521 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3523 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3524 HIMAGELIST himl = NULL;
3529 himl = infoPtr->himlNormal;
3532 himl = infoPtr->himlSmall;
3535 himl = infoPtr->himlState;
3539 return (LRESULT)himl;
3542 /* LISTVIEW_GetISearchString */
3546 * Retrieves item attributes.
3549 * [I] HWND : window handle
3550 * [IO] LPLVITEMA : item info
3551 * [I] internal : if true then we will use tricks that avoid copies
3552 * but are not compatible with the regular interface
3558 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
3560 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3561 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3562 NMLVDISPINFOA dispInfo;
3563 LISTVIEW_SUBITEM *lpSubItem;
3564 LISTVIEW_ITEM *lpItem;
3568 /* In the following:
3569 * lpLVItem describes the information requested by the user
3570 * lpItem/lpSubItem is what we have
3571 * dispInfo is a structure we use to request the missing
3572 * information from the application
3575 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3577 if ((lpLVItem == NULL) ||
3578 (lpLVItem->iItem < 0) ||
3579 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
3583 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3584 if (hdpaSubItems == NULL)
3587 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3591 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3592 if (lpLVItem->iSubItem == 0)
3594 piImage=&lpItem->iImage;
3595 ppszText=&lpItem->pszText;
3596 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3598 dispInfo.item.mask |= LVIF_STATE;
3599 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3604 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
3605 if (lpSubItem != NULL)
3607 piImage=&lpSubItem->iImage;
3608 ppszText=&lpSubItem->pszText;
3617 if ((lpLVItem->mask & LVIF_IMAGE) &&
3618 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
3620 dispInfo.item.mask |= LVIF_IMAGE;
3623 if ((lpLVItem->mask & LVIF_TEXT) &&
3624 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
3626 dispInfo.item.mask |= LVIF_TEXT;
3627 dispInfo.item.pszText = lpLVItem->pszText;
3628 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3631 if (dispInfo.item.mask != 0)
3633 /* We don't have all the requested info, query the application */
3634 dispInfo.hdr.hwndFrom = hwnd;
3635 dispInfo.hdr.idFrom = lCtrlId;
3636 dispInfo.hdr.code = LVN_GETDISPINFOA;
3637 dispInfo.item.iItem = lpLVItem->iItem;
3638 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3639 dispInfo.item.lParam = lpItem->lParam;
3640 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3643 if (dispInfo.item.mask & LVIF_IMAGE)
3645 lpLVItem->iImage = dispInfo.item.iImage;
3647 else if (lpLVItem->mask & LVIF_IMAGE)
3649 lpLVItem->iImage = *piImage;
3652 if (dispInfo.item.mask & LVIF_PARAM)
3654 lpLVItem->lParam = dispInfo.item.lParam;
3656 else if (lpLVItem->mask & LVIF_PARAM)
3658 lpLVItem->lParam = lpItem->lParam;
3661 if (dispInfo.item.mask & LVIF_TEXT)
3663 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
3665 Str_SetPtrA(ppszText, dispInfo.item.pszText);
3667 /* Here lpLVItem->pszText==dispInfo.item.pszText so a copy is unnecessary */
3669 else if (lpLVItem->mask & LVIF_TEXT)
3673 lpLVItem->pszText=*ppszText;
3675 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
3679 if (lpLVItem->iSubItem == 0)
3681 if (dispInfo.item.mask & LVIF_STATE)
3683 lpLVItem->state = lpItem->state;
3684 lpLVItem->state &= ~dispInfo.item.stateMask;
3685 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
3687 else if (lpLVItem->mask & LVIF_STATE)
3689 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3692 if (lpLVItem->mask & LVIF_PARAM)
3694 lpLVItem->lParam = lpItem->lParam;
3697 if (lpLVItem->mask & LVIF_INDENT)
3699 lpLVItem->iIndent = lpItem->iIndent;
3706 /* LISTVIEW_GetItemW */
3707 /* LISTVIEW_GetHotCursor */
3711 * Retrieves the index of the hot item.
3714 * [I] HWND : window handle
3717 * SUCCESS : hot item index
3718 * FAILURE : -1 (no hot item)
3720 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3722 LISTVIEW_INFO *infoPtr;
3724 /* make sure we can get the listview info */
3725 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3728 return (infoPtr->nHotItem);
3731 /* LISTVIEW_GetHoverTime */
3735 * Retrieves the number of items in the listview control.
3738 * [I] HWND : window handle
3743 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3745 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3747 return GETITEMCOUNT(infoPtr);
3752 * Retrieves the position (upper-left) of the listview control item.
3755 * [I] HWND : window handle
3756 * [I] INT : item index
3757 * [O] LPPOINT : coordinate information
3763 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3764 LPPOINT lpptPosition)
3766 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3767 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3768 BOOL bResult = FALSE;
3770 LISTVIEW_ITEM *lpItem;
3771 INT nCountPerColumn;
3774 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3777 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3778 (lpptPosition != NULL))
3780 if (uView == LVS_LIST)
3783 nItem = nItem - ListView_GetTopIndex(hwnd);
3784 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3787 nRow = nItem % nCountPerColumn;
3790 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3791 lpptPosition->y = 0;
3795 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3796 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3801 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3802 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3805 else if (uView == LVS_REPORT)
3808 lpptPosition->x = REPORT_MARGINX;
3809 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3810 infoPtr->nItemHeight) + infoPtr->rcList.top;
3814 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3815 if (hdpaSubItems != NULL)
3817 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3821 lpptPosition->x = lpItem->ptPosition.x;
3822 lpptPosition->y = lpItem->ptPosition.y;
3833 * Retrieves the bounding rectangle for a listview control item.
3836 * [I] HWND : window handle
3837 * [I] INT : item index
3838 * [IO] LPRECT : bounding rectangle coordinates
3844 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3846 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3847 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3848 BOOL bResult = FALSE;
3857 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3859 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3861 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3866 if (uView == LVS_ICON)
3868 if (infoPtr->himlNormal != NULL)
3870 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3873 lprc->left = ptItem.x + ptOrigin.x;
3874 lprc->top = ptItem.y + ptOrigin.y;
3875 lprc->right = lprc->left + infoPtr->iconSize.cx;
3876 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3877 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3881 else if (uView == LVS_SMALLICON)
3883 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3886 lprc->left = ptItem.x + ptOrigin.x;
3887 lprc->top = ptItem.y + ptOrigin.y;
3888 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3890 if (infoPtr->himlState != NULL)
3891 lprc->left += infoPtr->iconSize.cx;
3893 if (infoPtr->himlSmall != NULL)
3894 lprc->right = lprc->left + infoPtr->iconSize.cx;
3896 lprc->right = lprc->left;
3902 lprc->left = ptItem.x;
3903 lprc->top = ptItem.y;
3904 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3906 if (infoPtr->himlState != NULL)
3908 lprc->left += infoPtr->iconSize.cx;
3911 if (infoPtr->himlSmall != NULL)
3913 lprc->right = lprc->left + infoPtr->iconSize.cx;
3917 lprc->right = lprc->left;
3923 if (uView == LVS_ICON)
3925 if (infoPtr->himlNormal != NULL)
3927 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3930 lprc->left = ptItem.x + ptOrigin.x;
3931 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3932 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3933 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3934 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3936 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3937 lprc->right = lprc->left + nLabelWidth;
3942 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3946 hOldFont = SelectObject(hdc, infoPtr->hFont);
3947 GetTextMetricsA(hdc, &tm);
3948 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3949 SelectObject(hdc, hOldFont);
3950 ReleaseDC(hwnd, hdc);
3954 else if (uView == LVS_SMALLICON)
3956 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3959 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
3960 lprc->top = ptItem.y + ptOrigin.y;
3961 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3963 if (infoPtr->himlState != NULL)
3965 lprc->left += infoPtr->iconSize.cx;
3968 if (infoPtr->himlSmall != NULL)
3970 lprc->left += infoPtr->iconSize.cx;
3973 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3974 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3976 lprc->right = lprc->left + nLabelWidth;
3980 lprc->right = nLeftPos + infoPtr->nItemWidth;
3987 nLeftPos = lprc->left = ptItem.x;
3988 lprc->top = ptItem.y;
3989 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3991 if (infoPtr->himlState != NULL)
3993 lprc->left += infoPtr->iconSize.cx;
3996 if (infoPtr->himlSmall != NULL)
3998 lprc->left += infoPtr->iconSize.cx;
4001 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4002 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4004 lprc->right = lprc->left + nLabelWidth;
4008 lprc->right = nLeftPos + infoPtr->nItemWidth;
4014 if (uView == LVS_ICON)
4016 if (infoPtr->himlNormal != NULL)
4018 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4021 lprc->left = ptItem.x + ptOrigin.x;
4022 lprc->top = ptItem.y + ptOrigin.y;
4023 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4024 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4028 else if (uView == LVS_SMALLICON)
4030 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4033 lprc->left = ptItem.x + ptOrigin.x;
4034 lprc->right = lprc->left;
4035 lprc->top = ptItem.y + ptOrigin.y;
4036 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4037 if (infoPtr->himlState != NULL)
4038 lprc->right += infoPtr->iconSize.cx;
4039 if (infoPtr->himlSmall != NULL)
4040 lprc->right += infoPtr->iconSize.cx;
4042 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4043 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4045 lprc->right += nLabelWidth;
4049 lprc->right = lprc->left + infoPtr->nItemWidth;
4056 lprc->left = ptItem.x;
4057 lprc->right = lprc->left;
4058 lprc->top = ptItem.y;
4059 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4061 if (infoPtr->himlState != NULL)
4063 lprc->right += infoPtr->iconSize.cx;
4066 if (infoPtr->himlSmall != NULL)
4068 lprc->right += infoPtr->iconSize.cx;
4071 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4072 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4074 lprc->right += nLabelWidth;
4078 lprc->right = lprc->left + infoPtr->nItemWidth;
4083 case LVIR_SELECTBOUNDS:
4084 if (uView == LVS_ICON)
4086 if (infoPtr->himlNormal != NULL)
4088 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4091 lprc->left = ptItem.x + ptOrigin.x;
4092 lprc->top = ptItem.y + ptOrigin.y;
4093 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4094 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4098 else if (uView == LVS_SMALLICON)
4100 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4103 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4104 lprc->top = ptItem.y + ptOrigin.y;
4105 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4107 if (infoPtr->himlState != NULL)
4109 lprc->left += infoPtr->iconSize.cx;
4112 lprc->right = lprc->left;
4114 if (infoPtr->himlSmall != NULL)
4116 lprc->right += infoPtr->iconSize.cx;
4119 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4120 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4122 lprc->right += nLabelWidth;
4126 lprc->right = nLeftPos + infoPtr->nItemWidth;
4133 nLeftPos = lprc->left = ptItem.x;
4134 lprc->top = ptItem.y;
4135 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4137 if (infoPtr->himlState != NULL)
4139 lprc->left += infoPtr->iconSize.cx;
4142 lprc->right = lprc->left;
4144 if (infoPtr->himlSmall != NULL)
4146 lprc->right += infoPtr->iconSize.cx;
4149 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4150 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4152 lprc->right += nLabelWidth;
4156 lprc->right = nLeftPos + infoPtr->nItemWidth;
4169 * Retrieves the width of a label.
4172 * [I] HWND : window handle
4175 * SUCCESS : string width (in pixels)
4178 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4180 CHAR szDispText[DISP_TEXT_SIZE];
4181 INT nLabelWidth = 0;
4184 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4186 ZeroMemory(&lvItem, sizeof(LVITEMA));
4187 lvItem.mask = LVIF_TEXT;
4188 lvItem.iItem = nItem;
4189 lvItem.cchTextMax = DISP_TEXT_SIZE;
4190 lvItem.pszText = szDispText;
4191 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4193 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4201 * Retrieves the spacing between listview control items.
4204 * [I] HWND : window handle
4205 * [I] BOOL : flag for small or large icon
4208 * Horizontal + vertical spacing
4210 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4212 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4215 if (bSmall == FALSE)
4217 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4221 /* TODO: need to store width of smallicon item */
4222 lResult = MAKELONG(0, infoPtr->nItemHeight);
4230 * Retrieves the state of a listview control item.
4233 * [I] HWND : window handle
4234 * [I] INT : item index
4235 * [I] UINT : state mask
4238 * State specified by the mask.
4240 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4242 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4246 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4248 ZeroMemory(&lvItem, sizeof(LVITEMA));
4249 lvItem.iItem = nItem;
4250 lvItem.stateMask = uMask;
4251 lvItem.mask = LVIF_STATE;
4252 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4254 uState = lvItem.state;
4263 * Retrieves the text of a listview control item or subitem.
4266 * [I] HWND : window handle
4267 * [I] INT : item index
4268 * [IO] LPLVITEMA : item information
4271 * SUCCESS : string length
4274 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4276 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4279 if (lpLVItem != NULL)
4281 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4283 lpLVItem->mask = LVIF_TEXT;
4284 lpLVItem->iItem = nItem;
4285 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
4287 nLength = lstrlenA(lpLVItem->pszText);
4297 * Searches for an item based on properties + relationships.
4300 * [I] HWND : window handle
4301 * [I] INT : item index
4302 * [I] INT : relationship flag
4305 * SUCCESS : item index
4308 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4310 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4311 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4313 LVFINDINFO lvFindInfo;
4314 INT nCountPerColumn;
4317 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4319 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4321 if (uFlags & LVNI_CUT)
4324 if (uFlags & LVNI_DROPHILITED)
4325 uMask |= LVIS_DROPHILITED;
4327 if (uFlags & LVNI_FOCUSED)
4328 uMask |= LVIS_FOCUSED;
4330 if (uFlags & LVNI_SELECTED)
4331 uMask |= LVIS_SELECTED;
4333 if (uFlags & LVNI_ABOVE)
4335 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4340 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4346 lvFindInfo.flags = LVFI_NEARESTXY;
4347 lvFindInfo.vkDirection = VK_UP;
4348 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4349 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4351 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4356 else if (uFlags & LVNI_BELOW)
4358 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4360 while (nItem < GETITEMCOUNT(infoPtr))
4363 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4369 lvFindInfo.flags = LVFI_NEARESTXY;
4370 lvFindInfo.vkDirection = VK_DOWN;
4371 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4372 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4374 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4379 else if (uFlags & LVNI_TOLEFT)
4381 if (uView == LVS_LIST)
4383 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4384 while (nItem - nCountPerColumn >= 0)
4386 nItem -= nCountPerColumn;
4387 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4391 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4393 lvFindInfo.flags = LVFI_NEARESTXY;
4394 lvFindInfo.vkDirection = VK_LEFT;
4395 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4396 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4398 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4403 else if (uFlags & LVNI_TORIGHT)
4405 if (uView == LVS_LIST)
4407 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4408 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4410 nItem += nCountPerColumn;
4411 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4415 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4417 lvFindInfo.flags = LVFI_NEARESTXY;
4418 lvFindInfo.vkDirection = VK_RIGHT;
4419 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4420 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4422 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4431 /* search by index */
4432 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4434 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4443 /* LISTVIEW_GetNumberOfWorkAreas */
4447 * Retrieves the origin coordinates when in icon or small icon display mode.
4450 * [I] HWND : window handle
4451 * [O] LPPOINT : coordinate information
4457 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4459 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4460 UINT uView = lStyle & LVS_TYPEMASK;
4461 BOOL bResult = FALSE;
4463 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4465 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4467 SCROLLINFO scrollInfo;
4468 ZeroMemory(lpptOrigin, sizeof(POINT));
4469 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4470 scrollInfo.cbSize = sizeof(SCROLLINFO);
4472 if (lStyle & WS_HSCROLL)
4474 scrollInfo.fMask = SIF_POS;
4475 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4477 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4481 if (lStyle & WS_VSCROLL)
4483 scrollInfo.fMask = SIF_POS;
4484 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4486 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4498 * Retrieves the number of items that are marked as selected.
4501 * [I] HWND : window handle
4504 * Number of items selected.
4506 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4508 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4509 INT nSelectedCount = 0;
4512 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4514 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4520 return nSelectedCount;
4525 * Retrieves item index that marks the start of a multiple selection.
4528 * [I] HWND : window handle
4531 * Index number or -1 if there is no selection mark.
4533 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4535 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4537 return infoPtr->nSelectionMark;
4542 * Retrieves the width of a string.
4545 * [I] HWND : window handle
4548 * SUCCESS : string width (in pixels)
4551 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4553 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4554 HFONT hFont, hOldFont;
4558 ZeroMemory(&stringSize, sizeof(SIZE));
4559 if (lpszText != NULL)
4561 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4563 hOldFont = SelectObject(hdc, hFont);
4564 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4565 SelectObject(hdc, hOldFont);
4566 ReleaseDC(hwnd, hdc);
4569 return stringSize.cx;
4574 * Retrieves the text backgound color.
4577 * [I] HWND : window handle
4580 * COLORREF associated with the the background.
4582 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4584 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4586 return infoPtr->clrTextBk;
4591 * Retrieves the text color.
4594 * [I] HWND : window handle
4597 * COLORREF associated with the text.
4599 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4601 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4603 return infoPtr->clrText;
4608 * Determines which section of the item was selected (if any).
4611 * [I] HWND : window handle
4612 * [IO] LPLVHITTESTINFO : hit test information
4615 * SUCCESS : item index
4618 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4620 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4624 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4625 lpHitTestInfo->pt.y);
4627 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4629 rcItem.left = LVIR_BOUNDS;
4630 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4632 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4634 rcItem.left = LVIR_ICON;
4635 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4637 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4639 lpHitTestInfo->flags = LVHT_ONITEMICON;
4640 lpHitTestInfo->iItem = i;
4641 lpHitTestInfo->iSubItem = 0;
4646 rcItem.left = LVIR_LABEL;
4647 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4649 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4651 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4652 lpHitTestInfo->iItem = i;
4653 lpHitTestInfo->iSubItem = 0;
4658 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4659 lpHitTestInfo->iItem = i;
4660 lpHitTestInfo->iSubItem = 0;
4666 lpHitTestInfo->flags = LVHT_NOWHERE;
4673 * Determines which listview item is located at the specified position.
4676 * [I] HWND : window handle
4677 * [IO} LPLVHITTESTINFO : hit test information
4680 * SUCCESS : item index
4683 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4685 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4688 lpHitTestInfo->flags = 0;
4690 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4692 lpHitTestInfo->flags = LVHT_TOLEFT;
4694 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4696 lpHitTestInfo->flags = LVHT_TORIGHT;
4698 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4700 lpHitTestInfo->flags |= LVHT_ABOVE;
4702 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4704 lpHitTestInfo->flags |= LVHT_BELOW;
4707 if (lpHitTestInfo->flags == 0)
4709 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4717 * Inserts a new column.
4720 * [I] HWND : window handle
4721 * [I] INT : column index
4722 * [I] LPLVCOLUMNA : column information
4725 * SUCCESS : new column index
4728 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4729 LPLVCOLUMNA lpColumn)
4731 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4733 INT nNewColumn = -1;
4735 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4738 if (lpColumn != NULL)
4740 /* initialize memory */
4741 ZeroMemory(&hdi, sizeof(HDITEMA));
4743 if (lpColumn->mask & LVCF_FMT)
4745 /* format member is valid */
4746 hdi.mask |= HDI_FORMAT;
4748 /* set text alignment (leftmost column must be left-aligned) */
4751 hdi.fmt |= HDF_LEFT;
4755 if (lpColumn->fmt & LVCFMT_LEFT)
4757 hdi.fmt |= HDF_LEFT;
4759 else if (lpColumn->fmt & LVCFMT_RIGHT)
4761 hdi.fmt |= HDF_RIGHT;
4763 else if (lpColumn->fmt & LVCFMT_CENTER)
4765 hdi.fmt |= HDF_CENTER;
4769 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4771 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4775 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4780 if (lpColumn->fmt & LVCFMT_IMAGE)
4782 hdi.fmt |= HDF_IMAGE;
4783 hdi.iImage = I_IMAGECALLBACK;
4787 if (lpColumn->mask & LVCF_WIDTH)
4789 hdi.mask |= HDI_WIDTH;
4790 hdi.cxy = lpColumn->cx;
4793 if (lpColumn->mask & LVCF_TEXT)
4795 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4796 hdi.pszText = lpColumn->pszText;
4797 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4798 hdi.fmt |= HDF_STRING;
4801 if (lpColumn->mask & LVCF_IMAGE)
4803 hdi.mask |= HDI_IMAGE;
4804 hdi.iImage = lpColumn->iImage;
4807 if (lpColumn->mask & LVCF_ORDER)
4809 hdi.mask |= HDI_ORDER;
4810 hdi.iOrder = lpColumn->iOrder;
4813 /* insert item in header control */
4814 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4815 (WPARAM)nColumn, (LPARAM)&hdi);
4817 /* Need to reset the item width when inserting a new column */
4818 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4820 LISTVIEW_UpdateScroll(hwnd);
4821 InvalidateRect(hwnd, NULL, FALSE);
4827 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4828 LPLVCOLUMNW lpColumn)
4833 memcpy(&lvca,lpColumn,sizeof(lvca));
4834 if (lpColumn->mask & LVCF_TEXT)
4835 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4836 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4837 if (lpColumn->mask & LVCF_TEXT)
4838 HeapFree(GetProcessHeap(),0,lvca.pszText);
4842 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
4843 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
4844 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
4845 and not during the processing of a LVM_SORTITEMS message. Applications should provide
4846 their own sort proc. when sending LVM_SORTITEMS.
4849 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
4851 LVS_SORTXXX must be specified,
4852 LVS_OWNERDRAW is not set,
4853 <item>.pszText is not LPSTR_TEXTCALLBACK.
4855 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
4856 are sorted based on item text..."
4858 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
4860 HDPA hdpa_first = (HDPA) first;
4861 HDPA hdpa_second = (HDPA) second;
4862 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
4863 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
4864 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
4865 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
4866 /* if we're sorting descending, negate the return value */
4867 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
4872 * Inserts a new item in the listview control.
4875 * [I] HWND : window handle
4876 * [I] LPLVITEMA : item information
4879 * SUCCESS : new item index
4882 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4884 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4885 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4886 UINT uView = lStyle & LVS_TYPEMASK;
4887 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4892 LISTVIEW_ITEM *lpItem = NULL;
4894 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4896 if (lpLVItem != NULL)
4898 /* make sure it's not a subitem; cannot insert a subitem */
4899 if (lpLVItem->iSubItem == 0)
4901 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4904 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4905 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4907 /* insert item in listview control data structure */
4908 hdpaSubItems = DPA_Create(8);
4909 if (hdpaSubItems != NULL)
4911 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4914 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
4915 && !(lStyle & LVS_OWNERDRAWFIXED)
4916 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
4918 /* Insert the item in the proper sort order based on the pszText
4919 member. See comments for LISTVIEW_InsertCompare() for greater detail */
4920 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
4921 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
4922 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
4923 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
4927 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4932 /* manage item focus */
4933 if (lpLVItem->mask & LVIF_STATE)
4935 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
4936 if (lpLVItem->stateMask & LVIS_SELECTED)
4938 LISTVIEW_SetSelection(hwnd, nItem);
4940 else if (lpLVItem->stateMask & LVIS_FOCUSED)
4942 LISTVIEW_SetItemFocus(hwnd, nItem);
4946 /* send LVN_INSERTITEM notification */
4947 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4948 nmlv.hdr.hwndFrom = hwnd;
4949 nmlv.hdr.idFrom = lCtrlId;
4950 nmlv.hdr.code = LVN_INSERTITEM;
4952 nmlv.lParam = lpItem->lParam;;
4953 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4955 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
4957 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
4958 if (nItemWidth > infoPtr->nItemWidth)
4960 infoPtr->nItemWidth = nItemWidth;
4964 /* align items (set position of each item) */
4965 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4967 if (lStyle & LVS_ALIGNLEFT)
4969 LISTVIEW_AlignLeft(hwnd);
4973 LISTVIEW_AlignTop(hwnd);
4977 LISTVIEW_UpdateScroll(hwnd);
4978 /* refresh client area */
4979 InvalidateRect(hwnd, NULL, FALSE);
4988 /* free memory if unsuccessful */
4989 if ((nItem == -1) && (lpItem != NULL))
4991 COMCTL32_Free(lpItem);
4997 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
5001 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
5002 if (lvia.mask & LVIF_TEXT) {
5003 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
5004 lvia.pszText = LPSTR_TEXTCALLBACKA;
5006 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
5008 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
5009 if (lvia.mask & LVIF_TEXT) {
5010 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
5011 HeapFree(GetProcessHeap(),0,lvia.pszText);
5016 /* LISTVIEW_InsertItemW */
5020 * Redraws a range of items.
5023 * [I] HWND : window handle
5024 * [I] INT : first item
5025 * [I] INT : last item
5031 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
5033 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5034 BOOL bResult = FALSE;
5037 if (nFirst <= nLast)
5039 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
5041 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
5044 InvalidateRect(hwnd, &rc, FALSE);
5052 /* LISTVIEW_Scroll */
5056 * Sets the background color.
5059 * [I] HWND : window handle
5060 * [I] COLORREF : background color
5066 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
5068 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5070 infoPtr->clrBk = clrBk;
5071 InvalidateRect(hwnd, NULL, TRUE);
5076 /* LISTVIEW_SetBkImage */
5080 * Sets the callback mask. This mask will be used when the parent
5081 * window stores state information (some or all).
5084 * [I] HWND : window handle
5085 * [I] UINT : state mask
5091 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5093 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5095 infoPtr->uCallbackMask = uMask;
5102 * Sets the attributes of a header item.
5105 * [I] HWND : window handle
5106 * [I] INT : column index
5107 * [I] LPLVCOLUMNA : column attributes
5113 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5114 LPLVCOLUMNA lpColumn)
5116 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5117 BOOL bResult = FALSE;
5118 HDITEMA hdi, hdiget;
5120 if ((lpColumn != NULL) && (nColumn >= 0) &&
5121 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5123 /* initialize memory */
5124 ZeroMemory(&hdi, sizeof(HDITEMA));
5126 if (lpColumn->mask & LVCF_FMT)
5128 /* format member is valid */
5129 hdi.mask |= HDI_FORMAT;
5131 /* get current format first */
5132 hdiget.mask = HDI_FORMAT;
5133 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5134 /* preserve HDF_STRING if present */
5135 hdi.fmt = hdiget.fmt & HDF_STRING;
5137 /* set text alignment (leftmost column must be left-aligned) */
5140 hdi.fmt |= HDF_LEFT;
5144 if (lpColumn->fmt & LVCFMT_LEFT)
5146 hdi.fmt |= HDF_LEFT;
5148 else if (lpColumn->fmt & LVCFMT_RIGHT)
5150 hdi.fmt |= HDF_RIGHT;
5152 else if (lpColumn->fmt & LVCFMT_CENTER)
5154 hdi.fmt |= HDF_CENTER;
5158 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5160 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5163 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5165 hdi.fmt |= HDF_IMAGE;
5168 if (lpColumn->fmt & LVCFMT_IMAGE)
5170 hdi.fmt |= HDF_IMAGE;
5171 hdi.iImage = I_IMAGECALLBACK;
5175 if (lpColumn->mask & LVCF_WIDTH)
5177 hdi.mask |= HDI_WIDTH;
5178 hdi.cxy = lpColumn->cx;
5181 if (lpColumn->mask & LVCF_TEXT)
5183 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5184 hdi.pszText = lpColumn->pszText;
5185 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5186 hdi.fmt |= HDF_STRING;
5189 if (lpColumn->mask & LVCF_IMAGE)
5191 hdi.mask |= HDI_IMAGE;
5192 hdi.iImage = lpColumn->iImage;
5195 if (lpColumn->mask & LVCF_ORDER)
5197 hdi.mask |= HDI_ORDER;
5198 hdi.iOrder = lpColumn->iOrder;
5201 /* set header item attributes */
5202 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5208 /* LISTVIEW_SetColumnW */
5212 * Sets the column order array
5215 * [I] HWND : window handle
5216 * [I] INT : number of elements in column order array
5217 * [I] INT : pointer to column order array
5223 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
5225 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
5227 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
5238 * Sets the width of a column
5241 * [I] HWND : window handle
5242 * [I] INT : column index
5243 * [I] INT : column width
5249 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5251 LISTVIEW_INFO *infoPtr;
5256 /* set column width only if in report mode */
5257 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5258 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
5261 /* make sure we can get the listview info */
5262 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5264 if (!infoPtr->hwndHeader) /* make sure we have a header */
5267 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5268 * LVSCV_AUTOSIZE_USEHEADER (-2)
5273 hdi.mask = HDI_WIDTH;
5276 /* call header to update the column change */
5277 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5279 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5281 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5288 * Sets the extended listview style.
5291 * [I] HWND : window handle
5296 * SUCCESS : previous style
5299 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5301 LISTVIEW_INFO *infoPtr;
5304 /* make sure we can get the listview info */
5305 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5308 /* store previous style */
5309 dwOldStyle = infoPtr->dwExStyle;
5312 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5314 return (dwOldStyle);
5317 /* LISTVIEW_SetHotCursor */
5321 * Sets the hot item index.
5324 * [I] HWND : window handle
5328 * SUCCESS : previous hot item index
5329 * FAILURE : -1 (no hot item)
5331 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5333 LISTVIEW_INFO *infoPtr;
5336 /* make sure we can get the listview info */
5337 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5340 /* store previous index */
5341 iOldIndex = infoPtr->nHotItem;
5344 infoPtr->nHotItem = iIndex;
5349 /* LISTVIEW_SetIconSpacing */
5356 * [I] HWND : window handle
5357 * [I] INT : image list type
5358 * [I] HIMAGELIST : image list handle
5361 * SUCCESS : old image list
5364 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5366 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5367 HIMAGELIST himlTemp = 0;
5372 himlTemp = infoPtr->himlNormal;
5373 infoPtr->himlNormal = himl;
5374 return (LRESULT)himlTemp;
5377 himlTemp = infoPtr->himlSmall;
5378 infoPtr->himlSmall = himl;
5379 return (LRESULT)himlTemp;
5382 himlTemp = infoPtr->himlState;
5383 infoPtr->himlState = himl;
5384 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5385 return (LRESULT)himlTemp;
5388 return (LRESULT)NULL;
5394 * Sets the attributes of an item.
5397 * [I] HWND : window handle
5398 * [I] LPLVITEM : item information
5404 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5406 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5407 BOOL bResult = FALSE;
5409 if (lpLVItem != NULL)
5411 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5413 if (lpLVItem->iSubItem == 0)
5415 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5419 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5428 /* LISTVIEW_SetItemW */
5432 * Preallocates memory.
5435 * [I] HWND : window handle
5436 * [I] INT : item count (projected number of items)
5437 * [I] DWORD : update flags
5443 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5445 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5447 FIXME("(%d %08lx)empty stub!\n", nItems, dwFlags);
5450 return LISTVIEW_DeleteAllItems (hwnd);
5452 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
5454 FIXME("LVS_OWNERDATA is set!\n");
5458 if (nItems > GETITEMCOUNT(infoPtr))
5461 FIXME("append items\n");
5464 else if (nItems < GETITEMCOUNT(infoPtr))
5467 FIXME("remove items\n");
5477 * Sets the position of an item.
5480 * [I] HWND : window handle
5481 * [I] INT : item index
5482 * [I] INT : x coordinate
5483 * [I] INT : y coordinate
5489 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5490 INT nPosX, INT nPosY)
5492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5493 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5494 LISTVIEW_ITEM *lpItem;
5496 BOOL bResult = FALSE;
5498 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5500 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5502 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5504 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5505 if (hdpaSubItems != NULL)
5507 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5511 lpItem->ptPosition.x = nPosX;
5512 lpItem->ptPosition.y = nPosY;
5521 /* LISTVIEW_SetItemPosition32 */
5525 * Sets the state of one or many items.
5528 * [I] HWND : window handle
5529 * [I]INT : item index
5530 * [I] LPLVITEM : item or subitem info
5536 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5538 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5539 BOOL bResult = FALSE;
5546 ZeroMemory(&lvItem, sizeof(LVITEMA));
5547 lvItem.mask = LVIF_STATE;
5548 lvItem.state = lpLVItem->state;
5549 lvItem.stateMask = lpLVItem->stateMask ;
5551 /* apply to all items */
5552 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5555 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5563 ZeroMemory(&lvItem, sizeof(LVITEMA));
5564 lvItem.mask = LVIF_STATE;
5565 lvItem.state = lpLVItem->state;
5566 lvItem.stateMask = lpLVItem->stateMask;
5567 lvItem.iItem = nItem;
5568 bResult = ListView_SetItemA(hwnd, &lvItem);
5576 * Sets the text of an item or subitem.
5579 * [I] HWND : window handle
5580 * [I] INT : item index
5581 * [I] LPLVITEMA : item or subitem info
5587 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5589 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5590 BOOL bResult = FALSE;
5593 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5595 ZeroMemory(&lvItem, sizeof(LVITEMA));
5596 lvItem.mask = LVIF_TEXT;
5597 lvItem.pszText = lpLVItem->pszText;
5598 lvItem.iItem = nItem;
5599 lvItem.iSubItem = lpLVItem->iSubItem;
5600 bResult = ListView_SetItemA(hwnd, &lvItem);
5606 /* LISTVIEW_SetItemTextW */
5610 * Set item index that marks the start of a multiple selection.
5613 * [I] HWND : window handle
5617 * Index number or -1 if there is no selection mark.
5619 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5621 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5622 INT nOldIndex = infoPtr->nSelectionMark;
5624 infoPtr->nSelectionMark = nIndex;
5631 * Sets the text background color.
5634 * [I] HWND : window handle
5635 * [I] COLORREF : text background color
5641 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5643 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5645 infoPtr->clrTextBk = clrTextBk;
5646 InvalidateRect(hwnd, NULL, TRUE);
5653 * Sets the text foreground color.
5656 * [I] HWND : window handle
5657 * [I] COLORREF : text color
5663 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5665 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5667 infoPtr->clrText = clrText;
5668 InvalidateRect(hwnd, NULL, TRUE);
5673 /* LISTVIEW_SetToolTips */
5674 /* LISTVIEW_SetUnicodeFormat */
5675 /* LISTVIEW_SetWorkAreas */
5679 * Callback internally used by LISTVIEW_SortItems()
5682 * [I] LPVOID : first LISTVIEW_ITEM to compare
5683 * [I] LPVOID : second LISTVIEW_ITEM to compare
5684 * [I] LPARAM : HWND of control
5687 * if first comes before second : negative
5688 * if first comes after second : positive
5689 * if first and second are equivalent : zero
5691 static INT WINAPI LISTVIEW_CallBackCompare(
5696 /* Forward the call to the client defined callback */
5698 HWND hwnd = (HWND)lParam;
5699 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5701 rv = (infoPtr->pfnCompare)( ((LISTVIEW_ITEM*) first)->lParam,
5702 ((LISTVIEW_ITEM*) second)->lParam, infoPtr->lParamSort );
5709 * Sorts the listview items.
5712 * [I] HWND : window handle
5713 * [I] WPARAM : application-defined value
5714 * [I] LPARAM : pointer to comparision callback
5720 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5722 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5724 LISTVIEW_ITEM *lpItem;
5728 if (!infoPtr || !infoPtr->hdpaItems)
5731 nCount = GETITEMCOUNT(infoPtr);
5732 /* if there are 0 or 1 items, there is no need to sort */
5735 sortList = DPA_Create(nCount);
5737 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5738 infoPtr->lParamSort = (LPARAM)wParam;
5740 /* append pointers one by one to sortList */
5741 for (i = 0; i < nCount; i++)
5743 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5744 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5745 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5748 /* sort the sortList */
5749 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5751 /* copy the pointers back */
5752 for (i = 0; i < nCount; i++)
5754 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5755 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5756 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5759 DPA_Destroy(sortList);
5765 /* LISTVIEW_SubItemHitTest */
5769 * Updates an items or rearranges the listview control.
5772 * [I] HWND : window handle
5773 * [I] INT : item index
5779 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5781 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5782 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5783 BOOL bResult = FALSE;
5786 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5790 /* rearrange with default alignment style */
5791 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5792 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5794 ListView_Arrange(hwnd, 0);
5798 /* get item bounding rectangle */
5799 rc.left = LVIR_BOUNDS;
5800 ListView_GetItemRect(hwnd, nItem, &rc);
5801 InvalidateRect(hwnd, &rc, TRUE);
5810 * Creates the listview control.
5813 * [I] HWND : window handle
5818 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5820 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5821 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5822 UINT uView = lpcs->style & LVS_TYPEMASK;
5825 /* initialize info pointer */
5826 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5828 /* determine the type of structures to use */
5829 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5830 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5831 if (infoPtr->notifyFormat != NFR_ANSI)
5833 FIXME("ANSI notify format is NOT used\n");
5836 /* initialize color information */
5837 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5838 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5839 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5841 /* set default values */
5842 infoPtr->uCallbackMask = 0;
5843 infoPtr->nFocusedItem = -1;
5844 infoPtr->nSelectionMark = -1;
5845 infoPtr->nHotItem = -1;
5846 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5847 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5848 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5849 infoPtr->hwndEdit = 0;
5850 infoPtr->pedititem = NULL;
5851 infoPtr->bDoEditLabel = FALSE;
5853 /* get default font (icon title) */
5854 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5855 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5856 infoPtr->hFont = infoPtr->hDefaultFont;
5859 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5860 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5861 0, 0, 0, 0, hwnd, (HMENU)0,
5862 lpcs->hInstance, NULL);
5864 /* set header font */
5865 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5868 if (uView == LVS_ICON)
5870 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5871 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5873 else if (uView == LVS_REPORT)
5875 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5877 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5880 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5881 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5885 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5886 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5889 /* display unsupported listview window styles */
5890 LISTVIEW_UnsupportedStyles(lpcs->style);
5892 /* allocate memory for the data structure */
5893 infoPtr->hdpaItems = DPA_Create(10);
5895 /* initialize size of items */
5896 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5897 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
5904 * Erases the background of the listview control.
5907 * [I] HWND : window handle
5908 * [I] WPARAM : device context handle
5909 * [I] LPARAM : not used
5915 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5918 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5921 if (infoPtr->clrBk == CLR_NONE)
5923 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5928 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5929 GetClientRect(hwnd, &rc);
5930 FillRect((HDC)wParam, &rc, hBrush);
5931 DeleteObject(hBrush);
5940 * Retrieves the listview control font.
5943 * [I] HWND : window handle
5948 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5950 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5952 return infoPtr->hFont;
5957 * Performs vertical scrolling.
5960 * [I] HWND : window handle
5961 * [I] INT : scroll code
5962 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5964 * [I] HWND : scrollbar control window handle
5969 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5972 SCROLLINFO scrollInfo;
5974 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5975 scrollInfo.cbSize = sizeof(SCROLLINFO);
5976 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
5978 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5980 INT nOldScrollPos = scrollInfo.nPos;
5981 switch (nScrollCode)
5984 if (scrollInfo.nPos > scrollInfo.nMin)
5991 if (scrollInfo.nPos < scrollInfo.nMax)
5998 if (scrollInfo.nPos > scrollInfo.nMin)
6000 if (scrollInfo.nPos >= scrollInfo.nPage)
6002 scrollInfo.nPos -= scrollInfo.nPage;
6006 scrollInfo.nPos = scrollInfo.nMin;
6012 if (scrollInfo.nPos < scrollInfo.nMax)
6014 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6016 scrollInfo.nPos += scrollInfo.nPage;
6020 scrollInfo.nPos = scrollInfo.nMax;
6026 scrollInfo.nPos = nCurrentPos;
6027 if (scrollInfo.nPos > scrollInfo.nMax)
6028 scrollInfo.nPos=scrollInfo.nMax;
6030 if (scrollInfo.nPos < scrollInfo.nMin)
6031 scrollInfo.nPos=scrollInfo.nMin;
6036 if (nOldScrollPos != scrollInfo.nPos)
6038 scrollInfo.fMask = SIF_POS;
6039 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
6040 InvalidateRect(hwnd, NULL, TRUE);
6049 * Performs horizontal scrolling.
6052 * [I] HWND : window handle
6053 * [I] INT : scroll code
6054 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6056 * [I] HWND : scrollbar control window handle
6061 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6064 SCROLLINFO scrollInfo;
6066 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6067 scrollInfo.cbSize = sizeof(SCROLLINFO);
6068 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6070 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6072 INT nOldScrollPos = scrollInfo.nPos;
6074 switch (nScrollCode)
6077 if (scrollInfo.nPos > scrollInfo.nMin)
6084 if (scrollInfo.nPos < scrollInfo.nMax)
6091 if (scrollInfo.nPos > scrollInfo.nMin)
6093 if (scrollInfo.nPos >= scrollInfo.nPage)
6095 scrollInfo.nPos -= scrollInfo.nPage;
6099 scrollInfo.nPos = scrollInfo.nMin;
6105 if (scrollInfo.nPos < scrollInfo.nMax)
6107 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6109 scrollInfo.nPos += scrollInfo.nPage;
6113 scrollInfo.nPos = scrollInfo.nMax;
6119 scrollInfo.nPos = nCurrentPos;
6121 if (scrollInfo.nPos > scrollInfo.nMax)
6122 scrollInfo.nPos=scrollInfo.nMax;
6124 if (scrollInfo.nPos < scrollInfo.nMin)
6125 scrollInfo.nPos=scrollInfo.nMin;
6129 if (nOldScrollPos != scrollInfo.nPos)
6131 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6132 scrollInfo.fMask = SIF_POS;
6133 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6134 if(uView == LVS_REPORT)
6136 scrollInfo.fMask = SIF_POS;
6137 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6138 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6140 InvalidateRect(hwnd, NULL, TRUE);
6147 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
6149 INT gcWheelDelta = 0;
6150 UINT pulScrollLines = 3;
6151 SCROLLINFO scrollInfo;
6153 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6155 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
6156 gcWheelDelta -= wheelDelta;
6158 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6159 scrollInfo.cbSize = sizeof(SCROLLINFO);
6160 scrollInfo.fMask = SIF_POS | SIF_RANGE;
6167 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
6168 * should be fixed in the future.
6170 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6171 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
6175 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
6177 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6179 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
6180 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
6181 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
6187 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
6198 * [I] HWND : window handle
6199 * [I] INT : virtual key
6200 * [I] LONG : key data
6205 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6207 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6208 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6209 HWND hwndParent = GetParent(hwnd);
6210 NMLVKEYDOWN nmKeyDown;
6213 BOOL bRedraw = FALSE;
6215 /* send LVN_KEYDOWN notification */
6216 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6217 nmKeyDown.hdr.hwndFrom = hwnd;
6218 nmKeyDown.hdr.idFrom = nCtrlId;
6219 nmKeyDown.hdr.code = LVN_KEYDOWN;
6220 nmKeyDown.wVKey = nVirtualKey;
6221 nmKeyDown.flags = 0;
6222 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6225 nmh.hwndFrom = hwnd;
6226 nmh.idFrom = nCtrlId;
6228 switch (nVirtualKey)
6231 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6233 /* send NM_RETURN notification */
6234 nmh.code = NM_RETURN;
6235 ListView_Notify(hwndParent, nCtrlId, &nmh);
6237 /* send LVN_ITEMACTIVATE notification */
6238 nmh.code = LVN_ITEMACTIVATE;
6239 ListView_Notify(hwndParent, nCtrlId, &nmh);
6244 if (GETITEMCOUNT(infoPtr) > 0)
6251 if (GETITEMCOUNT(infoPtr) > 0)
6253 nItem = GETITEMCOUNT(infoPtr) - 1;
6258 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6262 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6266 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6270 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6282 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6284 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6285 if (bRedraw != FALSE)
6287 /* refresh client area */
6288 InvalidateRect(hwnd, NULL, TRUE);
6301 * [I] HWND : window handle
6306 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6308 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6309 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6312 TRACE("(hwnd=%x)\n", hwnd);
6314 /* send NM_KILLFOCUS notification */
6315 nmh.hwndFrom = hwnd;
6316 nmh.idFrom = nCtrlId;
6317 nmh.code = NM_KILLFOCUS;
6318 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6320 /* set window focus flag */
6321 infoPtr->bFocus = FALSE;
6323 /* NEED drawing optimization ; redraw the selected items */
6324 InvalidateRect(hwnd, NULL, FALSE);
6331 * Processes double click messages (left mouse button).
6334 * [I] HWND : window handle
6335 * [I] WORD : key flag
6336 * [I] WORD : x coordinate
6337 * [I] WORD : y coordinate
6342 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6345 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6347 LVHITTESTINFO htInfo;
6349 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6351 /* send NM_DBLCLK notification */
6352 nmh.hwndFrom = hwnd;
6353 nmh.idFrom = nCtrlId;
6354 nmh.code = NM_DBLCLK;
6355 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6357 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
6358 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6359 htInfo.pt.x = wPosX;
6360 htInfo.pt.y = wPosY;
6361 if(LISTVIEW_HitTest(hwnd, &htInfo) != -1)
6363 /* send LVN_ITEMACTIVATE notification */
6364 nmh.code = LVN_ITEMACTIVATE;
6365 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6373 * Processes mouse down messages (left mouse button).
6376 * [I] HWND : window handle
6377 * [I] WORD : key flag
6378 * [I] WORD : x coordinate
6379 * [I] WORD : y coordinate
6384 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6387 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6388 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6389 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6390 static BOOL bGroupSelect = TRUE;
6395 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6398 /* send NM_RELEASEDCAPTURE notification */
6399 nmh.hwndFrom = hwnd;
6400 nmh.idFrom = nCtrlId;
6401 nmh.code = NM_RELEASEDCAPTURE;
6402 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6404 if (infoPtr->bFocus == FALSE)
6409 /* set left button down flag */
6410 infoPtr->bLButtonDown = TRUE;
6412 ptPosition.x = wPosX;
6413 ptPosition.y = wPosY;
6414 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6415 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6417 if (lStyle & LVS_SINGLESEL)
6419 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
6420 && infoPtr->bDoEditLabel != TRUE)
6422 infoPtr->bDoEditLabel = TRUE;
6426 LISTVIEW_SetSelection(hwnd, nItem);
6431 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6433 if (bGroupSelect != FALSE)
6435 LISTVIEW_AddGroupSelection(hwnd, nItem);
6439 LISTVIEW_AddSelection(hwnd, nItem);
6442 else if (wKey & MK_CONTROL)
6444 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6446 else if (wKey & MK_SHIFT)
6448 LISTVIEW_SetGroupSelection(hwnd, nItem);
6452 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED
6453 && infoPtr->bDoEditLabel != TRUE)
6455 infoPtr->bDoEditLabel = TRUE;
6459 LISTVIEW_SetSelection(hwnd, nItem);
6467 /* remove all selections */
6468 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6471 InvalidateRect(hwnd, NULL, TRUE);
6478 * Processes mouse up messages (left mouse button).
6481 * [I] HWND : window handle
6482 * [I] WORD : key flag
6483 * [I] WORD : x coordinate
6484 * [I] WORD : y coordinate
6489 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6492 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6494 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6496 if (infoPtr->bLButtonDown != FALSE)
6498 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6501 /* send NM_CLICK notification */
6502 nmh.hwndFrom = hwnd;
6503 nmh.idFrom = nCtrlId;
6504 nmh.code = NM_CLICK;
6505 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6507 /* set left button flag */
6508 infoPtr->bLButtonDown = FALSE;
6510 if(infoPtr->bDoEditLabel)
6512 LVHITTESTINFO htInfo;
6514 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6515 htInfo.pt.x = wPosX;
6516 htInfo.pt.y = wPosY;
6517 nItem = LISTVIEW_HitTest(hwnd, &htInfo);
6518 if(nItem != -1 && htInfo.flags == LVHT_ONITEMLABEL)
6520 LISTVIEW_EditLabelA(hwnd, nItem);
6522 infoPtr->bDoEditLabel = FALSE;
6531 * Creates the listview control (called before WM_CREATE).
6534 * [I] HWND : window handle
6535 * [I] WPARAM : unhandled
6536 * [I] LPARAM : widow creation info
6541 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6543 LISTVIEW_INFO *infoPtr;
6545 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6547 /* allocate memory for info structure */
6548 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6549 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6550 if (infoPtr == NULL)
6552 ERR("could not allocate info memory!\n");
6556 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6558 ERR("pointer assignment error!\n");
6562 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6567 * Destroys the listview control (called after WM_DESTROY).
6570 * [I] HWND : window handle
6575 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6577 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6579 TRACE("(hwnd=%x)\n", hwnd);
6581 /* delete all items */
6582 LISTVIEW_DeleteAllItems(hwnd);
6584 /* destroy data structure */
6585 DPA_Destroy(infoPtr->hdpaItems);
6588 infoPtr->hFont = (HFONT)0;
6589 if (infoPtr->hDefaultFont)
6591 DeleteObject(infoPtr->hDefaultFont);
6594 /* free listview info pointer*/
6595 COMCTL32_Free(infoPtr);
6602 * Handles notifications from children.
6605 * [I] HWND : window handle
6606 * [I] INT : control identifier
6607 * [I] LPNMHDR : notification information
6612 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6614 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6616 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6618 /* handle notification from header control */
6619 if (lpnmh->code == HDN_ENDTRACKA)
6621 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6622 InvalidateRect(hwnd, NULL, TRUE);
6624 else if(lpnmh->code == HDN_ITEMCLICKA)
6626 /* Handle sorting by Header Column */
6628 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6629 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6631 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6632 nmlv.hdr.hwndFrom = hwnd;
6633 nmlv.hdr.idFrom = lCtrlId;
6634 nmlv.hdr.code = LVN_COLUMNCLICK;
6636 nmlv.iSubItem = pnmHeader->iItem;
6638 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6641 else if(lpnmh->code == NM_RELEASEDCAPTURE)
6643 /* Idealy this should be done in HDN_ENDTRACKA
6644 * but since SetItemBounds in Header.c is called after
6645 * the notification is sent, it is neccessary to handle the
6646 * update of the scroll bar here (Header.c works fine as it is,
6647 * no need to disturb it)
6649 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6650 LISTVIEW_UpdateScroll(hwnd);
6651 InvalidateRect(hwnd, NULL, TRUE);
6661 * Determines the type of structure to use.
6664 * [I] HWND : window handle of the sender
6665 * [I] HWND : listview window handle
6666 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6671 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6673 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6675 if (nCommand == NF_REQUERY)
6677 /* determine the type of structure to use */
6678 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6679 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6680 if (infoPtr->notifyFormat == NFR_UNICODE)
6682 FIXME("NO support for unicode structures");
6691 * Paints/Repaints the listview control.
6694 * [I] HWND : window handle
6695 * [I] HDC : device context handle
6700 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6704 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6708 hdc = BeginPaint(hwnd, &ps);
6709 LISTVIEW_Refresh(hwnd, hdc);
6710 EndPaint(hwnd, &ps);
6714 LISTVIEW_Refresh(hwnd, hdc);
6722 * Processes double click messages (right mouse button).
6725 * [I] HWND : window handle
6726 * [I] WORD : key flag
6727 * [I] WORD : x coordinate
6728 * [I] WORD : y coordinate
6733 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6736 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6739 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6741 /* send NM_RELEASEDCAPTURE notification */
6742 nmh.hwndFrom = hwnd;
6743 nmh.idFrom = nCtrlId;
6744 nmh.code = NM_RELEASEDCAPTURE;
6745 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6747 /* send NM_RDBLCLK notification */
6748 nmh.code = NM_RDBLCLK;
6749 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6756 * Processes mouse down messages (right mouse button).
6759 * [I] HWND : window handle
6760 * [I] WORD : key flag
6761 * [I] WORD : x coordinate
6762 * [I] WORD : y coordinate
6767 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6770 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6771 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6776 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6778 /* send NM_RELEASEDCAPTURE notification */
6779 nmh.hwndFrom = hwnd;
6780 nmh.idFrom = nCtrlId;
6781 nmh.code = NM_RELEASEDCAPTURE;
6782 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6784 /* make sure the listview control window has the focus */
6785 if (infoPtr->bFocus == FALSE)
6790 /* set right button down flag */
6791 infoPtr->bRButtonDown = TRUE;
6793 /* determine the index of the selected item */
6794 ptPosition.x = wPosX;
6795 ptPosition.y = wPosY;
6796 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6797 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6799 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6801 LISTVIEW_SetSelection(hwnd, nItem);
6806 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6814 * Processes mouse up messages (right mouse button).
6817 * [I] HWND : window handle
6818 * [I] WORD : key flag
6819 * [I] WORD : x coordinate
6820 * [I] WORD : y coordinate
6825 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6828 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6829 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6832 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6834 if (infoPtr->bRButtonDown != FALSE)
6840 /* Send NM_RClICK notification */
6841 ZeroMemory(&nmh, sizeof(NMHDR));
6842 nmh.hwndFrom = hwnd;
6843 nmh.idFrom = nCtrlId;
6844 nmh.code = NM_RCLICK;
6845 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6847 /* set button flag */
6848 infoPtr->bRButtonDown = FALSE;
6850 /* Change to screen coordinate for WM_CONTEXTMENU */
6851 ClientToScreen(hwnd, &pt);
6853 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
6854 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
6865 * [I] HWND : window handle
6866 * [I] HWND : window handle of previously focused window
6871 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6873 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6874 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6877 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
6879 /* send NM_SETFOCUS notification */
6880 nmh.hwndFrom = hwnd;
6881 nmh.idFrom = nCtrlId;
6882 nmh.code = NM_SETFOCUS;
6883 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6885 /* set window focus flag */
6886 infoPtr->bFocus = TRUE;
6888 InvalidateRect(hwnd, NULL, TRUE);
6899 * [I] HWND : window handle
6900 * [I] HFONT : font handle
6901 * [I] WORD : redraw flag
6906 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6908 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6909 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6911 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6915 infoPtr->hFont = infoPtr->hDefaultFont;
6919 infoPtr->hFont = hFont;
6922 if (uView == LVS_REPORT)
6924 /* set header font */
6925 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6926 MAKELPARAM(fRedraw, 0));
6929 /* invalidate listview control client area */
6930 InvalidateRect(hwnd, NULL, TRUE);
6932 if (fRedraw != FALSE)
6942 * Message handling for WM_SETREDRAW.
6943 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
6946 * [I] HWND : window handle
6947 * [I] bRedraw: state of redraw flag
6950 * DefWinProc return value
6952 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
6955 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
6958 RedrawWindow(hwnd, NULL, 0,
6959 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
6966 * Resizes the listview control. This function processes WM_SIZE
6967 * messages. At this time, the width and height are not used.
6970 * [I] HWND : window handle
6971 * [I] WORD : new width
6972 * [I] WORD : new height
6977 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6979 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6980 UINT uView = lStyle & LVS_TYPEMASK;
6982 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
6984 LISTVIEW_UpdateSize(hwnd);
6986 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6988 if (lStyle & LVS_ALIGNLEFT)
6990 LISTVIEW_AlignLeft(hwnd);
6994 LISTVIEW_AlignTop(hwnd);
6998 LISTVIEW_UpdateScroll(hwnd);
7000 /* invalidate client area + erase background */
7001 InvalidateRect(hwnd, NULL, TRUE);
7008 * Sets the size information.
7011 * [I] HWND : window handle
7016 static VOID LISTVIEW_UpdateSize(HWND hwnd)
7018 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7019 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7020 UINT uView = lStyle & LVS_TYPEMASK;
7023 GetClientRect(hwnd, &rcList);
7024 infoPtr->rcList.left = 0;
7025 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
7026 infoPtr->rcList.top = 0;
7027 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
7029 if (uView == LVS_LIST)
7031 if ((lStyle & WS_HSCROLL) == 0)
7033 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
7034 if (infoPtr->rcList.bottom > nHScrollHeight)
7036 infoPtr->rcList.bottom -= nHScrollHeight;
7040 else if (uView == LVS_REPORT)
7047 Header_Layout(infoPtr->hwndHeader, &hl);
7048 if (!(LVS_NOCOLUMNHEADER & lStyle))
7050 infoPtr->rcList.top = max(wp.cy, 0);
7057 * Processes WM_STYLECHANGED messages.
7060 * [I] HWND : window handle
7061 * [I] WPARAM : window style type (normal or extended)
7062 * [I] LPSTYLESTRUCT : window style information
7067 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
7070 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7071 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
7072 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
7073 RECT rcList = infoPtr->rcList;
7075 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
7076 hwnd, wStyleType, lpss);
7078 if (wStyleType == GWL_STYLE)
7080 if (uOldView == LVS_REPORT)
7082 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
7085 if ((lpss->styleOld & WS_HSCROLL) != 0)
7087 ShowScrollBar(hwnd, SB_HORZ, FALSE);
7090 if ((lpss->styleOld & WS_VSCROLL) != 0)
7092 ShowScrollBar(hwnd, SB_VERT, FALSE);
7095 if (uNewView == LVS_ICON)
7097 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7098 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7099 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7100 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7101 if (lpss->styleNew & LVS_ALIGNLEFT)
7103 LISTVIEW_AlignLeft(hwnd);
7107 LISTVIEW_AlignTop(hwnd);
7110 else if (uNewView == LVS_REPORT)
7117 Header_Layout(infoPtr->hwndHeader, &hl);
7118 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
7120 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
7122 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7124 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7125 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7126 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7127 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7129 else if (uNewView == LVS_LIST)
7131 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7132 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7133 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7134 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7138 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7139 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7140 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7141 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7142 if (lpss->styleNew & LVS_ALIGNLEFT)
7144 LISTVIEW_AlignLeft(hwnd);
7148 LISTVIEW_AlignTop(hwnd);
7152 /* update the size of the client area */
7153 LISTVIEW_UpdateSize(hwnd);
7155 /* add scrollbars if needed */
7156 LISTVIEW_UpdateScroll(hwnd);
7158 /* invalidate client area + erase background */
7159 InvalidateRect(hwnd, NULL, TRUE);
7161 /* print the list of unsupported window styles */
7162 LISTVIEW_UnsupportedStyles(lpss->styleNew);
7165 /* If they change the view and we have an active edit control
7166 we will need to kill the control since the redraw will
7167 misplace the edit control.
7169 if (infoPtr->hwndEdit &&
7170 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
7171 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
7173 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7181 * Window procedure of the listview control.
7184 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
7189 case LVM_APPROXIMATEVIEWRECT:
7190 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
7191 LOWORD(lParam), HIWORD(lParam));
7193 return LISTVIEW_Arrange(hwnd, (INT)wParam);
7195 /* case LVM_CREATEDRAGIMAGE: */
7197 case LVM_DELETEALLITEMS:
7198 return LISTVIEW_DeleteAllItems(hwnd);
7200 case LVM_DELETECOLUMN:
7201 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
7203 case LVM_DELETEITEM:
7204 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
7206 case LVM_EDITLABELW:
7207 case LVM_EDITLABELA:
7208 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
7210 case LVM_ENSUREVISIBLE:
7211 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
7214 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
7216 case LVM_GETBKCOLOR:
7217 return LISTVIEW_GetBkColor(hwnd);
7219 /* case LVM_GETBKIMAGE: */
7221 case LVM_GETCALLBACKMASK:
7222 return LISTVIEW_GetCallbackMask(hwnd);
7224 case LVM_GETCOLUMNA:
7225 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7227 /* case LVM_GETCOLUMNW: */
7229 case LVM_GETCOLUMNORDERARRAY:
7230 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7232 case LVM_GETCOLUMNWIDTH:
7233 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
7235 case LVM_GETCOUNTPERPAGE:
7236 return LISTVIEW_GetCountPerPage(hwnd);
7238 case LVM_GETEDITCONTROL:
7239 return LISTVIEW_GetEditControl(hwnd);
7241 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7242 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7245 return LISTVIEW_GetHeader(hwnd);
7247 /* case LVM_GETHOTCURSOR: */
7249 case LVM_GETHOTITEM:
7250 return LISTVIEW_GetHotItem(hwnd);
7252 /* case LVM_GETHOVERTIME: */
7254 case LVM_GETIMAGELIST:
7255 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7257 /* case LVM_GETISEARCHSTRING: */
7260 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
7262 /* case LVM_GETITEMW: */
7264 case LVM_GETITEMCOUNT:
7265 return LISTVIEW_GetItemCount(hwnd);
7267 case LVM_GETITEMPOSITION:
7268 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7270 case LVM_GETITEMRECT:
7271 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7273 case LVM_GETITEMSPACING:
7274 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7276 case LVM_GETITEMSTATE:
7277 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7279 case LVM_GETITEMTEXTA:
7280 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7283 /* case LVM_GETITEMTEXTW: */
7285 case LVM_GETNEXTITEM:
7286 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7288 /* case LVM_GETNUMBEROFWORKAREAS: */
7291 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7293 case LVM_GETSELECTEDCOUNT:
7294 return LISTVIEW_GetSelectedCount(hwnd);
7296 case LVM_GETSELECTIONMARK:
7297 return LISTVIEW_GetSelectionMark(hwnd);
7299 case LVM_GETSTRINGWIDTHA:
7300 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7302 /* case LVM_GETSTRINGWIDTHW: */
7303 /* case LVM_GETSUBITEMRECT: */
7305 case LVM_GETTEXTBKCOLOR:
7306 return LISTVIEW_GetTextBkColor(hwnd);
7308 case LVM_GETTEXTCOLOR:
7309 return LISTVIEW_GetTextColor(hwnd);
7311 /* case LVM_GETTOOLTIPS: */
7313 case LVM_GETTOPINDEX:
7314 return LISTVIEW_GetTopIndex(hwnd);
7316 /* case LVM_GETUNICODEFORMAT: */
7318 case LVM_GETVIEWRECT:
7319 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7321 /* case LVM_GETWORKAREAS: */
7324 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7326 case LVM_INSERTCOLUMNA:
7327 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7329 case LVM_INSERTCOLUMNW:
7330 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7332 case LVM_INSERTITEMA:
7333 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7335 case LVM_INSERTITEMW:
7336 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7338 case LVM_REDRAWITEMS:
7339 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7341 /* case LVM_SCROLL: */
7342 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7344 case LVM_SETBKCOLOR:
7345 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7347 /* case LVM_SETBKIMAGE: */
7349 case LVM_SETCALLBACKMASK:
7350 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7352 case LVM_SETCOLUMNA:
7353 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7355 case LVM_SETCOLUMNW:
7356 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7359 case LVM_SETCOLUMNORDERARRAY:
7360 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7362 case LVM_SETCOLUMNWIDTH:
7363 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
7365 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7366 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7368 /* case LVM_SETHOTCURSOR: */
7370 case LVM_SETHOTITEM:
7371 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7373 /* case LVM_SETHOVERTIME: */
7374 /* case LVM_SETICONSPACING: */
7376 case LVM_SETIMAGELIST:
7377 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7380 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7382 /* case LVM_SETITEMW: */
7384 case LVM_SETITEMCOUNT:
7385 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7387 case LVM_SETITEMPOSITION:
7388 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7389 (INT)HIWORD(lParam));
7391 /* case LVM_SETITEMPOSITION32: */
7393 case LVM_SETITEMSTATE:
7394 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7396 case LVM_SETITEMTEXTA:
7397 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7399 /* case LVM_SETITEMTEXTW: */
7401 case LVM_SETSELECTIONMARK:
7402 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7404 case LVM_SETTEXTBKCOLOR:
7405 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7407 case LVM_SETTEXTCOLOR:
7408 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7410 /* case LVM_SETTOOLTIPS: */
7411 /* case LVM_SETUNICODEFORMAT: */
7412 /* case LVM_SETWORKAREAS: */
7415 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7417 /* case LVM_SUBITEMHITTEST: */
7420 return LISTVIEW_Update(hwnd, (INT)wParam);
7424 return LISTVIEW_Command(hwnd, wParam, lParam);
7427 return LISTVIEW_Create(hwnd, wParam, lParam);
7430 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7433 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7436 return LISTVIEW_GetFont(hwnd);
7439 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7440 (INT)HIWORD(wParam), (HWND)lParam);
7443 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7446 return LISTVIEW_KillFocus(hwnd);
7448 case WM_LBUTTONDBLCLK:
7449 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7452 case WM_LBUTTONDOWN:
7453 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7456 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7459 /* case WM_MOUSEMOVE: */
7460 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
7463 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7466 return LISTVIEW_NCDestroy(hwnd);
7469 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7471 case WM_NOTIFYFORMAT:
7472 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7475 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7477 case WM_RBUTTONDBLCLK:
7478 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7481 case WM_RBUTTONDOWN:
7482 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7486 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7490 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7493 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7496 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
7499 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7501 case WM_STYLECHANGED:
7502 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7504 /* case WM_TIMER: */
7507 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7508 (INT)HIWORD(wParam), (HWND)lParam);
7511 if (wParam & (MK_SHIFT | MK_CONTROL))
7512 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
7513 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
7515 /* case WM_WININICHANGE: */
7518 if (uMsg >= WM_USER)
7520 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7524 /* call default window procedure */
7525 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7533 * Registers the window class.
7541 VOID LISTVIEW_Register(void)
7545 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7546 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7547 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7548 wndClass.cbClsExtra = 0;
7549 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7550 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7551 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7552 wndClass.lpszClassName = WC_LISTVIEWA;
7553 RegisterClassA(&wndClass);
7558 * Unregisters the window class.
7566 VOID LISTVIEW_Unregister(void)
7568 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
7573 * Handle any WM_COMMAND messages
7579 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
7581 switch (HIWORD(wParam))
7586 * Adjust the edit window size
7589 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7590 HDC hdc = GetDC(infoPtr->hwndEdit);
7591 HFONT hFont, hOldFont = 0;
7596 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
7597 GetWindowRect(infoPtr->hwndEdit, &rect);
7599 /* Select font to get the right dimension of the string */
7600 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
7603 hOldFont = SelectObject(hdc, hFont);
7606 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
7608 TEXTMETRICA textMetric;
7610 /* Add Extra spacing for the next character */
7611 GetTextMetricsA(hdc, &textMetric);
7612 sz.cx += (textMetric.tmMaxCharWidth * 2);
7620 rect.bottom - rect.top,
7621 SWP_DRAWFRAME|SWP_NOMOVE);
7625 SelectObject(hdc, hOldFont);
7628 ReleaseDC(hwnd, hdc);
7634 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
7643 * Subclassed edit control windproc function
7649 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
7650 WPARAM wParam, LPARAM lParam)
7652 BOOL cancel = FALSE;
7653 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
7654 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
7655 static BOOL bIgnoreKillFocus = FALSE;
7659 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
7662 if(bIgnoreKillFocus)
7670 WNDPROC editProc = einfo->EditWndProc;
7671 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
7672 COMCTL32_Free(einfo);
7673 infoPtr->pedititem = NULL;
7674 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
7678 if (VK_ESCAPE == (INT)wParam)
7684 else if (VK_RETURN == (INT)wParam)
7688 return CallWindowProcA(einfo->EditWndProc, hwnd,
7689 uMsg, wParam, lParam);
7692 if (einfo->EditLblCb)
7694 char *buffer = NULL;
7699 int len = 1 + GetWindowTextLengthA(hwnd);
7703 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
7705 GetWindowTextA(hwnd, buffer, len);
7709 /* Processing LVN_ENDLABELEDIT message could kill the focus */
7710 /* eg. Using a messagebox */
7711 bIgnoreKillFocus = TRUE;
7712 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
7715 COMCTL32_Free(buffer);
7717 einfo->EditLblCb = NULL;
7718 bIgnoreKillFocus = FALSE;
7721 SendMessageA(hwnd, WM_CLOSE, 0, 0);
7728 * Creates a subclassed edit cotrol
7734 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
7735 INT width, INT height, HWND parent, HINSTANCE hinst,
7736 EditlblCallback EditLblCb, DWORD param)
7742 TEXTMETRICA textMetric;
7743 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
7745 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
7748 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
7749 hdc = GetDC(parent);
7751 /* Select the font to get appropriate metric dimensions */
7752 if(infoPtr->hFont != 0)
7754 hOldFont = SelectObject(hdc, infoPtr->hFont);
7757 /*Get String Lenght in pixels */
7758 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
7760 /*Add Extra spacing for the next character */
7761 GetTextMetricsA(hdc, &textMetric);
7762 sz.cx += (textMetric.tmMaxCharWidth * 2);
7764 if(infoPtr->hFont != 0)
7766 SelectObject(hdc, hOldFont);
7769 ReleaseDC(parent, hdc);
7770 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
7771 parent, 0, hinst, 0)))
7773 COMCTL32_Free(infoPtr->pedititem);
7777 infoPtr->pedititem->param = param;
7778 infoPtr->pedititem->EditLblCb = EditLblCb;
7779 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
7780 GWL_WNDPROC, (LONG) EditLblWndProc);
7782 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);