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);
141 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
143 /*************************************************************************
144 * LISTVIEW_UpdateHeaderSize [Internal]
146 * Function to resize the header control
149 * hwnd [I] handle to a window
150 * nNewScrollPos [I] Scroll Pos to Set
157 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
159 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
163 GetWindowRect(infoPtr->hwndHeader, &winRect);
164 point[0].x = winRect.left;
165 point[0].y = winRect.top;
166 point[1].x = winRect.right;
167 point[1].y = winRect.bottom;
169 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
170 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
171 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
173 SetWindowPos(infoPtr->hwndHeader,0,
174 point[0].x,point[0].y,point[1].x,point[1].y,
175 SWP_NOZORDER | SWP_NOACTIVATE);
180 * Update the scrollbars. This functions should be called whenever
181 * the content, size or view changes.
184 * [I] HWND : window handle
189 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
191 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
192 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
193 UINT uView = lStyle & LVS_TYPEMASK;
194 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
195 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
196 SCROLLINFO scrollInfo;
198 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
199 scrollInfo.cbSize = sizeof(SCROLLINFO);
201 if (uView == LVS_LIST)
203 /* update horizontal scrollbar */
205 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
206 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
207 INT nNumOfItems = GETITEMCOUNT(infoPtr);
209 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
210 if((nNumOfItems % nCountPerColumn) == 0)
214 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
215 scrollInfo.nPage = nCountPerRow;
216 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
217 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
219 else if (uView == LVS_REPORT)
221 /* update vertical scrollbar */
223 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
224 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
225 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
226 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
227 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
229 /* update horizontal scrollbar */
230 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
231 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
232 || GETITEMCOUNT(infoPtr) == 0)
237 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
238 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
239 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
240 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
242 /* Update the Header Control */
243 scrollInfo.fMask = SIF_POS;
244 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
245 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
252 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
254 INT nViewWidth = rcView.right - rcView.left;
255 INT nViewHeight = rcView.bottom - rcView.top;
257 /* Update Horizontal Scrollbar */
258 scrollInfo.fMask = SIF_POS;
259 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
260 || GETITEMCOUNT(infoPtr) == 0)
264 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
266 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
267 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
268 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
270 /* Update Vertical Scrollbar */
271 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
272 scrollInfo.fMask = SIF_POS;
273 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
274 || GETITEMCOUNT(infoPtr) == 0)
278 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
280 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
281 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
282 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
289 * Prints a message for unsupported window styles.
290 * A kind of TODO list for window styles.
293 * [I] LONG : window style
298 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
300 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
302 FIXME(" LVS_EDITLABELS\n");
305 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
307 FIXME(" LVS_NOLABELWRAP\n");
310 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
312 FIXME(" LVS_NOSCROLL\n");
315 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
317 FIXME(" LVS_NOSORTHEADER\n");
320 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
322 FIXME(" LVS_OWNERDRAWFIXED\n");
325 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
327 FIXME(" LVS_SHAREIMAGELISTS\n");
330 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
332 FIXME(" LVS_SORTASCENDING\n");
335 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
337 FIXME(" LVS_SORTDESCENDING\n");
343 * Aligns the items with the top edge of the window.
346 * [I] HWND : window handle
351 static VOID LISTVIEW_AlignTop(HWND hwnd)
353 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
354 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
355 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
360 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
362 ZeroMemory(&ptItem, sizeof(POINT));
363 ZeroMemory(&rcView, sizeof(RECT));
365 if (nListWidth > infoPtr->nItemWidth)
367 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
369 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
372 ptItem.y += infoPtr->nItemHeight;
375 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
376 ptItem.x += infoPtr->nItemWidth;
377 rcView.right = max(rcView.right, ptItem.x);
380 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
384 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
386 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
387 ptItem.y += infoPtr->nItemHeight;
390 rcView.right = infoPtr->nItemWidth;
391 rcView.bottom = ptItem.y;
394 LISTVIEW_SetViewRect(hwnd, &rcView);
400 * Aligns the items with the left edge of the window.
403 * [I] HWND : window handle
408 static VOID LISTVIEW_AlignLeft(HWND hwnd)
410 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
411 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
412 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
417 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
419 ZeroMemory(&ptItem, sizeof(POINT));
420 ZeroMemory(&rcView, sizeof(RECT));
422 if (nListHeight > infoPtr->nItemHeight)
424 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
426 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
429 ptItem.x += infoPtr->nItemWidth;
432 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
433 ptItem.y += infoPtr->nItemHeight;
434 rcView.bottom = max(rcView.bottom, ptItem.y);
437 rcView.right = ptItem.x + infoPtr->nItemWidth;
441 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
443 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
444 ptItem.x += infoPtr->nItemWidth;
447 rcView.bottom = infoPtr->nItemHeight;
448 rcView.right = ptItem.x;
451 LISTVIEW_SetViewRect(hwnd, &rcView);
457 * Set the bounding rectangle of all the items.
460 * [I] HWND : window handle
461 * [I] LPRECT : bounding rectangle
467 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
469 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
470 BOOL bResult = FALSE;
472 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
473 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
475 if (lprcView != NULL)
478 infoPtr->rcView.left = lprcView->left;
479 infoPtr->rcView.top = lprcView->top;
480 infoPtr->rcView.right = lprcView->right;
481 infoPtr->rcView.bottom = lprcView->bottom;
489 * Retrieves the bounding rectangle of all the items.
492 * [I] HWND : window handle
493 * [O] LPRECT : bounding rectangle
499 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
501 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
502 BOOL bResult = FALSE;
505 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
507 if (lprcView != NULL)
509 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
510 if (bResult != FALSE)
512 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
513 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
514 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
515 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
518 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
519 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
527 * Retrieves the subitem pointer associated with the subitem index.
530 * [I] HDPA : DPA handle for a specific item
531 * [I] INT : index of subitem
534 * SUCCESS : subitem pointer
537 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
540 LISTVIEW_SUBITEM *lpSubItem;
543 for (i = 1; i < hdpaSubItems->nItemCount; i++)
545 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
546 if (lpSubItem != NULL)
548 if (lpSubItem->iSubItem == nSubItem)
560 * Calculates the width of an item.
563 * [I] HWND : window handle
564 * [I] LONG : window style
567 * Returns item width.
569 static INT LISTVIEW_GetItemWidth(HWND hwnd)
571 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
572 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
573 INT nHeaderItemCount;
579 TRACE("(hwnd=%x)\n", hwnd);
581 if (uView == LVS_ICON)
583 nItemWidth = infoPtr->iconSpacing.cx;
585 else if (uView == LVS_REPORT)
587 /* calculate width of header */
588 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
589 for (i = 0; i < nHeaderItemCount; i++)
591 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
593 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
599 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
601 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
602 nItemWidth = max(nItemWidth, nLabelWidth);
605 /* default label size */
606 if (GETITEMCOUNT(infoPtr) == 0)
608 nItemWidth = DEFAULT_COLUMN_WIDTH;
614 nItemWidth = DEFAULT_LABEL_WIDTH;
619 nItemWidth += WIDTH_PADDING;
621 if (infoPtr->himlSmall != NULL)
623 nItemWidth += infoPtr->iconSize.cx;
626 if (infoPtr->himlState != NULL)
628 nItemWidth += infoPtr->iconSize.cx;
635 /* nItemWidth Cannot be Zero */
643 * Calculates the width of a specific item.
646 * [I] HWND : window handle
650 * Returns the width of an item width a specified string.
652 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
654 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
655 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
656 INT nHeaderItemCount;
661 TRACE("(hwnd=%x)\n", hwnd);
663 if (uView == LVS_ICON)
665 nItemWidth = infoPtr->iconSpacing.cx;
667 else if (uView == LVS_REPORT)
669 /* calculate width of header */
670 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
671 for (i = 0; i < nHeaderItemCount; i++)
673 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
675 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
681 /* get width of string */
682 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
684 /* default label size */
685 if (GETITEMCOUNT(infoPtr) == 0)
687 nItemWidth = DEFAULT_COLUMN_WIDTH;
693 nItemWidth = DEFAULT_LABEL_WIDTH;
698 nItemWidth += WIDTH_PADDING;
700 if (infoPtr->himlSmall != NULL)
702 nItemWidth += infoPtr->iconSize.cx;
705 if (infoPtr->himlState != NULL)
707 nItemWidth += infoPtr->iconSize.cx;
718 * Calculates the height of an item.
721 * [I] HWND : window handle
722 * [I] LONG : window style
725 * Returns item height.
727 static INT LISTVIEW_GetItemHeight(HWND hwnd)
729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
730 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
733 if (uView == LVS_ICON)
735 nItemHeight = infoPtr->iconSpacing.cy;
740 HDC hdc = GetDC(hwnd);
741 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
742 GetTextMetricsA(hdc, &tm);
743 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
744 SelectObject(hdc, hOldFont);
745 ReleaseDC(hwnd, hdc);
753 * Adds a block of selections.
756 * [I] HWND : window handle
757 * [I] INT : item index
762 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
764 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
765 INT nFirst = min(infoPtr->nSelectionMark, nItem);
766 INT nLast = max(infoPtr->nSelectionMark, nItem);
770 lvItem.state = LVIS_SELECTED;
771 lvItem.stateMask= LVIS_SELECTED;
773 for (i = nFirst; i <= nLast; i++)
775 ListView_SetItemState(hwnd, i, &lvItem);
778 LISTVIEW_SetItemFocus(hwnd, nItem);
779 infoPtr->nSelectionMark = nItem;
784 * Adds a single selection.
787 * [I] HWND : window handle
788 * [I] INT : item index
793 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
795 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
798 lvItem.state = LVIS_SELECTED;
799 lvItem.stateMask= LVIS_SELECTED;
801 ListView_SetItemState(hwnd, nItem, &lvItem);
803 LISTVIEW_SetItemFocus(hwnd, nItem);
804 infoPtr->nSelectionMark = nItem;
809 * Selects or unselects an item.
812 * [I] HWND : window handle
813 * [I] INT : item index
819 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
821 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
825 lvItem.stateMask= LVIS_SELECTED;
827 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
830 ListView_SetItemState(hwnd, nItem, &lvItem);
835 lvItem.state = LVIS_SELECTED;
836 ListView_SetItemState(hwnd, nItem, &lvItem);
840 LISTVIEW_SetItemFocus(hwnd, nItem);
841 infoPtr->nSelectionMark = nItem;
848 * Selects items based on view coorddiantes.
851 * [I] HWND : window handle
852 * [I] RECT : selection rectangle
857 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
859 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
864 lvItem.stateMask = LVIS_SELECTED;
866 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
868 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
869 if (PtInRect(&rcSelRect, ptItem) != FALSE)
871 lvItem.state = LVIS_SELECTED;
878 ListView_SetItemState(hwnd, i, &lvItem);
884 * Sets a single group selection.
887 * [I] HWND : window handle
888 * [I] INT : item index
893 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
895 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
896 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
899 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
902 INT nFirst = min(infoPtr->nSelectionMark, nItem);
903 INT nLast = max(infoPtr->nSelectionMark, nItem);
904 lvItem.stateMask = LVIS_SELECTED;
906 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
908 if ((i < nFirst) || (i > nLast))
914 lvItem.state = LVIS_SELECTED;
917 ListView_SetItemState(hwnd, i, &lvItem);
925 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
926 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
927 rcSel.left = min(ptSelMark.x, ptItem.x);
928 rcSel.top = min(ptSelMark.y, ptItem.y);
929 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
930 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
931 LISTVIEW_SetSelectionRect(hwnd, rcSel);
934 LISTVIEW_SetItemFocus(hwnd, nItem);
939 * Manages the item focus.
942 * [I] HWND : window handle
943 * [I] INT : item index
946 * TRUE : focused item changed
947 * FALSE : focused item has NOT changed
949 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
951 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
952 BOOL bResult = FALSE;
955 if (infoPtr->nFocusedItem != nItem)
958 ZeroMemory(&lvItem, sizeof(LVITEMA));
959 lvItem.stateMask = LVIS_FOCUSED;
960 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
962 lvItem.state = LVIS_FOCUSED;
963 lvItem.stateMask = LVIS_FOCUSED;
964 ListView_SetItemState(hwnd, nItem, &lvItem);
966 infoPtr->nFocusedItem = nItem;
967 ListView_EnsureVisible(hwnd, nItem, FALSE);
975 * Sets a single selection.
978 * [I] HWND : window handle
979 * [I] INT : item index
984 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
986 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
991 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
994 if (nItem < GETITEMCOUNT(infoPtr))
996 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
999 ZeroMemory(&lvItem, sizeof(LVITEMA));
1000 lvItem.stateMask = LVIS_FOCUSED;
1001 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1003 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
1004 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1005 ListView_SetItemState(hwnd, nItem, &lvItem);
1007 infoPtr->nFocusedItem = nItem;
1008 infoPtr->nSelectionMark = nItem;
1013 * Set selection(s) with keyboard.
1016 * [I] HWND : window handle
1017 * [I] INT : item index
1020 * SUCCESS : TRUE (needs to be repainted)
1021 * FAILURE : FALSE (nothing has changed)
1023 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1025 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1026 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1027 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1028 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1029 BOOL bResult = FALSE;
1031 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1033 if (lStyle & LVS_SINGLESEL)
1036 LISTVIEW_SetSelection(hwnd, nItem);
1037 ListView_EnsureVisible(hwnd, nItem, FALSE);
1044 LISTVIEW_SetGroupSelection(hwnd, nItem);
1048 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1053 LISTVIEW_SetSelection(hwnd, nItem);
1054 ListView_EnsureVisible(hwnd, nItem, FALSE);
1064 * Called when the mouse is being actively tracked and has hovered for a specified
1068 * [I] HWND : window handle
1069 * [I] wParam : key indicator
1070 * [I] lParam : mouse position
1073 * 0 if the message was processed, non-zero if there was an error
1076 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1077 * over the item for a certain period of time.
1080 static LRESULT LISTVIEW_MouseHover(hwnd, wParam, lParam)
1082 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1085 pt.x = (INT)LOWORD(lParam);
1086 pt.y = (INT)HIWORD(lParam);
1088 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1089 /* select the item under the cursor */
1090 LISTVIEW_MouseSelection(hwnd, pt);
1098 * Called whenever WM_MOUSEMOVE is recieved.
1101 * [I] HWND : window handle
1102 * [I] wParam : key indicators
1103 * [I] lParam : cursor position
1106 * 0 if the message is processed, non-zero if there was an error
1108 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1110 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1111 TRACKMOUSEEVENT trackinfo;
1113 /* see if we are supposed to be tracking mouse hovering */
1114 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1115 /* fill in the trackinfo struct */
1116 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1117 trackinfo.dwFlags = TME_QUERY;
1118 trackinfo.hwndTrack = hwnd;
1119 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1121 /* see if we are already tracking this hwnd */
1122 _TrackMouseEvent(&trackinfo);
1124 if(!(trackinfo.dwFlags & TME_HOVER)) {
1125 trackinfo.dwFlags = TME_HOVER;
1127 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1128 _TrackMouseEvent(&trackinfo);
1137 * Selects an item based on coordinates.
1140 * [I] HWND : window handle
1141 * [I] POINT : mouse click ccordinates
1144 * SUCCESS : item index
1147 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1149 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1153 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1155 rcItem.left = LVIR_SELECTBOUNDS;
1156 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1158 if (PtInRect(&rcItem, pt) != FALSE)
1170 * Removes all selection states.
1173 * [I] HWND : window handle
1174 * [I] INT : item index
1180 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1186 lvItem.stateMask = LVIS_SELECTED;
1188 for (i = nFirst; i <= nLast; i++)
1190 ListView_SetItemState(hwnd, i, &lvItem);
1199 * [IO] HDPA : dynamic pointer array handle
1200 * [I] INT : column index (subitem index)
1206 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1208 BOOL bResult = TRUE;
1212 for (i = 0; i < hdpaItems->nItemCount; i++)
1214 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1215 if (hdpaSubItems != NULL)
1217 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1229 * Removes a subitem at a given position.
1232 * [IO] HDPA : dynamic pointer array handle
1233 * [I] INT : subitem index
1239 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1241 LISTVIEW_SUBITEM *lpSubItem;
1244 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1246 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1247 if (lpSubItem != NULL)
1249 if (lpSubItem->iSubItem == nSubItem)
1252 if ((lpSubItem->pszText != NULL) &&
1253 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1255 COMCTL32_Free(lpSubItem->pszText);
1259 COMCTL32_Free(lpSubItem);
1261 /* free dpa memory */
1262 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1267 else if (lpSubItem->iSubItem > nSubItem)
1279 * Compares the item information.
1282 * [I] LISTVIEW_ITEM *: destination item
1283 * [I] LPLVITEM : source item
1286 * SUCCCESS : TRUE (EQUAL)
1287 * FAILURE : FALSE (NOT EQUAL)
1289 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1293 if ((lpItem != NULL) && (lpLVItem != NULL))
1295 if (lpLVItem->mask & LVIF_STATE)
1297 if ((lpItem->state & lpLVItem->stateMask) !=
1298 (lpLVItem->state & lpLVItem->stateMask))
1300 uChanged |= LVIF_STATE;
1304 if (lpLVItem->mask & LVIF_IMAGE)
1306 if (lpItem->iImage != lpLVItem->iImage)
1308 uChanged |= LVIF_IMAGE;
1312 if (lpLVItem->mask & LVIF_PARAM)
1314 if (lpItem->lParam != lpLVItem->lParam)
1316 uChanged |= LVIF_PARAM;
1320 if (lpLVItem->mask & LVIF_INDENT)
1322 if (lpItem->iIndent != lpLVItem->iIndent)
1324 uChanged |= LVIF_INDENT;
1328 if (lpLVItem->mask & LVIF_TEXT)
1330 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1332 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1334 uChanged |= LVIF_TEXT;
1339 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1341 uChanged |= LVIF_TEXT;
1345 if (lpLVItem->pszText)
1347 if (lpItem->pszText)
1349 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1351 uChanged |= LVIF_TEXT;
1356 uChanged |= LVIF_TEXT;
1361 if (lpItem->pszText)
1363 uChanged |= LVIF_TEXT;
1375 * Initializes item attributes.
1378 * [I] HWND : window handle
1379 * [O] LISTVIEW_ITEM *: destination item
1380 * [I] LPLVITEM : source item
1386 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1389 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1390 BOOL bResult = FALSE;
1392 if ((lpItem != NULL) && (lpLVItem != NULL))
1396 if (lpLVItem->mask & LVIF_STATE)
1398 lpItem->state &= ~lpLVItem->stateMask;
1399 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1402 if (lpLVItem->mask & LVIF_IMAGE)
1404 lpItem->iImage = lpLVItem->iImage;
1407 if (lpLVItem->mask & LVIF_PARAM)
1409 lpItem->lParam = lpLVItem->lParam;
1412 if (lpLVItem->mask & LVIF_INDENT)
1414 lpItem->iIndent = lpLVItem->iIndent;
1417 if (lpLVItem->mask & LVIF_TEXT)
1419 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1421 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1426 if ((lpItem->pszText != NULL) &&
1427 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1429 COMCTL32_Free(lpItem->pszText);
1432 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1436 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1438 lpItem->pszText = NULL;
1441 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1451 * Initializes subitem attributes.
1453 * NOTE: The documentation specifies that the operation fails if the user
1454 * tries to set the indent of a subitem.
1457 * [I] HWND : window handle
1458 * [O] LISTVIEW_SUBITEM *: destination subitem
1459 * [I] LPLVITEM : source subitem
1465 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1468 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1469 BOOL bResult = FALSE;
1471 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1473 if (!(lpLVItem->mask & LVIF_INDENT))
1476 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1478 lpSubItem->iSubItem = lpLVItem->iSubItem;
1480 if (lpLVItem->mask & LVIF_IMAGE)
1482 lpSubItem->iImage = lpLVItem->iImage;
1485 if (lpLVItem->mask & LVIF_TEXT)
1487 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1489 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1494 if ((lpSubItem->pszText != NULL) &&
1495 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1497 COMCTL32_Free(lpSubItem->pszText);
1500 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1504 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1506 lpSubItem->pszText = NULL;
1509 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1520 * Adds a subitem at a given position (column index).
1523 * [I] HWND : window handle
1524 * [I] LPLVITEM : new subitem atttributes
1530 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1532 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1533 LISTVIEW_SUBITEM *lpSubItem = NULL;
1534 BOOL bResult = FALSE;
1536 INT nPosition, nItem;
1538 if (lpLVItem != NULL)
1540 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1541 if (hdpaSubItems != NULL)
1543 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1544 if (lpSubItem != NULL)
1546 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1548 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1549 lpSubItem->iSubItem);
1550 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1560 /* cleanup if unsuccessful */
1561 if ((bResult == FALSE) && (lpSubItem != NULL))
1563 COMCTL32_Free(lpSubItem);
1571 * Finds the dpa insert position (array index).
1574 * [I] HWND : window handle
1575 * [I] INT : subitem index
1581 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1583 LISTVIEW_SUBITEM *lpSubItem;
1586 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1588 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1589 if (lpSubItem != NULL)
1591 if (lpSubItem->iSubItem > nSubItem)
1598 return hdpaSubItems->nItemCount;
1603 * Retrieves a listview subitem at a given position (column index).
1606 * [I] HWND : window handle
1607 * [I] INT : subitem index
1613 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1615 LISTVIEW_SUBITEM *lpSubItem;
1618 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1620 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1621 if (lpSubItem != NULL)
1623 if (lpSubItem->iSubItem == nSubItem)
1627 else if (lpSubItem->iSubItem > nSubItem)
1639 * Sets item attributes.
1642 * [I] HWND : window handle
1643 * [I] LPLVITEM : new item atttributes
1649 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1651 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1652 BOOL bResult = FALSE;
1654 LISTVIEW_ITEM *lpItem;
1656 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1657 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1659 UINT uView = lStyle & LVS_TYPEMASK;
1662 if (lpLVItem != NULL)
1664 if (lpLVItem->iSubItem == 0)
1666 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1667 if (hdpaSubItems != NULL)
1669 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1672 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1673 nmlv.hdr.hwndFrom = hwnd;
1674 nmlv.hdr.idFrom = lCtrlId;
1675 nmlv.hdr.code = LVN_ITEMCHANGING;
1676 nmlv.lParam = lpItem->lParam;
1677 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1680 if (uChanged & LVIF_STATE)
1682 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1683 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1686 nmlv.uChanged = uChanged;
1687 nmlv.iItem = lpLVItem->iItem;
1688 nmlv.lParam = lpItem->lParam;
1689 /* send LVN_ITEMCHANGING notification */
1690 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1692 /* copy information */
1693 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1695 /* if LVS_LIST or LVS_SMALLICON, update the width of the items based on */
1696 /* the width of the items text */
1697 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
1699 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
1701 if(item_width > infoPtr->nItemWidth)
1702 infoPtr->nItemWidth = item_width;
1705 /* send LVN_ITEMCHANGED notification */
1706 nmlv.hdr.code = LVN_ITEMCHANGED;
1707 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1714 InvalidateRect(hwnd, NULL, FALSE);
1725 * Sets subitem attributes.
1728 * [I] HWND : window handle
1729 * [I] LPLVITEM : new subitem atttributes
1735 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1737 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1738 BOOL bResult = FALSE;
1740 LISTVIEW_SUBITEM *lpSubItem;
1742 if (lpLVItem != NULL)
1744 if (lpLVItem->iSubItem > 0)
1746 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1747 if (hdpaSubItems != NULL)
1749 /* set subitem only if column is present */
1750 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1752 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1753 if (lpSubItem != NULL)
1755 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1759 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1762 InvalidateRect(hwnd, NULL, FALSE);
1773 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1776 * [I] HWND : window handle
1781 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1783 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1784 UINT uView = lStyle & LVS_TYPEMASK;
1786 SCROLLINFO scrollInfo;
1788 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1789 scrollInfo.cbSize = sizeof(SCROLLINFO);
1790 scrollInfo.fMask = SIF_POS;
1792 if (uView == LVS_LIST)
1794 if (lStyle & WS_HSCROLL)
1796 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1798 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1802 else if (uView == LVS_REPORT)
1804 if (lStyle & WS_VSCROLL)
1806 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1808 nItem = scrollInfo.nPos;
1821 * [I] HWND : window handle
1822 * [I] HDC : device context handle
1823 * [I] INT : item index
1824 * [I] INT : subitem index
1825 * [I] RECT * : clipping rectangle
1830 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1833 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1834 CHAR szDispText[DISP_TEXT_SIZE];
1837 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
1840 /* get information needed for drawing the item */
1841 ZeroMemory(&lvItem, sizeof(LVITEMA));
1842 lvItem.mask = LVIF_TEXT;
1843 lvItem.iItem = nItem;
1844 lvItem.iSubItem = nSubItem;
1845 lvItem.cchTextMax = DISP_TEXT_SIZE;
1846 lvItem.pszText = szDispText;
1847 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1849 /* set item colors */
1850 SetBkColor(hdc, infoPtr->clrTextBk);
1851 SetTextColor(hdc, infoPtr->clrText);
1853 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1854 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1863 * [I] HWND : window handle
1864 * [I] HDC : device context handle
1865 * [I] INT : item index
1866 * [I] RECT * : clipping rectangle
1871 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1873 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1874 CHAR szDispText[DISP_TEXT_SIZE];
1881 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
1883 /* get information needed for drawing the item */
1884 ZeroMemory(&lvItem, sizeof(LVITEMA));
1885 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1886 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1887 lvItem.iItem = nItem;
1888 lvItem.iSubItem = 0;
1889 lvItem.cchTextMax = DISP_TEXT_SIZE;
1890 lvItem.pszText = szDispText;
1891 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
1894 if (infoPtr->himlState != NULL)
1896 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1897 if (uStateImage != 0)
1899 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1900 rcItem.top, ILD_NORMAL);
1903 rcItem.left += infoPtr->iconSize.cx;
1907 if (infoPtr->himlSmall != NULL)
1909 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1911 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1912 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1913 rcItem.top, ILD_SELECTED);
1917 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1918 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1919 rcItem.top, ILD_NORMAL);
1922 rcItem.left += infoPtr->iconSize.cx;
1925 /* Don't bother painting item being edited */
1926 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
1929 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1931 /* set item colors */
1932 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1933 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1934 /* set raster mode */
1935 nMixMode = SetROP2(hdc, R2_XORPEN);
1937 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1938 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1940 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1941 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1942 /* set raster mode */
1943 nMixMode = SetROP2(hdc, R2_COPYPEN);
1947 /* set item colors */
1948 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1949 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1950 /* set raster mode */
1951 nMixMode = SetROP2(hdc, R2_COPYPEN);
1954 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1955 if (rcItem.left + nLabelWidth < rcItem.right)
1957 rcItem.right = rcItem.left + nLabelWidth;
1961 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1962 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1964 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1966 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1971 SetROP2(hdc, R2_COPYPEN);
1972 SetBkColor(hdc, infoPtr->clrTextBk);
1973 SetTextColor(hdc, infoPtr->clrText);
1979 * Draws an item when in large icon display mode.
1982 * [I] HWND : window handle
1983 * [I] HDC : device context handle
1984 * [I] LISTVIEW_ITEM * : item
1985 * [I] INT : item index
1986 * [I] RECT * : clipping rectangle
1991 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1993 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1994 CHAR szDispText[DISP_TEXT_SIZE];
1995 INT nDrawPosX = rcItem.left;
2000 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
2001 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
2004 /* get information needed for drawing the item */
2005 ZeroMemory(&lvItem, sizeof(LVITEMA));
2006 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
2007 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2008 lvItem.iItem = nItem;
2009 lvItem.iSubItem = 0;
2010 lvItem.cchTextMax = DISP_TEXT_SIZE;
2011 lvItem.pszText = szDispText;
2012 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2014 if (lvItem.state & LVIS_SELECTED)
2016 /* set item colors */
2017 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2018 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2019 /* set raster mode */
2020 SetROP2(hdc, R2_XORPEN);
2024 /* set item colors */
2025 SetBkColor(hdc, infoPtr->clrTextBk);
2026 SetTextColor(hdc, infoPtr->clrText);
2027 /* set raster mode */
2028 SetROP2(hdc, R2_COPYPEN);
2031 if (infoPtr->himlNormal != NULL)
2033 rcItem.top += ICON_TOP_PADDING;
2034 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
2035 if (lvItem.state & LVIS_SELECTED)
2037 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2038 rcItem.top, ILD_SELECTED);
2042 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2043 rcItem.top, ILD_NORMAL);
2047 /* Don't bother painting item being edited */
2048 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
2051 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2052 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2053 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
2056 rcItem.left += nDrawPosX / 2;
2057 rcItem.right = rcItem.left + nLabelWidth;
2062 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
2066 GetTextMetricsA(hdc, &tm);
2067 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
2068 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2069 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2071 if (lvItem.state & LVIS_FOCUSED)
2073 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2079 * Draws listview items when in report display mode.
2082 * [I] HWND : window handle
2083 * [I] HDC : device context handle
2088 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2090 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2091 SCROLLINFO scrollInfo;
2092 INT nDrawPosY = infoPtr->rcList.top;
2099 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2100 scrollInfo.cbSize = sizeof(SCROLLINFO);
2101 scrollInfo.fMask = SIF_POS;
2103 nItem = ListView_GetTopIndex(hwnd);
2105 /* add 1 for displaying a partial item at the bottom */
2106 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2107 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2109 /* send cache hint notification */
2110 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
2114 nmlv.hdr.hwndFrom = hwnd;
2115 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
2116 nmlv.hdr.code = LVN_ODCACHEHINT;
2120 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
2124 for (; nItem < nLast; nItem++)
2126 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2127 for (j = 0; j < nColumnCount; j++)
2129 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2130 rcItem.left += REPORT_MARGINX;
2131 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2132 rcItem.top = nDrawPosY;
2133 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2135 /* Offset the Scroll Bar Pos */
2136 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2138 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2139 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2144 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2148 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2152 nDrawPosY += infoPtr->nItemHeight;
2158 * Retrieves the number of items that can fit vertically in the client area.
2161 * [I] HWND : window handle
2164 * Number of items per row.
2166 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2168 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2169 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2170 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2171 INT nCountPerRow = 1;
2175 if (uView == LVS_REPORT)
2181 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2182 if (nCountPerRow == 0)
2189 return nCountPerRow;
2194 * Retrieves the number of items that can fit horizontally in the client
2198 * [I] HWND : window handle
2201 * Number of items per column.
2203 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2205 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2206 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2207 INT nCountPerColumn = 1;
2209 if (nListHeight > 0)
2211 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2212 if (nCountPerColumn == 0)
2214 nCountPerColumn = 1;
2218 return nCountPerColumn;
2223 * Retrieves the number of columns needed to display all the items when in
2224 * list display mode.
2227 * [I] HWND : window handle
2230 * Number of columns.
2232 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2234 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2235 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2236 INT nColumnCount = 0;
2238 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2240 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2242 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2246 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2250 return nColumnCount;
2256 * Draws listview items when in list display mode.
2259 * [I] HWND : window handle
2260 * [I] HDC : device context handle
2265 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2267 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2272 INT nCountPerColumn;
2273 INT nItemWidth = infoPtr->nItemWidth;
2274 INT nItemHeight = infoPtr->nItemHeight;
2276 /* get number of fully visible columns */
2277 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2278 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2279 nItem = ListView_GetTopIndex(hwnd);
2281 for (i = 0; i < nColumnCount; i++)
2283 for (j = 0; j < nCountPerColumn; j++, nItem++)
2285 if (nItem >= GETITEMCOUNT(infoPtr))
2288 rcItem.top = j * nItemHeight;
2289 rcItem.left = i * nItemWidth;
2290 rcItem.bottom = rcItem.top + nItemHeight;
2291 rcItem.right = rcItem.left + nItemWidth;
2292 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2299 * Draws listview items when in icon or small icon display mode.
2302 * [I] HWND : window handle
2303 * [I] HDC : device context handle
2308 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2310 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2316 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2317 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2319 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2320 ptPosition.x += ptOrigin.x;
2321 ptPosition.y += ptOrigin.y;
2323 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2325 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2327 if (ptPosition.y < infoPtr->rcList.bottom)
2329 if (ptPosition.x < infoPtr->rcList.right)
2331 rcItem.top = ptPosition.y;
2332 rcItem.left = ptPosition.x;
2333 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2334 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2335 if (bSmall == FALSE)
2337 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2341 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2352 * Draws listview items.
2355 * [I] HWND : window handle
2356 * [I] HDC : device context handle
2361 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2363 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2364 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2369 hOldFont = SelectObject(hdc, infoPtr->hFont);
2371 /* select the doted pen (for drawing the focus box) */
2372 hPen = CreatePen(PS_DOT, 1, 0);
2373 hOldPen = SelectObject(hdc, hPen);
2375 /* select transparent brush (for drawing the focus box) */
2376 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2378 if (uView == LVS_LIST)
2380 LISTVIEW_RefreshList(hwnd, hdc);
2382 else if (uView == LVS_REPORT)
2384 LISTVIEW_RefreshReport(hwnd, hdc);
2386 else if (uView == LVS_SMALLICON)
2388 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2390 else if (uView == LVS_ICON)
2392 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2395 /* unselect objects */
2396 SelectObject(hdc, hOldFont);
2397 SelectObject(hdc, hOldPen);
2406 * Calculates the approximate width and height of a given number of items.
2409 * [I] HWND : window handle
2410 * [I] INT : number of items
2415 * Returns a DWORD. The width in the low word and the height in high word.
2417 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2418 WORD wWidth, WORD wHeight)
2420 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2421 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2422 INT nItemCountPerColumn = 1;
2423 INT nColumnCount = 0;
2424 DWORD dwViewRect = 0;
2426 if (nItemCount == -1)
2428 nItemCount = GETITEMCOUNT(infoPtr);
2431 if (uView == LVS_LIST)
2433 if (wHeight == 0xFFFF)
2435 /* use current height */
2436 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2439 if (wHeight < infoPtr->nItemHeight)
2441 wHeight = infoPtr->nItemHeight;
2446 if (infoPtr->nItemHeight > 0)
2448 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2449 if (nItemCountPerColumn == 0)
2451 nItemCountPerColumn = 1;
2454 if (nItemCount % nItemCountPerColumn != 0)
2456 nColumnCount = nItemCount / nItemCountPerColumn;
2460 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2465 /* Microsoft padding magic */
2466 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2467 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2469 dwViewRect = MAKELONG(wWidth, wHeight);
2471 else if (uView == LVS_REPORT)
2475 else if (uView == LVS_SMALLICON)
2479 else if (uView == LVS_ICON)
2489 * Arranges listview items in icon display mode.
2492 * [I] HWND : window handle
2493 * [I] INT : alignment code
2499 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2501 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2502 BOOL bResult = FALSE;
2504 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2517 case LVA_SNAPTOGRID:
2526 /* << LISTVIEW_CreateDragImage >> */
2530 * Removes all listview items and subitems.
2533 * [I] HWND : window handle
2539 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2541 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2542 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2543 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2544 UINT uView = lStyle & LVS_TYPEMASK;
2545 LISTVIEW_ITEM *lpItem;
2546 LISTVIEW_SUBITEM *lpSubItem;
2549 BOOL bResult = FALSE;
2554 TRACE("(hwnd=%x,)\n", hwnd);
2556 if (GETITEMCOUNT(infoPtr) > 0)
2558 /* initialize memory */
2559 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2561 /* send LVN_DELETEALLITEMS notification */
2562 nmlv.hdr.hwndFrom = hwnd;
2563 nmlv.hdr.idFrom = lCtrlId;
2564 nmlv.hdr.code = LVN_DELETEALLITEMS;
2567 /* verify if subsequent LVN_DELETEITEM notifications should be
2569 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2571 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2573 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2574 if (hdpaSubItems != NULL)
2576 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2578 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2579 if (lpSubItem != NULL)
2581 /* free subitem string */
2582 if ((lpSubItem->pszText != NULL) &&
2583 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2585 COMCTL32_Free(lpSubItem->pszText);
2589 COMCTL32_Free(lpSubItem);
2593 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2596 if (bSuppress == FALSE)
2598 /* send LVN_DELETEITEM notification */
2599 nmlv.hdr.code = LVN_DELETEITEM;
2601 nmlv.lParam = lpItem->lParam;
2602 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2605 /* free item string */
2606 if ((lpItem->pszText != NULL) &&
2607 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2609 COMCTL32_Free(lpItem->pszText);
2613 COMCTL32_Free(lpItem);
2616 DPA_Destroy(hdpaSubItems);
2620 /* reinitialize listview memory */
2621 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2623 /* align items (set position of each item) */
2624 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2626 if (lStyle & LVS_ALIGNLEFT)
2628 LISTVIEW_AlignLeft(hwnd);
2632 LISTVIEW_AlignTop(hwnd);
2636 LISTVIEW_UpdateScroll(hwnd);
2638 /* invalidate client area (optimization needed) */
2639 InvalidateRect(hwnd, NULL, TRUE);
2647 * Removes a column from the listview control.
2650 * [I] HWND : window handle
2651 * [I] INT : column index
2657 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2659 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2660 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2661 BOOL bResult = FALSE;
2663 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2665 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2667 /* Need to reset the item width when deleting a column */
2668 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2670 /* reset scroll parameters */
2671 if (uView == LVS_REPORT)
2673 /* update scrollbar(s) */
2674 LISTVIEW_UpdateScroll(hwnd);
2676 /* refresh client area */
2677 InvalidateRect(hwnd, NULL, FALSE);
2686 * Removes an item from the listview control.
2689 * [I] HWND : window handle
2690 * [I] INT : item index
2696 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2698 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2699 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2700 UINT uView = lStyle & LVS_TYPEMASK;
2701 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2703 BOOL bResult = FALSE;
2705 LISTVIEW_ITEM *lpItem;
2706 LISTVIEW_SUBITEM *lpSubItem;
2709 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2711 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2713 /* initialize memory */
2714 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2716 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2717 if (hdpaSubItems != NULL)
2719 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2721 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2722 if (lpSubItem != NULL)
2724 /* free item string */
2725 if ((lpSubItem->pszText != NULL) &&
2726 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2728 COMCTL32_Free(lpSubItem->pszText);
2732 COMCTL32_Free(lpSubItem);
2736 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2739 /* send LVN_DELETEITEM notification */
2740 nmlv.hdr.hwndFrom = hwnd;
2741 nmlv.hdr.idFrom = lCtrlId;
2742 nmlv.hdr.code = LVN_DELETEITEM;
2744 nmlv.lParam = lpItem->lParam;
2745 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2748 /* free item string */
2749 if ((lpItem->pszText != NULL) &&
2750 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2752 COMCTL32_Free(lpItem->pszText);
2756 COMCTL32_Free(lpItem);
2759 bResult = DPA_Destroy(hdpaSubItems);
2762 /* align items (set position of each item) */
2763 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2765 if (lStyle & LVS_ALIGNLEFT)
2767 LISTVIEW_AlignLeft(hwnd);
2771 LISTVIEW_AlignTop(hwnd);
2775 /* If this item had focus change focus to next or previous item */
2776 if (GETITEMCOUNT(infoPtr) > 0)
2778 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
2779 if (infoPtr->nFocusedItem == nItem)
2780 LISTVIEW_SetItemFocus(hwnd, sItem);
2783 infoPtr->nFocusedItem = -1;
2785 LISTVIEW_UpdateScroll(hwnd);
2787 /* refresh client area */
2788 InvalidateRect(hwnd, NULL, TRUE);
2797 * Return edit control handle of current edit label
2800 * [I] HWND : window handle
2806 static LRESULT LISTVIEW_GetEditControl(hwnd)
2808 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2809 return infoPtr->hwndEdit;
2815 * Callback implementation for editlabel control
2818 * [I] HWND : window handle
2819 * [I] LPSTR : modified text
2820 * [I] DWORD : item index
2827 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
2829 NMLVDISPINFOA dispInfo;
2830 LISTVIEW_ITEM *lpItem;
2831 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2832 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2834 BOOL bUpdateItemText;
2836 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2838 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2841 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2844 dispInfo.hdr.hwndFrom = hwnd;
2845 dispInfo.hdr.idFrom = nCtrlId;
2846 dispInfo.hdr.code = LVN_ENDLABELEDITA;
2847 dispInfo.item.mask = 0;
2848 dispInfo.item.iItem = nItem;
2849 dispInfo.item.state = lpItem->state;
2850 dispInfo.item.stateMask = 0;
2851 dispInfo.item.pszText = pszText;
2852 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
2853 dispInfo.item.iImage = lpItem->iImage;
2854 dispInfo.item.lParam = lpItem->lParam;
2855 infoPtr->hwndEdit = 0;
2857 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
2859 /* Do we need to update the Item Text */
2862 if(lpItem->pszText != LPSTR_TEXTCALLBACKA)
2864 Str_SetPtrA(&lpItem->pszText, pszText);
2873 * Begin in place editing of specified list view item
2876 * [I] HWND : window handle
2877 * [I] INT : item index
2884 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
2886 NMLVDISPINFOA dispInfo;
2888 LISTVIEW_ITEM *lpItem;
2890 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
2891 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
2892 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2894 CHAR szDispText[DISP_TEXT_SIZE];
2897 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
2900 /* Is the EditBox still there, if so remove it */
2901 if(infoPtr->hwndEdit != 0)
2906 LISTVIEW_SetSelection(hwnd, nItem);
2907 LISTVIEW_SetItemFocus(hwnd, nItem);
2909 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
2910 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
2913 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
2917 /* get information needed for drawing the item */
2918 ZeroMemory(&lvItem, sizeof(LVITEMA));
2919 lvItem.mask = LVIF_TEXT;
2920 lvItem.iItem = nItem;
2921 lvItem.iSubItem = 0;
2922 lvItem.cchTextMax = DISP_TEXT_SIZE;
2923 lvItem.pszText = szDispText;
2924 ListView_GetItemA(hwnd, &lvItem);
2926 dispInfo.hdr.hwndFrom = hwnd;
2927 dispInfo.hdr.idFrom = nCtrlId;
2928 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
2929 dispInfo.item.mask = 0;
2930 dispInfo.item.iItem = nItem;
2931 dispInfo.item.state = lpItem->state;
2932 dispInfo.item.stateMask = 0;
2933 dispInfo.item.pszText = lvItem.pszText;
2934 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
2935 dispInfo.item.iImage = lpItem->iImage;
2936 dispInfo.item.lParam = lpItem->lParam;
2938 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
2941 rect.left = LVIR_LABEL;
2942 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
2945 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
2946 rect.left-2, rect.top-1, 0,
2947 rect.bottom - rect.top+2,
2948 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
2951 infoPtr->hwndEdit = hedit;
2953 SendMessageA(hedit, EM_SETSEL, 0, -1);
2961 * Ensures the specified item is visible, scrolling into view if necessary.
2964 * [I] HWND : window handle
2965 * [I] INT : item index
2966 * [I] BOOL : partially or entirely visible
2972 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2974 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2975 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2976 INT nScrollPosHeight = 0;
2977 INT nScrollPosWidth = 0;
2978 SCROLLINFO scrollInfo;
2981 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2982 scrollInfo.cbSize = sizeof(SCROLLINFO);
2983 scrollInfo.fMask = SIF_POS;
2985 /* ALWAYS bPartial == FALSE, FOR NOW! */
2987 rcItem.left = LVIR_BOUNDS;
2988 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2990 if (rcItem.left < infoPtr->rcList.left)
2992 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2995 if (uView == LVS_LIST)
2997 nScrollPosWidth = infoPtr->nItemWidth;
2998 rcItem.left += infoPtr->rcList.left;
3000 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3002 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
3003 rcItem.left += infoPtr->rcList.left;
3006 /* When in LVS_REPORT view, the scroll position should
3008 if (nScrollPosWidth != 0)
3010 if (rcItem.left % nScrollPosWidth == 0)
3012 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
3016 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
3019 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3023 else if (rcItem.right > infoPtr->rcList.right)
3025 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3028 if (uView == LVS_LIST)
3030 rcItem.right -= infoPtr->rcList.right;
3031 nScrollPosWidth = infoPtr->nItemWidth;
3033 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3035 rcItem.right -= infoPtr->rcList.right;
3036 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
3039 /* When in LVS_REPORT view, the scroll position should
3041 if (nScrollPosWidth != 0)
3043 if (rcItem.right % nScrollPosWidth == 0)
3045 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
3049 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
3052 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3057 if (rcItem.top < infoPtr->rcList.top)
3060 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3062 if (uView == LVS_REPORT)
3064 rcItem.top -= infoPtr->rcList.top;
3065 nScrollPosHeight = infoPtr->nItemHeight;
3067 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3069 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3070 rcItem.top += infoPtr->rcList.top;
3073 if (rcItem.top % nScrollPosHeight == 0)
3075 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
3079 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
3082 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3085 else if (rcItem.bottom > infoPtr->rcList.bottom)
3088 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3090 if (uView == LVS_REPORT)
3092 rcItem.bottom -= infoPtr->rcList.bottom;
3093 nScrollPosHeight = infoPtr->nItemHeight;
3095 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3097 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3098 rcItem.bottom -= infoPtr->rcList.bottom;
3101 if (rcItem.bottom % nScrollPosHeight == 0)
3103 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
3107 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
3110 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3120 * Retrieves the nearest item, given a position and a direction.
3123 * [I] HWND : window handle
3124 * [I] POINT : start position
3125 * [I] UINT : direction
3128 * Item index if successdful, -1 otherwise.
3130 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3132 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3133 LVHITTESTINFO lvHitTestInfo;
3137 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3139 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3140 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3141 lvHitTestInfo.pt.x += pt.x;
3142 lvHitTestInfo.pt.y += pt.y;
3146 if (vkDirection == VK_DOWN)
3148 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3150 else if (vkDirection == VK_UP)
3152 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3154 else if (vkDirection == VK_LEFT)
3156 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3158 else if (vkDirection == VK_RIGHT)
3160 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3163 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3169 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3173 while (nItem == -1);
3181 * Searches for an item with specific characteristics.
3184 * [I] HWND : window handle
3185 * [I] INT : base item index
3186 * [I] LPLVFINDINFO : item information to look for
3189 * SUCCESS : index of item
3192 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3193 LPLVFINDINFO lpFindInfo)
3195 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3197 CHAR szDispText[DISP_TEXT_SIZE];
3201 INT nLast = GETITEMCOUNT(infoPtr);
3203 if ((nItem >= -1) && (lpFindInfo != NULL))
3205 ZeroMemory(&lvItem, sizeof(LVITEMA));
3207 if (lpFindInfo->flags & LVFI_PARAM)
3209 lvItem.mask |= LVIF_PARAM;
3212 if (lpFindInfo->flags & LVFI_STRING)
3214 lvItem.mask |= LVIF_TEXT;
3215 lvItem.pszText = szDispText;
3216 lvItem.cchTextMax = DISP_TEXT_SIZE;
3219 if (lpFindInfo->flags & LVFI_PARTIAL)
3221 lvItem.mask |= LVIF_TEXT;
3222 lvItem.pszText = szDispText;
3223 lvItem.cchTextMax = DISP_TEXT_SIZE;
3226 if (lpFindInfo->flags & LVFI_WRAP)
3231 if (lpFindInfo->flags & LVFI_NEARESTXY)
3233 ptItem.x = lpFindInfo->pt.x;
3234 ptItem.y = lpFindInfo->pt.y;
3239 while (nItem < nLast)
3241 if (lpFindInfo->flags & LVFI_NEARESTXY)
3243 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3244 lpFindInfo->vkDirection);
3247 /* get position of the new item index */
3248 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3259 lvItem.iItem = nItem;
3260 lvItem.iSubItem = 0;
3261 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
3263 if (lvItem.mask & LVIF_TEXT)
3265 if (lpFindInfo->flags & LVFI_PARTIAL)
3267 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3272 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3277 if (lvItem.mask & LVIF_PARAM)
3279 if (lpFindInfo->lParam != lvItem.lParam)
3305 * Retrieves the background color of the listview control.
3308 * [I] HWND : window handle
3311 * COLORREF associated with the background.
3313 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3315 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3317 return infoPtr->clrBk;
3322 * Retrieves the background image of the listview control.
3325 * [I] HWND : window handle
3326 * [O] LPLVMKBIMAGE : background image attributes
3332 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3334 /* FIXME (listview, "empty stub!\n"); */
3340 * Retrieves the callback mask.
3343 * [I] HWND : window handle
3348 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3350 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3352 return infoPtr->uCallbackMask;
3357 * Retrieves column attributes.
3360 * [I] HWND : window handle
3361 * [I] INT : column index
3362 * [IO] LPLVCOLUMNA : column information
3368 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3370 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3372 BOOL bResult = FALSE;
3374 if (lpColumn != NULL)
3376 /* initialize memory */
3377 ZeroMemory(&hdi, sizeof(HDITEMA));
3379 if (lpColumn->mask & LVCF_FMT)
3381 hdi.mask |= HDI_FORMAT;
3384 if (lpColumn->mask & LVCF_WIDTH)
3386 hdi.mask |= HDI_WIDTH;
3389 if (lpColumn->mask & LVCF_TEXT)
3391 hdi.mask |= HDI_TEXT;
3392 hdi.cchTextMax = lpColumn->cchTextMax;
3393 hdi.pszText = lpColumn->pszText;
3396 if (lpColumn->mask & LVCF_IMAGE)
3398 hdi.mask |= HDI_IMAGE;
3401 if (lpColumn->mask & LVCF_ORDER)
3403 hdi.mask |= HDI_ORDER;
3406 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3407 if (bResult != FALSE)
3409 if (lpColumn->mask & LVCF_FMT)
3413 if (hdi.fmt & HDF_LEFT)
3415 lpColumn->fmt |= LVCFMT_LEFT;
3417 else if (hdi.fmt & HDF_RIGHT)
3419 lpColumn->fmt |= LVCFMT_RIGHT;
3421 else if (hdi.fmt & HDF_CENTER)
3423 lpColumn->fmt |= LVCFMT_CENTER;
3426 if (hdi.fmt & HDF_IMAGE)
3428 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3431 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3433 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3437 if (lpColumn->mask & LVCF_WIDTH)
3439 lpColumn->cx = hdi.cxy;
3442 if (lpColumn->mask & LVCF_IMAGE)
3444 lpColumn->iImage = hdi.iImage;
3447 if (lpColumn->mask & LVCF_ORDER)
3449 lpColumn->iOrder = hdi.iOrder;
3457 /* LISTVIEW_GetColumnW */
3460 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
3462 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3469 for (i = 0; i < iCount; i++)
3477 * Retrieves the column width.
3480 * [I] HWND : window handle
3481 * [I] int : column index
3484 * SUCCESS : column width
3487 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3489 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3490 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3491 INT nColumnWidth = 0;
3494 if (uView == LVS_LIST)
3496 nColumnWidth = infoPtr->nItemWidth;
3498 else if (uView == LVS_REPORT)
3500 /* get column width from header */
3501 ZeroMemory(&hdi, sizeof(HDITEMA));
3502 hdi.mask = HDI_WIDTH;
3503 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3505 nColumnWidth = hdi.cxy;
3509 return nColumnWidth;
3514 * In list or report display mode, retrieves the number of items that can fit
3515 * vertically in the visible area. In icon or small icon display mode,
3516 * retrieves the total number of visible items.
3519 * [I] HWND : window handle
3522 * Number of fully visible items.
3524 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3526 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3527 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3530 if (uView == LVS_LIST)
3532 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3534 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3535 LISTVIEW_GetCountPerColumn(hwnd);
3538 else if (uView == LVS_REPORT)
3540 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3544 nItemCount = GETITEMCOUNT(infoPtr);
3550 /* LISTVIEW_GetEditControl */
3554 * Retrieves the extended listview style.
3557 * [I] HWND : window handle
3560 * SUCCESS : previous style
3563 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3565 LISTVIEW_INFO *infoPtr;
3567 /* make sure we can get the listview info */
3568 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3571 return (infoPtr->dwExStyle);
3576 * Retrieves the handle to the header control.
3579 * [I] HWND : window handle
3584 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3586 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3588 return infoPtr->hwndHeader;
3591 /* LISTVIEW_GetHotCursor */
3595 * Returns the time that the mouse cursor must hover over an item
3596 * before it is selected.
3599 * [I] HWND : window handle
3602 * Returns the previously set hover time or (DWORD)-1 to indicate that the
3603 * hover time is set to the default hover time.
3605 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
3607 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3609 return infoPtr->dwHoverTime;
3614 * Retrieves an image list handle.
3617 * [I] HWND : window handle
3618 * [I] INT : image list identifier
3621 * SUCCESS : image list handle
3624 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3626 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3627 HIMAGELIST himl = NULL;
3632 himl = infoPtr->himlNormal;
3635 himl = infoPtr->himlSmall;
3638 himl = infoPtr->himlState;
3642 return (LRESULT)himl;
3645 /* LISTVIEW_GetISearchString */
3649 * Retrieves item attributes.
3652 * [I] HWND : window handle
3653 * [IO] LPLVITEMA : item info
3654 * [I] internal : if true then we will use tricks that avoid copies
3655 * but are not compatible with the regular interface
3661 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
3663 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3664 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3665 NMLVDISPINFOA dispInfo;
3666 LISTVIEW_SUBITEM *lpSubItem;
3667 LISTVIEW_ITEM *lpItem;
3671 /* In the following:
3672 * lpLVItem describes the information requested by the user
3673 * lpItem/lpSubItem is what we have
3674 * dispInfo is a structure we use to request the missing
3675 * information from the application
3678 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3680 if ((lpLVItem == NULL) ||
3681 (lpLVItem->iItem < 0) ||
3682 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
3686 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3687 if (hdpaSubItems == NULL)
3690 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3694 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3695 if (lpLVItem->iSubItem == 0)
3697 piImage=&lpItem->iImage;
3698 ppszText=&lpItem->pszText;
3699 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3701 dispInfo.item.mask |= LVIF_STATE;
3702 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3707 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
3708 if (lpSubItem != NULL)
3710 piImage=&lpSubItem->iImage;
3711 ppszText=&lpSubItem->pszText;
3720 if ((lpLVItem->mask & LVIF_IMAGE) &&
3721 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
3723 dispInfo.item.mask |= LVIF_IMAGE;
3726 if ((lpLVItem->mask & LVIF_TEXT) &&
3727 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
3729 dispInfo.item.mask |= LVIF_TEXT;
3730 dispInfo.item.pszText = lpLVItem->pszText;
3731 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3734 if (dispInfo.item.mask != 0)
3736 /* We don't have all the requested info, query the application */
3737 dispInfo.hdr.hwndFrom = hwnd;
3738 dispInfo.hdr.idFrom = lCtrlId;
3739 dispInfo.hdr.code = LVN_GETDISPINFOA;
3740 dispInfo.item.iItem = lpLVItem->iItem;
3741 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3742 dispInfo.item.lParam = lpItem->lParam;
3743 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3746 if (dispInfo.item.mask & LVIF_IMAGE)
3748 lpLVItem->iImage = dispInfo.item.iImage;
3750 else if (lpLVItem->mask & LVIF_IMAGE)
3752 lpLVItem->iImage = *piImage;
3755 if (dispInfo.item.mask & LVIF_PARAM)
3757 lpLVItem->lParam = dispInfo.item.lParam;
3759 else if (lpLVItem->mask & LVIF_PARAM)
3761 lpLVItem->lParam = lpItem->lParam;
3764 if (dispInfo.item.mask & LVIF_TEXT)
3766 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
3768 Str_SetPtrA(ppszText, dispInfo.item.pszText);
3770 /* Here lpLVItem->pszText==dispInfo.item.pszText so a copy is unnecessary */
3772 else if (lpLVItem->mask & LVIF_TEXT)
3776 lpLVItem->pszText=*ppszText;
3778 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
3782 if (lpLVItem->iSubItem == 0)
3784 if (dispInfo.item.mask & LVIF_STATE)
3786 lpLVItem->state = lpItem->state;
3787 lpLVItem->state &= ~dispInfo.item.stateMask;
3788 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
3790 else if (lpLVItem->mask & LVIF_STATE)
3792 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3795 if (lpLVItem->mask & LVIF_PARAM)
3797 lpLVItem->lParam = lpItem->lParam;
3800 if (lpLVItem->mask & LVIF_INDENT)
3802 lpLVItem->iIndent = lpItem->iIndent;
3809 /* LISTVIEW_GetItemW */
3810 /* LISTVIEW_GetHotCursor */
3814 * Retrieves the index of the hot item.
3817 * [I] HWND : window handle
3820 * SUCCESS : hot item index
3821 * FAILURE : -1 (no hot item)
3823 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3825 LISTVIEW_INFO *infoPtr;
3827 /* make sure we can get the listview info */
3828 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3831 return (infoPtr->nHotItem);
3834 /* LISTVIEW_GetHoverTime */
3838 * Retrieves the number of items in the listview control.
3841 * [I] HWND : window handle
3846 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3848 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3850 return GETITEMCOUNT(infoPtr);
3855 * Retrieves the position (upper-left) of the listview control item.
3858 * [I] HWND : window handle
3859 * [I] INT : item index
3860 * [O] LPPOINT : coordinate information
3866 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3867 LPPOINT lpptPosition)
3869 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3870 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3871 BOOL bResult = FALSE;
3873 LISTVIEW_ITEM *lpItem;
3874 INT nCountPerColumn;
3877 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3880 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3881 (lpptPosition != NULL))
3883 if (uView == LVS_LIST)
3886 nItem = nItem - ListView_GetTopIndex(hwnd);
3887 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3890 nRow = nItem % nCountPerColumn;
3893 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3894 lpptPosition->y = 0;
3898 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3899 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3904 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3905 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3908 else if (uView == LVS_REPORT)
3911 lpptPosition->x = REPORT_MARGINX;
3912 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3913 infoPtr->nItemHeight) + infoPtr->rcList.top;
3917 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3918 if (hdpaSubItems != NULL)
3920 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3924 lpptPosition->x = lpItem->ptPosition.x;
3925 lpptPosition->y = lpItem->ptPosition.y;
3936 * Retrieves the bounding rectangle for a listview control item.
3939 * [I] HWND : window handle
3940 * [I] INT : item index
3941 * [IO] LPRECT : bounding rectangle coordinates
3947 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3949 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3950 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3951 BOOL bResult = FALSE;
3960 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3962 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3964 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3969 if (uView == LVS_ICON)
3971 if (infoPtr->himlNormal != NULL)
3973 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3976 lprc->left = ptItem.x + ptOrigin.x;
3977 lprc->top = ptItem.y + ptOrigin.y;
3978 lprc->right = lprc->left + infoPtr->iconSize.cx;
3979 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3980 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3984 else if (uView == LVS_SMALLICON)
3986 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3989 lprc->left = ptItem.x + ptOrigin.x;
3990 lprc->top = ptItem.y + ptOrigin.y;
3991 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3993 if (infoPtr->himlState != NULL)
3994 lprc->left += infoPtr->iconSize.cx;
3996 if (infoPtr->himlSmall != NULL)
3997 lprc->right = lprc->left + infoPtr->iconSize.cx;
3999 lprc->right = lprc->left;
4005 lprc->left = ptItem.x;
4006 lprc->top = ptItem.y;
4007 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4009 if (infoPtr->himlState != NULL)
4011 lprc->left += infoPtr->iconSize.cx;
4014 if (infoPtr->himlSmall != NULL)
4016 lprc->right = lprc->left + infoPtr->iconSize.cx;
4020 lprc->right = lprc->left;
4026 if (uView == LVS_ICON)
4028 if (infoPtr->himlNormal != NULL)
4030 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4033 lprc->left = ptItem.x + ptOrigin.x;
4034 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
4035 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
4036 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4037 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
4039 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
4040 lprc->right = lprc->left + nLabelWidth;
4045 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
4049 hOldFont = SelectObject(hdc, infoPtr->hFont);
4050 GetTextMetricsA(hdc, &tm);
4051 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
4052 SelectObject(hdc, hOldFont);
4053 ReleaseDC(hwnd, hdc);
4057 else if (uView == LVS_SMALLICON)
4059 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4062 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
4063 lprc->top = ptItem.y + ptOrigin.y;
4064 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4066 if (infoPtr->himlState != NULL)
4068 lprc->left += infoPtr->iconSize.cx;
4071 if (infoPtr->himlSmall != NULL)
4073 lprc->left += infoPtr->iconSize.cx;
4076 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4077 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4079 lprc->right = lprc->left + nLabelWidth;
4083 lprc->right = nLeftPos + infoPtr->nItemWidth;
4090 nLeftPos = lprc->left = ptItem.x;
4091 lprc->top = ptItem.y;
4092 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4094 if (infoPtr->himlState != NULL)
4096 lprc->left += infoPtr->iconSize.cx;
4099 if (infoPtr->himlSmall != NULL)
4101 lprc->left += infoPtr->iconSize.cx;
4104 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4105 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4107 lprc->right = lprc->left + nLabelWidth;
4111 lprc->right = nLeftPos + infoPtr->nItemWidth;
4117 if (uView == LVS_ICON)
4119 if (infoPtr->himlNormal != NULL)
4121 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4124 lprc->left = ptItem.x + ptOrigin.x;
4125 lprc->top = ptItem.y + ptOrigin.y;
4126 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4127 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4131 else if (uView == LVS_SMALLICON)
4133 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4136 lprc->left = ptItem.x + ptOrigin.x;
4137 lprc->right = lprc->left;
4138 lprc->top = ptItem.y + ptOrigin.y;
4139 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4140 if (infoPtr->himlState != NULL)
4141 lprc->right += infoPtr->iconSize.cx;
4142 if (infoPtr->himlSmall != NULL)
4143 lprc->right += infoPtr->iconSize.cx;
4145 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4146 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4148 lprc->right += nLabelWidth;
4152 lprc->right = lprc->left + infoPtr->nItemWidth;
4159 lprc->left = ptItem.x;
4160 lprc->right = lprc->left;
4161 lprc->top = ptItem.y;
4162 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4164 if (infoPtr->himlState != NULL)
4166 lprc->right += infoPtr->iconSize.cx;
4169 if (infoPtr->himlSmall != NULL)
4171 lprc->right += infoPtr->iconSize.cx;
4174 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4175 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4177 lprc->right += nLabelWidth;
4181 lprc->right = lprc->left + infoPtr->nItemWidth;
4186 case LVIR_SELECTBOUNDS:
4187 if (uView == LVS_ICON)
4189 if (infoPtr->himlNormal != NULL)
4191 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4194 lprc->left = ptItem.x + ptOrigin.x;
4195 lprc->top = ptItem.y + ptOrigin.y;
4196 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4197 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4201 else if (uView == LVS_SMALLICON)
4203 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4206 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4207 lprc->top = ptItem.y + ptOrigin.y;
4208 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4210 if (infoPtr->himlState != NULL)
4212 lprc->left += infoPtr->iconSize.cx;
4215 lprc->right = lprc->left;
4217 if (infoPtr->himlSmall != NULL)
4219 lprc->right += infoPtr->iconSize.cx;
4222 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4223 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4225 lprc->right += nLabelWidth;
4229 lprc->right = nLeftPos + infoPtr->nItemWidth;
4236 nLeftPos = lprc->left = ptItem.x;
4237 lprc->top = ptItem.y;
4238 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4240 if (infoPtr->himlState != NULL)
4242 lprc->left += infoPtr->iconSize.cx;
4245 lprc->right = lprc->left;
4247 if (infoPtr->himlSmall != NULL)
4249 lprc->right += infoPtr->iconSize.cx;
4252 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4253 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4255 lprc->right += nLabelWidth;
4259 lprc->right = nLeftPos + infoPtr->nItemWidth;
4272 * Retrieves the width of a label.
4275 * [I] HWND : window handle
4278 * SUCCESS : string width (in pixels)
4281 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4283 CHAR szDispText[DISP_TEXT_SIZE];
4284 INT nLabelWidth = 0;
4287 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4289 ZeroMemory(&lvItem, sizeof(LVITEMA));
4290 lvItem.mask = LVIF_TEXT;
4291 lvItem.iItem = nItem;
4292 lvItem.cchTextMax = DISP_TEXT_SIZE;
4293 lvItem.pszText = szDispText;
4294 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4296 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4304 * Retrieves the spacing between listview control items.
4307 * [I] HWND : window handle
4308 * [I] BOOL : flag for small or large icon
4311 * Horizontal + vertical spacing
4313 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4315 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4318 if (bSmall == FALSE)
4320 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4324 /* TODO: need to store width of smallicon item */
4325 lResult = MAKELONG(0, infoPtr->nItemHeight);
4333 * Retrieves the state of a listview control item.
4336 * [I] HWND : window handle
4337 * [I] INT : item index
4338 * [I] UINT : state mask
4341 * State specified by the mask.
4343 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4345 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4349 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4351 ZeroMemory(&lvItem, sizeof(LVITEMA));
4352 lvItem.iItem = nItem;
4353 lvItem.stateMask = uMask;
4354 lvItem.mask = LVIF_STATE;
4355 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4357 uState = lvItem.state;
4366 * Retrieves the text of a listview control item or subitem.
4369 * [I] HWND : window handle
4370 * [I] INT : item index
4371 * [IO] LPLVITEMA : item information
4374 * SUCCESS : string length
4377 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4379 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4382 if (lpLVItem != NULL)
4384 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4386 lpLVItem->mask = LVIF_TEXT;
4387 lpLVItem->iItem = nItem;
4388 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
4390 nLength = lstrlenA(lpLVItem->pszText);
4400 * Searches for an item based on properties + relationships.
4403 * [I] HWND : window handle
4404 * [I] INT : item index
4405 * [I] INT : relationship flag
4408 * SUCCESS : item index
4411 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4413 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4414 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4416 LVFINDINFO lvFindInfo;
4417 INT nCountPerColumn;
4420 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4422 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4424 if (uFlags & LVNI_CUT)
4427 if (uFlags & LVNI_DROPHILITED)
4428 uMask |= LVIS_DROPHILITED;
4430 if (uFlags & LVNI_FOCUSED)
4431 uMask |= LVIS_FOCUSED;
4433 if (uFlags & LVNI_SELECTED)
4434 uMask |= LVIS_SELECTED;
4436 if (uFlags & LVNI_ABOVE)
4438 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4443 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4449 lvFindInfo.flags = LVFI_NEARESTXY;
4450 lvFindInfo.vkDirection = VK_UP;
4451 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4452 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4454 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4459 else if (uFlags & LVNI_BELOW)
4461 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4463 while (nItem < GETITEMCOUNT(infoPtr))
4466 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4472 lvFindInfo.flags = LVFI_NEARESTXY;
4473 lvFindInfo.vkDirection = VK_DOWN;
4474 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4475 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4477 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4482 else if (uFlags & LVNI_TOLEFT)
4484 if (uView == LVS_LIST)
4486 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4487 while (nItem - nCountPerColumn >= 0)
4489 nItem -= nCountPerColumn;
4490 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4494 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4496 lvFindInfo.flags = LVFI_NEARESTXY;
4497 lvFindInfo.vkDirection = VK_LEFT;
4498 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4499 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4501 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4506 else if (uFlags & LVNI_TORIGHT)
4508 if (uView == LVS_LIST)
4510 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4511 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4513 nItem += nCountPerColumn;
4514 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4518 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4520 lvFindInfo.flags = LVFI_NEARESTXY;
4521 lvFindInfo.vkDirection = VK_RIGHT;
4522 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4523 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4525 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4534 /* search by index */
4535 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4537 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4546 /* LISTVIEW_GetNumberOfWorkAreas */
4550 * Retrieves the origin coordinates when in icon or small icon display mode.
4553 * [I] HWND : window handle
4554 * [O] LPPOINT : coordinate information
4560 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4562 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4563 UINT uView = lStyle & LVS_TYPEMASK;
4564 BOOL bResult = FALSE;
4566 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4568 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4570 SCROLLINFO scrollInfo;
4571 ZeroMemory(lpptOrigin, sizeof(POINT));
4572 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4573 scrollInfo.cbSize = sizeof(SCROLLINFO);
4575 if (lStyle & WS_HSCROLL)
4577 scrollInfo.fMask = SIF_POS;
4578 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4580 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4584 if (lStyle & WS_VSCROLL)
4586 scrollInfo.fMask = SIF_POS;
4587 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4589 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4601 * Retrieves the number of items that are marked as selected.
4604 * [I] HWND : window handle
4607 * Number of items selected.
4609 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4611 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4612 INT nSelectedCount = 0;
4615 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4617 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4623 return nSelectedCount;
4628 * Retrieves item index that marks the start of a multiple selection.
4631 * [I] HWND : window handle
4634 * Index number or -1 if there is no selection mark.
4636 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4638 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4640 return infoPtr->nSelectionMark;
4645 * Retrieves the width of a string.
4648 * [I] HWND : window handle
4651 * SUCCESS : string width (in pixels)
4654 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4656 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4657 HFONT hFont, hOldFont;
4661 ZeroMemory(&stringSize, sizeof(SIZE));
4662 if (lpszText != NULL)
4664 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4666 hOldFont = SelectObject(hdc, hFont);
4667 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4668 SelectObject(hdc, hOldFont);
4669 ReleaseDC(hwnd, hdc);
4672 return stringSize.cx;
4677 * Retrieves the text backgound color.
4680 * [I] HWND : window handle
4683 * COLORREF associated with the the background.
4685 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4687 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4689 return infoPtr->clrTextBk;
4694 * Retrieves the text color.
4697 * [I] HWND : window handle
4700 * COLORREF associated with the text.
4702 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4704 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4706 return infoPtr->clrText;
4711 * Determines which section of the item was selected (if any).
4714 * [I] HWND : window handle
4715 * [IO] LPLVHITTESTINFO : hit test information
4718 * SUCCESS : item index
4721 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4723 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4727 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4728 lpHitTestInfo->pt.y);
4730 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4732 rcItem.left = LVIR_BOUNDS;
4733 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4735 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4737 rcItem.left = LVIR_ICON;
4738 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4740 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4742 lpHitTestInfo->flags = LVHT_ONITEMICON;
4743 lpHitTestInfo->iItem = i;
4744 lpHitTestInfo->iSubItem = 0;
4749 rcItem.left = LVIR_LABEL;
4750 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4752 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4754 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4755 lpHitTestInfo->iItem = i;
4756 lpHitTestInfo->iSubItem = 0;
4761 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4762 lpHitTestInfo->iItem = i;
4763 lpHitTestInfo->iSubItem = 0;
4769 lpHitTestInfo->flags = LVHT_NOWHERE;
4776 * Determines which listview item is located at the specified position.
4779 * [I] HWND : window handle
4780 * [IO} LPLVHITTESTINFO : hit test information
4783 * SUCCESS : item index
4786 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4788 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4791 lpHitTestInfo->flags = 0;
4793 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4795 lpHitTestInfo->flags = LVHT_TOLEFT;
4797 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4799 lpHitTestInfo->flags = LVHT_TORIGHT;
4801 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4803 lpHitTestInfo->flags |= LVHT_ABOVE;
4805 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4807 lpHitTestInfo->flags |= LVHT_BELOW;
4810 if (lpHitTestInfo->flags == 0)
4812 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4820 * Inserts a new column.
4823 * [I] HWND : window handle
4824 * [I] INT : column index
4825 * [I] LPLVCOLUMNA : column information
4828 * SUCCESS : new column index
4831 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4832 LPLVCOLUMNA lpColumn)
4834 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4836 INT nNewColumn = -1;
4838 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4841 if (lpColumn != NULL)
4843 /* initialize memory */
4844 ZeroMemory(&hdi, sizeof(HDITEMA));
4846 if (lpColumn->mask & LVCF_FMT)
4848 /* format member is valid */
4849 hdi.mask |= HDI_FORMAT;
4851 /* set text alignment (leftmost column must be left-aligned) */
4854 hdi.fmt |= HDF_LEFT;
4858 if (lpColumn->fmt & LVCFMT_LEFT)
4860 hdi.fmt |= HDF_LEFT;
4862 else if (lpColumn->fmt & LVCFMT_RIGHT)
4864 hdi.fmt |= HDF_RIGHT;
4866 else if (lpColumn->fmt & LVCFMT_CENTER)
4868 hdi.fmt |= HDF_CENTER;
4872 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4874 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4878 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4883 if (lpColumn->fmt & LVCFMT_IMAGE)
4885 hdi.fmt |= HDF_IMAGE;
4886 hdi.iImage = I_IMAGECALLBACK;
4890 if (lpColumn->mask & LVCF_WIDTH)
4892 hdi.mask |= HDI_WIDTH;
4893 hdi.cxy = lpColumn->cx;
4896 if (lpColumn->mask & LVCF_TEXT)
4898 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4899 hdi.pszText = lpColumn->pszText;
4900 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4901 hdi.fmt |= HDF_STRING;
4904 if (lpColumn->mask & LVCF_IMAGE)
4906 hdi.mask |= HDI_IMAGE;
4907 hdi.iImage = lpColumn->iImage;
4910 if (lpColumn->mask & LVCF_ORDER)
4912 hdi.mask |= HDI_ORDER;
4913 hdi.iOrder = lpColumn->iOrder;
4916 /* insert item in header control */
4917 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4918 (WPARAM)nColumn, (LPARAM)&hdi);
4920 /* Need to reset the item width when inserting a new column */
4921 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4923 LISTVIEW_UpdateScroll(hwnd);
4924 InvalidateRect(hwnd, NULL, FALSE);
4930 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
4931 LPLVCOLUMNW lpColumn)
4936 memcpy(&lvca,lpColumn,sizeof(lvca));
4937 if (lpColumn->mask & LVCF_TEXT)
4938 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
4939 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
4940 if (lpColumn->mask & LVCF_TEXT)
4941 HeapFree(GetProcessHeap(),0,lvca.pszText);
4945 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
4946 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
4947 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
4948 and not during the processing of a LVM_SORTITEMS message. Applications should provide
4949 their own sort proc. when sending LVM_SORTITEMS.
4952 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
4954 LVS_SORTXXX must be specified,
4955 LVS_OWNERDRAW is not set,
4956 <item>.pszText is not LPSTR_TEXTCALLBACK.
4958 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
4959 are sorted based on item text..."
4961 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
4963 HDPA hdpa_first = (HDPA) first;
4964 HDPA hdpa_second = (HDPA) second;
4965 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
4966 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
4967 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
4968 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
4969 /* if we're sorting descending, negate the return value */
4970 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
4975 * Inserts a new item in the listview control.
4978 * [I] HWND : window handle
4979 * [I] LPLVITEMA : item information
4982 * SUCCESS : new item index
4985 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4987 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4988 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4989 UINT uView = lStyle & LVS_TYPEMASK;
4990 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4995 LISTVIEW_ITEM *lpItem = NULL;
4997 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4999 if (lpLVItem != NULL)
5001 /* make sure it's not a subitem; cannot insert a subitem */
5002 if (lpLVItem->iSubItem == 0)
5004 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
5007 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
5008 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
5010 /* insert item in listview control data structure */
5011 hdpaSubItems = DPA_Create(8);
5012 if (hdpaSubItems != NULL)
5014 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
5017 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
5018 && !(lStyle & LVS_OWNERDRAWFIXED)
5019 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
5021 /* Insert the item in the proper sort order based on the pszText
5022 member. See comments for LISTVIEW_InsertCompare() for greater detail */
5023 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
5024 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
5025 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
5026 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
5030 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
5035 /* manage item focus */
5036 if (lpLVItem->mask & LVIF_STATE)
5038 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
5039 if (lpLVItem->stateMask & LVIS_SELECTED)
5041 LISTVIEW_SetSelection(hwnd, nItem);
5043 else if (lpLVItem->stateMask & LVIS_FOCUSED)
5045 LISTVIEW_SetItemFocus(hwnd, nItem);
5049 /* send LVN_INSERTITEM notification */
5050 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
5051 nmlv.hdr.hwndFrom = hwnd;
5052 nmlv.hdr.idFrom = lCtrlId;
5053 nmlv.hdr.code = LVN_INSERTITEM;
5055 nmlv.lParam = lpItem->lParam;;
5056 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
5058 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
5060 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
5061 if (nItemWidth > infoPtr->nItemWidth)
5063 infoPtr->nItemWidth = nItemWidth;
5067 /* align items (set position of each item) */
5068 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5070 if (lStyle & LVS_ALIGNLEFT)
5072 LISTVIEW_AlignLeft(hwnd);
5076 LISTVIEW_AlignTop(hwnd);
5080 LISTVIEW_UpdateScroll(hwnd);
5081 /* refresh client area */
5082 InvalidateRect(hwnd, NULL, FALSE);
5091 /* free memory if unsuccessful */
5092 if ((nItem == -1) && (lpItem != NULL))
5094 COMCTL32_Free(lpItem);
5100 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
5104 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
5105 if (lvia.mask & LVIF_TEXT) {
5106 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
5107 lvia.pszText = LPSTR_TEXTCALLBACKA;
5109 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
5111 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
5112 if (lvia.mask & LVIF_TEXT) {
5113 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
5114 HeapFree(GetProcessHeap(),0,lvia.pszText);
5119 /* LISTVIEW_InsertItemW */
5123 * Redraws a range of items.
5126 * [I] HWND : window handle
5127 * [I] INT : first item
5128 * [I] INT : last item
5134 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
5136 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5137 BOOL bResult = FALSE;
5140 if (nFirst <= nLast)
5142 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
5144 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
5147 InvalidateRect(hwnd, &rc, FALSE);
5155 /* LISTVIEW_Scroll */
5159 * Sets the background color.
5162 * [I] HWND : window handle
5163 * [I] COLORREF : background color
5169 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
5171 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5173 infoPtr->clrBk = clrBk;
5174 InvalidateRect(hwnd, NULL, TRUE);
5179 /* LISTVIEW_SetBkImage */
5183 * Sets the callback mask. This mask will be used when the parent
5184 * window stores state information (some or all).
5187 * [I] HWND : window handle
5188 * [I] UINT : state mask
5194 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5196 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5198 infoPtr->uCallbackMask = uMask;
5205 * Sets the attributes of a header item.
5208 * [I] HWND : window handle
5209 * [I] INT : column index
5210 * [I] LPLVCOLUMNA : column attributes
5216 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5217 LPLVCOLUMNA lpColumn)
5219 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5220 BOOL bResult = FALSE;
5221 HDITEMA hdi, hdiget;
5223 if ((lpColumn != NULL) && (nColumn >= 0) &&
5224 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5226 /* initialize memory */
5227 ZeroMemory(&hdi, sizeof(HDITEMA));
5229 if (lpColumn->mask & LVCF_FMT)
5231 /* format member is valid */
5232 hdi.mask |= HDI_FORMAT;
5234 /* get current format first */
5235 hdiget.mask = HDI_FORMAT;
5236 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5237 /* preserve HDF_STRING if present */
5238 hdi.fmt = hdiget.fmt & HDF_STRING;
5240 /* set text alignment (leftmost column must be left-aligned) */
5243 hdi.fmt |= HDF_LEFT;
5247 if (lpColumn->fmt & LVCFMT_LEFT)
5249 hdi.fmt |= HDF_LEFT;
5251 else if (lpColumn->fmt & LVCFMT_RIGHT)
5253 hdi.fmt |= HDF_RIGHT;
5255 else if (lpColumn->fmt & LVCFMT_CENTER)
5257 hdi.fmt |= HDF_CENTER;
5261 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5263 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5266 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5268 hdi.fmt |= HDF_IMAGE;
5271 if (lpColumn->fmt & LVCFMT_IMAGE)
5273 hdi.fmt |= HDF_IMAGE;
5274 hdi.iImage = I_IMAGECALLBACK;
5278 if (lpColumn->mask & LVCF_WIDTH)
5280 hdi.mask |= HDI_WIDTH;
5281 hdi.cxy = lpColumn->cx;
5284 if (lpColumn->mask & LVCF_TEXT)
5286 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5287 hdi.pszText = lpColumn->pszText;
5288 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5289 hdi.fmt |= HDF_STRING;
5292 if (lpColumn->mask & LVCF_IMAGE)
5294 hdi.mask |= HDI_IMAGE;
5295 hdi.iImage = lpColumn->iImage;
5298 if (lpColumn->mask & LVCF_ORDER)
5300 hdi.mask |= HDI_ORDER;
5301 hdi.iOrder = lpColumn->iOrder;
5304 /* set header item attributes */
5305 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5311 /* LISTVIEW_SetColumnW */
5315 * Sets the column order array
5318 * [I] HWND : window handle
5319 * [I] INT : number of elements in column order array
5320 * [I] INT : pointer to column order array
5326 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
5328 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
5330 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
5341 * Sets the width of a column
5344 * [I] HWND : window handle
5345 * [I] INT : column index
5346 * [I] INT : column width
5352 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5354 LISTVIEW_INFO *infoPtr;
5359 /* set column width only if in report mode */
5360 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5361 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
5364 /* make sure we can get the listview info */
5365 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5367 if (!infoPtr->hwndHeader) /* make sure we have a header */
5370 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5371 * LVSCV_AUTOSIZE_USEHEADER (-2)
5376 hdi.mask = HDI_WIDTH;
5379 /* call header to update the column change */
5380 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5382 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5384 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5391 * Sets the extended listview style.
5394 * [I] HWND : window handle
5399 * SUCCESS : previous style
5402 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5404 LISTVIEW_INFO *infoPtr;
5407 /* make sure we can get the listview info */
5408 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5411 /* store previous style */
5412 dwOldStyle = infoPtr->dwExStyle;
5415 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5417 return (dwOldStyle);
5420 /* LISTVIEW_SetHotCursor */
5424 * Sets the hot item index.
5427 * [I] HWND : window handle
5431 * SUCCESS : previous hot item index
5432 * FAILURE : -1 (no hot item)
5434 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5436 LISTVIEW_INFO *infoPtr;
5439 /* make sure we can get the listview info */
5440 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5443 /* store previous index */
5444 iOldIndex = infoPtr->nHotItem;
5447 infoPtr->nHotItem = iIndex;
5454 * Sets the amount of time the cursor must hover over an item before it is selected.
5457 * [I] HWND : window handle
5458 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
5461 * Returns the previous hover time
5463 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
5465 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5466 DWORD oldHoverTime = infoPtr->dwHoverTime;
5468 infoPtr->dwHoverTime = dwHoverTime;
5470 return oldHoverTime;
5473 /* LISTVIEW_SetIconSpacing */
5480 * [I] HWND : window handle
5481 * [I] INT : image list type
5482 * [I] HIMAGELIST : image list handle
5485 * SUCCESS : old image list
5488 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5490 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5491 HIMAGELIST himlTemp = 0;
5496 himlTemp = infoPtr->himlNormal;
5497 infoPtr->himlNormal = himl;
5498 return (LRESULT)himlTemp;
5501 himlTemp = infoPtr->himlSmall;
5502 infoPtr->himlSmall = himl;
5503 return (LRESULT)himlTemp;
5506 himlTemp = infoPtr->himlState;
5507 infoPtr->himlState = himl;
5508 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5509 return (LRESULT)himlTemp;
5512 return (LRESULT)NULL;
5518 * Sets the attributes of an item.
5521 * [I] HWND : window handle
5522 * [I] LPLVITEM : item information
5528 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5530 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5531 BOOL bResult = FALSE;
5533 if (lpLVItem != NULL)
5535 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5537 if (lpLVItem->iSubItem == 0)
5539 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5543 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5552 /* LISTVIEW_SetItemW */
5556 * Preallocates memory.
5559 * [I] HWND : window handle
5560 * [I] INT : item count (projected number of items)
5561 * [I] DWORD : update flags
5567 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5569 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5571 FIXME("(%d %08lx)stub!\n", nItems, dwFlags);
5574 return LISTVIEW_DeleteAllItems (hwnd);
5576 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
5578 FIXME("LVS_OWNERDATA is set!\n");
5582 if (nItems > GETITEMCOUNT(infoPtr))
5585 FIXME("append items\n");
5588 else if (nItems < GETITEMCOUNT(infoPtr))
5591 while(nItems < GETITEMCOUNT(infoPtr)) {
5592 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
5602 * Sets the position of an item.
5605 * [I] HWND : window handle
5606 * [I] INT : item index
5607 * [I] INT : x coordinate
5608 * [I] INT : y coordinate
5614 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5615 INT nPosX, INT nPosY)
5617 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5618 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5619 LISTVIEW_ITEM *lpItem;
5621 BOOL bResult = FALSE;
5623 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5625 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5627 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5629 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5630 if (hdpaSubItems != NULL)
5632 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5636 lpItem->ptPosition.x = nPosX;
5637 lpItem->ptPosition.y = nPosY;
5646 /* LISTVIEW_SetItemPosition32 */
5650 * Sets the state of one or many items.
5653 * [I] HWND : window handle
5654 * [I]INT : item index
5655 * [I] LPLVITEM : item or subitem info
5661 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5663 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5664 BOOL bResult = FALSE;
5671 ZeroMemory(&lvItem, sizeof(LVITEMA));
5672 lvItem.mask = LVIF_STATE;
5673 lvItem.state = lpLVItem->state;
5674 lvItem.stateMask = lpLVItem->stateMask ;
5676 /* apply to all items */
5677 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5680 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5688 ZeroMemory(&lvItem, sizeof(LVITEMA));
5689 lvItem.mask = LVIF_STATE;
5690 lvItem.state = lpLVItem->state;
5691 lvItem.stateMask = lpLVItem->stateMask;
5692 lvItem.iItem = nItem;
5693 bResult = ListView_SetItemA(hwnd, &lvItem);
5701 * Sets the text of an item or subitem.
5704 * [I] HWND : window handle
5705 * [I] INT : item index
5706 * [I] LPLVITEMA : item or subitem info
5712 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5714 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5715 BOOL bResult = FALSE;
5718 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5720 ZeroMemory(&lvItem, sizeof(LVITEMA));
5721 lvItem.mask = LVIF_TEXT;
5722 lvItem.pszText = lpLVItem->pszText;
5723 lvItem.iItem = nItem;
5724 lvItem.iSubItem = lpLVItem->iSubItem;
5725 bResult = ListView_SetItemA(hwnd, &lvItem);
5731 /* LISTVIEW_SetItemTextW */
5735 * Set item index that marks the start of a multiple selection.
5738 * [I] HWND : window handle
5742 * Index number or -1 if there is no selection mark.
5744 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5746 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5747 INT nOldIndex = infoPtr->nSelectionMark;
5749 infoPtr->nSelectionMark = nIndex;
5756 * Sets the text background color.
5759 * [I] HWND : window handle
5760 * [I] COLORREF : text background color
5766 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5768 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5770 infoPtr->clrTextBk = clrTextBk;
5771 InvalidateRect(hwnd, NULL, TRUE);
5778 * Sets the text foreground color.
5781 * [I] HWND : window handle
5782 * [I] COLORREF : text color
5788 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5790 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5792 infoPtr->clrText = clrText;
5793 InvalidateRect(hwnd, NULL, TRUE);
5798 /* LISTVIEW_SetToolTips */
5799 /* LISTVIEW_SetUnicodeFormat */
5800 /* LISTVIEW_SetWorkAreas */
5804 * Callback internally used by LISTVIEW_SortItems()
5807 * [I] LPVOID : first LISTVIEW_ITEM to compare
5808 * [I] LPVOID : second LISTVIEW_ITEM to compare
5809 * [I] LPARAM : HWND of control
5812 * if first comes before second : negative
5813 * if first comes after second : positive
5814 * if first and second are equivalent : zero
5816 static INT WINAPI LISTVIEW_CallBackCompare(
5821 /* Forward the call to the client defined callback */
5823 HWND hwnd = (HWND)lParam;
5824 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5826 rv = (infoPtr->pfnCompare)( ((LISTVIEW_ITEM*) first)->lParam,
5827 ((LISTVIEW_ITEM*) second)->lParam, infoPtr->lParamSort );
5834 * Sorts the listview items.
5837 * [I] HWND : window handle
5838 * [I] WPARAM : application-defined value
5839 * [I] LPARAM : pointer to comparision callback
5845 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5847 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5849 LISTVIEW_ITEM *lpItem;
5853 if (!infoPtr || !infoPtr->hdpaItems)
5856 nCount = GETITEMCOUNT(infoPtr);
5857 /* if there are 0 or 1 items, there is no need to sort */
5860 sortList = DPA_Create(nCount);
5862 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5863 infoPtr->lParamSort = (LPARAM)wParam;
5865 /* append pointers one by one to sortList */
5866 for (i = 0; i < nCount; i++)
5868 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5869 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5870 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5873 /* sort the sortList */
5874 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5876 /* copy the pointers back */
5877 for (i = 0; i < nCount; i++)
5879 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5880 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5881 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5884 DPA_Destroy(sortList);
5890 /* LISTVIEW_SubItemHitTest */
5894 * Updates an items or rearranges the listview control.
5897 * [I] HWND : window handle
5898 * [I] INT : item index
5904 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5906 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5907 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5908 BOOL bResult = FALSE;
5911 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5915 /* rearrange with default alignment style */
5916 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5917 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5919 ListView_Arrange(hwnd, 0);
5923 /* get item bounding rectangle */
5924 rc.left = LVIR_BOUNDS;
5925 ListView_GetItemRect(hwnd, nItem, &rc);
5926 InvalidateRect(hwnd, &rc, TRUE);
5935 * Creates the listview control.
5938 * [I] HWND : window handle
5943 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5945 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5946 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5947 UINT uView = lpcs->style & LVS_TYPEMASK;
5950 /* initialize info pointer */
5951 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5953 /* determine the type of structures to use */
5954 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5955 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5956 if (infoPtr->notifyFormat != NFR_ANSI)
5958 FIXME("ANSI notify format is NOT used\n");
5961 /* initialize color information */
5962 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5963 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5964 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5966 /* set default values */
5967 infoPtr->uCallbackMask = 0;
5968 infoPtr->nFocusedItem = -1;
5969 infoPtr->nSelectionMark = -1;
5970 infoPtr->nHotItem = -1;
5971 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5972 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5973 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5974 infoPtr->hwndEdit = 0;
5975 infoPtr->pedititem = NULL;
5976 infoPtr->bDoEditLabel = FALSE;
5978 /* get default font (icon title) */
5979 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5980 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5981 infoPtr->hFont = infoPtr->hDefaultFont;
5984 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5985 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5986 0, 0, 0, 0, hwnd, (HMENU)0,
5987 lpcs->hInstance, NULL);
5989 /* set header font */
5990 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5993 if (uView == LVS_ICON)
5995 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5996 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5998 else if (uView == LVS_REPORT)
6000 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
6002 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6006 /* resize our header to nothing */
6010 memset(&zeroRect,0,sizeof(RECT));
6014 Header_Layout(infoPtr->hwndHeader,&hd);
6018 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6019 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6023 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6024 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6027 /* display unsupported listview window styles */
6028 LISTVIEW_UnsupportedStyles(lpcs->style);
6030 /* allocate memory for the data structure */
6031 infoPtr->hdpaItems = DPA_Create(10);
6033 /* initialize size of items */
6034 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6035 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6037 /* initialize the hover time to -1(indicating the default system hover time) */
6038 infoPtr->dwHoverTime = -1;
6045 * Erases the background of the listview control.
6048 * [I] HWND : window handle
6049 * [I] WPARAM : device context handle
6050 * [I] LPARAM : not used
6056 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
6059 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6062 if (infoPtr->clrBk == CLR_NONE)
6064 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
6069 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
6070 GetClientRect(hwnd, &rc);
6071 FillRect((HDC)wParam, &rc, hBrush);
6072 DeleteObject(hBrush);
6081 * Retrieves the listview control font.
6084 * [I] HWND : window handle
6089 static LRESULT LISTVIEW_GetFont(HWND hwnd)
6091 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6093 return infoPtr->hFont;
6098 * Performs vertical scrolling.
6101 * [I] HWND : window handle
6102 * [I] INT : scroll code
6103 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6105 * [I] HWND : scrollbar control window handle
6110 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6113 SCROLLINFO scrollInfo;
6115 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6116 scrollInfo.cbSize = sizeof(SCROLLINFO);
6117 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6119 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6121 INT nOldScrollPos = scrollInfo.nPos;
6122 switch (nScrollCode)
6125 if (scrollInfo.nPos > scrollInfo.nMin)
6132 if (scrollInfo.nPos < scrollInfo.nMax)
6139 if (scrollInfo.nPos > scrollInfo.nMin)
6141 if (scrollInfo.nPos >= scrollInfo.nPage)
6143 scrollInfo.nPos -= scrollInfo.nPage;
6147 scrollInfo.nPos = scrollInfo.nMin;
6153 if (scrollInfo.nPos < scrollInfo.nMax)
6155 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6157 scrollInfo.nPos += scrollInfo.nPage;
6161 scrollInfo.nPos = scrollInfo.nMax;
6167 scrollInfo.nPos = nCurrentPos;
6168 if (scrollInfo.nPos > scrollInfo.nMax)
6169 scrollInfo.nPos=scrollInfo.nMax;
6171 if (scrollInfo.nPos < scrollInfo.nMin)
6172 scrollInfo.nPos=scrollInfo.nMin;
6177 if (nOldScrollPos != scrollInfo.nPos)
6179 scrollInfo.fMask = SIF_POS;
6180 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
6181 InvalidateRect(hwnd, NULL, TRUE);
6190 * Performs horizontal scrolling.
6193 * [I] HWND : window handle
6194 * [I] INT : scroll code
6195 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6197 * [I] HWND : scrollbar control window handle
6202 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6205 SCROLLINFO scrollInfo;
6207 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6208 scrollInfo.cbSize = sizeof(SCROLLINFO);
6209 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6211 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6213 INT nOldScrollPos = scrollInfo.nPos;
6215 switch (nScrollCode)
6218 if (scrollInfo.nPos > scrollInfo.nMin)
6225 if (scrollInfo.nPos < scrollInfo.nMax)
6232 if (scrollInfo.nPos > scrollInfo.nMin)
6234 if (scrollInfo.nPos >= scrollInfo.nPage)
6236 scrollInfo.nPos -= scrollInfo.nPage;
6240 scrollInfo.nPos = scrollInfo.nMin;
6246 if (scrollInfo.nPos < scrollInfo.nMax)
6248 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6250 scrollInfo.nPos += scrollInfo.nPage;
6254 scrollInfo.nPos = scrollInfo.nMax;
6260 scrollInfo.nPos = nCurrentPos;
6262 if (scrollInfo.nPos > scrollInfo.nMax)
6263 scrollInfo.nPos=scrollInfo.nMax;
6265 if (scrollInfo.nPos < scrollInfo.nMin)
6266 scrollInfo.nPos=scrollInfo.nMin;
6270 if (nOldScrollPos != scrollInfo.nPos)
6272 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6273 scrollInfo.fMask = SIF_POS;
6274 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6275 if(uView == LVS_REPORT)
6277 scrollInfo.fMask = SIF_POS;
6278 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6279 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6281 InvalidateRect(hwnd, NULL, TRUE);
6288 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
6290 INT gcWheelDelta = 0;
6291 UINT pulScrollLines = 3;
6292 SCROLLINFO scrollInfo;
6294 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6296 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
6297 gcWheelDelta -= wheelDelta;
6299 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6300 scrollInfo.cbSize = sizeof(SCROLLINFO);
6301 scrollInfo.fMask = SIF_POS | SIF_RANGE;
6308 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
6309 * should be fixed in the future.
6311 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6312 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
6316 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
6318 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6320 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
6321 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
6322 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
6328 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
6339 * [I] HWND : window handle
6340 * [I] INT : virtual key
6341 * [I] LONG : key data
6346 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6348 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6349 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6350 HWND hwndParent = GetParent(hwnd);
6351 NMLVKEYDOWN nmKeyDown;
6354 BOOL bRedraw = FALSE;
6356 /* send LVN_KEYDOWN notification */
6357 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6358 nmKeyDown.hdr.hwndFrom = hwnd;
6359 nmKeyDown.hdr.idFrom = nCtrlId;
6360 nmKeyDown.hdr.code = LVN_KEYDOWN;
6361 nmKeyDown.wVKey = nVirtualKey;
6362 nmKeyDown.flags = 0;
6363 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6366 nmh.hwndFrom = hwnd;
6367 nmh.idFrom = nCtrlId;
6369 switch (nVirtualKey)
6372 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6374 /* send NM_RETURN notification */
6375 nmh.code = NM_RETURN;
6376 ListView_Notify(hwndParent, nCtrlId, &nmh);
6378 /* send LVN_ITEMACTIVATE notification */
6379 nmh.code = LVN_ITEMACTIVATE;
6380 ListView_Notify(hwndParent, nCtrlId, &nmh);
6385 if (GETITEMCOUNT(infoPtr) > 0)
6392 if (GETITEMCOUNT(infoPtr) > 0)
6394 nItem = GETITEMCOUNT(infoPtr) - 1;
6399 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6403 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6407 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6411 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6423 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6425 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6426 if (bRedraw != FALSE)
6428 /* refresh client area */
6429 InvalidateRect(hwnd, NULL, TRUE);
6442 * [I] HWND : window handle
6447 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6449 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6450 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6453 TRACE("(hwnd=%x)\n", hwnd);
6455 /* send NM_KILLFOCUS notification */
6456 nmh.hwndFrom = hwnd;
6457 nmh.idFrom = nCtrlId;
6458 nmh.code = NM_KILLFOCUS;
6459 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6461 /* set window focus flag */
6462 infoPtr->bFocus = FALSE;
6464 /* NEED drawing optimization ; redraw the selected items */
6465 InvalidateRect(hwnd, NULL, FALSE);
6472 * Processes double click messages (left mouse button).
6475 * [I] HWND : window handle
6476 * [I] WORD : key flag
6477 * [I] WORD : x coordinate
6478 * [I] WORD : y coordinate
6483 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6486 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6488 LVHITTESTINFO htInfo;
6490 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6492 /* send NM_DBLCLK notification */
6493 nmh.hwndFrom = hwnd;
6494 nmh.idFrom = nCtrlId;
6495 nmh.code = NM_DBLCLK;
6496 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6498 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
6499 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6500 htInfo.pt.x = wPosX;
6501 htInfo.pt.y = wPosY;
6502 if(LISTVIEW_HitTest(hwnd, &htInfo) != -1)
6504 /* send LVN_ITEMACTIVATE notification */
6505 nmh.code = LVN_ITEMACTIVATE;
6506 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6514 * Processes mouse down messages (left mouse button).
6517 * [I] HWND : window handle
6518 * [I] WORD : key flag
6519 * [I] WORD : x coordinate
6520 * [I] WORD : y coordinate
6525 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6528 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6529 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6530 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6531 static BOOL bGroupSelect = TRUE;
6536 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6539 /* send NM_RELEASEDCAPTURE notification */
6540 nmh.hwndFrom = hwnd;
6541 nmh.idFrom = nCtrlId;
6542 nmh.code = NM_RELEASEDCAPTURE;
6543 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6545 if (infoPtr->bFocus == FALSE)
6550 /* set left button down flag */
6551 infoPtr->bLButtonDown = TRUE;
6553 ptPosition.x = wPosX;
6554 ptPosition.y = wPosY;
6555 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6556 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6558 if (lStyle & LVS_SINGLESEL)
6560 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
6561 && infoPtr->bDoEditLabel != TRUE)
6563 infoPtr->bDoEditLabel = TRUE;
6567 LISTVIEW_SetSelection(hwnd, nItem);
6572 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6574 if (bGroupSelect != FALSE)
6576 LISTVIEW_AddGroupSelection(hwnd, nItem);
6580 LISTVIEW_AddSelection(hwnd, nItem);
6583 else if (wKey & MK_CONTROL)
6585 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6587 else if (wKey & MK_SHIFT)
6589 LISTVIEW_SetGroupSelection(hwnd, nItem);
6593 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED
6594 && infoPtr->bDoEditLabel != TRUE)
6596 infoPtr->bDoEditLabel = TRUE;
6600 LISTVIEW_SetSelection(hwnd, nItem);
6608 /* remove all selections */
6609 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6612 InvalidateRect(hwnd, NULL, TRUE);
6619 * Processes mouse up messages (left mouse button).
6622 * [I] HWND : window handle
6623 * [I] WORD : key flag
6624 * [I] WORD : x coordinate
6625 * [I] WORD : y coordinate
6630 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6633 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6635 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6637 if (infoPtr->bLButtonDown != FALSE)
6639 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6642 /* send NM_CLICK notification */
6643 nmh.hwndFrom = hwnd;
6644 nmh.idFrom = nCtrlId;
6645 nmh.code = NM_CLICK;
6646 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6648 /* set left button flag */
6649 infoPtr->bLButtonDown = FALSE;
6651 if(infoPtr->bDoEditLabel)
6653 LVHITTESTINFO htInfo;
6655 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6656 htInfo.pt.x = wPosX;
6657 htInfo.pt.y = wPosY;
6658 nItem = LISTVIEW_HitTest(hwnd, &htInfo);
6659 if(nItem != -1 && htInfo.flags == LVHT_ONITEMLABEL)
6661 LISTVIEW_EditLabelA(hwnd, nItem);
6663 infoPtr->bDoEditLabel = FALSE;
6672 * Creates the listview control (called before WM_CREATE).
6675 * [I] HWND : window handle
6676 * [I] WPARAM : unhandled
6677 * [I] LPARAM : widow creation info
6682 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6684 LISTVIEW_INFO *infoPtr;
6686 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6688 /* allocate memory for info structure */
6689 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6690 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6691 if (infoPtr == NULL)
6693 ERR("could not allocate info memory!\n");
6697 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6699 ERR("pointer assignment error!\n");
6703 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6708 * Destroys the listview control (called after WM_DESTROY).
6711 * [I] HWND : window handle
6716 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6718 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6720 TRACE("(hwnd=%x)\n", hwnd);
6722 /* delete all items */
6723 LISTVIEW_DeleteAllItems(hwnd);
6725 /* destroy data structure */
6726 DPA_Destroy(infoPtr->hdpaItems);
6729 infoPtr->hFont = (HFONT)0;
6730 if (infoPtr->hDefaultFont)
6732 DeleteObject(infoPtr->hDefaultFont);
6735 /* free listview info pointer*/
6736 COMCTL32_Free(infoPtr);
6738 SetWindowLongA(hwnd, 0, 0);
6744 * Handles notifications from children.
6747 * [I] HWND : window handle
6748 * [I] INT : control identifier
6749 * [I] LPNMHDR : notification information
6754 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6756 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6758 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6760 /* handle notification from header control */
6761 if (lpnmh->code == HDN_ENDTRACKA)
6763 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6764 InvalidateRect(hwnd, NULL, TRUE);
6766 else if(lpnmh->code == HDN_ITEMCLICKA)
6768 /* Handle sorting by Header Column */
6770 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
6771 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
6773 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
6774 nmlv.hdr.hwndFrom = hwnd;
6775 nmlv.hdr.idFrom = lCtrlId;
6776 nmlv.hdr.code = LVN_COLUMNCLICK;
6778 nmlv.iSubItem = pnmHeader->iItem;
6780 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
6783 else if(lpnmh->code == NM_RELEASEDCAPTURE)
6785 /* Idealy this should be done in HDN_ENDTRACKA
6786 * but since SetItemBounds in Header.c is called after
6787 * the notification is sent, it is neccessary to handle the
6788 * update of the scroll bar here (Header.c works fine as it is,
6789 * no need to disturb it)
6791 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6792 LISTVIEW_UpdateScroll(hwnd);
6793 InvalidateRect(hwnd, NULL, TRUE);
6803 * Determines the type of structure to use.
6806 * [I] HWND : window handle of the sender
6807 * [I] HWND : listview window handle
6808 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6813 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6815 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6817 if (nCommand == NF_REQUERY)
6819 /* determine the type of structure to use */
6820 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6821 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6822 if (infoPtr->notifyFormat == NFR_UNICODE)
6824 FIXME("NO support for unicode structures");
6833 * Paints/Repaints the listview control.
6836 * [I] HWND : window handle
6837 * [I] HDC : device context handle
6842 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6846 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6850 hdc = BeginPaint(hwnd, &ps);
6851 LISTVIEW_Refresh(hwnd, hdc);
6852 EndPaint(hwnd, &ps);
6856 LISTVIEW_Refresh(hwnd, hdc);
6864 * Processes double click messages (right mouse button).
6867 * [I] HWND : window handle
6868 * [I] WORD : key flag
6869 * [I] WORD : x coordinate
6870 * [I] WORD : y coordinate
6875 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6878 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6881 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6883 /* send NM_RELEASEDCAPTURE notification */
6884 nmh.hwndFrom = hwnd;
6885 nmh.idFrom = nCtrlId;
6886 nmh.code = NM_RELEASEDCAPTURE;
6887 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6889 /* send NM_RDBLCLK notification */
6890 nmh.code = NM_RDBLCLK;
6891 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6898 * Processes mouse down messages (right mouse button).
6901 * [I] HWND : window handle
6902 * [I] WORD : key flag
6903 * [I] WORD : x coordinate
6904 * [I] WORD : y coordinate
6909 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6912 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6913 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6918 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6920 /* send NM_RELEASEDCAPTURE notification */
6921 nmh.hwndFrom = hwnd;
6922 nmh.idFrom = nCtrlId;
6923 nmh.code = NM_RELEASEDCAPTURE;
6924 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6926 /* make sure the listview control window has the focus */
6927 if (infoPtr->bFocus == FALSE)
6932 /* set right button down flag */
6933 infoPtr->bRButtonDown = TRUE;
6935 /* determine the index of the selected item */
6936 ptPosition.x = wPosX;
6937 ptPosition.y = wPosY;
6938 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6939 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6941 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6943 LISTVIEW_SetSelection(hwnd, nItem);
6948 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6956 * Processes mouse up messages (right mouse button).
6959 * [I] HWND : window handle
6960 * [I] WORD : key flag
6961 * [I] WORD : x coordinate
6962 * [I] WORD : y coordinate
6967 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6970 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6971 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6974 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6976 if (infoPtr->bRButtonDown != FALSE)
6982 /* Send NM_RClICK notification */
6983 ZeroMemory(&nmh, sizeof(NMHDR));
6984 nmh.hwndFrom = hwnd;
6985 nmh.idFrom = nCtrlId;
6986 nmh.code = NM_RCLICK;
6987 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6989 /* set button flag */
6990 infoPtr->bRButtonDown = FALSE;
6992 /* Change to screen coordinate for WM_CONTEXTMENU */
6993 ClientToScreen(hwnd, &pt);
6995 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
6996 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
7007 * [I] HWND : window handle
7008 * [I] HWND : window handle of previously focused window
7013 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
7015 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7016 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7019 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
7021 /* send NM_SETFOCUS notification */
7022 nmh.hwndFrom = hwnd;
7023 nmh.idFrom = nCtrlId;
7024 nmh.code = NM_SETFOCUS;
7025 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7027 /* set window focus flag */
7028 infoPtr->bFocus = TRUE;
7030 InvalidateRect(hwnd, NULL, TRUE);
7041 * [I] HWND : window handle
7042 * [I] HFONT : font handle
7043 * [I] WORD : redraw flag
7048 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
7050 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7051 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7053 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
7057 infoPtr->hFont = infoPtr->hDefaultFont;
7061 infoPtr->hFont = hFont;
7064 if (uView == LVS_REPORT)
7066 /* set header font */
7067 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
7068 MAKELPARAM(fRedraw, 0));
7071 /* invalidate listview control client area */
7072 InvalidateRect(hwnd, NULL, TRUE);
7074 if (fRedraw != FALSE)
7084 * Message handling for WM_SETREDRAW.
7085 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
7088 * [I] HWND : window handle
7089 * [I] bRedraw: state of redraw flag
7092 * DefWinProc return value
7094 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
7097 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
7100 RedrawWindow(hwnd, NULL, 0,
7101 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
7108 * Resizes the listview control. This function processes WM_SIZE
7109 * messages. At this time, the width and height are not used.
7112 * [I] HWND : window handle
7113 * [I] WORD : new width
7114 * [I] WORD : new height
7119 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
7121 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7122 UINT uView = lStyle & LVS_TYPEMASK;
7124 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
7126 LISTVIEW_UpdateSize(hwnd);
7128 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
7130 if (lStyle & LVS_ALIGNLEFT)
7132 LISTVIEW_AlignLeft(hwnd);
7136 LISTVIEW_AlignTop(hwnd);
7140 LISTVIEW_UpdateScroll(hwnd);
7142 /* invalidate client area + erase background */
7143 InvalidateRect(hwnd, NULL, TRUE);
7150 * Sets the size information.
7153 * [I] HWND : window handle
7158 static VOID LISTVIEW_UpdateSize(HWND hwnd)
7160 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7161 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7162 UINT uView = lStyle & LVS_TYPEMASK;
7165 GetClientRect(hwnd, &rcList);
7166 infoPtr->rcList.left = 0;
7167 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
7168 infoPtr->rcList.top = 0;
7169 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
7171 if (uView == LVS_LIST)
7173 if ((lStyle & WS_HSCROLL) == 0)
7175 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
7176 if (infoPtr->rcList.bottom > nHScrollHeight)
7178 infoPtr->rcList.bottom -= nHScrollHeight;
7182 else if ((uView == LVS_REPORT)&&(!(LVS_NOCOLUMNHEADER & lStyle)))
7189 Header_Layout(infoPtr->hwndHeader, &hl);
7191 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
7193 if (!(LVS_NOCOLUMNHEADER & lStyle))
7195 infoPtr->rcList.top = max(wp.cy, 0);
7202 * Processes WM_STYLECHANGED messages.
7205 * [I] HWND : window handle
7206 * [I] WPARAM : window style type (normal or extended)
7207 * [I] LPSTYLESTRUCT : window style information
7212 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
7215 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7216 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
7217 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
7218 RECT rcList = infoPtr->rcList;
7220 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
7221 hwnd, wStyleType, lpss);
7223 if (wStyleType == GWL_STYLE)
7225 if (uOldView == LVS_REPORT)
7227 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
7230 if ((lpss->styleOld & WS_HSCROLL) != 0)
7232 ShowScrollBar(hwnd, SB_HORZ, FALSE);
7235 if ((lpss->styleOld & WS_VSCROLL) != 0)
7237 ShowScrollBar(hwnd, SB_VERT, FALSE);
7240 if (uNewView == LVS_ICON)
7242 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7243 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7244 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7245 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7246 if (lpss->styleNew & LVS_ALIGNLEFT)
7248 LISTVIEW_AlignLeft(hwnd);
7252 LISTVIEW_AlignTop(hwnd);
7255 else if (uNewView == LVS_REPORT)
7260 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
7264 Header_Layout(infoPtr->hwndHeader, &hl);
7265 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
7267 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7272 ZeroMemory(&zeroRect,sizeof(RECT));
7276 Header_Layout(infoPtr->hwndHeader, &hl);
7279 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7280 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7281 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7282 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7284 else if (uNewView == LVS_LIST)
7286 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7287 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7288 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7289 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7293 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7294 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7295 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7296 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7297 if (lpss->styleNew & LVS_ALIGNLEFT)
7299 LISTVIEW_AlignLeft(hwnd);
7303 LISTVIEW_AlignTop(hwnd);
7307 /* update the size of the client area */
7308 LISTVIEW_UpdateSize(hwnd);
7310 /* add scrollbars if needed */
7311 LISTVIEW_UpdateScroll(hwnd);
7313 /* invalidate client area + erase background */
7314 InvalidateRect(hwnd, NULL, TRUE);
7316 /* print the list of unsupported window styles */
7317 LISTVIEW_UnsupportedStyles(lpss->styleNew);
7320 /* If they change the view and we have an active edit control
7321 we will need to kill the control since the redraw will
7322 misplace the edit control.
7324 if (infoPtr->hwndEdit &&
7325 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
7326 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
7328 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7336 * Window procedure of the listview control.
7339 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
7342 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
7343 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
7344 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
7347 case LVM_APPROXIMATEVIEWRECT:
7348 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
7349 LOWORD(lParam), HIWORD(lParam));
7351 return LISTVIEW_Arrange(hwnd, (INT)wParam);
7353 /* case LVM_CREATEDRAGIMAGE: */
7355 case LVM_DELETEALLITEMS:
7356 return LISTVIEW_DeleteAllItems(hwnd);
7358 case LVM_DELETECOLUMN:
7359 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
7361 case LVM_DELETEITEM:
7362 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
7364 case LVM_EDITLABELW:
7365 case LVM_EDITLABELA:
7366 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
7368 case LVM_ENSUREVISIBLE:
7369 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
7372 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
7374 case LVM_GETBKCOLOR:
7375 return LISTVIEW_GetBkColor(hwnd);
7377 /* case LVM_GETBKIMAGE: */
7379 case LVM_GETCALLBACKMASK:
7380 return LISTVIEW_GetCallbackMask(hwnd);
7382 case LVM_GETCOLUMNA:
7383 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7385 /* case LVM_GETCOLUMNW: */
7387 case LVM_GETCOLUMNORDERARRAY:
7388 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7390 case LVM_GETCOLUMNWIDTH:
7391 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
7393 case LVM_GETCOUNTPERPAGE:
7394 return LISTVIEW_GetCountPerPage(hwnd);
7396 case LVM_GETEDITCONTROL:
7397 return LISTVIEW_GetEditControl(hwnd);
7399 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7400 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7403 return LISTVIEW_GetHeader(hwnd);
7405 /* case LVM_GETHOTCURSOR: */
7407 case LVM_GETHOTITEM:
7408 return LISTVIEW_GetHotItem(hwnd);
7410 case LVM_GETHOVERTIME:
7411 return LISTVIEW_GetHoverTime(hwnd);
7413 case LVM_GETIMAGELIST:
7414 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7416 /* case LVM_GETISEARCHSTRING: */
7419 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
7421 /* case LVM_GETITEMW: */
7423 case LVM_GETITEMCOUNT:
7424 return LISTVIEW_GetItemCount(hwnd);
7426 case LVM_GETITEMPOSITION:
7427 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7429 case LVM_GETITEMRECT:
7430 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7432 case LVM_GETITEMSPACING:
7433 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7435 case LVM_GETITEMSTATE:
7436 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7438 case LVM_GETITEMTEXTA:
7439 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7442 /* case LVM_GETITEMTEXTW: */
7444 case LVM_GETNEXTITEM:
7445 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7447 /* case LVM_GETNUMBEROFWORKAREAS: */
7450 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7452 case LVM_GETSELECTEDCOUNT:
7453 return LISTVIEW_GetSelectedCount(hwnd);
7455 case LVM_GETSELECTIONMARK:
7456 return LISTVIEW_GetSelectionMark(hwnd);
7458 case LVM_GETSTRINGWIDTHA:
7459 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7461 /* case LVM_GETSTRINGWIDTHW: */
7462 /* case LVM_GETSUBITEMRECT: */
7464 case LVM_GETTEXTBKCOLOR:
7465 return LISTVIEW_GetTextBkColor(hwnd);
7467 case LVM_GETTEXTCOLOR:
7468 return LISTVIEW_GetTextColor(hwnd);
7470 /* case LVM_GETTOOLTIPS: */
7472 case LVM_GETTOPINDEX:
7473 return LISTVIEW_GetTopIndex(hwnd);
7475 /* case LVM_GETUNICODEFORMAT: */
7477 case LVM_GETVIEWRECT:
7478 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7480 /* case LVM_GETWORKAREAS: */
7483 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7485 case LVM_INSERTCOLUMNA:
7486 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7488 case LVM_INSERTCOLUMNW:
7489 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7491 case LVM_INSERTITEMA:
7492 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7494 case LVM_INSERTITEMW:
7495 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7497 case LVM_REDRAWITEMS:
7498 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7500 /* case LVM_SCROLL: */
7501 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7503 case LVM_SETBKCOLOR:
7504 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7506 /* case LVM_SETBKIMAGE: */
7508 case LVM_SETCALLBACKMASK:
7509 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7511 case LVM_SETCOLUMNA:
7512 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7514 case LVM_SETCOLUMNW:
7515 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7518 case LVM_SETCOLUMNORDERARRAY:
7519 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7521 case LVM_SETCOLUMNWIDTH:
7522 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
7524 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7525 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7527 /* case LVM_SETHOTCURSOR: */
7529 case LVM_SETHOTITEM:
7530 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7532 case LVM_SETHOVERTIME:
7533 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
7535 /* case LVM_SETICONSPACING: */
7537 case LVM_SETIMAGELIST:
7538 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7541 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7543 /* case LVM_SETITEMW: */
7545 case LVM_SETITEMCOUNT:
7546 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7548 case LVM_SETITEMPOSITION:
7549 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7550 (INT)HIWORD(lParam));
7552 /* case LVM_SETITEMPOSITION32: */
7554 case LVM_SETITEMSTATE:
7555 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7557 case LVM_SETITEMTEXTA:
7558 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7560 /* case LVM_SETITEMTEXTW: */
7562 case LVM_SETSELECTIONMARK:
7563 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7565 case LVM_SETTEXTBKCOLOR:
7566 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7568 case LVM_SETTEXTCOLOR:
7569 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7571 /* case LVM_SETTOOLTIPS: */
7572 /* case LVM_SETUNICODEFORMAT: */
7573 /* case LVM_SETWORKAREAS: */
7576 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7578 /* case LVM_SUBITEMHITTEST: */
7581 return LISTVIEW_Update(hwnd, (INT)wParam);
7585 return LISTVIEW_Command(hwnd, wParam, lParam);
7588 return LISTVIEW_Create(hwnd, wParam, lParam);
7591 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7594 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7597 return LISTVIEW_GetFont(hwnd);
7600 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7601 (INT)HIWORD(wParam), (HWND)lParam);
7604 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7607 return LISTVIEW_KillFocus(hwnd);
7609 case WM_LBUTTONDBLCLK:
7610 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7613 case WM_LBUTTONDOWN:
7614 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7617 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7620 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
7623 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
7626 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7629 return LISTVIEW_NCDestroy(hwnd);
7632 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7634 case WM_NOTIFYFORMAT:
7635 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7638 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7640 case WM_RBUTTONDBLCLK:
7641 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7644 case WM_RBUTTONDOWN:
7645 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7649 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7653 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7656 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7659 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
7662 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7664 case WM_STYLECHANGED:
7665 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7667 /* case WM_TIMER: */
7670 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7671 (INT)HIWORD(wParam), (HWND)lParam);
7674 if (wParam & (MK_SHIFT | MK_CONTROL))
7675 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
7676 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
7678 /* case WM_WININICHANGE: */
7681 if (uMsg >= WM_USER)
7683 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
7687 /* call default window procedure */
7688 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
7696 * Registers the window class.
7704 VOID LISTVIEW_Register(void)
7708 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
7709 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
7710 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
7711 wndClass.cbClsExtra = 0;
7712 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
7713 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
7714 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
7715 wndClass.lpszClassName = WC_LISTVIEWA;
7716 RegisterClassA(&wndClass);
7721 * Unregisters the window class.
7729 VOID LISTVIEW_Unregister(void)
7731 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
7736 * Handle any WM_COMMAND messages
7742 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
7744 switch (HIWORD(wParam))
7749 * Adjust the edit window size
7752 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7753 HDC hdc = GetDC(infoPtr->hwndEdit);
7754 HFONT hFont, hOldFont = 0;
7759 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
7760 GetWindowRect(infoPtr->hwndEdit, &rect);
7762 /* Select font to get the right dimension of the string */
7763 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
7766 hOldFont = SelectObject(hdc, hFont);
7769 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
7771 TEXTMETRICA textMetric;
7773 /* Add Extra spacing for the next character */
7774 GetTextMetricsA(hdc, &textMetric);
7775 sz.cx += (textMetric.tmMaxCharWidth * 2);
7783 rect.bottom - rect.top,
7784 SWP_DRAWFRAME|SWP_NOMOVE);
7788 SelectObject(hdc, hOldFont);
7791 ReleaseDC(hwnd, hdc);
7797 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
7806 * Subclassed edit control windproc function
7812 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
7813 WPARAM wParam, LPARAM lParam)
7815 BOOL cancel = FALSE;
7816 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
7817 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
7818 static BOOL bIgnoreKillFocus = FALSE;
7822 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
7825 if(bIgnoreKillFocus)
7833 WNDPROC editProc = einfo->EditWndProc;
7834 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
7835 COMCTL32_Free(einfo);
7836 infoPtr->pedititem = NULL;
7837 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
7841 if (VK_ESCAPE == (INT)wParam)
7847 else if (VK_RETURN == (INT)wParam)
7851 return CallWindowProcA(einfo->EditWndProc, hwnd,
7852 uMsg, wParam, lParam);
7855 if (einfo->EditLblCb)
7857 char *buffer = NULL;
7862 int len = 1 + GetWindowTextLengthA(hwnd);
7866 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
7868 GetWindowTextA(hwnd, buffer, len);
7872 /* Processing LVN_ENDLABELEDIT message could kill the focus */
7873 /* eg. Using a messagebox */
7874 bIgnoreKillFocus = TRUE;
7875 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
7878 COMCTL32_Free(buffer);
7880 einfo->EditLblCb = NULL;
7881 bIgnoreKillFocus = FALSE;
7884 SendMessageA(hwnd, WM_CLOSE, 0, 0);
7891 * Creates a subclassed edit cotrol
7897 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
7898 INT width, INT height, HWND parent, HINSTANCE hinst,
7899 EditlblCallback EditLblCb, DWORD param)
7905 TEXTMETRICA textMetric;
7906 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
7908 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
7911 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
7912 hdc = GetDC(parent);
7914 /* Select the font to get appropriate metric dimensions */
7915 if(infoPtr->hFont != 0)
7917 hOldFont = SelectObject(hdc, infoPtr->hFont);
7920 /*Get String Lenght in pixels */
7921 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
7923 /*Add Extra spacing for the next character */
7924 GetTextMetricsA(hdc, &textMetric);
7925 sz.cx += (textMetric.tmMaxCharWidth * 2);
7927 if(infoPtr->hFont != 0)
7929 SelectObject(hdc, hOldFont);
7932 ReleaseDC(parent, hdc);
7933 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
7934 parent, 0, hinst, 0)))
7936 COMCTL32_Free(infoPtr->pedititem);
7940 infoPtr->pedititem->param = param;
7941 infoPtr->pedititem->EditLblCb = EditLblCb;
7942 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
7943 GWL_WNDPROC, (LONG) EditLblWndProc);
7945 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);