4 * Copyright 1998 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
8 * Listview control implementation.
12 * 1. Multiple selections in icon or small icon display modes DO NOT
13 * behave like the Microsoft control.
14 * 2. No horizontal scrolling when header is larger than the client area.
15 * 3. Implement LVM_FINDITEM for key selections.
16 * 4. Drawing optimizations.
19 * LISTVIEW_Notify : most notifications from children (editbox and header)
22 * LISTVIEW_SortItems : empty stub
23 * LISTVIEW_SetItemCount : empty stub
26 * LISTVIEW_SetItem32W : no unicode support
27 * LISTVIEW_InsertItem32W : no unicode support
28 * LISTVIEW_InsertColumn32W : no unicode support
29 * LISTVIEW_GetColumnW : no unicode support
31 * Advanced functionality:
32 * LISTVIEW_GetNumberOfWorkAreas : not implemented
33 * LISTVIEW_GetNextItem : empty stub
34 * LISTVIEW_GetHotCursor : not implemented
35 * LISTVIEW_GetHotItem : not implemented
36 * LISTVIEW_GetHoverTime : not implemented
37 * LISTVIEW_GetISearchString : not implemented
38 * LISTVIEW_GetBkImage : not implemented
39 * LISTVIEW_EditLabel : REPORT (need to implement a timer)
40 * LISTVIEW_GetColumnOrderArray : not implemented
41 * LISTVIEW_Arrange : empty stub
42 * LISTVIEW_FindItem : empty stub
43 * LISTVIEW_ApproximateViewRect : incomplete
44 * LISTVIEW_Scroll : not implemented
45 * LISTVIEW_KeyDown : page up and page down + redo small icon and icon
46 * LISTVIEW_RedrawItems : empty stub
47 * LISTVIEW_Update : not completed
56 DEFAULT_DEBUG_CHANNEL(listview)
62 /* maximum size of a label */
63 #define DISP_TEXT_SIZE 128
65 /* padding for items in list and small icon display modes */
66 #define WIDTH_PADDING 12
68 /* padding for items in list, report and small icon display modes */
69 #define HEIGHT_PADDING 1
71 /* offset of items in report display mode */
72 #define REPORT_MARGINX 2
74 /* padding for icon in large icon display mode */
75 #define ICON_TOP_PADDING 2
76 #define ICON_BOTTOM_PADDING 2
78 /* padding for label in large icon display mode */
79 #define LABEL_VERT_OFFSET 2
81 /* default label width for items in list and small icon display modes */
82 #define DEFAULT_LABEL_WIDTH 40
84 /* default column width for items in list display mode */
85 #define DEFAULT_COLUMN_WIDTH 96
91 /* retrieve the number of items in the listview */
92 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
93 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
94 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
95 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
96 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
99 * forward declarations
102 static VOID LISTVIEW_AlignLeft(HWND);
103 static VOID LISTVIEW_AlignTop(HWND);
104 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
105 static VOID LISTVIEW_AddSelection(HWND, INT);
106 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
107 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
108 static VOID LISTVIEW_GetItemDispInfo(HWND, INT, LISTVIEW_ITEM *lpItem, INT *,
109 UINT *, CHAR **, INT);
110 static INT LISTVIEW_GetItemHeight(HWND, LONG);
111 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
112 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
113 static INT LISTVIEW_GetItemWidth(HWND, LONG);
114 static INT LISTVIEW_GetLabelWidth(HWND, INT);
115 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
116 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
117 static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT, LPARAM,
118 LISTVIEW_SUBITEM *, INT, INT *,
120 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
121 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
122 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
123 static LRESULT LISTVIEW_MouseSelection(HWND, INT, INT);
124 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
125 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
126 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
127 static BOOL LISTVIEW_ScrollView(HWND, INT, INT);
128 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
129 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
130 static VOID LISTVIEW_SetItemFocus(HWND, INT);
131 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
132 static VOID LISTVIEW_SetScroll(HWND, LONG);
133 static VOID LISTVIEW_SetSelection(HWND, INT);
134 static VOID LISTVIEW_SetSize(HWND, LONG, LONG, LONG);
135 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
136 static VOID LISTVIEW_SetViewInfo(HWND, LONG);
137 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
138 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
139 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
143 * Scrolls the content of the listview.
146 * [I] HWND : window handle
147 * [I] INT : number of horizontal scroll positions
148 * (relative to the current scroll postioon)
149 * [I] INT : number of vertical scroll positions
150 * (relative to the current scroll postioon)
156 static BOOL LISTVIEW_ScrollView(HWND hwnd, INT nHScroll, INT nVScroll)
158 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
159 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
160 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
161 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
166 BOOL bResult = FALSE;
168 if (((lStyle & WS_HSCROLL) != 0) && (nHScroll != 0))
170 switch (LVS_TYPEMASK & lStyle)
173 nHScrollInc = nHScroll * infoPtr->nItemWidth;
177 /* TO DO : not implemented at this point. I experiences some
178 problems when performing child window scrolling. */
183 nHScrollInc = nHScroll * max(nListWidth, nListWidth / 10);
187 nHScrollPos = GetScrollPos(hwnd, SB_HORZ) + nHScroll;
190 if (((lStyle & WS_VSCROLL) != 0) & (nVScroll != 0))
192 switch (LVS_TYPEMASK & lStyle)
195 nVScrollInc = nVScroll * infoPtr->nItemHeight;
196 nVScrollPos = GetScrollPos(hwnd, SB_VERT) + nVScroll;
201 nVScrollInc = nVScroll * max(nListHeight, nListHeight / 10);
202 nVScrollPos = GetScrollPos(hwnd, SB_VERT) + nVScroll;
207 /* perform scroll operation & set new scroll position */
208 if ((nHScrollInc != 0) || (nVScrollInc != 0))
211 HDC hdc = GetDC(hwnd);
212 ScrollDC(hdc, -nHScrollInc, -nVScrollInc, &infoPtr->rcList, NULL,
214 InvalidateRect(hwnd, &rc, TRUE);
215 SetScrollPos(hwnd, SB_HORZ, nHScrollPos, TRUE);
216 SetScrollPos(hwnd, SB_VERT, nVScrollPos, TRUE);
217 ReleaseDC(hwnd, hdc);
226 * Prints a message for unsupported window styles.
227 * A kind of TODO list for window styles.
230 * [I] LONG : window style
235 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
237 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
239 FIXME( listview, " LVS_EDITLABELS\n");
242 if ((LVS_TYPEMASK & lStyle) == LVS_NOCOLUMNHEADER)
244 FIXME( listview, " LVS_SORTDESCENDING\n");
247 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
249 FIXME( listview, " LVS_NOLABELWRAP\n");
252 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
254 FIXME( listview, " LVS_NOSCROLL\n");
257 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
259 FIXME( listview, " LVS_NOSORTHEADER\n");
262 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
264 FIXME( listview, " LVS_OWNERDRAWFIXED\n");
267 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
269 FIXME( listview, " LVS_SHAREIMAGELISTS\n");
272 if ((LVS_TYPEMASK & lStyle) == LVS_SHOWSELALWAYS)
274 FIXME( listview, " LVS_SHOWSELALWAYS\n");
277 if ((LVS_TYPEMASK & lStyle) == LVS_SINGLESEL)
279 FIXME( listview, " LVS_SINGLESEL\n");
282 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
284 FIXME( listview, " LVS_SORTASCENDING\n");
287 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
289 FIXME( listview, " LVS_SORTDESCENDING\n");
295 * Aligns the items with the top edge of the window.
298 * [I] HWND : window handle
303 static VOID LISTVIEW_AlignTop(HWND hwnd)
305 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
306 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
307 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
312 switch (LVS_TYPEMASK & lStyle)
316 ZeroMemory(&ptItem, sizeof(POINT));
317 ZeroMemory(&rcView, sizeof(RECT));
318 if (nListWidth > infoPtr->nItemWidth)
320 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
322 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
325 ptItem.y += infoPtr->nItemHeight;
328 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
329 ptItem.x += infoPtr->nItemWidth;
330 rcView.right = max(rcView.right, ptItem.x);
335 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
337 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
338 ptItem.x += infoPtr->nItemWidth;
340 rcView.right = ptItem.x;
341 rcView.bottom = infoPtr->nItemHeight;
344 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
345 LISTVIEW_SetViewRect(hwnd, &rcView);
351 * Aligns the items with the left edge of the window.
354 * [I] HWND : window handle
359 static VOID LISTVIEW_AlignLeft(HWND hwnd)
361 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
362 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
363 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
368 switch (LVS_TYPEMASK & lStyle)
372 ZeroMemory(&ptItem, sizeof(POINT));
373 ZeroMemory(&rcView, sizeof(RECT));
374 if (nListHeight > infoPtr->nItemHeight)
376 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
378 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
381 ptItem.x += infoPtr->nItemWidth;
384 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
385 ptItem.y += infoPtr->nItemHeight;
386 rcView.bottom = max(rcView.bottom, ptItem.y);
391 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
393 LISTVIEW_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
394 ptItem.y += infoPtr->nItemHeight;
396 rcView.bottom = ptItem.y;
397 rcView.right = infoPtr->nItemWidth;
400 rcView.right = ptItem.x + infoPtr->nItemWidth;
401 LISTVIEW_SetViewRect(hwnd, &rcView);
408 * Retrieves display information.
411 * [I] HWND : window handle
412 * [I] INT : item index
413 * [I] LISTVIEW_ITEM* : listview control item
414 * [O] INT : image index
415 * [O] UINT : state value
416 * [O] CHAR** : string
417 * [I] INT : size of string
422 static VOID LISTVIEW_GetItemDispInfo(HWND hwnd, INT nItem,
423 LISTVIEW_ITEM *lpItem, INT *pnDispImage,
424 UINT *puState, CHAR **ppszDispText,
427 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
428 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
429 NMLVDISPINFOA dispInfo;
430 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
432 if ((pnDispImage != NULL) && (lpItem->iImage == I_IMAGECALLBACK))
434 dispInfo.item.mask |= LVIF_IMAGE;
437 if ((ppszDispText != NULL) && (lpItem->pszText == LPSTR_TEXTCALLBACKA))
439 ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
440 dispInfo.item.mask |= LVIF_TEXT;
441 dispInfo.item.pszText = *ppszDispText;
442 dispInfo.item.cchTextMax = nDispTextSize;
445 if ((puState != NULL) && (infoPtr->uCallbackMask != 0))
447 dispInfo.item.mask |= LVIF_STATE;
448 dispInfo.item.stateMask = infoPtr->uCallbackMask;
451 if (dispInfo.item.mask != 0)
453 dispInfo.hdr.hwndFrom = hwnd;
454 dispInfo.hdr.idFrom = lCtrlId;
455 dispInfo.hdr.code = LVN_GETDISPINFOA;
456 dispInfo.item.iItem = nItem;
457 dispInfo.item.iSubItem = 0;
458 dispInfo.item.lParam = lpItem->lParam;
459 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
462 if (pnDispImage != NULL)
464 if (dispInfo.item.mask & LVIF_IMAGE)
466 *pnDispImage = dispInfo.item.iImage;
470 *pnDispImage = lpItem->iImage;
474 if (ppszDispText != NULL)
476 if (dispInfo.item.mask & LVIF_TEXT)
478 if (dispInfo.item.mask & LVIF_DI_SETITEM)
480 Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
482 *ppszDispText = dispInfo.item.pszText;
486 *ppszDispText = lpItem->pszText;
492 if (dispInfo.item.mask & LVIF_STATE)
494 *puState = lpItem->state;
495 *puState &= ~dispInfo.item.stateMask;
496 *puState |= (dispInfo.item.state & dispInfo.item.stateMask);
500 *puState = lpItem->state;
507 * Retrieves subitem display information.
510 * [I] HWND : window handle
511 * [I] INT : item index
512 * [I] LONG : LPARAM of item
513 * [I] LISTVIEW_SUBITEM* : listview control subitem
514 * [I] INT : subitem position/order
515 * [O] INT : image index
516 * [O] UINT : state value
517 * [O] CHAR** : display string
518 * [I] INT : size of string
523 static VOID LISTVIEW_GetSubItemDispInfo(HWND hwnd, INT nItem, LPARAM lParam,
524 LISTVIEW_SUBITEM *lpSubItem,
525 INT nSubItemPos, INT *pnDispImage,
526 CHAR **ppszDispText, INT nDispTextSize)
528 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
529 NMLVDISPINFOA dispInfo;
530 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
532 if (lpSubItem == NULL)
534 ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
535 dispInfo.item.mask |= LVIF_TEXT;
536 dispInfo.item.pszText = *ppszDispText;
537 dispInfo.item.cchTextMax = nDispTextSize;
538 dispInfo.hdr.hwndFrom = hwnd;
539 dispInfo.hdr.idFrom = lCtrlId;
540 dispInfo.hdr.code = LVN_GETDISPINFOA;
541 dispInfo.item.iItem = nItem;
542 dispInfo.item.iSubItem = nSubItemPos;
543 dispInfo.item.lParam = lParam;
544 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
545 if (dispInfo.item.mask & LVIF_DI_SETITEM)
547 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
549 *ppszDispText = dispInfo.item.pszText;
553 if ((pnDispImage != NULL) && (lpSubItem->iImage == I_IMAGECALLBACK))
555 dispInfo.item.mask |= LVIF_IMAGE;
558 if ((ppszDispText != NULL) && (lpSubItem->pszText == LPSTR_TEXTCALLBACKA))
560 ZeroMemory(*ppszDispText, sizeof(CHAR)*nDispTextSize);
561 dispInfo.item.mask |= LVIF_TEXT;
562 dispInfo.item.pszText = *ppszDispText;
563 dispInfo.item.cchTextMax = nDispTextSize;
566 if (dispInfo.item.mask != 0)
568 dispInfo.hdr.hwndFrom = hwnd;
569 dispInfo.hdr.idFrom = lCtrlId;
570 dispInfo.hdr.code = LVN_GETDISPINFOA;
571 dispInfo.item.iItem = nItem;
572 dispInfo.item.iSubItem = lpSubItem->iSubItem;
573 dispInfo.item.lParam = lParam;
574 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
577 if (pnDispImage != NULL)
579 if (dispInfo.item.mask & LVIF_IMAGE)
581 *pnDispImage = dispInfo.item.iImage;
585 *pnDispImage = lpSubItem->iImage;
589 if (ppszDispText != NULL)
591 if (dispInfo.item.mask & LVIF_TEXT)
593 if (dispInfo.item.mask & LVIF_DI_SETITEM)
595 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
597 *ppszDispText = dispInfo.item.pszText;
601 *ppszDispText = lpSubItem->pszText;
609 * Calculates the width of an item.
612 * [I] HWND : window handle
613 * [I] LONG : window style
616 * Returns item width.
618 static INT LISTVIEW_GetItemWidth(HWND hwnd, LONG lStyle)
620 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
621 INT nHeaderItemCount;
627 TRACE(listview, "(hwnd=%x,lStyle=%lx)\n", hwnd, lStyle);
629 switch (LVS_TYPEMASK & lStyle)
632 nItemWidth = infoPtr->iconSpacing.cx;
636 /* calculate width of header */
637 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
638 for (i = 0; i < nHeaderItemCount; i++)
640 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
642 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
649 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
651 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
652 nItemWidth = max(nItemWidth, nLabelWidth);
655 /* default label size */
656 if (GETITEMCOUNT(infoPtr) == 0)
658 nItemWidth = DEFAULT_COLUMN_WIDTH;
664 nItemWidth = DEFAULT_LABEL_WIDTH;
669 nItemWidth += WIDTH_PADDING;
671 if (infoPtr->himlSmall != NULL)
673 nItemWidth += infoPtr->iconSize.cx;
676 if (infoPtr->himlState != NULL)
678 nItemWidth += infoPtr->iconSize.cx;
691 * Calculates the height of an item.
694 * [I] HWND : window handle
695 * [I] LONG : window style
698 * Returns item width.
700 static INT LISTVIEW_GetItemHeight(HWND hwnd, LONG lStyle)
702 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
708 switch (LVS_TYPEMASK & lStyle)
711 nItemHeight = infoPtr->iconSpacing.cy;
718 hOldFont = SelectObject(hdc, infoPtr->hFont);
719 GetTextMetricsA(hdc, &tm);
720 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
721 SelectObject(hdc, hOldFont);
722 ReleaseDC(hwnd, hdc);
731 * Sets diplay information (needed for drawing operations).
734 * [I] HWND : window handle
739 static VOID LISTVIEW_SetViewInfo(HWND hwnd, LONG lStyle)
741 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
742 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
743 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
745 switch (LVS_TYPEMASK & lStyle)
748 /* get number of fully visible items per column */
749 infoPtr->nCountPerColumn = max(1, nListHeight / infoPtr->nItemHeight);
753 /* get number of fully visible items per column */
754 infoPtr->nCountPerColumn = max(1, nListHeight / infoPtr->nItemHeight);
756 /* get number of fully visible items per row */
757 infoPtr->nCountPerRow = max(1, nListWidth / infoPtr->nItemWidth);
764 * Adds a block of selections.
767 * [I] HWND : window handle
768 * [I] INT : item index
773 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
775 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
776 INT nFirst = min(infoPtr->nSelectionMark, nItem);
777 INT nLast = max(infoPtr->nSelectionMark, nItem);
781 lvItem.state = LVIS_SELECTED;
782 lvItem.stateMask= LVIS_SELECTED;
784 for (i = nFirst; i <= nLast; i++)
786 ListView_SetItemState(hwnd, i, &lvItem);
789 LISTVIEW_SetItemFocus(hwnd, nItem);
790 infoPtr->nSelectionMark = nItem;
795 * Adds a single selection.
798 * [I] HWND : window handle
799 * [I] INT : item index
804 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
806 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
809 lvItem.state = LVIS_SELECTED;
810 lvItem.stateMask= LVIS_SELECTED;
812 ListView_SetItemState(hwnd, nItem, &lvItem);
814 LISTVIEW_SetItemFocus(hwnd, nItem);
815 infoPtr->nSelectionMark = nItem;
820 * Selects or unselects an item.
823 * [I] HWND : window handle
824 * [I] INT : item index
830 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
832 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
836 lvItem.stateMask= LVIS_SELECTED;
838 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
841 ListView_SetItemState(hwnd, nItem, &lvItem);
846 lvItem.state = LVIS_SELECTED;
847 ListView_SetItemState(hwnd, nItem, &lvItem);
851 LISTVIEW_SetItemFocus(hwnd, nItem);
852 infoPtr->nSelectionMark = nItem;
859 * Sets a single group selection.
862 * [I] HWND : window handle
863 * [I] INT : item index
868 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
870 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
871 INT nFirst = min(infoPtr->nSelectionMark, nItem);
872 INT nLast = max(infoPtr->nSelectionMark, nItem);
878 LISTVIEW_RemoveSelections(hwnd, 0, nFirst - 1);
881 if (nLast < GETITEMCOUNT(infoPtr))
883 LISTVIEW_RemoveSelections(hwnd, nLast + 1, GETITEMCOUNT(infoPtr));
886 lvItem.state = LVIS_SELECTED;
887 lvItem.stateMask = LVIS_SELECTED;
889 for (i = nFirst; i <= nLast; i++)
891 ListView_SetItemState(hwnd, i, &lvItem);
894 LISTVIEW_SetItemFocus(hwnd, nItem);
899 * Manages the item focus.
902 * [I] HWND : window handle
903 * [I] INT : item index
908 static VOID LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
910 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
914 lvItem.stateMask = LVIS_FOCUSED;
915 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
917 lvItem.state = LVIS_FOCUSED;
918 lvItem.stateMask = LVIS_FOCUSED;
919 ListView_SetItemState(hwnd, nItem, &lvItem);
921 infoPtr->nFocusedItem = nItem;
923 /* if multiple selection is allowed */
924 ListView_EnsureVisible(hwnd, nItem, FALSE);
929 * Sets a single selection.
932 * [I] HWND : window handle
933 * [I] INT : item index
938 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
940 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
945 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
948 if (nItem < GETITEMCOUNT(infoPtr))
950 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
954 lvItem.stateMask = LVIS_FOCUSED;
955 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
957 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
958 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
959 ListView_SetItemState(hwnd, nItem, &lvItem);
961 infoPtr->nFocusedItem = nItem;
962 infoPtr->nSelectionMark = nItem;
967 * Set selection(s) with keyboard.
970 * [I] HWND : window handle
971 * [I] INT : item index
976 static VOID LISTVIEW_KeySelection(HWND hwnd, INT nItem)
978 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
979 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
983 LISTVIEW_SetGroupSelection(hwnd, nItem);
987 LISTVIEW_SetItemFocus(hwnd, nItem);
991 LISTVIEW_SetSelection(hwnd, nItem);
993 /* if multiple selection is allowed */
994 ListView_EnsureVisible(hwnd, nItem, FALSE);
1000 * Determines the selected item.
1003 * [I] HWND : window handle
1004 * [I] INT : x ccordinate
1005 * [I] INT : y coordinate
1008 * SUCCESS : item index
1011 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, INT nPosX, INT nPosY)
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 ((rcItem.left <= nPosX) && (nPosX <= rcItem.right) &&
1023 (rcItem.top <= nPosY) && (nPosY <= rcItem.bottom))
1035 * Removes all selection states.
1038 * [I] HWND : window handle
1039 * [I] INT : item index
1045 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1051 lvItem.stateMask = LVIS_SELECTED;
1053 for (i = nFirst; i <= nLast; i++)
1055 ListView_SetItemState(hwnd, i, &lvItem);
1064 * [IO] HDPA : dynamic pointer array handle
1065 * [I] INT : column index (subitem index)
1071 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1073 BOOL bResult = TRUE;
1077 for (i = 0; i < hdpaItems->nItemCount; i++)
1079 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1080 if (hdpaSubItems != NULL)
1082 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1094 * Removes a subitem at a given position.
1097 * [IO] HDPA : dynamic pointer array handle
1098 * [I] INT : subitem index
1104 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1106 LISTVIEW_SUBITEM *lpSubItem;
1109 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1111 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1112 if (lpSubItem != NULL)
1114 if (lpSubItem->iSubItem == nSubItem)
1117 if ((lpSubItem->pszText != NULL) &&
1118 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1120 COMCTL32_Free(lpSubItem->pszText);
1124 COMCTL32_Free(lpSubItem);
1126 /* free dpa memory */
1127 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1132 else if (lpSubItem->iSubItem > nSubItem)
1144 * Compares the item information.
1147 * [I] LISTVIEW_ITEM *: destination item
1148 * [I] LPLVITEM : source item
1151 * SUCCCESS : TRUE (EQUAL)
1152 * FAILURE : FALSE (NOT EQUAL)
1154 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1158 if ((lpItem != NULL) && (lpLVItem != NULL))
1160 if (lpLVItem->mask & LVIF_STATE)
1162 if ((lpItem->state & lpLVItem->stateMask) !=
1163 (lpLVItem->state & lpLVItem->stateMask))
1165 uChanged |= LVIF_STATE;
1169 if (lpLVItem->mask & LVIF_IMAGE)
1171 if (lpItem->iImage != lpLVItem->iImage)
1173 uChanged |= LVIF_IMAGE;
1177 if (lpLVItem->mask & LVIF_PARAM)
1179 if (lpItem->lParam != lpLVItem->lParam)
1181 uChanged |= LVIF_PARAM;
1185 if (lpLVItem->mask & LVIF_INDENT)
1187 if (lpItem->iIndent != lpLVItem->iIndent)
1189 uChanged |= LVIF_INDENT;
1193 if (lpLVItem->mask & LVIF_TEXT)
1195 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1197 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1199 uChanged |= LVIF_TEXT;
1204 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1206 uChanged |= LVIF_TEXT;
1210 if (lpLVItem->pszText)
1212 if (lpItem->pszText)
1214 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1216 uChanged |= LVIF_TEXT;
1221 uChanged |= LVIF_TEXT;
1226 if (lpItem->pszText)
1228 uChanged |= LVIF_TEXT;
1240 * Initializes item attributes.
1243 * [I] HWND : window handle
1244 * [O] LISTVIEW_ITEM *: destination item
1245 * [I] LPLVITEM : source item
1251 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1254 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1255 BOOL bResult = FALSE;
1257 if ((lpItem != NULL) && (lpLVItem != NULL))
1261 if (lpLVItem->mask & LVIF_STATE)
1263 lpItem->state &= ~lpLVItem->stateMask;
1264 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1267 if (lpLVItem->mask & LVIF_IMAGE)
1269 lpItem->iImage = lpLVItem->iImage;
1272 if (lpLVItem->mask & LVIF_PARAM)
1274 lpItem->lParam = lpLVItem->lParam;
1277 if (lpLVItem->mask & LVIF_INDENT)
1279 lpItem->iIndent = lpLVItem->iIndent;
1282 if (lpLVItem->mask & LVIF_TEXT)
1284 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1286 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1291 if ((lpItem->pszText != NULL) &&
1292 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1294 COMCTL32_Free(lpItem->pszText);
1297 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1301 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1303 lpItem->pszText = NULL;
1306 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1316 * Initializes subitem attributes.
1318 * NOTE: the documentation specifies that the operation fails if the user
1319 * tries to set the indent of a subitem.
1322 * [I] HWND : window handle
1323 * [O] LISTVIEW_SUBITEM *: destination subitem
1324 * [I] LPLVITEM : source subitem
1330 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1333 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1334 BOOL bResult = FALSE;
1336 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1338 if (!(lpLVItem->mask & LVIF_INDENT))
1341 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1343 lpSubItem->iSubItem = lpLVItem->iSubItem;
1345 if (lpLVItem->mask & LVIF_IMAGE)
1347 lpSubItem->iImage = lpLVItem->iImage;
1350 if (lpLVItem->mask & LVIF_TEXT)
1352 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1354 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1359 if ((lpSubItem->pszText != NULL) &&
1360 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1362 COMCTL32_Free(lpSubItem->pszText);
1365 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1369 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1371 lpSubItem->pszText = NULL;
1374 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1385 * Adds a subitem at a given position (column index).
1388 * [I] HWND : window handle
1389 * [I] LPLVITEM : new subitem atttributes
1395 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1397 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1398 LISTVIEW_SUBITEM *lpSubItem = NULL;
1399 BOOL bResult = FALSE;
1401 INT nPosition, nItem;
1403 if (lpLVItem != NULL)
1405 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1406 if (hdpaSubItems != NULL)
1408 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1409 if (lpSubItem != NULL)
1411 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1413 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1414 lpSubItem->iSubItem);
1415 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1425 /* cleanup if unsuccessful */
1426 if ((bResult == FALSE) && (lpSubItem != NULL))
1428 COMCTL32_Free(lpSubItem);
1436 * Finds the dpa insert position (array index).
1439 * [I] HWND : window handle
1440 * [I] INT : subitem index
1446 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1448 LISTVIEW_SUBITEM *lpSubItem;
1451 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1453 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1454 if (lpSubItem != NULL)
1456 if (lpSubItem->iSubItem > nSubItem)
1463 return hdpaSubItems->nItemCount;
1468 * Retrieves a listview subitem at a given position (column index).
1471 * [I] HWND : window handle
1472 * [I] INT : subitem index
1478 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1480 LISTVIEW_SUBITEM *lpSubItem;
1483 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1485 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1486 if (lpSubItem != NULL)
1488 if (lpSubItem->iSubItem == nSubItem)
1492 else if (lpSubItem->iSubItem > nSubItem)
1504 * Sets item attributes.
1507 * [I] HWND : window handle
1508 * [I] LPLVITEM : new item atttributes
1514 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1516 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1517 BOOL bResult = FALSE;
1519 LISTVIEW_ITEM *lpItem;
1522 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1524 if (lpLVItem != NULL)
1526 if (lpLVItem->iSubItem == 0)
1528 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1529 if (hdpaSubItems != NULL)
1531 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1534 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1535 nmlv.hdr.hwndFrom = hwnd;
1536 nmlv.hdr.idFrom = lCtrlId;
1537 nmlv.hdr.code = LVN_ITEMCHANGING;
1538 nmlv.lParam = lpItem->lParam;
1539 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1542 if (uChanged & LVIF_STATE)
1544 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1545 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1548 nmlv.uChanged = uChanged;
1549 nmlv.iItem = lpLVItem->iItem;
1550 nmlv.lParam = lpItem->lParam;
1551 /* send LVN_ITEMCHANGING notification */
1552 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1554 /* copy information */
1555 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1557 /* send LVN_ITEMCHANGED notification */
1558 nmlv.hdr.code = LVN_ITEMCHANGED;
1559 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1566 InvalidateRect(hwnd, NULL, FALSE);
1577 * Sets subitem attributes.
1580 * [I] HWND : window handle
1581 * [I] LPLVITEM : new subitem atttributes
1587 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1589 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1590 BOOL bResult = FALSE;
1592 LISTVIEW_SUBITEM *lpSubItem;
1594 if (lpLVItem != NULL)
1596 if (lpLVItem->iSubItem > 0)
1598 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1599 if (hdpaSubItems != NULL)
1601 /* set subitem only if column is present */
1602 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1604 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1605 if (lpSubItem != NULL)
1607 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1611 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1614 InvalidateRect(hwnd, NULL, FALSE);
1625 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1628 * [I] HWND : window handle
1633 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1635 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *) GetWindowLongA(hwnd, 0);
1636 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1639 switch (LVS_TYPEMASK & lStyle)
1642 if (lStyle & WS_HSCROLL)
1644 nItem = GetScrollPos(hwnd, SB_HORZ) * infoPtr->nCountPerColumn;
1649 if (lStyle & WS_VSCROLL)
1651 nItem = GetScrollPos(hwnd, SB_VERT);
1661 * Evaluates if scrollbars are needed & sets the scroll range/position.
1664 * [I] HWND : window handle
1665 * [I] LONG : window style
1670 static VOID LISTVIEW_SetScroll(HWND hwnd, LONG lStyle)
1672 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1673 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
1674 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
1675 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
1676 INT nVScrollWidth = GetSystemMetrics(SM_CXVSCROLL);
1679 INT nHiddenItemCount;
1683 INT nPixPerScrollPos;
1686 TRACE(listview, "(hwnd=%x,lStyle=%lx)\n", hwnd, lStyle);
1688 switch (LVS_TYPEMASK & lStyle)
1691 nCountPerPage = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
1692 if (nCountPerPage < GETITEMCOUNT(infoPtr))
1694 /* display horizontal scrollbar */
1695 if ((lStyle & WS_HSCROLL) == 0)
1697 ShowScrollBar(hwnd, SB_HORZ, TRUE);
1700 /* calculate new scrollbar range */
1701 nHiddenItemCount = GETITEMCOUNT(infoPtr) - nCountPerPage;
1702 if ((nHiddenItemCount % infoPtr->nCountPerColumn) == 0)
1704 nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn;
1708 nMaxRange = nHiddenItemCount / infoPtr->nCountPerColumn + 1;
1711 SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE);
1712 nScrollPos = ListView_GetTopIndex(hwnd) / infoPtr->nCountPerColumn;
1713 SetScrollPos(hwnd, SB_HORZ, nScrollPos, TRUE);
1717 /* hide scrollbar */
1718 if ((lStyle & WS_HSCROLL) != 0)
1720 ShowScrollBar(hwnd, SB_HORZ, FALSE);
1727 * This section was commented out because I experienced some problems
1728 * with the scrolling of the header control. The idea was to add a
1729 * horizontal scrollbar when the width of the client area was smaller
1730 * than the width of the header control.
1733 /* if (infoPtr->nItemWidth > nListWidth) */
1735 /* if ((lStyle & WS_HSCROLL) == 0) */
1737 /* ShowScrollBar(hwnd, SB_HORZ, TRUE); */
1738 /* LISTVIEW_SetSize(hwnd, lStyle, -1, -1); */
1739 /* LISTVIEW_SetViewInfo(hwnd, lStyle); */
1742 /* nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; */
1743 /* nHiddenWidth = infoPtr->nItemWidth - nListWidth; */
1744 /* nPixPerScrollPos = max(1, nListWidth / 10); */
1746 /* if ((nHiddenWidth % nPixPerScrollPos) == 0) */
1748 /* nMaxRange = nHiddenWidth / nPixPerScrollPos; */
1752 /* nMaxRange = nHiddenWidth / nPixPerScrollPos + 1; */
1755 /* SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE); */
1756 /* SetScrollPos(hwnd, SB_HORZ, 0, TRUE); */
1760 /* if ((lStyle & WS_HSCROLL) != 0) */
1762 /* ShowScrollBar(hwnd, SB_HORZ, FASLE); */
1763 /* LISTVIEW_SetSize(hwnd, lStyle, -1, -1); */
1764 /* LISTVIEW_SetViewInfo(hwnd, lStyle); */
1768 if (infoPtr->nCountPerColumn < GETITEMCOUNT(infoPtr))
1770 if ((lStyle & WS_VSCROLL) == 0)
1772 if (nListWidth > nVScrollWidth)
1774 ShowScrollBar(hwnd, SB_VERT, TRUE);
1775 nListWidth -= nVScrollWidth;
1779 /* vertical range & position */
1780 nMaxRange = GETITEMCOUNT(infoPtr) - infoPtr->nCountPerColumn;
1781 SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE);
1782 SetScrollPos(hwnd, SB_VERT, ListView_GetTopIndex(hwnd), TRUE);
1786 if ((lStyle & WS_VSCROLL) != 0)
1788 ShowScrollBar(hwnd, SB_VERT, FALSE);
1789 nListWidth += nVScrollWidth;
1796 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
1798 if (rcView.right - rcView.left > nListWidth)
1800 if ((lStyle & WS_HSCROLL) == 0)
1802 if (nListHeight > nHScrollHeight)
1804 ShowScrollBar(hwnd, SB_HORZ, TRUE);
1805 nListHeight -= nHScrollHeight;
1809 /* calculate size of hidden items */
1810 nHiddenWidth = rcView.right - rcView.left - nListWidth;
1811 nPixPerScrollPos = max(1, nListWidth / 10);
1813 /* vertical range & position */
1814 if ((nHiddenWidth % nPixPerScrollPos) == 0)
1816 nMaxRange = nHiddenWidth / nPixPerScrollPos;
1820 nMaxRange = nHiddenWidth / nPixPerScrollPos + 1;
1823 /* set range and position */
1824 SetScrollRange(hwnd, SB_HORZ, 0, nMaxRange, FALSE);
1825 SetScrollPos(hwnd, SB_HORZ, 0, TRUE);
1829 if ((lStyle & WS_HSCROLL) != 0)
1831 ShowScrollBar(hwnd, SB_HORZ, FALSE);
1832 nListHeight += nHScrollHeight;
1836 if (rcView.bottom - rcView.top > nListHeight)
1838 if ((lStyle & WS_VSCROLL) == 0)
1840 if (nListWidth > nVScrollWidth)
1842 ShowScrollBar(hwnd, SB_VERT, TRUE);
1843 nListWidth -= nVScrollWidth;
1847 /* calculate size of hidden items */
1848 nHiddenHeight = rcView.bottom - rcView.top - nListHeight;
1849 nPixPerScrollPos = max(1, nListHeight / 10);
1851 /* set vertical range & position */
1852 if ((nHiddenHeight % nPixPerScrollPos) == 0)
1854 nMaxRange = nHiddenHeight / nPixPerScrollPos;
1858 nMaxRange = nHiddenHeight / nPixPerScrollPos + 1;
1861 /* set range and position */
1862 SetScrollRange(hwnd, SB_VERT, 0, nMaxRange, FALSE);
1863 SetScrollPos(hwnd, SB_VERT, 0, TRUE);
1867 if ((lStyle & WS_VSCROLL) != 0)
1869 ShowScrollBar(hwnd, SB_VERT, FALSE);
1870 nListWidth += nVScrollWidth;
1883 * [I] HWND : window handle
1884 * [I] HDC : device context handle
1885 * [I] INT : item index
1886 * [I] LPARAM : item lparam
1887 * [I] LISTVIEW_SUBITEM * : item
1888 * [I] INT : column index (header index)
1889 * [I] RECT * : clipping rectangle
1894 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, LPARAM lParam,
1895 LISTVIEW_SUBITEM *lpSubItem, INT nColumn,
1898 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1899 CHAR szDispText[DISP_TEXT_SIZE];
1900 LPSTR pszDispText = NULL;
1902 /* set item colors */
1903 SetBkColor(hdc, infoPtr->clrTextBk);
1904 SetTextColor(hdc, infoPtr->clrText);
1906 pszDispText = szDispText;
1907 LISTVIEW_GetSubItemDispInfo(hwnd, nItem, lParam, lpSubItem, nColumn, NULL,
1908 &pszDispText, DISP_TEXT_SIZE);
1910 /* draw text : using arbitrary offset of 10 pixels */
1912 ExtTextOutA(hdc, lprc->left, lprc->top, ETO_OPAQUE|ETO_CLIPPED,
1913 lprc, pszDispText, lstrlenA(pszDispText), NULL);
1921 * [I] HWND : window handle
1922 * [I] HDC : device context handle
1923 * [I] LISTVIEW_ITEM * : item
1924 * [I] INT : item index
1925 * [I] RECT * : clipping rectangle
1930 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem,
1933 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1934 CHAR szDispText[DISP_TEXT_SIZE];
1935 LPSTR pszDispText = NULL;
1941 TRACE(listview, "(hwnd=%x,hdc=%x,lpItem=%p,nItem=%d,rc.left=%d,rctop=%d,rc.right=%d,rc.bottom=%d)\n", hwnd, hdc, lpItem, nItem, rc.left, rc.top, rc.right, rc.bottom);
1943 pszDispText = szDispText;
1944 LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, &nImage, &uState, &pszDispText,
1947 if (uState & LVIS_SELECTED)
1951 /* set item colors */
1952 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1953 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1955 /* set raster mode */
1956 SetROP2(hdc, R2_XORPEN);
1962 /* set item colors */
1963 SetBkColor(hdc, infoPtr->clrTextBk);
1964 SetTextColor(hdc, infoPtr->clrText);
1966 /* set raster mode */
1967 SetROP2(hdc, R2_COPYPEN);
1971 if (infoPtr->himlState != NULL)
1973 /* right shift 12 bits to obtain index in image list */
1974 if (bSelected != FALSE)
1976 ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, rc.left,
1977 rc.top, ILD_SELECTED);
1981 ImageList_Draw(infoPtr->himlState, uState >> 12, hdc, rc.left,
1982 rc.top, ILD_NORMAL);
1985 rc.left += infoPtr->iconSize.cx;
1989 if (infoPtr->himlSmall != NULL)
1991 if (bSelected != FALSE)
1993 ImageList_Draw(infoPtr->himlSmall, nImage, hdc, rc.left,
1994 rc.top, ILD_SELECTED);
1998 ImageList_Draw(infoPtr->himlSmall, nImage, hdc, rc.left,
1999 rc.top, ILD_NORMAL);
2002 rc.left += infoPtr->iconSize.cx;
2005 nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
2006 if (rc.left + nLabelWidth < rc.right)
2008 rc.right = rc.left + nLabelWidth;
2012 ExtTextOutA(hdc, rc.left, rc.top, ETO_OPAQUE|ETO_CLIPPED,
2013 &rc, pszDispText, lstrlenA(pszDispText), NULL);
2015 if (lpItem->state & LVIS_FOCUSED)
2017 Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
2023 * Draws an item when in large icon display mode.
2026 * [I] HWND : window handle
2027 * [I] HDC : device context handle
2028 * [I] LISTVIEW_ITEM * : item
2029 * [I] INT : item index
2030 * [I] RECT * : clipping rectangle
2035 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, LISTVIEW_ITEM *lpItem,
2038 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2039 CHAR szDispText[DISP_TEXT_SIZE];
2040 LPSTR pszDispText = NULL;
2048 TRACE(listview, "(hwnd=%x,hdc=%x,lpItem=%p,nItem=%d,rc.left=%d,rctop=%d,rc.right=%d,rc.bottom=%d)\n", hwnd, hdc, lpItem, nItem, rc.left, rc.top, rc.right, rc.bottom);
2050 pszDispText = szDispText;
2051 LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, &nImage, &uState, &pszDispText,
2053 if (uState & LVIS_SELECTED)
2057 /* set item colors */
2058 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2059 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2061 /* set raster mode */
2062 SetROP2(hdc, R2_XORPEN);
2068 /* set item colors */
2069 SetBkColor(hdc, infoPtr->clrTextBk);
2070 SetTextColor(hdc, infoPtr->clrText);
2072 /* set raster mode */
2073 SetROP2(hdc, R2_COPYPEN);
2076 if (infoPtr->himlNormal != NULL)
2078 rc.top += ICON_TOP_PADDING;
2079 nDrawPosX = rc.left + (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
2080 if (bSelected != FALSE)
2082 ImageList_Draw(infoPtr->himlNormal, nImage, hdc, nDrawPosX, rc.top,
2087 ImageList_Draw(infoPtr->himlNormal, nImage, hdc, nDrawPosX, rc.top,
2092 rc.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2093 nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
2094 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
2097 rc.left += nDrawPosX / 2;
2098 rc.right = rc.left + nLabelWidth;
2103 rc.right = rc.left + infoPtr->iconSpacing.cx - 1;
2107 GetTextMetricsA(hdc, &tm);
2108 rc.bottom = rc.top + tm.tmHeight + HEIGHT_PADDING;
2109 ExtTextOutA(hdc, rc.left, rc.top, ETO_OPAQUE|ETO_CLIPPED,
2110 &rc, pszDispText, lstrlenA(pszDispText), NULL);
2112 if (lpItem->state & LVIS_FOCUSED)
2114 Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
2120 * Draws listview items when in report display mode.
2123 * [I] HWND : window handle
2124 * [I] HDC : device context handle
2129 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2131 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2132 INT nDrawPosY = infoPtr->rcList.top;
2133 LISTVIEW_ITEM *lpItem;
2134 LISTVIEW_SUBITEM *lpSubItem = NULL;
2135 BOOL bNeedSubItem = TRUE;
2143 nItem = ListView_GetTopIndex(hwnd);
2144 nLast = nItem + infoPtr->nCountPerColumn;
2145 while (nItem <= nLast)
2147 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
2148 if (hdpaSubItems != NULL)
2150 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2153 /* the width of the header items will determine the size of the
2155 Header_GetItemRect(infoPtr->hwndHeader, 0, &rcItem);
2156 rcItem.left += REPORT_MARGINX;
2157 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2158 rcItem.top = nDrawPosY;
2159 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2160 LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, rcItem);
2163 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2164 for (k = 1, j = 1; j < nColumnCount; j++)
2166 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2167 rcItem.left += REPORT_MARGINX;
2168 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2169 rcItem.top = nDrawPosY;
2170 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2172 if (k < hdpaSubItems->nItemCount)
2174 if (bNeedSubItem != FALSE)
2176 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, k);
2180 if (lpSubItem != NULL)
2182 if (lpSubItem->iSubItem == j)
2184 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, lpSubItem,
2186 bNeedSubItem = TRUE;
2190 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
2192 bNeedSubItem = FALSE;
2197 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
2199 bNeedSubItem = TRUE;
2204 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, lpItem->lParam, NULL, j,
2210 nDrawPosY += infoPtr->nItemHeight;
2217 * Draws listview items when in list display mode.
2220 * [I] HWND : window handle
2221 * [I] HDC : device context handle
2226 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2228 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2229 LISTVIEW_ITEM *lpItem;
2234 INT nItem = ListView_GetTopIndex(hwnd);
2236 if (infoPtr->rcList.right > 0)
2238 /* get number of display columns */
2239 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2241 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2245 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2248 for (i = 0; i < nColumnCount; i++)
2251 while ((nItem < GETITEMCOUNT(infoPtr)) &&
2252 (j<infoPtr->nCountPerColumn))
2254 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
2255 if (hdpaSubItems != NULL)
2257 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2260 rc.top = j * infoPtr->nItemHeight;
2261 rc.left = i * infoPtr->nItemWidth;
2262 rc.bottom = rc.top + infoPtr->nItemHeight;
2263 rc.right = rc.left + infoPtr->nItemWidth;
2264 LISTVIEW_DrawItem(hwnd, hdc, lpItem, nItem, rc);
2277 * Draws listview items when in icon or small icon display mode.
2280 * [I] HWND : window handle
2281 * [I] HDC : device context handle
2286 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2288 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2289 LISTVIEW_ITEM *lpItem;
2296 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2298 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2300 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2301 ptPosition.x += ptOrigin.x;
2302 ptPosition.y += ptOrigin.y;
2304 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2306 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2308 if (ptPosition.y < infoPtr->rcList.bottom)
2310 if (ptPosition.x < infoPtr->rcList.right)
2312 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2313 if (hdpaSubItems != NULL)
2315 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2318 rc.top = ptPosition.y;
2319 rc.left = ptPosition.x;
2320 rc.bottom = rc.top + infoPtr->nItemHeight;
2321 rc.right = rc.left + infoPtr->nItemWidth;
2322 if (bSmall == FALSE)
2324 LISTVIEW_DrawLargeItem(hwnd, hdc, lpItem, i, rc);
2328 LISTVIEW_DrawItem(hwnd, hdc, lpItem, i, rc);
2341 * Draws listview items.
2344 * [I] HWND : window handle
2345 * [I] HDC : device context handle
2350 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2352 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2353 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2358 hOldFont = SelectObject(hdc, infoPtr->hFont);
2360 /* select the doted pen (for drawing the focus box) */
2361 hPen = CreatePen(PS_DOT, 1, 0);
2362 hOldPen = SelectObject(hdc, hPen);
2364 /* select transparent brush (for drawing the focus box) */
2365 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2367 switch (LVS_TYPEMASK & lStyle)
2370 LISTVIEW_RefreshList(hwnd, hdc);
2373 LISTVIEW_RefreshReport(hwnd, hdc);
2376 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2379 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2382 /* unselect objects */
2383 SelectObject(hdc, hOldFont);
2384 SelectObject(hdc, hOldPen);
2393 * Calculates the approximate width and height of a given number of items.
2396 * [I] HWND : window handle
2397 * [I] INT : number of items
2402 * Returns a DWORD. The width in the low word and the height in high word.
2404 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2405 WORD wWidth, WORD wHeight)
2407 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2408 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2409 INT nItemCountPerColumn = 1;
2410 INT nColumnCount = 0;
2411 DWORD dwViewRect = 0;
2413 if (nItemCount == -1)
2414 nItemCount = GETITEMCOUNT(infoPtr);
2416 if (lStyle & LVS_LIST)
2418 if (wHeight == 0xFFFF)
2420 /* use current height */
2421 wHeight = infoPtr->rcList.bottom;
2424 if (wHeight < infoPtr->nItemHeight)
2426 wHeight = infoPtr->nItemHeight;
2431 if (infoPtr->nItemHeight > 0)
2433 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2434 if (nItemCountPerColumn == 0)
2435 nItemCountPerColumn = 1;
2437 if (nItemCount % nItemCountPerColumn != 0)
2438 nColumnCount = nItemCount / nItemCountPerColumn;
2440 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2444 /* Microsoft padding magic */
2445 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2446 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2448 dwViewRect = MAKELONG(wWidth, wHeight);
2450 else if (lStyle & LVS_REPORT)
2454 else if (lStyle & LVS_SMALLICON)
2458 else if (lStyle & LVS_ICON)
2468 * Arranges listview items in icon display mode.
2471 * [I] HWND : window handle
2472 * [I] INT : alignment code
2478 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2480 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2481 BOOL bResult = FALSE;
2483 if (((LVS_TYPEMASK & lStyle) == LVS_ICON) ||
2484 ((LVS_TYPEMASK & lStyle) == LVS_SMALLICON))
2497 case LVA_SNAPTOGRID:
2506 /* << LISTVIEW_CreateDragImage >> */
2510 * Removes all listview items and subitems.
2513 * [I] HWND : window handle
2519 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2521 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2522 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2523 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2524 LISTVIEW_ITEM *lpItem;
2525 LISTVIEW_SUBITEM *lpSubItem;
2528 BOOL bResult = FALSE;
2533 TRACE(listview, "(hwnd=%x,)\n", hwnd);
2535 if (GETITEMCOUNT(infoPtr) > 0)
2537 /* initialize memory */
2538 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2540 /* send LVN_DELETEALLITEMS notification */
2541 nmlv.hdr.hwndFrom = hwnd;
2542 nmlv.hdr.idFrom = lCtrlId;
2543 nmlv.hdr.code = LVN_DELETEALLITEMS;
2546 /* verify if subsequent LVN_DELETEITEM notifications should be
2548 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2550 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2552 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2553 if (hdpaSubItems != NULL)
2555 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2557 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2558 if (lpSubItem != NULL)
2560 /* free subitem string */
2561 if ((lpSubItem->pszText != NULL) &&
2562 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2564 COMCTL32_Free(lpSubItem->pszText);
2568 COMCTL32_Free(lpSubItem);
2572 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2575 if (bSuppress == FALSE)
2577 /* send LVN_DELETEITEM notification */
2578 nmlv.hdr.code = LVN_DELETEITEM;
2580 nmlv.lParam = lpItem->lParam;
2581 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2584 /* free item string */
2585 if ((lpItem->pszText != NULL) &&
2586 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2588 COMCTL32_Free(lpItem->pszText);
2592 COMCTL32_Free(lpItem);
2595 DPA_Destroy(hdpaSubItems);
2599 /* reinitialize listview memory */
2600 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2602 /* align items (set position of each item) */
2603 switch (lStyle & LVS_TYPEMASK)
2607 if (lStyle & LVS_ALIGNLEFT)
2609 LISTVIEW_AlignLeft(hwnd);
2613 LISTVIEW_AlignTop(hwnd);
2618 LISTVIEW_SetScroll(hwnd, lStyle);
2620 /* invalidate client area (optimization needed) */
2621 InvalidateRect(hwnd, NULL, TRUE);
2629 * Removes a column from the listview control.
2632 * [I] HWND : window handle
2633 * [I] INT : column index
2639 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2641 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2642 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2643 BOOL bResult = FALSE;
2645 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2647 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2649 /* reset scroll parameters */
2650 if ((lStyle & LVS_TYPEMASK) == LVS_REPORT)
2652 LISTVIEW_SetViewInfo(hwnd, lStyle);
2653 LISTVIEW_SetScroll(hwnd, lStyle);
2656 /* refresh client area */
2657 InvalidateRect(hwnd, NULL, FALSE);
2665 * Removes an item from the listview control.
2668 * [I] HWND : window handle
2669 * [I] INT : item index
2675 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2677 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2678 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2679 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2681 BOOL bResult = FALSE;
2683 LISTVIEW_ITEM *lpItem;
2684 LISTVIEW_SUBITEM *lpSubItem;
2687 TRACE(listview, "(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2689 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2691 /* initialize memory */
2692 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2694 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2695 if (hdpaSubItems != NULL)
2697 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2699 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2700 if (lpSubItem != NULL)
2702 /* free item string */
2703 if ((lpSubItem->pszText != NULL) &&
2704 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2706 COMCTL32_Free(lpSubItem->pszText);
2710 COMCTL32_Free(lpSubItem);
2714 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2717 /* send LVN_DELETEITEM notification */
2718 nmlv.hdr.hwndFrom = hwnd;
2719 nmlv.hdr.idFrom = lCtrlId;
2720 nmlv.hdr.code = LVN_DELETEITEM;
2722 nmlv.lParam = lpItem->lParam;
2723 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2726 /* free item string */
2727 if ((lpItem->pszText != NULL) &&
2728 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2730 COMCTL32_Free(lpItem->pszText);
2734 COMCTL32_Free(lpItem);
2737 bResult = DPA_Destroy(hdpaSubItems);
2740 /* align items (set position of each item) */
2741 switch(lStyle & LVS_TYPEMASK)
2745 if (lStyle & LVS_ALIGNLEFT)
2747 LISTVIEW_AlignLeft(hwnd);
2751 LISTVIEW_AlignTop(hwnd);
2756 LISTVIEW_SetScroll(hwnd, lStyle);
2758 /* refresh client area */
2759 InvalidateRect(hwnd, NULL, TRUE);
2765 /* LISTVIEW_EditLabel */
2769 * Ensures the specified item is visible, scrolling into view if necessary.
2772 * [I] HWND : window handle
2773 * [I] INT : item index
2774 * [I] BOOL : partially or entirely visible
2780 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2782 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2783 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2784 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2785 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2786 INT nHScrollPos = 0;
2787 INT nVScrollPos = 0;
2788 INT nScrollPosHeight = 0;
2789 INT nScrollPosWidth = 0;
2791 BOOL bResult = FALSE;
2793 /* ALWAYS bPartial == FALSE, FOR NOW! */
2795 rcItem.left = LVIR_BOUNDS;
2796 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2798 if (rcItem.left < infoPtr->rcList.left)
2801 switch (LVS_TYPEMASK & lStyle)
2804 rcItem.left += infoPtr->rcList.left;
2805 nScrollPosWidth = infoPtr->nItemWidth;
2810 nScrollPosWidth = max(1, nListWidth / 10);
2811 rcItem.left += infoPtr->rcList.left;
2815 if (rcItem.left % nScrollPosWidth == 0)
2817 nHScrollPos = rcItem.left / nScrollPosWidth;
2821 nHScrollPos = rcItem.left / nScrollPosWidth - 1;
2824 else if (rcItem.right > infoPtr->rcList.right)
2827 switch (LVS_TYPEMASK & lStyle)
2830 rcItem.right -= infoPtr->rcList.right;
2831 nScrollPosWidth = infoPtr->nItemWidth;
2836 nScrollPosWidth = max(1, nListWidth / 10);
2837 rcItem.right -= infoPtr->rcList.right;
2841 if (rcItem.right % nScrollPosWidth == 0)
2843 nHScrollPos = rcItem.right / nScrollPosWidth;
2847 nHScrollPos = rcItem.right / nScrollPosWidth + 1;
2851 if (rcItem.top < infoPtr->rcList.top)
2854 switch (LVS_TYPEMASK & lStyle)
2857 rcItem.top -= infoPtr->rcList.top;
2858 nScrollPosHeight = infoPtr->nItemHeight;
2863 nScrollPosHeight = max(1, nListHeight / 10);
2864 rcItem.top += infoPtr->rcList.top;
2868 if (rcItem.top % nScrollPosHeight == 0)
2870 nVScrollPos = rcItem.top / nScrollPosHeight;
2874 nVScrollPos = rcItem.top / nScrollPosHeight - 1;
2877 else if (rcItem.bottom > infoPtr->rcList.bottom)
2879 switch (LVS_TYPEMASK & lStyle)
2882 rcItem.bottom -= infoPtr->rcList.bottom;
2883 nScrollPosHeight = infoPtr->nItemHeight;
2888 nScrollPosHeight = max(1, nListHeight / 10);
2889 rcItem.bottom -= infoPtr->rcList.bottom;
2893 if (rcItem.bottom % nScrollPosHeight == 0)
2895 nVScrollPos = rcItem.bottom / nScrollPosHeight;
2899 nVScrollPos = rcItem.bottom / nScrollPosHeight + 1;
2903 bResult = LISTVIEW_ScrollView(hwnd, nHScrollPos, nVScrollPos);
2911 * Searches for an item with specific characteristics.
2914 * [I] HWND : window handle
2915 * [I] INT : base item index
2916 * [I] LPLVFINDINFO : item information to look for
2919 * SUCCESS : index of item
2922 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
2923 LPLVFINDINFO lpFindInfo)
2925 FIXME (listview, "empty stub!\n");
2932 * Retrieves the background color of the listview control.
2935 * [I] HWND : window handle
2938 * COLORREF associated with the background.
2940 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
2942 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2944 return infoPtr->clrBk;
2949 * Retrieves the background image of the listview control.
2952 * [I] HWND : window handle
2953 * [O] LPLVMKBIMAGE : background image attributes
2959 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
2961 /* FIXME (listview, "empty stub!\n"); */
2967 * Retrieves the callback mask.
2970 * [I] HWND : window handle
2975 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
2977 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2979 return infoPtr->uCallbackMask;
2984 * Retrieves column attributes.
2987 * [I] HWND : window handle
2988 * [I] INT : column index
2989 * [IO] LPLVCOLUMNA : column information
2995 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem,
2996 LPLVCOLUMNA lpColumn)
2998 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3000 BOOL bResult = FALSE;
3002 if (lpColumn != NULL)
3004 /* initialize memory */
3005 ZeroMemory(&hdi, sizeof(HDITEMA));
3007 if (lpColumn->mask & LVCF_FMT)
3009 hdi.mask |= HDI_FORMAT;
3012 if (lpColumn->mask & LVCF_WIDTH)
3014 hdi.mask |= HDI_WIDTH;
3017 if (lpColumn->mask & LVCF_TEXT)
3019 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3022 if (lpColumn->mask & LVCF_IMAGE)
3024 hdi.mask |= HDI_IMAGE;
3027 if (lpColumn->mask & LVCF_ORDER)
3029 hdi.mask |= HDI_ORDER;
3032 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3033 if (bResult != FALSE)
3035 if (lpColumn->mask & LVCF_FMT)
3039 if (hdi.fmt & HDF_LEFT)
3041 lpColumn->fmt |= LVCFMT_LEFT;
3043 else if (hdi.fmt & HDF_RIGHT)
3045 lpColumn->fmt |= LVCFMT_RIGHT;
3047 else if (hdi.fmt & HDF_CENTER)
3049 lpColumn->fmt |= LVCFMT_CENTER;
3052 if (hdi.fmt & HDF_IMAGE)
3054 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3058 if (lpColumn->mask & LVCF_WIDTH)
3060 lpColumn->cx = hdi.cxy;
3063 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3065 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3068 if (lpColumn->mask & LVCF_IMAGE)
3070 lpColumn->iImage = hdi.iImage;
3073 if (lpColumn->mask & LVCF_ORDER)
3075 lpColumn->iOrder = hdi.iOrder;
3083 /* LISTVIEW_GetColumnW */
3084 /* LISTVIEW_GetColumnOrderArray */
3088 * Retrieves the column width.
3091 * [I] HWND : window handle
3092 * [I] int : column index
3095 * SUCCESS : column width
3098 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3100 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3101 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3103 INT nColumnWidth = 0;
3105 switch (LVS_TYPEMASK & lStyle)
3108 nColumnWidth = infoPtr->nItemWidth;
3112 /* get column width from header */
3113 ZeroMemory(&hdi, sizeof(HDITEMA));
3114 hdi.mask = HDI_WIDTH;
3115 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3117 nColumnWidth = hdi.cxy;
3122 return nColumnWidth;
3127 * In list or report display mode, retrieves the number of items that can fit
3128 * vertically in the visible area. In icon or small icon display mode,
3129 * retrieves the total number of visible items.
3132 * [I] HWND : window handle
3135 * Number of fully visible items.
3137 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3139 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3140 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3143 switch (LVS_TYPEMASK & lStyle)
3146 if (infoPtr->rcList.right / infoPtr->nItemWidth)
3148 nItemCount = infoPtr->nCountPerRow * infoPtr->nCountPerColumn;
3153 nItemCount = infoPtr->nCountPerColumn;
3158 nItemCount = GETITEMCOUNT(infoPtr);
3165 /* LISTVIEW_GetEditControl */
3166 /* LISTVIEW_GetExtendedListViewStyle */
3170 * Retrieves the handle to the header control.
3173 * [I] HWND : window handle
3178 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3180 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3182 return infoPtr->hwndHeader;
3185 /* LISTVIEW_GetHotCursor */
3186 /* LISTVIEW_GetHotItem */
3187 /* LISTVIEW_GetHoverTime */
3191 * Retrieves an image list handle.
3194 * [I] HWND : window handle
3195 * [I] INT : image list identifier
3198 * SUCCESS : image list handle
3201 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3203 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3204 HIMAGELIST himl = NULL;
3209 himl = infoPtr->himlNormal;
3212 himl = infoPtr->himlSmall;
3215 himl = infoPtr->himlState;
3219 return (LRESULT)himl;
3222 /* LISTVIEW_GetISearchString */
3226 * Retrieves item attributes.
3229 * [I] HWND : window handle
3230 * [IO] LPLVITEMA : item info
3236 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
3238 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3239 LISTVIEW_ITEM *lpItem;
3240 LISTVIEW_SUBITEM *lpSubItem;
3242 BOOL bResult = FALSE;
3244 TRACE(listview, "(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
3246 if (lpLVItem != NULL)
3248 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
3250 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3251 if (hdpaSubItems != NULL)
3253 if (lpLVItem->iSubItem == 0)
3255 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3260 /* retrieve valid data */
3261 if (lpLVItem->mask & LVIF_STATE)
3263 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3266 if (lpLVItem->mask & LVIF_TEXT)
3268 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
3270 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3274 bResult = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText,
3275 lpLVItem->cchTextMax);
3279 if (lpLVItem->mask & LVIF_IMAGE)
3281 lpLVItem->iImage = lpItem->iImage;
3284 if (lpLVItem->mask & LVIF_PARAM)
3286 lpLVItem->lParam = lpItem->lParam;
3289 if (lpLVItem->mask & LVIF_INDENT)
3291 lpLVItem->iIndent = lpItem->iIndent;
3297 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems,
3298 lpLVItem->iSubItem);
3299 if (lpSubItem != NULL)
3303 if (lpLVItem->mask & LVIF_TEXT)
3305 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
3307 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3311 bResult = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText,
3312 lpLVItem->cchTextMax);
3316 if (lpLVItem->mask & LVIF_IMAGE)
3318 lpLVItem->iImage = lpSubItem->iImage;
3329 /* LISTVIEW_GetItemW */
3330 /* LISTVIEW_GetHotCursor */
3331 /* LISTVIEW_GetHotItem */
3332 /* LISTVIEW_GetHoverTime> */
3336 * Retrieves the number of items in the listview control.
3339 * [I] HWND : window handle
3344 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3346 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3348 return GETITEMCOUNT(infoPtr);
3353 * Retrieves the position (upper-left) of the listview control item.
3356 * [I] HWND : window handle
3357 * [I] INT : item index
3358 * [O] LPPOINT : coordinate information
3364 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3365 LPPOINT lpptPosition)
3367 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3368 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3369 BOOL bResult = FALSE;
3371 LISTVIEW_ITEM *lpItem;
3374 TRACE(listview, "(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3377 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3378 (lpptPosition != NULL))
3380 switch (LVS_TYPEMASK & lStyle)
3384 nItem = nItem - ListView_GetTopIndex(hwnd);
3387 nRow = nItem % infoPtr->nCountPerColumn;
3390 lpptPosition->x = (nItem / infoPtr->nCountPerColumn *
3391 infoPtr->nItemWidth);
3392 lpptPosition->y = 0;
3396 lpptPosition->x = ((nItem / infoPtr->nCountPerColumn - 1) *
3397 infoPtr->nItemWidth);
3398 lpptPosition->y = ((nRow + infoPtr->nCountPerColumn) *
3399 infoPtr->nItemHeight);
3404 lpptPosition->x = (nItem / infoPtr->nCountPerColumn *
3405 infoPtr->nItemWidth);
3406 lpptPosition->y = (nItem % infoPtr->nCountPerColumn *
3407 infoPtr->nItemHeight);
3413 lpptPosition->x = REPORT_MARGINX;
3414 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3415 infoPtr->nItemHeight) + infoPtr->rcList.top;
3420 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3421 if (hdpaSubItems != NULL)
3423 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3427 lpptPosition->x = lpItem->ptPosition.x;
3428 lpptPosition->y = lpItem->ptPosition.y;
3440 * Retrieves the bounding rectangle for a listview control item.
3443 * [I] HWND : window handle
3444 * [I] INT : item index
3445 * [IO] LPRECT : bounding rectangle coordinates
3451 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3453 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3454 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3455 BOOL bResult = FALSE;
3464 TRACE(listview, "(hwnd=%x,nItem=%d,lprc=%p)\n", hwnd, nItem, lprc);
3466 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3468 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3473 switch (LVS_TYPEMASK & lStyle)
3476 if (infoPtr->himlNormal != NULL)
3478 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3481 lprc->left = ptItem.x + ptOrigin.x;
3482 lprc->top = ptItem.y + ptOrigin.y;
3483 lprc->right = lprc->left + infoPtr->iconSize.cx;
3484 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3485 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3491 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3494 lprc->left = ptItem.x + ptOrigin.x;
3495 lprc->top = ptItem.y + ptOrigin.y;
3496 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3498 if (infoPtr->himlState != NULL)
3500 lprc->left += infoPtr->iconSize.cx;
3503 if (infoPtr->himlSmall != NULL)
3505 lprc->right = lprc->left + infoPtr->iconSize.cx;
3509 lprc->right = lprc->left;
3517 lprc->left = ptItem.x;
3518 lprc->top = ptItem.y;
3519 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3521 if (infoPtr->himlState != NULL)
3523 lprc->left += infoPtr->iconSize.cx;
3526 if (infoPtr->himlSmall != NULL)
3528 lprc->right = lprc->left + infoPtr->iconSize.cx;
3532 lprc->right = lprc->left;
3539 switch (LVS_TYPEMASK & lStyle)
3542 if (infoPtr->himlNormal != NULL)
3544 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3547 lprc->left = ptItem.x + ptOrigin.x;
3548 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3549 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3550 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3551 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3553 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3554 lprc->right = lprc->left + nLabelWidth;
3559 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3563 hOldFont = SelectObject(hdc, infoPtr->hFont);
3564 GetTextMetricsA(hdc, &tm);
3565 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3566 SelectObject(hdc, hOldFont);
3567 ReleaseDC(hwnd, hdc);
3573 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3576 nMaxWidth = lprc->left = ptItem.x + ptOrigin.x;
3577 lprc->top = ptItem.y + ptOrigin.y;
3578 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3580 if (infoPtr->himlState != NULL)
3582 lprc->left += infoPtr->iconSize.cx;
3585 if (infoPtr->himlSmall != NULL)
3587 lprc->left += infoPtr->iconSize.cx;
3590 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3591 if (lprc->left + nLabelWidth < nMaxWidth + infoPtr->nItemWidth)
3593 lprc->right = lprc->left + nLabelWidth;
3597 lprc->right = nMaxWidth + infoPtr->nItemWidth;
3605 lprc->left = ptItem.x;
3606 lprc->top = ptItem.y;
3607 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3609 if (infoPtr->himlState != NULL)
3611 lprc->left += infoPtr->iconSize.cx;
3614 if (infoPtr->himlSmall != NULL)
3616 lprc->left += infoPtr->iconSize.cx;
3619 lprc->right = lprc->left + LISTVIEW_GetLabelWidth(hwnd, nItem);
3625 switch (LVS_TYPEMASK & lStyle)
3628 if (infoPtr->himlNormal != NULL)
3630 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3633 lprc->left = ptItem.x + ptOrigin.x;
3634 lprc->top = ptItem.y + ptOrigin.y;
3635 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3636 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3642 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3645 lprc->left = ptItem.x +ptOrigin.x;
3646 lprc->right = lprc->left;
3647 lprc->top = ptItem.y + ptOrigin.y;
3648 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3650 if (infoPtr->himlState != NULL)
3652 lprc->right += infoPtr->iconSize.cx;
3655 if (infoPtr->himlSmall != NULL)
3657 lprc->right += infoPtr->iconSize.cx;
3660 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3667 lprc->left = ptItem.x;
3668 lprc->right = lprc->left;
3669 lprc->top = ptItem.y;
3670 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3672 if (infoPtr->himlState != NULL)
3674 lprc->right += infoPtr->iconSize.cx;
3677 if (infoPtr->himlSmall != NULL)
3679 lprc->right += infoPtr->iconSize.cx;
3682 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3687 case LVIR_SELECTBOUNDS:
3688 switch (LVS_TYPEMASK & lStyle)
3691 if (infoPtr->himlNormal != NULL)
3693 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3696 lprc->left = ptItem.x + ptOrigin.x;
3697 lprc->top = ptItem.y + ptOrigin.y;
3698 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3699 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3705 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3708 lprc->left = ptItem.x + ptOrigin.x;
3709 lprc->top = ptItem.y + ptOrigin.y;
3710 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3712 if (infoPtr->himlState != NULL)
3714 lprc->left += infoPtr->iconSize.cx;
3717 lprc->right = lprc->left;
3719 if (infoPtr->himlSmall != NULL)
3721 lprc->right += infoPtr->iconSize.cx;
3724 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3731 lprc->left = ptItem.x;
3732 lprc->top = ptItem.y;
3733 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3735 if (infoPtr->himlState != NULL)
3737 lprc->left += infoPtr->iconSize.cx;
3740 lprc->right = lprc->left;
3742 if (infoPtr->himlSmall != NULL)
3744 lprc->right += infoPtr->iconSize.cx;
3747 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3760 * Retrieves the width of a label.
3763 * [I] HWND : window handle
3766 * SUCCESS : string width (in pixels)
3770 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
3772 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3773 LISTVIEW_ITEM *lpItem;
3775 INT nLabelWidth = 0;
3777 TRACE(listview, "(hwnd=%x,nItem=%d)\n", hwnd, nItem);
3779 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3780 if (hdpaSubItems != NULL)
3782 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3785 CHAR szDispText[DISP_TEXT_SIZE];
3786 LPSTR pszDispText = NULL;
3787 pszDispText = szDispText;
3788 LISTVIEW_GetItemDispInfo(hwnd, nItem, lpItem, NULL, NULL, &pszDispText,
3790 nLabelWidth = ListView_GetStringWidthA(hwnd, pszDispText);
3799 * Retrieves the spacing between listview control items.
3802 * [I] HWND : window handle
3803 * [I] BOOL : flag for small or large icon
3806 * Horizontal + vertical spacing
3808 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
3810 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3813 if (bSmall == FALSE)
3815 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
3819 /* TODO: need to store width of smallicon item */
3820 lResult = MAKELONG(0, infoPtr->nItemHeight);
3828 * Retrieves the state of a listview control item.
3831 * [I] HWND : window handle
3832 * [I] INT : item index
3833 * [I] UINT : state mask
3836 * State specified by the mask.
3838 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
3840 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3844 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3846 ZeroMemory(&lvItem, sizeof(LVITEMA));
3847 lvItem.iItem = nItem;
3848 lvItem.stateMask = uMask;
3849 lvItem.mask = LVIF_STATE;
3850 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3852 uState = lvItem.state;
3861 * Retrieves the text of a listview control item or subitem.
3864 * [I] HWND : window handle
3865 * [I] INT : item index
3866 * [IO] LPLVITEMA : item information
3871 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
3873 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3874 LISTVIEW_ITEM *lpItem;
3875 LISTVIEW_SUBITEM *lpSubItem;
3879 if (lpLVItem != NULL)
3881 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3883 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3884 if (hdpaSubItems != NULL)
3886 if (lpLVItem->iSubItem == 0)
3888 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3891 if (lpLVItem->mask & LVIF_TEXT)
3893 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
3895 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3899 nLength = Str_GetPtrA(lpItem->pszText, lpLVItem->pszText,
3900 lpLVItem->cchTextMax);
3907 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems,
3908 lpLVItem->iSubItem);
3909 if (lpSubItem != NULL)
3911 if (lpLVItem->mask & LVIF_TEXT)
3913 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
3915 lpLVItem->pszText = LPSTR_TEXTCALLBACKA;
3919 nLength = Str_GetPtrA(lpSubItem->pszText, lpLVItem->pszText,
3920 lpLVItem->cchTextMax);
3934 * Searches for an item based on properties + relationships.
3937 * [I] HWND : window handle
3938 * [I] INT : item index
3939 * [I] UINT : relationship flag
3942 * SUCCESS : item index
3945 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
3947 FIXME (listview, "empty stub!\n");
3952 /* LISTVIEW_GetNumberOfWorkAreas */
3956 * Retrieves the origin coordinates when in icon or small icon display mode.
3959 * [I] HWND : window handle
3960 * [O] LPPOINT : coordinate information
3966 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
3968 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3969 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
3970 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
3971 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
3972 BOOL bResult = FALSE;
3974 TRACE(listview, "(hwnd=%x,lpptOrigin=%p)\n", hwnd, lpptOrigin);
3976 switch (LVS_TYPEMASK & lStyle)
3980 if ((lStyle & WS_HSCROLL) != 0)
3982 lpptOrigin->x = -GetScrollPos(hwnd, SB_HORZ) * nListWidth / 10;
3989 if ((lStyle & WS_VSCROLL) != 0)
3991 lpptOrigin->y = -GetScrollPos(hwnd, SB_VERT) * nListHeight / 10;
4007 * Retrieves the number of items that are marked as selected.
4010 * [I] HWND : window handle
4013 * Number of items selected.
4015 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4017 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4018 INT nSelectedCount = 0;
4021 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4023 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4029 return nSelectedCount;
4034 * Retrieves item index that marks the start of a multiple selection.
4037 * [I] HWND : window handle
4040 * Index number or -1 if there is no selection mark.
4042 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4044 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4046 return infoPtr->nSelectionMark;
4051 * Retrieves the width of a string.
4054 * [I] HWND : window handle
4057 * SUCCESS : string width (in pixels)
4060 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4062 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4063 HFONT hFont, hOldFont;
4067 ZeroMemory(&stringSize, sizeof(SIZE));
4068 if (lpszText != NULL)
4070 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4072 hOldFont = SelectObject(hdc, hFont);
4073 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4074 SelectObject(hdc, hOldFont);
4075 ReleaseDC(hwnd, hdc);
4078 return stringSize.cx;
4083 * Retrieves the text backgound color.
4086 * [I] HWND : window handle
4089 * COLORREF associated with the the background.
4091 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4093 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4095 return infoPtr->clrTextBk;
4100 * Retrieves the text color.
4103 * [I] HWND : window handle
4106 * COLORREF associated with the text.
4108 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4110 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4112 return infoPtr->clrText;
4117 * Set the bounding rectangle of all the items.
4120 * [I] HWND : window handle
4121 * [I] LPRECT : bounding rectangle
4127 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
4129 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4130 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4131 BOOL bResult = FALSE;
4133 TRACE(listview, "(hwnd=%x,lprcView->left=%d,lprcView->top=%d,lprcView->right=%d,lprcView->bottom=%d)\n", hwnd, lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
4135 if (lprcView != NULL)
4137 switch (lStyle & LVS_TYPEMASK)
4142 infoPtr->rcView.left = lprcView->left;
4143 infoPtr->rcView.top = lprcView->top;
4144 infoPtr->rcView.right = lprcView->right;
4145 infoPtr->rcView.bottom = lprcView->bottom;
4155 * Retrieves the bounding rectangle of all the items.
4158 * [I] HWND : window handle
4159 * [O] LPRECT : bounding rectangle
4165 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
4167 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4168 BOOL bResult = FALSE;
4171 TRACE(listview, "(hwnd=%x,lprcView=%p)\n", hwnd, lprcView);
4173 if (lprcView != NULL)
4175 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
4176 if (bResult != FALSE)
4178 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
4179 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
4180 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
4181 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
4184 TRACE(listview, "(lprcView->left=%d,lprcView->top=%d,lprcView->right=%d,lprcView->bottom=%d)\n", lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
4193 * Determines which section of the item was selected (if any).
4196 * [I] HWND : window handle
4197 * [IO] LPLVHITTESTINFO : hit test information
4200 * SUCCESS : item index
4203 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4205 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4209 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4211 rcItem.left = LVIR_BOUNDS;
4212 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4214 rcItem.left = LVIR_ICON;
4215 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4217 if ((lpHitTestInfo->pt.x >= rcItem.left) &&
4218 (lpHitTestInfo->pt.x <= rcItem.right) &&
4219 (lpHitTestInfo->pt.y >= rcItem.top) &&
4220 (lpHitTestInfo->pt.y <= rcItem.bottom))
4222 lpHitTestInfo->flags = LVHT_ONITEMICON | LVHT_ONITEM;
4223 lpHitTestInfo->iItem = i;
4224 lpHitTestInfo->iSubItem = 0;
4229 rcItem.left = LVIR_LABEL;
4230 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4232 if ((lpHitTestInfo->pt.x >= rcItem.left) &&
4233 (lpHitTestInfo->pt.x <= rcItem.right) &&
4234 (lpHitTestInfo->pt.y >= rcItem.top) &&
4235 (lpHitTestInfo->pt.y <= rcItem.bottom))
4237 lpHitTestInfo->flags = LVHT_ONITEMLABEL | LVHT_ONITEM;
4238 lpHitTestInfo->iItem = i;
4239 lpHitTestInfo->iSubItem = 0;
4244 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON | LVHT_ONITEM;
4245 lpHitTestInfo->iItem = i;
4246 lpHitTestInfo->iSubItem = 0;
4251 lpHitTestInfo->flags = LVHT_NOWHERE;
4258 * Determines wich listview item is located at the specified position.
4261 * [I] HWND : window handle
4262 * [IO} LPLVHITTESTINFO : hit test information
4265 * SUCCESS : item index
4268 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4270 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4273 lpHitTestInfo->flags = 0;
4274 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4276 lpHitTestInfo->flags = LVHT_TOLEFT;
4278 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4280 lpHitTestInfo->flags = LVHT_TORIGHT;
4283 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4285 lpHitTestInfo->flags |= LVHT_ABOVE;
4287 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4289 lpHitTestInfo->flags |= LVHT_BELOW;
4292 if (lpHitTestInfo->flags == 0)
4294 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4302 * Inserts a new column.
4305 * [I] HWND : window handle
4306 * [I] INT : column index
4307 * [I] LPLVCOLUMNA : column information
4310 * SUCCESS : new column index
4313 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4314 LPLVCOLUMNA lpColumn)
4316 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4317 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4319 INT nNewColumn = -1;
4321 TRACE(listview,"(hwnd=%x,nColumn=%d,lpColumn=%p)\n",hwnd, nColumn, lpColumn);
4323 if (lpColumn != NULL)
4325 /* initialize memory */
4326 ZeroMemory(&hdi, sizeof(HDITEMA));
4328 if (lpColumn->mask & LVCF_FMT)
4330 /* format member is valid */
4331 hdi.mask |= HDI_FORMAT;
4333 /* set text alignment (leftmost column must be left-aligned) */
4336 hdi.fmt |= HDF_LEFT;
4340 if (lpColumn->fmt & LVCFMT_LEFT)
4342 hdi.fmt |= HDF_LEFT;
4344 else if (lpColumn->fmt & LVCFMT_RIGHT)
4346 hdi.fmt |= HDF_RIGHT;
4348 else if (lpColumn->fmt & LVCFMT_CENTER)
4350 hdi.fmt |= HDF_CENTER;
4354 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4356 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4360 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4365 if (lpColumn->fmt & LVCFMT_IMAGE)
4367 hdi.fmt |= HDF_IMAGE;
4368 hdi.iImage = I_IMAGECALLBACK;
4372 if (lpColumn->mask & LVCF_WIDTH)
4374 hdi.mask |= HDI_WIDTH;
4375 hdi.cxy = lpColumn->cx;
4378 if (lpColumn->mask & LVCF_TEXT)
4380 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4381 hdi.pszText = lpColumn->pszText;
4382 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4383 hdi.fmt |= HDF_STRING;
4386 if (lpColumn->mask & LVCF_IMAGE)
4388 hdi.mask |= HDI_IMAGE;
4389 hdi.iImage = lpColumn->iImage;
4392 if (lpColumn->mask & LVCF_ORDER)
4394 hdi.mask |= HDI_ORDER;
4395 hdi.iOrder = lpColumn->iOrder;
4398 /* insert item in header control */
4399 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4400 (WPARAM)nColumn, (LPARAM)&hdi);
4402 LISTVIEW_SetScroll(hwnd, lStyle);
4403 InvalidateRect(hwnd, NULL, FALSE);
4409 /* LISTVIEW_InsertColumnW */
4413 * Inserts a new item in the listview control.
4416 * [I] HWND : window handle
4417 * [I] LPLVITEMA : item information
4420 * SUCCESS : new item index
4423 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4425 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4426 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4427 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4431 LISTVIEW_ITEM *lpItem = NULL;
4433 TRACE(listview, "(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4435 if (lpLVItem != NULL)
4437 /* make sure it's not a subitem; cannot insert a subitem */
4438 if (lpLVItem->iSubItem == 0)
4440 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4443 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4444 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4446 /* insert item in listview control data structure */
4447 hdpaSubItems = DPA_Create(8);
4448 if (hdpaSubItems != NULL)
4450 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4453 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4457 /* manage item focus */
4458 if (lpLVItem->mask & LVIF_STATE)
4460 if (lpLVItem->stateMask & LVIS_FOCUSED)
4462 LISTVIEW_SetItemFocus(hwnd, nItem);
4466 /* send LVN_INSERTITEM notification */
4467 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4468 nmlv.hdr.hwndFrom = hwnd;
4469 nmlv.hdr.idFrom = lCtrlId;
4470 nmlv.hdr.code = LVN_INSERTITEM;
4472 nmlv.lParam = lpItem->lParam;;
4473 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4475 /* align items (set position of each item) */
4476 switch (lStyle & LVS_TYPEMASK)
4480 if (lStyle & LVS_ALIGNLEFT)
4482 LISTVIEW_AlignLeft(hwnd);
4486 LISTVIEW_AlignTop(hwnd);
4491 LISTVIEW_SetScroll(hwnd, lStyle);
4492 /* refresh client area */
4493 InvalidateRect(hwnd, NULL, FALSE);
4502 /* free memory if unsuccessful */
4503 if ((nItem == -1) && (lpItem != NULL))
4505 COMCTL32_Free(lpItem);
4511 /* LISTVIEW_InsertItemW */
4515 * Redraws a range of items.
4518 * [I] HWND : window handle
4519 * [I] INT : first item
4520 * [I] INT : last item
4526 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4528 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4529 BOOL bResult = FALSE;
4532 if (nFirst <= nLast)
4534 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4536 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4539 InvalidateRect(hwnd, &rc, FALSE);
4547 /* LISTVIEW_Scroll */
4551 * Sets the background color.
4554 * [I] HWND : window handle
4555 * [I] COLORREF : background color
4561 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
4563 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4565 infoPtr->clrBk = clrBk;
4566 InvalidateRect(hwnd, NULL, TRUE);
4573 * Sets the callback mask. This mask will be used when the parent
4574 * window stores state information (some or all).
4577 * [I] HWND : window handle
4578 * [I] UINT : state mask
4584 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
4586 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4588 infoPtr->uCallbackMask = uMask;
4595 * Sets the attributes of a header item.
4598 * [I] HWND : window handle
4599 * [I] INT : column index
4600 * [I] LPLVCOLUMNA : column attributes
4606 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
4607 LPLVCOLUMNA lpColumn)
4609 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4610 BOOL bResult = FALSE;
4613 if ((lpColumn != NULL) && (nColumn >= 0) &&
4614 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
4616 /* initialize memory */
4617 ZeroMemory(&hdi, sizeof(HDITEMA));
4619 if (lpColumn->mask & LVCF_FMT)
4621 /* format member is valid */
4622 hdi.mask |= HDI_FORMAT;
4624 /* set text alignment (leftmost column must be left-aligned) */
4627 hdi.fmt |= HDF_LEFT;
4631 if (lpColumn->fmt & LVCFMT_LEFT)
4633 hdi.fmt |= HDF_LEFT;
4635 else if (lpColumn->fmt & LVCFMT_RIGHT)
4637 hdi.fmt |= HDF_RIGHT;
4639 else if (lpColumn->fmt & LVCFMT_CENTER)
4641 hdi.fmt |= HDF_CENTER;
4645 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4647 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4650 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4652 hdi.fmt |= HDF_IMAGE;
4655 if (lpColumn->fmt & LVCFMT_IMAGE)
4657 hdi.fmt |= HDF_IMAGE;
4658 hdi.iImage = I_IMAGECALLBACK;
4662 if (lpColumn->mask & LVCF_WIDTH)
4664 hdi.mask |= HDI_WIDTH;
4665 hdi.cxy = lpColumn->cx;
4668 if (lpColumn->mask & LVCF_TEXT)
4670 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4671 hdi.pszText = lpColumn->pszText;
4672 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4673 hdi.fmt |= HDF_STRING;
4676 if (lpColumn->mask & LVCF_IMAGE)
4678 hdi.mask |= HDI_IMAGE;
4679 hdi.iImage = lpColumn->iImage;
4682 if (lpColumn->mask & LVCF_ORDER)
4684 hdi.mask |= HDI_ORDER;
4685 hdi.iOrder = lpColumn->iOrder;
4688 /* set header item attributes */
4689 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
4697 * Sets the width of a column
4700 * [I] HWND : window handle
4701 * [I] INT : column index
4702 * [I] INT : column width
4708 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
4710 LISTVIEW_INFO *infoPtr;
4715 // set column width only if in report mode
4716 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4717 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
4720 // make sure we can get the listview info
4721 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4723 if (!infoPtr->hwndHeader) // make sure we have a header
4726 // FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
4727 // LVSCV_AUTOSIZE_USEHEADER (-2)
4731 hdi.mask = HDI_WIDTH;
4734 // call header to update the column change
4735 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
4737 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, LVS_REPORT);
4739 InvalidateRect(hwnd, NULL, TRUE); // force redraw of the listview
4749 * [I] HWND : window handle
4750 * [I] INT : image list type
4751 * [I] HIMAGELIST : image list handle
4754 * SUCCESS : old image list
4757 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
4759 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4760 HIMAGELIST himlTemp = 0;
4765 himlTemp = infoPtr->himlNormal;
4766 infoPtr->himlNormal = himl;
4767 return (LRESULT)himlTemp;
4770 himlTemp = infoPtr->himlSmall;
4771 infoPtr->himlSmall = himl;
4772 return (LRESULT)himlTemp;
4775 himlTemp = infoPtr->himlState;
4776 infoPtr->himlState = himl;
4777 return (LRESULT)himlTemp;
4780 return (LRESULT)NULL;
4786 * Sets the attributes of an item.
4789 * [I] HWND : window handle
4790 * [I] LPLVITEM : item information
4796 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
4798 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4799 BOOL bResult = FALSE;
4801 if (lpLVItem != NULL)
4803 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
4805 if (lpLVItem->iSubItem == 0)
4807 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
4811 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
4820 /* LISTVIEW_SetItemW */
4824 * Preallocates memory.
4827 * [I] HWND : window handle
4828 * [I] INT : item count (prjected number of items)
4833 static VOID LISTVIEW_SetItemCount(HWND hwnd, INT nItemCount)
4835 FIXME (listview, "empty stub!\n");
4840 * Sets the position of an item.
4843 * [I] HWND : window handle
4844 * [I] INT : item index
4845 * [I] INT : x coordinate
4846 * [I] INT : y coordinate
4852 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
4853 INT nPosX, INT nPosY)
4855 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4856 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4857 LISTVIEW_ITEM *lpItem;
4859 BOOL bResult = FALSE;
4861 TRACE(listview, "(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
4863 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
4865 switch (lStyle & LVS_TYPEMASK)
4869 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
4870 if (hdpaSubItems != NULL)
4872 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4876 lpItem->ptPosition.x = nPosX;
4877 lpItem->ptPosition.y = nPosY;
4889 * Sets the state of one or many items.
4892 * [I] HWND : window handle
4893 * [I]INT : item index
4894 * [I] LPLVITEM : item or subitem info
4900 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4902 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4903 BOOL bResult = FALSE;
4910 ZeroMemory(&lvItem, sizeof(LVITEMA));
4911 lvItem.mask = LVIF_STATE;
4912 lvItem.state = lpLVItem->state;
4913 lvItem.stateMask = lpLVItem->stateMask;
4915 /* apply to all items */
4916 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
4919 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
4927 ZeroMemory(&lvItem, sizeof(LVITEMA));
4928 lvItem.mask = LVIF_STATE;
4929 lvItem.state = lpLVItem->state;
4930 lvItem.stateMask = lpLVItem->stateMask;
4931 lvItem.iItem = nItem;
4932 bResult = ListView_SetItemA(hwnd, &lvItem);
4940 * Sets the text of an item or subitem.
4943 * [I] HWND : window handle
4944 * [I] INT : item index
4945 * [I] LPLVITEMA : item or subitem info
4951 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4953 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4954 BOOL bResult = FALSE;
4957 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4959 ZeroMemory(&lvItem, sizeof(LVITEMA));
4960 lvItem.mask = LVIF_TEXT;
4961 lvItem.pszText = lpLVItem->pszText;
4962 lvItem.iItem = nItem;
4963 lvItem.iSubItem = lpLVItem->iSubItem;
4964 bResult = ListView_SetItemA(hwnd, &lvItem);
4972 * Sets the text background color.
4975 * [I] HWND : window handle
4976 * [I] COLORREF : text background color
4982 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
4984 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4986 infoPtr->clrTextBk = clrTextBk;
4987 InvalidateRect(hwnd, NULL, TRUE);
4994 * Sets the text foreground color.
4997 * [I] HWND : window handle
4998 * [I] COLORREF : text color
5004 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5006 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5008 infoPtr->clrText = clrText;
5009 InvalidateRect(hwnd, NULL, TRUE);
5016 * Sorts the listview items.
5019 * [I] HWND : window handle
5025 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5027 FIXME (listview, "empty stub!\n");
5034 * Updates an items or rearranges the listview control.
5037 * [I] HWND : window handle
5038 * [I] INT : item index
5044 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5046 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5047 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5048 BOOL bResult = FALSE;
5051 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5055 /* rearrange with default alignment style */
5056 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5057 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5059 ListView_Arrange(hwnd, 0);
5063 /* get item bounding rectangle */
5064 rc.left = LVIR_BOUNDS;
5065 ListView_GetItemRect(hwnd, nItem, &rc);
5066 InvalidateRect(hwnd, &rc, FALSE);
5075 * Creates the listview control.
5078 * [I] HWND : window handle
5083 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5085 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5086 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5089 /* initialize info pointer */
5090 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5092 /* determine the type of structures to use */
5093 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5094 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5095 if (infoPtr->notifyFormat != NFR_ANSI)
5097 FIXME (listview, "ANSI notify format is NOT used\n");
5100 /* initialize color information */
5101 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5102 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5103 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5105 /* set default values */
5106 infoPtr->uCallbackMask = 0;
5107 infoPtr->nFocusedItem = -1;
5108 infoPtr->nSelectionMark = -1;
5109 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5110 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5111 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5113 /* get default font (icon title) */
5114 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5115 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5116 infoPtr->hFont = infoPtr->hDefaultFont;
5119 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5120 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5121 0, 0, 0, 0, hwnd, (HMENU)0,
5122 lpcs->hInstance, NULL);
5124 /* set header font */
5125 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5129 switch (lpcs->style & LVS_TYPEMASK)
5132 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5133 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5137 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5140 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5141 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5145 /* display unsupported listview window styles */
5146 LISTVIEW_UnsupportedStyles(lpcs->style);
5148 /* allocate memory for the data structure */
5149 infoPtr->hdpaItems = DPA_Create(10);
5151 /* initialize size of items */
5152 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpcs->style);
5153 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpcs->style);
5160 * Erases the background of the listview control.
5163 * [I] HWND : window handle
5164 * [I] WPARAM : device context handle
5165 * [I] LPARAM : not used
5171 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5174 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5177 if (infoPtr->clrBk == CLR_NONE)
5179 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5184 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5185 GetClientRect(hwnd, &rc);
5186 FillRect((HDC)wParam, &rc, hBrush);
5187 DeleteObject(hBrush);
5196 * Retrieves the listview control font.
5199 * [I] HWND : window handle
5204 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5206 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5208 return infoPtr->hFont;
5213 * Performs vertical scrolling.
5216 * [I] HWND : window handle
5217 * [I] INT : scroll code
5218 * [I] INT : scroll position
5219 * [I] HWND : scrollbar control window handle
5224 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, INT nScroll,
5227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5228 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5229 INT nScrollPosInc = 0;
5234 GetScrollRange(hwnd, SB_VERT, &nMinRange, &nMaxRange);
5235 nScrollPos = GetScrollPos(hwnd, SB_VERT);
5237 switch (nScrollCode)
5240 if (nScrollPos > nMinRange)
5247 if (nScrollPos < nMaxRange)
5254 switch (LVS_TYPEMASK & lStyle)
5257 if (nScrollPos > nMinRange + infoPtr->nCountPerColumn)
5259 nScrollPosInc = -infoPtr->nCountPerColumn;
5263 nScrollPosInc = nMinRange - nScrollPos;
5269 if (nScrollPos > nMinRange + 10)
5271 nScrollPosInc = -10;
5275 nScrollPosInc = nMinRange - nScrollPos;
5282 switch (LVS_TYPEMASK & lStyle)
5285 if (nScrollPos < nMaxRange - infoPtr->nCountPerColumn)
5287 nScrollPosInc = infoPtr->nCountPerColumn;
5291 nScrollPosInc = nMaxRange - nScrollPos;
5297 if (nScrollPos < nMaxRange - 10)
5303 nScrollPosInc = nMaxRange - nScrollPos;
5309 case SB_THUMBPOSITION:
5310 nScrollPosInc = nScroll - nScrollPos;
5314 if (nScrollPosInc != 0)
5316 LISTVIEW_ScrollView(hwnd, 0, nScrollPosInc);
5325 * Performs horizontal scrolling.
5328 * [I] HWND : window handle
5329 * [I] INT : scroll code
5330 * [I] INT : scroll position
5331 * [I] HWND : scrollbar control window handle
5336 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode,
5337 INT nScroll, HWND hScrollWnd)
5339 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5340 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5341 INT nScrollPosInc = 0;
5346 GetScrollRange(hwnd, SB_HORZ, &nMinRange, &nMaxRange);
5347 nScrollPos = GetScrollPos(hwnd, SB_HORZ);
5349 switch (nScrollCode)
5352 if (nScrollPos > nMinRange)
5359 if (nScrollPos < nMaxRange)
5366 switch (LVS_TYPEMASK & lStyle)
5369 if (nScrollPos > nMinRange + infoPtr->nCountPerRow)
5371 nScrollPosInc = -infoPtr->nCountPerRow;
5375 nScrollPosInc = nMinRange - nScrollPos;
5382 if (nScrollPos > nMinRange + 10)
5384 nScrollPosInc = -10;
5388 nScrollPosInc = nMinRange - nScrollPos;
5395 switch (LVS_TYPEMASK & lStyle)
5398 if (nScrollPos < nMaxRange - infoPtr->nCountPerRow)
5400 nScrollPosInc = infoPtr->nCountPerRow;
5404 nScrollPosInc = nMaxRange - nScrollPos;
5411 if (nScrollPos < nMaxRange - 10)
5417 nScrollPosInc = nMaxRange - nScrollPos;
5423 case SB_THUMBPOSITION:
5424 nScrollPosInc = nScroll - nScrollPos;
5428 if (nScrollPosInc != 0)
5430 LISTVIEW_ScrollView(hwnd, nScrollPosInc, 0);
5441 * [I] HWND : window handle
5442 * [I] INT : virtual key
5443 * [I] LONG : key data
5448 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
5450 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5451 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5452 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5453 INT nCountPerColumn;
5455 HWND hwndParent = GetParent(hwnd);
5456 NMLVKEYDOWN nmKeyDown;
5459 /* send LVN_KEYDOWN notification */
5460 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
5461 nmKeyDown.hdr.hwndFrom = hwnd;
5462 nmKeyDown.hdr.idFrom = nCtrlId;
5463 nmKeyDown.hdr.code = LVN_KEYDOWN;
5464 nmKeyDown.wVKey = nVirtualKey;
5465 nmKeyDown.flags = 0;
5466 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
5469 nmh.hwndFrom = hwnd;
5470 nmh.idFrom = nCtrlId;
5472 switch (nVirtualKey)
5475 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
5477 /* send NM_RETURN notification */
5478 nmh.code = NM_RETURN;
5479 ListView_Notify(hwndParent, nCtrlId, &nmh);
5481 /* send LVN_ITEMACTIVATE notification */
5482 nmh.code = LVN_ITEMACTIVATE;
5483 ListView_Notify(hwndParent, nCtrlId, &nmh);
5488 if (GETITEMCOUNT(infoPtr) > 0)
5490 LISTVIEW_KeySelection(hwnd, 0);
5495 if (GETITEMCOUNT(infoPtr) > 0)
5497 LISTVIEW_KeySelection(hwnd, GETITEMCOUNT(infoPtr) - 1);
5502 switch (LVS_TYPEMASK & lStyle)
5505 if (infoPtr->nFocusedItem >= infoPtr->nCountPerColumn)
5507 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem -
5508 infoPtr->nCountPerColumn);
5514 if (lStyle & LVS_ALIGNLEFT)
5516 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5517 infoPtr->nItemHeight, 1);
5518 if (infoPtr->nFocusedItem >= nCountPerColumn)
5520 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - nCountPerColumn);
5525 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5526 infoPtr->nItemWidth, 1);
5527 if (infoPtr->nFocusedItem % nCountPerRow != 0)
5529 LISTVIEW_SetSelection(hwnd, infoPtr->nFocusedItem - 1);
5537 switch (LVS_TYPEMASK & lStyle)
5541 if (infoPtr->nFocusedItem > 0)
5543 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - 1);
5548 if (lStyle & LVS_ALIGNLEFT)
5550 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5551 infoPtr->nItemHeight, 1);
5552 if (infoPtr->nFocusedItem % nCountPerColumn != 0)
5554 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - 1);
5559 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5560 infoPtr->nItemWidth, 1);
5561 if (infoPtr->nFocusedItem >= nCountPerRow)
5563 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem - nCountPerRow);
5570 switch (LVS_TYPEMASK & lStyle)
5573 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) -
5574 infoPtr->nCountPerColumn)
5576 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem +
5577 infoPtr->nCountPerColumn);
5583 if (lStyle & LVS_ALIGNLEFT)
5585 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5586 infoPtr->nItemHeight, 1);
5587 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - nCountPerColumn)
5589 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + nCountPerColumn);
5594 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5595 infoPtr->nItemWidth, 1);
5596 if ((infoPtr->nFocusedItem % nCountPerRow != nCountPerRow - 1) &&
5597 (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - 1))
5599 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1);
5606 switch (LVS_TYPEMASK & lStyle)
5610 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - 1)
5612 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1);
5618 if (lStyle & LVS_ALIGNLEFT)
5620 nCountPerColumn = max((infoPtr->rcList.bottom - infoPtr->rcList.top) /
5621 infoPtr->nItemHeight, 1);
5622 if (infoPtr->nFocusedItem % nCountPerColumn != nCountPerColumn - 1)
5624 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + 1);
5629 nCountPerRow = max((infoPtr->rcList.right - infoPtr->rcList.left) /
5630 infoPtr->nItemWidth, 1);
5631 if (infoPtr->nFocusedItem < GETITEMCOUNT(infoPtr) - nCountPerRow)
5633 LISTVIEW_KeySelection(hwnd, infoPtr->nFocusedItem + nCountPerRow);
5646 /* refresh client area */
5647 InvalidateRect(hwnd, NULL, TRUE);
5657 * [I] HWND : window handle
5662 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
5664 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5665 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5668 /* send NM_KILLFOCUS notification */
5669 nmh.hwndFrom = hwnd;
5670 nmh.idFrom = nCtrlId;
5671 nmh.code = NM_KILLFOCUS;
5672 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5674 /* set window focus flag */
5675 infoPtr->bFocus = FALSE;
5682 * Processes double click messages (left mouse button).
5685 * [I] HWND : window handle
5686 * [I] WORD : key flag
5687 * [I] WORD : x coordinate
5688 * [I] WORD : y coordinate
5693 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
5696 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5699 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5701 /* send NM_DBLCLK notification */
5702 nmh.hwndFrom = hwnd;
5703 nmh.idFrom = nCtrlId;
5704 nmh.code = NM_DBLCLK;
5705 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5707 /* send LVN_ITEMACTIVATE notification */
5708 nmh.code = LVN_ITEMACTIVATE;
5709 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5716 * Processes mouse down messages (left mouse button).
5719 * [I] HWND : window handle
5720 * [I] WORD : key flag
5721 * [I] WORD : x coordinate
5722 * [I] WORD : y coordinate
5727 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
5730 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5731 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5732 static BOOL bGroupSelect = TRUE;
5736 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5738 /* send NM_RELEASEDCAPTURE notification */
5739 nmh.hwndFrom = hwnd;
5740 nmh.idFrom = nCtrlId;
5741 nmh.code = NM_RELEASEDCAPTURE;
5742 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5744 if (infoPtr->bFocus == FALSE)
5749 /* set left button down flag */
5750 infoPtr->bLButtonDown = TRUE;
5752 nItem = LISTVIEW_MouseSelection(hwnd, wPosX, wPosY);
5753 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5755 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
5757 if (bGroupSelect != FALSE)
5759 LISTVIEW_AddGroupSelection(hwnd, nItem);
5763 LISTVIEW_AddSelection(hwnd, nItem);
5766 else if (wKey & MK_CONTROL)
5768 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
5770 else if (wKey & MK_SHIFT)
5772 LISTVIEW_SetGroupSelection(hwnd, nItem);
5776 LISTVIEW_SetSelection(hwnd, nItem);
5781 /* remove all selections */
5782 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
5785 InvalidateRect(hwnd, NULL, TRUE);
5792 * Processes mouse up messages (left mouse button).
5795 * [I] HWND : window handle
5796 * [I] WORD : key flag
5797 * [I] WORD : x coordinate
5798 * [I] WORD : y coordinate
5803 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
5806 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5808 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5810 if (infoPtr->bLButtonDown != FALSE)
5812 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5815 /* send NM_CLICK notification */
5816 nmh.hwndFrom = hwnd;
5817 nmh.idFrom = nCtrlId;
5818 nmh.code = NM_CLICK;
5819 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5821 /* set left button flag */
5822 infoPtr->bLButtonDown = FALSE;
5830 * Creates the listview control (called before WM_CREATE).
5833 * [I] HWND : window handle
5834 * [I] WPARAM : unhandled
5835 * [I] LPARAM : widow creation info
5840 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
5842 LISTVIEW_INFO *infoPtr;
5844 TRACE(listview, "(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
5846 /* allocate memory for info structure */
5847 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
5848 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
5849 if (infoPtr == NULL)
5851 ERR(listview, "could not allocate info memory!\n");
5855 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
5857 ERR(listview, "pointer assignment error!\n");
5861 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
5866 * Destroys the listview control (called after WM_DESTROY).
5869 * [I] HWND : window handle
5874 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
5876 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5878 TRACE(listview, "(hwnd=%x)\n", hwnd);
5880 /* delete all items */
5881 LISTVIEW_DeleteAllItems(hwnd);
5883 /* destroy data structure */
5884 DPA_Destroy(infoPtr->hdpaItems);
5887 infoPtr->hFont = (HFONT)0;
5888 if (infoPtr->hDefaultFont)
5890 DeleteObject(infoPtr->hDefaultFont);
5893 /* free listview info pointer*/
5894 COMCTL32_Free(infoPtr);
5901 * Handles notifications from children.
5904 * [I] HWND : window handle
5905 * [I] INT : control identifier
5906 * [I] LPNMHDR : notification information
5911 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
5913 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5915 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
5917 /* handle notification from header control */
5918 if (lpnmh->code == HDN_ENDTRACKA)
5920 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, LVS_REPORT);
5921 InvalidateRect(hwnd, NULL, TRUE);
5930 * Determines the type of structure to use.
5933 * [I] HWND : window handle of the sender
5934 * [I] HWND : listview window handle
5935 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
5940 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
5942 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5944 if (nCommand == NF_REQUERY)
5946 /* determine the type of structure to use */
5947 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
5948 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5949 if (infoPtr->notifyFormat == NFR_UNICODE)
5951 FIXME (listview, "NO support for unicode structures");
5960 * Paints/Repaints the listview control.
5963 * [I] HWND : window handle
5964 * [I] HDC : device context handle
5969 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
5973 TRACE(listview, "(hwnd=%x,hdc=%x)\n", hwnd, hdc);
5977 hdc = BeginPaint(hwnd, &ps);
5978 LISTVIEW_Refresh(hwnd, hdc);
5979 EndPaint(hwnd, &ps);
5983 LISTVIEW_Refresh(hwnd, hdc);
5991 * Processes double click messages (right mouse button).
5994 * [I] HWND : window handle
5995 * [I] WORD : key flag
5996 * [I] WORD : x coordinate
5997 * [I] WORD : y coordinate
6002 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6005 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6008 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6010 /* send NM_RELEASEDCAPTURE notification */
6011 nmh.hwndFrom = hwnd;
6012 nmh.idFrom = nCtrlId;
6013 nmh.code = NM_RELEASEDCAPTURE;
6014 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6016 /* send NM_RDBLCLK notification */
6017 nmh.code = NM_RDBLCLK;
6018 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6025 * Processes mouse down messages (right mouse button).
6028 * [I] HWND : window handle
6029 * [I] WORD : key flag
6030 * [I] WORD : x coordinate
6031 * [I] WORD : y coordinate
6036 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6039 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6040 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6044 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6046 /* send NM_RELEASEDCAPTURE notification */
6047 nmh.hwndFrom = hwnd;
6048 nmh.idFrom = nCtrlId;
6049 nmh.code = NM_RELEASEDCAPTURE;
6050 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6052 /* make sure the listview control window has the focus */
6053 if (infoPtr->bFocus == FALSE)
6058 /* set right button down flag */
6059 infoPtr->bRButtonDown = TRUE;
6061 /* determine the index of the selected item */
6062 nItem = LISTVIEW_MouseSelection(hwnd, wPosX, wPosY);
6063 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6065 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6067 LISTVIEW_SetSelection(hwnd, nItem);
6072 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6080 * Processes mouse up messages (right mouse button).
6083 * [I] HWND : window handle
6084 * [I] WORD : key flag
6085 * [I] WORD : x coordinate
6086 * [I] WORD : y coordinate
6091 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6094 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6095 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6098 TRACE(listview, "(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6100 if (infoPtr->bRButtonDown != FALSE)
6102 /* send NM_RClICK notification */
6103 ZeroMemory(&nmh, sizeof(NMHDR));
6104 nmh.hwndFrom = hwnd;
6105 nmh.idFrom = nCtrlId;
6106 nmh.code = NM_RCLICK;
6107 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6109 /* set button flag */
6110 infoPtr->bRButtonDown = FALSE;
6121 * [I] HWND : window handle
6122 * [I] HWND : window handle of previously focused window
6127 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6129 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6130 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6133 /* send NM_SETFOCUS notification */
6134 nmh.hwndFrom = hwnd;
6135 nmh.idFrom = nCtrlId;
6136 nmh.code = NM_SETFOCUS;
6137 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6139 /* set window focus flag */
6140 infoPtr->bFocus = TRUE;
6150 * [I] HWND : window handle
6151 * [I] HFONT : font handle
6152 * [I] WORD : redraw flag
6157 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6159 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6160 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6162 TRACE(listview, "(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6166 infoPtr->hFont = infoPtr->hDefaultFont;
6170 infoPtr->hFont = hFont;
6173 if ((LVS_TYPEMASK & lStyle ) == LVS_REPORT)
6175 /* set header font */
6176 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6177 MAKELPARAM(fRedraw, 0));
6180 /* invalidate listview control client area */
6181 InvalidateRect(hwnd, NULL, TRUE);
6183 if (fRedraw != FALSE)
6193 * Resizes the listview control. This function processes WM_SIZE
6194 * messages. At this time, the width and height are not used.
6197 * [I] HWND : window handle
6198 * [I] WORD : new width
6199 * [I] WORD : new height
6204 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6206 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6208 TRACE(listview, "(hwnd=%x,width=%d,height=%d)\n",hwnd, Width, Height);
6210 LISTVIEW_SetSize(hwnd, lStyle, -1, -1);
6211 switch (lStyle & LVS_TYPEMASK)
6215 LISTVIEW_SetViewInfo(hwnd, lStyle);
6220 if (lStyle & LVS_ALIGNLEFT)
6222 LISTVIEW_AlignLeft(hwnd);
6226 LISTVIEW_AlignTop(hwnd);
6231 LISTVIEW_SetScroll(hwnd, lStyle);
6233 /* invalidate + erase background */
6234 InvalidateRect(hwnd, NULL, TRUE);
6241 * Sets the size information for a given style.
6244 * [I] HWND : window handle
6245 * [I] LONG : window style
6246 * [I] WORD : new width
6247 * [I] WORD : new height
6252 static VOID LISTVIEW_SetSize(HWND hwnd, LONG lStyle, LONG lWidth, LONG lHeight)
6254 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6259 GetClientRect(hwnd, &rcList);
6262 infoPtr->rcList.left = max(rcList.left, 0);
6263 infoPtr->rcList.right = max(rcList.right, 0);
6267 infoPtr->rcList.left = max(rcList.left, 0);
6268 infoPtr->rcList.right = infoPtr->rcList.left + max(lWidth, 0);
6273 infoPtr->rcList.top = max(rcList.top, 0);
6274 infoPtr->rcList.bottom = max(rcList.bottom, 0);
6278 infoPtr->rcList.top = max(rcList.top, 0);
6279 infoPtr->rcList.bottom = infoPtr->rcList.top + max(lHeight, 0);
6282 switch (lStyle & LVS_TYPEMASK)
6285 if ((lStyle & WS_HSCROLL) == 0)
6288 nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6289 if (infoPtr->rcList.bottom > nHScrollHeight)
6291 infoPtr->rcList.bottom -= nHScrollHeight;
6299 Header_Layout(infoPtr->hwndHeader, &hl);
6300 infoPtr->rcList.top = max(wp.cy, 0);
6307 * Processes WM_STYLECHANGED messages.
6310 * [I] HWND : window handle
6311 * [I] WPARAM : window style type (normal or extended)
6312 * [I] LPSTYLESTRUCT : window style information
6317 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6320 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6321 RECT rcList = infoPtr->rcList;
6325 TRACE(listview, "(hwnd=%x,styletype=%x,stylestruct=%p)\n",
6326 hwnd, wStyleType, lpss);
6328 if (wStyleType == GWL_STYLE)
6330 if ((lpss->styleOld & WS_HSCROLL) != 0)
6332 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6335 if ((lpss->styleOld & WS_VSCROLL) != 0)
6337 ShowScrollBar(hwnd, SB_VERT, FALSE);
6340 if ((LVS_TYPEMASK & lpss->styleOld) == LVS_REPORT)
6343 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6346 switch (lpss->styleNew & LVS_TYPEMASK)
6349 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6350 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6351 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6352 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6353 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6354 if (lpss->styleNew & LVS_ALIGNLEFT)
6356 LISTVIEW_AlignLeft(hwnd);
6360 LISTVIEW_AlignTop(hwnd);
6367 Header_Layout(infoPtr->hwndHeader, &hl);
6368 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx,
6370 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6371 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6372 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6373 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6374 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6375 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6376 LISTVIEW_SetViewInfo(hwnd, lpss->styleNew);
6380 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6381 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6382 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6383 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6384 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6385 LISTVIEW_SetViewInfo(hwnd, lpss->styleNew);
6389 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6390 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6391 LISTVIEW_SetSize(hwnd, lpss->styleNew, -1, -1);
6392 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd, lpss->styleNew);
6393 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd, lpss->styleNew);
6394 if (lpss->styleNew & LVS_ALIGNLEFT)
6396 LISTVIEW_AlignLeft(hwnd);
6400 LISTVIEW_AlignTop(hwnd);
6405 LISTVIEW_SetScroll(hwnd, lpss->styleNew);
6407 /* print unsupported styles */
6408 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6410 /* invalidate client area */
6411 InvalidateRect(hwnd, NULL, TRUE);
6419 * Window procedure of the listview control.
6430 LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6435 case LVM_APPROXIMATEVIEWRECT:
6436 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6437 LOWORD(lParam), HIWORD(lParam));
6439 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6441 /* case LVM_CREATEDRAGIMAGE: */
6443 case LVM_DELETEALLITEMS:
6444 return LISTVIEW_DeleteAllItems(hwnd);
6446 case LVM_DELETECOLUMN:
6447 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6449 case LVM_DELETEITEM:
6450 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6452 /* case LVM_EDITLABEL: */
6454 case LVM_ENSUREVISIBLE:
6455 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6458 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6460 case LVM_GETBKCOLOR:
6461 return LISTVIEW_GetBkColor(hwnd);
6463 /* case LVM_GETBKIMAGE: */
6465 case LVM_GETCALLBACKMASK:
6466 return LISTVIEW_GetCallbackMask(hwnd);
6468 case LVM_GETCOLUMNA:
6469 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6471 /* case LVM_GETCOLUMNW: */
6472 /* case LVM_GETCOLUMNORDERARRAY: */
6474 case LVM_GETCOLUMNWIDTH:
6475 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
6477 case LVM_GETCOUNTPERPAGE:
6478 return LISTVIEW_GetCountPerPage(hwnd);
6480 /* case LVM_GETEDITCONTROL: */
6481 /* case LVM_GETEXTENDEDLISTVIEWSTYLE: */
6484 return LISTVIEW_GetHeader(hwnd);
6486 /* case LVM_GETHOTCURSOR: */
6487 /* case LVM_GETHOTITEM: */
6488 /* case LVM_GETHOVERTIME: */
6490 case LVM_GETIMAGELIST:
6491 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
6493 /* case LVM_GETISEARCHSTRING: */
6496 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
6498 /* case LVM_GETITEMW: */
6500 case LVM_GETITEMCOUNT:
6501 return LISTVIEW_GetItemCount(hwnd);
6503 case LVM_GETITEMPOSITION:
6504 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
6506 case LVM_GETITEMRECT:
6507 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
6509 case LVM_GETITEMSPACING:
6510 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
6512 case LVM_GETITEMSTATE:
6513 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
6515 case LVM_GETITEMTEXTA:
6516 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6519 /* case LVM_GETITEMTEXTW: */
6521 case LVM_GETNEXTITEM:
6522 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
6524 /* case LVM_GETNUMBEROFWORKAREAS: */
6527 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
6529 case LVM_GETSELECTEDCOUNT:
6530 return LISTVIEW_GetSelectedCount(hwnd);
6532 case LVM_GETSELECTIONMARK:
6533 return LISTVIEW_GetSelectionMark(hwnd);
6535 case LVM_GETSTRINGWIDTHA:
6536 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
6538 /* case LVM_GETSTRINGWIDTHW: */
6539 /* case LVM_GETSUBITEMRECT: */
6541 case LVM_GETTEXTBKCOLOR:
6542 return LISTVIEW_GetTextBkColor(hwnd);
6544 case LVM_GETTEXTCOLOR:
6545 return LISTVIEW_GetTextColor(hwnd);
6547 /* case LVM_GETTOOLTIPS: */
6549 case LVM_GETTOPINDEX:
6550 return LISTVIEW_GetTopIndex(hwnd);
6552 /* case LVM_GETUNICODEFORMAT: */
6554 case LVM_GETVIEWRECT:
6555 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
6557 /* case LVM_GETWORKAREAS: */
6560 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
6562 case LVM_INSERTCOLUMNA:
6563 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam,
6564 (LPLVCOLUMNA)lParam);
6566 /* case LVM_INSERTCOLUMNW: */
6568 case LVM_INSERTITEMA:
6569 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
6571 /* case LVM_INSERTITEMW: */
6573 case LVM_REDRAWITEMS:
6574 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
6576 /* case LVM_SCROLL: */
6577 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
6579 case LVM_SETBKCOLOR:
6580 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
6582 /* case LVM_SETBKIMAGE: */
6584 case LVM_SETCALLBACKMASK:
6585 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
6587 case LVM_SETCOLUMNA:
6588 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6590 /* case LVM_SETCOLUMNW: */
6591 /* case LVM_SETCOLUMNORDERARRAY: */
6593 case LVM_SETCOLUMNWIDTH:
6594 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
6596 /* case LVM_SETEXTENDEDLISTVIEWSTYLE: */
6597 /* case LVM_SETHOTCURSOR: */
6598 /* case LVM_SETHOTITEM: */
6599 /* case LVM_SETHOVERTIME: */
6600 /* case LVM_SETICONSPACING: */
6602 case LVM_SETIMAGELIST:
6603 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
6606 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
6608 /* case LVM_SETITEMW: */
6610 case LVM_SETITEMCOUNT:
6611 LISTVIEW_SetItemCount(hwnd, (INT)wParam);
6614 case LVM_SETITEMPOSITION:
6615 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
6616 (INT)HIWORD(lParam));
6618 /* case LVM_SETITEMPOSITION: */
6620 case LVM_SETITEMSTATE:
6621 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6623 case LVM_SETITEMTEXTA:
6624 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6626 /* case LVM_SETSELECTIONMARK: */
6628 case LVM_SETTEXTBKCOLOR:
6629 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
6631 case LVM_SETTEXTCOLOR:
6632 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
6634 /* case LVM_SETTOOLTIPS: */
6635 /* case LVM_SETUNICODEFORMAT: */
6636 /* case LVM_SETWORKAREAS: */
6639 return LISTVIEW_SortItems(hwnd, wParam, lParam);
6641 /* case LVM_SUBITEMHITTEST: */
6644 return LISTVIEW_Update(hwnd, (INT)wParam);
6647 /* case WM_COMMAND: */
6650 return LISTVIEW_Create(hwnd, wParam, lParam);
6653 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
6656 return DLGC_WANTTAB | DLGC_WANTARROWS;
6659 return LISTVIEW_GetFont(hwnd);
6662 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
6663 (INT)HIWORD(wParam), (HWND)lParam);
6666 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
6669 return LISTVIEW_KillFocus(hwnd);
6671 case WM_LBUTTONDBLCLK:
6672 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6675 case WM_LBUTTONDOWN:
6676 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6679 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6682 /* case WM_MOUSEMOVE: */
6683 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
6686 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
6689 return LISTVIEW_NCDestroy(hwnd);
6692 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
6694 case WM_NOTIFYFORMAT:
6695 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
6698 return LISTVIEW_Paint(hwnd, (HDC)wParam);
6700 case WM_RBUTTONDBLCLK:
6701 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6704 case WM_RBUTTONDOWN:
6705 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6709 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6713 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
6716 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
6718 /* case WM_SETREDRAW: */
6721 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
6723 case WM_STYLECHANGED:
6724 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
6726 /* case WM_TIMER: */
6729 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
6730 (INT)HIWORD(wParam), (HWND)lParam);
6732 /* case WM_WINDOWPOSCHANGED: */
6733 /* case WM_WININICHANGE: */
6736 if (uMsg >= WM_USER)
6738 ERR(listview, "unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
6742 /* call default window procedure */
6743 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
6751 * Registers the window class.
6759 VOID LISTVIEW_Register(VOID)
6763 if (!GlobalFindAtomA(WC_LISTVIEWA))
6765 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
6766 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
6767 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
6768 wndClass.cbClsExtra = 0;
6769 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
6770 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
6771 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
6772 wndClass.lpszClassName = WC_LISTVIEWA;
6773 RegisterClassA(&wndClass);
6779 * Unregisters the window class.
6787 VOID LISTVIEW_Unregister(VOID)
6789 if (GlobalFindAtomA(WC_LISTVIEWA))
6791 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);