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);
142 /*************************************************************************
143 * LISTVIEW_UpdateHeaderSize [Internal]
145 * Function to resize the header control
148 * hwnd [I] handle to a window
149 * nNewScrollPos [I] Scroll Pos to Set
156 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
158 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
162 GetWindowRect(infoPtr->hwndHeader, &winRect);
163 point[0].x = winRect.left;
164 point[0].y = winRect.top;
165 point[1].x = winRect.right;
166 point[1].y = winRect.bottom;
168 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
169 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
170 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
172 SetWindowPos(infoPtr->hwndHeader,0,
173 point[0].x,point[0].y,point[1].x,point[1].y,
174 SWP_NOZORDER | SWP_NOACTIVATE);
179 * Update the scrollbars. This functions should be called whenever
180 * the content, size or view changes.
183 * [I] HWND : window handle
188 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
190 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
191 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
192 UINT uView = lStyle & LVS_TYPEMASK;
193 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
194 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
195 SCROLLINFO scrollInfo;
197 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
198 scrollInfo.cbSize = sizeof(SCROLLINFO);
200 if (uView == LVS_LIST)
202 /* update horizontal scrollbar */
204 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
205 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
206 INT nCountPerPage = nCountPerRow * nCountPerColumn;
207 INT nNumOfItems = GETITEMCOUNT(infoPtr);
209 if (nCountPerPage < GETITEMCOUNT(infoPtr))
211 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
212 if((nNumOfItems % nCountPerColumn) == 0)
216 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
217 scrollInfo.nPage = nCountPerRow;
218 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
219 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
224 if (lStyle & WS_HSCROLL)
226 ShowScrollBar(hwnd, SB_HORZ, FALSE);
230 else if (uView == LVS_REPORT)
232 /* update vertical scrollbar */
234 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
235 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
236 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
237 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
238 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
240 /* update horizontal scrollbar */
241 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
246 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
247 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
248 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
249 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
251 /* Update the Header Control */
252 scrollInfo.fMask = SIF_POS;
253 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
254 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
261 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
263 INT nViewWidth = rcView.right - rcView.left;
264 INT nViewHeight = rcView.bottom - rcView.top;
266 if (nViewWidth > nListWidth)
268 scrollInfo.fMask = SIF_POS;
269 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
273 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
275 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
276 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
277 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
281 if (lStyle & WS_HSCROLL)
283 ShowScrollBar(hwnd, SB_HORZ, FALSE);
287 if (nViewHeight > nListHeight)
289 scrollInfo.fMask = SIF_POS;
290 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE)
294 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
296 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
297 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
298 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
302 if (lStyle & WS_VSCROLL)
304 ShowScrollBar(hwnd, SB_VERT, FALSE);
313 * Prints a message for unsupported window styles.
314 * A kind of TODO list for window styles.
317 * [I] LONG : window style
322 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
324 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
326 FIXME(" LVS_EDITLABELS\n");
329 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
331 FIXME(" LVS_NOLABELWRAP\n");
334 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
336 FIXME(" LVS_NOSCROLL\n");
339 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
341 FIXME(" LVS_NOSORTHEADER\n");
344 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
346 FIXME(" LVS_OWNERDRAWFIXED\n");
349 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
351 FIXME(" LVS_SHAREIMAGELISTS\n");
354 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
356 FIXME(" LVS_SORTASCENDING\n");
359 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
361 FIXME(" LVS_SORTDESCENDING\n");
367 * Aligns the items with the top edge of the window.
370 * [I] HWND : window handle
375 static VOID LISTVIEW_AlignTop(HWND hwnd)
377 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
378 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
379 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
384 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
386 ZeroMemory(&ptItem, sizeof(POINT));
387 ZeroMemory(&rcView, sizeof(RECT));
389 if (nListWidth > infoPtr->nItemWidth)
391 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
393 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
396 ptItem.y += infoPtr->nItemHeight;
399 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
400 ptItem.x += infoPtr->nItemWidth;
401 rcView.right = max(rcView.right, ptItem.x);
404 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
408 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
410 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
411 ptItem.y += infoPtr->nItemHeight;
414 rcView.right = infoPtr->nItemWidth;
415 rcView.bottom = ptItem.y;
418 LISTVIEW_SetViewRect(hwnd, &rcView);
424 * Aligns the items with the left edge of the window.
427 * [I] HWND : window handle
432 static VOID LISTVIEW_AlignLeft(HWND hwnd)
434 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
435 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
436 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
441 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
443 ZeroMemory(&ptItem, sizeof(POINT));
444 ZeroMemory(&rcView, sizeof(RECT));
446 if (nListHeight > infoPtr->nItemHeight)
448 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
450 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
453 ptItem.x += infoPtr->nItemWidth;
456 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
457 ptItem.y += infoPtr->nItemHeight;
458 rcView.bottom = max(rcView.bottom, ptItem.y);
461 rcView.right = ptItem.x + infoPtr->nItemWidth;
465 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
467 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
468 ptItem.x += infoPtr->nItemWidth;
471 rcView.bottom = infoPtr->nItemHeight;
472 rcView.right = ptItem.x;
475 LISTVIEW_SetViewRect(hwnd, &rcView);
481 * Set the bounding rectangle of all the items.
484 * [I] HWND : window handle
485 * [I] LPRECT : bounding rectangle
491 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
493 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
494 BOOL bResult = FALSE;
496 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
497 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
499 if (lprcView != NULL)
502 infoPtr->rcView.left = lprcView->left;
503 infoPtr->rcView.top = lprcView->top;
504 infoPtr->rcView.right = lprcView->right;
505 infoPtr->rcView.bottom = lprcView->bottom;
513 * Retrieves the bounding rectangle of all the items.
516 * [I] HWND : window handle
517 * [O] LPRECT : bounding rectangle
523 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
525 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
526 BOOL bResult = FALSE;
529 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
531 if (lprcView != NULL)
533 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
534 if (bResult != FALSE)
536 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
537 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
538 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
539 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
542 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
543 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
551 * Retrieves the subitem pointer associated with the subitem index.
554 * [I] HDPA : DPA handle for a specific item
555 * [I] INT : index of subitem
558 * SUCCESS : subitem pointer
561 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
564 LISTVIEW_SUBITEM *lpSubItem;
567 for (i = 1; i < hdpaSubItems->nItemCount; i++)
569 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
570 if (lpSubItem != NULL)
572 if (lpSubItem->iSubItem == nSubItem)
584 * Calculates the width of an item.
587 * [I] HWND : window handle
588 * [I] LONG : window style
591 * Returns item width.
593 static INT LISTVIEW_GetItemWidth(HWND hwnd)
595 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
596 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
597 INT nHeaderItemCount;
603 TRACE("(hwnd=%x)\n", hwnd);
605 if (uView == LVS_ICON)
607 nItemWidth = infoPtr->iconSpacing.cx;
609 else if (uView == LVS_REPORT)
611 /* calculate width of header */
612 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
613 for (i = 0; i < nHeaderItemCount; i++)
615 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
617 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
623 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
625 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
626 nItemWidth = max(nItemWidth, nLabelWidth);
629 /* default label size */
630 if (GETITEMCOUNT(infoPtr) == 0)
632 nItemWidth = DEFAULT_COLUMN_WIDTH;
638 nItemWidth = DEFAULT_LABEL_WIDTH;
643 nItemWidth += WIDTH_PADDING;
645 if (infoPtr->himlSmall != NULL)
647 nItemWidth += infoPtr->iconSize.cx;
650 if (infoPtr->himlState != NULL)
652 nItemWidth += infoPtr->iconSize.cx;
663 * Calculates the width of a specific item.
666 * [I] HWND : window handle
670 * Returns the width of an item width a specified string.
672 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
674 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
675 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
676 INT nHeaderItemCount;
681 TRACE("(hwnd=%x)\n", hwnd);
683 if (uView == LVS_ICON)
685 nItemWidth = infoPtr->iconSpacing.cx;
687 else if (uView == LVS_REPORT)
689 /* calculate width of header */
690 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
691 for (i = 0; i < nHeaderItemCount; i++)
693 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
695 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
701 /* get width of string */
702 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
704 /* default label size */
705 if (GETITEMCOUNT(infoPtr) == 0)
707 nItemWidth = DEFAULT_COLUMN_WIDTH;
713 nItemWidth = DEFAULT_LABEL_WIDTH;
718 nItemWidth += WIDTH_PADDING;
720 if (infoPtr->himlSmall != NULL)
722 nItemWidth += infoPtr->iconSize.cx;
725 if (infoPtr->himlState != NULL)
727 nItemWidth += infoPtr->iconSize.cx;
738 * Calculates the height of an item.
741 * [I] HWND : window handle
742 * [I] LONG : window style
745 * Returns item height.
747 static INT LISTVIEW_GetItemHeight(HWND hwnd)
749 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
750 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
753 if (uView == LVS_ICON)
755 nItemHeight = infoPtr->iconSpacing.cy;
760 HDC hdc = GetDC(hwnd);
761 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
762 GetTextMetricsA(hdc, &tm);
763 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
764 SelectObject(hdc, hOldFont);
765 ReleaseDC(hwnd, hdc);
773 * Adds a block of selections.
776 * [I] HWND : window handle
777 * [I] INT : item index
782 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
784 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
785 INT nFirst = min(infoPtr->nSelectionMark, nItem);
786 INT nLast = max(infoPtr->nSelectionMark, nItem);
790 lvItem.state = LVIS_SELECTED;
791 lvItem.stateMask= LVIS_SELECTED;
793 for (i = nFirst; i <= nLast; i++)
795 ListView_SetItemState(hwnd, i, &lvItem);
798 LISTVIEW_SetItemFocus(hwnd, nItem);
799 infoPtr->nSelectionMark = nItem;
804 * Adds a single selection.
807 * [I] HWND : window handle
808 * [I] INT : item index
813 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
815 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
818 lvItem.state = LVIS_SELECTED;
819 lvItem.stateMask= LVIS_SELECTED;
821 ListView_SetItemState(hwnd, nItem, &lvItem);
823 LISTVIEW_SetItemFocus(hwnd, nItem);
824 infoPtr->nSelectionMark = nItem;
829 * Selects or unselects an item.
832 * [I] HWND : window handle
833 * [I] INT : item index
839 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
841 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
845 lvItem.stateMask= LVIS_SELECTED;
847 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
850 ListView_SetItemState(hwnd, nItem, &lvItem);
855 lvItem.state = LVIS_SELECTED;
856 ListView_SetItemState(hwnd, nItem, &lvItem);
860 LISTVIEW_SetItemFocus(hwnd, nItem);
861 infoPtr->nSelectionMark = nItem;
868 * Selects items based on view coorddiantes.
871 * [I] HWND : window handle
872 * [I] RECT : selection rectangle
877 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
879 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
884 lvItem.stateMask = LVIS_SELECTED;
886 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
888 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
889 if (PtInRect(&rcSelRect, ptItem) != FALSE)
891 lvItem.state = LVIS_SELECTED;
898 ListView_SetItemState(hwnd, i, &lvItem);
904 * Sets a single group selection.
907 * [I] HWND : window handle
908 * [I] INT : item index
913 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
915 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
916 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
919 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
922 INT nFirst = min(infoPtr->nSelectionMark, nItem);
923 INT nLast = max(infoPtr->nSelectionMark, nItem);
924 lvItem.stateMask = LVIS_SELECTED;
926 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
928 if ((i < nFirst) || (i > nLast))
934 lvItem.state = LVIS_SELECTED;
937 ListView_SetItemState(hwnd, i, &lvItem);
945 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
946 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
947 rcSel.left = min(ptSelMark.x, ptItem.x);
948 rcSel.top = min(ptSelMark.y, ptItem.y);
949 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
950 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
951 LISTVIEW_SetSelectionRect(hwnd, rcSel);
954 LISTVIEW_SetItemFocus(hwnd, nItem);
959 * Manages the item focus.
962 * [I] HWND : window handle
963 * [I] INT : item index
966 * TRUE : focused item changed
967 * FALSE : focused item has NOT changed
969 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
971 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
972 BOOL bResult = FALSE;
975 if (infoPtr->nFocusedItem != nItem)
978 ZeroMemory(&lvItem, sizeof(LVITEMA));
979 lvItem.stateMask = LVIS_FOCUSED;
980 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
982 lvItem.state = LVIS_FOCUSED;
983 lvItem.stateMask = LVIS_FOCUSED;
984 ListView_SetItemState(hwnd, nItem, &lvItem);
986 infoPtr->nFocusedItem = nItem;
987 ListView_EnsureVisible(hwnd, nItem, FALSE);
995 * Sets a single selection.
998 * [I] HWND : window handle
999 * [I] INT : item index
1004 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1006 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1011 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
1014 if (nItem < GETITEMCOUNT(infoPtr))
1016 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
1019 ZeroMemory(&lvItem, sizeof(LVITEMA));
1020 lvItem.stateMask = LVIS_FOCUSED;
1021 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1023 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
1024 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1025 ListView_SetItemState(hwnd, nItem, &lvItem);
1027 infoPtr->nFocusedItem = nItem;
1028 infoPtr->nSelectionMark = nItem;
1033 * Set selection(s) with keyboard.
1036 * [I] HWND : window handle
1037 * [I] INT : item index
1040 * SUCCESS : TRUE (needs to be repainted)
1041 * FAILURE : FALSE (nothing has changed)
1043 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1045 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1046 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1047 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1048 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1049 BOOL bResult = FALSE;
1051 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1053 if (lStyle & LVS_SINGLESEL)
1056 LISTVIEW_SetSelection(hwnd, nItem);
1057 ListView_EnsureVisible(hwnd, nItem, FALSE);
1064 LISTVIEW_SetGroupSelection(hwnd, nItem);
1068 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1073 LISTVIEW_SetSelection(hwnd, nItem);
1074 ListView_EnsureVisible(hwnd, nItem, FALSE);
1084 * Selects an item based on coordinates.
1087 * [I] HWND : window handle
1088 * [I] POINT : mouse click ccordinates
1091 * SUCCESS : item index
1094 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1096 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1100 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1102 rcItem.left = LVIR_SELECTBOUNDS;
1103 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1105 if (PtInRect(&rcItem, pt) != FALSE)
1117 * Removes all selection states.
1120 * [I] HWND : window handle
1121 * [I] INT : item index
1127 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1133 lvItem.stateMask = LVIS_SELECTED;
1135 for (i = nFirst; i <= nLast; i++)
1137 ListView_SetItemState(hwnd, i, &lvItem);
1146 * [IO] HDPA : dynamic pointer array handle
1147 * [I] INT : column index (subitem index)
1153 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1155 BOOL bResult = TRUE;
1159 for (i = 0; i < hdpaItems->nItemCount; i++)
1161 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1162 if (hdpaSubItems != NULL)
1164 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1176 * Removes a subitem at a given position.
1179 * [IO] HDPA : dynamic pointer array handle
1180 * [I] INT : subitem index
1186 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1188 LISTVIEW_SUBITEM *lpSubItem;
1191 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1193 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1194 if (lpSubItem != NULL)
1196 if (lpSubItem->iSubItem == nSubItem)
1199 if ((lpSubItem->pszText != NULL) &&
1200 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1202 COMCTL32_Free(lpSubItem->pszText);
1206 COMCTL32_Free(lpSubItem);
1208 /* free dpa memory */
1209 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1214 else if (lpSubItem->iSubItem > nSubItem)
1226 * Compares the item information.
1229 * [I] LISTVIEW_ITEM *: destination item
1230 * [I] LPLVITEM : source item
1233 * SUCCCESS : TRUE (EQUAL)
1234 * FAILURE : FALSE (NOT EQUAL)
1236 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1240 if ((lpItem != NULL) && (lpLVItem != NULL))
1242 if (lpLVItem->mask & LVIF_STATE)
1244 if ((lpItem->state & lpLVItem->stateMask) !=
1245 (lpLVItem->state & lpLVItem->stateMask))
1247 uChanged |= LVIF_STATE;
1251 if (lpLVItem->mask & LVIF_IMAGE)
1253 if (lpItem->iImage != lpLVItem->iImage)
1255 uChanged |= LVIF_IMAGE;
1259 if (lpLVItem->mask & LVIF_PARAM)
1261 if (lpItem->lParam != lpLVItem->lParam)
1263 uChanged |= LVIF_PARAM;
1267 if (lpLVItem->mask & LVIF_INDENT)
1269 if (lpItem->iIndent != lpLVItem->iIndent)
1271 uChanged |= LVIF_INDENT;
1275 if (lpLVItem->mask & LVIF_TEXT)
1277 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1279 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1281 uChanged |= LVIF_TEXT;
1286 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1288 uChanged |= LVIF_TEXT;
1292 if (lpLVItem->pszText)
1294 if (lpItem->pszText)
1296 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1298 uChanged |= LVIF_TEXT;
1303 uChanged |= LVIF_TEXT;
1308 if (lpItem->pszText)
1310 uChanged |= LVIF_TEXT;
1322 * Initializes item attributes.
1325 * [I] HWND : window handle
1326 * [O] LISTVIEW_ITEM *: destination item
1327 * [I] LPLVITEM : source item
1333 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1336 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1337 BOOL bResult = FALSE;
1339 if ((lpItem != NULL) && (lpLVItem != NULL))
1343 if (lpLVItem->mask & LVIF_STATE)
1345 lpItem->state &= ~lpLVItem->stateMask;
1346 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1349 if (lpLVItem->mask & LVIF_IMAGE)
1351 lpItem->iImage = lpLVItem->iImage;
1354 if (lpLVItem->mask & LVIF_PARAM)
1356 lpItem->lParam = lpLVItem->lParam;
1359 if (lpLVItem->mask & LVIF_INDENT)
1361 lpItem->iIndent = lpLVItem->iIndent;
1364 if (lpLVItem->mask & LVIF_TEXT)
1366 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1368 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1373 if ((lpItem->pszText != NULL) &&
1374 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1376 COMCTL32_Free(lpItem->pszText);
1379 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1383 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1385 lpItem->pszText = NULL;
1388 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1398 * Initializes subitem attributes.
1400 * NOTE: The documentation specifies that the operation fails if the user
1401 * tries to set the indent of a subitem.
1404 * [I] HWND : window handle
1405 * [O] LISTVIEW_SUBITEM *: destination subitem
1406 * [I] LPLVITEM : source subitem
1412 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1415 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1416 BOOL bResult = FALSE;
1418 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1420 if (!(lpLVItem->mask & LVIF_INDENT))
1423 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1425 lpSubItem->iSubItem = lpLVItem->iSubItem;
1427 if (lpLVItem->mask & LVIF_IMAGE)
1429 lpSubItem->iImage = lpLVItem->iImage;
1432 if (lpLVItem->mask & LVIF_TEXT)
1434 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1436 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1441 if ((lpSubItem->pszText != NULL) &&
1442 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1444 COMCTL32_Free(lpSubItem->pszText);
1447 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1451 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1453 lpSubItem->pszText = NULL;
1456 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1467 * Adds a subitem at a given position (column index).
1470 * [I] HWND : window handle
1471 * [I] LPLVITEM : new subitem atttributes
1477 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1479 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1480 LISTVIEW_SUBITEM *lpSubItem = NULL;
1481 BOOL bResult = FALSE;
1483 INT nPosition, nItem;
1485 if (lpLVItem != NULL)
1487 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1488 if (hdpaSubItems != NULL)
1490 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1491 if (lpSubItem != NULL)
1493 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1495 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1496 lpSubItem->iSubItem);
1497 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1507 /* cleanup if unsuccessful */
1508 if ((bResult == FALSE) && (lpSubItem != NULL))
1510 COMCTL32_Free(lpSubItem);
1518 * Finds the dpa insert position (array index).
1521 * [I] HWND : window handle
1522 * [I] INT : subitem index
1528 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1530 LISTVIEW_SUBITEM *lpSubItem;
1533 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1535 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1536 if (lpSubItem != NULL)
1538 if (lpSubItem->iSubItem > nSubItem)
1545 return hdpaSubItems->nItemCount;
1550 * Retrieves a listview subitem at a given position (column index).
1553 * [I] HWND : window handle
1554 * [I] INT : subitem index
1560 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1562 LISTVIEW_SUBITEM *lpSubItem;
1565 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1567 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1568 if (lpSubItem != NULL)
1570 if (lpSubItem->iSubItem == nSubItem)
1574 else if (lpSubItem->iSubItem > nSubItem)
1586 * Sets item attributes.
1589 * [I] HWND : window handle
1590 * [I] LPLVITEM : new item atttributes
1596 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1598 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1599 BOOL bResult = FALSE;
1601 LISTVIEW_ITEM *lpItem;
1604 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1606 if (lpLVItem != NULL)
1608 if (lpLVItem->iSubItem == 0)
1610 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1611 if (hdpaSubItems != NULL)
1613 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1616 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1617 nmlv.hdr.hwndFrom = hwnd;
1618 nmlv.hdr.idFrom = lCtrlId;
1619 nmlv.hdr.code = LVN_ITEMCHANGING;
1620 nmlv.lParam = lpItem->lParam;
1621 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1624 if (uChanged & LVIF_STATE)
1626 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1627 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1630 nmlv.uChanged = uChanged;
1631 nmlv.iItem = lpLVItem->iItem;
1632 nmlv.lParam = lpItem->lParam;
1633 /* send LVN_ITEMCHANGING notification */
1634 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1636 /* copy information */
1637 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1639 /* send LVN_ITEMCHANGED notification */
1640 nmlv.hdr.code = LVN_ITEMCHANGED;
1641 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1648 InvalidateRect(hwnd, NULL, FALSE);
1659 * Sets subitem attributes.
1662 * [I] HWND : window handle
1663 * [I] LPLVITEM : new subitem atttributes
1669 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1671 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1672 BOOL bResult = FALSE;
1674 LISTVIEW_SUBITEM *lpSubItem;
1676 if (lpLVItem != NULL)
1678 if (lpLVItem->iSubItem > 0)
1680 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1681 if (hdpaSubItems != NULL)
1683 /* set subitem only if column is present */
1684 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1686 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1687 if (lpSubItem != NULL)
1689 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1693 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1696 InvalidateRect(hwnd, NULL, FALSE);
1707 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1710 * [I] HWND : window handle
1715 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1717 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1718 UINT uView = lStyle & LVS_TYPEMASK;
1720 SCROLLINFO scrollInfo;
1722 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1723 scrollInfo.cbSize = sizeof(SCROLLINFO);
1724 scrollInfo.fMask = SIF_POS;
1726 if (uView == LVS_LIST)
1728 if (lStyle & WS_HSCROLL)
1730 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1732 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1736 else if (uView == LVS_REPORT)
1738 if (lStyle & WS_VSCROLL)
1740 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1742 nItem = scrollInfo.nPos;
1755 * [I] HWND : window handle
1756 * [I] HDC : device context handle
1757 * [I] INT : item index
1758 * [I] INT : subitem index
1759 * [I] RECT * : clipping rectangle
1764 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1767 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1768 CHAR szDispText[DISP_TEXT_SIZE];
1771 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd, hdc,
1774 /* get information needed for drawing the item */
1775 ZeroMemory(&lvItem, sizeof(LVITEMA));
1776 lvItem.mask = LVIF_TEXT;
1777 lvItem.iItem = nItem;
1778 lvItem.iSubItem = nSubItem;
1779 lvItem.cchTextMax = DISP_TEXT_SIZE;
1780 lvItem.pszText = szDispText;
1781 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1783 /* set item colors */
1784 SetBkColor(hdc, infoPtr->clrTextBk);
1785 SetTextColor(hdc, infoPtr->clrText);
1787 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1788 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1797 * [I] HWND : window handle
1798 * [I] HDC : device context handle
1799 * [I] INT : item index
1800 * [I] RECT * : clipping rectangle
1805 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1807 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1808 CHAR szDispText[DISP_TEXT_SIZE];
1815 TRACE("(hwnd=%x, hdc=%x, nItem=%d\n", hwnd, hdc, nItem);
1817 /* get information needed for drawing the item */
1818 ZeroMemory(&lvItem, sizeof(LVITEMA));
1819 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1820 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1821 lvItem.iItem = nItem;
1822 lvItem.iSubItem = 0;
1823 lvItem.cchTextMax = DISP_TEXT_SIZE;
1824 lvItem.pszText = szDispText;
1825 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1828 if (infoPtr->himlState != NULL)
1830 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1831 if (uStateImage != 0)
1833 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1834 rcItem.top, ILD_NORMAL);
1837 rcItem.left += infoPtr->iconSize.cx;
1841 if (infoPtr->himlSmall != NULL)
1843 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1845 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1846 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1847 rcItem.top, ILD_SELECTED);
1851 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1852 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1853 rcItem.top, ILD_NORMAL);
1856 rcItem.left += infoPtr->iconSize.cx;
1859 /* Don't bother painting item being edited */
1860 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1863 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1865 /* set item colors */
1866 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1867 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1868 /* set raster mode */
1869 nMixMode = SetROP2(hdc, R2_XORPEN);
1871 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1872 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1874 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1875 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1876 /* set raster mode */
1877 nMixMode = SetROP2(hdc, R2_COPYPEN);
1881 /* set item colors */
1882 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1883 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1884 /* set raster mode */
1885 nMixMode = SetROP2(hdc, R2_COPYPEN);
1888 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1889 if (rcItem.left + nLabelWidth < rcItem.right)
1891 rcItem.right = rcItem.left + nLabelWidth;
1895 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1896 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1898 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1900 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1905 SetROP2(hdc, R2_COPYPEN);
1906 SetBkColor(hdc, infoPtr->clrTextBk);
1907 SetTextColor(hdc, infoPtr->clrText);
1913 * Draws an item when in large icon display mode.
1916 * [I] HWND : window handle
1917 * [I] HDC : device context handle
1918 * [I] LISTVIEW_ITEM * : item
1919 * [I] INT : item index
1920 * [I] RECT * : clipping rectangle
1925 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1927 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1928 CHAR szDispText[DISP_TEXT_SIZE];
1929 INT nDrawPosX = rcItem.left;
1934 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1935 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1938 /* get information needed for drawing the item */
1939 ZeroMemory(&lvItem, sizeof(LVITEMA));
1940 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1941 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1942 lvItem.iItem = nItem;
1943 lvItem.iSubItem = 0;
1944 lvItem.cchTextMax = DISP_TEXT_SIZE;
1945 lvItem.pszText = szDispText;
1946 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1948 if (lvItem.state & LVIS_SELECTED)
1950 /* set item colors */
1951 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1952 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1953 /* set raster mode */
1954 SetROP2(hdc, R2_XORPEN);
1958 /* set item colors */
1959 SetBkColor(hdc, infoPtr->clrTextBk);
1960 SetTextColor(hdc, infoPtr->clrText);
1961 /* set raster mode */
1962 SetROP2(hdc, R2_COPYPEN);
1965 if (infoPtr->himlNormal != NULL)
1967 rcItem.top += ICON_TOP_PADDING;
1968 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
1969 if (lvItem.state & LVIS_SELECTED)
1971 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1972 rcItem.top, ILD_SELECTED);
1976 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1977 rcItem.top, ILD_NORMAL);
1981 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
1982 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1983 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
1986 rcItem.left += nDrawPosX / 2;
1987 rcItem.right = rcItem.left + nLabelWidth;
1992 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
1996 GetTextMetricsA(hdc, &tm);
1997 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
1998 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1999 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2001 if (lvItem.state & LVIS_FOCUSED)
2003 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2009 * Draws listview items when in report display mode.
2012 * [I] HWND : window handle
2013 * [I] HDC : device context handle
2018 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2020 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2021 SCROLLINFO scrollInfo;
2022 INT nDrawPosY = infoPtr->rcList.top;
2029 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2030 scrollInfo.cbSize = sizeof(SCROLLINFO);
2031 scrollInfo.fMask = SIF_POS;
2033 nItem = ListView_GetTopIndex(hwnd);
2035 /* add 1 for displaying a partial item at the bottom */
2036 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2037 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2039 /* send cache hint notification */
2040 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
2044 nmlv.hdr.hwndFrom = hwnd;
2045 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
2046 nmlv.hdr.code = LVN_ODCACHEHINT;
2050 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
2054 for (; nItem < nLast; nItem++)
2056 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2057 for (j = 0; j < nColumnCount; j++)
2059 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2060 rcItem.left += REPORT_MARGINX;
2061 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2062 rcItem.top = nDrawPosY;
2063 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2065 /* Offset the Scroll Bar Pos */
2066 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2068 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2069 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2074 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2078 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2082 nDrawPosY += infoPtr->nItemHeight;
2088 * Retrieves the number of items that can fit vertically in the client area.
2091 * [I] HWND : window handle
2094 * Number of items per row.
2096 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2098 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2099 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2100 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2101 INT nCountPerRow = 1;
2105 if (uView == LVS_REPORT)
2111 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2112 if (nCountPerRow == 0)
2119 return nCountPerRow;
2124 * Retrieves the number of items that can fit horizontally in the client
2128 * [I] HWND : window handle
2131 * Number of items per column.
2133 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2135 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2136 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2137 INT nCountPerColumn = 1;
2139 if (nListHeight > 0)
2141 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2142 if (nCountPerColumn == 0)
2144 nCountPerColumn = 1;
2148 return nCountPerColumn;
2153 * Retrieves the number of columns needed to display all the items when in
2154 * list display mode.
2157 * [I] HWND : window handle
2160 * Number of columns.
2162 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2164 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2165 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2166 INT nColumnCount = 0;
2168 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2170 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2172 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2176 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2180 return nColumnCount;
2186 * Draws listview items when in list display mode.
2189 * [I] HWND : window handle
2190 * [I] HDC : device context handle
2195 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2197 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2202 INT nCountPerColumn;
2203 INT nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2204 INT nItemHeight = LISTVIEW_GetItemHeight(hwnd);
2206 /* get number of fully visible columns */
2207 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2208 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2209 nItem = ListView_GetTopIndex(hwnd);
2211 for (i = 0; i < nColumnCount; i++)
2213 for (j = 0; j < nCountPerColumn; j++, nItem++)
2215 if (nItem >= GETITEMCOUNT(infoPtr))
2218 rcItem.top = j * nItemHeight;
2219 rcItem.left = i * nItemWidth;
2220 rcItem.bottom = rcItem.top + nItemHeight;
2221 rcItem.right = rcItem.left + nItemWidth;
2222 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2229 * Draws listview items when in icon or small icon display mode.
2232 * [I] HWND : window handle
2233 * [I] HDC : device context handle
2238 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2240 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2246 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2247 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2249 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2250 ptPosition.x += ptOrigin.x;
2251 ptPosition.y += ptOrigin.y;
2253 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2255 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2257 if (ptPosition.y < infoPtr->rcList.bottom)
2259 if (ptPosition.x < infoPtr->rcList.right)
2261 rcItem.top = ptPosition.y;
2262 rcItem.left = ptPosition.x;
2263 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2264 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2265 if (bSmall == FALSE)
2267 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2271 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2282 * Draws listview items.
2285 * [I] HWND : window handle
2286 * [I] HDC : device context handle
2291 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2293 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2294 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2299 hOldFont = SelectObject(hdc, infoPtr->hFont);
2301 /* select the doted pen (for drawing the focus box) */
2302 hPen = CreatePen(PS_DOT, 1, 0);
2303 hOldPen = SelectObject(hdc, hPen);
2305 /* select transparent brush (for drawing the focus box) */
2306 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2308 if (uView == LVS_LIST)
2310 LISTVIEW_RefreshList(hwnd, hdc);
2312 else if (uView == LVS_REPORT)
2314 LISTVIEW_RefreshReport(hwnd, hdc);
2316 else if (uView == LVS_SMALLICON)
2318 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2320 else if (uView == LVS_ICON)
2322 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2325 /* unselect objects */
2326 SelectObject(hdc, hOldFont);
2327 SelectObject(hdc, hOldPen);
2336 * Calculates the approximate width and height of a given number of items.
2339 * [I] HWND : window handle
2340 * [I] INT : number of items
2345 * Returns a DWORD. The width in the low word and the height in high word.
2347 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2348 WORD wWidth, WORD wHeight)
2350 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2351 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2352 INT nItemCountPerColumn = 1;
2353 INT nColumnCount = 0;
2354 DWORD dwViewRect = 0;
2356 if (nItemCount == -1)
2358 nItemCount = GETITEMCOUNT(infoPtr);
2361 if (uView == LVS_LIST)
2363 if (wHeight == 0xFFFF)
2365 /* use current height */
2366 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2369 if (wHeight < infoPtr->nItemHeight)
2371 wHeight = infoPtr->nItemHeight;
2376 if (infoPtr->nItemHeight > 0)
2378 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2379 if (nItemCountPerColumn == 0)
2381 nItemCountPerColumn = 1;
2384 if (nItemCount % nItemCountPerColumn != 0)
2386 nColumnCount = nItemCount / nItemCountPerColumn;
2390 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2395 /* Microsoft padding magic */
2396 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2397 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2399 dwViewRect = MAKELONG(wWidth, wHeight);
2401 else if (uView == LVS_REPORT)
2405 else if (uView == LVS_SMALLICON)
2409 else if (uView == LVS_ICON)
2419 * Arranges listview items in icon display mode.
2422 * [I] HWND : window handle
2423 * [I] INT : alignment code
2429 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2431 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2432 BOOL bResult = FALSE;
2434 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2447 case LVA_SNAPTOGRID:
2456 /* << LISTVIEW_CreateDragImage >> */
2460 * Removes all listview items and subitems.
2463 * [I] HWND : window handle
2469 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2471 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2472 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2473 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2474 UINT uView = lStyle & LVS_TYPEMASK;
2475 LISTVIEW_ITEM *lpItem;
2476 LISTVIEW_SUBITEM *lpSubItem;
2479 BOOL bResult = FALSE;
2484 TRACE("(hwnd=%x,)\n", hwnd);
2486 if (GETITEMCOUNT(infoPtr) > 0)
2488 /* initialize memory */
2489 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2491 /* send LVN_DELETEALLITEMS notification */
2492 nmlv.hdr.hwndFrom = hwnd;
2493 nmlv.hdr.idFrom = lCtrlId;
2494 nmlv.hdr.code = LVN_DELETEALLITEMS;
2497 /* verify if subsequent LVN_DELETEITEM notifications should be
2499 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2501 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2503 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2504 if (hdpaSubItems != NULL)
2506 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2508 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2509 if (lpSubItem != NULL)
2511 /* free subitem string */
2512 if ((lpSubItem->pszText != NULL) &&
2513 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2515 COMCTL32_Free(lpSubItem->pszText);
2519 COMCTL32_Free(lpSubItem);
2523 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2526 if (bSuppress == FALSE)
2528 /* send LVN_DELETEITEM notification */
2529 nmlv.hdr.code = LVN_DELETEITEM;
2531 nmlv.lParam = lpItem->lParam;
2532 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2535 /* free item string */
2536 if ((lpItem->pszText != NULL) &&
2537 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2539 COMCTL32_Free(lpItem->pszText);
2543 COMCTL32_Free(lpItem);
2546 DPA_Destroy(hdpaSubItems);
2550 /* reinitialize listview memory */
2551 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2553 /* align items (set position of each item) */
2554 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2556 if (lStyle & LVS_ALIGNLEFT)
2558 LISTVIEW_AlignLeft(hwnd);
2562 LISTVIEW_AlignTop(hwnd);
2566 LISTVIEW_UpdateScroll(hwnd);
2568 /* invalidate client area (optimization needed) */
2569 InvalidateRect(hwnd, NULL, TRUE);
2577 * Removes a column from the listview control.
2580 * [I] HWND : window handle
2581 * [I] INT : column index
2587 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2589 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2590 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2591 BOOL bResult = FALSE;
2593 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2595 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2597 /* Need to reset the item width when deleting a column */
2598 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2600 /* reset scroll parameters */
2601 if (uView == LVS_REPORT)
2603 /* update scrollbar(s) */
2604 LISTVIEW_UpdateScroll(hwnd);
2606 /* refresh client area */
2607 InvalidateRect(hwnd, NULL, FALSE);
2616 * Removes an item from the listview control.
2619 * [I] HWND : window handle
2620 * [I] INT : item index
2626 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2628 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2629 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2630 UINT uView = lStyle & LVS_TYPEMASK;
2631 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2633 BOOL bResult = FALSE;
2635 LISTVIEW_ITEM *lpItem;
2636 LISTVIEW_SUBITEM *lpSubItem;
2639 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2641 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2643 /* initialize memory */
2644 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2646 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2647 if (hdpaSubItems != NULL)
2649 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2651 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2652 if (lpSubItem != NULL)
2654 /* free item string */
2655 if ((lpSubItem->pszText != NULL) &&
2656 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2658 COMCTL32_Free(lpSubItem->pszText);
2662 COMCTL32_Free(lpSubItem);
2666 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2669 /* send LVN_DELETEITEM notification */
2670 nmlv.hdr.hwndFrom = hwnd;
2671 nmlv.hdr.idFrom = lCtrlId;
2672 nmlv.hdr.code = LVN_DELETEITEM;
2674 nmlv.lParam = lpItem->lParam;
2675 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2678 /* free item string */
2679 if ((lpItem->pszText != NULL) &&
2680 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2682 COMCTL32_Free(lpItem->pszText);
2686 COMCTL32_Free(lpItem);
2689 bResult = DPA_Destroy(hdpaSubItems);
2692 /* align items (set position of each item) */
2693 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2695 if (lStyle & LVS_ALIGNLEFT)
2697 LISTVIEW_AlignLeft(hwnd);
2701 LISTVIEW_AlignTop(hwnd);
2705 /* If this item had focus change focus to next or previous item */
2706 if (GETITEMCOUNT(infoPtr) > 0)
2708 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
2709 if (infoPtr->nFocusedItem == nItem)
2710 LISTVIEW_SetItemFocus(hwnd, sItem);
2713 infoPtr->nFocusedItem = -1;
2715 LISTVIEW_UpdateScroll(hwnd);
2717 /* refresh client area */
2718 InvalidateRect(hwnd, NULL, TRUE);
2727 * Return edit control handle of current edit label
2730 * [I] HWND : window handle
2736 static LRESULT LISTVIEW_GetEditControl(hwnd)
2738 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2739 return infoPtr->hwndEdit;
2745 * Callback implementation for editlabel control
2748 * [I] HWND : window handle
2749 * [I] LPSTR : modified text
2750 * [I] DWORD : item index
2757 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
2759 NMLVDISPINFOA dispInfo;
2760 LISTVIEW_ITEM *lpItem;
2761 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2762 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2765 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2767 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2770 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2773 dispInfo.hdr.hwndFrom = hwnd;
2774 dispInfo.hdr.idFrom = nCtrlId;
2775 dispInfo.hdr.code = LVN_ENDLABELEDITA;
2776 dispInfo.item.mask = 0;
2777 dispInfo.item.iItem = nItem;
2778 dispInfo.item.state = lpItem->state;
2779 dispInfo.item.stateMask = 0;
2780 dispInfo.item.pszText = pszText;
2781 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
2782 dispInfo.item.iImage = lpItem->iImage;
2783 dispInfo.item.lParam = lpItem->lParam;
2785 ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
2786 infoPtr->hwndEdit = 0;
2793 * Begin in place editing of specified list view item
2796 * [I] HWND : window handle
2797 * [I] INT : item index
2804 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
2806 NMLVDISPINFOA dispInfo;
2808 LISTVIEW_ITEM *lpItem;
2810 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
2811 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2812 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2815 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
2818 LISTVIEW_SetSelection(hwnd, nItem);
2819 LISTVIEW_SetItemFocus(hwnd, nItem);
2821 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2822 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2825 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2828 dispInfo.hdr.hwndFrom = hwnd;
2829 dispInfo.hdr.idFrom = nCtrlId;
2830 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
2831 dispInfo.item.mask = 0;
2832 dispInfo.item.iItem = nItem;
2833 dispInfo.item.state = lpItem->state;
2834 dispInfo.item.stateMask = 0;
2835 dispInfo.item.pszText = lpItem->pszText;
2836 dispInfo.item.cchTextMax = strlen(lpItem->pszText);
2837 dispInfo.item.iImage = lpItem->iImage;
2838 dispInfo.item.lParam = lpItem->lParam;
2840 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
2843 rect.left = LVIR_LABEL;
2844 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
2847 if (!(hedit = CreateEditLabel(dispInfo.item.pszText , WS_VISIBLE,
2848 rect.left, rect.top, rect.right - rect.left + 15,
2849 rect.bottom - rect.top,
2850 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
2853 infoPtr->hwndEdit = hedit;
2855 SendMessageA(hedit, EM_SETSEL, 0, -1);
2863 * Ensures the specified item is visible, scrolling into view if necessary.
2866 * [I] HWND : window handle
2867 * [I] INT : item index
2868 * [I] BOOL : partially or entirely visible
2874 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2876 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2877 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2878 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2879 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2880 INT nScrollPosHeight = 0;
2881 INT nScrollPosWidth = 0;
2882 SCROLLINFO scrollInfo;
2885 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2886 scrollInfo.cbSize = sizeof(SCROLLINFO);
2887 scrollInfo.fMask = SIF_POS;
2889 /* ALWAYS bPartial == FALSE, FOR NOW! */
2891 rcItem.left = LVIR_BOUNDS;
2892 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2894 if (rcItem.left < infoPtr->rcList.left)
2896 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2899 if (uView == LVS_LIST)
2901 nScrollPosWidth = infoPtr->nItemWidth;
2902 rcItem.left += infoPtr->rcList.left;
2904 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2906 nScrollPosWidth = max(1, nListWidth / LISTVIEW_SCROLL_DIV_SIZE);
2907 rcItem.left += infoPtr->rcList.left;
2910 if (rcItem.left % nScrollPosWidth == 0)
2912 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
2916 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
2919 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2922 else if (rcItem.right > infoPtr->rcList.right)
2924 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2927 if (uView == LVS_LIST)
2929 rcItem.right -= infoPtr->rcList.right;
2930 nScrollPosWidth = infoPtr->nItemWidth;
2932 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2934 rcItem.right -= infoPtr->rcList.right;
2935 nScrollPosWidth = max(1, nListWidth / LISTVIEW_SCROLL_DIV_SIZE);
2938 if (rcItem.right % nScrollPosWidth == 0)
2940 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
2944 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
2947 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2951 if (rcItem.top < infoPtr->rcList.top)
2954 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2956 if (uView == LVS_REPORT)
2958 rcItem.top -= infoPtr->rcList.top;
2959 nScrollPosHeight = infoPtr->nItemHeight;
2961 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2963 nScrollPosHeight = max(1, nListHeight / LISTVIEW_SCROLL_DIV_SIZE);
2964 rcItem.top += infoPtr->rcList.top;
2967 if (rcItem.top % nScrollPosHeight == 0)
2969 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
2973 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
2976 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2979 else if (rcItem.bottom > infoPtr->rcList.bottom)
2982 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2984 if (uView == LVS_REPORT)
2986 rcItem.bottom -= infoPtr->rcList.bottom;
2987 nScrollPosHeight = infoPtr->nItemHeight;
2989 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2991 nScrollPosHeight = max(1, nListHeight / LISTVIEW_SCROLL_DIV_SIZE);
2992 rcItem.bottom -= infoPtr->rcList.bottom;
2995 if (rcItem.bottom % nScrollPosHeight == 0)
2997 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
3001 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
3004 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3014 * Retrieves the nearest item, given a position and a direction.
3017 * [I] HWND : window handle
3018 * [I] POINT : start position
3019 * [I] UINT : direction
3022 * Item index if successdful, -1 otherwise.
3024 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3026 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3027 LVHITTESTINFO lvHitTestInfo;
3031 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3033 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3034 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3035 lvHitTestInfo.pt.x += pt.x;
3036 lvHitTestInfo.pt.y += pt.y;
3040 if (vkDirection == VK_DOWN)
3042 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3044 else if (vkDirection == VK_UP)
3046 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3048 else if (vkDirection == VK_LEFT)
3050 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3052 else if (vkDirection == VK_RIGHT)
3054 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3057 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3063 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3067 while (nItem == -1);
3075 * Searches for an item with specific characteristics.
3078 * [I] HWND : window handle
3079 * [I] INT : base item index
3080 * [I] LPLVFINDINFO : item information to look for
3083 * SUCCESS : index of item
3086 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3087 LPLVFINDINFO lpFindInfo)
3089 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3091 CHAR szDispText[DISP_TEXT_SIZE];
3095 INT nLast = GETITEMCOUNT(infoPtr);
3097 if ((nItem >= -1) && (lpFindInfo != NULL))
3099 ZeroMemory(&lvItem, sizeof(LVITEMA));
3101 if (lpFindInfo->flags & LVFI_PARAM)
3103 lvItem.mask |= LVIF_PARAM;
3106 if (lpFindInfo->flags & LVFI_STRING)
3108 lvItem.mask |= LVIF_TEXT;
3109 lvItem.pszText = szDispText;
3110 lvItem.cchTextMax = DISP_TEXT_SIZE;
3113 if (lpFindInfo->flags & LVFI_PARTIAL)
3115 lvItem.mask |= LVIF_TEXT;
3116 lvItem.pszText = szDispText;
3117 lvItem.cchTextMax = DISP_TEXT_SIZE;
3120 if (lpFindInfo->flags & LVFI_WRAP)
3125 if (lpFindInfo->flags & LVFI_NEARESTXY)
3127 ptItem.x = lpFindInfo->pt.x;
3128 ptItem.y = lpFindInfo->pt.y;
3133 while (nItem < nLast)
3135 if (lpFindInfo->flags & LVFI_NEARESTXY)
3137 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3138 lpFindInfo->vkDirection);
3141 /* get position of the new item index */
3142 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3153 lvItem.iItem = nItem;
3154 lvItem.iSubItem = 0;
3155 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
3157 if (lvItem.mask & LVIF_TEXT)
3159 if (lpFindInfo->flags & LVFI_PARTIAL)
3161 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3166 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3171 if (lvItem.mask & LVIF_PARAM)
3173 if (lpFindInfo->lParam != lvItem.lParam)
3199 * Retrieves the background color of the listview control.
3202 * [I] HWND : window handle
3205 * COLORREF associated with the background.
3207 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3209 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3211 return infoPtr->clrBk;
3216 * Retrieves the background image of the listview control.
3219 * [I] HWND : window handle
3220 * [O] LPLVMKBIMAGE : background image attributes
3226 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3228 /* FIXME (listview, "empty stub!\n"); */
3234 * Retrieves the callback mask.
3237 * [I] HWND : window handle
3242 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3244 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3246 return infoPtr->uCallbackMask;
3251 * Retrieves column attributes.
3254 * [I] HWND : window handle
3255 * [I] INT : column index
3256 * [IO] LPLVCOLUMNA : column information
3262 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3264 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3266 BOOL bResult = FALSE;
3268 if (lpColumn != NULL)
3270 /* initialize memory */
3271 ZeroMemory(&hdi, sizeof(HDITEMA));
3273 if (lpColumn->mask & LVCF_FMT)
3275 hdi.mask |= HDI_FORMAT;
3278 if (lpColumn->mask & LVCF_WIDTH)
3280 hdi.mask |= HDI_WIDTH;
3283 if (lpColumn->mask & LVCF_TEXT)
3285 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3288 if (lpColumn->mask & LVCF_IMAGE)
3290 hdi.mask |= HDI_IMAGE;
3293 if (lpColumn->mask & LVCF_ORDER)
3295 hdi.mask |= HDI_ORDER;
3298 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3299 if (bResult != FALSE)
3301 if (lpColumn->mask & LVCF_FMT)
3305 if (hdi.fmt & HDF_LEFT)
3307 lpColumn->fmt |= LVCFMT_LEFT;
3309 else if (hdi.fmt & HDF_RIGHT)
3311 lpColumn->fmt |= LVCFMT_RIGHT;
3313 else if (hdi.fmt & HDF_CENTER)
3315 lpColumn->fmt |= LVCFMT_CENTER;
3318 if (hdi.fmt & HDF_IMAGE)
3320 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3323 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3325 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3329 if (lpColumn->mask & LVCF_WIDTH)
3331 lpColumn->cx = hdi.cxy;
3334 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3336 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3339 if (lpColumn->mask & LVCF_IMAGE)
3341 lpColumn->iImage = hdi.iImage;
3344 if (lpColumn->mask & LVCF_ORDER)
3346 lpColumn->iOrder = hdi.iOrder;
3354 /* LISTVIEW_GetColumnW */
3357 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
3359 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3366 for (i = 0; i < iCount; i++)
3374 * Retrieves the column width.
3377 * [I] HWND : window handle
3378 * [I] int : column index
3381 * SUCCESS : column width
3384 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3386 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3387 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3388 INT nColumnWidth = 0;
3391 if (uView == LVS_LIST)
3393 nColumnWidth = infoPtr->nItemWidth;
3395 else if (uView == LVS_REPORT)
3397 /* get column width from header */
3398 ZeroMemory(&hdi, sizeof(HDITEMA));
3399 hdi.mask = HDI_WIDTH;
3400 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3402 nColumnWidth = hdi.cxy;
3406 return nColumnWidth;
3411 * In list or report display mode, retrieves the number of items that can fit
3412 * vertically in the visible area. In icon or small icon display mode,
3413 * retrieves the total number of visible items.
3416 * [I] HWND : window handle
3419 * Number of fully visible items.
3421 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3423 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3424 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3427 if (uView == LVS_LIST)
3429 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3431 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3432 LISTVIEW_GetCountPerColumn(hwnd);
3435 else if (uView == LVS_REPORT)
3437 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3441 nItemCount = GETITEMCOUNT(infoPtr);
3447 /* LISTVIEW_GetEditControl */
3451 * Retrieves the extended listview style.
3454 * [I] HWND : window handle
3457 * SUCCESS : previous style
3460 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3462 LISTVIEW_INFO *infoPtr;
3464 /* make sure we can get the listview info */
3465 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3468 return (infoPtr->dwExStyle);
3473 * Retrieves the handle to the header control.
3476 * [I] HWND : window handle
3481 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3483 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3485 return infoPtr->hwndHeader;
3488 /* LISTVIEW_GetHotCursor */
3489 /* LISTVIEW_GetHotItem */
3490 /* LISTVIEW_GetHoverTime */
3494 * Retrieves an image list handle.
3497 * [I] HWND : window handle
3498 * [I] INT : image list identifier
3501 * SUCCESS : image list handle
3504 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3506 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3507 HIMAGELIST himl = NULL;
3512 himl = infoPtr->himlNormal;
3515 himl = infoPtr->himlSmall;
3518 himl = infoPtr->himlState;
3522 return (LRESULT)himl;
3525 /* LISTVIEW_GetISearchString */
3529 * Retrieves item attributes.
3532 * [I] HWND : window handle
3533 * [IO] LPLVITEMA : item info
3534 * [I] internal : if true then we will use tricks that avoid copies
3535 * but are not compatible with the regular interface
3541 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
3543 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3544 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3545 NMLVDISPINFOA dispInfo;
3546 LISTVIEW_SUBITEM *lpSubItem;
3547 LISTVIEW_ITEM *lpItem;
3551 /* In the following:
3552 * lpLVItem describes the information requested by the user
3553 * lpItem/lpSubItem is what we have
3554 * dispInfo is a structure we use to request the missing
3555 * information from the application
3558 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3560 if ((lpLVItem == NULL) ||
3561 (lpLVItem->iItem < 0) ||
3562 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
3566 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3567 if (hdpaSubItems == NULL)
3570 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3574 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3575 if (lpLVItem->iSubItem == 0)
3577 piImage=&lpItem->iImage;
3578 ppszText=&lpItem->pszText;
3579 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3581 dispInfo.item.mask |= LVIF_STATE;
3582 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3587 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
3588 if (lpSubItem != NULL)
3590 piImage=&lpItem->iImage;
3591 ppszText=&lpItem->pszText;
3600 if ((lpLVItem->mask & LVIF_IMAGE) &&
3601 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
3603 dispInfo.item.mask |= LVIF_IMAGE;
3606 if ((lpLVItem->mask & LVIF_TEXT) &&
3607 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
3609 dispInfo.item.mask |= LVIF_TEXT;
3610 dispInfo.item.pszText = lpLVItem->pszText;
3611 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3614 if (dispInfo.item.mask != 0)
3616 /* We don't have all the requested info, query the application */
3617 dispInfo.hdr.hwndFrom = hwnd;
3618 dispInfo.hdr.idFrom = lCtrlId;
3619 dispInfo.hdr.code = LVN_GETDISPINFOA;
3620 dispInfo.item.iItem = lpLVItem->iItem;
3621 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3622 dispInfo.item.lParam = lpItem->lParam;
3623 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3626 if (dispInfo.item.mask & LVIF_IMAGE)
3628 lpLVItem->iImage = dispInfo.item.iImage;
3630 else if (lpLVItem->mask & LVIF_IMAGE)
3632 lpLVItem->iImage = *piImage;
3635 if (dispInfo.item.mask & LVIF_TEXT)
3637 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
3639 Str_SetPtrA(ppszText, dispInfo.item.pszText);
3641 /* Here lpLVItem->pszText==dispInfo.item.pszText so a copy is unnecessary */
3643 else if (lpLVItem->mask & LVIF_TEXT)
3647 lpLVItem->pszText=*ppszText;
3649 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
3653 if (lpLVItem->iSubItem == 0)
3655 if (dispInfo.item.mask & LVIF_STATE)
3657 lpLVItem->state = lpItem->state;
3658 lpLVItem->state &= ~dispInfo.item.stateMask;
3659 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
3661 else if (lpLVItem->mask & LVIF_STATE)
3663 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3666 if (lpLVItem->mask & LVIF_PARAM)
3668 lpLVItem->lParam = lpItem->lParam;
3671 if (lpLVItem->mask & LVIF_INDENT)
3673 lpLVItem->iIndent = lpItem->iIndent;
3680 /* LISTVIEW_GetItemW */
3681 /* LISTVIEW_GetHotCursor */
3685 * Retrieves the index of the hot item.
3688 * [I] HWND : window handle
3691 * SUCCESS : hot item index
3692 * FAILURE : -1 (no hot item)
3694 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3696 LISTVIEW_INFO *infoPtr;
3698 /* make sure we can get the listview info */
3699 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3702 return (infoPtr->nHotItem);
3705 /* LISTVIEW_GetHoverTime */
3709 * Retrieves the number of items in the listview control.
3712 * [I] HWND : window handle
3717 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3719 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3721 return GETITEMCOUNT(infoPtr);
3726 * Retrieves the position (upper-left) of the listview control item.
3729 * [I] HWND : window handle
3730 * [I] INT : item index
3731 * [O] LPPOINT : coordinate information
3737 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3738 LPPOINT lpptPosition)
3740 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3741 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3742 BOOL bResult = FALSE;
3744 LISTVIEW_ITEM *lpItem;
3745 INT nCountPerColumn;
3748 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3751 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3752 (lpptPosition != NULL))
3754 if (uView == LVS_LIST)
3757 nItem = nItem - ListView_GetTopIndex(hwnd);
3758 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3761 nRow = nItem % nCountPerColumn;
3764 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3765 lpptPosition->y = 0;
3769 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3770 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3775 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3776 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3779 else if (uView == LVS_REPORT)
3782 lpptPosition->x = REPORT_MARGINX;
3783 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3784 infoPtr->nItemHeight) + infoPtr->rcList.top;
3788 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3789 if (hdpaSubItems != NULL)
3791 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3795 lpptPosition->x = lpItem->ptPosition.x;
3796 lpptPosition->y = lpItem->ptPosition.y;
3807 * Retrieves the bounding rectangle for a listview control item.
3810 * [I] HWND : window handle
3811 * [I] INT : item index
3812 * [IO] LPRECT : bounding rectangle coordinates
3818 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3820 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3821 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3822 BOOL bResult = FALSE;
3831 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3833 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3835 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3840 if (uView == LVS_ICON)
3842 if (infoPtr->himlNormal != NULL)
3844 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3847 lprc->left = ptItem.x + ptOrigin.x;
3848 lprc->top = ptItem.y + ptOrigin.y;
3849 lprc->right = lprc->left + infoPtr->iconSize.cx;
3850 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3851 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3855 else if (uView == LVS_SMALLICON)
3857 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3860 lprc->left = ptItem.x + ptOrigin.x;
3861 lprc->top = ptItem.y + ptOrigin.y;
3862 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3864 if (infoPtr->himlState != NULL)
3865 lprc->left += infoPtr->iconSize.cx;
3867 if (infoPtr->himlSmall != NULL)
3868 lprc->right = lprc->left + infoPtr->iconSize.cx;
3870 lprc->right = lprc->left;
3876 lprc->left = ptItem.x;
3877 lprc->top = ptItem.y;
3878 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3880 if (infoPtr->himlState != NULL)
3882 lprc->left += infoPtr->iconSize.cx;
3885 if (infoPtr->himlSmall != NULL)
3887 lprc->right = lprc->left + infoPtr->iconSize.cx;
3891 lprc->right = lprc->left;
3897 if (uView == LVS_ICON)
3899 if (infoPtr->himlNormal != NULL)
3901 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3904 lprc->left = ptItem.x + ptOrigin.x;
3905 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3906 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3907 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3908 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3910 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3911 lprc->right = lprc->left + nLabelWidth;
3916 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3920 hOldFont = SelectObject(hdc, infoPtr->hFont);
3921 GetTextMetricsA(hdc, &tm);
3922 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3923 SelectObject(hdc, hOldFont);
3924 ReleaseDC(hwnd, hdc);
3928 else if (uView == LVS_SMALLICON)
3930 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3933 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
3934 lprc->top = ptItem.y + ptOrigin.y;
3935 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3937 if (infoPtr->himlState != NULL)
3939 lprc->left += infoPtr->iconSize.cx;
3942 if (infoPtr->himlSmall != NULL)
3944 lprc->left += infoPtr->iconSize.cx;
3947 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3948 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3950 lprc->right = lprc->left + nLabelWidth;
3954 lprc->right = nLeftPos + infoPtr->nItemWidth;
3961 nLeftPos = lprc->left = ptItem.x;
3962 lprc->top = ptItem.y;
3963 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3965 if (infoPtr->himlState != NULL)
3967 lprc->left += infoPtr->iconSize.cx;
3970 if (infoPtr->himlSmall != NULL)
3972 lprc->left += infoPtr->iconSize.cx;
3975 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3976 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3978 lprc->right = lprc->left + nLabelWidth;
3982 lprc->right = nLeftPos + infoPtr->nItemWidth;
3988 if (uView == LVS_ICON)
3990 if (infoPtr->himlNormal != NULL)
3992 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3995 lprc->left = ptItem.x + ptOrigin.x;
3996 lprc->top = ptItem.y + ptOrigin.y;
3997 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3998 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4002 else if (uView == LVS_SMALLICON)
4004 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4007 lprc->left = ptItem.x + ptOrigin.x;
4008 lprc->right = lprc->left;
4009 lprc->top = ptItem.y + ptOrigin.y;
4010 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4011 if (infoPtr->himlState != NULL)
4012 lprc->right += infoPtr->iconSize.cx;
4013 if (infoPtr->himlSmall != NULL)
4014 lprc->right += infoPtr->iconSize.cx;
4016 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4017 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4019 lprc->right += nLabelWidth;
4023 lprc->right = lprc->left + infoPtr->nItemWidth;
4030 lprc->left = ptItem.x;
4031 lprc->right = lprc->left;
4032 lprc->top = ptItem.y;
4033 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4035 if (infoPtr->himlState != NULL)
4037 lprc->right += infoPtr->iconSize.cx;
4040 if (infoPtr->himlSmall != NULL)
4042 lprc->right += infoPtr->iconSize.cx;
4045 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4046 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4048 lprc->right += nLabelWidth;
4052 lprc->right = lprc->left + infoPtr->nItemWidth;
4057 case LVIR_SELECTBOUNDS:
4058 if (uView == LVS_ICON)
4060 if (infoPtr->himlNormal != NULL)
4062 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4065 lprc->left = ptItem.x + ptOrigin.x;
4066 lprc->top = ptItem.y + ptOrigin.y;
4067 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4068 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4072 else if (uView == LVS_SMALLICON)
4074 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4077 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4078 lprc->top = ptItem.y + ptOrigin.y;
4079 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4081 if (infoPtr->himlState != NULL)
4083 lprc->left += infoPtr->iconSize.cx;
4086 lprc->right = lprc->left;
4088 if (infoPtr->himlSmall != NULL)
4090 lprc->right += infoPtr->iconSize.cx;
4093 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4094 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4096 lprc->right += nLabelWidth;
4100 lprc->right = nLeftPos + infoPtr->nItemWidth;
4107 nLeftPos = lprc->left = ptItem.x;
4108 lprc->top = ptItem.y;
4109 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4111 if (infoPtr->himlState != NULL)
4113 lprc->left += infoPtr->iconSize.cx;
4116 lprc->right = lprc->left;
4118 if (infoPtr->himlSmall != NULL)
4120 lprc->right += infoPtr->iconSize.cx;
4123 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4124 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4126 lprc->right += nLabelWidth;
4130 lprc->right = nLeftPos + infoPtr->nItemWidth;
4143 * Retrieves the width of a label.
4146 * [I] HWND : window handle
4149 * SUCCESS : string width (in pixels)
4152 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4154 CHAR szDispText[DISP_TEXT_SIZE];
4155 INT nLabelWidth = 0;
4158 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4160 ZeroMemory(&lvItem, sizeof(LVITEMA));
4161 lvItem.mask = LVIF_TEXT;
4162 lvItem.iItem = nItem;
4163 lvItem.cchTextMax = DISP_TEXT_SIZE;
4164 lvItem.pszText = szDispText;
4165 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4167 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4175 * Retrieves the spacing between listview control items.
4178 * [I] HWND : window handle
4179 * [I] BOOL : flag for small or large icon
4182 * Horizontal + vertical spacing
4184 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4186 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4189 if (bSmall == FALSE)
4191 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4195 /* TODO: need to store width of smallicon item */
4196 lResult = MAKELONG(0, infoPtr->nItemHeight);
4204 * Retrieves the state of a listview control item.
4207 * [I] HWND : window handle
4208 * [I] INT : item index
4209 * [I] UINT : state mask
4212 * State specified by the mask.
4214 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4216 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4220 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4222 ZeroMemory(&lvItem, sizeof(LVITEMA));
4223 lvItem.iItem = nItem;
4224 lvItem.stateMask = uMask;
4225 lvItem.mask = LVIF_STATE;
4226 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4228 uState = lvItem.state;
4237 * Retrieves the text of a listview control item or subitem.
4240 * [I] HWND : window handle
4241 * [I] INT : item index
4242 * [IO] LPLVITEMA : item information
4245 * SUCCESS : string length
4248 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4250 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4253 if (lpLVItem != NULL)
4255 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4257 lpLVItem->mask = LVIF_TEXT;
4258 lpLVItem->iItem = nItem;
4259 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
4261 nLength = lstrlenA(lpLVItem->pszText);
4271 * Searches for an item based on properties + relationships.
4274 * [I] HWND : window handle
4275 * [I] INT : item index
4276 * [I] INT : relationship flag
4279 * SUCCESS : item index
4282 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4284 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4285 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4287 LVFINDINFO lvFindInfo;
4288 INT nCountPerColumn;
4291 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4293 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4295 if (uFlags & LVNI_CUT)
4298 if (uFlags & LVNI_DROPHILITED)
4299 uMask |= LVIS_DROPHILITED;
4301 if (uFlags & LVNI_FOCUSED)
4302 uMask |= LVIS_FOCUSED;
4304 if (uFlags & LVNI_SELECTED)
4305 uMask |= LVIS_SELECTED;
4307 if (uFlags & LVNI_ABOVE)
4309 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4314 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4320 lvFindInfo.flags = LVFI_NEARESTXY;
4321 lvFindInfo.vkDirection = VK_UP;
4322 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4323 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4325 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4330 else if (uFlags & LVNI_BELOW)
4332 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4334 while (nItem < GETITEMCOUNT(infoPtr))
4337 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4343 lvFindInfo.flags = LVFI_NEARESTXY;
4344 lvFindInfo.vkDirection = VK_DOWN;
4345 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4346 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4348 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4353 else if (uFlags & LVNI_TOLEFT)
4355 if (uView == LVS_LIST)
4357 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4358 while (nItem - nCountPerColumn >= 0)
4360 nItem -= nCountPerColumn;
4361 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4365 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4367 lvFindInfo.flags = LVFI_NEARESTXY;
4368 lvFindInfo.vkDirection = VK_LEFT;
4369 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4370 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4372 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4377 else if (uFlags & LVNI_TORIGHT)
4379 if (uView == LVS_LIST)
4381 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4382 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4384 nItem += nCountPerColumn;
4385 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4389 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4391 lvFindInfo.flags = LVFI_NEARESTXY;
4392 lvFindInfo.vkDirection = VK_RIGHT;
4393 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4394 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4396 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4405 /* search by index */
4406 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4408 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4417 /* LISTVIEW_GetNumberOfWorkAreas */
4421 * Retrieves the origin coordinates when in icon or small icon display mode.
4424 * [I] HWND : window handle
4425 * [O] LPPOINT : coordinate information
4431 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4433 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4434 UINT uView = lStyle & LVS_TYPEMASK;
4435 BOOL bResult = FALSE;
4437 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4439 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4441 SCROLLINFO scrollInfo;
4442 ZeroMemory(lpptOrigin, sizeof(POINT));
4443 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4444 scrollInfo.cbSize = sizeof(SCROLLINFO);
4446 if (lStyle & WS_HSCROLL)
4448 scrollInfo.fMask = SIF_POS;
4449 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4451 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4455 if (lStyle & WS_VSCROLL)
4457 scrollInfo.fMask = SIF_POS;
4458 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4460 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4472 * Retrieves the number of items that are marked as selected.
4475 * [I] HWND : window handle
4478 * Number of items selected.
4480 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4482 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4483 INT nSelectedCount = 0;
4486 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4488 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4494 return nSelectedCount;
4499 * Retrieves item index that marks the start of a multiple selection.
4502 * [I] HWND : window handle
4505 * Index number or -1 if there is no selection mark.
4507 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4509 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4511 return infoPtr->nSelectionMark;
4516 * Retrieves the width of a string.
4519 * [I] HWND : window handle
4522 * SUCCESS : string width (in pixels)
4525 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4527 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4528 HFONT hFont, hOldFont;
4532 ZeroMemory(&stringSize, sizeof(SIZE));
4533 if (lpszText != NULL)
4535 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4537 hOldFont = SelectObject(hdc, hFont);
4538 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4539 SelectObject(hdc, hOldFont);
4540 ReleaseDC(hwnd, hdc);
4543 return stringSize.cx;
4548 * Retrieves the text backgound color.
4551 * [I] HWND : window handle
4554 * COLORREF associated with the the background.
4556 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4558 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4560 return infoPtr->clrTextBk;
4565 * Retrieves the text color.
4568 * [I] HWND : window handle
4571 * COLORREF associated with the text.
4573 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4575 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4577 return infoPtr->clrText;
4582 * Determines which section of the item was selected (if any).
4585 * [I] HWND : window handle
4586 * [IO] LPLVHITTESTINFO : hit test information
4589 * SUCCESS : item index
4592 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4594 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4598 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4599 lpHitTestInfo->pt.y);
4601 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4603 rcItem.left = LVIR_BOUNDS;
4604 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4606 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4608 rcItem.left = LVIR_ICON;
4609 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4611 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4613 lpHitTestInfo->flags = LVHT_ONITEMICON;
4614 lpHitTestInfo->iItem = i;
4615 lpHitTestInfo->iSubItem = 0;
4620 rcItem.left = LVIR_LABEL;
4621 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4623 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4625 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4626 lpHitTestInfo->iItem = i;
4627 lpHitTestInfo->iSubItem = 0;
4632 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4633 lpHitTestInfo->iItem = i;
4634 lpHitTestInfo->iSubItem = 0;
4640 lpHitTestInfo->flags = LVHT_NOWHERE;
4647 * Determines which listview item is located at the specified position.
4650 * [I] HWND : window handle
4651 * [IO} LPLVHITTESTINFO : hit test information
4654 * SUCCESS : item index
4657 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4659 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4662 lpHitTestInfo->flags = 0;
4664 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4666 lpHitTestInfo->flags = LVHT_TOLEFT;
4668 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4670 lpHitTestInfo->flags = LVHT_TORIGHT;
4672 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4674 lpHitTestInfo->flags |= LVHT_ABOVE;
4676 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4678 lpHitTestInfo->flags |= LVHT_BELOW;
4681 if (lpHitTestInfo->flags == 0)
4683 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4691 * Inserts a new column.
4694 * [I] HWND : window handle
4695 * [I] INT : column index
4696 * [I] LPLVCOLUMNA : column information
4699 * SUCCESS : new column index
4702 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4703 LPLVCOLUMNA lpColumn)
4705 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4707 INT nNewColumn = -1;
4709 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4712 if (lpColumn != NULL)
4714 /* initialize memory */
4715 ZeroMemory(&hdi, sizeof(HDITEMA));
4717 if (lpColumn->mask & LVCF_FMT)
4719 /* format member is valid */
4720 hdi.mask |= HDI_FORMAT;
4722 /* set text alignment (leftmost column must be left-aligned) */
4725 hdi.fmt |= HDF_LEFT;
4729 if (lpColumn->fmt & LVCFMT_LEFT)
4731 hdi.fmt |= HDF_LEFT;
4733 else if (lpColumn->fmt & LVCFMT_RIGHT)
4735 hdi.fmt |= HDF_RIGHT;
4737 else if (lpColumn->fmt & LVCFMT_CENTER)
4739 hdi.fmt |= HDF_CENTER;
4743 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4745 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4749 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4754 if (lpColumn->fmt & LVCFMT_IMAGE)
4756 hdi.fmt |= HDF_IMAGE;
4757 hdi.iImage = I_IMAGECALLBACK;
4761 if (lpColumn->mask & LVCF_WIDTH)
4763 hdi.mask |= HDI_WIDTH;
4764 hdi.cxy = lpColumn->cx;
4767 if (lpColumn->mask & LVCF_TEXT)
4769 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4770 hdi.pszText = lpColumn->pszText;
4771 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4772 hdi.fmt |= HDF_STRING;
4775 if (lpColumn->mask & LVCF_IMAGE)
4777 hdi.mask |= HDI_IMAGE;
4778 hdi.iImage = lpColumn->iImage;
4781 if (lpColumn->mask & LVCF_ORDER)
4783 hdi.mask |= HDI_ORDER;
4784 hdi.iOrder = lpColumn->iOrder;
4787 /* insert item in header control */
4788 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4789 (WPARAM)nColumn, (LPARAM)&hdi);
4791 /* Need to reset the item width when inserting a new column */
4792 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4794 LISTVIEW_UpdateScroll(hwnd);
4795 InvalidateRect(hwnd, NULL, FALSE);
4801 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4802 LPLVCOLUMNW lpColumn)
4807 memcpy(&lvca,lpColumn,sizeof(lvca));
4808 if (lpColumn->mask & LVCF_TEXT)
4809 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4810 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4811 if (lpColumn->mask & LVCF_TEXT)
4812 HeapFree(GetProcessHeap(),0,lvca.pszText);
4819 * Inserts a new item in the listview control.
4822 * [I] HWND : window handle
4823 * [I] LPLVITEMA : item information
4826 * SUCCESS : new item index
4829 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4831 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4832 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4833 UINT uView = lStyle & LVS_TYPEMASK;
4834 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4839 LISTVIEW_ITEM *lpItem = NULL;
4841 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4843 if (lpLVItem != NULL)
4845 /* make sure it's not a subitem; cannot insert a subitem */
4846 if (lpLVItem->iSubItem == 0)
4848 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4851 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4852 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4854 /* insert item in listview control data structure */
4855 hdpaSubItems = DPA_Create(8);
4856 if (hdpaSubItems != NULL)
4858 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4861 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4865 /* manage item focus */
4866 if (lpLVItem->mask & LVIF_STATE)
4868 if (lpLVItem->stateMask & LVIS_FOCUSED)
4870 LISTVIEW_SetItemFocus(hwnd, nItem);
4874 /* send LVN_INSERTITEM notification */
4875 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4876 nmlv.hdr.hwndFrom = hwnd;
4877 nmlv.hdr.idFrom = lCtrlId;
4878 nmlv.hdr.code = LVN_INSERTITEM;
4880 nmlv.lParam = lpItem->lParam;;
4881 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4883 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
4885 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
4886 if (nItemWidth > infoPtr->nItemWidth)
4888 infoPtr->nItemWidth = nItemWidth;
4892 /* align items (set position of each item) */
4893 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4895 if (lStyle & LVS_ALIGNLEFT)
4897 LISTVIEW_AlignLeft(hwnd);
4901 LISTVIEW_AlignTop(hwnd);
4905 LISTVIEW_UpdateScroll(hwnd);
4906 /* refresh client area */
4907 InvalidateRect(hwnd, NULL, FALSE);
4916 /* free memory if unsuccessful */
4917 if ((nItem == -1) && (lpItem != NULL))
4919 COMCTL32_Free(lpItem);
4925 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
4929 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
4930 if (lvia.mask & LVIF_TEXT) {
4931 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
4932 lvia.pszText = LPSTR_TEXTCALLBACKA;
4934 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
4936 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
4937 if (lvia.mask & LVIF_TEXT) {
4938 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
4939 HeapFree(GetProcessHeap(),0,lvia.pszText);
4944 /* LISTVIEW_InsertItemW */
4948 * Redraws a range of items.
4951 * [I] HWND : window handle
4952 * [I] INT : first item
4953 * [I] INT : last item
4959 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4961 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4962 BOOL bResult = FALSE;
4965 if (nFirst <= nLast)
4967 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4969 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4972 InvalidateRect(hwnd, &rc, FALSE);
4980 /* LISTVIEW_Scroll */
4984 * Sets the background color.
4987 * [I] HWND : window handle
4988 * [I] COLORREF : background color
4994 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
4996 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4998 infoPtr->clrBk = clrBk;
4999 InvalidateRect(hwnd, NULL, TRUE);
5004 /* LISTVIEW_SetBkImage */
5008 * Sets the callback mask. This mask will be used when the parent
5009 * window stores state information (some or all).
5012 * [I] HWND : window handle
5013 * [I] UINT : state mask
5019 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5021 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5023 infoPtr->uCallbackMask = uMask;
5030 * Sets the attributes of a header item.
5033 * [I] HWND : window handle
5034 * [I] INT : column index
5035 * [I] LPLVCOLUMNA : column attributes
5041 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5042 LPLVCOLUMNA lpColumn)
5044 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5045 BOOL bResult = FALSE;
5046 HDITEMA hdi, hdiget;
5048 if ((lpColumn != NULL) && (nColumn >= 0) &&
5049 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5051 /* initialize memory */
5052 ZeroMemory(&hdi, sizeof(HDITEMA));
5054 if (lpColumn->mask & LVCF_FMT)
5056 /* format member is valid */
5057 hdi.mask |= HDI_FORMAT;
5059 /* get current format first */
5060 hdiget.mask = HDI_FORMAT;
5061 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5062 /* preserve HDF_STRING if present */
5063 hdi.fmt = hdiget.fmt & HDF_STRING;
5065 /* set text alignment (leftmost column must be left-aligned) */
5068 hdi.fmt |= HDF_LEFT;
5072 if (lpColumn->fmt & LVCFMT_LEFT)
5074 hdi.fmt |= HDF_LEFT;
5076 else if (lpColumn->fmt & LVCFMT_RIGHT)
5078 hdi.fmt |= HDF_RIGHT;
5080 else if (lpColumn->fmt & LVCFMT_CENTER)
5082 hdi.fmt |= HDF_CENTER;
5086 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5088 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5091 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5093 hdi.fmt |= HDF_IMAGE;
5096 if (lpColumn->fmt & LVCFMT_IMAGE)
5098 hdi.fmt |= HDF_IMAGE;
5099 hdi.iImage = I_IMAGECALLBACK;
5103 if (lpColumn->mask & LVCF_WIDTH)
5105 hdi.mask |= HDI_WIDTH;
5106 hdi.cxy = lpColumn->cx;
5109 if (lpColumn->mask & LVCF_TEXT)
5111 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5112 hdi.pszText = lpColumn->pszText;
5113 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5114 hdi.fmt |= HDF_STRING;
5117 if (lpColumn->mask & LVCF_IMAGE)
5119 hdi.mask |= HDI_IMAGE;
5120 hdi.iImage = lpColumn->iImage;
5123 if (lpColumn->mask & LVCF_ORDER)
5125 hdi.mask |= HDI_ORDER;
5126 hdi.iOrder = lpColumn->iOrder;
5129 /* set header item attributes */
5130 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5136 /* LISTVIEW_SetColumnW */
5140 * Sets the column order array
5143 * [I] HWND : window handle
5144 * [I] INT : number of elements in column order array
5145 * [I] INT : pointer to column order array
5151 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
5153 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
5155 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
5166 * Sets the width of a column
5169 * [I] HWND : window handle
5170 * [I] INT : column index
5171 * [I] INT : column width
5177 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5179 LISTVIEW_INFO *infoPtr;
5184 /* set column width only if in report mode */
5185 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5186 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
5189 /* make sure we can get the listview info */
5190 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5192 if (!infoPtr->hwndHeader) /* make sure we have a header */
5195 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5196 * LVSCV_AUTOSIZE_USEHEADER (-2)
5201 hdi.mask = HDI_WIDTH;
5204 /* call header to update the column change */
5205 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5207 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5209 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5216 * Sets the extended listview style.
5219 * [I] HWND : window handle
5224 * SUCCESS : previous style
5227 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5229 LISTVIEW_INFO *infoPtr;
5232 /* make sure we can get the listview info */
5233 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5236 /* store previous style */
5237 dwOldStyle = infoPtr->dwExStyle;
5240 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5242 return (dwOldStyle);
5245 /* LISTVIEW_SetHotCursor */
5249 * Sets the hot item index.
5252 * [I] HWND : window handle
5256 * SUCCESS : previous hot item index
5257 * FAILURE : -1 (no hot item)
5259 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5261 LISTVIEW_INFO *infoPtr;
5264 /* make sure we can get the listview info */
5265 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5268 /* store previous index */
5269 iOldIndex = infoPtr->nHotItem;
5272 infoPtr->nHotItem = iIndex;
5277 /* LISTVIEW_SetIconSpacing */
5284 * [I] HWND : window handle
5285 * [I] INT : image list type
5286 * [I] HIMAGELIST : image list handle
5289 * SUCCESS : old image list
5292 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5294 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5295 HIMAGELIST himlTemp = 0;
5300 himlTemp = infoPtr->himlNormal;
5301 infoPtr->himlNormal = himl;
5302 return (LRESULT)himlTemp;
5305 himlTemp = infoPtr->himlSmall;
5306 infoPtr->himlSmall = himl;
5307 return (LRESULT)himlTemp;
5310 himlTemp = infoPtr->himlState;
5311 infoPtr->himlState = himl;
5312 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5313 return (LRESULT)himlTemp;
5316 return (LRESULT)NULL;
5322 * Sets the attributes of an item.
5325 * [I] HWND : window handle
5326 * [I] LPLVITEM : item information
5332 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5334 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5335 BOOL bResult = FALSE;
5337 if (lpLVItem != NULL)
5339 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5341 if (lpLVItem->iSubItem == 0)
5343 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5347 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5356 /* LISTVIEW_SetItemW */
5360 * Preallocates memory.
5363 * [I] HWND : window handle
5364 * [I] INT : item count (projected number of items)
5365 * [I] DWORD : update flags
5371 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5373 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5375 FIXME("(%d %08lx)empty stub!\n", nItems, dwFlags);
5378 return LISTVIEW_DeleteAllItems (hwnd);
5380 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
5382 FIXME("LVS_OWNERDATA is set!\n");
5386 if (nItems > GETITEMCOUNT(infoPtr))
5389 FIXME("append items\n");
5392 else if (nItems < GETITEMCOUNT(infoPtr))
5395 FIXME("remove items\n");
5405 * Sets the position of an item.
5408 * [I] HWND : window handle
5409 * [I] INT : item index
5410 * [I] INT : x coordinate
5411 * [I] INT : y coordinate
5417 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5418 INT nPosX, INT nPosY)
5420 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5421 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5422 LISTVIEW_ITEM *lpItem;
5424 BOOL bResult = FALSE;
5426 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5428 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5430 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5432 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5433 if (hdpaSubItems != NULL)
5435 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5439 lpItem->ptPosition.x = nPosX;
5440 lpItem->ptPosition.y = nPosY;
5449 /* LISTVIEW_SetItemPosition32 */
5453 * Sets the state of one or many items.
5456 * [I] HWND : window handle
5457 * [I]INT : item index
5458 * [I] LPLVITEM : item or subitem info
5464 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5466 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5467 BOOL bResult = FALSE;
5474 ZeroMemory(&lvItem, sizeof(LVITEMA));
5475 lvItem.mask = LVIF_STATE;
5476 lvItem.state = lpLVItem->state;
5477 lvItem.stateMask = lpLVItem->stateMask ;
5479 /* apply to all items */
5480 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5483 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5491 ZeroMemory(&lvItem, sizeof(LVITEMA));
5492 lvItem.mask = LVIF_STATE;
5493 lvItem.state = lpLVItem->state;
5494 lvItem.stateMask = lpLVItem->stateMask;
5495 lvItem.iItem = nItem;
5496 bResult = ListView_SetItemA(hwnd, &lvItem);
5504 * Sets the text of an item or subitem.
5507 * [I] HWND : window handle
5508 * [I] INT : item index
5509 * [I] LPLVITEMA : item or subitem info
5515 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5517 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5518 BOOL bResult = FALSE;
5521 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5523 ZeroMemory(&lvItem, sizeof(LVITEMA));
5524 lvItem.mask = LVIF_TEXT;
5525 lvItem.pszText = lpLVItem->pszText;
5526 lvItem.iItem = nItem;
5527 lvItem.iSubItem = lpLVItem->iSubItem;
5528 bResult = ListView_SetItemA(hwnd, &lvItem);
5534 /* LISTVIEW_SetItemTextW */
5538 * Set item index that marks the start of a multiple selection.
5541 * [I] HWND : window handle
5545 * Index number or -1 if there is no selection mark.
5547 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5549 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5550 INT nOldIndex = infoPtr->nSelectionMark;
5552 infoPtr->nSelectionMark = nIndex;
5559 * Sets the text background color.
5562 * [I] HWND : window handle
5563 * [I] COLORREF : text background color
5569 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5571 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5573 infoPtr->clrTextBk = clrTextBk;
5574 InvalidateRect(hwnd, NULL, TRUE);
5581 * Sets the text foreground color.
5584 * [I] HWND : window handle
5585 * [I] COLORREF : text color
5591 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5593 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5595 infoPtr->clrText = clrText;
5596 InvalidateRect(hwnd, NULL, TRUE);
5601 /* LISTVIEW_SetToolTips */
5602 /* LISTVIEW_SetUnicodeFormat */
5603 /* LISTVIEW_SetWorkAreas */
5607 * Callback internally used by LISTVIEW_SortItems()
5610 * [I] LPVOID : first LISTVIEW_ITEM to compare
5611 * [I] LPVOID : second LISTVIEW_ITEM to compare
5612 * [I] LPARAM : HWND of control
5615 * if first comes before second : negative
5616 * if first comes after second : positive
5617 * if first and second are equivalent : zero
5619 static INT WINAPI LISTVIEW_CallBackCompare(
5624 /* Forward the call to the client defined callback */
5625 HWND hwnd = (HWND)lParam;
5626 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5628 return (infoPtr->pfnCompare)(
5629 ((LISTVIEW_ITEM *)first)->lParam,
5630 ((LISTVIEW_ITEM *)second)->lParam,
5631 infoPtr->lParamSort);
5636 * Sorts the listview items.
5639 * [I] HWND : window handle
5640 * [I] WPARAM : application-defined value
5641 * [I] LPARAM : pointer to comparision callback
5647 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5649 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5651 LISTVIEW_ITEM *lpItem;
5655 if (!infoPtr || !infoPtr->hdpaItems)
5658 nCount = GETITEMCOUNT(infoPtr);
5659 /* if there are 0 or 1 items, there is no need to sort */
5662 sortList = DPA_Create(nCount);
5664 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5665 infoPtr->lParamSort = (LPARAM)wParam;
5667 /* append pointers one by one to sortList */
5668 for (i = 0; i < nCount; i++)
5670 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5671 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5672 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5675 /* sort the sortList */
5676 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5678 /* copy the pointers back */
5679 for (i = 0; i < nCount; i++)
5681 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5682 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5683 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5686 DPA_Destroy(sortList);
5692 /* LISTVIEW_SubItemHitTest */
5696 * Updates an items or rearranges the listview control.
5699 * [I] HWND : window handle
5700 * [I] INT : item index
5706 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5708 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5709 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5710 BOOL bResult = FALSE;
5713 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5717 /* rearrange with default alignment style */
5718 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5719 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5721 ListView_Arrange(hwnd, 0);
5725 /* get item bounding rectangle */
5726 rc.left = LVIR_BOUNDS;
5727 ListView_GetItemRect(hwnd, nItem, &rc);
5728 InvalidateRect(hwnd, &rc, TRUE);
5737 * Creates the listview control.
5740 * [I] HWND : window handle
5745 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5747 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5748 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5749 UINT uView = lpcs->style & LVS_TYPEMASK;
5752 /* initialize info pointer */
5753 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5755 /* determine the type of structures to use */
5756 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5757 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5758 if (infoPtr->notifyFormat != NFR_ANSI)
5760 FIXME("ANSI notify format is NOT used\n");
5763 /* initialize color information */
5764 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5765 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5766 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5768 /* set default values */
5769 infoPtr->uCallbackMask = 0;
5770 infoPtr->nFocusedItem = -1;
5771 infoPtr->nSelectionMark = -1;
5772 infoPtr->nHotItem = -1;
5773 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5774 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5775 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5776 infoPtr->hwndEdit = 0;
5777 infoPtr->pedititem = NULL;
5779 /* get default font (icon title) */
5780 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5781 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5782 infoPtr->hFont = infoPtr->hDefaultFont;
5785 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5786 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5787 0, 0, 0, 0, hwnd, (HMENU)0,
5788 lpcs->hInstance, NULL);
5790 /* set header font */
5791 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5794 if (uView == LVS_ICON)
5796 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5797 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5799 else if (uView == LVS_REPORT)
5801 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5803 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5806 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5807 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5811 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5812 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5815 /* display unsupported listview window styles */
5816 LISTVIEW_UnsupportedStyles(lpcs->style);
5818 /* allocate memory for the data structure */
5819 infoPtr->hdpaItems = DPA_Create(10);
5821 /* initialize size of items */
5822 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5823 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
5830 * Erases the background of the listview control.
5833 * [I] HWND : window handle
5834 * [I] WPARAM : device context handle
5835 * [I] LPARAM : not used
5841 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5844 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5847 if (infoPtr->clrBk == CLR_NONE)
5849 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5854 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5855 GetClientRect(hwnd, &rc);
5856 FillRect((HDC)wParam, &rc, hBrush);
5857 DeleteObject(hBrush);
5866 * Retrieves the listview control font.
5869 * [I] HWND : window handle
5874 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5876 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5878 return infoPtr->hFont;
5883 * Performs vertical scrolling.
5886 * [I] HWND : window handle
5887 * [I] INT : scroll code
5888 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5890 * [I] HWND : scrollbar control window handle
5895 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5898 SCROLLINFO scrollInfo;
5900 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5901 scrollInfo.cbSize = sizeof(SCROLLINFO);
5902 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
5904 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5906 INT nOldScrollPos = scrollInfo.nPos;
5907 switch (nScrollCode)
5910 if (scrollInfo.nPos > scrollInfo.nMin)
5917 if (scrollInfo.nPos < scrollInfo.nMax)
5924 if (scrollInfo.nPos > scrollInfo.nMin)
5926 if (scrollInfo.nPos >= scrollInfo.nPage)
5928 scrollInfo.nPos -= scrollInfo.nPage;
5932 scrollInfo.nPos = scrollInfo.nMin;
5938 if (scrollInfo.nPos < scrollInfo.nMax)
5940 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
5942 scrollInfo.nPos += scrollInfo.nPage;
5946 scrollInfo.nPos = scrollInfo.nMax;
5952 scrollInfo.nPos = nCurrentPos;
5956 if (nOldScrollPos != scrollInfo.nPos)
5958 scrollInfo.fMask = SIF_POS;
5959 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
5960 InvalidateRect(hwnd, NULL, TRUE);
5969 * Performs horizontal scrolling.
5972 * [I] HWND : window handle
5973 * [I] INT : scroll code
5974 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5976 * [I] HWND : scrollbar control window handle
5981 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5984 SCROLLINFO scrollInfo;
5986 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5987 scrollInfo.cbSize = sizeof(SCROLLINFO);
5988 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
5990 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5992 INT nOldScrollPos = scrollInfo.nPos;
5994 switch (nScrollCode)
5997 if (scrollInfo.nPos > scrollInfo.nMin)
6004 if (scrollInfo.nPos < scrollInfo.nMax)
6011 if (scrollInfo.nPos > scrollInfo.nMin)
6013 if (scrollInfo.nPos >= scrollInfo.nPage)
6015 scrollInfo.nPos -= scrollInfo.nPage;
6019 scrollInfo.nPos = scrollInfo.nMin;
6025 if (scrollInfo.nPos < scrollInfo.nMax)
6027 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6029 scrollInfo.nPos += scrollInfo.nPage;
6033 scrollInfo.nPos = scrollInfo.nMax;
6039 scrollInfo.nPos = nCurrentPos;
6043 if (nOldScrollPos != scrollInfo.nPos)
6045 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6046 scrollInfo.fMask = SIF_POS;
6047 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6048 if(uView == LVS_REPORT)
6050 scrollInfo.fMask = SIF_POS;
6051 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6052 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6054 InvalidateRect(hwnd, NULL, TRUE);
6066 * [I] HWND : window handle
6067 * [I] INT : virtual key
6068 * [I] LONG : key data
6073 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6075 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6076 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6077 HWND hwndParent = GetParent(hwnd);
6078 NMLVKEYDOWN nmKeyDown;
6081 BOOL bRedraw = FALSE;
6083 /* send LVN_KEYDOWN notification */
6084 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6085 nmKeyDown.hdr.hwndFrom = hwnd;
6086 nmKeyDown.hdr.idFrom = nCtrlId;
6087 nmKeyDown.hdr.code = LVN_KEYDOWN;
6088 nmKeyDown.wVKey = nVirtualKey;
6089 nmKeyDown.flags = 0;
6090 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6093 nmh.hwndFrom = hwnd;
6094 nmh.idFrom = nCtrlId;
6096 switch (nVirtualKey)
6099 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6101 /* send NM_RETURN notification */
6102 nmh.code = NM_RETURN;
6103 ListView_Notify(hwndParent, nCtrlId, &nmh);
6105 /* send LVN_ITEMACTIVATE notification */
6106 nmh.code = LVN_ITEMACTIVATE;
6107 ListView_Notify(hwndParent, nCtrlId, &nmh);
6112 if (GETITEMCOUNT(infoPtr) > 0)
6119 if (GETITEMCOUNT(infoPtr) > 0)
6121 nItem = GETITEMCOUNT(infoPtr) - 1;
6126 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6130 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6134 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6138 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6150 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6152 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6153 if (bRedraw != FALSE)
6155 /* refresh client area */
6156 InvalidateRect(hwnd, NULL, TRUE);
6169 * [I] HWND : window handle
6174 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6176 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6177 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6180 TRACE("(hwnd=%x)\n", hwnd);
6182 /* send NM_KILLFOCUS notification */
6183 nmh.hwndFrom = hwnd;
6184 nmh.idFrom = nCtrlId;
6185 nmh.code = NM_KILLFOCUS;
6186 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6188 /* set window focus flag */
6189 infoPtr->bFocus = FALSE;
6191 /* NEED drawing optimization ; redraw the selected items */
6192 InvalidateRect(hwnd, NULL, FALSE);
6199 * Processes double click messages (left mouse button).
6202 * [I] HWND : window handle
6203 * [I] WORD : key flag
6204 * [I] WORD : x coordinate
6205 * [I] WORD : y coordinate
6210 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6213 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6216 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6218 /* send NM_DBLCLK notification */
6219 nmh.hwndFrom = hwnd;
6220 nmh.idFrom = nCtrlId;
6221 nmh.code = NM_DBLCLK;
6222 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6224 /* send LVN_ITEMACTIVATE notification */
6225 nmh.code = LVN_ITEMACTIVATE;
6226 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6233 * Processes mouse down messages (left mouse button).
6236 * [I] HWND : window handle
6237 * [I] WORD : key flag
6238 * [I] WORD : x coordinate
6239 * [I] WORD : y coordinate
6244 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6247 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6248 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6249 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6250 static BOOL bGroupSelect = TRUE;
6255 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6258 /* send NM_RELEASEDCAPTURE notification */
6259 nmh.hwndFrom = hwnd;
6260 nmh.idFrom = nCtrlId;
6261 nmh.code = NM_RELEASEDCAPTURE;
6262 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6264 if (infoPtr->bFocus == FALSE)
6269 /* set left button down flag */
6270 infoPtr->bLButtonDown = TRUE;
6272 ptPosition.x = wPosX;
6273 ptPosition.y = wPosY;
6274 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6275 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6277 if (lStyle & LVS_SINGLESEL)
6279 LISTVIEW_SetSelection(hwnd, nItem);
6283 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6285 if (bGroupSelect != FALSE)
6287 LISTVIEW_AddGroupSelection(hwnd, nItem);
6291 LISTVIEW_AddSelection(hwnd, nItem);
6294 else if (wKey & MK_CONTROL)
6296 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6298 else if (wKey & MK_SHIFT)
6300 LISTVIEW_SetGroupSelection(hwnd, nItem);
6304 LISTVIEW_SetSelection(hwnd, nItem);
6310 /* remove all selections */
6311 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6314 InvalidateRect(hwnd, NULL, TRUE);
6321 * Processes mouse up messages (left mouse button).
6324 * [I] HWND : window handle
6325 * [I] WORD : key flag
6326 * [I] WORD : x coordinate
6327 * [I] WORD : y coordinate
6332 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6335 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6337 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6339 if (infoPtr->bLButtonDown != FALSE)
6341 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6344 /* send NM_CLICK notification */
6345 nmh.hwndFrom = hwnd;
6346 nmh.idFrom = nCtrlId;
6347 nmh.code = NM_CLICK;
6348 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6350 /* set left button flag */
6351 infoPtr->bLButtonDown = FALSE;
6359 * Creates the listview control (called before WM_CREATE).
6362 * [I] HWND : window handle
6363 * [I] WPARAM : unhandled
6364 * [I] LPARAM : widow creation info
6369 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6371 LISTVIEW_INFO *infoPtr;
6373 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6375 /* allocate memory for info structure */
6376 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6377 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6378 if (infoPtr == NULL)
6380 ERR("could not allocate info memory!\n");
6384 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6386 ERR("pointer assignment error!\n");
6390 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6395 * Destroys the listview control (called after WM_DESTROY).
6398 * [I] HWND : window handle
6403 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6405 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6407 TRACE("(hwnd=%x)\n", hwnd);
6409 /* delete all items */
6410 LISTVIEW_DeleteAllItems(hwnd);
6412 /* destroy data structure */
6413 DPA_Destroy(infoPtr->hdpaItems);
6416 infoPtr->hFont = (HFONT)0;
6417 if (infoPtr->hDefaultFont)
6419 DeleteObject(infoPtr->hDefaultFont);
6422 /* free listview info pointer*/
6423 COMCTL32_Free(infoPtr);
6430 * Handles notifications from children.
6433 * [I] HWND : window handle
6434 * [I] INT : control identifier
6435 * [I] LPNMHDR : notification information
6440 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6442 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6444 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6446 /* handle notification from header control */
6447 if (lpnmh->code == HDN_ENDTRACKA)
6449 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6450 InvalidateRect(hwnd, NULL, TRUE);
6452 else if(lpnmh->code == HDN_ITEMCLICKA)
6454 /* Handle sorting by Header Column */
6456 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6457 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6459 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6460 nmlv.hdr.hwndFrom = hwnd;
6461 nmlv.hdr.idFrom = lCtrlId;
6462 nmlv.hdr.code = LVN_COLUMNCLICK;
6464 nmlv.iSubItem = pnmHeader->iItem;
6466 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6469 else if(lpnmh->code == NM_RELEASEDCAPTURE)
6471 /* Idealy this should be done in HDN_ENDTRACKA
6472 * but since SetItemBounds in Header.c is called after
6473 * the notification is sent, it is neccessary to handle the
6474 * update of the scroll bar here (Header.c works fine as it is,
6475 * no need to disturb it)
6477 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6478 LISTVIEW_UpdateScroll(hwnd);
6479 InvalidateRect(hwnd, NULL, TRUE);
6489 * Determines the type of structure to use.
6492 * [I] HWND : window handle of the sender
6493 * [I] HWND : listview window handle
6494 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6499 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6501 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6503 if (nCommand == NF_REQUERY)
6505 /* determine the type of structure to use */
6506 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6507 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6508 if (infoPtr->notifyFormat == NFR_UNICODE)
6510 FIXME("NO support for unicode structures");
6519 * Paints/Repaints the listview control.
6522 * [I] HWND : window handle
6523 * [I] HDC : device context handle
6528 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6532 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6536 hdc = BeginPaint(hwnd, &ps);
6537 LISTVIEW_Refresh(hwnd, hdc);
6538 EndPaint(hwnd, &ps);
6542 LISTVIEW_Refresh(hwnd, hdc);
6550 * Processes double click messages (right mouse button).
6553 * [I] HWND : window handle
6554 * [I] WORD : key flag
6555 * [I] WORD : x coordinate
6556 * [I] WORD : y coordinate
6561 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6564 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6567 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6569 /* send NM_RELEASEDCAPTURE notification */
6570 nmh.hwndFrom = hwnd;
6571 nmh.idFrom = nCtrlId;
6572 nmh.code = NM_RELEASEDCAPTURE;
6573 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6575 /* send NM_RDBLCLK notification */
6576 nmh.code = NM_RDBLCLK;
6577 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6584 * Processes mouse down messages (right mouse button).
6587 * [I] HWND : window handle
6588 * [I] WORD : key flag
6589 * [I] WORD : x coordinate
6590 * [I] WORD : y coordinate
6595 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6598 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6599 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6604 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6606 /* send NM_RELEASEDCAPTURE notification */
6607 nmh.hwndFrom = hwnd;
6608 nmh.idFrom = nCtrlId;
6609 nmh.code = NM_RELEASEDCAPTURE;
6610 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6612 /* make sure the listview control window has the focus */
6613 if (infoPtr->bFocus == FALSE)
6618 /* set right button down flag */
6619 infoPtr->bRButtonDown = TRUE;
6621 /* determine the index of the selected item */
6622 ptPosition.x = wPosX;
6623 ptPosition.y = wPosY;
6624 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6625 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6627 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6629 LISTVIEW_SetSelection(hwnd, nItem);
6634 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6642 * Processes mouse up messages (right mouse button).
6645 * [I] HWND : window handle
6646 * [I] WORD : key flag
6647 * [I] WORD : x coordinate
6648 * [I] WORD : y coordinate
6653 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6656 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6657 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6660 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6662 if (infoPtr->bRButtonDown != FALSE)
6664 /* send NM_RClICK notification */
6665 ZeroMemory(&nmh, sizeof(NMHDR));
6666 nmh.hwndFrom = hwnd;
6667 nmh.idFrom = nCtrlId;
6668 nmh.code = NM_RCLICK;
6669 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6671 /* set button flag */
6672 infoPtr->bRButtonDown = FALSE;
6683 * [I] HWND : window handle
6684 * [I] HWND : window handle of previously focused window
6689 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6691 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6692 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6695 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
6697 /* send NM_SETFOCUS notification */
6698 nmh.hwndFrom = hwnd;
6699 nmh.idFrom = nCtrlId;
6700 nmh.code = NM_SETFOCUS;
6701 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6703 /* set window focus flag */
6704 infoPtr->bFocus = TRUE;
6706 InvalidateRect(hwnd, NULL, TRUE);
6717 * [I] HWND : window handle
6718 * [I] HFONT : font handle
6719 * [I] WORD : redraw flag
6724 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6726 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6727 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6729 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6733 infoPtr->hFont = infoPtr->hDefaultFont;
6737 infoPtr->hFont = hFont;
6740 if (uView == LVS_REPORT)
6742 /* set header font */
6743 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6744 MAKELPARAM(fRedraw, 0));
6747 /* invalidate listview control client area */
6748 InvalidateRect(hwnd, NULL, TRUE);
6750 if (fRedraw != FALSE)
6760 * Resizes the listview control. This function processes WM_SIZE
6761 * messages. At this time, the width and height are not used.
6764 * [I] HWND : window handle
6765 * [I] WORD : new width
6766 * [I] WORD : new height
6771 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6773 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6774 UINT uView = lStyle & LVS_TYPEMASK;
6776 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
6778 LISTVIEW_UpdateSize(hwnd);
6780 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6782 if (lStyle & LVS_ALIGNLEFT)
6784 LISTVIEW_AlignLeft(hwnd);
6788 LISTVIEW_AlignTop(hwnd);
6792 LISTVIEW_UpdateScroll(hwnd);
6794 /* invalidate client area + erase background */
6795 InvalidateRect(hwnd, NULL, TRUE);
6802 * Sets the size information.
6805 * [I] HWND : window handle
6810 static VOID LISTVIEW_UpdateSize(HWND hwnd)
6812 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6813 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6814 UINT uView = lStyle & LVS_TYPEMASK;
6817 GetClientRect(hwnd, &rcList);
6818 infoPtr->rcList.left = 0;
6819 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
6820 infoPtr->rcList.top = 0;
6821 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
6823 if (uView == LVS_LIST)
6825 if ((lStyle & WS_HSCROLL) == 0)
6827 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6828 if (infoPtr->rcList.bottom > nHScrollHeight)
6830 infoPtr->rcList.bottom -= nHScrollHeight;
6834 else if (uView == LVS_REPORT)
6841 Header_Layout(infoPtr->hwndHeader, &hl);
6842 if (!(LVS_NOCOLUMNHEADER & lStyle))
6844 infoPtr->rcList.top = max(wp.cy, 0);
6851 * Processes WM_STYLECHANGED messages.
6854 * [I] HWND : window handle
6855 * [I] WPARAM : window style type (normal or extended)
6856 * [I] LPSTYLESTRUCT : window style information
6861 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6864 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6865 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
6866 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
6867 RECT rcList = infoPtr->rcList;
6869 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
6870 hwnd, wStyleType, lpss);
6872 if (wStyleType == GWL_STYLE)
6874 if (uOldView == LVS_REPORT)
6876 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6879 if ((lpss->styleOld & WS_HSCROLL) != 0)
6881 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6884 if ((lpss->styleOld & WS_VSCROLL) != 0)
6886 ShowScrollBar(hwnd, SB_VERT, FALSE);
6889 if (uNewView == LVS_ICON)
6891 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6892 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6893 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6894 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6895 if (lpss->styleNew & LVS_ALIGNLEFT)
6897 LISTVIEW_AlignLeft(hwnd);
6901 LISTVIEW_AlignTop(hwnd);
6904 else if (uNewView == LVS_REPORT)
6911 Header_Layout(infoPtr->hwndHeader, &hl);
6912 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
6914 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
6916 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6918 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6919 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6920 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6921 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6923 else if (uNewView == LVS_LIST)
6925 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6926 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6927 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6928 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6932 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6933 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6934 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6935 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6936 if (lpss->styleNew & LVS_ALIGNLEFT)
6938 LISTVIEW_AlignLeft(hwnd);
6942 LISTVIEW_AlignTop(hwnd);
6946 /* update the size of the client area */
6947 LISTVIEW_UpdateSize(hwnd);
6949 /* add scrollbars if needed */
6950 LISTVIEW_UpdateScroll(hwnd);
6952 /* invalidate client area + erase background */
6953 InvalidateRect(hwnd, NULL, TRUE);
6955 /* print the list of unsupported window styles */
6956 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6964 * Window procedure of the listview control.
6967 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6972 case LVM_APPROXIMATEVIEWRECT:
6973 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6974 LOWORD(lParam), HIWORD(lParam));
6976 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6978 /* case LVM_CREATEDRAGIMAGE: */
6980 case LVM_DELETEALLITEMS:
6981 return LISTVIEW_DeleteAllItems(hwnd);
6983 case LVM_DELETECOLUMN:
6984 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6986 case LVM_DELETEITEM:
6987 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6989 case LVM_EDITLABELW:
6990 case LVM_EDITLABELA:
6991 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
6993 case LVM_ENSUREVISIBLE:
6994 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6997 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6999 case LVM_GETBKCOLOR:
7000 return LISTVIEW_GetBkColor(hwnd);
7002 /* case LVM_GETBKIMAGE: */
7004 case LVM_GETCALLBACKMASK:
7005 return LISTVIEW_GetCallbackMask(hwnd);
7007 case LVM_GETCOLUMNA:
7008 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7010 /* case LVM_GETCOLUMNW: */
7012 case LVM_GETCOLUMNORDERARRAY:
7013 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7015 case LVM_GETCOLUMNWIDTH:
7016 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
7018 case LVM_GETCOUNTPERPAGE:
7019 return LISTVIEW_GetCountPerPage(hwnd);
7021 case LVM_GETEDITCONTROL:
7022 return LISTVIEW_GetEditControl(hwnd);
7024 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7025 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7028 return LISTVIEW_GetHeader(hwnd);
7030 /* case LVM_GETHOTCURSOR: */
7032 case LVM_GETHOTITEM:
7033 return LISTVIEW_GetHotItem(hwnd);
7035 /* case LVM_GETHOVERTIME: */
7037 case LVM_GETIMAGELIST:
7038 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7040 /* case LVM_GETISEARCHSTRING: */
7043 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
7045 /* case LVM_GETITEMW: */
7047 case LVM_GETITEMCOUNT:
7048 return LISTVIEW_GetItemCount(hwnd);
7050 case LVM_GETITEMPOSITION:
7051 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7053 case LVM_GETITEMRECT:
7054 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7056 case LVM_GETITEMSPACING:
7057 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7059 case LVM_GETITEMSTATE:
7060 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7062 case LVM_GETITEMTEXTA:
7063 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7066 /* case LVM_GETITEMTEXTW: */
7068 case LVM_GETNEXTITEM:
7069 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7071 /* case LVM_GETNUMBEROFWORKAREAS: */
7074 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7076 case LVM_GETSELECTEDCOUNT:
7077 return LISTVIEW_GetSelectedCount(hwnd);
7079 case LVM_GETSELECTIONMARK:
7080 return LISTVIEW_GetSelectionMark(hwnd);
7082 case LVM_GETSTRINGWIDTHA:
7083 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7085 /* case LVM_GETSTRINGWIDTHW: */
7086 /* case LVM_GETSUBITEMRECT: */
7088 case LVM_GETTEXTBKCOLOR:
7089 return LISTVIEW_GetTextBkColor(hwnd);
7091 case LVM_GETTEXTCOLOR:
7092 return LISTVIEW_GetTextColor(hwnd);
7094 /* case LVM_GETTOOLTIPS: */
7096 case LVM_GETTOPINDEX:
7097 return LISTVIEW_GetTopIndex(hwnd);
7099 /* case LVM_GETUNICODEFORMAT: */
7101 case LVM_GETVIEWRECT:
7102 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7104 /* case LVM_GETWORKAREAS: */
7107 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7109 case LVM_INSERTCOLUMNA:
7110 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7112 case LVM_INSERTCOLUMNW:
7113 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7115 case LVM_INSERTITEMA:
7116 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7118 case LVM_INSERTITEMW:
7119 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7121 case LVM_REDRAWITEMS:
7122 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7124 /* case LVM_SCROLL: */
7125 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7127 case LVM_SETBKCOLOR:
7128 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7130 /* case LVM_SETBKIMAGE: */
7132 case LVM_SETCALLBACKMASK:
7133 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7135 case LVM_SETCOLUMNA:
7136 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7138 case LVM_SETCOLUMNW:
7139 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7142 case LVM_SETCOLUMNORDERARRAY:
7143 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7145 case LVM_SETCOLUMNWIDTH:
7146 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
7148 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7149 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7151 /* case LVM_SETHOTCURSOR: */
7153 case LVM_SETHOTITEM:
7154 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7156 /* case LVM_SETHOVERTIME: */
7157 /* case LVM_SETICONSPACING: */
7159 case LVM_SETIMAGELIST:
7160 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7163 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7165 /* case LVM_SETITEMW: */
7167 case LVM_SETITEMCOUNT:
7168 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7170 case LVM_SETITEMPOSITION:
7171 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7172 (INT)HIWORD(lParam));
7174 /* case LVM_SETITEMPOSITION32: */
7176 case LVM_SETITEMSTATE:
7177 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7179 case LVM_SETITEMTEXTA:
7180 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7182 /* case LVM_SETITEMTEXTW: */
7184 case LVM_SETSELECTIONMARK:
7185 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7187 case LVM_SETTEXTBKCOLOR:
7188 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7190 case LVM_SETTEXTCOLOR:
7191 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7193 /* case LVM_SETTOOLTIPS: */
7194 /* case LVM_SETUNICODEFORMAT: */
7195 /* case LVM_SETWORKAREAS: */
7198 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7200 /* case LVM_SUBITEMHITTEST: */
7203 return LISTVIEW_Update(hwnd, (INT)wParam);
7207 return LISTVIEW_Command(hwnd, wParam, lParam);
7210 return LISTVIEW_Create(hwnd, wParam, lParam);
7213 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7216 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7219 return LISTVIEW_GetFont(hwnd);
7222 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7223 (INT)HIWORD(wParam), (HWND)lParam);
7226 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7229 return LISTVIEW_KillFocus(hwnd);
7231 case WM_LBUTTONDBLCLK:
7232 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7235 case WM_LBUTTONDOWN:
7236 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7239 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7242 /* case WM_MOUSEMOVE: */
7243 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
7246 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7249 return LISTVIEW_NCDestroy(hwnd);
7252 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7254 case WM_NOTIFYFORMAT:
7255 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7258 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7260 case WM_RBUTTONDBLCLK:
7261 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7264 case WM_RBUTTONDOWN:
7265 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7269 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7273 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7276 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7278 /* case WM_SETREDRAW: */
7281 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7283 case WM_STYLECHANGED:
7284 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7286 /* case WM_TIMER: */
7289 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7290 (INT)HIWORD(wParam), (HWND)lParam);
7292 /* case WM_WINDOWPOSCHANGED: */
7293 /* case WM_WININICHANGE: */
7296 if (uMsg >= WM_USER)
7298 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7302 /* call default window procedure */
7303 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7311 * Registers the window class.
7319 VOID LISTVIEW_Register(void)
7323 if (!GlobalFindAtomA(WC_LISTVIEWA))
7325 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7326 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7327 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7328 wndClass.cbClsExtra = 0;
7329 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7330 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7331 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7332 wndClass.lpszClassName = WC_LISTVIEWA;
7333 RegisterClassA(&wndClass);
7339 * Unregisters the window class.
7347 VOID LISTVIEW_Unregister(void)
7349 if (GlobalFindAtomA(WC_LISTVIEWA))
7351 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
7357 * Handle any WM_COMMAND messages
7363 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
7365 switch (HIWORD(wParam))
7370 * Adjust the edit window size
7373 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7374 HDC hdc = GetDC(infoPtr->hwndEdit);
7378 GetWindowTextA(infoPtr->hwndEdit, buffer, 1024);
7379 GetWindowRect(infoPtr->hwndEdit, &rect);
7380 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
7388 rect.bottom - rect.top,
7389 SWP_DRAWFRAME|SWP_NOMOVE);
7391 ReleaseDC(hwnd, hdc);
7397 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
7406 * Subclassed edit control windproc function
7412 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
7413 WPARAM wParam, LPARAM lParam)
7416 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
7417 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
7422 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
7429 WNDPROC editProc = einfo->EditWndProc;
7430 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
7431 COMCTL32_Free(einfo);
7432 infoPtr->pedititem = NULL;
7433 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
7437 if (VK_RETURN == (INT)wParam)
7442 else if (VK_ESCAPE == (INT)wParam)
7446 return CallWindowProcA(einfo->EditWndProc, hwnd,
7447 uMsg, wParam, lParam);
7450 if (einfo->EditLblCb)
7452 char *buffer = NULL;
7456 int len = 1 + GetWindowTextLengthA(hwnd);
7460 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
7462 GetWindowTextA(hwnd, buffer, len);
7467 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
7470 COMCTL32_Free(buffer);
7472 einfo->EditLblCb = NULL;
7475 SendMessageA(hwnd, WM_CLOSE, 0, 0);
7482 * Creates a subclassed edit cotrol
7488 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
7489 INT width, INT height, HWND parent, HINSTANCE hinst,
7490 EditlblCallback EditLblCb, DWORD param)
7493 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
7494 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
7497 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
7498 if (!(hedit = CreateWindowA("Edit", text, style, x, y, width, height,
7499 parent, 0, hinst, 0)))
7501 COMCTL32_Free(infoPtr->pedititem);
7505 infoPtr->pedititem->param = param;
7506 infoPtr->pedititem->EditLblCb = EditLblCb;
7507 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
7508 GWL_WNDPROC, (LONG) EditLblWndProc);