4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
8 * Listview control implementation.
11 * 1. No horizontal scrolling when header is larger than the client area.
12 * 2. Drawing optimizations.
13 * 3. Hot item handling.
16 * LISTVIEW_Notify : most notifications from children (editbox and header)
19 * LISTVIEW_SetItemCount : not completed
22 * LISTVIEW_SetItemW : no unicode support
23 * LISTVIEW_InsertItemW : no unicode support
24 * LISTVIEW_InsertColumnW : no unicode support
25 * LISTVIEW_GetColumnW : no unicode support
26 * LISTVIEW_SetColumnW : no unicode support
28 * Advanced functionality:
29 * LISTVIEW_GetNumberOfWorkAreas : not implemented
30 * LISTVIEW_GetHotCursor : not implemented
31 * LISTVIEW_GetISearchString : not implemented
32 * LISTVIEW_GetBkImage : not implemented
33 * LISTVIEW_GetColumnOrderArray : simple hack only
34 * LISTVIEW_SetColumnOrderArray : simple hack only
35 * LISTVIEW_Arrange : empty stub
36 * LISTVIEW_ApproximateViewRect : incomplete
37 * LISTVIEW_Scroll : not implemented
38 * LISTVIEW_RedrawItems : empty stub
39 * LISTVIEW_Update : not completed
47 #include "debugtools.h"
49 DEFAULT_DEBUG_CHANNEL(listview)
55 /* maximum size of a label */
56 #define DISP_TEXT_SIZE 512
58 /* padding for items in list and small icon display modes */
59 #define WIDTH_PADDING 12
61 /* padding for items in list, report and small icon display modes */
62 #define HEIGHT_PADDING 1
64 /* offset of items in report display mode */
65 #define REPORT_MARGINX 2
67 /* padding for icon in large icon display mode */
68 #define ICON_TOP_PADDING 2
69 #define ICON_BOTTOM_PADDING 2
71 /* padding for label in large icon display mode */
72 #define LABEL_VERT_OFFSET 2
74 /* default label width for items in list and small icon display modes */
75 #define DEFAULT_LABEL_WIDTH 40
77 /* default column width for items in list display mode */
78 #define DEFAULT_COLUMN_WIDTH 96
80 /* Increment size of the horizontal scroll bar */
81 #define LISTVIEW_SCROLL_DIV_SIZE 10
86 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
87 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
88 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
89 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
90 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
91 /* retrieve the number of items in the listview */
92 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
94 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
95 INT width, INT height, HWND parent, HINSTANCE hinst,
96 EditlblCallback EditLblCb, DWORD param);
99 * forward declarations
101 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
102 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
103 static INT LISTVIEW_GetCountPerRow(HWND);
104 static INT LISTVIEW_GetCountPerColumn(HWND);
105 static VOID LISTVIEW_AlignLeft(HWND);
106 static VOID LISTVIEW_AlignTop(HWND);
107 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
108 static VOID LISTVIEW_AddSelection(HWND, INT);
109 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
110 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
111 static INT LISTVIEW_GetItemHeight(HWND);
112 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
113 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
114 static INT LISTVIEW_GetItemWidth(HWND);
115 static INT LISTVIEW_GetLabelWidth(HWND, INT);
116 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
117 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
118 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
119 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
120 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
121 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
122 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
123 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
124 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
125 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
126 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
127 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
128 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
129 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
130 static VOID LISTVIEW_UpdateScroll(HWND);
131 static VOID LISTVIEW_SetSelection(HWND, INT);
132 static VOID LISTVIEW_UpdateSize(HWND);
133 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
134 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
135 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
136 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
137 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
138 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
139 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
140 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
142 /*************************************************************************
143 * LISTVIEW_UpdateHeaderSize [Internal]
145 * Function to resize the header control
148 * hwnd [I] handle to a window
149 * nNewScrollPos [I] Scroll Pos to Set
156 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
158 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
162 GetWindowRect(infoPtr->hwndHeader, &winRect);
163 point[0].x = winRect.left;
164 point[0].y = winRect.top;
165 point[1].x = winRect.right;
166 point[1].y = winRect.bottom;
168 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
169 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
170 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
172 SetWindowPos(infoPtr->hwndHeader,0,
173 point[0].x,point[0].y,point[1].x,point[1].y,
174 SWP_NOZORDER | SWP_NOACTIVATE);
179 * Update the scrollbars. This functions should be called whenever
180 * the content, size or view changes.
183 * [I] HWND : window handle
188 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
190 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
191 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
192 UINT uView = lStyle & LVS_TYPEMASK;
193 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
194 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
195 SCROLLINFO scrollInfo;
197 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
198 scrollInfo.cbSize = sizeof(SCROLLINFO);
200 if (uView == LVS_LIST)
202 /* update horizontal scrollbar */
204 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
205 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
206 INT nNumOfItems = GETITEMCOUNT(infoPtr);
208 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
209 if((nNumOfItems % nCountPerColumn) == 0)
213 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
214 scrollInfo.nPage = nCountPerRow;
215 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
216 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
218 else if (uView == LVS_REPORT)
220 /* update vertical scrollbar */
222 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
223 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
224 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
225 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
226 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
228 /* update horizontal scrollbar */
229 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
230 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
231 || GETITEMCOUNT(infoPtr) == 0)
236 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
237 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
238 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
239 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
241 /* Update the Header Control */
242 scrollInfo.fMask = SIF_POS;
243 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
244 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
251 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
253 INT nViewWidth = rcView.right - rcView.left;
254 INT nViewHeight = rcView.bottom - rcView.top;
256 /* Update Horizontal Scrollbar */
257 scrollInfo.fMask = SIF_POS;
258 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
259 || GETITEMCOUNT(infoPtr) == 0)
263 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
265 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
266 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
267 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
269 /* Update Vertical Scrollbar */
270 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
271 scrollInfo.fMask = SIF_POS;
272 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
273 || GETITEMCOUNT(infoPtr) == 0)
277 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
279 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
280 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
281 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
288 * Prints a message for unsupported window styles.
289 * A kind of TODO list for window styles.
292 * [I] LONG : window style
297 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
299 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
301 FIXME(" LVS_EDITLABELS\n");
304 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
306 FIXME(" LVS_NOLABELWRAP\n");
309 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
311 FIXME(" LVS_NOSCROLL\n");
314 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
316 FIXME(" LVS_NOSORTHEADER\n");
319 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
321 FIXME(" LVS_OWNERDRAWFIXED\n");
324 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
326 FIXME(" LVS_SHAREIMAGELISTS\n");
329 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
331 FIXME(" LVS_SORTASCENDING\n");
334 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
336 FIXME(" LVS_SORTDESCENDING\n");
342 * Aligns the items with the top edge of the window.
345 * [I] HWND : window handle
350 static VOID LISTVIEW_AlignTop(HWND hwnd)
352 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
353 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
354 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
359 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
361 ZeroMemory(&ptItem, sizeof(POINT));
362 ZeroMemory(&rcView, sizeof(RECT));
364 if (nListWidth > infoPtr->nItemWidth)
366 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
368 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
371 ptItem.y += infoPtr->nItemHeight;
374 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
375 ptItem.x += infoPtr->nItemWidth;
376 rcView.right = max(rcView.right, ptItem.x);
379 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
383 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
385 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
386 ptItem.y += infoPtr->nItemHeight;
389 rcView.right = infoPtr->nItemWidth;
390 rcView.bottom = ptItem.y;
393 LISTVIEW_SetViewRect(hwnd, &rcView);
399 * Aligns the items with the left edge of the window.
402 * [I] HWND : window handle
407 static VOID LISTVIEW_AlignLeft(HWND hwnd)
409 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
410 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
411 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
416 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
418 ZeroMemory(&ptItem, sizeof(POINT));
419 ZeroMemory(&rcView, sizeof(RECT));
421 if (nListHeight > infoPtr->nItemHeight)
423 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
425 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
428 ptItem.x += infoPtr->nItemWidth;
431 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
432 ptItem.y += infoPtr->nItemHeight;
433 rcView.bottom = max(rcView.bottom, ptItem.y);
436 rcView.right = ptItem.x + infoPtr->nItemWidth;
440 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
442 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
443 ptItem.x += infoPtr->nItemWidth;
446 rcView.bottom = infoPtr->nItemHeight;
447 rcView.right = ptItem.x;
450 LISTVIEW_SetViewRect(hwnd, &rcView);
456 * Set the bounding rectangle of all the items.
459 * [I] HWND : window handle
460 * [I] LPRECT : bounding rectangle
466 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
468 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
469 BOOL bResult = FALSE;
471 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
472 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
474 if (lprcView != NULL)
477 infoPtr->rcView.left = lprcView->left;
478 infoPtr->rcView.top = lprcView->top;
479 infoPtr->rcView.right = lprcView->right;
480 infoPtr->rcView.bottom = lprcView->bottom;
488 * Retrieves the bounding rectangle of all the items.
491 * [I] HWND : window handle
492 * [O] LPRECT : bounding rectangle
498 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
500 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
501 BOOL bResult = FALSE;
504 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
506 if (lprcView != NULL)
508 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
509 if (bResult != FALSE)
511 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
512 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
513 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
514 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
517 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
518 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
526 * Retrieves the subitem pointer associated with the subitem index.
529 * [I] HDPA : DPA handle for a specific item
530 * [I] INT : index of subitem
533 * SUCCESS : subitem pointer
536 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
539 LISTVIEW_SUBITEM *lpSubItem;
542 for (i = 1; i < hdpaSubItems->nItemCount; i++)
544 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
545 if (lpSubItem != NULL)
547 if (lpSubItem->iSubItem == nSubItem)
559 * Calculates the width of an item.
562 * [I] HWND : window handle
563 * [I] LONG : window style
566 * Returns item width.
568 static INT LISTVIEW_GetItemWidth(HWND hwnd)
570 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
571 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
572 INT nHeaderItemCount;
578 TRACE("(hwnd=%x)\n", hwnd);
580 if (uView == LVS_ICON)
582 nItemWidth = infoPtr->iconSpacing.cx;
584 else if (uView == LVS_REPORT)
586 /* calculate width of header */
587 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
588 for (i = 0; i < nHeaderItemCount; i++)
590 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
592 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
598 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
600 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
601 nItemWidth = max(nItemWidth, nLabelWidth);
604 /* default label size */
605 if (GETITEMCOUNT(infoPtr) == 0)
607 nItemWidth = DEFAULT_COLUMN_WIDTH;
613 nItemWidth = DEFAULT_LABEL_WIDTH;
618 nItemWidth += WIDTH_PADDING;
620 if (infoPtr->himlSmall != NULL)
622 nItemWidth += infoPtr->iconSize.cx;
625 if (infoPtr->himlState != NULL)
627 nItemWidth += infoPtr->iconSize.cx;
634 /* nItemWidth Cannot be Zero */
642 * Calculates the width of a specific item.
645 * [I] HWND : window handle
649 * Returns the width of an item width a specified string.
651 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
653 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
654 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
655 INT nHeaderItemCount;
660 TRACE("(hwnd=%x)\n", hwnd);
662 if (uView == LVS_ICON)
664 nItemWidth = infoPtr->iconSpacing.cx;
666 else if (uView == LVS_REPORT)
668 /* calculate width of header */
669 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
670 for (i = 0; i < nHeaderItemCount; i++)
672 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
674 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
680 /* get width of string */
681 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
683 /* default label size */
684 if (GETITEMCOUNT(infoPtr) == 0)
686 nItemWidth = DEFAULT_COLUMN_WIDTH;
692 nItemWidth = DEFAULT_LABEL_WIDTH;
697 nItemWidth += WIDTH_PADDING;
699 if (infoPtr->himlSmall != NULL)
701 nItemWidth += infoPtr->iconSize.cx;
704 if (infoPtr->himlState != NULL)
706 nItemWidth += infoPtr->iconSize.cx;
717 * Calculates the height of an item.
720 * [I] HWND : window handle
721 * [I] LONG : window style
724 * Returns item height.
726 static INT LISTVIEW_GetItemHeight(HWND hwnd)
728 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
729 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
732 if (uView == LVS_ICON)
734 nItemHeight = infoPtr->iconSpacing.cy;
739 HDC hdc = GetDC(hwnd);
740 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
741 GetTextMetricsA(hdc, &tm);
742 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
743 SelectObject(hdc, hOldFont);
744 ReleaseDC(hwnd, hdc);
752 * Adds a block of selections.
755 * [I] HWND : window handle
756 * [I] INT : item index
761 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
763 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
764 INT nFirst = min(infoPtr->nSelectionMark, nItem);
765 INT nLast = max(infoPtr->nSelectionMark, nItem);
769 lvItem.state = LVIS_SELECTED;
770 lvItem.stateMask= LVIS_SELECTED;
772 for (i = nFirst; i <= nLast; i++)
774 ListView_SetItemState(hwnd, i, &lvItem);
777 LISTVIEW_SetItemFocus(hwnd, nItem);
778 infoPtr->nSelectionMark = nItem;
783 * Adds a single selection.
786 * [I] HWND : window handle
787 * [I] INT : item index
792 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
794 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
797 lvItem.state = LVIS_SELECTED;
798 lvItem.stateMask= LVIS_SELECTED;
800 ListView_SetItemState(hwnd, nItem, &lvItem);
802 LISTVIEW_SetItemFocus(hwnd, nItem);
803 infoPtr->nSelectionMark = nItem;
808 * Selects or unselects an item.
811 * [I] HWND : window handle
812 * [I] INT : item index
818 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
820 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
824 lvItem.stateMask= LVIS_SELECTED;
826 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
829 ListView_SetItemState(hwnd, nItem, &lvItem);
834 lvItem.state = LVIS_SELECTED;
835 ListView_SetItemState(hwnd, nItem, &lvItem);
839 LISTVIEW_SetItemFocus(hwnd, nItem);
840 infoPtr->nSelectionMark = nItem;
847 * Selects items based on view coorddiantes.
850 * [I] HWND : window handle
851 * [I] RECT : selection rectangle
856 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
858 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
863 lvItem.stateMask = LVIS_SELECTED;
865 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
867 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
868 if (PtInRect(&rcSelRect, ptItem) != FALSE)
870 lvItem.state = LVIS_SELECTED;
877 ListView_SetItemState(hwnd, i, &lvItem);
883 * Sets a single group selection.
886 * [I] HWND : window handle
887 * [I] INT : item index
892 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
894 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
895 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
898 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
901 INT nFirst = min(infoPtr->nSelectionMark, nItem);
902 INT nLast = max(infoPtr->nSelectionMark, nItem);
903 lvItem.stateMask = LVIS_SELECTED;
905 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
907 if ((i < nFirst) || (i > nLast))
913 lvItem.state = LVIS_SELECTED;
916 ListView_SetItemState(hwnd, i, &lvItem);
924 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
925 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
926 rcSel.left = min(ptSelMark.x, ptItem.x);
927 rcSel.top = min(ptSelMark.y, ptItem.y);
928 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
929 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
930 LISTVIEW_SetSelectionRect(hwnd, rcSel);
933 LISTVIEW_SetItemFocus(hwnd, nItem);
938 * Manages the item focus.
941 * [I] HWND : window handle
942 * [I] INT : item index
945 * TRUE : focused item changed
946 * FALSE : focused item has NOT changed
948 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
950 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
951 BOOL bResult = FALSE;
954 if (infoPtr->nFocusedItem != nItem)
957 ZeroMemory(&lvItem, sizeof(LVITEMA));
958 lvItem.stateMask = LVIS_FOCUSED;
959 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
961 lvItem.state = LVIS_FOCUSED;
962 lvItem.stateMask = LVIS_FOCUSED;
963 ListView_SetItemState(hwnd, nItem, &lvItem);
965 infoPtr->nFocusedItem = nItem;
966 ListView_EnsureVisible(hwnd, nItem, FALSE);
974 * Sets a single selection.
977 * [I] HWND : window handle
978 * [I] INT : item index
983 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
985 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
990 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
993 if (nItem < GETITEMCOUNT(infoPtr))
995 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
998 ZeroMemory(&lvItem, sizeof(LVITEMA));
999 lvItem.stateMask = LVIS_FOCUSED;
1000 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1002 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
1003 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1004 ListView_SetItemState(hwnd, nItem, &lvItem);
1006 infoPtr->nFocusedItem = nItem;
1007 infoPtr->nSelectionMark = nItem;
1012 * Set selection(s) with keyboard.
1015 * [I] HWND : window handle
1016 * [I] INT : item index
1019 * SUCCESS : TRUE (needs to be repainted)
1020 * FAILURE : FALSE (nothing has changed)
1022 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1024 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1025 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1026 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1027 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1028 BOOL bResult = FALSE;
1030 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1032 if (lStyle & LVS_SINGLESEL)
1035 LISTVIEW_SetSelection(hwnd, nItem);
1036 ListView_EnsureVisible(hwnd, nItem, FALSE);
1043 LISTVIEW_SetGroupSelection(hwnd, nItem);
1047 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1052 LISTVIEW_SetSelection(hwnd, nItem);
1053 ListView_EnsureVisible(hwnd, nItem, FALSE);
1063 * Called when the mouse is being actively tracked and has hovered for a specified
1067 * [I] HWND : window handle
1068 * [I] wParam : key indicator
1069 * [I] lParam : mouse position
1072 * 0 if the message was processed, non-zero if there was an error
1075 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1076 * over the item for a certain period of time.
1079 static LRESULT LISTVIEW_MouseHover(hwnd, wParam, lParam)
1081 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1084 pt.x = (INT)LOWORD(lParam);
1085 pt.y = (INT)HIWORD(lParam);
1087 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1088 /* select the item under the cursor */
1089 LISTVIEW_MouseSelection(hwnd, pt);
1097 * Called whenever WM_MOUSEMOVE is recieved.
1100 * [I] HWND : window handle
1101 * [I] wParam : key indicators
1102 * [I] lParam : cursor position
1105 * 0 if the message is processed, non-zero if there was an error
1107 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1109 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1110 TRACKMOUSEEVENT trackinfo;
1113 /* see if we are supposed to be tracking mouse hovering */
1114 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1115 /* fill in the trackinfo struct */
1116 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1117 trackinfo.dwFlags = TME_QUERY;
1118 trackinfo.hwndTrack = hwnd;
1119 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1121 /* see if we are already tracking this hwnd */
1122 _TrackMouseEvent(&trackinfo);
1124 if(!(trackinfo.dwFlags & TME_HOVER)) {
1125 trackinfo.dwFlags = TME_HOVER;
1127 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1128 _TrackMouseEvent(&trackinfo);
1137 * Selects an item based on coordinates.
1140 * [I] HWND : window handle
1141 * [I] POINT : mouse click ccordinates
1144 * SUCCESS : item index
1147 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1149 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1153 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1155 rcItem.left = LVIR_SELECTBOUNDS;
1156 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1158 if (PtInRect(&rcItem, pt) != FALSE)
1170 * Removes all selection states.
1173 * [I] HWND : window handle
1174 * [I] INT : item index
1180 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1186 lvItem.stateMask = LVIS_SELECTED;
1188 for (i = nFirst; i <= nLast; i++)
1190 ListView_SetItemState(hwnd, i, &lvItem);
1199 * [IO] HDPA : dynamic pointer array handle
1200 * [I] INT : column index (subitem index)
1206 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1208 BOOL bResult = TRUE;
1212 for (i = 0; i < hdpaItems->nItemCount; i++)
1214 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1215 if (hdpaSubItems != NULL)
1217 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1229 * Removes a subitem at a given position.
1232 * [IO] HDPA : dynamic pointer array handle
1233 * [I] INT : subitem index
1239 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1241 LISTVIEW_SUBITEM *lpSubItem;
1244 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1246 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1247 if (lpSubItem != NULL)
1249 if (lpSubItem->iSubItem == nSubItem)
1252 if ((lpSubItem->pszText != NULL) &&
1253 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1255 COMCTL32_Free(lpSubItem->pszText);
1259 COMCTL32_Free(lpSubItem);
1261 /* free dpa memory */
1262 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1267 else if (lpSubItem->iSubItem > nSubItem)
1279 * Compares the item information.
1282 * [I] LISTVIEW_ITEM *: destination item
1283 * [I] LPLVITEM : source item
1286 * SUCCCESS : TRUE (EQUAL)
1287 * FAILURE : FALSE (NOT EQUAL)
1289 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1293 if ((lpItem != NULL) && (lpLVItem != NULL))
1295 if (lpLVItem->mask & LVIF_STATE)
1297 if ((lpItem->state & lpLVItem->stateMask) !=
1298 (lpLVItem->state & lpLVItem->stateMask))
1300 uChanged |= LVIF_STATE;
1304 if (lpLVItem->mask & LVIF_IMAGE)
1306 if (lpItem->iImage != lpLVItem->iImage)
1308 uChanged |= LVIF_IMAGE;
1312 if (lpLVItem->mask & LVIF_PARAM)
1314 if (lpItem->lParam != lpLVItem->lParam)
1316 uChanged |= LVIF_PARAM;
1320 if (lpLVItem->mask & LVIF_INDENT)
1322 if (lpItem->iIndent != lpLVItem->iIndent)
1324 uChanged |= LVIF_INDENT;
1328 if (lpLVItem->mask & LVIF_TEXT)
1330 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1332 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1334 uChanged |= LVIF_TEXT;
1339 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1341 uChanged |= LVIF_TEXT;
1345 if (lpLVItem->pszText)
1347 if (lpItem->pszText)
1349 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1351 uChanged |= LVIF_TEXT;
1356 uChanged |= LVIF_TEXT;
1361 if (lpItem->pszText)
1363 uChanged |= LVIF_TEXT;
1375 * Initializes item attributes.
1378 * [I] HWND : window handle
1379 * [O] LISTVIEW_ITEM *: destination item
1380 * [I] LPLVITEM : source item
1386 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1389 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1390 BOOL bResult = FALSE;
1392 if ((lpItem != NULL) && (lpLVItem != NULL))
1396 if (lpLVItem->mask & LVIF_STATE)
1398 lpItem->state &= ~lpLVItem->stateMask;
1399 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1402 if (lpLVItem->mask & LVIF_IMAGE)
1404 lpItem->iImage = lpLVItem->iImage;
1407 if (lpLVItem->mask & LVIF_PARAM)
1409 lpItem->lParam = lpLVItem->lParam;
1412 if (lpLVItem->mask & LVIF_INDENT)
1414 lpItem->iIndent = lpLVItem->iIndent;
1417 if (lpLVItem->mask & LVIF_TEXT)
1419 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1421 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1426 if ((lpItem->pszText != NULL) &&
1427 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1429 COMCTL32_Free(lpItem->pszText);
1432 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1436 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1438 lpItem->pszText = NULL;
1441 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1451 * Initializes subitem attributes.
1453 * NOTE: The documentation specifies that the operation fails if the user
1454 * tries to set the indent of a subitem.
1457 * [I] HWND : window handle
1458 * [O] LISTVIEW_SUBITEM *: destination subitem
1459 * [I] LPLVITEM : source subitem
1465 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1468 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1469 BOOL bResult = FALSE;
1471 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1473 if (!(lpLVItem->mask & LVIF_INDENT))
1476 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1478 lpSubItem->iSubItem = lpLVItem->iSubItem;
1480 if (lpLVItem->mask & LVIF_IMAGE)
1482 lpSubItem->iImage = lpLVItem->iImage;
1485 if (lpLVItem->mask & LVIF_TEXT)
1487 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1489 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1494 if ((lpSubItem->pszText != NULL) &&
1495 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1497 COMCTL32_Free(lpSubItem->pszText);
1500 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1504 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1506 lpSubItem->pszText = NULL;
1509 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1520 * Adds a subitem at a given position (column index).
1523 * [I] HWND : window handle
1524 * [I] LPLVITEM : new subitem atttributes
1530 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1532 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1533 LISTVIEW_SUBITEM *lpSubItem = NULL;
1534 BOOL bResult = FALSE;
1536 INT nPosition, nItem;
1538 if (lpLVItem != NULL)
1540 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1541 if (hdpaSubItems != NULL)
1543 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1544 if (lpSubItem != NULL)
1546 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1548 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1549 lpSubItem->iSubItem);
1550 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1560 /* cleanup if unsuccessful */
1561 if ((bResult == FALSE) && (lpSubItem != NULL))
1563 COMCTL32_Free(lpSubItem);
1571 * Finds the dpa insert position (array index).
1574 * [I] HWND : window handle
1575 * [I] INT : subitem index
1581 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1583 LISTVIEW_SUBITEM *lpSubItem;
1586 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1588 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1589 if (lpSubItem != NULL)
1591 if (lpSubItem->iSubItem > nSubItem)
1598 return hdpaSubItems->nItemCount;
1603 * Retrieves a listview subitem at a given position (column index).
1606 * [I] HWND : window handle
1607 * [I] INT : subitem index
1613 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1615 LISTVIEW_SUBITEM *lpSubItem;
1618 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1620 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1621 if (lpSubItem != NULL)
1623 if (lpSubItem->iSubItem == nSubItem)
1627 else if (lpSubItem->iSubItem > nSubItem)
1639 * Sets item attributes.
1642 * [I] HWND : window handle
1643 * [I] LPLVITEM : new item atttributes
1649 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1651 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1652 BOOL bResult = FALSE;
1654 LISTVIEW_ITEM *lpItem;
1657 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1659 if (lpLVItem != NULL)
1661 if (lpLVItem->iSubItem == 0)
1663 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1664 if (hdpaSubItems != NULL)
1666 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1669 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1670 nmlv.hdr.hwndFrom = hwnd;
1671 nmlv.hdr.idFrom = lCtrlId;
1672 nmlv.hdr.code = LVN_ITEMCHANGING;
1673 nmlv.lParam = lpItem->lParam;
1674 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1677 if (uChanged & LVIF_STATE)
1679 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1680 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1683 nmlv.uChanged = uChanged;
1684 nmlv.iItem = lpLVItem->iItem;
1685 nmlv.lParam = lpItem->lParam;
1686 /* send LVN_ITEMCHANGING notification */
1687 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1689 /* copy information */
1690 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1692 /* send LVN_ITEMCHANGED notification */
1693 nmlv.hdr.code = LVN_ITEMCHANGED;
1694 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1701 InvalidateRect(hwnd, NULL, FALSE);
1712 * Sets subitem attributes.
1715 * [I] HWND : window handle
1716 * [I] LPLVITEM : new subitem atttributes
1722 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1724 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1725 BOOL bResult = FALSE;
1727 LISTVIEW_SUBITEM *lpSubItem;
1729 if (lpLVItem != NULL)
1731 if (lpLVItem->iSubItem > 0)
1733 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1734 if (hdpaSubItems != NULL)
1736 /* set subitem only if column is present */
1737 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1739 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1740 if (lpSubItem != NULL)
1742 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1746 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1749 InvalidateRect(hwnd, NULL, FALSE);
1760 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1763 * [I] HWND : window handle
1768 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1770 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1771 UINT uView = lStyle & LVS_TYPEMASK;
1773 SCROLLINFO scrollInfo;
1775 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1776 scrollInfo.cbSize = sizeof(SCROLLINFO);
1777 scrollInfo.fMask = SIF_POS;
1779 if (uView == LVS_LIST)
1781 if (lStyle & WS_HSCROLL)
1783 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1785 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1789 else if (uView == LVS_REPORT)
1791 if (lStyle & WS_VSCROLL)
1793 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1795 nItem = scrollInfo.nPos;
1808 * [I] HWND : window handle
1809 * [I] HDC : device context handle
1810 * [I] INT : item index
1811 * [I] INT : subitem index
1812 * [I] RECT * : clipping rectangle
1817 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1820 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1821 CHAR szDispText[DISP_TEXT_SIZE];
1824 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
1827 /* get information needed for drawing the item */
1828 ZeroMemory(&lvItem, sizeof(LVITEMA));
1829 lvItem.mask = LVIF_TEXT;
1830 lvItem.iItem = nItem;
1831 lvItem.iSubItem = nSubItem;
1832 lvItem.cchTextMax = DISP_TEXT_SIZE;
1833 lvItem.pszText = szDispText;
1834 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1836 /* set item colors */
1837 SetBkColor(hdc, infoPtr->clrTextBk);
1838 SetTextColor(hdc, infoPtr->clrText);
1840 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1841 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1850 * [I] HWND : window handle
1851 * [I] HDC : device context handle
1852 * [I] INT : item index
1853 * [I] RECT * : clipping rectangle
1858 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1860 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1861 CHAR szDispText[DISP_TEXT_SIZE];
1868 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
1870 /* get information needed for drawing the item */
1871 ZeroMemory(&lvItem, sizeof(LVITEMA));
1872 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1873 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1874 lvItem.iItem = nItem;
1875 lvItem.iSubItem = 0;
1876 lvItem.cchTextMax = DISP_TEXT_SIZE;
1877 lvItem.pszText = szDispText;
1878 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1881 if (infoPtr->himlState != NULL)
1883 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1884 if (uStateImage != 0)
1886 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1887 rcItem.top, ILD_NORMAL);
1890 rcItem.left += infoPtr->iconSize.cx;
1894 if (infoPtr->himlSmall != NULL)
1896 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1898 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1899 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1900 rcItem.top, ILD_SELECTED);
1904 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1905 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1906 rcItem.top, ILD_NORMAL);
1909 rcItem.left += infoPtr->iconSize.cx;
1912 /* Don't bother painting item being edited */
1913 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1916 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1918 /* set item colors */
1919 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1920 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1921 /* set raster mode */
1922 nMixMode = SetROP2(hdc, R2_XORPEN);
1924 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1925 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1927 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1928 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1929 /* set raster mode */
1930 nMixMode = SetROP2(hdc, R2_COPYPEN);
1934 /* set item colors */
1935 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1936 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1937 /* set raster mode */
1938 nMixMode = SetROP2(hdc, R2_COPYPEN);
1941 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1942 if (rcItem.left + nLabelWidth < rcItem.right)
1944 rcItem.right = rcItem.left + nLabelWidth;
1948 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1949 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1951 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1953 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1958 SetROP2(hdc, R2_COPYPEN);
1959 SetBkColor(hdc, infoPtr->clrTextBk);
1960 SetTextColor(hdc, infoPtr->clrText);
1966 * Draws an item when in large icon display mode.
1969 * [I] HWND : window handle
1970 * [I] HDC : device context handle
1971 * [I] LISTVIEW_ITEM * : item
1972 * [I] INT : item index
1973 * [I] RECT * : clipping rectangle
1978 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1980 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1981 CHAR szDispText[DISP_TEXT_SIZE];
1982 INT nDrawPosX = rcItem.left;
1987 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1988 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1991 /* get information needed for drawing the item */
1992 ZeroMemory(&lvItem, sizeof(LVITEMA));
1993 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1994 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1995 lvItem.iItem = nItem;
1996 lvItem.iSubItem = 0;
1997 lvItem.cchTextMax = DISP_TEXT_SIZE;
1998 lvItem.pszText = szDispText;
1999 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2001 if (lvItem.state & LVIS_SELECTED)
2003 /* set item colors */
2004 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2005 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2006 /* set raster mode */
2007 SetROP2(hdc, R2_XORPEN);
2011 /* set item colors */
2012 SetBkColor(hdc, infoPtr->clrTextBk);
2013 SetTextColor(hdc, infoPtr->clrText);
2014 /* set raster mode */
2015 SetROP2(hdc, R2_COPYPEN);
2018 if (infoPtr->himlNormal != NULL)
2020 rcItem.top += ICON_TOP_PADDING;
2021 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
2022 if (lvItem.state & LVIS_SELECTED)
2024 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2025 rcItem.top, ILD_SELECTED);
2029 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2030 rcItem.top, ILD_NORMAL);
2034 /* Don't bother painting item being edited */
2035 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
2038 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2039 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2040 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
2043 rcItem.left += nDrawPosX / 2;
2044 rcItem.right = rcItem.left + nLabelWidth;
2049 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
2053 GetTextMetricsA(hdc, &tm);
2054 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
2055 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2056 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2058 if (lvItem.state & LVIS_FOCUSED)
2060 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2066 * Draws listview items when in report display mode.
2069 * [I] HWND : window handle
2070 * [I] HDC : device context handle
2075 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2077 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2078 SCROLLINFO scrollInfo;
2079 INT nDrawPosY = infoPtr->rcList.top;
2086 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2087 scrollInfo.cbSize = sizeof(SCROLLINFO);
2088 scrollInfo.fMask = SIF_POS;
2090 nItem = ListView_GetTopIndex(hwnd);
2092 /* add 1 for displaying a partial item at the bottom */
2093 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2094 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2096 /* send cache hint notification */
2097 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
2101 nmlv.hdr.hwndFrom = hwnd;
2102 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
2103 nmlv.hdr.code = LVN_ODCACHEHINT;
2107 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
2111 for (; nItem < nLast; nItem++)
2113 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2114 for (j = 0; j < nColumnCount; j++)
2116 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2117 rcItem.left += REPORT_MARGINX;
2118 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2119 rcItem.top = nDrawPosY;
2120 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2122 /* Offset the Scroll Bar Pos */
2123 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2125 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2126 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2131 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2135 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2139 nDrawPosY += infoPtr->nItemHeight;
2145 * Retrieves the number of items that can fit vertically in the client area.
2148 * [I] HWND : window handle
2151 * Number of items per row.
2153 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2155 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2156 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2157 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2158 INT nCountPerRow = 1;
2162 if (uView == LVS_REPORT)
2168 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2169 if (nCountPerRow == 0)
2176 return nCountPerRow;
2181 * Retrieves the number of items that can fit horizontally in the client
2185 * [I] HWND : window handle
2188 * Number of items per column.
2190 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2192 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2193 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2194 INT nCountPerColumn = 1;
2196 if (nListHeight > 0)
2198 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2199 if (nCountPerColumn == 0)
2201 nCountPerColumn = 1;
2205 return nCountPerColumn;
2210 * Retrieves the number of columns needed to display all the items when in
2211 * list display mode.
2214 * [I] HWND : window handle
2217 * Number of columns.
2219 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2221 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2222 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2223 INT nColumnCount = 0;
2225 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2227 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2229 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2233 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2237 return nColumnCount;
2243 * Draws listview items when in list display mode.
2246 * [I] HWND : window handle
2247 * [I] HDC : device context handle
2252 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2254 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2259 INT nCountPerColumn;
2260 INT nItemWidth = infoPtr->nItemWidth;
2261 INT nItemHeight = infoPtr->nItemHeight;
2263 /* get number of fully visible columns */
2264 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2265 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2266 nItem = ListView_GetTopIndex(hwnd);
2268 for (i = 0; i < nColumnCount; i++)
2270 for (j = 0; j < nCountPerColumn; j++, nItem++)
2272 if (nItem >= GETITEMCOUNT(infoPtr))
2275 rcItem.top = j * nItemHeight;
2276 rcItem.left = i * nItemWidth;
2277 rcItem.bottom = rcItem.top + nItemHeight;
2278 rcItem.right = rcItem.left + nItemWidth;
2279 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2286 * Draws listview items when in icon or small icon display mode.
2289 * [I] HWND : window handle
2290 * [I] HDC : device context handle
2295 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2297 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2303 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2304 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2306 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2307 ptPosition.x += ptOrigin.x;
2308 ptPosition.y += ptOrigin.y;
2310 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2312 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2314 if (ptPosition.y < infoPtr->rcList.bottom)
2316 if (ptPosition.x < infoPtr->rcList.right)
2318 rcItem.top = ptPosition.y;
2319 rcItem.left = ptPosition.x;
2320 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2321 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2322 if (bSmall == FALSE)
2324 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2328 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2339 * Draws listview items.
2342 * [I] HWND : window handle
2343 * [I] HDC : device context handle
2348 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2350 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2351 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2356 hOldFont = SelectObject(hdc, infoPtr->hFont);
2358 /* select the doted pen (for drawing the focus box) */
2359 hPen = CreatePen(PS_DOT, 1, 0);
2360 hOldPen = SelectObject(hdc, hPen);
2362 /* select transparent brush (for drawing the focus box) */
2363 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2365 if (uView == LVS_LIST)
2367 LISTVIEW_RefreshList(hwnd, hdc);
2369 else if (uView == LVS_REPORT)
2371 LISTVIEW_RefreshReport(hwnd, hdc);
2373 else if (uView == LVS_SMALLICON)
2375 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2377 else if (uView == LVS_ICON)
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 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2409 INT nItemCountPerColumn = 1;
2410 INT nColumnCount = 0;
2411 DWORD dwViewRect = 0;
2413 if (nItemCount == -1)
2415 nItemCount = GETITEMCOUNT(infoPtr);
2418 if (uView == LVS_LIST)
2420 if (wHeight == 0xFFFF)
2422 /* use current height */
2423 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2426 if (wHeight < infoPtr->nItemHeight)
2428 wHeight = infoPtr->nItemHeight;
2433 if (infoPtr->nItemHeight > 0)
2435 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2436 if (nItemCountPerColumn == 0)
2438 nItemCountPerColumn = 1;
2441 if (nItemCount % nItemCountPerColumn != 0)
2443 nColumnCount = nItemCount / nItemCountPerColumn;
2447 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2452 /* Microsoft padding magic */
2453 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2454 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2456 dwViewRect = MAKELONG(wWidth, wHeight);
2458 else if (uView == LVS_REPORT)
2462 else if (uView == LVS_SMALLICON)
2466 else if (uView == LVS_ICON)
2476 * Arranges listview items in icon display mode.
2479 * [I] HWND : window handle
2480 * [I] INT : alignment code
2486 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2488 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2489 BOOL bResult = FALSE;
2491 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2504 case LVA_SNAPTOGRID:
2513 /* << LISTVIEW_CreateDragImage >> */
2517 * Removes all listview items and subitems.
2520 * [I] HWND : window handle
2526 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2528 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2529 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2530 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2531 UINT uView = lStyle & LVS_TYPEMASK;
2532 LISTVIEW_ITEM *lpItem;
2533 LISTVIEW_SUBITEM *lpSubItem;
2536 BOOL bResult = FALSE;
2541 TRACE("(hwnd=%x,)\n", hwnd);
2543 if (GETITEMCOUNT(infoPtr) > 0)
2545 /* initialize memory */
2546 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2548 /* send LVN_DELETEALLITEMS notification */
2549 nmlv.hdr.hwndFrom = hwnd;
2550 nmlv.hdr.idFrom = lCtrlId;
2551 nmlv.hdr.code = LVN_DELETEALLITEMS;
2554 /* verify if subsequent LVN_DELETEITEM notifications should be
2556 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2558 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2560 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2561 if (hdpaSubItems != NULL)
2563 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2565 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2566 if (lpSubItem != NULL)
2568 /* free subitem string */
2569 if ((lpSubItem->pszText != NULL) &&
2570 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2572 COMCTL32_Free(lpSubItem->pszText);
2576 COMCTL32_Free(lpSubItem);
2580 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2583 if (bSuppress == FALSE)
2585 /* send LVN_DELETEITEM notification */
2586 nmlv.hdr.code = LVN_DELETEITEM;
2588 nmlv.lParam = lpItem->lParam;
2589 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2592 /* free item string */
2593 if ((lpItem->pszText != NULL) &&
2594 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2596 COMCTL32_Free(lpItem->pszText);
2600 COMCTL32_Free(lpItem);
2603 DPA_Destroy(hdpaSubItems);
2607 /* reinitialize listview memory */
2608 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2610 /* align items (set position of each item) */
2611 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2613 if (lStyle & LVS_ALIGNLEFT)
2615 LISTVIEW_AlignLeft(hwnd);
2619 LISTVIEW_AlignTop(hwnd);
2623 LISTVIEW_UpdateScroll(hwnd);
2625 /* invalidate client area (optimization needed) */
2626 InvalidateRect(hwnd, NULL, TRUE);
2634 * Removes a column from the listview control.
2637 * [I] HWND : window handle
2638 * [I] INT : column index
2644 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2646 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2647 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2648 BOOL bResult = FALSE;
2650 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2652 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2654 /* Need to reset the item width when deleting a column */
2655 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2657 /* reset scroll parameters */
2658 if (uView == LVS_REPORT)
2660 /* update scrollbar(s) */
2661 LISTVIEW_UpdateScroll(hwnd);
2663 /* refresh client area */
2664 InvalidateRect(hwnd, NULL, FALSE);
2673 * Removes an item from the listview control.
2676 * [I] HWND : window handle
2677 * [I] INT : item index
2683 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2685 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2686 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2687 UINT uView = lStyle & LVS_TYPEMASK;
2688 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2690 BOOL bResult = FALSE;
2692 LISTVIEW_ITEM *lpItem;
2693 LISTVIEW_SUBITEM *lpSubItem;
2696 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2698 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2700 /* initialize memory */
2701 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2703 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2704 if (hdpaSubItems != NULL)
2706 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2708 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2709 if (lpSubItem != NULL)
2711 /* free item string */
2712 if ((lpSubItem->pszText != NULL) &&
2713 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2715 COMCTL32_Free(lpSubItem->pszText);
2719 COMCTL32_Free(lpSubItem);
2723 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2726 /* send LVN_DELETEITEM notification */
2727 nmlv.hdr.hwndFrom = hwnd;
2728 nmlv.hdr.idFrom = lCtrlId;
2729 nmlv.hdr.code = LVN_DELETEITEM;
2731 nmlv.lParam = lpItem->lParam;
2732 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2735 /* free item string */
2736 if ((lpItem->pszText != NULL) &&
2737 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2739 COMCTL32_Free(lpItem->pszText);
2743 COMCTL32_Free(lpItem);
2746 bResult = DPA_Destroy(hdpaSubItems);
2749 /* align items (set position of each item) */
2750 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2752 if (lStyle & LVS_ALIGNLEFT)
2754 LISTVIEW_AlignLeft(hwnd);
2758 LISTVIEW_AlignTop(hwnd);
2762 /* If this item had focus change focus to next or previous item */
2763 if (GETITEMCOUNT(infoPtr) > 0)
2765 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
2766 if (infoPtr->nFocusedItem == nItem)
2767 LISTVIEW_SetItemFocus(hwnd, sItem);
2770 infoPtr->nFocusedItem = -1;
2772 LISTVIEW_UpdateScroll(hwnd);
2774 /* refresh client area */
2775 InvalidateRect(hwnd, NULL, TRUE);
2784 * Return edit control handle of current edit label
2787 * [I] HWND : window handle
2793 static LRESULT LISTVIEW_GetEditControl(hwnd)
2795 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2796 return infoPtr->hwndEdit;
2802 * Callback implementation for editlabel control
2805 * [I] HWND : window handle
2806 * [I] LPSTR : modified text
2807 * [I] DWORD : item index
2814 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
2816 NMLVDISPINFOA dispInfo;
2817 LISTVIEW_ITEM *lpItem;
2818 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2819 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2821 BOOL bUpdateItemText;
2823 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2825 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2828 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2831 dispInfo.hdr.hwndFrom = hwnd;
2832 dispInfo.hdr.idFrom = nCtrlId;
2833 dispInfo.hdr.code = LVN_ENDLABELEDITA;
2834 dispInfo.item.mask = 0;
2835 dispInfo.item.iItem = nItem;
2836 dispInfo.item.state = lpItem->state;
2837 dispInfo.item.stateMask = 0;
2838 dispInfo.item.pszText = pszText;
2839 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
2840 dispInfo.item.iImage = lpItem->iImage;
2841 dispInfo.item.lParam = lpItem->lParam;
2842 infoPtr->hwndEdit = 0;
2844 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
2846 /* Do we need to update the Item Text */
2849 if(lpItem->pszText != LPSTR_TEXTCALLBACKA)
2851 Str_SetPtrA(&lpItem->pszText, pszText);
2860 * Begin in place editing of specified list view item
2863 * [I] HWND : window handle
2864 * [I] INT : item index
2871 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
2873 NMLVDISPINFOA dispInfo;
2875 LISTVIEW_ITEM *lpItem;
2877 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
2878 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2879 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2881 CHAR szDispText[DISP_TEXT_SIZE];
2884 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
2887 /* Is the EditBox still there, if so remove it */
2888 if(infoPtr->hwndEdit != 0)
2893 LISTVIEW_SetSelection(hwnd, nItem);
2894 LISTVIEW_SetItemFocus(hwnd, nItem);
2896 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2897 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2900 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2904 /* get information needed for drawing the item */
2905 ZeroMemory(&lvItem, sizeof(LVITEMA));
2906 lvItem.mask = LVIF_TEXT;
2907 lvItem.iItem = nItem;
2908 lvItem.iSubItem = 0;
2909 lvItem.cchTextMax = DISP_TEXT_SIZE;
2910 lvItem.pszText = szDispText;
2911 ListView_GetItemA(hwnd, &lvItem);
2913 dispInfo.hdr.hwndFrom = hwnd;
2914 dispInfo.hdr.idFrom = nCtrlId;
2915 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
2916 dispInfo.item.mask = 0;
2917 dispInfo.item.iItem = nItem;
2918 dispInfo.item.state = lpItem->state;
2919 dispInfo.item.stateMask = 0;
2920 dispInfo.item.pszText = lvItem.pszText;
2921 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
2922 dispInfo.item.iImage = lpItem->iImage;
2923 dispInfo.item.lParam = lpItem->lParam;
2925 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
2928 rect.left = LVIR_LABEL;
2929 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
2932 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
2933 rect.left-2, rect.top-1, 0,
2934 rect.bottom - rect.top+2,
2935 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
2938 infoPtr->hwndEdit = hedit;
2940 SendMessageA(hedit, EM_SETSEL, 0, -1);
2948 * Ensures the specified item is visible, scrolling into view if necessary.
2951 * [I] HWND : window handle
2952 * [I] INT : item index
2953 * [I] BOOL : partially or entirely visible
2959 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2961 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2962 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2963 INT nScrollPosHeight = 0;
2964 INT nScrollPosWidth = 0;
2965 SCROLLINFO scrollInfo;
2968 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2969 scrollInfo.cbSize = sizeof(SCROLLINFO);
2970 scrollInfo.fMask = SIF_POS;
2972 /* ALWAYS bPartial == FALSE, FOR NOW! */
2974 rcItem.left = LVIR_BOUNDS;
2975 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2977 if (rcItem.left < infoPtr->rcList.left)
2979 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2982 if (uView == LVS_LIST)
2984 nScrollPosWidth = infoPtr->nItemWidth;
2985 rcItem.left += infoPtr->rcList.left;
2987 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2989 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
2990 rcItem.left += infoPtr->rcList.left;
2993 /* When in LVS_REPORT view, the scroll position should
2995 if (nScrollPosWidth != 0)
2997 if (rcItem.left % nScrollPosWidth == 0)
2999 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
3003 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
3006 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3010 else if (rcItem.right > infoPtr->rcList.right)
3012 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3015 if (uView == LVS_LIST)
3017 rcItem.right -= infoPtr->rcList.right;
3018 nScrollPosWidth = infoPtr->nItemWidth;
3020 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3022 rcItem.right -= infoPtr->rcList.right;
3023 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
3026 /* When in LVS_REPORT view, the scroll position should
3028 if (nScrollPosWidth != 0)
3030 if (rcItem.right % nScrollPosWidth == 0)
3032 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
3036 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
3039 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3044 if (rcItem.top < infoPtr->rcList.top)
3047 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3049 if (uView == LVS_REPORT)
3051 rcItem.top -= infoPtr->rcList.top;
3052 nScrollPosHeight = infoPtr->nItemHeight;
3054 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3056 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3057 rcItem.top += infoPtr->rcList.top;
3060 if (rcItem.top % nScrollPosHeight == 0)
3062 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
3066 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
3069 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3072 else if (rcItem.bottom > infoPtr->rcList.bottom)
3075 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3077 if (uView == LVS_REPORT)
3079 rcItem.bottom -= infoPtr->rcList.bottom;
3080 nScrollPosHeight = infoPtr->nItemHeight;
3082 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3084 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3085 rcItem.bottom -= infoPtr->rcList.bottom;
3088 if (rcItem.bottom % nScrollPosHeight == 0)
3090 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
3094 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
3097 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3107 * Retrieves the nearest item, given a position and a direction.
3110 * [I] HWND : window handle
3111 * [I] POINT : start position
3112 * [I] UINT : direction
3115 * Item index if successdful, -1 otherwise.
3117 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3119 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3120 LVHITTESTINFO lvHitTestInfo;
3124 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3126 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3127 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3128 lvHitTestInfo.pt.x += pt.x;
3129 lvHitTestInfo.pt.y += pt.y;
3133 if (vkDirection == VK_DOWN)
3135 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3137 else if (vkDirection == VK_UP)
3139 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3141 else if (vkDirection == VK_LEFT)
3143 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3145 else if (vkDirection == VK_RIGHT)
3147 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3150 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3156 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3160 while (nItem == -1);
3168 * Searches for an item with specific characteristics.
3171 * [I] HWND : window handle
3172 * [I] INT : base item index
3173 * [I] LPLVFINDINFO : item information to look for
3176 * SUCCESS : index of item
3179 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3180 LPLVFINDINFO lpFindInfo)
3182 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3184 CHAR szDispText[DISP_TEXT_SIZE];
3188 INT nLast = GETITEMCOUNT(infoPtr);
3190 if ((nItem >= -1) && (lpFindInfo != NULL))
3192 ZeroMemory(&lvItem, sizeof(LVITEMA));
3194 if (lpFindInfo->flags & LVFI_PARAM)
3196 lvItem.mask |= LVIF_PARAM;
3199 if (lpFindInfo->flags & LVFI_STRING)
3201 lvItem.mask |= LVIF_TEXT;
3202 lvItem.pszText = szDispText;
3203 lvItem.cchTextMax = DISP_TEXT_SIZE;
3206 if (lpFindInfo->flags & LVFI_PARTIAL)
3208 lvItem.mask |= LVIF_TEXT;
3209 lvItem.pszText = szDispText;
3210 lvItem.cchTextMax = DISP_TEXT_SIZE;
3213 if (lpFindInfo->flags & LVFI_WRAP)
3218 if (lpFindInfo->flags & LVFI_NEARESTXY)
3220 ptItem.x = lpFindInfo->pt.x;
3221 ptItem.y = lpFindInfo->pt.y;
3226 while (nItem < nLast)
3228 if (lpFindInfo->flags & LVFI_NEARESTXY)
3230 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3231 lpFindInfo->vkDirection);
3234 /* get position of the new item index */
3235 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3246 lvItem.iItem = nItem;
3247 lvItem.iSubItem = 0;
3248 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
3250 if (lvItem.mask & LVIF_TEXT)
3252 if (lpFindInfo->flags & LVFI_PARTIAL)
3254 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3259 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3264 if (lvItem.mask & LVIF_PARAM)
3266 if (lpFindInfo->lParam != lvItem.lParam)
3292 * Retrieves the background color of the listview control.
3295 * [I] HWND : window handle
3298 * COLORREF associated with the background.
3300 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3302 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3304 return infoPtr->clrBk;
3309 * Retrieves the background image of the listview control.
3312 * [I] HWND : window handle
3313 * [O] LPLVMKBIMAGE : background image attributes
3319 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3321 /* FIXME (listview, "empty stub!\n"); */
3327 * Retrieves the callback mask.
3330 * [I] HWND : window handle
3335 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3337 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3339 return infoPtr->uCallbackMask;
3344 * Retrieves column attributes.
3347 * [I] HWND : window handle
3348 * [I] INT : column index
3349 * [IO] LPLVCOLUMNA : column information
3355 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3357 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3359 BOOL bResult = FALSE;
3361 if (lpColumn != NULL)
3363 /* initialize memory */
3364 ZeroMemory(&hdi, sizeof(HDITEMA));
3366 if (lpColumn->mask & LVCF_FMT)
3368 hdi.mask |= HDI_FORMAT;
3371 if (lpColumn->mask & LVCF_WIDTH)
3373 hdi.mask |= HDI_WIDTH;
3376 if (lpColumn->mask & LVCF_TEXT)
3378 hdi.mask |= HDI_TEXT;
3379 hdi.cchTextMax = lpColumn->cchTextMax;
3380 hdi.pszText = lpColumn->pszText;
3383 if (lpColumn->mask & LVCF_IMAGE)
3385 hdi.mask |= HDI_IMAGE;
3388 if (lpColumn->mask & LVCF_ORDER)
3390 hdi.mask |= HDI_ORDER;
3393 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3394 if (bResult != FALSE)
3396 if (lpColumn->mask & LVCF_FMT)
3400 if (hdi.fmt & HDF_LEFT)
3402 lpColumn->fmt |= LVCFMT_LEFT;
3404 else if (hdi.fmt & HDF_RIGHT)
3406 lpColumn->fmt |= LVCFMT_RIGHT;
3408 else if (hdi.fmt & HDF_CENTER)
3410 lpColumn->fmt |= LVCFMT_CENTER;
3413 if (hdi.fmt & HDF_IMAGE)
3415 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3418 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3420 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3424 if (lpColumn->mask & LVCF_WIDTH)
3426 lpColumn->cx = hdi.cxy;
3429 if (lpColumn->mask & LVCF_IMAGE)
3431 lpColumn->iImage = hdi.iImage;
3434 if (lpColumn->mask & LVCF_ORDER)
3436 lpColumn->iOrder = hdi.iOrder;
3444 /* LISTVIEW_GetColumnW */
3447 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
3449 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3456 for (i = 0; i < iCount; i++)
3464 * Retrieves the column width.
3467 * [I] HWND : window handle
3468 * [I] int : column index
3471 * SUCCESS : column width
3474 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3476 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3477 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3478 INT nColumnWidth = 0;
3481 if (uView == LVS_LIST)
3483 nColumnWidth = infoPtr->nItemWidth;
3485 else if (uView == LVS_REPORT)
3487 /* get column width from header */
3488 ZeroMemory(&hdi, sizeof(HDITEMA));
3489 hdi.mask = HDI_WIDTH;
3490 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3492 nColumnWidth = hdi.cxy;
3496 return nColumnWidth;
3501 * In list or report display mode, retrieves the number of items that can fit
3502 * vertically in the visible area. In icon or small icon display mode,
3503 * retrieves the total number of visible items.
3506 * [I] HWND : window handle
3509 * Number of fully visible items.
3511 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3513 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3514 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3517 if (uView == LVS_LIST)
3519 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3521 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3522 LISTVIEW_GetCountPerColumn(hwnd);
3525 else if (uView == LVS_REPORT)
3527 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3531 nItemCount = GETITEMCOUNT(infoPtr);
3537 /* LISTVIEW_GetEditControl */
3541 * Retrieves the extended listview style.
3544 * [I] HWND : window handle
3547 * SUCCESS : previous style
3550 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3552 LISTVIEW_INFO *infoPtr;
3554 /* make sure we can get the listview info */
3555 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3558 return (infoPtr->dwExStyle);
3563 * Retrieves the handle to the header control.
3566 * [I] HWND : window handle
3571 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3573 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3575 return infoPtr->hwndHeader;
3578 /* LISTVIEW_GetHotCursor */
3582 * Returns the time that the mouse cursor must hover over an item
3583 * before it is selected.
3586 * [I] HWND : window handle
3589 * Returns the previously set hover time or (DWORD)-1 to indicate that the
3590 * hover time is set to the default hover time.
3592 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
3594 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3596 return infoPtr->dwHoverTime;
3601 * Retrieves an image list handle.
3604 * [I] HWND : window handle
3605 * [I] INT : image list identifier
3608 * SUCCESS : image list handle
3611 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3613 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3614 HIMAGELIST himl = NULL;
3619 himl = infoPtr->himlNormal;
3622 himl = infoPtr->himlSmall;
3625 himl = infoPtr->himlState;
3629 return (LRESULT)himl;
3632 /* LISTVIEW_GetISearchString */
3636 * Retrieves item attributes.
3639 * [I] HWND : window handle
3640 * [IO] LPLVITEMA : item info
3641 * [I] internal : if true then we will use tricks that avoid copies
3642 * but are not compatible with the regular interface
3648 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
3650 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3651 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3652 NMLVDISPINFOA dispInfo;
3653 LISTVIEW_SUBITEM *lpSubItem;
3654 LISTVIEW_ITEM *lpItem;
3658 /* In the following:
3659 * lpLVItem describes the information requested by the user
3660 * lpItem/lpSubItem is what we have
3661 * dispInfo is a structure we use to request the missing
3662 * information from the application
3665 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3667 if ((lpLVItem == NULL) ||
3668 (lpLVItem->iItem < 0) ||
3669 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
3673 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3674 if (hdpaSubItems == NULL)
3677 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3681 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3682 if (lpLVItem->iSubItem == 0)
3684 piImage=&lpItem->iImage;
3685 ppszText=&lpItem->pszText;
3686 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3688 dispInfo.item.mask |= LVIF_STATE;
3689 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3694 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
3695 if (lpSubItem != NULL)
3697 piImage=&lpSubItem->iImage;
3698 ppszText=&lpSubItem->pszText;
3707 if ((lpLVItem->mask & LVIF_IMAGE) &&
3708 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
3710 dispInfo.item.mask |= LVIF_IMAGE;
3713 if ((lpLVItem->mask & LVIF_TEXT) &&
3714 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
3716 dispInfo.item.mask |= LVIF_TEXT;
3717 dispInfo.item.pszText = lpLVItem->pszText;
3718 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3721 if (dispInfo.item.mask != 0)
3723 /* We don't have all the requested info, query the application */
3724 dispInfo.hdr.hwndFrom = hwnd;
3725 dispInfo.hdr.idFrom = lCtrlId;
3726 dispInfo.hdr.code = LVN_GETDISPINFOA;
3727 dispInfo.item.iItem = lpLVItem->iItem;
3728 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3729 dispInfo.item.lParam = lpItem->lParam;
3730 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3733 if (dispInfo.item.mask & LVIF_IMAGE)
3735 lpLVItem->iImage = dispInfo.item.iImage;
3737 else if (lpLVItem->mask & LVIF_IMAGE)
3739 lpLVItem->iImage = *piImage;
3742 if (dispInfo.item.mask & LVIF_PARAM)
3744 lpLVItem->lParam = dispInfo.item.lParam;
3746 else if (lpLVItem->mask & LVIF_PARAM)
3748 lpLVItem->lParam = lpItem->lParam;
3751 if (dispInfo.item.mask & LVIF_TEXT)
3753 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
3755 Str_SetPtrA(ppszText, dispInfo.item.pszText);
3757 /* Here lpLVItem->pszText==dispInfo.item.pszText so a copy is unnecessary */
3759 else if (lpLVItem->mask & LVIF_TEXT)
3763 lpLVItem->pszText=*ppszText;
3765 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
3769 if (lpLVItem->iSubItem == 0)
3771 if (dispInfo.item.mask & LVIF_STATE)
3773 lpLVItem->state = lpItem->state;
3774 lpLVItem->state &= ~dispInfo.item.stateMask;
3775 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
3777 else if (lpLVItem->mask & LVIF_STATE)
3779 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3782 if (lpLVItem->mask & LVIF_PARAM)
3784 lpLVItem->lParam = lpItem->lParam;
3787 if (lpLVItem->mask & LVIF_INDENT)
3789 lpLVItem->iIndent = lpItem->iIndent;
3796 /* LISTVIEW_GetItemW */
3797 /* LISTVIEW_GetHotCursor */
3801 * Retrieves the index of the hot item.
3804 * [I] HWND : window handle
3807 * SUCCESS : hot item index
3808 * FAILURE : -1 (no hot item)
3810 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3812 LISTVIEW_INFO *infoPtr;
3814 /* make sure we can get the listview info */
3815 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3818 return (infoPtr->nHotItem);
3821 /* LISTVIEW_GetHoverTime */
3825 * Retrieves the number of items in the listview control.
3828 * [I] HWND : window handle
3833 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3835 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3837 return GETITEMCOUNT(infoPtr);
3842 * Retrieves the position (upper-left) of the listview control item.
3845 * [I] HWND : window handle
3846 * [I] INT : item index
3847 * [O] LPPOINT : coordinate information
3853 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3854 LPPOINT lpptPosition)
3856 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3857 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3858 BOOL bResult = FALSE;
3860 LISTVIEW_ITEM *lpItem;
3861 INT nCountPerColumn;
3864 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3867 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3868 (lpptPosition != NULL))
3870 if (uView == LVS_LIST)
3873 nItem = nItem - ListView_GetTopIndex(hwnd);
3874 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3877 nRow = nItem % nCountPerColumn;
3880 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3881 lpptPosition->y = 0;
3885 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3886 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3891 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3892 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3895 else if (uView == LVS_REPORT)
3898 lpptPosition->x = REPORT_MARGINX;
3899 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3900 infoPtr->nItemHeight) + infoPtr->rcList.top;
3904 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3905 if (hdpaSubItems != NULL)
3907 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3911 lpptPosition->x = lpItem->ptPosition.x;
3912 lpptPosition->y = lpItem->ptPosition.y;
3923 * Retrieves the bounding rectangle for a listview control item.
3926 * [I] HWND : window handle
3927 * [I] INT : item index
3928 * [IO] LPRECT : bounding rectangle coordinates
3934 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3936 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3937 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3938 BOOL bResult = FALSE;
3947 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3949 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3951 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3956 if (uView == LVS_ICON)
3958 if (infoPtr->himlNormal != NULL)
3960 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3963 lprc->left = ptItem.x + ptOrigin.x;
3964 lprc->top = ptItem.y + ptOrigin.y;
3965 lprc->right = lprc->left + infoPtr->iconSize.cx;
3966 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3967 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3971 else if (uView == LVS_SMALLICON)
3973 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3976 lprc->left = ptItem.x + ptOrigin.x;
3977 lprc->top = ptItem.y + ptOrigin.y;
3978 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3980 if (infoPtr->himlState != NULL)
3981 lprc->left += infoPtr->iconSize.cx;
3983 if (infoPtr->himlSmall != NULL)
3984 lprc->right = lprc->left + infoPtr->iconSize.cx;
3986 lprc->right = lprc->left;
3992 lprc->left = ptItem.x;
3993 lprc->top = ptItem.y;
3994 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3996 if (infoPtr->himlState != NULL)
3998 lprc->left += infoPtr->iconSize.cx;
4001 if (infoPtr->himlSmall != NULL)
4003 lprc->right = lprc->left + infoPtr->iconSize.cx;
4007 lprc->right = lprc->left;
4013 if (uView == LVS_ICON)
4015 if (infoPtr->himlNormal != NULL)
4017 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4020 lprc->left = ptItem.x + ptOrigin.x;
4021 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
4022 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
4023 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4024 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
4026 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
4027 lprc->right = lprc->left + nLabelWidth;
4032 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
4036 hOldFont = SelectObject(hdc, infoPtr->hFont);
4037 GetTextMetricsA(hdc, &tm);
4038 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
4039 SelectObject(hdc, hOldFont);
4040 ReleaseDC(hwnd, hdc);
4044 else if (uView == LVS_SMALLICON)
4046 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4049 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
4050 lprc->top = ptItem.y + ptOrigin.y;
4051 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4053 if (infoPtr->himlState != NULL)
4055 lprc->left += infoPtr->iconSize.cx;
4058 if (infoPtr->himlSmall != NULL)
4060 lprc->left += infoPtr->iconSize.cx;
4063 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4064 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4066 lprc->right = lprc->left + nLabelWidth;
4070 lprc->right = nLeftPos + infoPtr->nItemWidth;
4077 nLeftPos = lprc->left = ptItem.x;
4078 lprc->top = ptItem.y;
4079 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4081 if (infoPtr->himlState != NULL)
4083 lprc->left += infoPtr->iconSize.cx;
4086 if (infoPtr->himlSmall != NULL)
4088 lprc->left += infoPtr->iconSize.cx;
4091 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4092 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4094 lprc->right = lprc->left + nLabelWidth;
4098 lprc->right = nLeftPos + infoPtr->nItemWidth;
4104 if (uView == LVS_ICON)
4106 if (infoPtr->himlNormal != NULL)
4108 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4111 lprc->left = ptItem.x + ptOrigin.x;
4112 lprc->top = ptItem.y + ptOrigin.y;
4113 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4114 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4118 else if (uView == LVS_SMALLICON)
4120 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4123 lprc->left = ptItem.x + ptOrigin.x;
4124 lprc->right = lprc->left;
4125 lprc->top = ptItem.y + ptOrigin.y;
4126 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4127 if (infoPtr->himlState != NULL)
4128 lprc->right += infoPtr->iconSize.cx;
4129 if (infoPtr->himlSmall != NULL)
4130 lprc->right += infoPtr->iconSize.cx;
4132 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4133 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4135 lprc->right += nLabelWidth;
4139 lprc->right = lprc->left + infoPtr->nItemWidth;
4146 lprc->left = ptItem.x;
4147 lprc->right = lprc->left;
4148 lprc->top = ptItem.y;
4149 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4151 if (infoPtr->himlState != NULL)
4153 lprc->right += infoPtr->iconSize.cx;
4156 if (infoPtr->himlSmall != NULL)
4158 lprc->right += infoPtr->iconSize.cx;
4161 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4162 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4164 lprc->right += nLabelWidth;
4168 lprc->right = lprc->left + infoPtr->nItemWidth;
4173 case LVIR_SELECTBOUNDS:
4174 if (uView == LVS_ICON)
4176 if (infoPtr->himlNormal != NULL)
4178 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4181 lprc->left = ptItem.x + ptOrigin.x;
4182 lprc->top = ptItem.y + ptOrigin.y;
4183 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4184 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4188 else if (uView == LVS_SMALLICON)
4190 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4193 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4194 lprc->top = ptItem.y + ptOrigin.y;
4195 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4197 if (infoPtr->himlState != NULL)
4199 lprc->left += infoPtr->iconSize.cx;
4202 lprc->right = lprc->left;
4204 if (infoPtr->himlSmall != NULL)
4206 lprc->right += infoPtr->iconSize.cx;
4209 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4210 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4212 lprc->right += nLabelWidth;
4216 lprc->right = nLeftPos + infoPtr->nItemWidth;
4223 nLeftPos = lprc->left = ptItem.x;
4224 lprc->top = ptItem.y;
4225 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4227 if (infoPtr->himlState != NULL)
4229 lprc->left += infoPtr->iconSize.cx;
4232 lprc->right = lprc->left;
4234 if (infoPtr->himlSmall != NULL)
4236 lprc->right += infoPtr->iconSize.cx;
4239 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4240 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4242 lprc->right += nLabelWidth;
4246 lprc->right = nLeftPos + infoPtr->nItemWidth;
4259 * Retrieves the width of a label.
4262 * [I] HWND : window handle
4265 * SUCCESS : string width (in pixels)
4268 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4270 CHAR szDispText[DISP_TEXT_SIZE];
4271 INT nLabelWidth = 0;
4274 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4276 ZeroMemory(&lvItem, sizeof(LVITEMA));
4277 lvItem.mask = LVIF_TEXT;
4278 lvItem.iItem = nItem;
4279 lvItem.cchTextMax = DISP_TEXT_SIZE;
4280 lvItem.pszText = szDispText;
4281 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4283 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4291 * Retrieves the spacing between listview control items.
4294 * [I] HWND : window handle
4295 * [I] BOOL : flag for small or large icon
4298 * Horizontal + vertical spacing
4300 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4302 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4305 if (bSmall == FALSE)
4307 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4311 /* TODO: need to store width of smallicon item */
4312 lResult = MAKELONG(0, infoPtr->nItemHeight);
4320 * Retrieves the state of a listview control item.
4323 * [I] HWND : window handle
4324 * [I] INT : item index
4325 * [I] UINT : state mask
4328 * State specified by the mask.
4330 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4332 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4336 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4338 ZeroMemory(&lvItem, sizeof(LVITEMA));
4339 lvItem.iItem = nItem;
4340 lvItem.stateMask = uMask;
4341 lvItem.mask = LVIF_STATE;
4342 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4344 uState = lvItem.state;
4353 * Retrieves the text of a listview control item or subitem.
4356 * [I] HWND : window handle
4357 * [I] INT : item index
4358 * [IO] LPLVITEMA : item information
4361 * SUCCESS : string length
4364 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4366 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4369 if (lpLVItem != NULL)
4371 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4373 lpLVItem->mask = LVIF_TEXT;
4374 lpLVItem->iItem = nItem;
4375 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
4377 nLength = lstrlenA(lpLVItem->pszText);
4387 * Searches for an item based on properties + relationships.
4390 * [I] HWND : window handle
4391 * [I] INT : item index
4392 * [I] INT : relationship flag
4395 * SUCCESS : item index
4398 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4400 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4401 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4403 LVFINDINFO lvFindInfo;
4404 INT nCountPerColumn;
4407 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4409 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4411 if (uFlags & LVNI_CUT)
4414 if (uFlags & LVNI_DROPHILITED)
4415 uMask |= LVIS_DROPHILITED;
4417 if (uFlags & LVNI_FOCUSED)
4418 uMask |= LVIS_FOCUSED;
4420 if (uFlags & LVNI_SELECTED)
4421 uMask |= LVIS_SELECTED;
4423 if (uFlags & LVNI_ABOVE)
4425 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4430 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4436 lvFindInfo.flags = LVFI_NEARESTXY;
4437 lvFindInfo.vkDirection = VK_UP;
4438 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4439 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4441 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4446 else if (uFlags & LVNI_BELOW)
4448 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4450 while (nItem < GETITEMCOUNT(infoPtr))
4453 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4459 lvFindInfo.flags = LVFI_NEARESTXY;
4460 lvFindInfo.vkDirection = VK_DOWN;
4461 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4462 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4464 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4469 else if (uFlags & LVNI_TOLEFT)
4471 if (uView == LVS_LIST)
4473 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4474 while (nItem - nCountPerColumn >= 0)
4476 nItem -= nCountPerColumn;
4477 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4481 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4483 lvFindInfo.flags = LVFI_NEARESTXY;
4484 lvFindInfo.vkDirection = VK_LEFT;
4485 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4486 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4488 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4493 else if (uFlags & LVNI_TORIGHT)
4495 if (uView == LVS_LIST)
4497 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4498 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4500 nItem += nCountPerColumn;
4501 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4505 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4507 lvFindInfo.flags = LVFI_NEARESTXY;
4508 lvFindInfo.vkDirection = VK_RIGHT;
4509 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4510 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4512 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4521 /* search by index */
4522 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4524 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4533 /* LISTVIEW_GetNumberOfWorkAreas */
4537 * Retrieves the origin coordinates when in icon or small icon display mode.
4540 * [I] HWND : window handle
4541 * [O] LPPOINT : coordinate information
4547 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4549 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4550 UINT uView = lStyle & LVS_TYPEMASK;
4551 BOOL bResult = FALSE;
4553 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4555 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4557 SCROLLINFO scrollInfo;
4558 ZeroMemory(lpptOrigin, sizeof(POINT));
4559 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4560 scrollInfo.cbSize = sizeof(SCROLLINFO);
4562 if (lStyle & WS_HSCROLL)
4564 scrollInfo.fMask = SIF_POS;
4565 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4567 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4571 if (lStyle & WS_VSCROLL)
4573 scrollInfo.fMask = SIF_POS;
4574 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4576 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4588 * Retrieves the number of items that are marked as selected.
4591 * [I] HWND : window handle
4594 * Number of items selected.
4596 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4598 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4599 INT nSelectedCount = 0;
4602 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4604 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4610 return nSelectedCount;
4615 * Retrieves item index that marks the start of a multiple selection.
4618 * [I] HWND : window handle
4621 * Index number or -1 if there is no selection mark.
4623 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4625 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4627 return infoPtr->nSelectionMark;
4632 * Retrieves the width of a string.
4635 * [I] HWND : window handle
4638 * SUCCESS : string width (in pixels)
4641 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4643 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4644 HFONT hFont, hOldFont;
4648 ZeroMemory(&stringSize, sizeof(SIZE));
4649 if (lpszText != NULL)
4651 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4653 hOldFont = SelectObject(hdc, hFont);
4654 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4655 SelectObject(hdc, hOldFont);
4656 ReleaseDC(hwnd, hdc);
4659 return stringSize.cx;
4664 * Retrieves the text backgound color.
4667 * [I] HWND : window handle
4670 * COLORREF associated with the the background.
4672 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4674 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4676 return infoPtr->clrTextBk;
4681 * Retrieves the text color.
4684 * [I] HWND : window handle
4687 * COLORREF associated with the text.
4689 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4691 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4693 return infoPtr->clrText;
4698 * Determines which section of the item was selected (if any).
4701 * [I] HWND : window handle
4702 * [IO] LPLVHITTESTINFO : hit test information
4705 * SUCCESS : item index
4708 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4710 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4714 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4715 lpHitTestInfo->pt.y);
4717 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4719 rcItem.left = LVIR_BOUNDS;
4720 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4722 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4724 rcItem.left = LVIR_ICON;
4725 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4727 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4729 lpHitTestInfo->flags = LVHT_ONITEMICON;
4730 lpHitTestInfo->iItem = i;
4731 lpHitTestInfo->iSubItem = 0;
4736 rcItem.left = LVIR_LABEL;
4737 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4739 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4741 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4742 lpHitTestInfo->iItem = i;
4743 lpHitTestInfo->iSubItem = 0;
4748 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4749 lpHitTestInfo->iItem = i;
4750 lpHitTestInfo->iSubItem = 0;
4756 lpHitTestInfo->flags = LVHT_NOWHERE;
4763 * Determines which listview item is located at the specified position.
4766 * [I] HWND : window handle
4767 * [IO} LPLVHITTESTINFO : hit test information
4770 * SUCCESS : item index
4773 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4775 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4778 lpHitTestInfo->flags = 0;
4780 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4782 lpHitTestInfo->flags = LVHT_TOLEFT;
4784 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4786 lpHitTestInfo->flags = LVHT_TORIGHT;
4788 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4790 lpHitTestInfo->flags |= LVHT_ABOVE;
4792 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4794 lpHitTestInfo->flags |= LVHT_BELOW;
4797 if (lpHitTestInfo->flags == 0)
4799 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4807 * Inserts a new column.
4810 * [I] HWND : window handle
4811 * [I] INT : column index
4812 * [I] LPLVCOLUMNA : column information
4815 * SUCCESS : new column index
4818 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4819 LPLVCOLUMNA lpColumn)
4821 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4823 INT nNewColumn = -1;
4825 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4828 if (lpColumn != NULL)
4830 /* initialize memory */
4831 ZeroMemory(&hdi, sizeof(HDITEMA));
4833 if (lpColumn->mask & LVCF_FMT)
4835 /* format member is valid */
4836 hdi.mask |= HDI_FORMAT;
4838 /* set text alignment (leftmost column must be left-aligned) */
4841 hdi.fmt |= HDF_LEFT;
4845 if (lpColumn->fmt & LVCFMT_LEFT)
4847 hdi.fmt |= HDF_LEFT;
4849 else if (lpColumn->fmt & LVCFMT_RIGHT)
4851 hdi.fmt |= HDF_RIGHT;
4853 else if (lpColumn->fmt & LVCFMT_CENTER)
4855 hdi.fmt |= HDF_CENTER;
4859 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4861 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4865 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4870 if (lpColumn->fmt & LVCFMT_IMAGE)
4872 hdi.fmt |= HDF_IMAGE;
4873 hdi.iImage = I_IMAGECALLBACK;
4877 if (lpColumn->mask & LVCF_WIDTH)
4879 hdi.mask |= HDI_WIDTH;
4880 hdi.cxy = lpColumn->cx;
4883 if (lpColumn->mask & LVCF_TEXT)
4885 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4886 hdi.pszText = lpColumn->pszText;
4887 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4888 hdi.fmt |= HDF_STRING;
4891 if (lpColumn->mask & LVCF_IMAGE)
4893 hdi.mask |= HDI_IMAGE;
4894 hdi.iImage = lpColumn->iImage;
4897 if (lpColumn->mask & LVCF_ORDER)
4899 hdi.mask |= HDI_ORDER;
4900 hdi.iOrder = lpColumn->iOrder;
4903 /* insert item in header control */
4904 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4905 (WPARAM)nColumn, (LPARAM)&hdi);
4907 /* Need to reset the item width when inserting a new column */
4908 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4910 LISTVIEW_UpdateScroll(hwnd);
4911 InvalidateRect(hwnd, NULL, FALSE);
4917 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4918 LPLVCOLUMNW lpColumn)
4923 memcpy(&lvca,lpColumn,sizeof(lvca));
4924 if (lpColumn->mask & LVCF_TEXT)
4925 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4926 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4927 if (lpColumn->mask & LVCF_TEXT)
4928 HeapFree(GetProcessHeap(),0,lvca.pszText);
4932 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
4933 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
4934 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
4935 and not during the processing of a LVM_SORTITEMS message. Applications should provide
4936 their own sort proc. when sending LVM_SORTITEMS.
4939 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
4941 LVS_SORTXXX must be specified,
4942 LVS_OWNERDRAW is not set,
4943 <item>.pszText is not LPSTR_TEXTCALLBACK.
4945 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
4946 are sorted based on item text..."
4948 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
4950 HDPA hdpa_first = (HDPA) first;
4951 HDPA hdpa_second = (HDPA) second;
4952 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
4953 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
4954 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
4955 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
4956 /* if we're sorting descending, negate the return value */
4957 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
4962 * Inserts a new item in the listview control.
4965 * [I] HWND : window handle
4966 * [I] LPLVITEMA : item information
4969 * SUCCESS : new item index
4972 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4974 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4975 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4976 UINT uView = lStyle & LVS_TYPEMASK;
4977 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4982 LISTVIEW_ITEM *lpItem = NULL;
4984 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4986 if (lpLVItem != NULL)
4988 /* make sure it's not a subitem; cannot insert a subitem */
4989 if (lpLVItem->iSubItem == 0)
4991 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4994 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4995 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4997 /* insert item in listview control data structure */
4998 hdpaSubItems = DPA_Create(8);
4999 if (hdpaSubItems != NULL)
5001 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
5004 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
5005 && !(lStyle & LVS_OWNERDRAWFIXED)
5006 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
5008 /* Insert the item in the proper sort order based on the pszText
5009 member. See comments for LISTVIEW_InsertCompare() for greater detail */
5010 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
5011 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
5012 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
5013 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
5017 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
5022 /* manage item focus */
5023 if (lpLVItem->mask & LVIF_STATE)
5025 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
5026 if (lpLVItem->stateMask & LVIS_SELECTED)
5028 LISTVIEW_SetSelection(hwnd, nItem);
5030 else if (lpLVItem->stateMask & LVIS_FOCUSED)
5032 LISTVIEW_SetItemFocus(hwnd, nItem);
5036 /* send LVN_INSERTITEM notification */
5037 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
5038 nmlv.hdr.hwndFrom = hwnd;
5039 nmlv.hdr.idFrom = lCtrlId;
5040 nmlv.hdr.code = LVN_INSERTITEM;
5042 nmlv.lParam = lpItem->lParam;;
5043 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
5045 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
5047 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
5048 if (nItemWidth > infoPtr->nItemWidth)
5050 infoPtr->nItemWidth = nItemWidth;
5054 /* align items (set position of each item) */
5055 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5057 if (lStyle & LVS_ALIGNLEFT)
5059 LISTVIEW_AlignLeft(hwnd);
5063 LISTVIEW_AlignTop(hwnd);
5067 LISTVIEW_UpdateScroll(hwnd);
5068 /* refresh client area */
5069 InvalidateRect(hwnd, NULL, FALSE);
5078 /* free memory if unsuccessful */
5079 if ((nItem == -1) && (lpItem != NULL))
5081 COMCTL32_Free(lpItem);
5087 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
5091 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
5092 if (lvia.mask & LVIF_TEXT) {
5093 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
5094 lvia.pszText = LPSTR_TEXTCALLBACKA;
5096 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
5098 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
5099 if (lvia.mask & LVIF_TEXT) {
5100 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
5101 HeapFree(GetProcessHeap(),0,lvia.pszText);
5106 /* LISTVIEW_InsertItemW */
5110 * Redraws a range of items.
5113 * [I] HWND : window handle
5114 * [I] INT : first item
5115 * [I] INT : last item
5121 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
5123 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5124 BOOL bResult = FALSE;
5127 if (nFirst <= nLast)
5129 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
5131 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
5134 InvalidateRect(hwnd, &rc, FALSE);
5142 /* LISTVIEW_Scroll */
5146 * Sets the background color.
5149 * [I] HWND : window handle
5150 * [I] COLORREF : background color
5156 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
5158 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5160 infoPtr->clrBk = clrBk;
5161 InvalidateRect(hwnd, NULL, TRUE);
5166 /* LISTVIEW_SetBkImage */
5170 * Sets the callback mask. This mask will be used when the parent
5171 * window stores state information (some or all).
5174 * [I] HWND : window handle
5175 * [I] UINT : state mask
5181 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5183 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5185 infoPtr->uCallbackMask = uMask;
5192 * Sets the attributes of a header item.
5195 * [I] HWND : window handle
5196 * [I] INT : column index
5197 * [I] LPLVCOLUMNA : column attributes
5203 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5204 LPLVCOLUMNA lpColumn)
5206 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5207 BOOL bResult = FALSE;
5208 HDITEMA hdi, hdiget;
5210 if ((lpColumn != NULL) && (nColumn >= 0) &&
5211 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5213 /* initialize memory */
5214 ZeroMemory(&hdi, sizeof(HDITEMA));
5216 if (lpColumn->mask & LVCF_FMT)
5218 /* format member is valid */
5219 hdi.mask |= HDI_FORMAT;
5221 /* get current format first */
5222 hdiget.mask = HDI_FORMAT;
5223 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5224 /* preserve HDF_STRING if present */
5225 hdi.fmt = hdiget.fmt & HDF_STRING;
5227 /* set text alignment (leftmost column must be left-aligned) */
5230 hdi.fmt |= HDF_LEFT;
5234 if (lpColumn->fmt & LVCFMT_LEFT)
5236 hdi.fmt |= HDF_LEFT;
5238 else if (lpColumn->fmt & LVCFMT_RIGHT)
5240 hdi.fmt |= HDF_RIGHT;
5242 else if (lpColumn->fmt & LVCFMT_CENTER)
5244 hdi.fmt |= HDF_CENTER;
5248 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5250 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5253 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5255 hdi.fmt |= HDF_IMAGE;
5258 if (lpColumn->fmt & LVCFMT_IMAGE)
5260 hdi.fmt |= HDF_IMAGE;
5261 hdi.iImage = I_IMAGECALLBACK;
5265 if (lpColumn->mask & LVCF_WIDTH)
5267 hdi.mask |= HDI_WIDTH;
5268 hdi.cxy = lpColumn->cx;
5271 if (lpColumn->mask & LVCF_TEXT)
5273 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5274 hdi.pszText = lpColumn->pszText;
5275 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5276 hdi.fmt |= HDF_STRING;
5279 if (lpColumn->mask & LVCF_IMAGE)
5281 hdi.mask |= HDI_IMAGE;
5282 hdi.iImage = lpColumn->iImage;
5285 if (lpColumn->mask & LVCF_ORDER)
5287 hdi.mask |= HDI_ORDER;
5288 hdi.iOrder = lpColumn->iOrder;
5291 /* set header item attributes */
5292 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5298 /* LISTVIEW_SetColumnW */
5302 * Sets the column order array
5305 * [I] HWND : window handle
5306 * [I] INT : number of elements in column order array
5307 * [I] INT : pointer to column order array
5313 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
5315 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
5317 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
5328 * Sets the width of a column
5331 * [I] HWND : window handle
5332 * [I] INT : column index
5333 * [I] INT : column width
5339 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5341 LISTVIEW_INFO *infoPtr;
5346 /* set column width only if in report mode */
5347 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5348 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
5351 /* make sure we can get the listview info */
5352 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5354 if (!infoPtr->hwndHeader) /* make sure we have a header */
5357 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5358 * LVSCV_AUTOSIZE_USEHEADER (-2)
5363 hdi.mask = HDI_WIDTH;
5366 /* call header to update the column change */
5367 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5369 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5371 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5378 * Sets the extended listview style.
5381 * [I] HWND : window handle
5386 * SUCCESS : previous style
5389 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5391 LISTVIEW_INFO *infoPtr;
5394 /* make sure we can get the listview info */
5395 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5398 /* store previous style */
5399 dwOldStyle = infoPtr->dwExStyle;
5402 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5404 return (dwOldStyle);
5407 /* LISTVIEW_SetHotCursor */
5411 * Sets the hot item index.
5414 * [I] HWND : window handle
5418 * SUCCESS : previous hot item index
5419 * FAILURE : -1 (no hot item)
5421 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5423 LISTVIEW_INFO *infoPtr;
5426 /* make sure we can get the listview info */
5427 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5430 /* store previous index */
5431 iOldIndex = infoPtr->nHotItem;
5434 infoPtr->nHotItem = iIndex;
5441 * Sets the amount of time the cursor must hover over an item before it is selected.
5444 * [I] HWND : window handle
5445 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
5448 * Returns the previous hover time
5450 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
5452 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5453 DWORD oldHoverTime = infoPtr->dwHoverTime;
5455 infoPtr->dwHoverTime = dwHoverTime;
5457 return oldHoverTime;
5460 /* LISTVIEW_SetIconSpacing */
5467 * [I] HWND : window handle
5468 * [I] INT : image list type
5469 * [I] HIMAGELIST : image list handle
5472 * SUCCESS : old image list
5475 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5477 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5478 HIMAGELIST himlTemp = 0;
5483 himlTemp = infoPtr->himlNormal;
5484 infoPtr->himlNormal = himl;
5485 return (LRESULT)himlTemp;
5488 himlTemp = infoPtr->himlSmall;
5489 infoPtr->himlSmall = himl;
5490 return (LRESULT)himlTemp;
5493 himlTemp = infoPtr->himlState;
5494 infoPtr->himlState = himl;
5495 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5496 return (LRESULT)himlTemp;
5499 return (LRESULT)NULL;
5505 * Sets the attributes of an item.
5508 * [I] HWND : window handle
5509 * [I] LPLVITEM : item information
5515 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5517 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5518 BOOL bResult = FALSE;
5520 if (lpLVItem != NULL)
5522 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5524 if (lpLVItem->iSubItem == 0)
5526 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5530 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5539 /* LISTVIEW_SetItemW */
5543 * Preallocates memory.
5546 * [I] HWND : window handle
5547 * [I] INT : item count (projected number of items)
5548 * [I] DWORD : update flags
5554 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5556 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5557 LISTVIEW_ITEM *lpItem = NULL;
5559 FIXME("(%d %08lx)stub!\n", nItems, dwFlags);
5562 return LISTVIEW_DeleteAllItems (hwnd);
5564 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
5566 FIXME("LVS_OWNERDATA is set!\n");
5570 if (nItems > GETITEMCOUNT(infoPtr))
5573 FIXME("append items\n");
5576 else if (nItems < GETITEMCOUNT(infoPtr))
5579 while(nItems < GETITEMCOUNT(infoPtr)) {
5580 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
5590 * Sets the position of an item.
5593 * [I] HWND : window handle
5594 * [I] INT : item index
5595 * [I] INT : x coordinate
5596 * [I] INT : y coordinate
5602 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5603 INT nPosX, INT nPosY)
5605 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5606 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5607 LISTVIEW_ITEM *lpItem;
5609 BOOL bResult = FALSE;
5611 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5613 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5615 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5617 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5618 if (hdpaSubItems != NULL)
5620 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5624 lpItem->ptPosition.x = nPosX;
5625 lpItem->ptPosition.y = nPosY;
5634 /* LISTVIEW_SetItemPosition32 */
5638 * Sets the state of one or many items.
5641 * [I] HWND : window handle
5642 * [I]INT : item index
5643 * [I] LPLVITEM : item or subitem info
5649 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5651 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5652 BOOL bResult = FALSE;
5659 ZeroMemory(&lvItem, sizeof(LVITEMA));
5660 lvItem.mask = LVIF_STATE;
5661 lvItem.state = lpLVItem->state;
5662 lvItem.stateMask = lpLVItem->stateMask ;
5664 /* apply to all items */
5665 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5668 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5676 ZeroMemory(&lvItem, sizeof(LVITEMA));
5677 lvItem.mask = LVIF_STATE;
5678 lvItem.state = lpLVItem->state;
5679 lvItem.stateMask = lpLVItem->stateMask;
5680 lvItem.iItem = nItem;
5681 bResult = ListView_SetItemA(hwnd, &lvItem);
5689 * Sets the text of an item or subitem.
5692 * [I] HWND : window handle
5693 * [I] INT : item index
5694 * [I] LPLVITEMA : item or subitem info
5700 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5702 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5703 BOOL bResult = FALSE;
5706 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5708 ZeroMemory(&lvItem, sizeof(LVITEMA));
5709 lvItem.mask = LVIF_TEXT;
5710 lvItem.pszText = lpLVItem->pszText;
5711 lvItem.iItem = nItem;
5712 lvItem.iSubItem = lpLVItem->iSubItem;
5713 bResult = ListView_SetItemA(hwnd, &lvItem);
5719 /* LISTVIEW_SetItemTextW */
5723 * Set item index that marks the start of a multiple selection.
5726 * [I] HWND : window handle
5730 * Index number or -1 if there is no selection mark.
5732 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5734 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5735 INT nOldIndex = infoPtr->nSelectionMark;
5737 infoPtr->nSelectionMark = nIndex;
5744 * Sets the text background color.
5747 * [I] HWND : window handle
5748 * [I] COLORREF : text background color
5754 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5756 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5758 infoPtr->clrTextBk = clrTextBk;
5759 InvalidateRect(hwnd, NULL, TRUE);
5766 * Sets the text foreground color.
5769 * [I] HWND : window handle
5770 * [I] COLORREF : text color
5776 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5778 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5780 infoPtr->clrText = clrText;
5781 InvalidateRect(hwnd, NULL, TRUE);
5786 /* LISTVIEW_SetToolTips */
5787 /* LISTVIEW_SetUnicodeFormat */
5788 /* LISTVIEW_SetWorkAreas */
5792 * Callback internally used by LISTVIEW_SortItems()
5795 * [I] LPVOID : first LISTVIEW_ITEM to compare
5796 * [I] LPVOID : second LISTVIEW_ITEM to compare
5797 * [I] LPARAM : HWND of control
5800 * if first comes before second : negative
5801 * if first comes after second : positive
5802 * if first and second are equivalent : zero
5804 static INT WINAPI LISTVIEW_CallBackCompare(
5809 /* Forward the call to the client defined callback */
5811 HWND hwnd = (HWND)lParam;
5812 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5814 rv = (infoPtr->pfnCompare)( ((LISTVIEW_ITEM*) first)->lParam,
5815 ((LISTVIEW_ITEM*) second)->lParam, infoPtr->lParamSort );
5822 * Sorts the listview items.
5825 * [I] HWND : window handle
5826 * [I] WPARAM : application-defined value
5827 * [I] LPARAM : pointer to comparision callback
5833 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5835 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5837 LISTVIEW_ITEM *lpItem;
5841 if (!infoPtr || !infoPtr->hdpaItems)
5844 nCount = GETITEMCOUNT(infoPtr);
5845 /* if there are 0 or 1 items, there is no need to sort */
5848 sortList = DPA_Create(nCount);
5850 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5851 infoPtr->lParamSort = (LPARAM)wParam;
5853 /* append pointers one by one to sortList */
5854 for (i = 0; i < nCount; i++)
5856 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5857 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5858 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5861 /* sort the sortList */
5862 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5864 /* copy the pointers back */
5865 for (i = 0; i < nCount; i++)
5867 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5868 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5869 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5872 DPA_Destroy(sortList);
5878 /* LISTVIEW_SubItemHitTest */
5882 * Updates an items or rearranges the listview control.
5885 * [I] HWND : window handle
5886 * [I] INT : item index
5892 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5894 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5895 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5896 BOOL bResult = FALSE;
5899 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5903 /* rearrange with default alignment style */
5904 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5905 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5907 ListView_Arrange(hwnd, 0);
5911 /* get item bounding rectangle */
5912 rc.left = LVIR_BOUNDS;
5913 ListView_GetItemRect(hwnd, nItem, &rc);
5914 InvalidateRect(hwnd, &rc, TRUE);
5923 * Creates the listview control.
5926 * [I] HWND : window handle
5931 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5933 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5934 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5935 UINT uView = lpcs->style & LVS_TYPEMASK;
5938 /* initialize info pointer */
5939 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5941 /* determine the type of structures to use */
5942 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5943 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5944 if (infoPtr->notifyFormat != NFR_ANSI)
5946 FIXME("ANSI notify format is NOT used\n");
5949 /* initialize color information */
5950 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5951 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5952 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5954 /* set default values */
5955 infoPtr->uCallbackMask = 0;
5956 infoPtr->nFocusedItem = -1;
5957 infoPtr->nSelectionMark = -1;
5958 infoPtr->nHotItem = -1;
5959 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5960 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5961 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5962 infoPtr->hwndEdit = 0;
5963 infoPtr->pedititem = NULL;
5964 infoPtr->bDoEditLabel = FALSE;
5966 /* get default font (icon title) */
5967 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5968 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5969 infoPtr->hFont = infoPtr->hDefaultFont;
5972 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5973 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5974 0, 0, 0, 0, hwnd, (HMENU)0,
5975 lpcs->hInstance, NULL);
5977 /* set header font */
5978 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5981 if (uView == LVS_ICON)
5983 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5984 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5986 else if (uView == LVS_REPORT)
5988 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5990 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5993 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5994 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5998 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5999 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6002 /* display unsupported listview window styles */
6003 LISTVIEW_UnsupportedStyles(lpcs->style);
6005 /* allocate memory for the data structure */
6006 infoPtr->hdpaItems = DPA_Create(10);
6008 /* initialize size of items */
6009 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6010 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6012 /* initialize the hover time to -1(indicating the default system hover time) */
6013 infoPtr->dwHoverTime = -1;
6020 * Erases the background of the listview control.
6023 * [I] HWND : window handle
6024 * [I] WPARAM : device context handle
6025 * [I] LPARAM : not used
6031 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
6034 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6037 if (infoPtr->clrBk == CLR_NONE)
6039 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
6044 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
6045 GetClientRect(hwnd, &rc);
6046 FillRect((HDC)wParam, &rc, hBrush);
6047 DeleteObject(hBrush);
6056 * Retrieves the listview control font.
6059 * [I] HWND : window handle
6064 static LRESULT LISTVIEW_GetFont(HWND hwnd)
6066 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6068 return infoPtr->hFont;
6073 * Performs vertical scrolling.
6076 * [I] HWND : window handle
6077 * [I] INT : scroll code
6078 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6080 * [I] HWND : scrollbar control window handle
6085 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6088 SCROLLINFO scrollInfo;
6090 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6091 scrollInfo.cbSize = sizeof(SCROLLINFO);
6092 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6094 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6096 INT nOldScrollPos = scrollInfo.nPos;
6097 switch (nScrollCode)
6100 if (scrollInfo.nPos > scrollInfo.nMin)
6107 if (scrollInfo.nPos < scrollInfo.nMax)
6114 if (scrollInfo.nPos > scrollInfo.nMin)
6116 if (scrollInfo.nPos >= scrollInfo.nPage)
6118 scrollInfo.nPos -= scrollInfo.nPage;
6122 scrollInfo.nPos = scrollInfo.nMin;
6128 if (scrollInfo.nPos < scrollInfo.nMax)
6130 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6132 scrollInfo.nPos += scrollInfo.nPage;
6136 scrollInfo.nPos = scrollInfo.nMax;
6142 scrollInfo.nPos = nCurrentPos;
6143 if (scrollInfo.nPos > scrollInfo.nMax)
6144 scrollInfo.nPos=scrollInfo.nMax;
6146 if (scrollInfo.nPos < scrollInfo.nMin)
6147 scrollInfo.nPos=scrollInfo.nMin;
6152 if (nOldScrollPos != scrollInfo.nPos)
6154 scrollInfo.fMask = SIF_POS;
6155 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
6156 InvalidateRect(hwnd, NULL, TRUE);
6165 * Performs horizontal scrolling.
6168 * [I] HWND : window handle
6169 * [I] INT : scroll code
6170 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6172 * [I] HWND : scrollbar control window handle
6177 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6180 SCROLLINFO scrollInfo;
6182 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6183 scrollInfo.cbSize = sizeof(SCROLLINFO);
6184 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6186 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6188 INT nOldScrollPos = scrollInfo.nPos;
6190 switch (nScrollCode)
6193 if (scrollInfo.nPos > scrollInfo.nMin)
6200 if (scrollInfo.nPos < scrollInfo.nMax)
6207 if (scrollInfo.nPos > scrollInfo.nMin)
6209 if (scrollInfo.nPos >= scrollInfo.nPage)
6211 scrollInfo.nPos -= scrollInfo.nPage;
6215 scrollInfo.nPos = scrollInfo.nMin;
6221 if (scrollInfo.nPos < scrollInfo.nMax)
6223 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6225 scrollInfo.nPos += scrollInfo.nPage;
6229 scrollInfo.nPos = scrollInfo.nMax;
6235 scrollInfo.nPos = nCurrentPos;
6237 if (scrollInfo.nPos > scrollInfo.nMax)
6238 scrollInfo.nPos=scrollInfo.nMax;
6240 if (scrollInfo.nPos < scrollInfo.nMin)
6241 scrollInfo.nPos=scrollInfo.nMin;
6245 if (nOldScrollPos != scrollInfo.nPos)
6247 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6248 scrollInfo.fMask = SIF_POS;
6249 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6250 if(uView == LVS_REPORT)
6252 scrollInfo.fMask = SIF_POS;
6253 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6254 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6256 InvalidateRect(hwnd, NULL, TRUE);
6263 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
6265 INT gcWheelDelta = 0;
6266 UINT pulScrollLines = 3;
6267 SCROLLINFO scrollInfo;
6269 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6271 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
6272 gcWheelDelta -= wheelDelta;
6274 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6275 scrollInfo.cbSize = sizeof(SCROLLINFO);
6276 scrollInfo.fMask = SIF_POS | SIF_RANGE;
6283 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
6284 * should be fixed in the future.
6286 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6287 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
6291 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
6293 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6295 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
6296 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
6297 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
6303 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
6314 * [I] HWND : window handle
6315 * [I] INT : virtual key
6316 * [I] LONG : key data
6321 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6323 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6324 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6325 HWND hwndParent = GetParent(hwnd);
6326 NMLVKEYDOWN nmKeyDown;
6329 BOOL bRedraw = FALSE;
6331 /* send LVN_KEYDOWN notification */
6332 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6333 nmKeyDown.hdr.hwndFrom = hwnd;
6334 nmKeyDown.hdr.idFrom = nCtrlId;
6335 nmKeyDown.hdr.code = LVN_KEYDOWN;
6336 nmKeyDown.wVKey = nVirtualKey;
6337 nmKeyDown.flags = 0;
6338 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6341 nmh.hwndFrom = hwnd;
6342 nmh.idFrom = nCtrlId;
6344 switch (nVirtualKey)
6347 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6349 /* send NM_RETURN notification */
6350 nmh.code = NM_RETURN;
6351 ListView_Notify(hwndParent, nCtrlId, &nmh);
6353 /* send LVN_ITEMACTIVATE notification */
6354 nmh.code = LVN_ITEMACTIVATE;
6355 ListView_Notify(hwndParent, nCtrlId, &nmh);
6360 if (GETITEMCOUNT(infoPtr) > 0)
6367 if (GETITEMCOUNT(infoPtr) > 0)
6369 nItem = GETITEMCOUNT(infoPtr) - 1;
6374 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6378 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6382 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6386 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6398 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6400 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6401 if (bRedraw != FALSE)
6403 /* refresh client area */
6404 InvalidateRect(hwnd, NULL, TRUE);
6417 * [I] HWND : window handle
6422 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6424 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6425 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6428 TRACE("(hwnd=%x)\n", hwnd);
6430 /* send NM_KILLFOCUS notification */
6431 nmh.hwndFrom = hwnd;
6432 nmh.idFrom = nCtrlId;
6433 nmh.code = NM_KILLFOCUS;
6434 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6436 /* set window focus flag */
6437 infoPtr->bFocus = FALSE;
6439 /* NEED drawing optimization ; redraw the selected items */
6440 InvalidateRect(hwnd, NULL, FALSE);
6447 * Processes double click messages (left mouse button).
6450 * [I] HWND : window handle
6451 * [I] WORD : key flag
6452 * [I] WORD : x coordinate
6453 * [I] WORD : y coordinate
6458 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6461 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6463 LVHITTESTINFO htInfo;
6465 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6467 /* send NM_DBLCLK notification */
6468 nmh.hwndFrom = hwnd;
6469 nmh.idFrom = nCtrlId;
6470 nmh.code = NM_DBLCLK;
6471 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6473 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
6474 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6475 htInfo.pt.x = wPosX;
6476 htInfo.pt.y = wPosY;
6477 if(LISTVIEW_HitTest(hwnd, &htInfo) != -1)
6479 /* send LVN_ITEMACTIVATE notification */
6480 nmh.code = LVN_ITEMACTIVATE;
6481 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6489 * Processes mouse down messages (left mouse button).
6492 * [I] HWND : window handle
6493 * [I] WORD : key flag
6494 * [I] WORD : x coordinate
6495 * [I] WORD : y coordinate
6500 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6503 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6504 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6505 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6506 static BOOL bGroupSelect = TRUE;
6511 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6514 /* send NM_RELEASEDCAPTURE notification */
6515 nmh.hwndFrom = hwnd;
6516 nmh.idFrom = nCtrlId;
6517 nmh.code = NM_RELEASEDCAPTURE;
6518 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6520 if (infoPtr->bFocus == FALSE)
6525 /* set left button down flag */
6526 infoPtr->bLButtonDown = TRUE;
6528 ptPosition.x = wPosX;
6529 ptPosition.y = wPosY;
6530 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6531 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6533 if (lStyle & LVS_SINGLESEL)
6535 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
6536 && infoPtr->bDoEditLabel != TRUE)
6538 infoPtr->bDoEditLabel = TRUE;
6542 LISTVIEW_SetSelection(hwnd, nItem);
6547 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6549 if (bGroupSelect != FALSE)
6551 LISTVIEW_AddGroupSelection(hwnd, nItem);
6555 LISTVIEW_AddSelection(hwnd, nItem);
6558 else if (wKey & MK_CONTROL)
6560 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6562 else if (wKey & MK_SHIFT)
6564 LISTVIEW_SetGroupSelection(hwnd, nItem);
6568 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED
6569 && infoPtr->bDoEditLabel != TRUE)
6571 infoPtr->bDoEditLabel = TRUE;
6575 LISTVIEW_SetSelection(hwnd, nItem);
6583 /* remove all selections */
6584 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6587 InvalidateRect(hwnd, NULL, TRUE);
6594 * Processes mouse up messages (left mouse button).
6597 * [I] HWND : window handle
6598 * [I] WORD : key flag
6599 * [I] WORD : x coordinate
6600 * [I] WORD : y coordinate
6605 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6608 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6610 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6612 if (infoPtr->bLButtonDown != FALSE)
6614 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6617 /* send NM_CLICK notification */
6618 nmh.hwndFrom = hwnd;
6619 nmh.idFrom = nCtrlId;
6620 nmh.code = NM_CLICK;
6621 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6623 /* set left button flag */
6624 infoPtr->bLButtonDown = FALSE;
6626 if(infoPtr->bDoEditLabel)
6628 LVHITTESTINFO htInfo;
6630 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6631 htInfo.pt.x = wPosX;
6632 htInfo.pt.y = wPosY;
6633 nItem = LISTVIEW_HitTest(hwnd, &htInfo);
6634 if(nItem != -1 && htInfo.flags == LVHT_ONITEMLABEL)
6636 LISTVIEW_EditLabelA(hwnd, nItem);
6638 infoPtr->bDoEditLabel = FALSE;
6647 * Creates the listview control (called before WM_CREATE).
6650 * [I] HWND : window handle
6651 * [I] WPARAM : unhandled
6652 * [I] LPARAM : widow creation info
6657 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6659 LISTVIEW_INFO *infoPtr;
6661 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6663 /* allocate memory for info structure */
6664 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6665 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6666 if (infoPtr == NULL)
6668 ERR("could not allocate info memory!\n");
6672 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6674 ERR("pointer assignment error!\n");
6678 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6683 * Destroys the listview control (called after WM_DESTROY).
6686 * [I] HWND : window handle
6691 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6693 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6695 TRACE("(hwnd=%x)\n", hwnd);
6697 /* delete all items */
6698 LISTVIEW_DeleteAllItems(hwnd);
6700 /* destroy data structure */
6701 DPA_Destroy(infoPtr->hdpaItems);
6704 infoPtr->hFont = (HFONT)0;
6705 if (infoPtr->hDefaultFont)
6707 DeleteObject(infoPtr->hDefaultFont);
6710 /* free listview info pointer*/
6711 COMCTL32_Free(infoPtr);
6718 * Handles notifications from children.
6721 * [I] HWND : window handle
6722 * [I] INT : control identifier
6723 * [I] LPNMHDR : notification information
6728 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6730 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6732 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6734 /* handle notification from header control */
6735 if (lpnmh->code == HDN_ENDTRACKA)
6737 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6738 InvalidateRect(hwnd, NULL, TRUE);
6740 else if(lpnmh->code == HDN_ITEMCLICKA)
6742 /* Handle sorting by Header Column */
6744 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6745 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6747 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6748 nmlv.hdr.hwndFrom = hwnd;
6749 nmlv.hdr.idFrom = lCtrlId;
6750 nmlv.hdr.code = LVN_COLUMNCLICK;
6752 nmlv.iSubItem = pnmHeader->iItem;
6754 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6757 else if(lpnmh->code == NM_RELEASEDCAPTURE)
6759 /* Idealy this should be done in HDN_ENDTRACKA
6760 * but since SetItemBounds in Header.c is called after
6761 * the notification is sent, it is neccessary to handle the
6762 * update of the scroll bar here (Header.c works fine as it is,
6763 * no need to disturb it)
6765 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6766 LISTVIEW_UpdateScroll(hwnd);
6767 InvalidateRect(hwnd, NULL, TRUE);
6777 * Determines the type of structure to use.
6780 * [I] HWND : window handle of the sender
6781 * [I] HWND : listview window handle
6782 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6787 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6789 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6791 if (nCommand == NF_REQUERY)
6793 /* determine the type of structure to use */
6794 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6795 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6796 if (infoPtr->notifyFormat == NFR_UNICODE)
6798 FIXME("NO support for unicode structures");
6807 * Paints/Repaints the listview control.
6810 * [I] HWND : window handle
6811 * [I] HDC : device context handle
6816 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6820 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6824 hdc = BeginPaint(hwnd, &ps);
6825 LISTVIEW_Refresh(hwnd, hdc);
6826 EndPaint(hwnd, &ps);
6830 LISTVIEW_Refresh(hwnd, hdc);
6838 * Processes double click messages (right mouse button).
6841 * [I] HWND : window handle
6842 * [I] WORD : key flag
6843 * [I] WORD : x coordinate
6844 * [I] WORD : y coordinate
6849 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6852 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6855 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6857 /* send NM_RELEASEDCAPTURE notification */
6858 nmh.hwndFrom = hwnd;
6859 nmh.idFrom = nCtrlId;
6860 nmh.code = NM_RELEASEDCAPTURE;
6861 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6863 /* send NM_RDBLCLK notification */
6864 nmh.code = NM_RDBLCLK;
6865 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6872 * Processes mouse down messages (right mouse button).
6875 * [I] HWND : window handle
6876 * [I] WORD : key flag
6877 * [I] WORD : x coordinate
6878 * [I] WORD : y coordinate
6883 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6886 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6887 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6892 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6894 /* send NM_RELEASEDCAPTURE notification */
6895 nmh.hwndFrom = hwnd;
6896 nmh.idFrom = nCtrlId;
6897 nmh.code = NM_RELEASEDCAPTURE;
6898 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6900 /* make sure the listview control window has the focus */
6901 if (infoPtr->bFocus == FALSE)
6906 /* set right button down flag */
6907 infoPtr->bRButtonDown = TRUE;
6909 /* determine the index of the selected item */
6910 ptPosition.x = wPosX;
6911 ptPosition.y = wPosY;
6912 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6913 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6915 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6917 LISTVIEW_SetSelection(hwnd, nItem);
6922 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6930 * Processes mouse up messages (right mouse button).
6933 * [I] HWND : window handle
6934 * [I] WORD : key flag
6935 * [I] WORD : x coordinate
6936 * [I] WORD : y coordinate
6941 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6944 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6945 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6948 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6950 if (infoPtr->bRButtonDown != FALSE)
6956 /* Send NM_RClICK notification */
6957 ZeroMemory(&nmh, sizeof(NMHDR));
6958 nmh.hwndFrom = hwnd;
6959 nmh.idFrom = nCtrlId;
6960 nmh.code = NM_RCLICK;
6961 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6963 /* set button flag */
6964 infoPtr->bRButtonDown = FALSE;
6966 /* Change to screen coordinate for WM_CONTEXTMENU */
6967 ClientToScreen(hwnd, &pt);
6969 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
6970 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
6981 * [I] HWND : window handle
6982 * [I] HWND : window handle of previously focused window
6987 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6989 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6990 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6993 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
6995 /* send NM_SETFOCUS notification */
6996 nmh.hwndFrom = hwnd;
6997 nmh.idFrom = nCtrlId;
6998 nmh.code = NM_SETFOCUS;
6999 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7001 /* set window focus flag */
7002 infoPtr->bFocus = TRUE;
7004 InvalidateRect(hwnd, NULL, TRUE);
7015 * [I] HWND : window handle
7016 * [I] HFONT : font handle
7017 * [I] WORD : redraw flag
7022 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
7024 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7025 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7027 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
7031 infoPtr->hFont = infoPtr->hDefaultFont;
7035 infoPtr->hFont = hFont;
7038 if (uView == LVS_REPORT)
7040 /* set header font */
7041 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
7042 MAKELPARAM(fRedraw, 0));
7045 /* invalidate listview control client area */
7046 InvalidateRect(hwnd, NULL, TRUE);
7048 if (fRedraw != FALSE)
7058 * Message handling for WM_SETREDRAW.
7059 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
7062 * [I] HWND : window handle
7063 * [I] bRedraw: state of redraw flag
7066 * DefWinProc return value
7068 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
7071 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
7074 RedrawWindow(hwnd, NULL, 0,
7075 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
7082 * Resizes the listview control. This function processes WM_SIZE
7083 * messages. At this time, the width and height are not used.
7086 * [I] HWND : window handle
7087 * [I] WORD : new width
7088 * [I] WORD : new height
7093 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
7095 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7096 UINT uView = lStyle & LVS_TYPEMASK;
7098 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
7100 LISTVIEW_UpdateSize(hwnd);
7102 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
7104 if (lStyle & LVS_ALIGNLEFT)
7106 LISTVIEW_AlignLeft(hwnd);
7110 LISTVIEW_AlignTop(hwnd);
7114 LISTVIEW_UpdateScroll(hwnd);
7116 /* invalidate client area + erase background */
7117 InvalidateRect(hwnd, NULL, TRUE);
7124 * Sets the size information.
7127 * [I] HWND : window handle
7132 static VOID LISTVIEW_UpdateSize(HWND hwnd)
7134 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7135 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7136 UINT uView = lStyle & LVS_TYPEMASK;
7139 GetClientRect(hwnd, &rcList);
7140 infoPtr->rcList.left = 0;
7141 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
7142 infoPtr->rcList.top = 0;
7143 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
7145 if (uView == LVS_LIST)
7147 if ((lStyle & WS_HSCROLL) == 0)
7149 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
7150 if (infoPtr->rcList.bottom > nHScrollHeight)
7152 infoPtr->rcList.bottom -= nHScrollHeight;
7156 else if (uView == LVS_REPORT)
7163 Header_Layout(infoPtr->hwndHeader, &hl);
7164 if (!(LVS_NOCOLUMNHEADER & lStyle))
7166 infoPtr->rcList.top = max(wp.cy, 0);
7173 * Processes WM_STYLECHANGED messages.
7176 * [I] HWND : window handle
7177 * [I] WPARAM : window style type (normal or extended)
7178 * [I] LPSTYLESTRUCT : window style information
7183 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
7186 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7187 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
7188 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
7189 RECT rcList = infoPtr->rcList;
7191 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
7192 hwnd, wStyleType, lpss);
7194 if (wStyleType == GWL_STYLE)
7196 if (uOldView == LVS_REPORT)
7198 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
7201 if ((lpss->styleOld & WS_HSCROLL) != 0)
7203 ShowScrollBar(hwnd, SB_HORZ, FALSE);
7206 if ((lpss->styleOld & WS_VSCROLL) != 0)
7208 ShowScrollBar(hwnd, SB_VERT, FALSE);
7211 if (uNewView == LVS_ICON)
7213 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7214 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7215 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7216 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7217 if (lpss->styleNew & LVS_ALIGNLEFT)
7219 LISTVIEW_AlignLeft(hwnd);
7223 LISTVIEW_AlignTop(hwnd);
7226 else if (uNewView == LVS_REPORT)
7233 Header_Layout(infoPtr->hwndHeader, &hl);
7234 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
7236 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
7238 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7240 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7241 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7242 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7243 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7245 else if (uNewView == LVS_LIST)
7247 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7248 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7249 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7250 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7254 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7255 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7256 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7257 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7258 if (lpss->styleNew & LVS_ALIGNLEFT)
7260 LISTVIEW_AlignLeft(hwnd);
7264 LISTVIEW_AlignTop(hwnd);
7268 /* update the size of the client area */
7269 LISTVIEW_UpdateSize(hwnd);
7271 /* add scrollbars if needed */
7272 LISTVIEW_UpdateScroll(hwnd);
7274 /* invalidate client area + erase background */
7275 InvalidateRect(hwnd, NULL, TRUE);
7277 /* print the list of unsupported window styles */
7278 LISTVIEW_UnsupportedStyles(lpss->styleNew);
7281 /* If they change the view and we have an active edit control
7282 we will need to kill the control since the redraw will
7283 misplace the edit control.
7285 if (infoPtr->hwndEdit &&
7286 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
7287 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
7289 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7297 * Window procedure of the listview control.
7300 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
7305 case LVM_APPROXIMATEVIEWRECT:
7306 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
7307 LOWORD(lParam), HIWORD(lParam));
7309 return LISTVIEW_Arrange(hwnd, (INT)wParam);
7311 /* case LVM_CREATEDRAGIMAGE: */
7313 case LVM_DELETEALLITEMS:
7314 return LISTVIEW_DeleteAllItems(hwnd);
7316 case LVM_DELETECOLUMN:
7317 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
7319 case LVM_DELETEITEM:
7320 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
7322 case LVM_EDITLABELW:
7323 case LVM_EDITLABELA:
7324 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
7326 case LVM_ENSUREVISIBLE:
7327 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
7330 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
7332 case LVM_GETBKCOLOR:
7333 return LISTVIEW_GetBkColor(hwnd);
7335 /* case LVM_GETBKIMAGE: */
7337 case LVM_GETCALLBACKMASK:
7338 return LISTVIEW_GetCallbackMask(hwnd);
7340 case LVM_GETCOLUMNA:
7341 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7343 /* case LVM_GETCOLUMNW: */
7345 case LVM_GETCOLUMNORDERARRAY:
7346 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7348 case LVM_GETCOLUMNWIDTH:
7349 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
7351 case LVM_GETCOUNTPERPAGE:
7352 return LISTVIEW_GetCountPerPage(hwnd);
7354 case LVM_GETEDITCONTROL:
7355 return LISTVIEW_GetEditControl(hwnd);
7357 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7358 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7361 return LISTVIEW_GetHeader(hwnd);
7363 /* case LVM_GETHOTCURSOR: */
7365 case LVM_GETHOTITEM:
7366 return LISTVIEW_GetHotItem(hwnd);
7368 case LVM_GETHOVERTIME:
7369 return LISTVIEW_GetHoverTime(hwnd);
7371 case LVM_GETIMAGELIST:
7372 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7374 /* case LVM_GETISEARCHSTRING: */
7377 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
7379 /* case LVM_GETITEMW: */
7381 case LVM_GETITEMCOUNT:
7382 return LISTVIEW_GetItemCount(hwnd);
7384 case LVM_GETITEMPOSITION:
7385 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7387 case LVM_GETITEMRECT:
7388 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7390 case LVM_GETITEMSPACING:
7391 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7393 case LVM_GETITEMSTATE:
7394 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7396 case LVM_GETITEMTEXTA:
7397 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7400 /* case LVM_GETITEMTEXTW: */
7402 case LVM_GETNEXTITEM:
7403 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7405 /* case LVM_GETNUMBEROFWORKAREAS: */
7408 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7410 case LVM_GETSELECTEDCOUNT:
7411 return LISTVIEW_GetSelectedCount(hwnd);
7413 case LVM_GETSELECTIONMARK:
7414 return LISTVIEW_GetSelectionMark(hwnd);
7416 case LVM_GETSTRINGWIDTHA:
7417 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7419 /* case LVM_GETSTRINGWIDTHW: */
7420 /* case LVM_GETSUBITEMRECT: */
7422 case LVM_GETTEXTBKCOLOR:
7423 return LISTVIEW_GetTextBkColor(hwnd);
7425 case LVM_GETTEXTCOLOR:
7426 return LISTVIEW_GetTextColor(hwnd);
7428 /* case LVM_GETTOOLTIPS: */
7430 case LVM_GETTOPINDEX:
7431 return LISTVIEW_GetTopIndex(hwnd);
7433 /* case LVM_GETUNICODEFORMAT: */
7435 case LVM_GETVIEWRECT:
7436 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7438 /* case LVM_GETWORKAREAS: */
7441 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7443 case LVM_INSERTCOLUMNA:
7444 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7446 case LVM_INSERTCOLUMNW:
7447 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7449 case LVM_INSERTITEMA:
7450 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7452 case LVM_INSERTITEMW:
7453 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7455 case LVM_REDRAWITEMS:
7456 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7458 /* case LVM_SCROLL: */
7459 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7461 case LVM_SETBKCOLOR:
7462 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7464 /* case LVM_SETBKIMAGE: */
7466 case LVM_SETCALLBACKMASK:
7467 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7469 case LVM_SETCOLUMNA:
7470 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7472 case LVM_SETCOLUMNW:
7473 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7476 case LVM_SETCOLUMNORDERARRAY:
7477 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7479 case LVM_SETCOLUMNWIDTH:
7480 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
7482 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7483 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7485 /* case LVM_SETHOTCURSOR: */
7487 case LVM_SETHOTITEM:
7488 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7490 case LVM_SETHOVERTIME:
7491 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
7493 /* case LVM_SETICONSPACING: */
7495 case LVM_SETIMAGELIST:
7496 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7499 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7501 /* case LVM_SETITEMW: */
7503 case LVM_SETITEMCOUNT:
7504 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7506 case LVM_SETITEMPOSITION:
7507 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7508 (INT)HIWORD(lParam));
7510 /* case LVM_SETITEMPOSITION32: */
7512 case LVM_SETITEMSTATE:
7513 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7515 case LVM_SETITEMTEXTA:
7516 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7518 /* case LVM_SETITEMTEXTW: */
7520 case LVM_SETSELECTIONMARK:
7521 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7523 case LVM_SETTEXTBKCOLOR:
7524 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7526 case LVM_SETTEXTCOLOR:
7527 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7529 /* case LVM_SETTOOLTIPS: */
7530 /* case LVM_SETUNICODEFORMAT: */
7531 /* case LVM_SETWORKAREAS: */
7534 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7536 /* case LVM_SUBITEMHITTEST: */
7539 return LISTVIEW_Update(hwnd, (INT)wParam);
7543 return LISTVIEW_Command(hwnd, wParam, lParam);
7546 return LISTVIEW_Create(hwnd, wParam, lParam);
7549 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7552 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7555 return LISTVIEW_GetFont(hwnd);
7558 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7559 (INT)HIWORD(wParam), (HWND)lParam);
7562 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7565 return LISTVIEW_KillFocus(hwnd);
7567 case WM_LBUTTONDBLCLK:
7568 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7571 case WM_LBUTTONDOWN:
7572 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7575 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7578 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
7581 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
7584 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7587 return LISTVIEW_NCDestroy(hwnd);
7590 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7592 case WM_NOTIFYFORMAT:
7593 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7596 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7598 case WM_RBUTTONDBLCLK:
7599 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7602 case WM_RBUTTONDOWN:
7603 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7607 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7611 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7614 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7617 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
7620 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7622 case WM_STYLECHANGED:
7623 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7625 /* case WM_TIMER: */
7628 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7629 (INT)HIWORD(wParam), (HWND)lParam);
7632 if (wParam & (MK_SHIFT | MK_CONTROL))
7633 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
7634 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
7636 /* case WM_WININICHANGE: */
7639 if (uMsg >= WM_USER)
7641 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7645 /* call default window procedure */
7646 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7654 * Registers the window class.
7662 VOID LISTVIEW_Register(void)
7666 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7667 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7668 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7669 wndClass.cbClsExtra = 0;
7670 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7671 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7672 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7673 wndClass.lpszClassName = WC_LISTVIEWA;
7674 RegisterClassA(&wndClass);
7679 * Unregisters the window class.
7687 VOID LISTVIEW_Unregister(void)
7689 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
7694 * Handle any WM_COMMAND messages
7700 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
7702 switch (HIWORD(wParam))
7707 * Adjust the edit window size
7710 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7711 HDC hdc = GetDC(infoPtr->hwndEdit);
7712 HFONT hFont, hOldFont = 0;
7717 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
7718 GetWindowRect(infoPtr->hwndEdit, &rect);
7720 /* Select font to get the right dimension of the string */
7721 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
7724 hOldFont = SelectObject(hdc, hFont);
7727 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
7729 TEXTMETRICA textMetric;
7731 /* Add Extra spacing for the next character */
7732 GetTextMetricsA(hdc, &textMetric);
7733 sz.cx += (textMetric.tmMaxCharWidth * 2);
7741 rect.bottom - rect.top,
7742 SWP_DRAWFRAME|SWP_NOMOVE);
7746 SelectObject(hdc, hOldFont);
7749 ReleaseDC(hwnd, hdc);
7755 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
7764 * Subclassed edit control windproc function
7770 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
7771 WPARAM wParam, LPARAM lParam)
7773 BOOL cancel = FALSE;
7774 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
7775 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
7776 static BOOL bIgnoreKillFocus = FALSE;
7780 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
7783 if(bIgnoreKillFocus)
7791 WNDPROC editProc = einfo->EditWndProc;
7792 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
7793 COMCTL32_Free(einfo);
7794 infoPtr->pedititem = NULL;
7795 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
7799 if (VK_ESCAPE == (INT)wParam)
7805 else if (VK_RETURN == (INT)wParam)
7809 return CallWindowProcA(einfo->EditWndProc, hwnd,
7810 uMsg, wParam, lParam);
7813 if (einfo->EditLblCb)
7815 char *buffer = NULL;
7820 int len = 1 + GetWindowTextLengthA(hwnd);
7824 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
7826 GetWindowTextA(hwnd, buffer, len);
7830 /* Processing LVN_ENDLABELEDIT message could kill the focus */
7831 /* eg. Using a messagebox */
7832 bIgnoreKillFocus = TRUE;
7833 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
7836 COMCTL32_Free(buffer);
7838 einfo->EditLblCb = NULL;
7839 bIgnoreKillFocus = FALSE;
7842 SendMessageA(hwnd, WM_CLOSE, 0, 0);
7849 * Creates a subclassed edit cotrol
7855 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
7856 INT width, INT height, HWND parent, HINSTANCE hinst,
7857 EditlblCallback EditLblCb, DWORD param)
7863 TEXTMETRICA textMetric;
7864 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
7866 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
7869 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
7870 hdc = GetDC(parent);
7872 /* Select the font to get appropriate metric dimensions */
7873 if(infoPtr->hFont != 0)
7875 hOldFont = SelectObject(hdc, infoPtr->hFont);
7878 /*Get String Lenght in pixels */
7879 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
7881 /*Add Extra spacing for the next character */
7882 GetTextMetricsA(hdc, &textMetric);
7883 sz.cx += (textMetric.tmMaxCharWidth * 2);
7885 if(infoPtr->hFont != 0)
7887 SelectObject(hdc, hOldFont);
7890 ReleaseDC(parent, hdc);
7891 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
7892 parent, 0, hinst, 0)))
7894 COMCTL32_Free(infoPtr->pedititem);
7898 infoPtr->pedititem->param = param;
7899 infoPtr->pedititem->EditLblCb = EditLblCb;
7900 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
7901 GWL_WNDPROC, (LONG) EditLblWndProc);
7903 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);