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;
1112 /* see if we are supposed to be tracking mouse hovering */
1113 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1114 /* fill in the trackinfo struct */
1115 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1116 trackinfo.dwFlags = TME_QUERY;
1117 trackinfo.hwndTrack = hwnd;
1118 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1120 /* see if we are already tracking this hwnd */
1121 _TrackMouseEvent(&trackinfo);
1123 if(!(trackinfo.dwFlags & TME_HOVER)) {
1124 trackinfo.dwFlags = TME_HOVER;
1126 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1127 _TrackMouseEvent(&trackinfo);
1136 * Selects an item based on coordinates.
1139 * [I] HWND : window handle
1140 * [I] POINT : mouse click ccordinates
1143 * SUCCESS : item index
1146 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1148 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1152 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1154 rcItem.left = LVIR_SELECTBOUNDS;
1155 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1157 if (PtInRect(&rcItem, pt) != FALSE)
1169 * Removes all selection states.
1172 * [I] HWND : window handle
1173 * [I] INT : item index
1179 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1185 lvItem.stateMask = LVIS_SELECTED;
1187 for (i = nFirst; i <= nLast; i++)
1189 ListView_SetItemState(hwnd, i, &lvItem);
1198 * [IO] HDPA : dynamic pointer array handle
1199 * [I] INT : column index (subitem index)
1205 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1207 BOOL bResult = TRUE;
1211 for (i = 0; i < hdpaItems->nItemCount; i++)
1213 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1214 if (hdpaSubItems != NULL)
1216 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1228 * Removes a subitem at a given position.
1231 * [IO] HDPA : dynamic pointer array handle
1232 * [I] INT : subitem index
1238 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1240 LISTVIEW_SUBITEM *lpSubItem;
1243 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1245 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1246 if (lpSubItem != NULL)
1248 if (lpSubItem->iSubItem == nSubItem)
1251 if ((lpSubItem->pszText != NULL) &&
1252 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1254 COMCTL32_Free(lpSubItem->pszText);
1258 COMCTL32_Free(lpSubItem);
1260 /* free dpa memory */
1261 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1266 else if (lpSubItem->iSubItem > nSubItem)
1278 * Compares the item information.
1281 * [I] LISTVIEW_ITEM *: destination item
1282 * [I] LPLVITEM : source item
1285 * SUCCCESS : TRUE (EQUAL)
1286 * FAILURE : FALSE (NOT EQUAL)
1288 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1292 if ((lpItem != NULL) && (lpLVItem != NULL))
1294 if (lpLVItem->mask & LVIF_STATE)
1296 if ((lpItem->state & lpLVItem->stateMask) !=
1297 (lpLVItem->state & lpLVItem->stateMask))
1299 uChanged |= LVIF_STATE;
1303 if (lpLVItem->mask & LVIF_IMAGE)
1305 if (lpItem->iImage != lpLVItem->iImage)
1307 uChanged |= LVIF_IMAGE;
1311 if (lpLVItem->mask & LVIF_PARAM)
1313 if (lpItem->lParam != lpLVItem->lParam)
1315 uChanged |= LVIF_PARAM;
1319 if (lpLVItem->mask & LVIF_INDENT)
1321 if (lpItem->iIndent != lpLVItem->iIndent)
1323 uChanged |= LVIF_INDENT;
1327 if (lpLVItem->mask & LVIF_TEXT)
1329 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1331 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1333 uChanged |= LVIF_TEXT;
1338 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1340 uChanged |= LVIF_TEXT;
1344 if (lpLVItem->pszText)
1346 if (lpItem->pszText)
1348 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1350 uChanged |= LVIF_TEXT;
1355 uChanged |= LVIF_TEXT;
1360 if (lpItem->pszText)
1362 uChanged |= LVIF_TEXT;
1374 * Initializes item attributes.
1377 * [I] HWND : window handle
1378 * [O] LISTVIEW_ITEM *: destination item
1379 * [I] LPLVITEM : source item
1385 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1388 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1389 BOOL bResult = FALSE;
1391 if ((lpItem != NULL) && (lpLVItem != NULL))
1395 if (lpLVItem->mask & LVIF_STATE)
1397 lpItem->state &= ~lpLVItem->stateMask;
1398 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1401 if (lpLVItem->mask & LVIF_IMAGE)
1403 lpItem->iImage = lpLVItem->iImage;
1406 if (lpLVItem->mask & LVIF_PARAM)
1408 lpItem->lParam = lpLVItem->lParam;
1411 if (lpLVItem->mask & LVIF_INDENT)
1413 lpItem->iIndent = lpLVItem->iIndent;
1416 if (lpLVItem->mask & LVIF_TEXT)
1418 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1420 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1425 if ((lpItem->pszText != NULL) &&
1426 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1428 COMCTL32_Free(lpItem->pszText);
1431 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1435 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1437 lpItem->pszText = NULL;
1440 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1450 * Initializes subitem attributes.
1452 * NOTE: The documentation specifies that the operation fails if the user
1453 * tries to set the indent of a subitem.
1456 * [I] HWND : window handle
1457 * [O] LISTVIEW_SUBITEM *: destination subitem
1458 * [I] LPLVITEM : source subitem
1464 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1467 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1468 BOOL bResult = FALSE;
1470 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1472 if (!(lpLVItem->mask & LVIF_INDENT))
1475 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1477 lpSubItem->iSubItem = lpLVItem->iSubItem;
1479 if (lpLVItem->mask & LVIF_IMAGE)
1481 lpSubItem->iImage = lpLVItem->iImage;
1484 if (lpLVItem->mask & LVIF_TEXT)
1486 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1488 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1493 if ((lpSubItem->pszText != NULL) &&
1494 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1496 COMCTL32_Free(lpSubItem->pszText);
1499 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1503 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1505 lpSubItem->pszText = NULL;
1508 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1519 * Adds a subitem at a given position (column index).
1522 * [I] HWND : window handle
1523 * [I] LPLVITEM : new subitem atttributes
1529 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1531 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1532 LISTVIEW_SUBITEM *lpSubItem = NULL;
1533 BOOL bResult = FALSE;
1535 INT nPosition, nItem;
1537 if (lpLVItem != NULL)
1539 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1540 if (hdpaSubItems != NULL)
1542 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1543 if (lpSubItem != NULL)
1545 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1547 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1548 lpSubItem->iSubItem);
1549 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1559 /* cleanup if unsuccessful */
1560 if ((bResult == FALSE) && (lpSubItem != NULL))
1562 COMCTL32_Free(lpSubItem);
1570 * Finds the dpa insert position (array index).
1573 * [I] HWND : window handle
1574 * [I] INT : subitem index
1580 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1582 LISTVIEW_SUBITEM *lpSubItem;
1585 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1587 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1588 if (lpSubItem != NULL)
1590 if (lpSubItem->iSubItem > nSubItem)
1597 return hdpaSubItems->nItemCount;
1602 * Retrieves a listview subitem at a given position (column index).
1605 * [I] HWND : window handle
1606 * [I] INT : subitem index
1612 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1614 LISTVIEW_SUBITEM *lpSubItem;
1617 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1619 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1620 if (lpSubItem != NULL)
1622 if (lpSubItem->iSubItem == nSubItem)
1626 else if (lpSubItem->iSubItem > nSubItem)
1638 * Sets item attributes.
1641 * [I] HWND : window handle
1642 * [I] LPLVITEM : new item atttributes
1648 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1650 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1651 BOOL bResult = FALSE;
1653 LISTVIEW_ITEM *lpItem;
1656 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1658 if (lpLVItem != NULL)
1660 if (lpLVItem->iSubItem == 0)
1662 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1663 if (hdpaSubItems != NULL)
1665 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1668 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1669 nmlv.hdr.hwndFrom = hwnd;
1670 nmlv.hdr.idFrom = lCtrlId;
1671 nmlv.hdr.code = LVN_ITEMCHANGING;
1672 nmlv.lParam = lpItem->lParam;
1673 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1676 if (uChanged & LVIF_STATE)
1678 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1679 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1682 nmlv.uChanged = uChanged;
1683 nmlv.iItem = lpLVItem->iItem;
1684 nmlv.lParam = lpItem->lParam;
1685 /* send LVN_ITEMCHANGING notification */
1686 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1688 /* copy information */
1689 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1691 /* send LVN_ITEMCHANGED notification */
1692 nmlv.hdr.code = LVN_ITEMCHANGED;
1693 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1700 InvalidateRect(hwnd, NULL, FALSE);
1711 * Sets subitem attributes.
1714 * [I] HWND : window handle
1715 * [I] LPLVITEM : new subitem atttributes
1721 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1723 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1724 BOOL bResult = FALSE;
1726 LISTVIEW_SUBITEM *lpSubItem;
1728 if (lpLVItem != NULL)
1730 if (lpLVItem->iSubItem > 0)
1732 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1733 if (hdpaSubItems != NULL)
1735 /* set subitem only if column is present */
1736 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1738 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1739 if (lpSubItem != NULL)
1741 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1745 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1748 InvalidateRect(hwnd, NULL, FALSE);
1759 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1762 * [I] HWND : window handle
1767 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1769 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1770 UINT uView = lStyle & LVS_TYPEMASK;
1772 SCROLLINFO scrollInfo;
1774 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1775 scrollInfo.cbSize = sizeof(SCROLLINFO);
1776 scrollInfo.fMask = SIF_POS;
1778 if (uView == LVS_LIST)
1780 if (lStyle & WS_HSCROLL)
1782 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1784 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1788 else if (uView == LVS_REPORT)
1790 if (lStyle & WS_VSCROLL)
1792 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1794 nItem = scrollInfo.nPos;
1807 * [I] HWND : window handle
1808 * [I] HDC : device context handle
1809 * [I] INT : item index
1810 * [I] INT : subitem index
1811 * [I] RECT * : clipping rectangle
1816 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1819 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1820 CHAR szDispText[DISP_TEXT_SIZE];
1823 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
1826 /* get information needed for drawing the item */
1827 ZeroMemory(&lvItem, sizeof(LVITEMA));
1828 lvItem.mask = LVIF_TEXT;
1829 lvItem.iItem = nItem;
1830 lvItem.iSubItem = nSubItem;
1831 lvItem.cchTextMax = DISP_TEXT_SIZE;
1832 lvItem.pszText = szDispText;
1833 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1835 /* set item colors */
1836 SetBkColor(hdc, infoPtr->clrTextBk);
1837 SetTextColor(hdc, infoPtr->clrText);
1839 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1840 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1849 * [I] HWND : window handle
1850 * [I] HDC : device context handle
1851 * [I] INT : item index
1852 * [I] RECT * : clipping rectangle
1857 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1860 CHAR szDispText[DISP_TEXT_SIZE];
1867 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
1869 /* get information needed for drawing the item */
1870 ZeroMemory(&lvItem, sizeof(LVITEMA));
1871 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1872 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1873 lvItem.iItem = nItem;
1874 lvItem.iSubItem = 0;
1875 lvItem.cchTextMax = DISP_TEXT_SIZE;
1876 lvItem.pszText = szDispText;
1877 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1880 if (infoPtr->himlState != NULL)
1882 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1883 if (uStateImage != 0)
1885 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1886 rcItem.top, ILD_NORMAL);
1889 rcItem.left += infoPtr->iconSize.cx;
1893 if (infoPtr->himlSmall != NULL)
1895 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1897 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1898 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1899 rcItem.top, ILD_SELECTED);
1903 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1904 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1905 rcItem.top, ILD_NORMAL);
1908 rcItem.left += infoPtr->iconSize.cx;
1911 /* Don't bother painting item being edited */
1912 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1915 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1917 /* set item colors */
1918 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1919 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1920 /* set raster mode */
1921 nMixMode = SetROP2(hdc, R2_XORPEN);
1923 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1924 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1926 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1927 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1928 /* set raster mode */
1929 nMixMode = SetROP2(hdc, R2_COPYPEN);
1933 /* set item colors */
1934 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1935 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1936 /* set raster mode */
1937 nMixMode = SetROP2(hdc, R2_COPYPEN);
1940 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1941 if (rcItem.left + nLabelWidth < rcItem.right)
1943 rcItem.right = rcItem.left + nLabelWidth;
1947 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1948 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1950 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1952 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1957 SetROP2(hdc, R2_COPYPEN);
1958 SetBkColor(hdc, infoPtr->clrTextBk);
1959 SetTextColor(hdc, infoPtr->clrText);
1965 * Draws an item when in large icon display mode.
1968 * [I] HWND : window handle
1969 * [I] HDC : device context handle
1970 * [I] LISTVIEW_ITEM * : item
1971 * [I] INT : item index
1972 * [I] RECT * : clipping rectangle
1977 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1979 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1980 CHAR szDispText[DISP_TEXT_SIZE];
1981 INT nDrawPosX = rcItem.left;
1986 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1987 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1990 /* get information needed for drawing the item */
1991 ZeroMemory(&lvItem, sizeof(LVITEMA));
1992 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1993 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1994 lvItem.iItem = nItem;
1995 lvItem.iSubItem = 0;
1996 lvItem.cchTextMax = DISP_TEXT_SIZE;
1997 lvItem.pszText = szDispText;
1998 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2000 if (lvItem.state & LVIS_SELECTED)
2002 /* set item colors */
2003 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2004 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2005 /* set raster mode */
2006 SetROP2(hdc, R2_XORPEN);
2010 /* set item colors */
2011 SetBkColor(hdc, infoPtr->clrTextBk);
2012 SetTextColor(hdc, infoPtr->clrText);
2013 /* set raster mode */
2014 SetROP2(hdc, R2_COPYPEN);
2017 if (infoPtr->himlNormal != NULL)
2019 rcItem.top += ICON_TOP_PADDING;
2020 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
2021 if (lvItem.state & LVIS_SELECTED)
2023 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2024 rcItem.top, ILD_SELECTED);
2028 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2029 rcItem.top, ILD_NORMAL);
2033 /* Don't bother painting item being edited */
2034 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
2037 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2038 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2039 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
2042 rcItem.left += nDrawPosX / 2;
2043 rcItem.right = rcItem.left + nLabelWidth;
2048 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
2052 GetTextMetricsA(hdc, &tm);
2053 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
2054 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2055 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2057 if (lvItem.state & LVIS_FOCUSED)
2059 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2065 * Draws listview items when in report display mode.
2068 * [I] HWND : window handle
2069 * [I] HDC : device context handle
2074 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2076 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2077 SCROLLINFO scrollInfo;
2078 INT nDrawPosY = infoPtr->rcList.top;
2085 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2086 scrollInfo.cbSize = sizeof(SCROLLINFO);
2087 scrollInfo.fMask = SIF_POS;
2089 nItem = ListView_GetTopIndex(hwnd);
2091 /* add 1 for displaying a partial item at the bottom */
2092 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2093 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2095 /* send cache hint notification */
2096 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
2100 nmlv.hdr.hwndFrom = hwnd;
2101 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
2102 nmlv.hdr.code = LVN_ODCACHEHINT;
2106 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
2110 for (; nItem < nLast; nItem++)
2112 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2113 for (j = 0; j < nColumnCount; j++)
2115 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2116 rcItem.left += REPORT_MARGINX;
2117 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2118 rcItem.top = nDrawPosY;
2119 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2121 /* Offset the Scroll Bar Pos */
2122 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2124 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2125 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2130 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2134 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2138 nDrawPosY += infoPtr->nItemHeight;
2144 * Retrieves the number of items that can fit vertically in the client area.
2147 * [I] HWND : window handle
2150 * Number of items per row.
2152 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2154 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2155 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2156 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2157 INT nCountPerRow = 1;
2161 if (uView == LVS_REPORT)
2167 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2168 if (nCountPerRow == 0)
2175 return nCountPerRow;
2180 * Retrieves the number of items that can fit horizontally in the client
2184 * [I] HWND : window handle
2187 * Number of items per column.
2189 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2191 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2192 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2193 INT nCountPerColumn = 1;
2195 if (nListHeight > 0)
2197 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2198 if (nCountPerColumn == 0)
2200 nCountPerColumn = 1;
2204 return nCountPerColumn;
2209 * Retrieves the number of columns needed to display all the items when in
2210 * list display mode.
2213 * [I] HWND : window handle
2216 * Number of columns.
2218 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2220 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2221 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2222 INT nColumnCount = 0;
2224 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2226 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2228 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2232 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2236 return nColumnCount;
2242 * Draws listview items when in list display mode.
2245 * [I] HWND : window handle
2246 * [I] HDC : device context handle
2251 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2253 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2258 INT nCountPerColumn;
2259 INT nItemWidth = infoPtr->nItemWidth;
2260 INT nItemHeight = infoPtr->nItemHeight;
2262 /* get number of fully visible columns */
2263 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2264 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2265 nItem = ListView_GetTopIndex(hwnd);
2267 for (i = 0; i < nColumnCount; i++)
2269 for (j = 0; j < nCountPerColumn; j++, nItem++)
2271 if (nItem >= GETITEMCOUNT(infoPtr))
2274 rcItem.top = j * nItemHeight;
2275 rcItem.left = i * nItemWidth;
2276 rcItem.bottom = rcItem.top + nItemHeight;
2277 rcItem.right = rcItem.left + nItemWidth;
2278 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2285 * Draws listview items when in icon or small icon display mode.
2288 * [I] HWND : window handle
2289 * [I] HDC : device context handle
2294 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2296 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2302 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2303 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2305 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2306 ptPosition.x += ptOrigin.x;
2307 ptPosition.y += ptOrigin.y;
2309 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2311 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2313 if (ptPosition.y < infoPtr->rcList.bottom)
2315 if (ptPosition.x < infoPtr->rcList.right)
2317 rcItem.top = ptPosition.y;
2318 rcItem.left = ptPosition.x;
2319 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2320 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2321 if (bSmall == FALSE)
2323 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2327 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2338 * Draws listview items.
2341 * [I] HWND : window handle
2342 * [I] HDC : device context handle
2347 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2349 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2350 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2355 hOldFont = SelectObject(hdc, infoPtr->hFont);
2357 /* select the doted pen (for drawing the focus box) */
2358 hPen = CreatePen(PS_DOT, 1, 0);
2359 hOldPen = SelectObject(hdc, hPen);
2361 /* select transparent brush (for drawing the focus box) */
2362 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2364 if (uView == LVS_LIST)
2366 LISTVIEW_RefreshList(hwnd, hdc);
2368 else if (uView == LVS_REPORT)
2370 LISTVIEW_RefreshReport(hwnd, hdc);
2372 else if (uView == LVS_SMALLICON)
2374 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2376 else if (uView == LVS_ICON)
2378 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2381 /* unselect objects */
2382 SelectObject(hdc, hOldFont);
2383 SelectObject(hdc, hOldPen);
2392 * Calculates the approximate width and height of a given number of items.
2395 * [I] HWND : window handle
2396 * [I] INT : number of items
2401 * Returns a DWORD. The width in the low word and the height in high word.
2403 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2404 WORD wWidth, WORD wHeight)
2406 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2407 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2408 INT nItemCountPerColumn = 1;
2409 INT nColumnCount = 0;
2410 DWORD dwViewRect = 0;
2412 if (nItemCount == -1)
2414 nItemCount = GETITEMCOUNT(infoPtr);
2417 if (uView == LVS_LIST)
2419 if (wHeight == 0xFFFF)
2421 /* use current height */
2422 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2425 if (wHeight < infoPtr->nItemHeight)
2427 wHeight = infoPtr->nItemHeight;
2432 if (infoPtr->nItemHeight > 0)
2434 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2435 if (nItemCountPerColumn == 0)
2437 nItemCountPerColumn = 1;
2440 if (nItemCount % nItemCountPerColumn != 0)
2442 nColumnCount = nItemCount / nItemCountPerColumn;
2446 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2451 /* Microsoft padding magic */
2452 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2453 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2455 dwViewRect = MAKELONG(wWidth, wHeight);
2457 else if (uView == LVS_REPORT)
2461 else if (uView == LVS_SMALLICON)
2465 else if (uView == LVS_ICON)
2475 * Arranges listview items in icon display mode.
2478 * [I] HWND : window handle
2479 * [I] INT : alignment code
2485 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2487 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2488 BOOL bResult = FALSE;
2490 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2503 case LVA_SNAPTOGRID:
2512 /* << LISTVIEW_CreateDragImage >> */
2516 * Removes all listview items and subitems.
2519 * [I] HWND : window handle
2525 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2527 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2528 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2529 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2530 UINT uView = lStyle & LVS_TYPEMASK;
2531 LISTVIEW_ITEM *lpItem;
2532 LISTVIEW_SUBITEM *lpSubItem;
2535 BOOL bResult = FALSE;
2540 TRACE("(hwnd=%x,)\n", hwnd);
2542 if (GETITEMCOUNT(infoPtr) > 0)
2544 /* initialize memory */
2545 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2547 /* send LVN_DELETEALLITEMS notification */
2548 nmlv.hdr.hwndFrom = hwnd;
2549 nmlv.hdr.idFrom = lCtrlId;
2550 nmlv.hdr.code = LVN_DELETEALLITEMS;
2553 /* verify if subsequent LVN_DELETEITEM notifications should be
2555 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2557 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2559 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2560 if (hdpaSubItems != NULL)
2562 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2564 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2565 if (lpSubItem != NULL)
2567 /* free subitem string */
2568 if ((lpSubItem->pszText != NULL) &&
2569 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2571 COMCTL32_Free(lpSubItem->pszText);
2575 COMCTL32_Free(lpSubItem);
2579 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2582 if (bSuppress == FALSE)
2584 /* send LVN_DELETEITEM notification */
2585 nmlv.hdr.code = LVN_DELETEITEM;
2587 nmlv.lParam = lpItem->lParam;
2588 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2591 /* free item string */
2592 if ((lpItem->pszText != NULL) &&
2593 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2595 COMCTL32_Free(lpItem->pszText);
2599 COMCTL32_Free(lpItem);
2602 DPA_Destroy(hdpaSubItems);
2606 /* reinitialize listview memory */
2607 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2609 /* align items (set position of each item) */
2610 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2612 if (lStyle & LVS_ALIGNLEFT)
2614 LISTVIEW_AlignLeft(hwnd);
2618 LISTVIEW_AlignTop(hwnd);
2622 LISTVIEW_UpdateScroll(hwnd);
2624 /* invalidate client area (optimization needed) */
2625 InvalidateRect(hwnd, NULL, TRUE);
2633 * Removes a column from the listview control.
2636 * [I] HWND : window handle
2637 * [I] INT : column index
2643 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2645 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2646 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2647 BOOL bResult = FALSE;
2649 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2651 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2653 /* Need to reset the item width when deleting a column */
2654 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2656 /* reset scroll parameters */
2657 if (uView == LVS_REPORT)
2659 /* update scrollbar(s) */
2660 LISTVIEW_UpdateScroll(hwnd);
2662 /* refresh client area */
2663 InvalidateRect(hwnd, NULL, FALSE);
2672 * Removes an item from the listview control.
2675 * [I] HWND : window handle
2676 * [I] INT : item index
2682 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2684 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2685 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2686 UINT uView = lStyle & LVS_TYPEMASK;
2687 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2689 BOOL bResult = FALSE;
2691 LISTVIEW_ITEM *lpItem;
2692 LISTVIEW_SUBITEM *lpSubItem;
2695 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2697 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2699 /* initialize memory */
2700 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2702 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2703 if (hdpaSubItems != NULL)
2705 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2707 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2708 if (lpSubItem != NULL)
2710 /* free item string */
2711 if ((lpSubItem->pszText != NULL) &&
2712 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2714 COMCTL32_Free(lpSubItem->pszText);
2718 COMCTL32_Free(lpSubItem);
2722 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2725 /* send LVN_DELETEITEM notification */
2726 nmlv.hdr.hwndFrom = hwnd;
2727 nmlv.hdr.idFrom = lCtrlId;
2728 nmlv.hdr.code = LVN_DELETEITEM;
2730 nmlv.lParam = lpItem->lParam;
2731 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2734 /* free item string */
2735 if ((lpItem->pszText != NULL) &&
2736 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2738 COMCTL32_Free(lpItem->pszText);
2742 COMCTL32_Free(lpItem);
2745 bResult = DPA_Destroy(hdpaSubItems);
2748 /* align items (set position of each item) */
2749 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2751 if (lStyle & LVS_ALIGNLEFT)
2753 LISTVIEW_AlignLeft(hwnd);
2757 LISTVIEW_AlignTop(hwnd);
2761 /* If this item had focus change focus to next or previous item */
2762 if (GETITEMCOUNT(infoPtr) > 0)
2764 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
2765 if (infoPtr->nFocusedItem == nItem)
2766 LISTVIEW_SetItemFocus(hwnd, sItem);
2769 infoPtr->nFocusedItem = -1;
2771 LISTVIEW_UpdateScroll(hwnd);
2773 /* refresh client area */
2774 InvalidateRect(hwnd, NULL, TRUE);
2783 * Return edit control handle of current edit label
2786 * [I] HWND : window handle
2792 static LRESULT LISTVIEW_GetEditControl(hwnd)
2794 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2795 return infoPtr->hwndEdit;
2801 * Callback implementation for editlabel control
2804 * [I] HWND : window handle
2805 * [I] LPSTR : modified text
2806 * [I] DWORD : item index
2813 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
2815 NMLVDISPINFOA dispInfo;
2816 LISTVIEW_ITEM *lpItem;
2817 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2818 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2820 BOOL bUpdateItemText;
2822 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2824 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2827 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2830 dispInfo.hdr.hwndFrom = hwnd;
2831 dispInfo.hdr.idFrom = nCtrlId;
2832 dispInfo.hdr.code = LVN_ENDLABELEDITA;
2833 dispInfo.item.mask = 0;
2834 dispInfo.item.iItem = nItem;
2835 dispInfo.item.state = lpItem->state;
2836 dispInfo.item.stateMask = 0;
2837 dispInfo.item.pszText = pszText;
2838 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
2839 dispInfo.item.iImage = lpItem->iImage;
2840 dispInfo.item.lParam = lpItem->lParam;
2841 infoPtr->hwndEdit = 0;
2843 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
2845 /* Do we need to update the Item Text */
2848 if(lpItem->pszText != LPSTR_TEXTCALLBACKA)
2850 Str_SetPtrA(&lpItem->pszText, pszText);
2859 * Begin in place editing of specified list view item
2862 * [I] HWND : window handle
2863 * [I] INT : item index
2870 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
2872 NMLVDISPINFOA dispInfo;
2874 LISTVIEW_ITEM *lpItem;
2876 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
2877 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2878 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2880 CHAR szDispText[DISP_TEXT_SIZE];
2883 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
2886 /* Is the EditBox still there, if so remove it */
2887 if(infoPtr->hwndEdit != 0)
2892 LISTVIEW_SetSelection(hwnd, nItem);
2893 LISTVIEW_SetItemFocus(hwnd, nItem);
2895 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2896 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2899 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2903 /* get information needed for drawing the item */
2904 ZeroMemory(&lvItem, sizeof(LVITEMA));
2905 lvItem.mask = LVIF_TEXT;
2906 lvItem.iItem = nItem;
2907 lvItem.iSubItem = 0;
2908 lvItem.cchTextMax = DISP_TEXT_SIZE;
2909 lvItem.pszText = szDispText;
2910 ListView_GetItemA(hwnd, &lvItem);
2912 dispInfo.hdr.hwndFrom = hwnd;
2913 dispInfo.hdr.idFrom = nCtrlId;
2914 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
2915 dispInfo.item.mask = 0;
2916 dispInfo.item.iItem = nItem;
2917 dispInfo.item.state = lpItem->state;
2918 dispInfo.item.stateMask = 0;
2919 dispInfo.item.pszText = lvItem.pszText;
2920 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
2921 dispInfo.item.iImage = lpItem->iImage;
2922 dispInfo.item.lParam = lpItem->lParam;
2924 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
2927 rect.left = LVIR_LABEL;
2928 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
2931 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
2932 rect.left-2, rect.top-1, 0,
2933 rect.bottom - rect.top+2,
2934 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
2937 infoPtr->hwndEdit = hedit;
2939 SendMessageA(hedit, EM_SETSEL, 0, -1);
2947 * Ensures the specified item is visible, scrolling into view if necessary.
2950 * [I] HWND : window handle
2951 * [I] INT : item index
2952 * [I] BOOL : partially or entirely visible
2958 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2960 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2961 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2962 INT nScrollPosHeight = 0;
2963 INT nScrollPosWidth = 0;
2964 SCROLLINFO scrollInfo;
2967 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2968 scrollInfo.cbSize = sizeof(SCROLLINFO);
2969 scrollInfo.fMask = SIF_POS;
2971 /* ALWAYS bPartial == FALSE, FOR NOW! */
2973 rcItem.left = LVIR_BOUNDS;
2974 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2976 if (rcItem.left < infoPtr->rcList.left)
2978 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2981 if (uView == LVS_LIST)
2983 nScrollPosWidth = infoPtr->nItemWidth;
2984 rcItem.left += infoPtr->rcList.left;
2986 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2988 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
2989 rcItem.left += infoPtr->rcList.left;
2992 /* When in LVS_REPORT view, the scroll position should
2994 if (nScrollPosWidth != 0)
2996 if (rcItem.left % nScrollPosWidth == 0)
2998 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
3002 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
3005 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3009 else if (rcItem.right > infoPtr->rcList.right)
3011 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3014 if (uView == LVS_LIST)
3016 rcItem.right -= infoPtr->rcList.right;
3017 nScrollPosWidth = infoPtr->nItemWidth;
3019 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3021 rcItem.right -= infoPtr->rcList.right;
3022 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
3025 /* When in LVS_REPORT view, the scroll position should
3027 if (nScrollPosWidth != 0)
3029 if (rcItem.right % nScrollPosWidth == 0)
3031 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
3035 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
3038 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3043 if (rcItem.top < infoPtr->rcList.top)
3046 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3048 if (uView == LVS_REPORT)
3050 rcItem.top -= infoPtr->rcList.top;
3051 nScrollPosHeight = infoPtr->nItemHeight;
3053 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3055 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3056 rcItem.top += infoPtr->rcList.top;
3059 if (rcItem.top % nScrollPosHeight == 0)
3061 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
3065 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
3068 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3071 else if (rcItem.bottom > infoPtr->rcList.bottom)
3074 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3076 if (uView == LVS_REPORT)
3078 rcItem.bottom -= infoPtr->rcList.bottom;
3079 nScrollPosHeight = infoPtr->nItemHeight;
3081 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3083 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3084 rcItem.bottom -= infoPtr->rcList.bottom;
3087 if (rcItem.bottom % nScrollPosHeight == 0)
3089 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
3093 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
3096 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3106 * Retrieves the nearest item, given a position and a direction.
3109 * [I] HWND : window handle
3110 * [I] POINT : start position
3111 * [I] UINT : direction
3114 * Item index if successdful, -1 otherwise.
3116 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3118 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3119 LVHITTESTINFO lvHitTestInfo;
3123 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3125 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3126 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3127 lvHitTestInfo.pt.x += pt.x;
3128 lvHitTestInfo.pt.y += pt.y;
3132 if (vkDirection == VK_DOWN)
3134 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3136 else if (vkDirection == VK_UP)
3138 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3140 else if (vkDirection == VK_LEFT)
3142 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3144 else if (vkDirection == VK_RIGHT)
3146 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3149 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3155 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3159 while (nItem == -1);
3167 * Searches for an item with specific characteristics.
3170 * [I] HWND : window handle
3171 * [I] INT : base item index
3172 * [I] LPLVFINDINFO : item information to look for
3175 * SUCCESS : index of item
3178 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3179 LPLVFINDINFO lpFindInfo)
3181 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3183 CHAR szDispText[DISP_TEXT_SIZE];
3187 INT nLast = GETITEMCOUNT(infoPtr);
3189 if ((nItem >= -1) && (lpFindInfo != NULL))
3191 ZeroMemory(&lvItem, sizeof(LVITEMA));
3193 if (lpFindInfo->flags & LVFI_PARAM)
3195 lvItem.mask |= LVIF_PARAM;
3198 if (lpFindInfo->flags & LVFI_STRING)
3200 lvItem.mask |= LVIF_TEXT;
3201 lvItem.pszText = szDispText;
3202 lvItem.cchTextMax = DISP_TEXT_SIZE;
3205 if (lpFindInfo->flags & LVFI_PARTIAL)
3207 lvItem.mask |= LVIF_TEXT;
3208 lvItem.pszText = szDispText;
3209 lvItem.cchTextMax = DISP_TEXT_SIZE;
3212 if (lpFindInfo->flags & LVFI_WRAP)
3217 if (lpFindInfo->flags & LVFI_NEARESTXY)
3219 ptItem.x = lpFindInfo->pt.x;
3220 ptItem.y = lpFindInfo->pt.y;
3225 while (nItem < nLast)
3227 if (lpFindInfo->flags & LVFI_NEARESTXY)
3229 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3230 lpFindInfo->vkDirection);
3233 /* get position of the new item index */
3234 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3245 lvItem.iItem = nItem;
3246 lvItem.iSubItem = 0;
3247 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
3249 if (lvItem.mask & LVIF_TEXT)
3251 if (lpFindInfo->flags & LVFI_PARTIAL)
3253 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3258 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3263 if (lvItem.mask & LVIF_PARAM)
3265 if (lpFindInfo->lParam != lvItem.lParam)
3291 * Retrieves the background color of the listview control.
3294 * [I] HWND : window handle
3297 * COLORREF associated with the background.
3299 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3301 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3303 return infoPtr->clrBk;
3308 * Retrieves the background image of the listview control.
3311 * [I] HWND : window handle
3312 * [O] LPLVMKBIMAGE : background image attributes
3318 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3320 /* FIXME (listview, "empty stub!\n"); */
3326 * Retrieves the callback mask.
3329 * [I] HWND : window handle
3334 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3336 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3338 return infoPtr->uCallbackMask;
3343 * Retrieves column attributes.
3346 * [I] HWND : window handle
3347 * [I] INT : column index
3348 * [IO] LPLVCOLUMNA : column information
3354 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3356 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3358 BOOL bResult = FALSE;
3360 if (lpColumn != NULL)
3362 /* initialize memory */
3363 ZeroMemory(&hdi, sizeof(HDITEMA));
3365 if (lpColumn->mask & LVCF_FMT)
3367 hdi.mask |= HDI_FORMAT;
3370 if (lpColumn->mask & LVCF_WIDTH)
3372 hdi.mask |= HDI_WIDTH;
3375 if (lpColumn->mask & LVCF_TEXT)
3377 hdi.mask |= HDI_TEXT;
3378 hdi.cchTextMax = lpColumn->cchTextMax;
3379 hdi.pszText = lpColumn->pszText;
3382 if (lpColumn->mask & LVCF_IMAGE)
3384 hdi.mask |= HDI_IMAGE;
3387 if (lpColumn->mask & LVCF_ORDER)
3389 hdi.mask |= HDI_ORDER;
3392 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3393 if (bResult != FALSE)
3395 if (lpColumn->mask & LVCF_FMT)
3399 if (hdi.fmt & HDF_LEFT)
3401 lpColumn->fmt |= LVCFMT_LEFT;
3403 else if (hdi.fmt & HDF_RIGHT)
3405 lpColumn->fmt |= LVCFMT_RIGHT;
3407 else if (hdi.fmt & HDF_CENTER)
3409 lpColumn->fmt |= LVCFMT_CENTER;
3412 if (hdi.fmt & HDF_IMAGE)
3414 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3417 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3419 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3423 if (lpColumn->mask & LVCF_WIDTH)
3425 lpColumn->cx = hdi.cxy;
3428 if (lpColumn->mask & LVCF_IMAGE)
3430 lpColumn->iImage = hdi.iImage;
3433 if (lpColumn->mask & LVCF_ORDER)
3435 lpColumn->iOrder = hdi.iOrder;
3443 /* LISTVIEW_GetColumnW */
3446 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
3448 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3455 for (i = 0; i < iCount; i++)
3463 * Retrieves the column width.
3466 * [I] HWND : window handle
3467 * [I] int : column index
3470 * SUCCESS : column width
3473 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3475 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3476 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3477 INT nColumnWidth = 0;
3480 if (uView == LVS_LIST)
3482 nColumnWidth = infoPtr->nItemWidth;
3484 else if (uView == LVS_REPORT)
3486 /* get column width from header */
3487 ZeroMemory(&hdi, sizeof(HDITEMA));
3488 hdi.mask = HDI_WIDTH;
3489 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3491 nColumnWidth = hdi.cxy;
3495 return nColumnWidth;
3500 * In list or report display mode, retrieves the number of items that can fit
3501 * vertically in the visible area. In icon or small icon display mode,
3502 * retrieves the total number of visible items.
3505 * [I] HWND : window handle
3508 * Number of fully visible items.
3510 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3512 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3513 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3516 if (uView == LVS_LIST)
3518 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3520 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3521 LISTVIEW_GetCountPerColumn(hwnd);
3524 else if (uView == LVS_REPORT)
3526 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3530 nItemCount = GETITEMCOUNT(infoPtr);
3536 /* LISTVIEW_GetEditControl */
3540 * Retrieves the extended listview style.
3543 * [I] HWND : window handle
3546 * SUCCESS : previous style
3549 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3551 LISTVIEW_INFO *infoPtr;
3553 /* make sure we can get the listview info */
3554 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3557 return (infoPtr->dwExStyle);
3562 * Retrieves the handle to the header control.
3565 * [I] HWND : window handle
3570 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3572 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3574 return infoPtr->hwndHeader;
3577 /* LISTVIEW_GetHotCursor */
3581 * Returns the time that the mouse cursor must hover over an item
3582 * before it is selected.
3585 * [I] HWND : window handle
3588 * Returns the previously set hover time or (DWORD)-1 to indicate that the
3589 * hover time is set to the default hover time.
3591 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
3593 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3595 return infoPtr->dwHoverTime;
3600 * Retrieves an image list handle.
3603 * [I] HWND : window handle
3604 * [I] INT : image list identifier
3607 * SUCCESS : image list handle
3610 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3612 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3613 HIMAGELIST himl = NULL;
3618 himl = infoPtr->himlNormal;
3621 himl = infoPtr->himlSmall;
3624 himl = infoPtr->himlState;
3628 return (LRESULT)himl;
3631 /* LISTVIEW_GetISearchString */
3635 * Retrieves item attributes.
3638 * [I] HWND : window handle
3639 * [IO] LPLVITEMA : item info
3640 * [I] internal : if true then we will use tricks that avoid copies
3641 * but are not compatible with the regular interface
3647 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
3649 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3650 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3651 NMLVDISPINFOA dispInfo;
3652 LISTVIEW_SUBITEM *lpSubItem;
3653 LISTVIEW_ITEM *lpItem;
3657 /* In the following:
3658 * lpLVItem describes the information requested by the user
3659 * lpItem/lpSubItem is what we have
3660 * dispInfo is a structure we use to request the missing
3661 * information from the application
3664 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3666 if ((lpLVItem == NULL) ||
3667 (lpLVItem->iItem < 0) ||
3668 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
3672 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3673 if (hdpaSubItems == NULL)
3676 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3680 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3681 if (lpLVItem->iSubItem == 0)
3683 piImage=&lpItem->iImage;
3684 ppszText=&lpItem->pszText;
3685 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3687 dispInfo.item.mask |= LVIF_STATE;
3688 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3693 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
3694 if (lpSubItem != NULL)
3696 piImage=&lpSubItem->iImage;
3697 ppszText=&lpSubItem->pszText;
3706 if ((lpLVItem->mask & LVIF_IMAGE) &&
3707 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
3709 dispInfo.item.mask |= LVIF_IMAGE;
3712 if ((lpLVItem->mask & LVIF_TEXT) &&
3713 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
3715 dispInfo.item.mask |= LVIF_TEXT;
3716 dispInfo.item.pszText = lpLVItem->pszText;
3717 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3720 if (dispInfo.item.mask != 0)
3722 /* We don't have all the requested info, query the application */
3723 dispInfo.hdr.hwndFrom = hwnd;
3724 dispInfo.hdr.idFrom = lCtrlId;
3725 dispInfo.hdr.code = LVN_GETDISPINFOA;
3726 dispInfo.item.iItem = lpLVItem->iItem;
3727 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3728 dispInfo.item.lParam = lpItem->lParam;
3729 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3732 if (dispInfo.item.mask & LVIF_IMAGE)
3734 lpLVItem->iImage = dispInfo.item.iImage;
3736 else if (lpLVItem->mask & LVIF_IMAGE)
3738 lpLVItem->iImage = *piImage;
3741 if (dispInfo.item.mask & LVIF_PARAM)
3743 lpLVItem->lParam = dispInfo.item.lParam;
3745 else if (lpLVItem->mask & LVIF_PARAM)
3747 lpLVItem->lParam = lpItem->lParam;
3750 if (dispInfo.item.mask & LVIF_TEXT)
3752 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
3754 Str_SetPtrA(ppszText, dispInfo.item.pszText);
3756 /* Here lpLVItem->pszText==dispInfo.item.pszText so a copy is unnecessary */
3758 else if (lpLVItem->mask & LVIF_TEXT)
3762 lpLVItem->pszText=*ppszText;
3764 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
3768 if (lpLVItem->iSubItem == 0)
3770 if (dispInfo.item.mask & LVIF_STATE)
3772 lpLVItem->state = lpItem->state;
3773 lpLVItem->state &= ~dispInfo.item.stateMask;
3774 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
3776 else if (lpLVItem->mask & LVIF_STATE)
3778 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3781 if (lpLVItem->mask & LVIF_PARAM)
3783 lpLVItem->lParam = lpItem->lParam;
3786 if (lpLVItem->mask & LVIF_INDENT)
3788 lpLVItem->iIndent = lpItem->iIndent;
3795 /* LISTVIEW_GetItemW */
3796 /* LISTVIEW_GetHotCursor */
3800 * Retrieves the index of the hot item.
3803 * [I] HWND : window handle
3806 * SUCCESS : hot item index
3807 * FAILURE : -1 (no hot item)
3809 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3811 LISTVIEW_INFO *infoPtr;
3813 /* make sure we can get the listview info */
3814 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3817 return (infoPtr->nHotItem);
3820 /* LISTVIEW_GetHoverTime */
3824 * Retrieves the number of items in the listview control.
3827 * [I] HWND : window handle
3832 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3834 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3836 return GETITEMCOUNT(infoPtr);
3841 * Retrieves the position (upper-left) of the listview control item.
3844 * [I] HWND : window handle
3845 * [I] INT : item index
3846 * [O] LPPOINT : coordinate information
3852 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3853 LPPOINT lpptPosition)
3855 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3856 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3857 BOOL bResult = FALSE;
3859 LISTVIEW_ITEM *lpItem;
3860 INT nCountPerColumn;
3863 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3866 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3867 (lpptPosition != NULL))
3869 if (uView == LVS_LIST)
3872 nItem = nItem - ListView_GetTopIndex(hwnd);
3873 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3876 nRow = nItem % nCountPerColumn;
3879 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3880 lpptPosition->y = 0;
3884 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3885 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3890 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3891 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3894 else if (uView == LVS_REPORT)
3897 lpptPosition->x = REPORT_MARGINX;
3898 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3899 infoPtr->nItemHeight) + infoPtr->rcList.top;
3903 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3904 if (hdpaSubItems != NULL)
3906 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3910 lpptPosition->x = lpItem->ptPosition.x;
3911 lpptPosition->y = lpItem->ptPosition.y;
3922 * Retrieves the bounding rectangle for a listview control item.
3925 * [I] HWND : window handle
3926 * [I] INT : item index
3927 * [IO] LPRECT : bounding rectangle coordinates
3933 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3935 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3936 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3937 BOOL bResult = FALSE;
3946 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3948 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3950 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3955 if (uView == LVS_ICON)
3957 if (infoPtr->himlNormal != NULL)
3959 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3962 lprc->left = ptItem.x + ptOrigin.x;
3963 lprc->top = ptItem.y + ptOrigin.y;
3964 lprc->right = lprc->left + infoPtr->iconSize.cx;
3965 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3966 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3970 else if (uView == LVS_SMALLICON)
3972 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3975 lprc->left = ptItem.x + ptOrigin.x;
3976 lprc->top = ptItem.y + ptOrigin.y;
3977 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3979 if (infoPtr->himlState != NULL)
3980 lprc->left += infoPtr->iconSize.cx;
3982 if (infoPtr->himlSmall != NULL)
3983 lprc->right = lprc->left + infoPtr->iconSize.cx;
3985 lprc->right = lprc->left;
3991 lprc->left = ptItem.x;
3992 lprc->top = ptItem.y;
3993 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3995 if (infoPtr->himlState != NULL)
3997 lprc->left += infoPtr->iconSize.cx;
4000 if (infoPtr->himlSmall != NULL)
4002 lprc->right = lprc->left + infoPtr->iconSize.cx;
4006 lprc->right = lprc->left;
4012 if (uView == LVS_ICON)
4014 if (infoPtr->himlNormal != NULL)
4016 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4019 lprc->left = ptItem.x + ptOrigin.x;
4020 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
4021 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
4022 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4023 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
4025 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
4026 lprc->right = lprc->left + nLabelWidth;
4031 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
4035 hOldFont = SelectObject(hdc, infoPtr->hFont);
4036 GetTextMetricsA(hdc, &tm);
4037 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
4038 SelectObject(hdc, hOldFont);
4039 ReleaseDC(hwnd, hdc);
4043 else if (uView == LVS_SMALLICON)
4045 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4048 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
4049 lprc->top = ptItem.y + ptOrigin.y;
4050 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4052 if (infoPtr->himlState != NULL)
4054 lprc->left += infoPtr->iconSize.cx;
4057 if (infoPtr->himlSmall != NULL)
4059 lprc->left += infoPtr->iconSize.cx;
4062 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4063 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4065 lprc->right = lprc->left + nLabelWidth;
4069 lprc->right = nLeftPos + infoPtr->nItemWidth;
4076 nLeftPos = lprc->left = ptItem.x;
4077 lprc->top = ptItem.y;
4078 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4080 if (infoPtr->himlState != NULL)
4082 lprc->left += infoPtr->iconSize.cx;
4085 if (infoPtr->himlSmall != NULL)
4087 lprc->left += infoPtr->iconSize.cx;
4090 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4091 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4093 lprc->right = lprc->left + nLabelWidth;
4097 lprc->right = nLeftPos + infoPtr->nItemWidth;
4103 if (uView == LVS_ICON)
4105 if (infoPtr->himlNormal != NULL)
4107 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4110 lprc->left = ptItem.x + ptOrigin.x;
4111 lprc->top = ptItem.y + ptOrigin.y;
4112 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4113 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4117 else if (uView == LVS_SMALLICON)
4119 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4122 lprc->left = ptItem.x + ptOrigin.x;
4123 lprc->right = lprc->left;
4124 lprc->top = ptItem.y + ptOrigin.y;
4125 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4126 if (infoPtr->himlState != NULL)
4127 lprc->right += infoPtr->iconSize.cx;
4128 if (infoPtr->himlSmall != NULL)
4129 lprc->right += infoPtr->iconSize.cx;
4131 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4132 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4134 lprc->right += nLabelWidth;
4138 lprc->right = lprc->left + infoPtr->nItemWidth;
4145 lprc->left = ptItem.x;
4146 lprc->right = lprc->left;
4147 lprc->top = ptItem.y;
4148 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4150 if (infoPtr->himlState != NULL)
4152 lprc->right += infoPtr->iconSize.cx;
4155 if (infoPtr->himlSmall != NULL)
4157 lprc->right += infoPtr->iconSize.cx;
4160 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4161 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4163 lprc->right += nLabelWidth;
4167 lprc->right = lprc->left + infoPtr->nItemWidth;
4172 case LVIR_SELECTBOUNDS:
4173 if (uView == LVS_ICON)
4175 if (infoPtr->himlNormal != NULL)
4177 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4180 lprc->left = ptItem.x + ptOrigin.x;
4181 lprc->top = ptItem.y + ptOrigin.y;
4182 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4183 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4187 else if (uView == LVS_SMALLICON)
4189 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4192 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4193 lprc->top = ptItem.y + ptOrigin.y;
4194 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4196 if (infoPtr->himlState != NULL)
4198 lprc->left += infoPtr->iconSize.cx;
4201 lprc->right = lprc->left;
4203 if (infoPtr->himlSmall != NULL)
4205 lprc->right += infoPtr->iconSize.cx;
4208 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4209 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4211 lprc->right += nLabelWidth;
4215 lprc->right = nLeftPos + infoPtr->nItemWidth;
4222 nLeftPos = lprc->left = ptItem.x;
4223 lprc->top = ptItem.y;
4224 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4226 if (infoPtr->himlState != NULL)
4228 lprc->left += infoPtr->iconSize.cx;
4231 lprc->right = lprc->left;
4233 if (infoPtr->himlSmall != NULL)
4235 lprc->right += infoPtr->iconSize.cx;
4238 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4239 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4241 lprc->right += nLabelWidth;
4245 lprc->right = nLeftPos + infoPtr->nItemWidth;
4258 * Retrieves the width of a label.
4261 * [I] HWND : window handle
4264 * SUCCESS : string width (in pixels)
4267 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4269 CHAR szDispText[DISP_TEXT_SIZE];
4270 INT nLabelWidth = 0;
4273 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4275 ZeroMemory(&lvItem, sizeof(LVITEMA));
4276 lvItem.mask = LVIF_TEXT;
4277 lvItem.iItem = nItem;
4278 lvItem.cchTextMax = DISP_TEXT_SIZE;
4279 lvItem.pszText = szDispText;
4280 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4282 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4290 * Retrieves the spacing between listview control items.
4293 * [I] HWND : window handle
4294 * [I] BOOL : flag for small or large icon
4297 * Horizontal + vertical spacing
4299 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4301 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4304 if (bSmall == FALSE)
4306 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4310 /* TODO: need to store width of smallicon item */
4311 lResult = MAKELONG(0, infoPtr->nItemHeight);
4319 * Retrieves the state of a listview control item.
4322 * [I] HWND : window handle
4323 * [I] INT : item index
4324 * [I] UINT : state mask
4327 * State specified by the mask.
4329 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4331 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4335 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4337 ZeroMemory(&lvItem, sizeof(LVITEMA));
4338 lvItem.iItem = nItem;
4339 lvItem.stateMask = uMask;
4340 lvItem.mask = LVIF_STATE;
4341 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4343 uState = lvItem.state;
4352 * Retrieves the text of a listview control item or subitem.
4355 * [I] HWND : window handle
4356 * [I] INT : item index
4357 * [IO] LPLVITEMA : item information
4360 * SUCCESS : string length
4363 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4365 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4368 if (lpLVItem != NULL)
4370 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4372 lpLVItem->mask = LVIF_TEXT;
4373 lpLVItem->iItem = nItem;
4374 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
4376 nLength = lstrlenA(lpLVItem->pszText);
4386 * Searches for an item based on properties + relationships.
4389 * [I] HWND : window handle
4390 * [I] INT : item index
4391 * [I] INT : relationship flag
4394 * SUCCESS : item index
4397 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4399 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4400 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4402 LVFINDINFO lvFindInfo;
4403 INT nCountPerColumn;
4406 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4408 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4410 if (uFlags & LVNI_CUT)
4413 if (uFlags & LVNI_DROPHILITED)
4414 uMask |= LVIS_DROPHILITED;
4416 if (uFlags & LVNI_FOCUSED)
4417 uMask |= LVIS_FOCUSED;
4419 if (uFlags & LVNI_SELECTED)
4420 uMask |= LVIS_SELECTED;
4422 if (uFlags & LVNI_ABOVE)
4424 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4429 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4435 lvFindInfo.flags = LVFI_NEARESTXY;
4436 lvFindInfo.vkDirection = VK_UP;
4437 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4438 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4440 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4445 else if (uFlags & LVNI_BELOW)
4447 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4449 while (nItem < GETITEMCOUNT(infoPtr))
4452 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4458 lvFindInfo.flags = LVFI_NEARESTXY;
4459 lvFindInfo.vkDirection = VK_DOWN;
4460 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4461 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4463 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4468 else if (uFlags & LVNI_TOLEFT)
4470 if (uView == LVS_LIST)
4472 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4473 while (nItem - nCountPerColumn >= 0)
4475 nItem -= nCountPerColumn;
4476 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4480 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4482 lvFindInfo.flags = LVFI_NEARESTXY;
4483 lvFindInfo.vkDirection = VK_LEFT;
4484 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4485 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4487 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4492 else if (uFlags & LVNI_TORIGHT)
4494 if (uView == LVS_LIST)
4496 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4497 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4499 nItem += nCountPerColumn;
4500 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4504 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4506 lvFindInfo.flags = LVFI_NEARESTXY;
4507 lvFindInfo.vkDirection = VK_RIGHT;
4508 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4509 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4511 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4520 /* search by index */
4521 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4523 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4532 /* LISTVIEW_GetNumberOfWorkAreas */
4536 * Retrieves the origin coordinates when in icon or small icon display mode.
4539 * [I] HWND : window handle
4540 * [O] LPPOINT : coordinate information
4546 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4548 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4549 UINT uView = lStyle & LVS_TYPEMASK;
4550 BOOL bResult = FALSE;
4552 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4554 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4556 SCROLLINFO scrollInfo;
4557 ZeroMemory(lpptOrigin, sizeof(POINT));
4558 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4559 scrollInfo.cbSize = sizeof(SCROLLINFO);
4561 if (lStyle & WS_HSCROLL)
4563 scrollInfo.fMask = SIF_POS;
4564 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4566 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4570 if (lStyle & WS_VSCROLL)
4572 scrollInfo.fMask = SIF_POS;
4573 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4575 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4587 * Retrieves the number of items that are marked as selected.
4590 * [I] HWND : window handle
4593 * Number of items selected.
4595 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4597 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4598 INT nSelectedCount = 0;
4601 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4603 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4609 return nSelectedCount;
4614 * Retrieves item index that marks the start of a multiple selection.
4617 * [I] HWND : window handle
4620 * Index number or -1 if there is no selection mark.
4622 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4624 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4626 return infoPtr->nSelectionMark;
4631 * Retrieves the width of a string.
4634 * [I] HWND : window handle
4637 * SUCCESS : string width (in pixels)
4640 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4642 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4643 HFONT hFont, hOldFont;
4647 ZeroMemory(&stringSize, sizeof(SIZE));
4648 if (lpszText != NULL)
4650 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4652 hOldFont = SelectObject(hdc, hFont);
4653 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4654 SelectObject(hdc, hOldFont);
4655 ReleaseDC(hwnd, hdc);
4658 return stringSize.cx;
4663 * Retrieves the text backgound color.
4666 * [I] HWND : window handle
4669 * COLORREF associated with the the background.
4671 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4673 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4675 return infoPtr->clrTextBk;
4680 * Retrieves the text color.
4683 * [I] HWND : window handle
4686 * COLORREF associated with the text.
4688 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4690 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4692 return infoPtr->clrText;
4697 * Determines which section of the item was selected (if any).
4700 * [I] HWND : window handle
4701 * [IO] LPLVHITTESTINFO : hit test information
4704 * SUCCESS : item index
4707 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4709 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4713 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4714 lpHitTestInfo->pt.y);
4716 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4718 rcItem.left = LVIR_BOUNDS;
4719 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4721 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4723 rcItem.left = LVIR_ICON;
4724 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4726 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4728 lpHitTestInfo->flags = LVHT_ONITEMICON;
4729 lpHitTestInfo->iItem = i;
4730 lpHitTestInfo->iSubItem = 0;
4735 rcItem.left = LVIR_LABEL;
4736 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4738 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4740 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4741 lpHitTestInfo->iItem = i;
4742 lpHitTestInfo->iSubItem = 0;
4747 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4748 lpHitTestInfo->iItem = i;
4749 lpHitTestInfo->iSubItem = 0;
4755 lpHitTestInfo->flags = LVHT_NOWHERE;
4762 * Determines which listview item is located at the specified position.
4765 * [I] HWND : window handle
4766 * [IO} LPLVHITTESTINFO : hit test information
4769 * SUCCESS : item index
4772 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4774 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4777 lpHitTestInfo->flags = 0;
4779 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4781 lpHitTestInfo->flags = LVHT_TOLEFT;
4783 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4785 lpHitTestInfo->flags = LVHT_TORIGHT;
4787 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4789 lpHitTestInfo->flags |= LVHT_ABOVE;
4791 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4793 lpHitTestInfo->flags |= LVHT_BELOW;
4796 if (lpHitTestInfo->flags == 0)
4798 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4806 * Inserts a new column.
4809 * [I] HWND : window handle
4810 * [I] INT : column index
4811 * [I] LPLVCOLUMNA : column information
4814 * SUCCESS : new column index
4817 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4818 LPLVCOLUMNA lpColumn)
4820 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4822 INT nNewColumn = -1;
4824 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4827 if (lpColumn != NULL)
4829 /* initialize memory */
4830 ZeroMemory(&hdi, sizeof(HDITEMA));
4832 if (lpColumn->mask & LVCF_FMT)
4834 /* format member is valid */
4835 hdi.mask |= HDI_FORMAT;
4837 /* set text alignment (leftmost column must be left-aligned) */
4840 hdi.fmt |= HDF_LEFT;
4844 if (lpColumn->fmt & LVCFMT_LEFT)
4846 hdi.fmt |= HDF_LEFT;
4848 else if (lpColumn->fmt & LVCFMT_RIGHT)
4850 hdi.fmt |= HDF_RIGHT;
4852 else if (lpColumn->fmt & LVCFMT_CENTER)
4854 hdi.fmt |= HDF_CENTER;
4858 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4860 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4864 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4869 if (lpColumn->fmt & LVCFMT_IMAGE)
4871 hdi.fmt |= HDF_IMAGE;
4872 hdi.iImage = I_IMAGECALLBACK;
4876 if (lpColumn->mask & LVCF_WIDTH)
4878 hdi.mask |= HDI_WIDTH;
4879 hdi.cxy = lpColumn->cx;
4882 if (lpColumn->mask & LVCF_TEXT)
4884 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4885 hdi.pszText = lpColumn->pszText;
4886 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4887 hdi.fmt |= HDF_STRING;
4890 if (lpColumn->mask & LVCF_IMAGE)
4892 hdi.mask |= HDI_IMAGE;
4893 hdi.iImage = lpColumn->iImage;
4896 if (lpColumn->mask & LVCF_ORDER)
4898 hdi.mask |= HDI_ORDER;
4899 hdi.iOrder = lpColumn->iOrder;
4902 /* insert item in header control */
4903 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4904 (WPARAM)nColumn, (LPARAM)&hdi);
4906 /* Need to reset the item width when inserting a new column */
4907 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4909 LISTVIEW_UpdateScroll(hwnd);
4910 InvalidateRect(hwnd, NULL, FALSE);
4916 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4917 LPLVCOLUMNW lpColumn)
4922 memcpy(&lvca,lpColumn,sizeof(lvca));
4923 if (lpColumn->mask & LVCF_TEXT)
4924 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4925 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4926 if (lpColumn->mask & LVCF_TEXT)
4927 HeapFree(GetProcessHeap(),0,lvca.pszText);
4931 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
4932 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
4933 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
4934 and not during the processing of a LVM_SORTITEMS message. Applications should provide
4935 their own sort proc. when sending LVM_SORTITEMS.
4938 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
4940 LVS_SORTXXX must be specified,
4941 LVS_OWNERDRAW is not set,
4942 <item>.pszText is not LPSTR_TEXTCALLBACK.
4944 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
4945 are sorted based on item text..."
4947 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
4949 HDPA hdpa_first = (HDPA) first;
4950 HDPA hdpa_second = (HDPA) second;
4951 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
4952 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
4953 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
4954 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
4955 /* if we're sorting descending, negate the return value */
4956 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
4961 * Inserts a new item in the listview control.
4964 * [I] HWND : window handle
4965 * [I] LPLVITEMA : item information
4968 * SUCCESS : new item index
4971 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4973 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4974 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4975 UINT uView = lStyle & LVS_TYPEMASK;
4976 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4981 LISTVIEW_ITEM *lpItem = NULL;
4983 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4985 if (lpLVItem != NULL)
4987 /* make sure it's not a subitem; cannot insert a subitem */
4988 if (lpLVItem->iSubItem == 0)
4990 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4993 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4994 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4996 /* insert item in listview control data structure */
4997 hdpaSubItems = DPA_Create(8);
4998 if (hdpaSubItems != NULL)
5000 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
5003 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
5004 && !(lStyle & LVS_OWNERDRAWFIXED)
5005 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
5007 /* Insert the item in the proper sort order based on the pszText
5008 member. See comments for LISTVIEW_InsertCompare() for greater detail */
5009 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
5010 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
5011 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
5012 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
5016 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
5021 /* manage item focus */
5022 if (lpLVItem->mask & LVIF_STATE)
5024 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
5025 if (lpLVItem->stateMask & LVIS_SELECTED)
5027 LISTVIEW_SetSelection(hwnd, nItem);
5029 else if (lpLVItem->stateMask & LVIS_FOCUSED)
5031 LISTVIEW_SetItemFocus(hwnd, nItem);
5035 /* send LVN_INSERTITEM notification */
5036 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
5037 nmlv.hdr.hwndFrom = hwnd;
5038 nmlv.hdr.idFrom = lCtrlId;
5039 nmlv.hdr.code = LVN_INSERTITEM;
5041 nmlv.lParam = lpItem->lParam;;
5042 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
5044 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
5046 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
5047 if (nItemWidth > infoPtr->nItemWidth)
5049 infoPtr->nItemWidth = nItemWidth;
5053 /* align items (set position of each item) */
5054 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5056 if (lStyle & LVS_ALIGNLEFT)
5058 LISTVIEW_AlignLeft(hwnd);
5062 LISTVIEW_AlignTop(hwnd);
5066 LISTVIEW_UpdateScroll(hwnd);
5067 /* refresh client area */
5068 InvalidateRect(hwnd, NULL, FALSE);
5077 /* free memory if unsuccessful */
5078 if ((nItem == -1) && (lpItem != NULL))
5080 COMCTL32_Free(lpItem);
5086 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
5090 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
5091 if (lvia.mask & LVIF_TEXT) {
5092 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
5093 lvia.pszText = LPSTR_TEXTCALLBACKA;
5095 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
5097 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
5098 if (lvia.mask & LVIF_TEXT) {
5099 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
5100 HeapFree(GetProcessHeap(),0,lvia.pszText);
5105 /* LISTVIEW_InsertItemW */
5109 * Redraws a range of items.
5112 * [I] HWND : window handle
5113 * [I] INT : first item
5114 * [I] INT : last item
5120 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
5122 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5123 BOOL bResult = FALSE;
5126 if (nFirst <= nLast)
5128 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
5130 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
5133 InvalidateRect(hwnd, &rc, FALSE);
5141 /* LISTVIEW_Scroll */
5145 * Sets the background color.
5148 * [I] HWND : window handle
5149 * [I] COLORREF : background color
5155 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
5157 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5159 infoPtr->clrBk = clrBk;
5160 InvalidateRect(hwnd, NULL, TRUE);
5165 /* LISTVIEW_SetBkImage */
5169 * Sets the callback mask. This mask will be used when the parent
5170 * window stores state information (some or all).
5173 * [I] HWND : window handle
5174 * [I] UINT : state mask
5180 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5182 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5184 infoPtr->uCallbackMask = uMask;
5191 * Sets the attributes of a header item.
5194 * [I] HWND : window handle
5195 * [I] INT : column index
5196 * [I] LPLVCOLUMNA : column attributes
5202 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5203 LPLVCOLUMNA lpColumn)
5205 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5206 BOOL bResult = FALSE;
5207 HDITEMA hdi, hdiget;
5209 if ((lpColumn != NULL) && (nColumn >= 0) &&
5210 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5212 /* initialize memory */
5213 ZeroMemory(&hdi, sizeof(HDITEMA));
5215 if (lpColumn->mask & LVCF_FMT)
5217 /* format member is valid */
5218 hdi.mask |= HDI_FORMAT;
5220 /* get current format first */
5221 hdiget.mask = HDI_FORMAT;
5222 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5223 /* preserve HDF_STRING if present */
5224 hdi.fmt = hdiget.fmt & HDF_STRING;
5226 /* set text alignment (leftmost column must be left-aligned) */
5229 hdi.fmt |= HDF_LEFT;
5233 if (lpColumn->fmt & LVCFMT_LEFT)
5235 hdi.fmt |= HDF_LEFT;
5237 else if (lpColumn->fmt & LVCFMT_RIGHT)
5239 hdi.fmt |= HDF_RIGHT;
5241 else if (lpColumn->fmt & LVCFMT_CENTER)
5243 hdi.fmt |= HDF_CENTER;
5247 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5249 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5252 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5254 hdi.fmt |= HDF_IMAGE;
5257 if (lpColumn->fmt & LVCFMT_IMAGE)
5259 hdi.fmt |= HDF_IMAGE;
5260 hdi.iImage = I_IMAGECALLBACK;
5264 if (lpColumn->mask & LVCF_WIDTH)
5266 hdi.mask |= HDI_WIDTH;
5267 hdi.cxy = lpColumn->cx;
5270 if (lpColumn->mask & LVCF_TEXT)
5272 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5273 hdi.pszText = lpColumn->pszText;
5274 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5275 hdi.fmt |= HDF_STRING;
5278 if (lpColumn->mask & LVCF_IMAGE)
5280 hdi.mask |= HDI_IMAGE;
5281 hdi.iImage = lpColumn->iImage;
5284 if (lpColumn->mask & LVCF_ORDER)
5286 hdi.mask |= HDI_ORDER;
5287 hdi.iOrder = lpColumn->iOrder;
5290 /* set header item attributes */
5291 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5297 /* LISTVIEW_SetColumnW */
5301 * Sets the column order array
5304 * [I] HWND : window handle
5305 * [I] INT : number of elements in column order array
5306 * [I] INT : pointer to column order array
5312 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
5314 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
5316 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
5327 * Sets the width of a column
5330 * [I] HWND : window handle
5331 * [I] INT : column index
5332 * [I] INT : column width
5338 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5340 LISTVIEW_INFO *infoPtr;
5345 /* set column width only if in report mode */
5346 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5347 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
5350 /* make sure we can get the listview info */
5351 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5353 if (!infoPtr->hwndHeader) /* make sure we have a header */
5356 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5357 * LVSCV_AUTOSIZE_USEHEADER (-2)
5362 hdi.mask = HDI_WIDTH;
5365 /* call header to update the column change */
5366 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5368 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5370 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5377 * Sets the extended listview style.
5380 * [I] HWND : window handle
5385 * SUCCESS : previous style
5388 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5390 LISTVIEW_INFO *infoPtr;
5393 /* make sure we can get the listview info */
5394 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5397 /* store previous style */
5398 dwOldStyle = infoPtr->dwExStyle;
5401 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5403 return (dwOldStyle);
5406 /* LISTVIEW_SetHotCursor */
5410 * Sets the hot item index.
5413 * [I] HWND : window handle
5417 * SUCCESS : previous hot item index
5418 * FAILURE : -1 (no hot item)
5420 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5422 LISTVIEW_INFO *infoPtr;
5425 /* make sure we can get the listview info */
5426 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5429 /* store previous index */
5430 iOldIndex = infoPtr->nHotItem;
5433 infoPtr->nHotItem = iIndex;
5440 * Sets the amount of time the cursor must hover over an item before it is selected.
5443 * [I] HWND : window handle
5444 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
5447 * Returns the previous hover time
5449 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
5451 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5452 DWORD oldHoverTime = infoPtr->dwHoverTime;
5454 infoPtr->dwHoverTime = dwHoverTime;
5456 return oldHoverTime;
5459 /* LISTVIEW_SetIconSpacing */
5466 * [I] HWND : window handle
5467 * [I] INT : image list type
5468 * [I] HIMAGELIST : image list handle
5471 * SUCCESS : old image list
5474 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5476 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5477 HIMAGELIST himlTemp = 0;
5482 himlTemp = infoPtr->himlNormal;
5483 infoPtr->himlNormal = himl;
5484 return (LRESULT)himlTemp;
5487 himlTemp = infoPtr->himlSmall;
5488 infoPtr->himlSmall = himl;
5489 return (LRESULT)himlTemp;
5492 himlTemp = infoPtr->himlState;
5493 infoPtr->himlState = himl;
5494 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5495 return (LRESULT)himlTemp;
5498 return (LRESULT)NULL;
5504 * Sets the attributes of an item.
5507 * [I] HWND : window handle
5508 * [I] LPLVITEM : item information
5514 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5516 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5517 BOOL bResult = FALSE;
5519 if (lpLVItem != NULL)
5521 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5523 if (lpLVItem->iSubItem == 0)
5525 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5529 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5538 /* LISTVIEW_SetItemW */
5542 * Preallocates memory.
5545 * [I] HWND : window handle
5546 * [I] INT : item count (projected number of items)
5547 * [I] DWORD : update flags
5553 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5555 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5557 FIXME("(%d %08lx)stub!\n", nItems, dwFlags);
5560 return LISTVIEW_DeleteAllItems (hwnd);
5562 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
5564 FIXME("LVS_OWNERDATA is set!\n");
5568 if (nItems > GETITEMCOUNT(infoPtr))
5571 FIXME("append items\n");
5574 else if (nItems < GETITEMCOUNT(infoPtr))
5577 while(nItems < GETITEMCOUNT(infoPtr)) {
5578 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
5588 * Sets the position of an item.
5591 * [I] HWND : window handle
5592 * [I] INT : item index
5593 * [I] INT : x coordinate
5594 * [I] INT : y coordinate
5600 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5601 INT nPosX, INT nPosY)
5603 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5604 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5605 LISTVIEW_ITEM *lpItem;
5607 BOOL bResult = FALSE;
5609 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5611 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5613 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5615 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5616 if (hdpaSubItems != NULL)
5618 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5622 lpItem->ptPosition.x = nPosX;
5623 lpItem->ptPosition.y = nPosY;
5632 /* LISTVIEW_SetItemPosition32 */
5636 * Sets the state of one or many items.
5639 * [I] HWND : window handle
5640 * [I]INT : item index
5641 * [I] LPLVITEM : item or subitem info
5647 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5649 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5650 BOOL bResult = FALSE;
5657 ZeroMemory(&lvItem, sizeof(LVITEMA));
5658 lvItem.mask = LVIF_STATE;
5659 lvItem.state = lpLVItem->state;
5660 lvItem.stateMask = lpLVItem->stateMask ;
5662 /* apply to all items */
5663 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5666 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5674 ZeroMemory(&lvItem, sizeof(LVITEMA));
5675 lvItem.mask = LVIF_STATE;
5676 lvItem.state = lpLVItem->state;
5677 lvItem.stateMask = lpLVItem->stateMask;
5678 lvItem.iItem = nItem;
5679 bResult = ListView_SetItemA(hwnd, &lvItem);
5687 * Sets the text of an item or subitem.
5690 * [I] HWND : window handle
5691 * [I] INT : item index
5692 * [I] LPLVITEMA : item or subitem info
5698 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5700 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5701 BOOL bResult = FALSE;
5704 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5706 ZeroMemory(&lvItem, sizeof(LVITEMA));
5707 lvItem.mask = LVIF_TEXT;
5708 lvItem.pszText = lpLVItem->pszText;
5709 lvItem.iItem = nItem;
5710 lvItem.iSubItem = lpLVItem->iSubItem;
5711 bResult = ListView_SetItemA(hwnd, &lvItem);
5717 /* LISTVIEW_SetItemTextW */
5721 * Set item index that marks the start of a multiple selection.
5724 * [I] HWND : window handle
5728 * Index number or -1 if there is no selection mark.
5730 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5732 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5733 INT nOldIndex = infoPtr->nSelectionMark;
5735 infoPtr->nSelectionMark = nIndex;
5742 * Sets the text background color.
5745 * [I] HWND : window handle
5746 * [I] COLORREF : text background color
5752 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5754 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5756 infoPtr->clrTextBk = clrTextBk;
5757 InvalidateRect(hwnd, NULL, TRUE);
5764 * Sets the text foreground color.
5767 * [I] HWND : window handle
5768 * [I] COLORREF : text color
5774 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5776 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5778 infoPtr->clrText = clrText;
5779 InvalidateRect(hwnd, NULL, TRUE);
5784 /* LISTVIEW_SetToolTips */
5785 /* LISTVIEW_SetUnicodeFormat */
5786 /* LISTVIEW_SetWorkAreas */
5790 * Callback internally used by LISTVIEW_SortItems()
5793 * [I] LPVOID : first LISTVIEW_ITEM to compare
5794 * [I] LPVOID : second LISTVIEW_ITEM to compare
5795 * [I] LPARAM : HWND of control
5798 * if first comes before second : negative
5799 * if first comes after second : positive
5800 * if first and second are equivalent : zero
5802 static INT WINAPI LISTVIEW_CallBackCompare(
5807 /* Forward the call to the client defined callback */
5809 HWND hwnd = (HWND)lParam;
5810 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5812 rv = (infoPtr->pfnCompare)( ((LISTVIEW_ITEM*) first)->lParam,
5813 ((LISTVIEW_ITEM*) second)->lParam, infoPtr->lParamSort );
5820 * Sorts the listview items.
5823 * [I] HWND : window handle
5824 * [I] WPARAM : application-defined value
5825 * [I] LPARAM : pointer to comparision callback
5831 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5833 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5835 LISTVIEW_ITEM *lpItem;
5839 if (!infoPtr || !infoPtr->hdpaItems)
5842 nCount = GETITEMCOUNT(infoPtr);
5843 /* if there are 0 or 1 items, there is no need to sort */
5846 sortList = DPA_Create(nCount);
5848 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5849 infoPtr->lParamSort = (LPARAM)wParam;
5851 /* append pointers one by one to sortList */
5852 for (i = 0; i < nCount; i++)
5854 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5855 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5856 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5859 /* sort the sortList */
5860 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5862 /* copy the pointers back */
5863 for (i = 0; i < nCount; i++)
5865 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5866 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5867 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5870 DPA_Destroy(sortList);
5876 /* LISTVIEW_SubItemHitTest */
5880 * Updates an items or rearranges the listview control.
5883 * [I] HWND : window handle
5884 * [I] INT : item index
5890 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5892 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5893 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5894 BOOL bResult = FALSE;
5897 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5901 /* rearrange with default alignment style */
5902 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5903 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5905 ListView_Arrange(hwnd, 0);
5909 /* get item bounding rectangle */
5910 rc.left = LVIR_BOUNDS;
5911 ListView_GetItemRect(hwnd, nItem, &rc);
5912 InvalidateRect(hwnd, &rc, TRUE);
5921 * Creates the listview control.
5924 * [I] HWND : window handle
5929 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5931 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5932 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5933 UINT uView = lpcs->style & LVS_TYPEMASK;
5936 /* initialize info pointer */
5937 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5939 /* determine the type of structures to use */
5940 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5941 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5942 if (infoPtr->notifyFormat != NFR_ANSI)
5944 FIXME("ANSI notify format is NOT used\n");
5947 /* initialize color information */
5948 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5949 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5950 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5952 /* set default values */
5953 infoPtr->uCallbackMask = 0;
5954 infoPtr->nFocusedItem = -1;
5955 infoPtr->nSelectionMark = -1;
5956 infoPtr->nHotItem = -1;
5957 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5958 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5959 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5960 infoPtr->hwndEdit = 0;
5961 infoPtr->pedititem = NULL;
5962 infoPtr->bDoEditLabel = FALSE;
5964 /* get default font (icon title) */
5965 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5966 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5967 infoPtr->hFont = infoPtr->hDefaultFont;
5970 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5971 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5972 0, 0, 0, 0, hwnd, (HMENU)0,
5973 lpcs->hInstance, NULL);
5975 /* set header font */
5976 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5979 if (uView == LVS_ICON)
5981 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5982 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5984 else if (uView == LVS_REPORT)
5986 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5988 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5991 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5992 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5996 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5997 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6000 /* display unsupported listview window styles */
6001 LISTVIEW_UnsupportedStyles(lpcs->style);
6003 /* allocate memory for the data structure */
6004 infoPtr->hdpaItems = DPA_Create(10);
6006 /* initialize size of items */
6007 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6008 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6010 /* initialize the hover time to -1(indicating the default system hover time) */
6011 infoPtr->dwHoverTime = -1;
6018 * Erases the background of the listview control.
6021 * [I] HWND : window handle
6022 * [I] WPARAM : device context handle
6023 * [I] LPARAM : not used
6029 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
6032 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6035 if (infoPtr->clrBk == CLR_NONE)
6037 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
6042 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
6043 GetClientRect(hwnd, &rc);
6044 FillRect((HDC)wParam, &rc, hBrush);
6045 DeleteObject(hBrush);
6054 * Retrieves the listview control font.
6057 * [I] HWND : window handle
6062 static LRESULT LISTVIEW_GetFont(HWND hwnd)
6064 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6066 return infoPtr->hFont;
6071 * Performs vertical scrolling.
6074 * [I] HWND : window handle
6075 * [I] INT : scroll code
6076 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6078 * [I] HWND : scrollbar control window handle
6083 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6086 SCROLLINFO scrollInfo;
6088 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6089 scrollInfo.cbSize = sizeof(SCROLLINFO);
6090 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6092 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6094 INT nOldScrollPos = scrollInfo.nPos;
6095 switch (nScrollCode)
6098 if (scrollInfo.nPos > scrollInfo.nMin)
6105 if (scrollInfo.nPos < scrollInfo.nMax)
6112 if (scrollInfo.nPos > scrollInfo.nMin)
6114 if (scrollInfo.nPos >= scrollInfo.nPage)
6116 scrollInfo.nPos -= scrollInfo.nPage;
6120 scrollInfo.nPos = scrollInfo.nMin;
6126 if (scrollInfo.nPos < scrollInfo.nMax)
6128 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6130 scrollInfo.nPos += scrollInfo.nPage;
6134 scrollInfo.nPos = scrollInfo.nMax;
6140 scrollInfo.nPos = nCurrentPos;
6141 if (scrollInfo.nPos > scrollInfo.nMax)
6142 scrollInfo.nPos=scrollInfo.nMax;
6144 if (scrollInfo.nPos < scrollInfo.nMin)
6145 scrollInfo.nPos=scrollInfo.nMin;
6150 if (nOldScrollPos != scrollInfo.nPos)
6152 scrollInfo.fMask = SIF_POS;
6153 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
6154 InvalidateRect(hwnd, NULL, TRUE);
6163 * Performs horizontal scrolling.
6166 * [I] HWND : window handle
6167 * [I] INT : scroll code
6168 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6170 * [I] HWND : scrollbar control window handle
6175 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6178 SCROLLINFO scrollInfo;
6180 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6181 scrollInfo.cbSize = sizeof(SCROLLINFO);
6182 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6184 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6186 INT nOldScrollPos = scrollInfo.nPos;
6188 switch (nScrollCode)
6191 if (scrollInfo.nPos > scrollInfo.nMin)
6198 if (scrollInfo.nPos < scrollInfo.nMax)
6205 if (scrollInfo.nPos > scrollInfo.nMin)
6207 if (scrollInfo.nPos >= scrollInfo.nPage)
6209 scrollInfo.nPos -= scrollInfo.nPage;
6213 scrollInfo.nPos = scrollInfo.nMin;
6219 if (scrollInfo.nPos < scrollInfo.nMax)
6221 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6223 scrollInfo.nPos += scrollInfo.nPage;
6227 scrollInfo.nPos = scrollInfo.nMax;
6233 scrollInfo.nPos = nCurrentPos;
6235 if (scrollInfo.nPos > scrollInfo.nMax)
6236 scrollInfo.nPos=scrollInfo.nMax;
6238 if (scrollInfo.nPos < scrollInfo.nMin)
6239 scrollInfo.nPos=scrollInfo.nMin;
6243 if (nOldScrollPos != scrollInfo.nPos)
6245 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6246 scrollInfo.fMask = SIF_POS;
6247 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6248 if(uView == LVS_REPORT)
6250 scrollInfo.fMask = SIF_POS;
6251 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6252 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6254 InvalidateRect(hwnd, NULL, TRUE);
6261 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
6263 INT gcWheelDelta = 0;
6264 UINT pulScrollLines = 3;
6265 SCROLLINFO scrollInfo;
6267 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6269 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
6270 gcWheelDelta -= wheelDelta;
6272 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6273 scrollInfo.cbSize = sizeof(SCROLLINFO);
6274 scrollInfo.fMask = SIF_POS | SIF_RANGE;
6281 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
6282 * should be fixed in the future.
6284 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6285 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
6289 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
6291 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6293 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
6294 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
6295 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
6301 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
6312 * [I] HWND : window handle
6313 * [I] INT : virtual key
6314 * [I] LONG : key data
6319 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6321 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6322 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6323 HWND hwndParent = GetParent(hwnd);
6324 NMLVKEYDOWN nmKeyDown;
6327 BOOL bRedraw = FALSE;
6329 /* send LVN_KEYDOWN notification */
6330 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6331 nmKeyDown.hdr.hwndFrom = hwnd;
6332 nmKeyDown.hdr.idFrom = nCtrlId;
6333 nmKeyDown.hdr.code = LVN_KEYDOWN;
6334 nmKeyDown.wVKey = nVirtualKey;
6335 nmKeyDown.flags = 0;
6336 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6339 nmh.hwndFrom = hwnd;
6340 nmh.idFrom = nCtrlId;
6342 switch (nVirtualKey)
6345 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6347 /* send NM_RETURN notification */
6348 nmh.code = NM_RETURN;
6349 ListView_Notify(hwndParent, nCtrlId, &nmh);
6351 /* send LVN_ITEMACTIVATE notification */
6352 nmh.code = LVN_ITEMACTIVATE;
6353 ListView_Notify(hwndParent, nCtrlId, &nmh);
6358 if (GETITEMCOUNT(infoPtr) > 0)
6365 if (GETITEMCOUNT(infoPtr) > 0)
6367 nItem = GETITEMCOUNT(infoPtr) - 1;
6372 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6376 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6380 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6384 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6396 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6398 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6399 if (bRedraw != FALSE)
6401 /* refresh client area */
6402 InvalidateRect(hwnd, NULL, TRUE);
6415 * [I] HWND : window handle
6420 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6422 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6423 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6426 TRACE("(hwnd=%x)\n", hwnd);
6428 /* send NM_KILLFOCUS notification */
6429 nmh.hwndFrom = hwnd;
6430 nmh.idFrom = nCtrlId;
6431 nmh.code = NM_KILLFOCUS;
6432 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6434 /* set window focus flag */
6435 infoPtr->bFocus = FALSE;
6437 /* NEED drawing optimization ; redraw the selected items */
6438 InvalidateRect(hwnd, NULL, FALSE);
6445 * Processes double click messages (left mouse button).
6448 * [I] HWND : window handle
6449 * [I] WORD : key flag
6450 * [I] WORD : x coordinate
6451 * [I] WORD : y coordinate
6456 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6459 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6461 LVHITTESTINFO htInfo;
6463 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6465 /* send NM_DBLCLK notification */
6466 nmh.hwndFrom = hwnd;
6467 nmh.idFrom = nCtrlId;
6468 nmh.code = NM_DBLCLK;
6469 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6471 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
6472 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6473 htInfo.pt.x = wPosX;
6474 htInfo.pt.y = wPosY;
6475 if(LISTVIEW_HitTest(hwnd, &htInfo) != -1)
6477 /* send LVN_ITEMACTIVATE notification */
6478 nmh.code = LVN_ITEMACTIVATE;
6479 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6487 * Processes mouse down messages (left mouse button).
6490 * [I] HWND : window handle
6491 * [I] WORD : key flag
6492 * [I] WORD : x coordinate
6493 * [I] WORD : y coordinate
6498 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6501 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6502 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6503 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6504 static BOOL bGroupSelect = TRUE;
6509 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6512 /* send NM_RELEASEDCAPTURE notification */
6513 nmh.hwndFrom = hwnd;
6514 nmh.idFrom = nCtrlId;
6515 nmh.code = NM_RELEASEDCAPTURE;
6516 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6518 if (infoPtr->bFocus == FALSE)
6523 /* set left button down flag */
6524 infoPtr->bLButtonDown = TRUE;
6526 ptPosition.x = wPosX;
6527 ptPosition.y = wPosY;
6528 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6529 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6531 if (lStyle & LVS_SINGLESEL)
6533 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
6534 && infoPtr->bDoEditLabel != TRUE)
6536 infoPtr->bDoEditLabel = TRUE;
6540 LISTVIEW_SetSelection(hwnd, nItem);
6545 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6547 if (bGroupSelect != FALSE)
6549 LISTVIEW_AddGroupSelection(hwnd, nItem);
6553 LISTVIEW_AddSelection(hwnd, nItem);
6556 else if (wKey & MK_CONTROL)
6558 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6560 else if (wKey & MK_SHIFT)
6562 LISTVIEW_SetGroupSelection(hwnd, nItem);
6566 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED
6567 && infoPtr->bDoEditLabel != TRUE)
6569 infoPtr->bDoEditLabel = TRUE;
6573 LISTVIEW_SetSelection(hwnd, nItem);
6581 /* remove all selections */
6582 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6585 InvalidateRect(hwnd, NULL, TRUE);
6592 * Processes mouse up messages (left mouse button).
6595 * [I] HWND : window handle
6596 * [I] WORD : key flag
6597 * [I] WORD : x coordinate
6598 * [I] WORD : y coordinate
6603 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6606 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6608 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6610 if (infoPtr->bLButtonDown != FALSE)
6612 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6615 /* send NM_CLICK notification */
6616 nmh.hwndFrom = hwnd;
6617 nmh.idFrom = nCtrlId;
6618 nmh.code = NM_CLICK;
6619 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6621 /* set left button flag */
6622 infoPtr->bLButtonDown = FALSE;
6624 if(infoPtr->bDoEditLabel)
6626 LVHITTESTINFO htInfo;
6628 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6629 htInfo.pt.x = wPosX;
6630 htInfo.pt.y = wPosY;
6631 nItem = LISTVIEW_HitTest(hwnd, &htInfo);
6632 if(nItem != -1 && htInfo.flags == LVHT_ONITEMLABEL)
6634 LISTVIEW_EditLabelA(hwnd, nItem);
6636 infoPtr->bDoEditLabel = FALSE;
6645 * Creates the listview control (called before WM_CREATE).
6648 * [I] HWND : window handle
6649 * [I] WPARAM : unhandled
6650 * [I] LPARAM : widow creation info
6655 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6657 LISTVIEW_INFO *infoPtr;
6659 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6661 /* allocate memory for info structure */
6662 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6663 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6664 if (infoPtr == NULL)
6666 ERR("could not allocate info memory!\n");
6670 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6672 ERR("pointer assignment error!\n");
6676 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6681 * Destroys the listview control (called after WM_DESTROY).
6684 * [I] HWND : window handle
6689 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6691 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6693 TRACE("(hwnd=%x)\n", hwnd);
6695 /* delete all items */
6696 LISTVIEW_DeleteAllItems(hwnd);
6698 /* destroy data structure */
6699 DPA_Destroy(infoPtr->hdpaItems);
6702 infoPtr->hFont = (HFONT)0;
6703 if (infoPtr->hDefaultFont)
6705 DeleteObject(infoPtr->hDefaultFont);
6708 /* free listview info pointer*/
6709 COMCTL32_Free(infoPtr);
6711 SetWindowLongA(hwnd, 0, 0);
6717 * Handles notifications from children.
6720 * [I] HWND : window handle
6721 * [I] INT : control identifier
6722 * [I] LPNMHDR : notification information
6727 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6731 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6733 /* handle notification from header control */
6734 if (lpnmh->code == HDN_ENDTRACKA)
6736 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6737 InvalidateRect(hwnd, NULL, TRUE);
6739 else if(lpnmh->code == HDN_ITEMCLICKA)
6741 /* Handle sorting by Header Column */
6743 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6744 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6746 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6747 nmlv.hdr.hwndFrom = hwnd;
6748 nmlv.hdr.idFrom = lCtrlId;
6749 nmlv.hdr.code = LVN_COLUMNCLICK;
6751 nmlv.iSubItem = pnmHeader->iItem;
6753 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6756 else if(lpnmh->code == NM_RELEASEDCAPTURE)
6758 /* Idealy this should be done in HDN_ENDTRACKA
6759 * but since SetItemBounds in Header.c is called after
6760 * the notification is sent, it is neccessary to handle the
6761 * update of the scroll bar here (Header.c works fine as it is,
6762 * no need to disturb it)
6764 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6765 LISTVIEW_UpdateScroll(hwnd);
6766 InvalidateRect(hwnd, NULL, TRUE);
6776 * Determines the type of structure to use.
6779 * [I] HWND : window handle of the sender
6780 * [I] HWND : listview window handle
6781 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6786 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6788 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6790 if (nCommand == NF_REQUERY)
6792 /* determine the type of structure to use */
6793 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6794 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6795 if (infoPtr->notifyFormat == NFR_UNICODE)
6797 FIXME("NO support for unicode structures");
6806 * Paints/Repaints the listview control.
6809 * [I] HWND : window handle
6810 * [I] HDC : device context handle
6815 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6819 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6823 hdc = BeginPaint(hwnd, &ps);
6824 LISTVIEW_Refresh(hwnd, hdc);
6825 EndPaint(hwnd, &ps);
6829 LISTVIEW_Refresh(hwnd, hdc);
6837 * Processes double click messages (right mouse button).
6840 * [I] HWND : window handle
6841 * [I] WORD : key flag
6842 * [I] WORD : x coordinate
6843 * [I] WORD : y coordinate
6848 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6851 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6854 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6856 /* send NM_RELEASEDCAPTURE notification */
6857 nmh.hwndFrom = hwnd;
6858 nmh.idFrom = nCtrlId;
6859 nmh.code = NM_RELEASEDCAPTURE;
6860 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6862 /* send NM_RDBLCLK notification */
6863 nmh.code = NM_RDBLCLK;
6864 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6871 * Processes mouse down messages (right mouse button).
6874 * [I] HWND : window handle
6875 * [I] WORD : key flag
6876 * [I] WORD : x coordinate
6877 * [I] WORD : y coordinate
6882 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6885 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6886 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6891 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6893 /* send NM_RELEASEDCAPTURE notification */
6894 nmh.hwndFrom = hwnd;
6895 nmh.idFrom = nCtrlId;
6896 nmh.code = NM_RELEASEDCAPTURE;
6897 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6899 /* make sure the listview control window has the focus */
6900 if (infoPtr->bFocus == FALSE)
6905 /* set right button down flag */
6906 infoPtr->bRButtonDown = TRUE;
6908 /* determine the index of the selected item */
6909 ptPosition.x = wPosX;
6910 ptPosition.y = wPosY;
6911 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6912 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6914 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6916 LISTVIEW_SetSelection(hwnd, nItem);
6921 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6929 * Processes mouse up messages (right mouse button).
6932 * [I] HWND : window handle
6933 * [I] WORD : key flag
6934 * [I] WORD : x coordinate
6935 * [I] WORD : y coordinate
6940 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6943 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6944 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6947 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6949 if (infoPtr->bRButtonDown != FALSE)
6955 /* Send NM_RClICK notification */
6956 ZeroMemory(&nmh, sizeof(NMHDR));
6957 nmh.hwndFrom = hwnd;
6958 nmh.idFrom = nCtrlId;
6959 nmh.code = NM_RCLICK;
6960 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6962 /* set button flag */
6963 infoPtr->bRButtonDown = FALSE;
6965 /* Change to screen coordinate for WM_CONTEXTMENU */
6966 ClientToScreen(hwnd, &pt);
6968 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
6969 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
6980 * [I] HWND : window handle
6981 * [I] HWND : window handle of previously focused window
6986 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6988 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6989 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6992 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
6994 /* send NM_SETFOCUS notification */
6995 nmh.hwndFrom = hwnd;
6996 nmh.idFrom = nCtrlId;
6997 nmh.code = NM_SETFOCUS;
6998 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7000 /* set window focus flag */
7001 infoPtr->bFocus = TRUE;
7003 InvalidateRect(hwnd, NULL, TRUE);
7014 * [I] HWND : window handle
7015 * [I] HFONT : font handle
7016 * [I] WORD : redraw flag
7021 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
7023 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7024 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7026 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
7030 infoPtr->hFont = infoPtr->hDefaultFont;
7034 infoPtr->hFont = hFont;
7037 if (uView == LVS_REPORT)
7039 /* set header font */
7040 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
7041 MAKELPARAM(fRedraw, 0));
7044 /* invalidate listview control client area */
7045 InvalidateRect(hwnd, NULL, TRUE);
7047 if (fRedraw != FALSE)
7057 * Message handling for WM_SETREDRAW.
7058 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
7061 * [I] HWND : window handle
7062 * [I] bRedraw: state of redraw flag
7065 * DefWinProc return value
7067 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
7070 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
7073 RedrawWindow(hwnd, NULL, 0,
7074 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
7081 * Resizes the listview control. This function processes WM_SIZE
7082 * messages. At this time, the width and height are not used.
7085 * [I] HWND : window handle
7086 * [I] WORD : new width
7087 * [I] WORD : new height
7092 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
7094 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7095 UINT uView = lStyle & LVS_TYPEMASK;
7097 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
7099 LISTVIEW_UpdateSize(hwnd);
7101 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
7103 if (lStyle & LVS_ALIGNLEFT)
7105 LISTVIEW_AlignLeft(hwnd);
7109 LISTVIEW_AlignTop(hwnd);
7113 LISTVIEW_UpdateScroll(hwnd);
7115 /* invalidate client area + erase background */
7116 InvalidateRect(hwnd, NULL, TRUE);
7123 * Sets the size information.
7126 * [I] HWND : window handle
7131 static VOID LISTVIEW_UpdateSize(HWND hwnd)
7133 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7134 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7135 UINT uView = lStyle & LVS_TYPEMASK;
7138 GetClientRect(hwnd, &rcList);
7139 infoPtr->rcList.left = 0;
7140 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
7141 infoPtr->rcList.top = 0;
7142 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
7144 if (uView == LVS_LIST)
7146 if ((lStyle & WS_HSCROLL) == 0)
7148 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
7149 if (infoPtr->rcList.bottom > nHScrollHeight)
7151 infoPtr->rcList.bottom -= nHScrollHeight;
7155 else if (uView == LVS_REPORT)
7162 Header_Layout(infoPtr->hwndHeader, &hl);
7163 if (!(LVS_NOCOLUMNHEADER & lStyle))
7165 infoPtr->rcList.top = max(wp.cy, 0);
7172 * Processes WM_STYLECHANGED messages.
7175 * [I] HWND : window handle
7176 * [I] WPARAM : window style type (normal or extended)
7177 * [I] LPSTYLESTRUCT : window style information
7182 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
7185 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7186 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
7187 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
7188 RECT rcList = infoPtr->rcList;
7190 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
7191 hwnd, wStyleType, lpss);
7193 if (wStyleType == GWL_STYLE)
7195 if (uOldView == LVS_REPORT)
7197 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
7200 if ((lpss->styleOld & WS_HSCROLL) != 0)
7202 ShowScrollBar(hwnd, SB_HORZ, FALSE);
7205 if ((lpss->styleOld & WS_VSCROLL) != 0)
7207 ShowScrollBar(hwnd, SB_VERT, FALSE);
7210 if (uNewView == LVS_ICON)
7212 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7213 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7214 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7215 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7216 if (lpss->styleNew & LVS_ALIGNLEFT)
7218 LISTVIEW_AlignLeft(hwnd);
7222 LISTVIEW_AlignTop(hwnd);
7225 else if (uNewView == LVS_REPORT)
7232 Header_Layout(infoPtr->hwndHeader, &hl);
7233 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
7235 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
7237 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7239 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7240 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7241 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7242 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7244 else if (uNewView == LVS_LIST)
7246 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7247 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7248 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7249 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7253 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7254 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7255 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7256 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7257 if (lpss->styleNew & LVS_ALIGNLEFT)
7259 LISTVIEW_AlignLeft(hwnd);
7263 LISTVIEW_AlignTop(hwnd);
7267 /* update the size of the client area */
7268 LISTVIEW_UpdateSize(hwnd);
7270 /* add scrollbars if needed */
7271 LISTVIEW_UpdateScroll(hwnd);
7273 /* invalidate client area + erase background */
7274 InvalidateRect(hwnd, NULL, TRUE);
7276 /* print the list of unsupported window styles */
7277 LISTVIEW_UnsupportedStyles(lpss->styleNew);
7280 /* If they change the view and we have an active edit control
7281 we will need to kill the control since the redraw will
7282 misplace the edit control.
7284 if (infoPtr->hwndEdit &&
7285 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
7286 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
7288 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7296 * Window procedure of the listview control.
7299 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
7302 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
7303 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
7304 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
7307 case LVM_APPROXIMATEVIEWRECT:
7308 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
7309 LOWORD(lParam), HIWORD(lParam));
7311 return LISTVIEW_Arrange(hwnd, (INT)wParam);
7313 /* case LVM_CREATEDRAGIMAGE: */
7315 case LVM_DELETEALLITEMS:
7316 return LISTVIEW_DeleteAllItems(hwnd);
7318 case LVM_DELETECOLUMN:
7319 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
7321 case LVM_DELETEITEM:
7322 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
7324 case LVM_EDITLABELW:
7325 case LVM_EDITLABELA:
7326 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
7328 case LVM_ENSUREVISIBLE:
7329 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
7332 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
7334 case LVM_GETBKCOLOR:
7335 return LISTVIEW_GetBkColor(hwnd);
7337 /* case LVM_GETBKIMAGE: */
7339 case LVM_GETCALLBACKMASK:
7340 return LISTVIEW_GetCallbackMask(hwnd);
7342 case LVM_GETCOLUMNA:
7343 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7345 /* case LVM_GETCOLUMNW: */
7347 case LVM_GETCOLUMNORDERARRAY:
7348 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7350 case LVM_GETCOLUMNWIDTH:
7351 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
7353 case LVM_GETCOUNTPERPAGE:
7354 return LISTVIEW_GetCountPerPage(hwnd);
7356 case LVM_GETEDITCONTROL:
7357 return LISTVIEW_GetEditControl(hwnd);
7359 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7360 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7363 return LISTVIEW_GetHeader(hwnd);
7365 /* case LVM_GETHOTCURSOR: */
7367 case LVM_GETHOTITEM:
7368 return LISTVIEW_GetHotItem(hwnd);
7370 case LVM_GETHOVERTIME:
7371 return LISTVIEW_GetHoverTime(hwnd);
7373 case LVM_GETIMAGELIST:
7374 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7376 /* case LVM_GETISEARCHSTRING: */
7379 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
7381 /* case LVM_GETITEMW: */
7383 case LVM_GETITEMCOUNT:
7384 return LISTVIEW_GetItemCount(hwnd);
7386 case LVM_GETITEMPOSITION:
7387 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7389 case LVM_GETITEMRECT:
7390 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7392 case LVM_GETITEMSPACING:
7393 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7395 case LVM_GETITEMSTATE:
7396 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7398 case LVM_GETITEMTEXTA:
7399 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7402 /* case LVM_GETITEMTEXTW: */
7404 case LVM_GETNEXTITEM:
7405 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7407 /* case LVM_GETNUMBEROFWORKAREAS: */
7410 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7412 case LVM_GETSELECTEDCOUNT:
7413 return LISTVIEW_GetSelectedCount(hwnd);
7415 case LVM_GETSELECTIONMARK:
7416 return LISTVIEW_GetSelectionMark(hwnd);
7418 case LVM_GETSTRINGWIDTHA:
7419 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7421 /* case LVM_GETSTRINGWIDTHW: */
7422 /* case LVM_GETSUBITEMRECT: */
7424 case LVM_GETTEXTBKCOLOR:
7425 return LISTVIEW_GetTextBkColor(hwnd);
7427 case LVM_GETTEXTCOLOR:
7428 return LISTVIEW_GetTextColor(hwnd);
7430 /* case LVM_GETTOOLTIPS: */
7432 case LVM_GETTOPINDEX:
7433 return LISTVIEW_GetTopIndex(hwnd);
7435 /* case LVM_GETUNICODEFORMAT: */
7437 case LVM_GETVIEWRECT:
7438 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7440 /* case LVM_GETWORKAREAS: */
7443 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7445 case LVM_INSERTCOLUMNA:
7446 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7448 case LVM_INSERTCOLUMNW:
7449 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7451 case LVM_INSERTITEMA:
7452 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7454 case LVM_INSERTITEMW:
7455 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7457 case LVM_REDRAWITEMS:
7458 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7460 /* case LVM_SCROLL: */
7461 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7463 case LVM_SETBKCOLOR:
7464 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7466 /* case LVM_SETBKIMAGE: */
7468 case LVM_SETCALLBACKMASK:
7469 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7471 case LVM_SETCOLUMNA:
7472 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7474 case LVM_SETCOLUMNW:
7475 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7478 case LVM_SETCOLUMNORDERARRAY:
7479 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7481 case LVM_SETCOLUMNWIDTH:
7482 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
7484 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7485 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7487 /* case LVM_SETHOTCURSOR: */
7489 case LVM_SETHOTITEM:
7490 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7492 case LVM_SETHOVERTIME:
7493 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
7495 /* case LVM_SETICONSPACING: */
7497 case LVM_SETIMAGELIST:
7498 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7501 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7503 /* case LVM_SETITEMW: */
7505 case LVM_SETITEMCOUNT:
7506 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7508 case LVM_SETITEMPOSITION:
7509 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7510 (INT)HIWORD(lParam));
7512 /* case LVM_SETITEMPOSITION32: */
7514 case LVM_SETITEMSTATE:
7515 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7517 case LVM_SETITEMTEXTA:
7518 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7520 /* case LVM_SETITEMTEXTW: */
7522 case LVM_SETSELECTIONMARK:
7523 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7525 case LVM_SETTEXTBKCOLOR:
7526 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7528 case LVM_SETTEXTCOLOR:
7529 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7531 /* case LVM_SETTOOLTIPS: */
7532 /* case LVM_SETUNICODEFORMAT: */
7533 /* case LVM_SETWORKAREAS: */
7536 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7538 /* case LVM_SUBITEMHITTEST: */
7541 return LISTVIEW_Update(hwnd, (INT)wParam);
7545 return LISTVIEW_Command(hwnd, wParam, lParam);
7548 return LISTVIEW_Create(hwnd, wParam, lParam);
7551 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7554 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7557 return LISTVIEW_GetFont(hwnd);
7560 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7561 (INT)HIWORD(wParam), (HWND)lParam);
7564 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7567 return LISTVIEW_KillFocus(hwnd);
7569 case WM_LBUTTONDBLCLK:
7570 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7573 case WM_LBUTTONDOWN:
7574 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7577 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7580 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
7583 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
7586 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7589 return LISTVIEW_NCDestroy(hwnd);
7592 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7594 case WM_NOTIFYFORMAT:
7595 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7598 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7600 case WM_RBUTTONDBLCLK:
7601 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7604 case WM_RBUTTONDOWN:
7605 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7609 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7613 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7616 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7619 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
7622 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7624 case WM_STYLECHANGED:
7625 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7627 /* case WM_TIMER: */
7630 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7631 (INT)HIWORD(wParam), (HWND)lParam);
7634 if (wParam & (MK_SHIFT | MK_CONTROL))
7635 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
7636 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
7638 /* case WM_WININICHANGE: */
7641 if (uMsg >= WM_USER)
7643 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7647 /* call default window procedure */
7648 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7656 * Registers the window class.
7664 VOID LISTVIEW_Register(void)
7668 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7669 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7670 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7671 wndClass.cbClsExtra = 0;
7672 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7673 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7674 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7675 wndClass.lpszClassName = WC_LISTVIEWA;
7676 RegisterClassA(&wndClass);
7681 * Unregisters the window class.
7689 VOID LISTVIEW_Unregister(void)
7691 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
7696 * Handle any WM_COMMAND messages
7702 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
7704 switch (HIWORD(wParam))
7709 * Adjust the edit window size
7712 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7713 HDC hdc = GetDC(infoPtr->hwndEdit);
7714 HFONT hFont, hOldFont = 0;
7719 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
7720 GetWindowRect(infoPtr->hwndEdit, &rect);
7722 /* Select font to get the right dimension of the string */
7723 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
7726 hOldFont = SelectObject(hdc, hFont);
7729 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
7731 TEXTMETRICA textMetric;
7733 /* Add Extra spacing for the next character */
7734 GetTextMetricsA(hdc, &textMetric);
7735 sz.cx += (textMetric.tmMaxCharWidth * 2);
7743 rect.bottom - rect.top,
7744 SWP_DRAWFRAME|SWP_NOMOVE);
7748 SelectObject(hdc, hOldFont);
7751 ReleaseDC(hwnd, hdc);
7757 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
7766 * Subclassed edit control windproc function
7772 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
7773 WPARAM wParam, LPARAM lParam)
7775 BOOL cancel = FALSE;
7776 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
7777 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
7778 static BOOL bIgnoreKillFocus = FALSE;
7782 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
7785 if(bIgnoreKillFocus)
7793 WNDPROC editProc = einfo->EditWndProc;
7794 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
7795 COMCTL32_Free(einfo);
7796 infoPtr->pedititem = NULL;
7797 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
7801 if (VK_ESCAPE == (INT)wParam)
7807 else if (VK_RETURN == (INT)wParam)
7811 return CallWindowProcA(einfo->EditWndProc, hwnd,
7812 uMsg, wParam, lParam);
7815 if (einfo->EditLblCb)
7817 char *buffer = NULL;
7822 int len = 1 + GetWindowTextLengthA(hwnd);
7826 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
7828 GetWindowTextA(hwnd, buffer, len);
7832 /* Processing LVN_ENDLABELEDIT message could kill the focus */
7833 /* eg. Using a messagebox */
7834 bIgnoreKillFocus = TRUE;
7835 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
7838 COMCTL32_Free(buffer);
7840 einfo->EditLblCb = NULL;
7841 bIgnoreKillFocus = FALSE;
7844 SendMessageA(hwnd, WM_CLOSE, 0, 0);
7851 * Creates a subclassed edit cotrol
7857 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
7858 INT width, INT height, HWND parent, HINSTANCE hinst,
7859 EditlblCallback EditLblCb, DWORD param)
7865 TEXTMETRICA textMetric;
7866 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
7868 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
7871 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
7872 hdc = GetDC(parent);
7874 /* Select the font to get appropriate metric dimensions */
7875 if(infoPtr->hFont != 0)
7877 hOldFont = SelectObject(hdc, infoPtr->hFont);
7880 /*Get String Lenght in pixels */
7881 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
7883 /*Add Extra spacing for the next character */
7884 GetTextMetricsA(hdc, &textMetric);
7885 sz.cx += (textMetric.tmMaxCharWidth * 2);
7887 if(infoPtr->hFont != 0)
7889 SelectObject(hdc, hOldFont);
7892 ReleaseDC(parent, hdc);
7893 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
7894 parent, 0, hinst, 0)))
7896 COMCTL32_Free(infoPtr->pedititem);
7900 infoPtr->pedititem->param = param;
7901 infoPtr->pedititem->EditLblCb = EditLblCb;
7902 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
7903 GWL_WNDPROC, (LONG) EditLblWndProc);
7905 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);