4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
8 * Listview control implementation.
11 * 1. No horizontal scrolling when header is larger than the client area.
12 * 2. Drawing optimizations.
13 * 3. Hot item handling.
16 * LISTVIEW_Notify : most notifications from children (editbox and header)
19 * LISTVIEW_SetItemCount : empty stub
22 * LISTVIEW_SetItemW : no unicode support
23 * LISTVIEW_InsertItemW : no unicode support
24 * LISTVIEW_InsertColumnW : no unicode support
25 * LISTVIEW_GetColumnW : no unicode support
26 * LISTVIEW_SetColumnW : no unicode support
28 * Advanced functionality:
29 * LISTVIEW_GetNumberOfWorkAreas : not implemented
30 * LISTVIEW_GetHotCursor : not implemented
31 * LISTVIEW_GetHoverTime : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_EditLabel : REPORT (need to implement a timer)
35 * LISTVIEW_GetColumnOrderArray : not implemented
36 * LISTVIEW_SetColumnOrderArray : not implemented
37 * LISTVIEW_Arrange : empty stub
38 * LISTVIEW_ApproximateViewRect : incomplete
39 * LISTVIEW_Scroll : not implemented
40 * LISTVIEW_RedrawItems : empty stub
41 * LISTVIEW_Update : not completed
49 #include "debugtools.h"
51 DEFAULT_DEBUG_CHANNEL(listview)
57 /* maximum size of a label */
58 #define DISP_TEXT_SIZE 128
60 /* padding for items in list and small icon display modes */
61 #define WIDTH_PADDING 12
63 /* padding for items in list, report and small icon display modes */
64 #define HEIGHT_PADDING 1
66 /* offset of items in report display mode */
67 #define REPORT_MARGINX 2
69 /* padding for icon in large icon display mode */
70 #define ICON_TOP_PADDING 2
71 #define ICON_BOTTOM_PADDING 2
73 /* padding for label in large icon display mode */
74 #define LABEL_VERT_OFFSET 2
76 /* default label width for items in list and small icon display modes */
77 #define DEFAULT_LABEL_WIDTH 40
79 /* default column width for items in list display mode */
80 #define DEFAULT_COLUMN_WIDTH 96
85 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
86 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
87 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
88 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
89 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
90 /* retrieve the number of items in the listview */
91 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
94 * forward declarations
96 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
97 static INT LISTVIEW_GetCountPerRow(HWND);
98 static INT LISTVIEW_GetCountPerColumn(HWND);
99 static VOID LISTVIEW_AlignLeft(HWND);
100 static VOID LISTVIEW_AlignTop(HWND);
101 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
102 static VOID LISTVIEW_AddSelection(HWND, INT);
103 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
104 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
105 static INT LISTVIEW_GetItemHeight(HWND);
106 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
107 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
108 static INT LISTVIEW_GetItemWidth(HWND);
109 static INT LISTVIEW_GetLabelWidth(HWND, INT);
110 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
111 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
112 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
113 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
114 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
115 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
116 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
117 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
118 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
119 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
120 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
121 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
122 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
123 static VOID LISTVIEW_UpdateScroll(HWND);
124 static VOID LISTVIEW_SetSelection(HWND, INT);
125 static VOID LISTVIEW_UpdateSize(HWND);
126 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
127 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
128 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
129 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
133 * Update the scrollbars. This functions should be called whenever
134 * the content, size or view changes.
137 * [I] HWND : window handle
142 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
144 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
145 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
146 UINT uView = lStyle & LVS_TYPEMASK;
147 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
148 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
149 SCROLLINFO scrollInfo;
151 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
152 scrollInfo.cbSize = sizeof(SCROLLINFO);
154 if (uView == LVS_LIST)
156 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
157 INT nCountPerPage = LISTVIEW_GetCountPerRow(hwnd) * nCountPerColumn;
158 if (nCountPerPage < GETITEMCOUNT(infoPtr))
160 /* calculate new scrollbar range */
161 INT nHiddenItemCount = GETITEMCOUNT(infoPtr) - nCountPerPage;
162 if (nHiddenItemCount % nCountPerColumn == 0)
164 scrollInfo.nMax = nHiddenItemCount / nCountPerColumn;
168 scrollInfo.nMax = nHiddenItemCount / nCountPerColumn + 1;
171 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
172 /*scrollInfo.nPage = LISTVIEW_GetCountPerRow(hwnd);*/
173 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
174 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
179 if (lStyle & WS_HSCROLL)
181 ShowScrollBar(hwnd, SB_HORZ, FALSE);
185 else if (uView == LVS_REPORT)
187 /* update vertical scrollbar */
189 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - LISTVIEW_GetCountPerColumn(hwnd);
190 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
191 /*scrollInfo.nPage = nCountPerColumn;*/
192 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
193 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
195 /* update horizontal scrollbar */
196 /* if (infoPtr->nItemWidth > nListWidth) */
198 /* scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; */
199 /* SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE); */
202 /* horizontal scrolling has not been implemented yet! I experienced some
203 problems when performing child window scrolling. */
209 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
211 INT nViewWidth = rcView.right - rcView.left;
212 INT nViewHeight = rcView.bottom - rcView.top;
214 if (nViewWidth > nListWidth)
217 INT nScrollPosWidth = nListWidth / 10;
219 if (nScrollPosWidth == 0)
222 nHiddenWidth = nViewWidth - nListWidth;
226 nHiddenWidth = nViewWidth - nScrollPosWidth * 10;
229 scrollInfo.fMask = SIF_POS;
230 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
235 if (nHiddenWidth % nScrollPosWidth == 0)
237 scrollInfo.nMax = nHiddenWidth / nScrollPosWidth;
241 scrollInfo.nMax = nHiddenWidth / nScrollPosWidth + 1;
245 /*scrollInfo.nPage = 10;*/
246 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
247 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
251 if (lStyle & WS_HSCROLL)
253 ShowScrollBar(hwnd, SB_HORZ, FALSE);
257 if (nViewHeight > nListHeight)
260 INT nScrollPosHeight = nListHeight / 10;
262 if (nScrollPosHeight == 0)
264 nScrollPosHeight = 1;
265 nHiddenHeight = nViewHeight - nListHeight;
269 nHiddenHeight = nViewHeight - nScrollPosHeight * 10;
272 scrollInfo.fMask = SIF_POS;
273 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE)
278 if (nHiddenHeight % nScrollPosHeight == 0)
280 scrollInfo.nMax = nHiddenHeight / nScrollPosHeight;
284 scrollInfo.nMax = nHiddenHeight / nScrollPosHeight + 1;
288 /*scrollInfo.nPage = 10;*/
289 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
290 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
294 if (lStyle & WS_VSCROLL)
296 ShowScrollBar(hwnd, SB_VERT, FALSE);
305 * Prints a message for unsupported window styles.
306 * A kind of TODO list for window styles.
309 * [I] LONG : window style
314 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
316 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
318 FIXME(" LVS_EDITLABELS\n");
321 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
323 FIXME(" LVS_NOLABELWRAP\n");
326 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
328 FIXME(" LVS_NOSCROLL\n");
331 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
333 FIXME(" LVS_NOSORTHEADER\n");
336 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
338 FIXME(" LVS_OWNERDRAWFIXED\n");
341 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
343 FIXME(" LVS_SHAREIMAGELISTS\n");
346 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
348 FIXME(" LVS_SORTASCENDING\n");
351 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
353 FIXME(" LVS_SORTDESCENDING\n");
359 * Aligns the items with the top edge of the window.
362 * [I] HWND : window handle
367 static VOID LISTVIEW_AlignTop(HWND hwnd)
369 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
370 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
371 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
376 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
378 ZeroMemory(&ptItem, sizeof(POINT));
379 ZeroMemory(&rcView, sizeof(RECT));
381 if (nListWidth > infoPtr->nItemWidth)
383 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
385 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
388 ptItem.y += infoPtr->nItemHeight;
391 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
392 ptItem.x += infoPtr->nItemWidth;
393 rcView.right = max(rcView.right, ptItem.x);
396 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
400 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
402 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
403 ptItem.y += infoPtr->nItemHeight;
406 rcView.right = infoPtr->nItemWidth;
407 rcView.bottom = ptItem.y;
410 LISTVIEW_SetViewRect(hwnd, &rcView);
416 * Aligns the items with the left edge of the window.
419 * [I] HWND : window handle
424 static VOID LISTVIEW_AlignLeft(HWND hwnd)
426 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
427 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
428 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
433 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
435 ZeroMemory(&ptItem, sizeof(POINT));
436 ZeroMemory(&rcView, sizeof(RECT));
438 if (nListHeight > infoPtr->nItemHeight)
440 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
442 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
445 ptItem.x += infoPtr->nItemWidth;
448 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
449 ptItem.y += infoPtr->nItemHeight;
450 rcView.bottom = max(rcView.bottom, ptItem.y);
453 rcView.right = ptItem.x + infoPtr->nItemWidth;
457 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
459 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
460 ptItem.x += infoPtr->nItemWidth;
463 rcView.bottom = infoPtr->nItemHeight;
464 rcView.right = ptItem.x;
467 LISTVIEW_SetViewRect(hwnd, &rcView);
473 * Set the bounding rectangle of all the items.
476 * [I] HWND : window handle
477 * [I] LPRECT : bounding rectangle
483 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
485 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
486 BOOL bResult = FALSE;
488 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
489 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
491 if (lprcView != NULL)
494 infoPtr->rcView.left = lprcView->left;
495 infoPtr->rcView.top = lprcView->top;
496 infoPtr->rcView.right = lprcView->right;
497 infoPtr->rcView.bottom = lprcView->bottom;
505 * Retrieves the bounding rectangle of all the items.
508 * [I] HWND : window handle
509 * [O] LPRECT : bounding rectangle
515 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
517 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
518 BOOL bResult = FALSE;
521 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
523 if (lprcView != NULL)
525 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
526 if (bResult != FALSE)
528 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
529 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
530 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
531 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
534 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
535 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
543 * Retrieves the subitem pointer associated with the subitem index.
546 * [I] HDPA : DPA handle for a specific item
547 * [I] INT : index of subitem
550 * SUCCESS : subitem pointer
553 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
556 LISTVIEW_SUBITEM *lpSubItem;
559 for (i = 1; i < hdpaSubItems->nItemCount; i++)
561 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
562 if (lpSubItem != NULL)
564 if (lpSubItem->iSubItem == nSubItem)
576 * Calculates the width of an item.
579 * [I] HWND : window handle
580 * [I] LONG : window style
583 * Returns item width.
585 static INT LISTVIEW_GetItemWidth(HWND hwnd)
587 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
588 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
589 INT nHeaderItemCount;
595 TRACE("(hwnd=%x)\n", hwnd);
597 if (uView == LVS_ICON)
599 nItemWidth = infoPtr->iconSpacing.cx;
601 else if (uView == LVS_REPORT)
603 /* calculate width of header */
604 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
605 for (i = 0; i < nHeaderItemCount; i++)
607 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
609 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
615 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
617 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
618 nItemWidth = max(nItemWidth, nLabelWidth);
621 /* default label size */
622 if (GETITEMCOUNT(infoPtr) == 0)
624 nItemWidth = DEFAULT_COLUMN_WIDTH;
630 nItemWidth = DEFAULT_LABEL_WIDTH;
635 nItemWidth += WIDTH_PADDING;
637 if (infoPtr->himlSmall != NULL)
639 nItemWidth += infoPtr->iconSize.cx;
642 if (infoPtr->himlState != NULL)
644 nItemWidth += infoPtr->iconSize.cx;
655 * Calculates the height of an item.
658 * [I] HWND : window handle
659 * [I] LONG : window style
662 * Returns item height.
664 static INT LISTVIEW_GetItemHeight(HWND hwnd)
666 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
667 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
670 if (uView == LVS_ICON)
672 nItemHeight = infoPtr->iconSpacing.cy;
677 HDC hdc = GetDC(hwnd);
678 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
679 GetTextMetricsA(hdc, &tm);
680 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
681 SelectObject(hdc, hOldFont);
682 ReleaseDC(hwnd, hdc);
690 * Adds a block of selections.
693 * [I] HWND : window handle
694 * [I] INT : item index
699 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
701 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
702 INT nFirst = min(infoPtr->nSelectionMark, nItem);
703 INT nLast = max(infoPtr->nSelectionMark, nItem);
707 lvItem.state = LVIS_SELECTED;
708 lvItem.stateMask= LVIS_SELECTED;
710 for (i = nFirst; i <= nLast; i++)
712 ListView_SetItemState(hwnd, i, &lvItem);
715 LISTVIEW_SetItemFocus(hwnd, nItem);
716 infoPtr->nSelectionMark = nItem;
721 * Adds a single selection.
724 * [I] HWND : window handle
725 * [I] INT : item index
730 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
732 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
735 lvItem.state = LVIS_SELECTED;
736 lvItem.stateMask= LVIS_SELECTED;
738 ListView_SetItemState(hwnd, nItem, &lvItem);
740 LISTVIEW_SetItemFocus(hwnd, nItem);
741 infoPtr->nSelectionMark = nItem;
746 * Selects or unselects an item.
749 * [I] HWND : window handle
750 * [I] INT : item index
756 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
758 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
762 lvItem.stateMask= LVIS_SELECTED;
764 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
767 ListView_SetItemState(hwnd, nItem, &lvItem);
772 lvItem.state = LVIS_SELECTED;
773 ListView_SetItemState(hwnd, nItem, &lvItem);
777 LISTVIEW_SetItemFocus(hwnd, nItem);
778 infoPtr->nSelectionMark = nItem;
785 * Selects items based on view coorddiantes.
788 * [I] HWND : window handle
789 * [I] RECT : selection rectangle
794 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
796 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
801 lvItem.stateMask = LVIS_SELECTED;
803 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
805 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
806 if (PtInRect(&rcSelRect, ptItem) != FALSE)
808 lvItem.state = LVIS_SELECTED;
815 ListView_SetItemState(hwnd, i, &lvItem);
821 * Sets a single group selection.
824 * [I] HWND : window handle
825 * [I] INT : item index
830 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
832 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
833 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
836 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
839 INT nFirst = min(infoPtr->nSelectionMark, nItem);
840 INT nLast = max(infoPtr->nSelectionMark, nItem);
841 lvItem.stateMask = LVIS_SELECTED;
843 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
845 if ((i < nFirst) || (i > nLast))
851 lvItem.state = LVIS_SELECTED;
854 ListView_SetItemState(hwnd, i, &lvItem);
862 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
863 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
864 rcSel.left = min(ptSelMark.x, ptItem.x);
865 rcSel.top = min(ptSelMark.y, ptItem.y);
866 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
867 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
868 LISTVIEW_SetSelectionRect(hwnd, rcSel);
871 LISTVIEW_SetItemFocus(hwnd, nItem);
876 * Manages the item focus.
879 * [I] HWND : window handle
880 * [I] INT : item index
883 * TRUE : focused item changed
884 * FALSE : focused item has NOT changed
886 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
888 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
889 BOOL bResult = FALSE;
892 if (infoPtr->nFocusedItem != nItem)
895 ZeroMemory(&lvItem, sizeof(LVITEMA));
896 lvItem.stateMask = LVIS_FOCUSED;
897 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
899 lvItem.state = LVIS_FOCUSED;
900 lvItem.stateMask = LVIS_FOCUSED;
901 ListView_SetItemState(hwnd, nItem, &lvItem);
903 infoPtr->nFocusedItem = nItem;
904 ListView_EnsureVisible(hwnd, nItem, FALSE);
912 * Sets a single selection.
915 * [I] HWND : window handle
916 * [I] INT : item index
921 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
923 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
928 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
931 if (nItem < GETITEMCOUNT(infoPtr))
933 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
936 ZeroMemory(&lvItem, sizeof(LVITEMA));
937 lvItem.stateMask = LVIS_FOCUSED;
938 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
940 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
941 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
942 ListView_SetItemState(hwnd, nItem, &lvItem);
944 infoPtr->nFocusedItem = nItem;
945 infoPtr->nSelectionMark = nItem;
950 * Set selection(s) with keyboard.
953 * [I] HWND : window handle
954 * [I] INT : item index
957 * SUCCESS : TRUE (needs to be repainted)
958 * FAILURE : FALSE (nothing has changed)
960 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
962 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
963 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
964 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
965 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
966 BOOL bResult = FALSE;
968 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
970 if (lStyle & LVS_SINGLESEL)
973 LISTVIEW_SetSelection(hwnd, nItem);
974 ListView_EnsureVisible(hwnd, nItem, FALSE);
981 LISTVIEW_SetGroupSelection(hwnd, nItem);
985 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
990 LISTVIEW_SetSelection(hwnd, nItem);
991 ListView_EnsureVisible(hwnd, nItem, FALSE);
1001 * Selects an item based on coordinates.
1004 * [I] HWND : window handle
1005 * [I] POINT : mouse click ccordinates
1008 * SUCCESS : item index
1011 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1013 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1017 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1019 rcItem.left = LVIR_SELECTBOUNDS;
1020 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1022 if (PtInRect(&rcItem, pt) != FALSE)
1034 * Removes all selection states.
1037 * [I] HWND : window handle
1038 * [I] INT : item index
1044 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1050 lvItem.stateMask = LVIS_SELECTED;
1052 for (i = nFirst; i <= nLast; i++)
1054 ListView_SetItemState(hwnd, i, &lvItem);
1063 * [IO] HDPA : dynamic pointer array handle
1064 * [I] INT : column index (subitem index)
1070 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1072 BOOL bResult = TRUE;
1076 for (i = 0; i < hdpaItems->nItemCount; i++)
1078 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1079 if (hdpaSubItems != NULL)
1081 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1093 * Removes a subitem at a given position.
1096 * [IO] HDPA : dynamic pointer array handle
1097 * [I] INT : subitem index
1103 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1105 LISTVIEW_SUBITEM *lpSubItem;
1108 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1110 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1111 if (lpSubItem != NULL)
1113 if (lpSubItem->iSubItem == nSubItem)
1116 if ((lpSubItem->pszText != NULL) &&
1117 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1119 COMCTL32_Free(lpSubItem->pszText);
1123 COMCTL32_Free(lpSubItem);
1125 /* free dpa memory */
1126 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1131 else if (lpSubItem->iSubItem > nSubItem)
1143 * Compares the item information.
1146 * [I] LISTVIEW_ITEM *: destination item
1147 * [I] LPLVITEM : source item
1150 * SUCCCESS : TRUE (EQUAL)
1151 * FAILURE : FALSE (NOT EQUAL)
1153 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1157 if ((lpItem != NULL) && (lpLVItem != NULL))
1159 if (lpLVItem->mask & LVIF_STATE)
1161 if ((lpItem->state & lpLVItem->stateMask) !=
1162 (lpLVItem->state & lpLVItem->stateMask))
1164 uChanged |= LVIF_STATE;
1168 if (lpLVItem->mask & LVIF_IMAGE)
1170 if (lpItem->iImage != lpLVItem->iImage)
1172 uChanged |= LVIF_IMAGE;
1176 if (lpLVItem->mask & LVIF_PARAM)
1178 if (lpItem->lParam != lpLVItem->lParam)
1180 uChanged |= LVIF_PARAM;
1184 if (lpLVItem->mask & LVIF_INDENT)
1186 if (lpItem->iIndent != lpLVItem->iIndent)
1188 uChanged |= LVIF_INDENT;
1192 if (lpLVItem->mask & LVIF_TEXT)
1194 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1196 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1198 uChanged |= LVIF_TEXT;
1203 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1205 uChanged |= LVIF_TEXT;
1209 if (lpLVItem->pszText)
1211 if (lpItem->pszText)
1213 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1215 uChanged |= LVIF_TEXT;
1220 uChanged |= LVIF_TEXT;
1225 if (lpItem->pszText)
1227 uChanged |= LVIF_TEXT;
1239 * Initializes item attributes.
1242 * [I] HWND : window handle
1243 * [O] LISTVIEW_ITEM *: destination item
1244 * [I] LPLVITEM : source item
1250 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1253 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1254 BOOL bResult = FALSE;
1256 if ((lpItem != NULL) && (lpLVItem != NULL))
1260 if (lpLVItem->mask & LVIF_STATE)
1262 lpItem->state &= ~lpLVItem->stateMask;
1263 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1266 if (lpLVItem->mask & LVIF_IMAGE)
1268 lpItem->iImage = lpLVItem->iImage;
1271 if (lpLVItem->mask & LVIF_PARAM)
1273 lpItem->lParam = lpLVItem->lParam;
1276 if (lpLVItem->mask & LVIF_INDENT)
1278 lpItem->iIndent = lpLVItem->iIndent;
1281 if (lpLVItem->mask & LVIF_TEXT)
1283 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1285 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1290 if ((lpItem->pszText != NULL) &&
1291 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1293 COMCTL32_Free(lpItem->pszText);
1296 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1300 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1302 lpItem->pszText = NULL;
1305 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1315 * Initializes subitem attributes.
1317 * NOTE: The documentation specifies that the operation fails if the user
1318 * tries to set the indent of a subitem.
1321 * [I] HWND : window handle
1322 * [O] LISTVIEW_SUBITEM *: destination subitem
1323 * [I] LPLVITEM : source subitem
1329 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1332 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1333 BOOL bResult = FALSE;
1335 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1337 if (!(lpLVItem->mask & LVIF_INDENT))
1340 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1342 lpSubItem->iSubItem = lpLVItem->iSubItem;
1344 if (lpLVItem->mask & LVIF_IMAGE)
1346 lpSubItem->iImage = lpLVItem->iImage;
1349 if (lpLVItem->mask & LVIF_TEXT)
1351 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1353 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1358 if ((lpSubItem->pszText != NULL) &&
1359 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1361 COMCTL32_Free(lpSubItem->pszText);
1364 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1368 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1370 lpSubItem->pszText = NULL;
1373 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1384 * Adds a subitem at a given position (column index).
1387 * [I] HWND : window handle
1388 * [I] LPLVITEM : new subitem atttributes
1394 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1396 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1397 LISTVIEW_SUBITEM *lpSubItem = NULL;
1398 BOOL bResult = FALSE;
1400 INT nPosition, nItem;
1402 if (lpLVItem != NULL)
1404 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1405 if (hdpaSubItems != NULL)
1407 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1408 if (lpSubItem != NULL)
1410 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1412 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1413 lpSubItem->iSubItem);
1414 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1424 /* cleanup if unsuccessful */
1425 if ((bResult == FALSE) && (lpSubItem != NULL))
1427 COMCTL32_Free(lpSubItem);
1435 * Finds the dpa insert position (array index).
1438 * [I] HWND : window handle
1439 * [I] INT : subitem index
1445 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1447 LISTVIEW_SUBITEM *lpSubItem;
1450 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1452 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1453 if (lpSubItem != NULL)
1455 if (lpSubItem->iSubItem > nSubItem)
1462 return hdpaSubItems->nItemCount;
1467 * Retrieves a listview subitem at a given position (column index).
1470 * [I] HWND : window handle
1471 * [I] INT : subitem index
1477 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1479 LISTVIEW_SUBITEM *lpSubItem;
1482 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1484 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1485 if (lpSubItem != NULL)
1487 if (lpSubItem->iSubItem == nSubItem)
1491 else if (lpSubItem->iSubItem > nSubItem)
1503 * Sets item attributes.
1506 * [I] HWND : window handle
1507 * [I] LPLVITEM : new item atttributes
1513 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1515 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1516 BOOL bResult = FALSE;
1518 LISTVIEW_ITEM *lpItem;
1521 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1523 if (lpLVItem != NULL)
1525 if (lpLVItem->iSubItem == 0)
1527 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1528 if (hdpaSubItems != NULL)
1530 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1533 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1534 nmlv.hdr.hwndFrom = hwnd;
1535 nmlv.hdr.idFrom = lCtrlId;
1536 nmlv.hdr.code = LVN_ITEMCHANGING;
1537 nmlv.lParam = lpItem->lParam;
1538 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1541 if (uChanged & LVIF_STATE)
1543 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1544 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1547 nmlv.uChanged = uChanged;
1548 nmlv.iItem = lpLVItem->iItem;
1549 nmlv.lParam = lpItem->lParam;
1550 /* send LVN_ITEMCHANGING notification */
1551 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1553 /* copy information */
1554 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1556 /* send LVN_ITEMCHANGED notification */
1557 nmlv.hdr.code = LVN_ITEMCHANGED;
1558 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1565 InvalidateRect(hwnd, NULL, FALSE);
1576 * Sets subitem attributes.
1579 * [I] HWND : window handle
1580 * [I] LPLVITEM : new subitem atttributes
1586 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1588 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1589 BOOL bResult = FALSE;
1591 LISTVIEW_SUBITEM *lpSubItem;
1593 if (lpLVItem != NULL)
1595 if (lpLVItem->iSubItem > 0)
1597 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1598 if (hdpaSubItems != NULL)
1600 /* set subitem only if column is present */
1601 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1603 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1604 if (lpSubItem != NULL)
1606 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1610 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1613 InvalidateRect(hwnd, NULL, FALSE);
1624 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1627 * [I] HWND : window handle
1632 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1634 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1635 UINT uView = lStyle & LVS_TYPEMASK;
1637 SCROLLINFO scrollInfo;
1639 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1640 scrollInfo.cbSize = sizeof(SCROLLINFO);
1641 scrollInfo.fMask = SIF_POS;
1643 if (uView == LVS_LIST)
1645 if (lStyle & WS_HSCROLL)
1647 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1649 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1653 else if (uView == LVS_REPORT)
1655 if (lStyle & WS_VSCROLL)
1657 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1659 nItem = scrollInfo.nPos;
1672 * [I] HWND : window handle
1673 * [I] HDC : device context handle
1674 * [I] INT : item index
1675 * [I] INT : subitem index
1676 * [I] RECT * : clipping rectangle
1681 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1684 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1685 CHAR szDispText[DISP_TEXT_SIZE];
1688 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd, hdc,
1691 /* get information needed for drawing the item */
1692 ZeroMemory(&lvItem, sizeof(LVITEMA));
1693 lvItem.mask = LVIF_TEXT;
1694 lvItem.iItem = nItem;
1695 lvItem.iSubItem = nSubItem;
1696 lvItem.cchTextMax = DISP_TEXT_SIZE;
1697 lvItem.pszText = szDispText;
1698 ListView_GetItemA(hwnd, &lvItem);
1700 /* set item colors */
1701 SetBkColor(hdc, infoPtr->clrTextBk);
1702 SetTextColor(hdc, infoPtr->clrText);
1704 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1705 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1714 * [I] HWND : window handle
1715 * [I] HDC : device context handle
1716 * [I] INT : item index
1717 * [I] RECT * : clipping rectangle
1722 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1724 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1725 CHAR szDispText[DISP_TEXT_SIZE];
1732 TRACE("(hwnd=%x, hdc=%x, nItem=%d\n", hwnd, hdc, nItem);
1734 /* get information needed for drawing the item */
1735 ZeroMemory(&lvItem, sizeof(LVITEMA));
1736 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1737 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1738 lvItem.iItem = nItem;
1739 lvItem.iSubItem = 0;
1740 lvItem.cchTextMax = DISP_TEXT_SIZE;
1741 lvItem.pszText = szDispText;
1742 ListView_GetItemA(hwnd, &lvItem);
1745 if (infoPtr->himlState != NULL)
1747 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1748 if (uStateImage != 0)
1750 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1751 rcItem.top, ILD_NORMAL);
1754 rcItem.left += infoPtr->iconSize.cx;
1758 if (infoPtr->himlSmall != NULL)
1760 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1762 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1763 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1764 rcItem.top, ILD_SELECTED);
1768 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1769 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1770 rcItem.top, ILD_NORMAL);
1773 rcItem.left += infoPtr->iconSize.cx;
1776 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1778 /* set item colors */
1779 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1780 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1781 /* set raster mode */
1782 nMixMode = SetROP2(hdc, R2_XORPEN);
1784 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1785 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1787 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1788 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1789 /* set raster mode */
1790 nMixMode = SetROP2(hdc, R2_COPYPEN);
1794 /* set item colors */
1795 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1796 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1797 /* set raster mode */
1798 nMixMode = SetROP2(hdc, R2_COPYPEN);
1801 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1802 if (rcItem.left + nLabelWidth < rcItem.right)
1804 rcItem.right = rcItem.left + nLabelWidth;
1808 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1809 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1811 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1813 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1818 SetROP2(hdc, R2_COPYPEN);
1819 SetBkColor(hdc, infoPtr->clrTextBk);
1820 SetTextColor(hdc, infoPtr->clrText);
1826 * Draws an item when in large icon display mode.
1829 * [I] HWND : window handle
1830 * [I] HDC : device context handle
1831 * [I] LISTVIEW_ITEM * : item
1832 * [I] INT : item index
1833 * [I] RECT * : clipping rectangle
1838 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1840 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1841 CHAR szDispText[DISP_TEXT_SIZE];
1842 INT nDrawPosX = rcItem.left;
1847 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1848 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1851 /* get information needed for drawing the item */
1852 ZeroMemory(&lvItem, sizeof(LVITEMA));
1853 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1854 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1855 lvItem.iItem = nItem;
1856 lvItem.iSubItem = 0;
1857 lvItem.cchTextMax = DISP_TEXT_SIZE;
1858 lvItem.pszText = szDispText;
1859 ListView_GetItemA(hwnd, &lvItem);
1861 if (lvItem.state & LVIS_SELECTED)
1863 /* set item colors */
1864 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1865 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1866 /* set raster mode */
1867 SetROP2(hdc, R2_XORPEN);
1871 /* set item colors */
1872 SetBkColor(hdc, infoPtr->clrTextBk);
1873 SetTextColor(hdc, infoPtr->clrText);
1874 /* set raster mode */
1875 SetROP2(hdc, R2_COPYPEN);
1878 if (infoPtr->himlNormal != NULL)
1880 rcItem.top += ICON_TOP_PADDING;
1881 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
1882 if (lvItem.state & LVIS_SELECTED)
1884 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1885 rcItem.top, ILD_SELECTED);
1889 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1890 rcItem.top, ILD_NORMAL);
1894 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
1895 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1896 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
1899 rcItem.left += nDrawPosX / 2;
1900 rcItem.right = rcItem.left + nLabelWidth;
1905 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
1909 GetTextMetricsA(hdc, &tm);
1910 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
1911 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1912 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1914 if (lvItem.state & LVIS_FOCUSED)
1916 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1922 * Draws listview items when in report display mode.
1925 * [I] HWND : window handle
1926 * [I] HDC : device context handle
1931 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
1933 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
1934 INT nDrawPosY = infoPtr->rcList.top;
1941 nItem = ListView_GetTopIndex(hwnd);
1943 /* add 1 for displaying a partial item at the bottom */
1944 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
1945 nLast = min(nLast, GETITEMCOUNT(infoPtr));
1946 for (; nItem < nLast; nItem++)
1948 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
1949 for (j = 0; j < nColumnCount; j++)
1951 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
1952 rcItem.left += REPORT_MARGINX;
1953 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
1954 rcItem.top = nDrawPosY;
1955 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
1958 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
1962 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
1966 nDrawPosY += infoPtr->nItemHeight;
1972 * Retrieves the number of items that can fit vertically in the client area.
1975 * [I] HWND : window handle
1978 * Number of items per row.
1980 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
1982 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
1983 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1984 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
1985 INT nCountPerRow = 1;
1989 if (uView == LVS_REPORT)
1995 nCountPerRow = nListWidth / infoPtr->nItemWidth;
1996 if (nCountPerRow == 0)
2003 return nCountPerRow;
2008 * Retrieves the number of items that can fit horizontally in the client
2012 * [I] HWND : window handle
2015 * Number of items per column.
2017 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2019 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2020 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2021 INT nCountPerColumn = 1;
2023 if (nListHeight > 0)
2025 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2026 if (nCountPerColumn == 0)
2028 nCountPerColumn = 1;
2032 return nCountPerColumn;
2037 * Retrieves the number of columns needed to display all the items when in
2038 * list display mode.
2041 * [I] HWND : window handle
2044 * Number of columns.
2046 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2048 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2049 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2050 INT nColumnCount = 0;
2052 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2054 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2056 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2060 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2064 return nColumnCount;
2070 * Draws listview items when in list display mode.
2073 * [I] HWND : window handle
2074 * [I] HDC : device context handle
2079 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2081 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2086 INT nCountPerColumn;
2087 INT nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2088 INT nItemHeight = LISTVIEW_GetItemHeight(hwnd);
2090 /* get number of fully visible columns */
2091 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2092 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2093 nItem = ListView_GetTopIndex(hwnd);
2095 for (i = 0; i < nColumnCount; i++)
2097 for (j = 0; j < nCountPerColumn; j++, nItem++)
2099 if (nItem >= GETITEMCOUNT(infoPtr))
2102 rcItem.top = j * nItemHeight;
2103 rcItem.left = i * nItemWidth;
2104 rcItem.bottom = rcItem.top + nItemHeight;
2105 rcItem.right = rcItem.left + nItemWidth;
2106 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2113 * Draws listview items when in icon or small icon display mode.
2116 * [I] HWND : window handle
2117 * [I] HDC : device context handle
2122 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2124 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2130 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2131 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2133 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2134 ptPosition.x += ptOrigin.x;
2135 ptPosition.y += ptOrigin.y;
2137 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2139 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2141 if (ptPosition.y < infoPtr->rcList.bottom)
2143 if (ptPosition.x < infoPtr->rcList.right)
2145 rcItem.top = ptPosition.y;
2146 rcItem.left = ptPosition.x;
2147 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2148 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2149 if (bSmall == FALSE)
2151 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2155 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2166 * Draws listview items.
2169 * [I] HWND : window handle
2170 * [I] HDC : device context handle
2175 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2177 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2178 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2183 hOldFont = SelectObject(hdc, infoPtr->hFont);
2185 /* select the doted pen (for drawing the focus box) */
2186 hPen = CreatePen(PS_DOT, 1, 0);
2187 hOldPen = SelectObject(hdc, hPen);
2189 /* select transparent brush (for drawing the focus box) */
2190 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2192 if (uView == LVS_LIST)
2194 LISTVIEW_RefreshList(hwnd, hdc);
2196 else if (uView == LVS_REPORT)
2198 LISTVIEW_RefreshReport(hwnd, hdc);
2200 else if (uView == LVS_SMALLICON)
2202 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2204 else if (uView == LVS_ICON)
2206 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2209 /* unselect objects */
2210 SelectObject(hdc, hOldFont);
2211 SelectObject(hdc, hOldPen);
2220 * Calculates the approximate width and height of a given number of items.
2223 * [I] HWND : window handle
2224 * [I] INT : number of items
2229 * Returns a DWORD. The width in the low word and the height in high word.
2231 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2232 WORD wWidth, WORD wHeight)
2234 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2235 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2236 INT nItemCountPerColumn = 1;
2237 INT nColumnCount = 0;
2238 DWORD dwViewRect = 0;
2240 if (nItemCount == -1)
2242 nItemCount = GETITEMCOUNT(infoPtr);
2245 if (uView == LVS_LIST)
2247 if (wHeight == 0xFFFF)
2249 /* use current height */
2250 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2253 if (wHeight < infoPtr->nItemHeight)
2255 wHeight = infoPtr->nItemHeight;
2260 if (infoPtr->nItemHeight > 0)
2262 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2263 if (nItemCountPerColumn == 0)
2265 nItemCountPerColumn = 1;
2268 if (nItemCount % nItemCountPerColumn != 0)
2270 nColumnCount = nItemCount / nItemCountPerColumn;
2274 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2279 /* Microsoft padding magic */
2280 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2281 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2283 dwViewRect = MAKELONG(wWidth, wHeight);
2285 else if (uView == LVS_REPORT)
2289 else if (uView == LVS_SMALLICON)
2293 else if (uView == LVS_ICON)
2303 * Arranges listview items in icon display mode.
2306 * [I] HWND : window handle
2307 * [I] INT : alignment code
2313 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2315 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2316 BOOL bResult = FALSE;
2318 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2331 case LVA_SNAPTOGRID:
2340 /* << LISTVIEW_CreateDragImage >> */
2344 * Removes all listview items and subitems.
2347 * [I] HWND : window handle
2353 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2355 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2356 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2357 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2358 UINT uView = lStyle & LVS_TYPEMASK;
2359 LISTVIEW_ITEM *lpItem;
2360 LISTVIEW_SUBITEM *lpSubItem;
2363 BOOL bResult = FALSE;
2368 TRACE("(hwnd=%x,)\n", hwnd);
2370 if (GETITEMCOUNT(infoPtr) > 0)
2372 /* initialize memory */
2373 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2375 /* send LVN_DELETEALLITEMS notification */
2376 nmlv.hdr.hwndFrom = hwnd;
2377 nmlv.hdr.idFrom = lCtrlId;
2378 nmlv.hdr.code = LVN_DELETEALLITEMS;
2381 /* verify if subsequent LVN_DELETEITEM notifications should be
2383 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2385 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2387 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2388 if (hdpaSubItems != NULL)
2390 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2392 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2393 if (lpSubItem != NULL)
2395 /* free subitem string */
2396 if ((lpSubItem->pszText != NULL) &&
2397 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2399 COMCTL32_Free(lpSubItem->pszText);
2403 COMCTL32_Free(lpSubItem);
2407 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2410 if (bSuppress == FALSE)
2412 /* send LVN_DELETEITEM notification */
2413 nmlv.hdr.code = LVN_DELETEITEM;
2415 nmlv.lParam = lpItem->lParam;
2416 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2419 /* free item string */
2420 if ((lpItem->pszText != NULL) &&
2421 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2423 COMCTL32_Free(lpItem->pszText);
2427 COMCTL32_Free(lpItem);
2430 DPA_Destroy(hdpaSubItems);
2434 /* reinitialize listview memory */
2435 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2437 /* align items (set position of each item) */
2438 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2440 if (lStyle & LVS_ALIGNLEFT)
2442 LISTVIEW_AlignLeft(hwnd);
2446 LISTVIEW_AlignTop(hwnd);
2450 LISTVIEW_UpdateScroll(hwnd);
2452 /* invalidate client area (optimization needed) */
2453 InvalidateRect(hwnd, NULL, TRUE);
2461 * Removes a column from the listview control.
2464 * [I] HWND : window handle
2465 * [I] INT : column index
2471 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2473 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2474 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2475 BOOL bResult = FALSE;
2477 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2479 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2481 /* reset scroll parameters */
2482 if (uView == LVS_REPORT)
2484 /* update scrollbar(s) */
2485 LISTVIEW_UpdateScroll(hwnd);
2487 /* refresh client area */
2488 InvalidateRect(hwnd, NULL, FALSE);
2497 * Removes an item from the listview control.
2500 * [I] HWND : window handle
2501 * [I] INT : item index
2507 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2509 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2510 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2511 UINT uView = lStyle & LVS_TYPEMASK;
2512 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2514 BOOL bResult = FALSE;
2516 LISTVIEW_ITEM *lpItem;
2517 LISTVIEW_SUBITEM *lpSubItem;
2520 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2522 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2524 /* initialize memory */
2525 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2527 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2528 if (hdpaSubItems != NULL)
2530 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2532 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2533 if (lpSubItem != NULL)
2535 /* free item string */
2536 if ((lpSubItem->pszText != NULL) &&
2537 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2539 COMCTL32_Free(lpSubItem->pszText);
2543 COMCTL32_Free(lpSubItem);
2547 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2550 /* send LVN_DELETEITEM notification */
2551 nmlv.hdr.hwndFrom = hwnd;
2552 nmlv.hdr.idFrom = lCtrlId;
2553 nmlv.hdr.code = LVN_DELETEITEM;
2555 nmlv.lParam = lpItem->lParam;
2556 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2559 /* free item string */
2560 if ((lpItem->pszText != NULL) &&
2561 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2563 COMCTL32_Free(lpItem->pszText);
2567 COMCTL32_Free(lpItem);
2570 bResult = DPA_Destroy(hdpaSubItems);
2573 /* align items (set position of each item) */
2574 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2576 if (lStyle & LVS_ALIGNLEFT)
2578 LISTVIEW_AlignLeft(hwnd);
2582 LISTVIEW_AlignTop(hwnd);
2586 LISTVIEW_UpdateScroll(hwnd);
2588 /* refresh client area */
2589 InvalidateRect(hwnd, NULL, TRUE);
2595 /* LISTVIEW_EditLabel */
2599 * Ensures the specified item is visible, scrolling into view if necessary.
2602 * [I] HWND : window handle
2603 * [I] INT : item index
2604 * [I] BOOL : partially or entirely visible
2610 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2612 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2613 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2614 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2615 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2616 INT nScrollPosHeight = 0;
2617 INT nScrollPosWidth = 0;
2618 SCROLLINFO scrollInfo;
2621 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2622 scrollInfo.cbSize = sizeof(SCROLLINFO);
2623 scrollInfo.fMask = SIF_POS;
2625 /* ALWAYS bPartial == FALSE, FOR NOW! */
2627 rcItem.left = LVIR_BOUNDS;
2628 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2630 if (rcItem.left < infoPtr->rcList.left)
2632 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2635 if (uView == LVS_LIST)
2637 nScrollPosWidth = infoPtr->nItemWidth;
2638 rcItem.left += infoPtr->rcList.left;
2640 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2642 nScrollPosWidth = max(1, nListWidth / 10);
2643 rcItem.left += infoPtr->rcList.left;
2646 if (rcItem.left % nScrollPosWidth == 0)
2648 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
2652 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
2655 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2658 else if (rcItem.right > infoPtr->rcList.right)
2660 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2663 if (uView == LVS_LIST)
2665 rcItem.right -= infoPtr->rcList.right;
2666 nScrollPosWidth = infoPtr->nItemWidth;
2668 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2670 rcItem.right -= infoPtr->rcList.right;
2671 nScrollPosWidth = max(1, nListWidth / 10);
2674 if (rcItem.right % nScrollPosWidth == 0)
2676 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
2680 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
2683 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2687 if (rcItem.top < infoPtr->rcList.top)
2690 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2692 if (uView == LVS_REPORT)
2694 rcItem.top -= infoPtr->rcList.top;
2695 nScrollPosHeight = infoPtr->nItemHeight;
2697 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2699 nScrollPosHeight = max(1, nListHeight / 10);
2700 rcItem.top += infoPtr->rcList.top;
2703 if (rcItem.top % nScrollPosHeight == 0)
2705 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
2709 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
2712 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2715 else if (rcItem.bottom > infoPtr->rcList.bottom)
2718 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2720 if (uView == LVS_REPORT)
2722 rcItem.bottom -= infoPtr->rcList.bottom;
2723 nScrollPosHeight = infoPtr->nItemHeight;
2725 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2727 nScrollPosHeight = max(1, nListHeight / 10);
2728 rcItem.bottom -= infoPtr->rcList.bottom;
2731 if (rcItem.bottom % nScrollPosHeight == 0)
2733 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
2737 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
2740 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2750 * Retrieves the nearest item, given a position and a direction.
2753 * [I] HWND : window handle
2754 * [I] POINT : start position
2755 * [I] UINT : direction
2758 * Item index if successdful, -1 otherwise.
2760 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
2762 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2763 LVHITTESTINFO lvHitTestInfo;
2767 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
2769 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
2770 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
2771 lvHitTestInfo.pt.x += pt.x;
2772 lvHitTestInfo.pt.y += pt.y;
2776 if (vkDirection == VK_DOWN)
2778 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
2780 else if (vkDirection == VK_UP)
2782 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
2784 else if (vkDirection == VK_LEFT)
2786 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
2788 else if (vkDirection == VK_RIGHT)
2790 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
2793 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
2799 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
2803 while (nItem == -1);
2811 * Searches for an item with specific characteristics.
2814 * [I] HWND : window handle
2815 * [I] INT : base item index
2816 * [I] LPLVFINDINFO : item information to look for
2819 * SUCCESS : index of item
2822 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
2823 LPLVFINDINFO lpFindInfo)
2825 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2827 CHAR szDispText[DISP_TEXT_SIZE];
2831 INT nLast = GETITEMCOUNT(infoPtr);
2833 if ((nItem >= -1) && (lpFindInfo != NULL))
2835 ZeroMemory(&lvItem, sizeof(LVITEMA));
2837 if (lpFindInfo->flags & LVFI_PARAM)
2839 lvItem.mask |= LVIF_PARAM;
2842 if (lpFindInfo->flags & LVFI_STRING)
2844 lvItem.mask |= LVIF_TEXT;
2845 lvItem.pszText = szDispText;
2846 lvItem.cchTextMax = DISP_TEXT_SIZE;
2849 if (lpFindInfo->flags & LVFI_PARTIAL)
2851 lvItem.mask |= LVIF_TEXT;
2852 lvItem.pszText = szDispText;
2853 lvItem.cchTextMax = DISP_TEXT_SIZE;
2856 if (lpFindInfo->flags & LVFI_WRAP)
2861 if (lpFindInfo->flags & LVFI_NEARESTXY)
2863 ptItem.x = lpFindInfo->pt.x;
2864 ptItem.y = lpFindInfo->pt.y;
2869 while (nItem < nLast)
2871 if (lpFindInfo->flags & LVFI_NEARESTXY)
2873 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
2874 lpFindInfo->vkDirection);
2877 /* get position of the new item index */
2878 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
2889 lvItem.iItem = nItem;
2890 lvItem.iSubItem = 0;
2891 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
2893 if (lvItem.mask & LVIF_TEXT)
2895 if (lpFindInfo->flags & LVFI_PARTIAL)
2897 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
2902 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
2907 if (lvItem.mask & LVIF_PARAM)
2909 if (lpFindInfo->lParam != lvItem.lParam)
2935 * Retrieves the background color of the listview control.
2938 * [I] HWND : window handle
2941 * COLORREF associated with the background.
2943 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
2945 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2947 return infoPtr->clrBk;
2952 * Retrieves the background image of the listview control.
2955 * [I] HWND : window handle
2956 * [O] LPLVMKBIMAGE : background image attributes
2962 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
2964 /* FIXME (listview, "empty stub!\n"); */
2970 * Retrieves the callback mask.
2973 * [I] HWND : window handle
2978 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
2980 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2982 return infoPtr->uCallbackMask;
2987 * Retrieves column attributes.
2990 * [I] HWND : window handle
2991 * [I] INT : column index
2992 * [IO] LPLVCOLUMNA : column information
2998 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3000 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3002 BOOL bResult = FALSE;
3004 if (lpColumn != NULL)
3006 /* initialize memory */
3007 ZeroMemory(&hdi, sizeof(HDITEMA));
3009 if (lpColumn->mask & LVCF_FMT)
3011 hdi.mask |= HDI_FORMAT;
3014 if (lpColumn->mask & LVCF_WIDTH)
3016 hdi.mask |= HDI_WIDTH;
3019 if (lpColumn->mask & LVCF_TEXT)
3021 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3024 if (lpColumn->mask & LVCF_IMAGE)
3026 hdi.mask |= HDI_IMAGE;
3029 if (lpColumn->mask & LVCF_ORDER)
3031 hdi.mask |= HDI_ORDER;
3034 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3035 if (bResult != FALSE)
3037 if (lpColumn->mask & LVCF_FMT)
3041 if (hdi.fmt & HDF_LEFT)
3043 lpColumn->fmt |= LVCFMT_LEFT;
3045 else if (hdi.fmt & HDF_RIGHT)
3047 lpColumn->fmt |= LVCFMT_RIGHT;
3049 else if (hdi.fmt & HDF_CENTER)
3051 lpColumn->fmt |= LVCFMT_CENTER;
3054 if (hdi.fmt & HDF_IMAGE)
3056 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3059 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3061 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3065 if (lpColumn->mask & LVCF_WIDTH)
3067 lpColumn->cx = hdi.cxy;
3070 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3072 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3075 if (lpColumn->mask & LVCF_IMAGE)
3077 lpColumn->iImage = hdi.iImage;
3080 if (lpColumn->mask & LVCF_ORDER)
3082 lpColumn->iOrder = hdi.iOrder;
3090 /* LISTVIEW_GetColumnW */
3091 /* LISTVIEW_GetColumnOrderArray */
3095 * Retrieves the column width.
3098 * [I] HWND : window handle
3099 * [I] int : column index
3102 * SUCCESS : column width
3105 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3107 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3108 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3109 INT nColumnWidth = 0;
3112 if (uView == LVS_LIST)
3114 nColumnWidth = infoPtr->nItemWidth;
3116 else if (uView == LVS_REPORT)
3118 /* get column width from header */
3119 ZeroMemory(&hdi, sizeof(HDITEMA));
3120 hdi.mask = HDI_WIDTH;
3121 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3123 nColumnWidth = hdi.cxy;
3127 return nColumnWidth;
3132 * In list or report display mode, retrieves the number of items that can fit
3133 * vertically in the visible area. In icon or small icon display mode,
3134 * retrieves the total number of visible items.
3137 * [I] HWND : window handle
3140 * Number of fully visible items.
3142 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3144 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3145 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3148 if (uView == LVS_LIST)
3150 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3152 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3153 LISTVIEW_GetCountPerColumn(hwnd);
3156 else if (uView == LVS_REPORT)
3158 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3162 nItemCount = GETITEMCOUNT(infoPtr);
3168 /* LISTVIEW_GetEditControl */
3172 * Retrieves the extended listview style.
3175 * [I] HWND : window handle
3178 * SUCCESS : previous style
3181 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3183 LISTVIEW_INFO *infoPtr;
3185 /* make sure we can get the listview info */
3186 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3189 return (infoPtr->dwExStyle);
3194 * Retrieves the handle to the header control.
3197 * [I] HWND : window handle
3202 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3204 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3206 return infoPtr->hwndHeader;
3209 /* LISTVIEW_GetHotCursor */
3210 /* LISTVIEW_GetHotItem */
3211 /* LISTVIEW_GetHoverTime */
3215 * Retrieves an image list handle.
3218 * [I] HWND : window handle
3219 * [I] INT : image list identifier
3222 * SUCCESS : image list handle
3225 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3228 HIMAGELIST himl = NULL;
3233 himl = infoPtr->himlNormal;
3236 himl = infoPtr->himlSmall;
3239 himl = infoPtr->himlState;
3243 return (LRESULT)himl;
3246 /* LISTVIEW_GetISearchString */
3250 * Retrieves item attributes.
3253 * [I] HWND : window handle
3254 * [IO] LPLVITEMA : item info
3260 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
3262 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3263 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3264 BOOL bResult = FALSE;
3265 NMLVDISPINFOA dispInfo;
3266 LISTVIEW_SUBITEM *lpSubItem;
3267 LISTVIEW_ITEM *lpItem;
3270 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3272 if (lpLVItem != NULL)
3274 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
3276 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3277 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3278 if (hdpaSubItems != NULL)
3280 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3284 if (lpLVItem->iSubItem == 0)
3286 if ((lpItem->iImage == I_IMAGECALLBACK) &&
3287 (lpLVItem->mask & LVIF_IMAGE))
3289 dispInfo.item.mask |= LVIF_IMAGE;
3292 if ((lpItem->pszText == LPSTR_TEXTCALLBACKA) &&
3293 (lpLVItem->mask & LVIF_TEXT))
3295 dispInfo.item.mask |= LVIF_TEXT;
3296 ZeroMemory(lpLVItem->pszText, sizeof(CHAR)*lpLVItem->cchTextMax);
3297 dispInfo.item.pszText = lpLVItem->pszText;
3298 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3301 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3303 dispInfo.item.mask |= LVIF_STATE;
3304 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3307 if (dispInfo.item.mask != 0)
3309 dispInfo.hdr.hwndFrom = hwnd;
3310 dispInfo.hdr.idFrom = lCtrlId;
3311 dispInfo.hdr.code = LVN_GETDISPINFOA;
3312 dispInfo.item.iItem = lpLVItem->iItem;
3313 dispInfo.item.iSubItem = 0;
3314 dispInfo.item.lParam = lpItem->lParam;
3315 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3318 if (dispInfo.item.mask & LVIF_IMAGE)
3320 lpLVItem->iImage = dispInfo.item.iImage;
3322 else if (lpLVItem->mask & LVIF_IMAGE)
3324 lpLVItem->iImage = lpItem->iImage;
3327 if (dispInfo.item.mask & LVIF_TEXT)
3329 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3331 Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
3333 strncpy(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
3335 else if (lpLVItem->mask & LVIF_TEXT)
3337 strncpy(lpLVItem->pszText, lpItem->pszText, lpLVItem->cchTextMax);
3340 if (dispInfo.item.mask & LVIF_STATE)
3342 lpLVItem->state = lpItem->state;
3343 lpLVItem->state &= ~dispInfo.item.stateMask;
3344 lpLVItem->state |= (dispInfo.item.state &
3345 dispInfo.item.stateMask);
3347 else if (lpLVItem->mask & LVIF_STATE)
3349 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3352 if (lpLVItem->mask & LVIF_PARAM)
3354 lpLVItem->lParam = lpItem->lParam;
3357 if (lpLVItem->mask & LVIF_INDENT)
3359 lpLVItem->iIndent = lpItem->iIndent;
3364 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems,
3365 lpLVItem->iSubItem);
3366 if (lpSubItem != NULL)
3368 if ((lpSubItem->iImage == I_IMAGECALLBACK) &&
3369 (lpLVItem->mask & LVIF_IMAGE))
3371 dispInfo.item.mask |= LVIF_IMAGE;
3374 if ((lpSubItem->pszText == LPSTR_TEXTCALLBACKA) &&
3375 (lpLVItem->mask & LVIF_TEXT))
3377 dispInfo.item.mask |= LVIF_TEXT;
3378 ZeroMemory(lpLVItem->pszText,
3379 sizeof(CHAR)*lpLVItem->cchTextMax);
3380 dispInfo.item.pszText = lpLVItem->pszText;
3381 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3386 if (lpLVItem->mask & LVIF_IMAGE)
3388 dispInfo.item.mask |= LVIF_IMAGE;
3391 if (lpLVItem->mask & LVIF_TEXT)
3393 dispInfo.item.mask |= LVIF_TEXT;
3394 ZeroMemory(lpLVItem->pszText,
3395 sizeof(CHAR)*lpLVItem->cchTextMax);
3396 dispInfo.item.pszText = lpLVItem->pszText;
3397 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3401 if (dispInfo.item.mask != 0)
3403 dispInfo.hdr.hwndFrom = hwnd;
3404 dispInfo.hdr.idFrom = lCtrlId;
3405 dispInfo.hdr.code = LVN_GETDISPINFOA;
3406 dispInfo.item.iItem = lpLVItem->iItem;
3407 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3408 dispInfo.item.lParam = lpItem->lParam;
3409 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3412 if (dispInfo.item.mask & LVIF_IMAGE)
3414 lpLVItem->iImage = dispInfo.item.iImage;
3416 else if (lpLVItem->mask & LVIF_IMAGE)
3418 lpLVItem->iImage = lpItem->iImage;
3421 if (dispInfo.item.mask & LVIF_TEXT)
3423 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3426 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
3428 strncpy(lpLVItem->pszText, dispInfo.item.pszText, lpLVItem->cchTextMax);
3430 else if (lpLVItem->mask & LVIF_TEXT)
3432 strncpy(lpLVItem->pszText, lpSubItem->pszText, lpLVItem->cchTextMax);
3443 /* LISTVIEW_GetItemW */
3444 /* LISTVIEW_GetHotCursor */
3448 * Retrieves the index of the hot item.
3451 * [I] HWND : window handle
3454 * SUCCESS : hot item index
3455 * FAILURE : -1 (no hot item)
3457 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3459 LISTVIEW_INFO *infoPtr;
3461 /* make sure we can get the listview info */
3462 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3465 return (infoPtr->nHotItem);
3468 /* LISTVIEW_GetHoverTime */
3472 * Retrieves the number of items in the listview control.
3475 * [I] HWND : window handle
3480 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3482 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3484 return GETITEMCOUNT(infoPtr);
3489 * Retrieves the position (upper-left) of the listview control item.
3492 * [I] HWND : window handle
3493 * [I] INT : item index
3494 * [O] LPPOINT : coordinate information
3500 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3501 LPPOINT lpptPosition)
3503 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3504 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3505 BOOL bResult = FALSE;
3507 LISTVIEW_ITEM *lpItem;
3508 INT nCountPerColumn;
3511 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3514 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3515 (lpptPosition != NULL))
3517 if (uView == LVS_LIST)
3520 nItem = nItem - ListView_GetTopIndex(hwnd);
3521 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3524 nRow = nItem % nCountPerColumn;
3527 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3528 lpptPosition->y = 0;
3532 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3533 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3538 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3539 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3542 else if (uView == LVS_REPORT)
3545 lpptPosition->x = REPORT_MARGINX;
3546 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3547 infoPtr->nItemHeight) + infoPtr->rcList.top;
3551 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3552 if (hdpaSubItems != NULL)
3554 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3558 lpptPosition->x = lpItem->ptPosition.x;
3559 lpptPosition->y = lpItem->ptPosition.y;
3570 * Retrieves the bounding rectangle for a listview control item.
3573 * [I] HWND : window handle
3574 * [I] INT : item index
3575 * [IO] LPRECT : bounding rectangle coordinates
3581 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3583 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3584 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3585 BOOL bResult = FALSE;
3594 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3596 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3598 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3603 if (uView == LVS_ICON)
3605 if (infoPtr->himlNormal != NULL)
3607 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3610 lprc->left = ptItem.x + ptOrigin.x;
3611 lprc->top = ptItem.y + ptOrigin.y;
3612 lprc->right = lprc->left + infoPtr->iconSize.cx;
3613 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3614 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3618 else if (uView == LVS_SMALLICON)
3620 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3623 lprc->left = ptItem.x + ptOrigin.x;
3624 lprc->top = ptItem.y + ptOrigin.y;
3625 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3627 if (infoPtr->himlState != NULL)
3628 lprc->left += infoPtr->iconSize.cx;
3630 if (infoPtr->himlSmall != NULL)
3631 lprc->right = lprc->left + infoPtr->iconSize.cx;
3633 lprc->right = lprc->left;
3639 lprc->left = ptItem.x;
3640 lprc->top = ptItem.y;
3641 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3643 if (infoPtr->himlState != NULL)
3645 lprc->left += infoPtr->iconSize.cx;
3648 if (infoPtr->himlSmall != NULL)
3650 lprc->right = lprc->left + infoPtr->iconSize.cx;
3654 lprc->right = lprc->left;
3660 if (uView == LVS_ICON)
3662 if (infoPtr->himlNormal != NULL)
3664 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3667 lprc->left = ptItem.x + ptOrigin.x;
3668 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3669 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3670 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3671 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3673 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3674 lprc->right = lprc->left + nLabelWidth;
3679 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3683 hOldFont = SelectObject(hdc, infoPtr->hFont);
3684 GetTextMetricsA(hdc, &tm);
3685 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3686 SelectObject(hdc, hOldFont);
3687 ReleaseDC(hwnd, hdc);
3691 else if (uView == LVS_SMALLICON)
3693 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3696 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
3697 lprc->top = ptItem.y + ptOrigin.y;
3698 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3700 if (infoPtr->himlState != NULL)
3702 lprc->left += infoPtr->iconSize.cx;
3705 if (infoPtr->himlSmall != NULL)
3707 lprc->left += infoPtr->iconSize.cx;
3710 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3711 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3713 lprc->right = lprc->left + nLabelWidth;
3717 lprc->right = nLeftPos + infoPtr->nItemWidth;
3724 nLeftPos = lprc->left = ptItem.x;
3725 lprc->top = ptItem.y;
3726 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3728 if (infoPtr->himlState != NULL)
3730 lprc->left += infoPtr->iconSize.cx;
3733 if (infoPtr->himlSmall != NULL)
3735 lprc->left += infoPtr->iconSize.cx;
3738 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3739 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3741 lprc->right = lprc->left + nLabelWidth;
3745 lprc->right = nLeftPos + infoPtr->nItemWidth;
3751 if (uView == LVS_ICON)
3753 if (infoPtr->himlNormal != NULL)
3755 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3758 lprc->left = ptItem.x + ptOrigin.x;
3759 lprc->top = ptItem.y + ptOrigin.y;
3760 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3761 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3765 else if (uView == LVS_SMALLICON)
3767 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3770 lprc->left = ptItem.x + ptOrigin.x;
3771 lprc->right = lprc->left;
3772 lprc->top = ptItem.y + ptOrigin.y;
3773 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3774 if (infoPtr->himlState != NULL)
3775 lprc->right += infoPtr->iconSize.cx;
3776 if (infoPtr->himlSmall != NULL)
3777 lprc->right += infoPtr->iconSize.cx;
3779 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3780 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
3782 lprc->right += nLabelWidth;
3786 lprc->right = lprc->left + infoPtr->nItemWidth;
3793 lprc->left = ptItem.x;
3794 lprc->right = lprc->left;
3795 lprc->top = ptItem.y;
3796 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3798 if (infoPtr->himlState != NULL)
3800 lprc->right += infoPtr->iconSize.cx;
3803 if (infoPtr->himlSmall != NULL)
3805 lprc->right += infoPtr->iconSize.cx;
3808 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3809 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
3811 lprc->right += nLabelWidth;
3815 lprc->right = lprc->left + infoPtr->nItemWidth;
3820 case LVIR_SELECTBOUNDS:
3821 if (uView == LVS_ICON)
3823 if (infoPtr->himlNormal != NULL)
3825 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3828 lprc->left = ptItem.x + ptOrigin.x;
3829 lprc->top = ptItem.y + ptOrigin.y;
3830 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3831 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3835 else if (uView == LVS_SMALLICON)
3837 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3840 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
3841 lprc->top = ptItem.y + ptOrigin.y;
3842 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3844 if (infoPtr->himlState != NULL)
3846 lprc->left += infoPtr->iconSize.cx;
3849 lprc->right = lprc->left;
3851 if (infoPtr->himlSmall != NULL)
3853 lprc->right += infoPtr->iconSize.cx;
3856 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3857 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3859 lprc->right += nLabelWidth;
3863 lprc->right = nLeftPos + infoPtr->nItemWidth;
3870 nLeftPos = lprc->left = ptItem.x;
3871 lprc->top = ptItem.y;
3872 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3874 if (infoPtr->himlState != NULL)
3876 lprc->left += infoPtr->iconSize.cx;
3879 lprc->right = lprc->left;
3881 if (infoPtr->himlSmall != NULL)
3883 lprc->right += infoPtr->iconSize.cx;
3886 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3887 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
3889 lprc->right += nLabelWidth;
3893 lprc->right = nLeftPos + infoPtr->nItemWidth;
3906 * Retrieves the width of a label.
3909 * [I] HWND : window handle
3912 * SUCCESS : string width (in pixels)
3915 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
3917 CHAR szDispText[DISP_TEXT_SIZE];
3918 INT nLabelWidth = 0;
3921 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
3923 ZeroMemory(&lvItem, sizeof(LVITEMA));
3924 lvItem.mask = LVIF_TEXT;
3925 lvItem.iItem = nItem;
3926 lvItem.cchTextMax = DISP_TEXT_SIZE;
3927 lvItem.pszText = szDispText;
3928 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3930 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3938 * Retrieves the spacing between listview control items.
3941 * [I] HWND : window handle
3942 * [I] BOOL : flag for small or large icon
3945 * Horizontal + vertical spacing
3947 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
3949 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3952 if (bSmall == FALSE)
3954 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
3958 /* TODO: need to store width of smallicon item */
3959 lResult = MAKELONG(0, infoPtr->nItemHeight);
3967 * Retrieves the state of a listview control item.
3970 * [I] HWND : window handle
3971 * [I] INT : item index
3972 * [I] UINT : state mask
3975 * State specified by the mask.
3977 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
3979 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3983 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3985 ZeroMemory(&lvItem, sizeof(LVITEMA));
3986 lvItem.iItem = nItem;
3987 lvItem.stateMask = uMask;
3988 lvItem.mask = LVIF_STATE;
3989 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3991 uState = lvItem.state;
4000 * Retrieves the text of a listview control item or subitem.
4003 * [I] HWND : window handle
4004 * [I] INT : item index
4005 * [IO] LPLVITEMA : item information
4008 * SUCCESS : string length
4011 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4013 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4016 if (lpLVItem != NULL)
4018 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4020 lpLVItem->mask = LVIF_TEXT;
4021 lpLVItem->iItem = nItem;
4022 if (ListView_GetItemA(hwnd, lpLVItem) != FALSE)
4024 nLength = lstrlenA(lpLVItem->pszText);
4034 * Searches for an item based on properties + relationships.
4037 * [I] HWND : window handle
4038 * [I] INT : item index
4039 * [I] INT : relationship flag
4042 * SUCCESS : item index
4045 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4047 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4048 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4050 LVFINDINFO lvFindInfo;
4051 INT nCountPerColumn;
4054 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4056 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4058 if (uFlags & LVNI_CUT)
4061 if (uFlags & LVNI_DROPHILITED)
4062 uMask |= LVIS_DROPHILITED;
4064 if (uFlags & LVNI_FOCUSED)
4065 uMask |= LVIS_FOCUSED;
4067 if (uFlags & LVNI_SELECTED)
4068 uMask |= LVIS_SELECTED;
4070 if (uFlags & LVNI_ABOVE)
4072 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4077 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4083 lvFindInfo.flags = LVFI_NEARESTXY;
4084 lvFindInfo.vkDirection = VK_UP;
4085 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4086 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4088 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4093 else if (uFlags & LVNI_BELOW)
4095 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4097 while (nItem < GETITEMCOUNT(infoPtr))
4100 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4106 lvFindInfo.flags = LVFI_NEARESTXY;
4107 lvFindInfo.vkDirection = VK_DOWN;
4108 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4109 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4111 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4116 else if (uFlags & LVNI_TOLEFT)
4118 if (uView == LVS_LIST)
4120 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4121 while (nItem - nCountPerColumn >= 0)
4123 nItem -= nCountPerColumn;
4124 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4128 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4130 lvFindInfo.flags = LVFI_NEARESTXY;
4131 lvFindInfo.vkDirection = VK_LEFT;
4132 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4133 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4135 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4140 else if (uFlags & LVNI_TORIGHT)
4142 if (uView == LVS_LIST)
4144 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4145 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4147 nItem += nCountPerColumn;
4148 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4152 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4154 lvFindInfo.flags = LVFI_NEARESTXY;
4155 lvFindInfo.vkDirection = VK_RIGHT;
4156 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4157 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4159 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4168 /* search by index */
4169 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4171 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4180 /* LISTVIEW_GetNumberOfWorkAreas */
4184 * Retrieves the origin coordinates when in icon or small icon display mode.
4187 * [I] HWND : window handle
4188 * [O] LPPOINT : coordinate information
4194 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4196 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4197 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4198 UINT uView = lStyle & LVS_TYPEMASK;
4199 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
4200 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
4201 BOOL bResult = FALSE;
4203 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4205 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4207 SCROLLINFO scrollInfo;
4208 ZeroMemory(lpptOrigin, sizeof(POINT));
4209 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4210 scrollInfo.cbSize = sizeof(SCROLLINFO);
4212 if (lStyle & WS_HSCROLL)
4214 scrollInfo.fMask = SIF_POS;
4215 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4217 lpptOrigin->x = -scrollInfo.nPos * max(nListWidth / 10, 1);
4221 if (lStyle & WS_VSCROLL)
4223 scrollInfo.fMask = SIF_POS;
4224 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4226 lpptOrigin->y = -scrollInfo.nPos * max(nListHeight / 10, 1);
4238 * Retrieves the number of items that are marked as selected.
4241 * [I] HWND : window handle
4244 * Number of items selected.
4246 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4248 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4249 INT nSelectedCount = 0;
4252 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4254 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4260 return nSelectedCount;
4265 * Retrieves item index that marks the start of a multiple selection.
4268 * [I] HWND : window handle
4271 * Index number or -1 if there is no selection mark.
4273 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4275 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4277 return infoPtr->nSelectionMark;
4282 * Retrieves the width of a string.
4285 * [I] HWND : window handle
4288 * SUCCESS : string width (in pixels)
4291 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4293 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4294 HFONT hFont, hOldFont;
4298 ZeroMemory(&stringSize, sizeof(SIZE));
4299 if (lpszText != NULL)
4301 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4303 hOldFont = SelectObject(hdc, hFont);
4304 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4305 SelectObject(hdc, hOldFont);
4306 ReleaseDC(hwnd, hdc);
4309 return stringSize.cx;
4314 * Retrieves the text backgound color.
4317 * [I] HWND : window handle
4320 * COLORREF associated with the the background.
4322 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4324 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4326 return infoPtr->clrTextBk;
4331 * Retrieves the text color.
4334 * [I] HWND : window handle
4337 * COLORREF associated with the text.
4339 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4341 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4343 return infoPtr->clrText;
4348 * Determines which section of the item was selected (if any).
4351 * [I] HWND : window handle
4352 * [IO] LPLVHITTESTINFO : hit test information
4355 * SUCCESS : item index
4358 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4360 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4364 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4365 lpHitTestInfo->pt.y);
4367 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4369 rcItem.left = LVIR_BOUNDS;
4370 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4372 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4374 rcItem.left = LVIR_ICON;
4375 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4377 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4379 lpHitTestInfo->flags = LVHT_ONITEMICON;
4380 lpHitTestInfo->iItem = i;
4381 lpHitTestInfo->iSubItem = 0;
4386 rcItem.left = LVIR_LABEL;
4387 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4389 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4391 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4392 lpHitTestInfo->iItem = i;
4393 lpHitTestInfo->iSubItem = 0;
4398 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4399 lpHitTestInfo->iItem = i;
4400 lpHitTestInfo->iSubItem = 0;
4406 lpHitTestInfo->flags = LVHT_NOWHERE;
4413 * Determines which listview item is located at the specified position.
4416 * [I] HWND : window handle
4417 * [IO} LPLVHITTESTINFO : hit test information
4420 * SUCCESS : item index
4423 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4425 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4428 lpHitTestInfo->flags = 0;
4430 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4432 lpHitTestInfo->flags = LVHT_TOLEFT;
4434 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4436 lpHitTestInfo->flags = LVHT_TORIGHT;
4438 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4440 lpHitTestInfo->flags |= LVHT_ABOVE;
4442 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4444 lpHitTestInfo->flags |= LVHT_BELOW;
4447 if (lpHitTestInfo->flags == 0)
4449 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4457 * Inserts a new column.
4460 * [I] HWND : window handle
4461 * [I] INT : column index
4462 * [I] LPLVCOLUMNA : column information
4465 * SUCCESS : new column index
4468 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4469 LPLVCOLUMNA lpColumn)
4471 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4473 INT nNewColumn = -1;
4475 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4478 if (lpColumn != NULL)
4480 /* initialize memory */
4481 ZeroMemory(&hdi, sizeof(HDITEMA));
4483 if (lpColumn->mask & LVCF_FMT)
4485 /* format member is valid */
4486 hdi.mask |= HDI_FORMAT;
4488 /* set text alignment (leftmost column must be left-aligned) */
4491 hdi.fmt |= HDF_LEFT;
4495 if (lpColumn->fmt & LVCFMT_LEFT)
4497 hdi.fmt |= HDF_LEFT;
4499 else if (lpColumn->fmt & LVCFMT_RIGHT)
4501 hdi.fmt |= HDF_RIGHT;
4503 else if (lpColumn->fmt & LVCFMT_CENTER)
4505 hdi.fmt |= HDF_CENTER;
4509 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4511 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4515 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4520 if (lpColumn->fmt & LVCFMT_IMAGE)
4522 hdi.fmt |= HDF_IMAGE;
4523 hdi.iImage = I_IMAGECALLBACK;
4527 if (lpColumn->mask & LVCF_WIDTH)
4529 hdi.mask |= HDI_WIDTH;
4530 hdi.cxy = lpColumn->cx;
4533 if (lpColumn->mask & LVCF_TEXT)
4535 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4536 hdi.pszText = lpColumn->pszText;
4537 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4538 hdi.fmt |= HDF_STRING;
4541 if (lpColumn->mask & LVCF_IMAGE)
4543 hdi.mask |= HDI_IMAGE;
4544 hdi.iImage = lpColumn->iImage;
4547 if (lpColumn->mask & LVCF_ORDER)
4549 hdi.mask |= HDI_ORDER;
4550 hdi.iOrder = lpColumn->iOrder;
4553 /* insert item in header control */
4554 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4555 (WPARAM)nColumn, (LPARAM)&hdi);
4557 LISTVIEW_UpdateScroll(hwnd);
4558 InvalidateRect(hwnd, NULL, FALSE);
4564 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4565 LPLVCOLUMNW lpColumn)
4570 memcpy(&lvca,lpColumn,sizeof(lvca));
4571 if (lpColumn->mask & LVCF_TEXT)
4572 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4573 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4574 if (lpColumn->mask & LVCF_TEXT)
4575 HeapFree(GetProcessHeap(),0,lvca.pszText);
4582 * Inserts a new item in the listview control.
4585 * [I] HWND : window handle
4586 * [I] LPLVITEMA : item information
4589 * SUCCESS : new item index
4592 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4594 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4595 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4596 UINT uView = lStyle & LVS_TYPEMASK;
4597 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4601 LISTVIEW_ITEM *lpItem = NULL;
4603 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4605 if (lpLVItem != NULL)
4607 /* make sure it's not a subitem; cannot insert a subitem */
4608 if (lpLVItem->iSubItem == 0)
4610 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4613 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4614 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4616 /* insert item in listview control data structure */
4617 hdpaSubItems = DPA_Create(8);
4618 if (hdpaSubItems != NULL)
4620 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4623 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4627 /* manage item focus */
4628 if (lpLVItem->mask & LVIF_STATE)
4630 if (lpLVItem->stateMask & LVIS_FOCUSED)
4632 LISTVIEW_SetItemFocus(hwnd, nItem);
4636 /* send LVN_INSERTITEM notification */
4637 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4638 nmlv.hdr.hwndFrom = hwnd;
4639 nmlv.hdr.idFrom = lCtrlId;
4640 nmlv.hdr.code = LVN_INSERTITEM;
4642 nmlv.lParam = lpItem->lParam;;
4643 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4645 /* align items (set position of each item) */
4646 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4648 if (lStyle & LVS_ALIGNLEFT)
4650 LISTVIEW_AlignLeft(hwnd);
4654 LISTVIEW_AlignTop(hwnd);
4658 LISTVIEW_UpdateScroll(hwnd);
4659 /* refresh client area */
4660 InvalidateRect(hwnd, NULL, FALSE);
4669 /* free memory if unsuccessful */
4670 if ((nItem == -1) && (lpItem != NULL))
4672 COMCTL32_Free(lpItem);
4678 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
4682 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
4683 if (lvia.mask & LVIF_TEXT) {
4684 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
4685 lvia.pszText = LPSTR_TEXTCALLBACKA;
4687 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
4689 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
4690 if (lvia.mask & LVIF_TEXT) {
4691 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
4692 HeapFree(GetProcessHeap(),0,lvia.pszText);
4697 /* LISTVIEW_InsertItemW */
4701 * Redraws a range of items.
4704 * [I] HWND : window handle
4705 * [I] INT : first item
4706 * [I] INT : last item
4712 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4714 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4715 BOOL bResult = FALSE;
4718 if (nFirst <= nLast)
4720 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4722 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4725 InvalidateRect(hwnd, &rc, FALSE);
4733 /* LISTVIEW_Scroll */
4737 * Sets the background color.
4740 * [I] HWND : window handle
4741 * [I] COLORREF : background color
4747 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
4749 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4751 infoPtr->clrBk = clrBk;
4752 InvalidateRect(hwnd, NULL, TRUE);
4757 /* LISTVIEW_SetBkImage */
4761 * Sets the callback mask. This mask will be used when the parent
4762 * window stores state information (some or all).
4765 * [I] HWND : window handle
4766 * [I] UINT : state mask
4772 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
4774 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4776 infoPtr->uCallbackMask = uMask;
4783 * Sets the attributes of a header item.
4786 * [I] HWND : window handle
4787 * [I] INT : column index
4788 * [I] LPLVCOLUMNA : column attributes
4794 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
4795 LPLVCOLUMNA lpColumn)
4797 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4798 BOOL bResult = FALSE;
4799 HDITEMA hdi, hdiget;
4801 if ((lpColumn != NULL) && (nColumn >= 0) &&
4802 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
4804 /* initialize memory */
4805 ZeroMemory(&hdi, sizeof(HDITEMA));
4807 if (lpColumn->mask & LVCF_FMT)
4809 /* format member is valid */
4810 hdi.mask |= HDI_FORMAT;
4812 /* get current format first */
4813 hdiget.mask = HDI_FORMAT;
4814 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
4815 /* preserve HDF_STRING if present */
4816 hdi.fmt = hdiget.fmt & HDF_STRING;
4818 /* set text alignment (leftmost column must be left-aligned) */
4821 hdi.fmt |= HDF_LEFT;
4825 if (lpColumn->fmt & LVCFMT_LEFT)
4827 hdi.fmt |= HDF_LEFT;
4829 else if (lpColumn->fmt & LVCFMT_RIGHT)
4831 hdi.fmt |= HDF_RIGHT;
4833 else if (lpColumn->fmt & LVCFMT_CENTER)
4835 hdi.fmt |= HDF_CENTER;
4839 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4841 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4844 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4846 hdi.fmt |= HDF_IMAGE;
4849 if (lpColumn->fmt & LVCFMT_IMAGE)
4851 hdi.fmt |= HDF_IMAGE;
4852 hdi.iImage = I_IMAGECALLBACK;
4856 if (lpColumn->mask & LVCF_WIDTH)
4858 hdi.mask |= HDI_WIDTH;
4859 hdi.cxy = lpColumn->cx;
4862 if (lpColumn->mask & LVCF_TEXT)
4864 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4865 hdi.pszText = lpColumn->pszText;
4866 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4867 hdi.fmt |= HDF_STRING;
4870 if (lpColumn->mask & LVCF_IMAGE)
4872 hdi.mask |= HDI_IMAGE;
4873 hdi.iImage = lpColumn->iImage;
4876 if (lpColumn->mask & LVCF_ORDER)
4878 hdi.mask |= HDI_ORDER;
4879 hdi.iOrder = lpColumn->iOrder;
4882 /* set header item attributes */
4883 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
4889 /* LISTVIEW_SetColumnW */
4890 /* LISTVIEW_SetColumnOrderArray */
4894 * Sets the width of a column
4897 * [I] HWND : window handle
4898 * [I] INT : column index
4899 * [I] INT : column width
4905 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
4907 LISTVIEW_INFO *infoPtr;
4912 /* set column width only if in report mode */
4913 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4914 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
4917 /* make sure we can get the listview info */
4918 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4920 if (!infoPtr->hwndHeader) /* make sure we have a header */
4923 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
4924 * LVSCV_AUTOSIZE_USEHEADER (-2)
4929 hdi.mask = HDI_WIDTH;
4932 /* call header to update the column change */
4933 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
4935 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4937 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
4944 * Sets the extended listview style.
4947 * [I] HWND : window handle
4952 * SUCCESS : previous style
4955 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
4957 LISTVIEW_INFO *infoPtr;
4960 /* make sure we can get the listview info */
4961 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4964 /* store previous style */
4965 dwOldStyle = infoPtr->dwExStyle;
4968 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
4970 return (dwOldStyle);
4973 /* LISTVIEW_SetHotCursor */
4977 * Sets the hot item index.
4980 * [I] HWND : window handle
4984 * SUCCESS : previous hot item index
4985 * FAILURE : -1 (no hot item)
4987 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
4989 LISTVIEW_INFO *infoPtr;
4992 /* make sure we can get the listview info */
4993 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4996 /* store previous index */
4997 iOldIndex = infoPtr->nHotItem;
5000 infoPtr->nHotItem = iIndex;
5005 /* LISTVIEW_SetIconSpacing */
5012 * [I] HWND : window handle
5013 * [I] INT : image list type
5014 * [I] HIMAGELIST : image list handle
5017 * SUCCESS : old image list
5020 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5022 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5023 HIMAGELIST himlTemp = 0;
5028 himlTemp = infoPtr->himlNormal;
5029 infoPtr->himlNormal = himl;
5030 return (LRESULT)himlTemp;
5033 himlTemp = infoPtr->himlSmall;
5034 infoPtr->himlSmall = himl;
5035 return (LRESULT)himlTemp;
5038 himlTemp = infoPtr->himlState;
5039 infoPtr->himlState = himl;
5040 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5041 return (LRESULT)himlTemp;
5044 return (LRESULT)NULL;
5050 * Sets the attributes of an item.
5053 * [I] HWND : window handle
5054 * [I] LPLVITEM : item information
5060 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5062 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5063 BOOL bResult = FALSE;
5065 if (lpLVItem != NULL)
5067 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5069 if (lpLVItem->iSubItem == 0)
5071 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5075 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5084 /* LISTVIEW_SetItemW */
5088 * Preallocates memory.
5091 * [I] HWND : window handle
5092 * [I] INT : item count (prjected number of items)
5093 * [I] DWORD : update flags
5099 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5101 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5103 FIXME("(%d %08lx)empty stub!\n", nItems, dwFlags);
5106 return LISTVIEW_DeleteAllItems (hwnd);
5108 if (nItems > GETITEMCOUNT(infoPtr))
5111 FIXME("append items\n");
5114 else if (nItems < GETITEMCOUNT(infoPtr))
5117 FIXME("remove items\n");
5126 * Sets the position of an item.
5129 * [I] HWND : window handle
5130 * [I] INT : item index
5131 * [I] INT : x coordinate
5132 * [I] INT : y coordinate
5138 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5139 INT nPosX, INT nPosY)
5141 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5142 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5143 LISTVIEW_ITEM *lpItem;
5145 BOOL bResult = FALSE;
5147 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5149 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5151 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5153 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5154 if (hdpaSubItems != NULL)
5156 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5160 lpItem->ptPosition.x = nPosX;
5161 lpItem->ptPosition.y = nPosY;
5170 /* LISTVIEW_SetItemPosition32 */
5174 * Sets the state of one or many items.
5177 * [I] HWND : window handle
5178 * [I]INT : item index
5179 * [I] LPLVITEM : item or subitem info
5185 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5187 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5188 BOOL bResult = FALSE;
5195 ZeroMemory(&lvItem, sizeof(LVITEMA));
5196 lvItem.mask = LVIF_STATE;
5197 lvItem.state = lpLVItem->state;
5198 lvItem.stateMask = lpLVItem->stateMask ;
5200 /* apply to all items */
5201 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5204 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5212 ZeroMemory(&lvItem, sizeof(LVITEMA));
5213 lvItem.mask = LVIF_STATE;
5214 lvItem.state = lpLVItem->state;
5215 lvItem.stateMask = lpLVItem->stateMask;
5216 lvItem.iItem = nItem;
5217 bResult = ListView_SetItemA(hwnd, &lvItem);
5225 * Sets the text of an item or subitem.
5228 * [I] HWND : window handle
5229 * [I] INT : item index
5230 * [I] LPLVITEMA : item or subitem info
5236 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5238 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5239 BOOL bResult = FALSE;
5242 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5244 ZeroMemory(&lvItem, sizeof(LVITEMA));
5245 lvItem.mask = LVIF_TEXT;
5246 lvItem.pszText = lpLVItem->pszText;
5247 lvItem.iItem = nItem;
5248 lvItem.iSubItem = lpLVItem->iSubItem;
5249 bResult = ListView_SetItemA(hwnd, &lvItem);
5255 /* LISTVIEW_SetItemTextW */
5259 * Set item index that marks the start of a multiple selection.
5262 * [I] HWND : window handle
5266 * Index number or -1 if there is no selection mark.
5268 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5270 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5271 INT nOldIndex = infoPtr->nSelectionMark;
5273 infoPtr->nSelectionMark = nIndex;
5280 * Sets the text background color.
5283 * [I] HWND : window handle
5284 * [I] COLORREF : text background color
5290 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5292 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5294 infoPtr->clrTextBk = clrTextBk;
5295 InvalidateRect(hwnd, NULL, TRUE);
5302 * Sets the text foreground color.
5305 * [I] HWND : window handle
5306 * [I] COLORREF : text color
5312 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5314 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5316 infoPtr->clrText = clrText;
5317 InvalidateRect(hwnd, NULL, TRUE);
5322 /* LISTVIEW_SetToolTips */
5323 /* LISTVIEW_SetUnicodeFormat */
5324 /* LISTVIEW_SetWorkAreas */
5328 * Callback internally used by LISTVIEW_SortItems()
5331 * [I] LPVOID : first LISTVIEW_ITEM to compare
5332 * [I] LPVOID : second LISTVIEW_ITEM to compare
5333 * [I] LPARAM : HWND of control
5336 * if first comes before second : negative
5337 * if first comes after second : positive
5338 * if first and second are equivalent : zero
5340 static INT WINAPI LISTVIEW_CallBackCompare(
5345 /* Forward the call to the client defined callback */
5346 HWND hwnd = (HWND)lParam;
5347 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5349 return (infoPtr->pfnCompare)(
5350 ((LISTVIEW_ITEM *)first)->lParam,
5351 ((LISTVIEW_ITEM *)second)->lParam,
5352 infoPtr->lParamSort);
5357 * Sorts the listview items.
5360 * [I] HWND : window handle
5361 * [I] WPARAM : application-defined value
5362 * [I] LPARAM : pointer to comparision callback
5368 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5370 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5372 LISTVIEW_ITEM *lpItem;
5376 if (!infoPtr || !infoPtr->hdpaItems)
5379 nCount = GETITEMCOUNT(infoPtr);
5380 /* if there are 0 or 1 items, there is no need to sort */
5383 sortList = DPA_Create(nCount);
5385 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5386 infoPtr->lParamSort = (LPARAM)wParam;
5388 /* append pointers one by one to sortList */
5389 for (i = 0; i < nCount; i++)
5391 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5392 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5393 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5396 /* sort the sortList */
5397 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5399 /* copy the pointers back */
5400 for (i = 0; i < nCount; i++)
5402 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5403 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5404 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5407 DPA_Destroy(sortList);
5413 /* LISTVIEW_SubItemHitTest */
5417 * Updates an items or rearranges the listview control.
5420 * [I] HWND : window handle
5421 * [I] INT : item index
5427 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5429 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5430 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5431 BOOL bResult = FALSE;
5434 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5438 /* rearrange with default alignment style */
5439 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5440 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5442 ListView_Arrange(hwnd, 0);
5446 /* get item bounding rectangle */
5447 rc.left = LVIR_BOUNDS;
5448 ListView_GetItemRect(hwnd, nItem, &rc);
5449 InvalidateRect(hwnd, &rc, TRUE);
5458 * Creates the listview control.
5461 * [I] HWND : window handle
5466 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5468 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5469 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5470 UINT uView = lpcs->style & LVS_TYPEMASK;
5473 /* initialize info pointer */
5474 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5476 /* determine the type of structures to use */
5477 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5478 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5479 if (infoPtr->notifyFormat != NFR_ANSI)
5481 FIXME("ANSI notify format is NOT used\n");
5484 /* initialize color information */
5485 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5486 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5487 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5489 /* set default values */
5490 infoPtr->uCallbackMask = 0;
5491 infoPtr->nFocusedItem = -1;
5492 infoPtr->nSelectionMark = -1;
5493 infoPtr->nHotItem = -1;
5494 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5495 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5496 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5498 /* get default font (icon title) */
5499 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5500 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5501 infoPtr->hFont = infoPtr->hDefaultFont;
5504 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5505 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5506 0, 0, 0, 0, hwnd, (HMENU)0,
5507 lpcs->hInstance, NULL);
5509 /* set header font */
5510 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5513 if (uView == LVS_ICON)
5515 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5516 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5518 else if (uView == LVS_REPORT)
5520 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5522 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5525 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5526 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5530 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5531 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5534 /* display unsupported listview window styles */
5535 LISTVIEW_UnsupportedStyles(lpcs->style);
5537 /* allocate memory for the data structure */
5538 infoPtr->hdpaItems = DPA_Create(10);
5540 /* initialize size of items */
5541 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5542 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
5549 * Erases the background of the listview control.
5552 * [I] HWND : window handle
5553 * [I] WPARAM : device context handle
5554 * [I] LPARAM : not used
5560 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5563 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5566 if (infoPtr->clrBk == CLR_NONE)
5568 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5573 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5574 GetClientRect(hwnd, &rc);
5575 FillRect((HDC)wParam, &rc, hBrush);
5576 DeleteObject(hBrush);
5585 * Retrieves the listview control font.
5588 * [I] HWND : window handle
5593 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5595 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5597 return infoPtr->hFont;
5602 * Performs vertical scrolling.
5605 * [I] HWND : window handle
5606 * [I] INT : scroll code
5607 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5609 * [I] HWND : scrollbar control window handle
5614 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5617 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5618 SCROLLINFO scrollInfo;
5620 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5621 scrollInfo.cbSize = sizeof(SCROLLINFO);
5622 scrollInfo.fMask = /*SIF_PAGE |*/ SIF_POS | SIF_RANGE;
5624 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5626 INT nOldScrollPos = scrollInfo.nPos;
5627 switch (nScrollCode)
5630 if (scrollInfo.nPos > scrollInfo.nMin)
5637 if (scrollInfo.nPos < scrollInfo.nMax)
5644 if (scrollInfo.nPos > scrollInfo.nMin)
5648 if (uView == LVS_REPORT)
5650 nPage = LISTVIEW_GetCountPerColumn(hwnd);
5652 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5657 if (scrollInfo.nPos >= nPage)
5659 scrollInfo.nPos -= nPage;
5663 scrollInfo.nPos = scrollInfo.nMin;
5669 if (scrollInfo.nPos < scrollInfo.nMax)
5673 if (uView == LVS_REPORT)
5675 nPage = LISTVIEW_GetCountPerColumn(hwnd);
5677 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5682 if (scrollInfo.nPos <= scrollInfo.nMax - nPage)
5684 scrollInfo.nPos += nPage;
5688 scrollInfo.nPos = scrollInfo.nMax;
5693 case SB_THUMBPOSITION:
5697 if (nOldScrollPos != scrollInfo.nPos)
5699 scrollInfo.fMask = SIF_POS;
5700 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
5701 InvalidateRect(hwnd, NULL, TRUE);
5710 * Performs horizontal scrolling.
5713 * [I] HWND : window handle
5714 * [I] INT : scroll code
5715 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5717 * [I] HWND : scrollbar control window handle
5722 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5725 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5726 SCROLLINFO scrollInfo;
5728 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5729 scrollInfo.cbSize = sizeof(SCROLLINFO);
5730 scrollInfo.fMask = /*SIF_PAGE |*/ SIF_POS | SIF_RANGE;
5732 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5734 INT nOldScrollPos = scrollInfo.nPos;
5736 switch (nScrollCode)
5739 if (scrollInfo.nPos > scrollInfo.nMin)
5746 if (scrollInfo.nPos < scrollInfo.nMax)
5753 if (scrollInfo.nPos > scrollInfo.nMin)
5757 if (uView == LVS_LIST)
5759 nPage = LISTVIEW_GetCountPerRow(hwnd);
5761 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5766 if (scrollInfo.nPos >= nPage)
5768 scrollInfo.nPos -= nPage;
5772 scrollInfo.nPos = scrollInfo.nMin;
5778 if (scrollInfo.nPos < scrollInfo.nMax)
5782 if (uView == LVS_LIST)
5784 nPage = LISTVIEW_GetCountPerRow(hwnd);
5786 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5791 if (scrollInfo.nPos <= scrollInfo.nMax - nPage)
5793 scrollInfo.nPos += nPage;
5797 scrollInfo.nPos = scrollInfo.nMax;
5802 case SB_THUMBPOSITION:
5806 if (nOldScrollPos != scrollInfo.nPos)
5808 scrollInfo.fMask = SIF_POS;
5809 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
5810 InvalidateRect(hwnd, NULL, TRUE);
5822 * [I] HWND : window handle
5823 * [I] INT : virtual key
5824 * [I] LONG : key data
5829 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
5831 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5832 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5833 HWND hwndParent = GetParent(hwnd);
5834 NMLVKEYDOWN nmKeyDown;
5837 BOOL bRedraw = FALSE;
5839 /* send LVN_KEYDOWN notification */
5840 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
5841 nmKeyDown.hdr.hwndFrom = hwnd;
5842 nmKeyDown.hdr.idFrom = nCtrlId;
5843 nmKeyDown.hdr.code = LVN_KEYDOWN;
5844 nmKeyDown.wVKey = nVirtualKey;
5845 nmKeyDown.flags = 0;
5846 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
5849 nmh.hwndFrom = hwnd;
5850 nmh.idFrom = nCtrlId;
5852 switch (nVirtualKey)
5855 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
5857 /* send NM_RETURN notification */
5858 nmh.code = NM_RETURN;
5859 ListView_Notify(hwndParent, nCtrlId, &nmh);
5861 /* send LVN_ITEMACTIVATE notification */
5862 nmh.code = LVN_ITEMACTIVATE;
5863 ListView_Notify(hwndParent, nCtrlId, &nmh);
5868 if (GETITEMCOUNT(infoPtr) > 0)
5875 if (GETITEMCOUNT(infoPtr) > 0)
5877 nItem = GETITEMCOUNT(infoPtr) - 1;
5882 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
5886 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
5890 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
5894 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
5906 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
5908 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
5909 if (bRedraw != FALSE)
5911 /* refresh client area */
5912 InvalidateRect(hwnd, NULL, TRUE);
5925 * [I] HWND : window handle
5930 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
5932 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5933 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5936 TRACE("(hwnd=%x)\n", hwnd);
5938 /* send NM_KILLFOCUS notification */
5939 nmh.hwndFrom = hwnd;
5940 nmh.idFrom = nCtrlId;
5941 nmh.code = NM_KILLFOCUS;
5942 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5944 /* set window focus flag */
5945 infoPtr->bFocus = FALSE;
5947 /* NEED drawing optimization ; redraw the selected items */
5948 InvalidateRect(hwnd, NULL, FALSE);
5955 * Processes double click messages (left mouse button).
5958 * [I] HWND : window handle
5959 * [I] WORD : key flag
5960 * [I] WORD : x coordinate
5961 * [I] WORD : y coordinate
5966 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
5969 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5972 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5974 /* send NM_DBLCLK notification */
5975 nmh.hwndFrom = hwnd;
5976 nmh.idFrom = nCtrlId;
5977 nmh.code = NM_DBLCLK;
5978 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5980 /* send LVN_ITEMACTIVATE notification */
5981 nmh.code = LVN_ITEMACTIVATE;
5982 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5989 * Processes mouse down messages (left mouse button).
5992 * [I] HWND : window handle
5993 * [I] WORD : key flag
5994 * [I] WORD : x coordinate
5995 * [I] WORD : y coordinate
6000 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6003 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6004 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6005 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6006 static BOOL bGroupSelect = TRUE;
6011 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6014 /* send NM_RELEASEDCAPTURE notification */
6015 nmh.hwndFrom = hwnd;
6016 nmh.idFrom = nCtrlId;
6017 nmh.code = NM_RELEASEDCAPTURE;
6018 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6020 if (infoPtr->bFocus == FALSE)
6025 /* set left button down flag */
6026 infoPtr->bLButtonDown = TRUE;
6028 ptPosition.x = wPosX;
6029 ptPosition.y = wPosY;
6030 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6031 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6033 if (lStyle & LVS_SINGLESEL)
6035 LISTVIEW_SetSelection(hwnd, nItem);
6039 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6041 if (bGroupSelect != FALSE)
6043 LISTVIEW_AddGroupSelection(hwnd, nItem);
6047 LISTVIEW_AddSelection(hwnd, nItem);
6050 else if (wKey & MK_CONTROL)
6052 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6054 else if (wKey & MK_SHIFT)
6056 LISTVIEW_SetGroupSelection(hwnd, nItem);
6060 LISTVIEW_SetSelection(hwnd, nItem);
6066 /* remove all selections */
6067 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6070 InvalidateRect(hwnd, NULL, TRUE);
6077 * Processes mouse up messages (left mouse button).
6080 * [I] HWND : window handle
6081 * [I] WORD : key flag
6082 * [I] WORD : x coordinate
6083 * [I] WORD : y coordinate
6088 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6091 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6093 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6095 if (infoPtr->bLButtonDown != FALSE)
6097 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6100 /* send NM_CLICK notification */
6101 nmh.hwndFrom = hwnd;
6102 nmh.idFrom = nCtrlId;
6103 nmh.code = NM_CLICK;
6104 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6106 /* set left button flag */
6107 infoPtr->bLButtonDown = FALSE;
6115 * Creates the listview control (called before WM_CREATE).
6118 * [I] HWND : window handle
6119 * [I] WPARAM : unhandled
6120 * [I] LPARAM : widow creation info
6125 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6127 LISTVIEW_INFO *infoPtr;
6129 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6131 /* allocate memory for info structure */
6132 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6133 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6134 if (infoPtr == NULL)
6136 ERR("could not allocate info memory!\n");
6140 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6142 ERR("pointer assignment error!\n");
6146 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6151 * Destroys the listview control (called after WM_DESTROY).
6154 * [I] HWND : window handle
6159 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6161 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6163 TRACE("(hwnd=%x)\n", hwnd);
6165 /* delete all items */
6166 LISTVIEW_DeleteAllItems(hwnd);
6168 /* destroy data structure */
6169 DPA_Destroy(infoPtr->hdpaItems);
6172 infoPtr->hFont = (HFONT)0;
6173 if (infoPtr->hDefaultFont)
6175 DeleteObject(infoPtr->hDefaultFont);
6178 /* free listview info pointer*/
6179 COMCTL32_Free(infoPtr);
6186 * Handles notifications from children.
6189 * [I] HWND : window handle
6190 * [I] INT : control identifier
6191 * [I] LPNMHDR : notification information
6196 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6198 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6200 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6202 /* handle notification from header control */
6203 if (lpnmh->code == HDN_ENDTRACKA)
6205 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6206 InvalidateRect(hwnd, NULL, TRUE);
6208 if(lpnmh->code == HDN_ITEMCLICKA)
6210 /* Handle sorting by Header Column */
6212 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6213 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6215 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6216 nmlv.hdr.hwndFrom = hwnd;
6217 nmlv.hdr.idFrom = lCtrlId;
6218 nmlv.hdr.code = LVN_COLUMNCLICK;
6220 nmlv.iSubItem = pnmHeader->iItem;
6222 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6223 InvalidateRect(hwnd, NULL, TRUE);
6234 * Determines the type of structure to use.
6237 * [I] HWND : window handle of the sender
6238 * [I] HWND : listview window handle
6239 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6244 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6246 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6248 if (nCommand == NF_REQUERY)
6250 /* determine the type of structure to use */
6251 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6252 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6253 if (infoPtr->notifyFormat == NFR_UNICODE)
6255 FIXME("NO support for unicode structures");
6264 * Paints/Repaints the listview control.
6267 * [I] HWND : window handle
6268 * [I] HDC : device context handle
6273 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6277 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6281 hdc = BeginPaint(hwnd, &ps);
6282 LISTVIEW_Refresh(hwnd, hdc);
6283 EndPaint(hwnd, &ps);
6287 LISTVIEW_Refresh(hwnd, hdc);
6295 * Processes double click messages (right mouse button).
6298 * [I] HWND : window handle
6299 * [I] WORD : key flag
6300 * [I] WORD : x coordinate
6301 * [I] WORD : y coordinate
6306 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6309 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6312 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6314 /* send NM_RELEASEDCAPTURE notification */
6315 nmh.hwndFrom = hwnd;
6316 nmh.idFrom = nCtrlId;
6317 nmh.code = NM_RELEASEDCAPTURE;
6318 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6320 /* send NM_RDBLCLK notification */
6321 nmh.code = NM_RDBLCLK;
6322 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6329 * Processes mouse down messages (right mouse button).
6332 * [I] HWND : window handle
6333 * [I] WORD : key flag
6334 * [I] WORD : x coordinate
6335 * [I] WORD : y coordinate
6340 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6343 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6344 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6349 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6351 /* send NM_RELEASEDCAPTURE notification */
6352 nmh.hwndFrom = hwnd;
6353 nmh.idFrom = nCtrlId;
6354 nmh.code = NM_RELEASEDCAPTURE;
6355 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6357 /* make sure the listview control window has the focus */
6358 if (infoPtr->bFocus == FALSE)
6363 /* set right button down flag */
6364 infoPtr->bRButtonDown = TRUE;
6366 /* determine the index of the selected item */
6367 ptPosition.x = wPosX;
6368 ptPosition.y = wPosY;
6369 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6370 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6372 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6374 LISTVIEW_SetSelection(hwnd, nItem);
6379 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6387 * Processes mouse up messages (right mouse button).
6390 * [I] HWND : window handle
6391 * [I] WORD : key flag
6392 * [I] WORD : x coordinate
6393 * [I] WORD : y coordinate
6398 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6401 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6402 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6405 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6407 if (infoPtr->bRButtonDown != FALSE)
6409 /* send NM_RClICK notification */
6410 ZeroMemory(&nmh, sizeof(NMHDR));
6411 nmh.hwndFrom = hwnd;
6412 nmh.idFrom = nCtrlId;
6413 nmh.code = NM_RCLICK;
6414 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6416 /* set button flag */
6417 infoPtr->bRButtonDown = FALSE;
6428 * [I] HWND : window handle
6429 * [I] HWND : window handle of previously focused window
6434 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6436 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6437 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6440 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
6442 /* send NM_SETFOCUS notification */
6443 nmh.hwndFrom = hwnd;
6444 nmh.idFrom = nCtrlId;
6445 nmh.code = NM_SETFOCUS;
6446 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6448 /* set window focus flag */
6449 infoPtr->bFocus = TRUE;
6451 InvalidateRect(hwnd, NULL, TRUE);
6462 * [I] HWND : window handle
6463 * [I] HFONT : font handle
6464 * [I] WORD : redraw flag
6469 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6471 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6472 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6474 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6478 infoPtr->hFont = infoPtr->hDefaultFont;
6482 infoPtr->hFont = hFont;
6485 if (uView == LVS_REPORT)
6487 /* set header font */
6488 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6489 MAKELPARAM(fRedraw, 0));
6492 /* invalidate listview control client area */
6493 InvalidateRect(hwnd, NULL, TRUE);
6495 if (fRedraw != FALSE)
6505 * Resizes the listview control. This function processes WM_SIZE
6506 * messages. At this time, the width and height are not used.
6509 * [I] HWND : window handle
6510 * [I] WORD : new width
6511 * [I] WORD : new height
6516 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6518 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6519 UINT uView = lStyle & LVS_TYPEMASK;
6521 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
6523 LISTVIEW_UpdateSize(hwnd);
6525 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6527 if (lStyle & LVS_ALIGNLEFT)
6529 LISTVIEW_AlignLeft(hwnd);
6533 LISTVIEW_AlignTop(hwnd);
6537 LISTVIEW_UpdateScroll(hwnd);
6539 /* invalidate client area + erase background */
6540 InvalidateRect(hwnd, NULL, TRUE);
6547 * Sets the size information.
6550 * [I] HWND : window handle
6555 static VOID LISTVIEW_UpdateSize(HWND hwnd)
6557 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6558 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6559 UINT uView = lStyle & LVS_TYPEMASK;
6562 GetClientRect(hwnd, &rcList);
6563 infoPtr->rcList.left = 0;
6564 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
6565 infoPtr->rcList.top = 0;
6566 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
6568 if (uView == LVS_LIST)
6570 if ((lStyle & WS_HSCROLL) == 0)
6572 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6573 if (infoPtr->rcList.bottom > nHScrollHeight)
6575 infoPtr->rcList.bottom -= nHScrollHeight;
6579 else if (uView == LVS_REPORT)
6586 Header_Layout(infoPtr->hwndHeader, &hl);
6587 if (!(LVS_NOCOLUMNHEADER & lStyle))
6589 infoPtr->rcList.top = max(wp.cy, 0);
6596 * Processes WM_STYLECHANGED messages.
6599 * [I] HWND : window handle
6600 * [I] WPARAM : window style type (normal or extended)
6601 * [I] LPSTYLESTRUCT : window style information
6606 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6609 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6610 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
6611 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
6612 RECT rcList = infoPtr->rcList;
6614 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
6615 hwnd, wStyleType, lpss);
6617 if (wStyleType == GWL_STYLE)
6619 if (uOldView == LVS_REPORT)
6621 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6624 if ((lpss->styleOld & WS_HSCROLL) != 0)
6626 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6629 if ((lpss->styleOld & WS_VSCROLL) != 0)
6631 ShowScrollBar(hwnd, SB_VERT, FALSE);
6634 if (uNewView == LVS_ICON)
6636 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6637 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6638 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6639 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6640 if (lpss->styleNew & LVS_ALIGNLEFT)
6642 LISTVIEW_AlignLeft(hwnd);
6646 LISTVIEW_AlignTop(hwnd);
6649 else if (uNewView == LVS_REPORT)
6656 Header_Layout(infoPtr->hwndHeader, &hl);
6657 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
6659 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
6661 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6663 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6664 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6665 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6666 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6668 else if (uNewView == LVS_LIST)
6670 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6671 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6672 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6673 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6677 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6678 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6679 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6680 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6681 if (lpss->styleNew & LVS_ALIGNLEFT)
6683 LISTVIEW_AlignLeft(hwnd);
6687 LISTVIEW_AlignTop(hwnd);
6691 /* update the size of the client area */
6692 LISTVIEW_UpdateSize(hwnd);
6694 /* add scrollbars if needed */
6695 LISTVIEW_UpdateScroll(hwnd);
6697 /* invalidate client area + erase background */
6698 InvalidateRect(hwnd, NULL, TRUE);
6700 /* print the list of unsupported window styles */
6701 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6709 * Window procedure of the listview control.
6712 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6717 case LVM_APPROXIMATEVIEWRECT:
6718 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6719 LOWORD(lParam), HIWORD(lParam));
6721 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6723 /* case LVM_CREATEDRAGIMAGE: */
6725 case LVM_DELETEALLITEMS:
6726 return LISTVIEW_DeleteAllItems(hwnd);
6728 case LVM_DELETECOLUMN:
6729 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6731 case LVM_DELETEITEM:
6732 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6734 /* case LVM_EDITLABEL: */
6736 case LVM_ENSUREVISIBLE:
6737 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6740 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6742 case LVM_GETBKCOLOR:
6743 return LISTVIEW_GetBkColor(hwnd);
6745 /* case LVM_GETBKIMAGE: */
6747 case LVM_GETCALLBACKMASK:
6748 return LISTVIEW_GetCallbackMask(hwnd);
6750 case LVM_GETCOLUMNA:
6751 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6753 /* case LVM_GETCOLUMNW: */
6755 case LVM_GETCOLUMNORDERARRAY:
6756 FIXME("Unimplemented msg LVM_GETCOLUMNORDERARRAY\n");
6759 case LVM_GETCOLUMNWIDTH:
6760 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
6762 case LVM_GETCOUNTPERPAGE:
6763 return LISTVIEW_GetCountPerPage(hwnd);
6765 /* case LVM_GETEDITCONTROL: */
6767 case LVM_GETEXTENDEDLISTVIEWSTYLE:
6768 return LISTVIEW_GetExtendedListViewStyle(hwnd);
6771 return LISTVIEW_GetHeader(hwnd);
6773 /* case LVM_GETHOTCURSOR: */
6775 case LVM_GETHOTITEM:
6776 return LISTVIEW_GetHotItem(hwnd);
6778 /* case LVM_GETHOVERTIME: */
6780 case LVM_GETIMAGELIST:
6781 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
6783 /* case LVM_GETISEARCHSTRING: */
6786 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
6788 /* case LVM_GETITEMW: */
6790 case LVM_GETITEMCOUNT:
6791 return LISTVIEW_GetItemCount(hwnd);
6793 case LVM_GETITEMPOSITION:
6794 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
6796 case LVM_GETITEMRECT:
6797 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
6799 case LVM_GETITEMSPACING:
6800 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
6802 case LVM_GETITEMSTATE:
6803 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
6805 case LVM_GETITEMTEXTA:
6806 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6809 /* case LVM_GETITEMTEXTW: */
6811 case LVM_GETNEXTITEM:
6812 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
6814 /* case LVM_GETNUMBEROFWORKAREAS: */
6817 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
6819 case LVM_GETSELECTEDCOUNT:
6820 return LISTVIEW_GetSelectedCount(hwnd);
6822 case LVM_GETSELECTIONMARK:
6823 return LISTVIEW_GetSelectionMark(hwnd);
6825 case LVM_GETSTRINGWIDTHA:
6826 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
6828 /* case LVM_GETSTRINGWIDTHW: */
6829 /* case LVM_GETSUBITEMRECT: */
6831 case LVM_GETTEXTBKCOLOR:
6832 return LISTVIEW_GetTextBkColor(hwnd);
6834 case LVM_GETTEXTCOLOR:
6835 return LISTVIEW_GetTextColor(hwnd);
6837 /* case LVM_GETTOOLTIPS: */
6839 case LVM_GETTOPINDEX:
6840 return LISTVIEW_GetTopIndex(hwnd);
6842 /* case LVM_GETUNICODEFORMAT: */
6844 case LVM_GETVIEWRECT:
6845 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
6847 /* case LVM_GETWORKAREAS: */
6850 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
6852 case LVM_INSERTCOLUMNA:
6853 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6855 case LVM_INSERTCOLUMNW:
6856 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
6858 case LVM_INSERTITEMA:
6859 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
6861 case LVM_INSERTITEMW:
6862 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
6864 case LVM_REDRAWITEMS:
6865 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
6867 /* case LVM_SCROLL: */
6868 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
6870 case LVM_SETBKCOLOR:
6871 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
6873 /* case LVM_SETBKIMAGE: */
6875 case LVM_SETCALLBACKMASK:
6876 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
6878 case LVM_SETCOLUMNA:
6879 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6881 case LVM_SETCOLUMNW:
6882 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
6885 case LVM_SETCOLUMNORDERARRAY:
6886 FIXME("Unimplemented msg LVM_SETCOLUMNORDERARRAY\n");
6889 case LVM_SETCOLUMNWIDTH:
6890 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
6892 case LVM_SETEXTENDEDLISTVIEWSTYLE:
6893 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
6895 /* case LVM_SETHOTCURSOR: */
6897 case LVM_SETHOTITEM:
6898 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
6900 /* case LVM_SETHOVERTIME: */
6901 /* case LVM_SETICONSPACING: */
6903 case LVM_SETIMAGELIST:
6904 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
6907 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
6909 /* case LVM_SETITEMW: */
6911 case LVM_SETITEMCOUNT:
6912 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
6914 case LVM_SETITEMPOSITION:
6915 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
6916 (INT)HIWORD(lParam));
6918 /* case LVM_SETITEMPOSITION32: */
6920 case LVM_SETITEMSTATE:
6921 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6923 case LVM_SETITEMTEXTA:
6924 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6926 /* case LVM_SETITEMTEXTW: */
6928 case LVM_SETSELECTIONMARK:
6929 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
6931 case LVM_SETTEXTBKCOLOR:
6932 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
6934 case LVM_SETTEXTCOLOR:
6935 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
6937 /* case LVM_SETTOOLTIPS: */
6938 /* case LVM_SETUNICODEFORMAT: */
6939 /* case LVM_SETWORKAREAS: */
6942 return LISTVIEW_SortItems(hwnd, wParam, lParam);
6944 /* case LVM_SUBITEMHITTEST: */
6947 return LISTVIEW_Update(hwnd, (INT)wParam);
6950 /* case WM_COMMAND: */
6953 return LISTVIEW_Create(hwnd, wParam, lParam);
6956 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
6959 return DLGC_WANTCHARS | DLGC_WANTARROWS;
6962 return LISTVIEW_GetFont(hwnd);
6965 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
6966 (INT)HIWORD(wParam), (HWND)lParam);
6969 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
6972 return LISTVIEW_KillFocus(hwnd);
6974 case WM_LBUTTONDBLCLK:
6975 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6978 case WM_LBUTTONDOWN:
6979 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6982 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6985 /* case WM_MOUSEMOVE: */
6986 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
6989 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
6992 return LISTVIEW_NCDestroy(hwnd);
6995 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
6997 case WM_NOTIFYFORMAT:
6998 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7001 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7003 case WM_RBUTTONDBLCLK:
7004 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7007 case WM_RBUTTONDOWN:
7008 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7012 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7016 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7019 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7021 /* case WM_SETREDRAW: */
7024 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7026 case WM_STYLECHANGED:
7027 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7029 /* case WM_TIMER: */
7032 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7033 (INT)HIWORD(wParam), (HWND)lParam);
7035 /* case WM_WINDOWPOSCHANGED: */
7036 /* case WM_WININICHANGE: */
7039 if (uMsg >= WM_USER)
7041 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7045 /* call default window procedure */
7046 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7054 * Registers the window class.
7062 VOID LISTVIEW_Register(void)
7066 if (!GlobalFindAtomA(WC_LISTVIEWA))
7068 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7069 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7070 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7071 wndClass.cbClsExtra = 0;
7072 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7073 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7074 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7075 wndClass.lpszClassName = WC_LISTVIEWA;
7076 RegisterClassA(&wndClass);
7082 * Unregisters the window class.
7090 VOID LISTVIEW_Unregister(void)
7092 if (GlobalFindAtomA(WC_LISTVIEWA))
7094 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);