4 * Copyright 1998 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.
15 * LISTVIEW_Notify : most notifications from children (editbox and header)
18 * LISTVIEW_SetItemCount : empty stub
21 * LISTVIEW_SetItem32W : no unicode support
22 * LISTVIEW_InsertItem32W : no unicode support
23 * LISTVIEW_InsertColumn32W : no unicode support
24 * LISTVIEW_GetColumnW : no unicode support
26 * Advanced functionality:
27 * LISTVIEW_GetNumberOfWorkAreas : not implemented
28 * LISTVIEW_GetHotCursor : not implemented
29 * LISTVIEW_GetHotItem : not implemented
30 * LISTVIEW_GetHoverTime : not implemented
31 * LISTVIEW_GetISearchString : not implemented
32 * LISTVIEW_GetBkImage : not implemented
33 * LISTVIEW_EditLabel : REPORT (need to implement a timer)
34 * LISTVIEW_GetColumnOrderArray : not implemented
35 * LISTVIEW_Arrange : empty stub
36 * LISTVIEW_ApproximateViewRect : incomplete
37 * LISTVIEW_Scroll : not implemented
38 * LISTVIEW_RedrawItems : empty stub
39 * LISTVIEW_Update : not completed
46 #include "debugtools.h"
48 DEFAULT_DEBUG_CHANNEL(listview)
54 /* maximum size of a label */
55 #define DISP_TEXT_SIZE 128
57 /* padding for items in list and small icon display modes */
58 #define WIDTH_PADDING 12
60 /* padding for items in list, report and small icon display modes */
61 #define HEIGHT_PADDING 1
63 /* offset of items in report display mode */
64 #define REPORT_MARGINX 2
66 /* padding for icon in large icon display mode */
67 #define ICON_TOP_PADDING 2
68 #define ICON_BOTTOM_PADDING 2
70 /* padding for label in large icon display mode */
71 #define LABEL_VERT_OFFSET 2
73 /* default label width for items in list and small icon display modes */
74 #define DEFAULT_LABEL_WIDTH 40
76 /* default column width for items in list display mode */
77 #define DEFAULT_COLUMN_WIDTH 96
82 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
83 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
84 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
85 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
86 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
87 /* retrieve the number of items in the listview */
88 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
91 * forward declarations
93 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
94 static INT LISTVIEW_GetCountPerRow(HWND);
95 static INT LISTVIEW_GetCountPerColumn(HWND);
96 static VOID LISTVIEW_AlignLeft(HWND);
97 static VOID LISTVIEW_AlignTop(HWND);
98 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
99 static VOID LISTVIEW_AddSelection(HWND, INT);
100 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
101 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
102 static INT LISTVIEW_GetItemHeight(HWND);
103 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
104 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
105 static INT LISTVIEW_GetItemWidth(HWND);
106 static INT LISTVIEW_GetLabelWidth(HWND, INT);
107 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
108 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
109 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
110 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
111 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
112 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
113 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
114 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
115 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
116 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
117 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
118 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
119 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
120 static VOID LISTVIEW_UpdateScroll(HWND);
121 static VOID LISTVIEW_SetSelection(HWND, INT);
122 static VOID LISTVIEW_UpdateSize(HWND);
123 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
124 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
125 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
126 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
130 * Update the scrollbars. This functions should be called whenever
131 * the content, size or view changes.
134 * [I] HWND : window handle
139 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
141 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
142 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
143 UINT uView = lStyle & LVS_TYPEMASK;
144 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
145 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
146 SCROLLINFO scrollInfo;
148 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
149 scrollInfo.cbSize = sizeof(SCROLLINFO);
151 if (uView == LVS_LIST)
153 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
154 INT nCountPerPage = LISTVIEW_GetCountPerRow(hwnd) * nCountPerColumn;
155 if (nCountPerPage < GETITEMCOUNT(infoPtr))
157 /* calculate new scrollbar range */
158 INT nHiddenItemCount = GETITEMCOUNT(infoPtr) - nCountPerPage;
159 if (nHiddenItemCount % nCountPerColumn == 0)
161 scrollInfo.nMax = nHiddenItemCount / nCountPerColumn;
165 scrollInfo.nMax = nHiddenItemCount / nCountPerColumn + 1;
168 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
169 /*scrollInfo.nPage = LISTVIEW_GetCountPerRow(hwnd);*/
170 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
171 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
176 if (lStyle & WS_HSCROLL)
178 ShowScrollBar(hwnd, SB_HORZ, FALSE);
182 else if (uView == LVS_REPORT)
184 /* update vertical scrollbar */
186 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - LISTVIEW_GetCountPerColumn(hwnd);
187 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
188 /*scrollInfo.nPage = nCountPerColumn;*/
189 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
190 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
192 /* update horizontal scrollbar */
193 /* if (infoPtr->nItemWidth > nListWidth) */
195 /* scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; */
196 /* SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE); */
199 /* horizontal scrolling has not been implemented yet! I experienced some
200 problems when performing child window scrolling. */
206 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
208 INT nViewWidth = rcView.right - rcView.left;
209 INT nViewHeight = rcView.bottom - rcView.top;
211 if (nViewWidth > nListWidth)
214 INT nScrollPosWidth = nListWidth / 10;
216 if (nScrollPosWidth == 0)
219 nHiddenWidth = nViewWidth - nListWidth;
223 nHiddenWidth = nViewWidth - nScrollPosWidth * 10;
226 scrollInfo.fMask = SIF_POS;
227 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
232 if (nHiddenWidth % nScrollPosWidth == 0)
234 scrollInfo.nMax = nHiddenWidth / nScrollPosWidth;
238 scrollInfo.nMax = nHiddenWidth / nScrollPosWidth + 1;
242 /*scrollInfo.nPage = 10;*/
243 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
244 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
248 if (lStyle & WS_HSCROLL)
250 ShowScrollBar(hwnd, SB_HORZ, FALSE);
254 if (nViewHeight > nListHeight)
257 INT nScrollPosHeight = nListHeight / 10;
259 if (nScrollPosHeight == 0)
261 nScrollPosHeight = 1;
262 nHiddenHeight = nViewHeight - nListHeight;
266 nHiddenHeight = nViewHeight - nScrollPosHeight * 10;
269 scrollInfo.fMask = SIF_POS;
270 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE)
275 if (nHiddenHeight % nScrollPosHeight == 0)
277 scrollInfo.nMax = nHiddenHeight / nScrollPosHeight;
281 scrollInfo.nMax = nHiddenHeight / nScrollPosHeight + 1;
285 /*scrollInfo.nPage = 10;*/
286 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
287 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
291 if (lStyle & WS_VSCROLL)
293 ShowScrollBar(hwnd, SB_VERT, FALSE);
302 * Prints a message for unsupported window styles.
303 * A kind of TODO list for window styles.
306 * [I] LONG : window style
311 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
313 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
315 FIXME(" LVS_EDITLABELS\n");
318 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
320 FIXME(" LVS_NOLABELWRAP\n");
323 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
325 FIXME(" LVS_NOSCROLL\n");
328 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
330 FIXME(" LVS_NOSORTHEADER\n");
333 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
335 FIXME(" LVS_OWNERDRAWFIXED\n");
338 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
340 FIXME(" LVS_SHAREIMAGELISTS\n");
343 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
345 FIXME(" LVS_SORTASCENDING\n");
348 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
350 FIXME(" LVS_SORTDESCENDING\n");
356 * Aligns the items with the top edge of the window.
359 * [I] HWND : window handle
364 static VOID LISTVIEW_AlignTop(HWND hwnd)
366 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
367 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
368 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
373 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
375 ZeroMemory(&ptItem, sizeof(POINT));
376 ZeroMemory(&rcView, sizeof(RECT));
378 if (nListWidth > infoPtr->nItemWidth)
380 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
382 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
385 ptItem.y += infoPtr->nItemHeight;
388 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
389 ptItem.x += infoPtr->nItemWidth;
390 rcView.right = max(rcView.right, ptItem.x);
393 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
397 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
399 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
400 ptItem.y += infoPtr->nItemHeight;
403 rcView.right = infoPtr->nItemWidth;
404 rcView.bottom = ptItem.y;
407 LISTVIEW_SetViewRect(hwnd, &rcView);
413 * Aligns the items with the left edge of the window.
416 * [I] HWND : window handle
421 static VOID LISTVIEW_AlignLeft(HWND hwnd)
423 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
424 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
425 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
430 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
432 ZeroMemory(&ptItem, sizeof(POINT));
433 ZeroMemory(&rcView, sizeof(RECT));
435 if (nListHeight > infoPtr->nItemHeight)
437 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
439 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
442 ptItem.x += infoPtr->nItemWidth;
445 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
446 ptItem.y += infoPtr->nItemHeight;
447 rcView.bottom = max(rcView.bottom, ptItem.y);
450 rcView.right = ptItem.x + infoPtr->nItemWidth;
454 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
456 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
457 ptItem.x += infoPtr->nItemWidth;
460 rcView.bottom = infoPtr->nItemHeight;
461 rcView.right = ptItem.x;
464 LISTVIEW_SetViewRect(hwnd, &rcView);
470 * Set the bounding rectangle of all the items.
473 * [I] HWND : window handle
474 * [I] LPRECT : bounding rectangle
480 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
482 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
483 BOOL bResult = FALSE;
485 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
486 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
488 if (lprcView != NULL)
491 infoPtr->rcView.left = lprcView->left;
492 infoPtr->rcView.top = lprcView->top;
493 infoPtr->rcView.right = lprcView->right;
494 infoPtr->rcView.bottom = lprcView->bottom;
502 * Retrieves the bounding rectangle of all the items.
505 * [I] HWND : window handle
506 * [O] LPRECT : bounding rectangle
512 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
514 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
515 BOOL bResult = FALSE;
518 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
520 if (lprcView != NULL)
522 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
523 if (bResult != FALSE)
525 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
526 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
527 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
528 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
531 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
532 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
540 * Retrieves the subitem pointer associated with the subitem index.
543 * [I] HDPA : DPA handle for a specific item
544 * [I] INT : index of subitem
547 * SUCCESS : subitem pointer
550 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
553 LISTVIEW_SUBITEM *lpSubItem;
556 for (i = 1; i < hdpaSubItems->nItemCount; i++)
558 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
559 if (lpSubItem != NULL)
561 if (lpSubItem->iSubItem == nSubItem)
573 * Calculates the width of an item.
576 * [I] HWND : window handle
577 * [I] LONG : window style
580 * Returns item width.
582 static INT LISTVIEW_GetItemWidth(HWND hwnd)
584 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
585 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
586 INT nHeaderItemCount;
592 TRACE("(hwnd=%x)\n", hwnd);
594 if (uView == LVS_ICON)
596 nItemWidth = infoPtr->iconSpacing.cx;
598 else if (uView == LVS_REPORT)
600 /* calculate width of header */
601 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
602 for (i = 0; i < nHeaderItemCount; i++)
604 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
606 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
612 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
614 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
615 nItemWidth = max(nItemWidth, nLabelWidth);
618 /* default label size */
619 if (GETITEMCOUNT(infoPtr) == 0)
621 nItemWidth = DEFAULT_COLUMN_WIDTH;
627 nItemWidth = DEFAULT_LABEL_WIDTH;
632 nItemWidth += WIDTH_PADDING;
634 if (infoPtr->himlSmall != NULL)
636 nItemWidth += infoPtr->iconSize.cx;
639 if (infoPtr->himlState != NULL)
641 nItemWidth += infoPtr->iconSize.cx;
652 * Calculates the height of an item.
655 * [I] HWND : window handle
656 * [I] LONG : window style
659 * Returns item height.
661 static INT LISTVIEW_GetItemHeight(HWND hwnd)
663 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
664 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
667 if (uView == LVS_ICON)
669 nItemHeight = infoPtr->iconSpacing.cy;
674 HDC hdc = GetDC(hwnd);
675 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
676 GetTextMetricsA(hdc, &tm);
677 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
678 SelectObject(hdc, hOldFont);
679 ReleaseDC(hwnd, hdc);
687 * Adds a block of selections.
690 * [I] HWND : window handle
691 * [I] INT : item index
696 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
698 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
699 INT nFirst = min(infoPtr->nSelectionMark, nItem);
700 INT nLast = max(infoPtr->nSelectionMark, nItem);
704 lvItem.state = LVIS_SELECTED;
705 lvItem.stateMask= LVIS_SELECTED;
707 for (i = nFirst; i <= nLast; i++)
709 ListView_SetItemState(hwnd, i, &lvItem);
712 LISTVIEW_SetItemFocus(hwnd, nItem);
713 infoPtr->nSelectionMark = nItem;
718 * Adds a single selection.
721 * [I] HWND : window handle
722 * [I] INT : item index
727 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
729 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
732 lvItem.state = LVIS_SELECTED;
733 lvItem.stateMask= LVIS_SELECTED;
735 ListView_SetItemState(hwnd, nItem, &lvItem);
737 LISTVIEW_SetItemFocus(hwnd, nItem);
738 infoPtr->nSelectionMark = nItem;
743 * Selects or unselects an item.
746 * [I] HWND : window handle
747 * [I] INT : item index
753 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
755 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
759 lvItem.stateMask= LVIS_SELECTED;
761 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
764 ListView_SetItemState(hwnd, nItem, &lvItem);
769 lvItem.state = LVIS_SELECTED;
770 ListView_SetItemState(hwnd, nItem, &lvItem);
774 LISTVIEW_SetItemFocus(hwnd, nItem);
775 infoPtr->nSelectionMark = nItem;
782 * Selects items based on view coorddiantes.
785 * [I] HWND : window handle
786 * [I] RECT : selection rectangle
791 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
793 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
798 lvItem.stateMask = LVIS_SELECTED;
800 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
802 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
803 if (PtInRect(&rcSelRect, ptItem) != FALSE)
805 lvItem.state = LVIS_SELECTED;
812 ListView_SetItemState(hwnd, i, &lvItem);
818 * Sets a single group selection.
821 * [I] HWND : window handle
822 * [I] INT : item index
827 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
829 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
830 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
833 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
836 INT nFirst = min(infoPtr->nSelectionMark, nItem);
837 INT nLast = max(infoPtr->nSelectionMark, nItem);
838 lvItem.stateMask = LVIS_SELECTED;
840 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
842 if ((i < nFirst) || (i > nLast))
848 lvItem.state = LVIS_SELECTED;
851 ListView_SetItemState(hwnd, i, &lvItem);
859 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
860 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
861 rcSel.left = min(ptSelMark.x, ptItem.x);
862 rcSel.top = min(ptSelMark.y, ptItem.y);
863 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
864 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
865 LISTVIEW_SetSelectionRect(hwnd, rcSel);
868 LISTVIEW_SetItemFocus(hwnd, nItem);
873 * Manages the item focus.
876 * [I] HWND : window handle
877 * [I] INT : item index
880 * TRUE : focused item changed
881 * FALSE : focused item has NOT changed
883 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
885 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
886 BOOL bResult = FALSE;
889 if (infoPtr->nFocusedItem != nItem)
892 ZeroMemory(&lvItem, sizeof(LVITEMA));
893 lvItem.stateMask = LVIS_FOCUSED;
894 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
896 lvItem.state = LVIS_FOCUSED;
897 lvItem.stateMask = LVIS_FOCUSED;
898 ListView_SetItemState(hwnd, nItem, &lvItem);
900 infoPtr->nFocusedItem = nItem;
901 ListView_EnsureVisible(hwnd, nItem, FALSE);
909 * Sets a single selection.
912 * [I] HWND : window handle
913 * [I] INT : item index
918 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
920 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
925 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
928 if (nItem < GETITEMCOUNT(infoPtr))
930 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
933 ZeroMemory(&lvItem, sizeof(LVITEMA));
934 lvItem.stateMask = LVIS_FOCUSED;
935 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
937 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
938 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
939 ListView_SetItemState(hwnd, nItem, &lvItem);
941 infoPtr->nFocusedItem = nItem;
942 infoPtr->nSelectionMark = nItem;
947 * Set selection(s) with keyboard.
950 * [I] HWND : window handle
951 * [I] INT : item index
954 * SUCCESS : TRUE (needs to be repainted)
955 * FAILURE : FALSE (nothing has changed)
957 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
959 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
960 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
961 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
962 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
963 BOOL bResult = FALSE;
965 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
967 if (lStyle & LVS_SINGLESEL)
970 LISTVIEW_SetSelection(hwnd, nItem);
971 ListView_EnsureVisible(hwnd, nItem, FALSE);
978 LISTVIEW_SetGroupSelection(hwnd, nItem);
982 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
987 LISTVIEW_SetSelection(hwnd, nItem);
988 ListView_EnsureVisible(hwnd, nItem, FALSE);
998 * Selects an item based on coordinates.
1001 * [I] HWND : window handle
1002 * [I] POINT : mouse click ccordinates
1005 * SUCCESS : item index
1008 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1010 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1014 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1016 rcItem.left = LVIR_SELECTBOUNDS;
1017 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1019 if (PtInRect(&rcItem, pt) != FALSE)
1031 * Removes all selection states.
1034 * [I] HWND : window handle
1035 * [I] INT : item index
1041 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1047 lvItem.stateMask = LVIS_SELECTED;
1049 for (i = nFirst; i <= nLast; i++)
1051 ListView_SetItemState(hwnd, i, &lvItem);
1060 * [IO] HDPA : dynamic pointer array handle
1061 * [I] INT : column index (subitem index)
1067 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1069 BOOL bResult = TRUE;
1073 for (i = 0; i < hdpaItems->nItemCount; i++)
1075 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1076 if (hdpaSubItems != NULL)
1078 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1090 * Removes a subitem at a given position.
1093 * [IO] HDPA : dynamic pointer array handle
1094 * [I] INT : subitem index
1100 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1102 LISTVIEW_SUBITEM *lpSubItem;
1105 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1107 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1108 if (lpSubItem != NULL)
1110 if (lpSubItem->iSubItem == nSubItem)
1113 if ((lpSubItem->pszText != NULL) &&
1114 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1116 COMCTL32_Free(lpSubItem->pszText);
1120 COMCTL32_Free(lpSubItem);
1122 /* free dpa memory */
1123 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1128 else if (lpSubItem->iSubItem > nSubItem)
1140 * Compares the item information.
1143 * [I] LISTVIEW_ITEM *: destination item
1144 * [I] LPLVITEM : source item
1147 * SUCCCESS : TRUE (EQUAL)
1148 * FAILURE : FALSE (NOT EQUAL)
1150 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1154 if ((lpItem != NULL) && (lpLVItem != NULL))
1156 if (lpLVItem->mask & LVIF_STATE)
1158 if ((lpItem->state & lpLVItem->stateMask) !=
1159 (lpLVItem->state & lpLVItem->stateMask))
1161 uChanged |= LVIF_STATE;
1165 if (lpLVItem->mask & LVIF_IMAGE)
1167 if (lpItem->iImage != lpLVItem->iImage)
1169 uChanged |= LVIF_IMAGE;
1173 if (lpLVItem->mask & LVIF_PARAM)
1175 if (lpItem->lParam != lpLVItem->lParam)
1177 uChanged |= LVIF_PARAM;
1181 if (lpLVItem->mask & LVIF_INDENT)
1183 if (lpItem->iIndent != lpLVItem->iIndent)
1185 uChanged |= LVIF_INDENT;
1189 if (lpLVItem->mask & LVIF_TEXT)
1191 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1193 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1195 uChanged |= LVIF_TEXT;
1200 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1202 uChanged |= LVIF_TEXT;
1206 if (lpLVItem->pszText)
1208 if (lpItem->pszText)
1210 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1212 uChanged |= LVIF_TEXT;
1217 uChanged |= LVIF_TEXT;
1222 if (lpItem->pszText)
1224 uChanged |= LVIF_TEXT;
1236 * Initializes item attributes.
1239 * [I] HWND : window handle
1240 * [O] LISTVIEW_ITEM *: destination item
1241 * [I] LPLVITEM : source item
1247 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1250 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1251 BOOL bResult = FALSE;
1253 if ((lpItem != NULL) && (lpLVItem != NULL))
1257 if (lpLVItem->mask & LVIF_STATE)
1259 lpItem->state &= ~lpLVItem->stateMask;
1260 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1263 if (lpLVItem->mask & LVIF_IMAGE)
1265 lpItem->iImage = lpLVItem->iImage;
1268 if (lpLVItem->mask & LVIF_PARAM)
1270 lpItem->lParam = lpLVItem->lParam;
1273 if (lpLVItem->mask & LVIF_INDENT)
1275 lpItem->iIndent = lpLVItem->iIndent;
1278 if (lpLVItem->mask & LVIF_TEXT)
1280 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1282 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1287 if ((lpItem->pszText != NULL) &&
1288 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1290 COMCTL32_Free(lpItem->pszText);
1293 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1297 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1299 lpItem->pszText = NULL;
1302 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1312 * Initializes subitem attributes.
1314 * NOTE: The documentation specifies that the operation fails if the user
1315 * tries to set the indent of a subitem.
1318 * [I] HWND : window handle
1319 * [O] LISTVIEW_SUBITEM *: destination subitem
1320 * [I] LPLVITEM : source subitem
1326 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1329 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1330 BOOL bResult = FALSE;
1332 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1334 if (!(lpLVItem->mask & LVIF_INDENT))
1337 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1339 lpSubItem->iSubItem = lpLVItem->iSubItem;
1341 if (lpLVItem->mask & LVIF_IMAGE)
1343 lpSubItem->iImage = lpLVItem->iImage;
1346 if (lpLVItem->mask & LVIF_TEXT)
1348 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1350 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1355 if ((lpSubItem->pszText != NULL) &&
1356 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1358 COMCTL32_Free(lpSubItem->pszText);
1361 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1365 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1367 lpSubItem->pszText = NULL;
1370 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1381 * Adds a subitem at a given position (column index).
1384 * [I] HWND : window handle
1385 * [I] LPLVITEM : new subitem atttributes
1391 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1393 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1394 LISTVIEW_SUBITEM *lpSubItem = NULL;
1395 BOOL bResult = FALSE;
1397 INT nPosition, nItem;
1399 if (lpLVItem != NULL)
1401 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1402 if (hdpaSubItems != NULL)
1404 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1405 if (lpSubItem != NULL)
1407 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1409 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1410 lpSubItem->iSubItem);
1411 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1421 /* cleanup if unsuccessful */
1422 if ((bResult == FALSE) && (lpSubItem != NULL))
1424 COMCTL32_Free(lpSubItem);
1432 * Finds the dpa insert position (array index).
1435 * [I] HWND : window handle
1436 * [I] INT : subitem index
1442 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1444 LISTVIEW_SUBITEM *lpSubItem;
1447 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1449 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1450 if (lpSubItem != NULL)
1452 if (lpSubItem->iSubItem > nSubItem)
1459 return hdpaSubItems->nItemCount;
1464 * Retrieves a listview subitem at a given position (column index).
1467 * [I] HWND : window handle
1468 * [I] INT : subitem index
1474 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1476 LISTVIEW_SUBITEM *lpSubItem;
1479 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1481 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1482 if (lpSubItem != NULL)
1484 if (lpSubItem->iSubItem == nSubItem)
1488 else if (lpSubItem->iSubItem > nSubItem)
1500 * Sets item attributes.
1503 * [I] HWND : window handle
1504 * [I] LPLVITEM : new item atttributes
1510 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1512 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1513 BOOL bResult = FALSE;
1515 LISTVIEW_ITEM *lpItem;
1518 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1520 if (lpLVItem != NULL)
1522 if (lpLVItem->iSubItem == 0)
1524 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1525 if (hdpaSubItems != NULL)
1527 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1530 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1531 nmlv.hdr.hwndFrom = hwnd;
1532 nmlv.hdr.idFrom = lCtrlId;
1533 nmlv.hdr.code = LVN_ITEMCHANGING;
1534 nmlv.lParam = lpItem->lParam;
1535 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1538 if (uChanged & LVIF_STATE)
1540 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1541 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1544 nmlv.uChanged = uChanged;
1545 nmlv.iItem = lpLVItem->iItem;
1546 nmlv.lParam = lpItem->lParam;
1547 /* send LVN_ITEMCHANGING notification */
1548 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1550 /* copy information */
1551 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1553 /* send LVN_ITEMCHANGED notification */
1554 nmlv.hdr.code = LVN_ITEMCHANGED;
1555 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1562 InvalidateRect(hwnd, NULL, FALSE);
1573 * Sets subitem attributes.
1576 * [I] HWND : window handle
1577 * [I] LPLVITEM : new subitem atttributes
1583 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1585 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1586 BOOL bResult = FALSE;
1588 LISTVIEW_SUBITEM *lpSubItem;
1590 if (lpLVItem != NULL)
1592 if (lpLVItem->iSubItem > 0)
1594 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1595 if (hdpaSubItems != NULL)
1597 /* set subitem only if column is present */
1598 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1600 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1601 if (lpSubItem != NULL)
1603 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1607 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1610 InvalidateRect(hwnd, NULL, FALSE);
1621 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1624 * [I] HWND : window handle
1629 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1631 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1632 UINT uView = lStyle & LVS_TYPEMASK;
1634 SCROLLINFO scrollInfo;
1636 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1637 scrollInfo.cbSize = sizeof(SCROLLINFO);
1638 scrollInfo.fMask = SIF_POS;
1640 if (uView == LVS_LIST)
1642 if (lStyle & WS_HSCROLL)
1644 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1646 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1650 else if (uView == LVS_REPORT)
1652 if (lStyle & WS_VSCROLL)
1654 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1656 nItem = scrollInfo.nPos;
1669 * [I] HWND : window handle
1670 * [I] HDC : device context handle
1671 * [I] INT : item index
1672 * [I] INT : subitem index
1673 * [I] RECT * : clipping rectangle
1678 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1681 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1682 CHAR szDispText[DISP_TEXT_SIZE];
1685 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd, hdc,
1688 /* get information needed for drawing the item */
1689 ZeroMemory(&lvItem, sizeof(LVITEMA));
1690 lvItem.mask = LVIF_TEXT;
1691 lvItem.iItem = nItem;
1692 lvItem.iSubItem = nSubItem;
1693 lvItem.cchTextMax = DISP_TEXT_SIZE;
1694 lvItem.pszText = szDispText;
1695 ListView_GetItemA(hwnd, &lvItem);
1697 /* set item colors */
1698 SetBkColor(hdc, infoPtr->clrTextBk);
1699 SetTextColor(hdc, infoPtr->clrText);
1701 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1702 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1711 * [I] HWND : window handle
1712 * [I] HDC : device context handle
1713 * [I] INT : item index
1714 * [I] RECT * : clipping rectangle
1719 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1721 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1722 CHAR szDispText[DISP_TEXT_SIZE];
1729 TRACE("(hwnd=%x, hdc=%x, nItem=%d\n", hwnd, hdc, nItem);
1731 /* get information needed for drawing the item */
1732 ZeroMemory(&lvItem, sizeof(LVITEMA));
1733 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1734 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1735 lvItem.iItem = nItem;
1736 lvItem.iSubItem = 0;
1737 lvItem.cchTextMax = DISP_TEXT_SIZE;
1738 lvItem.pszText = szDispText;
1739 ListView_GetItemA(hwnd, &lvItem);
1742 if (infoPtr->himlState != NULL)
1744 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1745 if (uStateImage != 0)
1747 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1748 rcItem.top, ILD_NORMAL);
1751 rcItem.left += infoPtr->iconSize.cx;
1755 if (infoPtr->himlSmall != NULL)
1757 if (lvItem.state & LVIS_SELECTED)
1759 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1760 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1761 rcItem.top, ILD_SELECTED);
1765 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1766 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1767 rcItem.top, ILD_NORMAL);
1770 rcItem.left += infoPtr->iconSize.cx;
1773 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1775 /* set item colors */
1776 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1777 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1778 /* set raster mode */
1779 nMixMode = SetROP2(hdc, R2_XORPEN);
1781 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1782 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1784 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1785 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1786 /* set raster mode */
1787 nMixMode = SetROP2(hdc, R2_COPYPEN);
1791 /* set item colors */
1792 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1793 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1794 /* set raster mode */
1795 nMixMode = SetROP2(hdc, R2_COPYPEN);
1798 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1799 if (rcItem.left + nLabelWidth < rcItem.right)
1801 rcItem.right = rcItem.left + nLabelWidth;
1805 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1806 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1808 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1810 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1815 SetROP2(hdc, R2_COPYPEN);
1816 SetBkColor(hdc, infoPtr->clrTextBk);
1817 SetTextColor(hdc, infoPtr->clrText);
1823 * Draws an item when in large icon display mode.
1826 * [I] HWND : window handle
1827 * [I] HDC : device context handle
1828 * [I] LISTVIEW_ITEM * : item
1829 * [I] INT : item index
1830 * [I] RECT * : clipping rectangle
1835 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1837 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1838 CHAR szDispText[DISP_TEXT_SIZE];
1839 INT nDrawPosX = rcItem.left;
1844 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1845 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1848 /* get information needed for drawing the item */
1849 ZeroMemory(&lvItem, sizeof(LVITEMA));
1850 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1851 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1852 lvItem.iItem = nItem;
1853 lvItem.iSubItem = 0;
1854 lvItem.cchTextMax = DISP_TEXT_SIZE;
1855 lvItem.pszText = szDispText;
1856 ListView_GetItemA(hwnd, &lvItem);
1858 if (lvItem.state & LVIS_SELECTED)
1860 /* set item colors */
1861 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1862 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1863 /* set raster mode */
1864 SetROP2(hdc, R2_XORPEN);
1868 /* set item colors */
1869 SetBkColor(hdc, infoPtr->clrTextBk);
1870 SetTextColor(hdc, infoPtr->clrText);
1871 /* set raster mode */
1872 SetROP2(hdc, R2_COPYPEN);
1875 if (infoPtr->himlNormal != NULL)
1877 rcItem.top += ICON_TOP_PADDING;
1878 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
1879 if (lvItem.state & LVIS_SELECTED)
1881 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1882 rcItem.top, ILD_SELECTED);
1886 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1887 rcItem.top, ILD_NORMAL);
1891 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
1892 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1893 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
1896 rcItem.left += nDrawPosX / 2;
1897 rcItem.right = rcItem.left + nLabelWidth;
1902 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
1906 GetTextMetricsA(hdc, &tm);
1907 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
1908 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1909 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1911 if (lvItem.state & LVIS_FOCUSED)
1913 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1919 * Draws listview items when in report display mode.
1922 * [I] HWND : window handle
1923 * [I] HDC : device context handle
1928 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
1930 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
1931 INT nDrawPosY = infoPtr->rcList.top;
1938 nItem = ListView_GetTopIndex(hwnd);
1940 /* add 1 for displaying a partial item at the bottom */
1941 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
1942 nLast = min(nLast, GETITEMCOUNT(infoPtr));
1943 for (; nItem < nLast; nItem++)
1945 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
1946 for (j = 0; j < nColumnCount; j++)
1948 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
1949 rcItem.left += REPORT_MARGINX;
1950 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
1951 rcItem.top = nDrawPosY;
1952 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
1955 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
1959 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
1963 nDrawPosY += infoPtr->nItemHeight;
1969 * Retrieves the number of items that can fit vertically in the client area.
1972 * [I] HWND : window handle
1975 * Number of items per row.
1977 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
1979 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
1980 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1981 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
1982 INT nCountPerRow = 1;
1986 if (uView == LVS_REPORT)
1992 nCountPerRow = nListWidth / infoPtr->nItemWidth;
1993 if (nCountPerRow == 0)
2000 return nCountPerRow;
2005 * Retrieves the number of items that can fit horizontally in the client
2009 * [I] HWND : window handle
2012 * Number of items per column.
2014 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2016 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2017 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2018 INT nCountPerColumn = 1;
2020 if (nListHeight > 0)
2022 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2023 if (nCountPerColumn == 0)
2025 nCountPerColumn = 1;
2029 return nCountPerColumn;
2034 * Retrieves the number of columns needed to display all the items when in
2035 * list display mode.
2038 * [I] HWND : window handle
2041 * Number of columns.
2043 static INT LISTVIEW_GetColumnCount(hwnd)
2045 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2046 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2047 INT nColumnCount = 0;
2049 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2051 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2053 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2057 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2061 return nColumnCount;
2067 * Draws listview items when in list display mode.
2070 * [I] HWND : window handle
2071 * [I] HDC : device context handle
2076 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2078 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2083 INT nCountPerColumn;
2085 /* get number of fully visible columns */
2086 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2087 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2088 nItem = ListView_GetTopIndex(hwnd);
2090 for (i = 0; i < nColumnCount; i++)
2092 for (j = 0; j < nCountPerColumn; j++, nItem++)
2094 if (nItem >= GETITEMCOUNT(infoPtr))
2097 rcItem.top = j * infoPtr->nItemHeight;
2098 rcItem.left = i * infoPtr->nItemWidth;
2099 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2100 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2101 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2108 * Draws listview items when in icon or small icon display mode.
2111 * [I] HWND : window handle
2112 * [I] HDC : device context handle
2117 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2119 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2125 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2126 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2128 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2129 ptPosition.x += ptOrigin.x;
2130 ptPosition.y += ptOrigin.y;
2132 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2134 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2136 if (ptPosition.y < infoPtr->rcList.bottom)
2138 if (ptPosition.x < infoPtr->rcList.right)
2140 rcItem.top = ptPosition.y;
2141 rcItem.left = ptPosition.x;
2142 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2143 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2144 if (bSmall == FALSE)
2146 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2150 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2161 * Draws listview items.
2164 * [I] HWND : window handle
2165 * [I] HDC : device context handle
2170 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2172 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2173 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2178 hOldFont = SelectObject(hdc, infoPtr->hFont);
2180 /* select the doted pen (for drawing the focus box) */
2181 hPen = CreatePen(PS_DOT, 1, 0);
2182 hOldPen = SelectObject(hdc, hPen);
2184 /* select transparent brush (for drawing the focus box) */
2185 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2187 if (uView == LVS_LIST)
2189 LISTVIEW_RefreshList(hwnd, hdc);
2191 else if (uView == LVS_REPORT)
2193 LISTVIEW_RefreshReport(hwnd, hdc);
2195 else if (uView == LVS_SMALLICON)
2197 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2199 else if (uView == LVS_ICON)
2201 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2204 /* unselect objects */
2205 SelectObject(hdc, hOldFont);
2206 SelectObject(hdc, hOldPen);
2215 * Calculates the approximate width and height of a given number of items.
2218 * [I] HWND : window handle
2219 * [I] INT : number of items
2224 * Returns a DWORD. The width in the low word and the height in high word.
2226 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2227 WORD wWidth, WORD wHeight)
2229 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2230 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2231 INT nItemCountPerColumn = 1;
2232 INT nColumnCount = 0;
2233 DWORD dwViewRect = 0;
2235 if (nItemCount == -1)
2237 nItemCount = GETITEMCOUNT(infoPtr);
2240 if (uView == LVS_LIST)
2242 if (wHeight == 0xFFFF)
2244 /* use current height */
2245 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2248 if (wHeight < infoPtr->nItemHeight)
2250 wHeight = infoPtr->nItemHeight;
2255 if (infoPtr->nItemHeight > 0)
2257 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2258 if (nItemCountPerColumn == 0)
2260 nItemCountPerColumn = 1;
2263 if (nItemCount % nItemCountPerColumn != 0)
2265 nColumnCount = nItemCount / nItemCountPerColumn;
2269 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2274 /* Microsoft padding magic */
2275 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2276 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2278 dwViewRect = MAKELONG(wWidth, wHeight);
2280 else if (uView == LVS_REPORT)
2284 else if (uView == LVS_SMALLICON)
2288 else if (uView == LVS_ICON)
2298 * Arranges listview items in icon display mode.
2301 * [I] HWND : window handle
2302 * [I] INT : alignment code
2308 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2310 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2311 BOOL bResult = FALSE;
2313 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2326 case LVA_SNAPTOGRID:
2335 /* << LISTVIEW_CreateDragImage >> */
2339 * Removes all listview items and subitems.
2342 * [I] HWND : window handle
2348 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2350 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2351 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2352 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2353 UINT uView = lStyle & LVS_TYPEMASK;
2354 LISTVIEW_ITEM *lpItem;
2355 LISTVIEW_SUBITEM *lpSubItem;
2358 BOOL bResult = FALSE;
2363 TRACE("(hwnd=%x,)\n", hwnd);
2365 if (GETITEMCOUNT(infoPtr) > 0)
2367 /* initialize memory */
2368 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2370 /* send LVN_DELETEALLITEMS notification */
2371 nmlv.hdr.hwndFrom = hwnd;
2372 nmlv.hdr.idFrom = lCtrlId;
2373 nmlv.hdr.code = LVN_DELETEALLITEMS;
2376 /* verify if subsequent LVN_DELETEITEM notifications should be
2378 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2380 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2382 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2383 if (hdpaSubItems != NULL)
2385 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2387 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2388 if (lpSubItem != NULL)
2390 /* free subitem string */
2391 if ((lpSubItem->pszText != NULL) &&
2392 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2394 COMCTL32_Free(lpSubItem->pszText);
2398 COMCTL32_Free(lpSubItem);
2402 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2405 if (bSuppress == FALSE)
2407 /* send LVN_DELETEITEM notification */
2408 nmlv.hdr.code = LVN_DELETEITEM;
2410 nmlv.lParam = lpItem->lParam;
2411 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2414 /* free item string */
2415 if ((lpItem->pszText != NULL) &&
2416 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2418 COMCTL32_Free(lpItem->pszText);
2422 COMCTL32_Free(lpItem);
2425 DPA_Destroy(hdpaSubItems);
2429 /* reinitialize listview memory */
2430 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2432 /* align items (set position of each item) */
2433 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2435 if (lStyle & LVS_ALIGNLEFT)
2437 LISTVIEW_AlignLeft(hwnd);
2441 LISTVIEW_AlignTop(hwnd);
2445 LISTVIEW_UpdateScroll(hwnd);
2447 /* invalidate client area (optimization needed) */
2448 InvalidateRect(hwnd, NULL, TRUE);
2456 * Removes a column from the listview control.
2459 * [I] HWND : window handle
2460 * [I] INT : column index
2466 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2468 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2469 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2470 BOOL bResult = FALSE;
2472 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2474 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2476 /* reset scroll parameters */
2477 if (uView == LVS_REPORT)
2479 /* update scrollbar(s) */
2480 LISTVIEW_UpdateScroll(hwnd);
2482 /* refresh client area */
2483 InvalidateRect(hwnd, NULL, FALSE);
2492 * Removes an item from the listview control.
2495 * [I] HWND : window handle
2496 * [I] INT : item index
2502 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2504 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2505 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2506 UINT uView = lStyle & LVS_TYPEMASK;
2507 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2509 BOOL bResult = FALSE;
2511 LISTVIEW_ITEM *lpItem;
2512 LISTVIEW_SUBITEM *lpSubItem;
2515 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2517 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2519 /* initialize memory */
2520 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2522 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2523 if (hdpaSubItems != NULL)
2525 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2527 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2528 if (lpSubItem != NULL)
2530 /* free item string */
2531 if ((lpSubItem->pszText != NULL) &&
2532 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2534 COMCTL32_Free(lpSubItem->pszText);
2538 COMCTL32_Free(lpSubItem);
2542 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2545 /* send LVN_DELETEITEM notification */
2546 nmlv.hdr.hwndFrom = hwnd;
2547 nmlv.hdr.idFrom = lCtrlId;
2548 nmlv.hdr.code = LVN_DELETEITEM;
2550 nmlv.lParam = lpItem->lParam;
2551 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2554 /* free item string */
2555 if ((lpItem->pszText != NULL) &&
2556 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2558 COMCTL32_Free(lpItem->pszText);
2562 COMCTL32_Free(lpItem);
2565 bResult = DPA_Destroy(hdpaSubItems);
2568 /* align items (set position of each item) */
2569 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2571 if (lStyle & LVS_ALIGNLEFT)
2573 LISTVIEW_AlignLeft(hwnd);
2577 LISTVIEW_AlignTop(hwnd);
2581 LISTVIEW_UpdateScroll(hwnd);
2583 /* refresh client area */
2584 InvalidateRect(hwnd, NULL, TRUE);
2590 /* LISTVIEW_EditLabel */
2594 * Ensures the specified item is visible, scrolling into view if necessary.
2597 * [I] HWND : window handle
2598 * [I] INT : item index
2599 * [I] BOOL : partially or entirely visible
2605 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2607 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2608 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2609 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2610 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2611 INT nScrollPosHeight = 0;
2612 INT nScrollPosWidth = 0;
2613 SCROLLINFO scrollInfo;
2616 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2617 scrollInfo.cbSize = sizeof(SCROLLINFO);
2618 scrollInfo.fMask = SIF_POS;
2620 /* ALWAYS bPartial == FALSE, FOR NOW! */
2622 rcItem.left = LVIR_BOUNDS;
2623 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2625 if (rcItem.left < infoPtr->rcList.left)
2627 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2630 if (uView == LVS_LIST)
2632 nScrollPosWidth = infoPtr->nItemWidth;
2633 rcItem.left += infoPtr->rcList.left;
2635 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2637 nScrollPosWidth = max(1, nListWidth / 10);
2638 rcItem.left += infoPtr->rcList.left;
2641 if (rcItem.left % nScrollPosWidth == 0)
2643 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
2647 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
2650 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2653 else if (rcItem.right > infoPtr->rcList.right)
2655 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2658 if (uView == LVS_LIST)
2660 rcItem.right -= infoPtr->rcList.right;
2661 nScrollPosWidth = infoPtr->nItemWidth;
2663 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2665 rcItem.right -= infoPtr->rcList.right;
2666 nScrollPosWidth = max(1, nListWidth / 10);
2669 if (rcItem.right % nScrollPosWidth == 0)
2671 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
2675 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
2678 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2682 if (rcItem.top < infoPtr->rcList.top)
2685 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2687 if (uView == LVS_REPORT)
2689 rcItem.top -= infoPtr->rcList.top;
2690 nScrollPosHeight = infoPtr->nItemHeight;
2692 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2694 nScrollPosHeight = max(1, nListHeight / 10);
2695 rcItem.top += infoPtr->rcList.top;
2698 if (rcItem.top % nScrollPosHeight == 0)
2700 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
2704 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
2707 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2710 else if (rcItem.bottom > infoPtr->rcList.bottom)
2713 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2715 if (uView == LVS_REPORT)
2717 rcItem.bottom -= infoPtr->rcList.bottom;
2718 nScrollPosHeight = infoPtr->nItemHeight;
2720 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2722 nScrollPosHeight = max(1, nListHeight / 10);
2723 rcItem.bottom -= infoPtr->rcList.bottom;
2726 if (rcItem.bottom % nScrollPosHeight == 0)
2728 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
2732 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
2735 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2745 * Retrieves the nearest item, given a position and a direction.
2748 * [I] HWND : window handle
2749 * [I] POINT : start position
2750 * [I] UINT : direction
2753 * Item index if successdful, -1 otherwise.
2755 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
2757 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2758 LVHITTESTINFO lvHitTestInfo;
2762 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
2764 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
2765 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
2766 lvHitTestInfo.pt.x += pt.x;
2767 lvHitTestInfo.pt.y += pt.y;
2771 if (vkDirection == VK_DOWN)
2773 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
2775 else if (vkDirection == VK_UP)
2777 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
2779 else if (vkDirection == VK_LEFT)
2781 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
2783 else if (vkDirection == VK_RIGHT)
2785 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
2788 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
2794 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
2798 while (nItem == -1);
2806 * Searches for an item with specific characteristics.
2809 * [I] HWND : window handle
2810 * [I] INT : base item index
2811 * [I] LPLVFINDINFO : item information to look for
2814 * SUCCESS : index of item
2817 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
2818 LPLVFINDINFO lpFindInfo)
2820 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2822 CHAR szDispText[DISP_TEXT_SIZE];
2826 INT nLast = GETITEMCOUNT(infoPtr);
2828 if ((nItem >= -1) && (lpFindInfo != NULL))
2830 ZeroMemory(&lvItem, sizeof(LVITEMA));
2832 if (lpFindInfo->flags & LVFI_PARAM)
2834 lvItem.mask |= LVIF_PARAM;
2837 if (lpFindInfo->flags & LVFI_STRING)
2839 lvItem.mask |= LVIF_TEXT;
2840 lvItem.pszText = szDispText;
2841 lvItem.cchTextMax = DISP_TEXT_SIZE;
2844 if (lpFindInfo->flags & LVFI_PARTIAL)
2846 lvItem.mask |= LVIF_TEXT;
2847 lvItem.pszText = szDispText;
2848 lvItem.cchTextMax = DISP_TEXT_SIZE;
2851 if (lpFindInfo->flags & LVFI_WRAP)
2856 if (lpFindInfo->flags & LVFI_NEARESTXY)
2858 ptItem.x = lpFindInfo->pt.x;
2859 ptItem.y = lpFindInfo->pt.y;
2864 while (nItem < nLast)
2866 if (lpFindInfo->flags & LVFI_NEARESTXY)
2868 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
2869 lpFindInfo->vkDirection);
2872 /* get position of the new item index */
2873 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
2884 lvItem.iItem = nItem;
2885 lvItem.iSubItem = 0;
2886 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
2888 if (lvItem.mask & LVIF_TEXT)
2890 if (lpFindInfo->flags & LVFI_PARTIAL)
2892 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
2897 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
2902 if (lvItem.mask & LVIF_PARAM)
2904 if (lpFindInfo->lParam != lvItem.lParam)
2930 * Retrieves the background color of the listview control.
2933 * [I] HWND : window handle
2936 * COLORREF associated with the background.
2938 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
2940 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2942 return infoPtr->clrBk;
2947 * Retrieves the background image of the listview control.
2950 * [I] HWND : window handle
2951 * [O] LPLVMKBIMAGE : background image attributes
2957 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
2959 /* FIXME (listview, "empty stub!\n"); */
2965 * Retrieves the callback mask.
2968 * [I] HWND : window handle
2973 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
2975 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2977 return infoPtr->uCallbackMask;
2982 * Retrieves column attributes.
2985 * [I] HWND : window handle
2986 * [I] INT : column index
2987 * [IO] LPLVCOLUMNA : column information
2993 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
2995 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2997 BOOL bResult = FALSE;
2999 if (lpColumn != NULL)
3001 /* initialize memory */
3002 ZeroMemory(&hdi, sizeof(HDITEMA));
3004 if (lpColumn->mask & LVCF_FMT)
3006 hdi.mask |= HDI_FORMAT;
3009 if (lpColumn->mask & LVCF_WIDTH)
3011 hdi.mask |= HDI_WIDTH;
3014 if (lpColumn->mask & LVCF_TEXT)
3016 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3019 if (lpColumn->mask & LVCF_IMAGE)
3021 hdi.mask |= HDI_IMAGE;
3024 if (lpColumn->mask & LVCF_ORDER)
3026 hdi.mask |= HDI_ORDER;
3029 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3030 if (bResult != FALSE)
3032 if (lpColumn->mask & LVCF_FMT)
3036 if (hdi.fmt & HDF_LEFT)
3038 lpColumn->fmt |= LVCFMT_LEFT;
3040 else if (hdi.fmt & HDF_RIGHT)
3042 lpColumn->fmt |= LVCFMT_RIGHT;
3044 else if (hdi.fmt & HDF_CENTER)
3046 lpColumn->fmt |= LVCFMT_CENTER;
3049 if (hdi.fmt & HDF_IMAGE)
3051 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3054 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3056 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3060 if (lpColumn->mask & LVCF_WIDTH)
3062 lpColumn->cx = hdi.cxy;
3065 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3067 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3070 if (lpColumn->mask & LVCF_IMAGE)
3072 lpColumn->iImage = hdi.iImage;
3075 if (lpColumn->mask & LVCF_ORDER)
3077 lpColumn->iOrder = hdi.iOrder;
3085 /* LISTVIEW_GetColumnW */
3086 /* LISTVIEW_GetColumnOrderArray */
3090 * Retrieves the column width.
3093 * [I] HWND : window handle
3094 * [I] int : column index
3097 * SUCCESS : column width
3100 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3102 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3103 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3104 INT nColumnWidth = 0;
3107 if (uView == LVS_LIST)
3109 nColumnWidth = infoPtr->nItemWidth;
3111 else if (uView == LVS_REPORT)
3113 /* get column width from header */
3114 ZeroMemory(&hdi, sizeof(HDITEMA));
3115 hdi.mask = HDI_WIDTH;
3116 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3118 nColumnWidth = hdi.cxy;
3122 return nColumnWidth;
3127 * In list or report display mode, retrieves the number of items that can fit
3128 * vertically in the visible area. In icon or small icon display mode,
3129 * retrieves the total number of visible items.
3132 * [I] HWND : window handle
3135 * Number of fully visible items.
3137 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3139 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3140 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3143 if (uView == LVS_LIST)
3145 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3147 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3148 LISTVIEW_GetCountPerColumn(hwnd);
3151 else if (uView == LVS_REPORT)
3153 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3157 nItemCount = GETITEMCOUNT(infoPtr);
3163 /* LISTVIEW_GetEditControl */
3164 /* LISTVIEW_GetExtendedListViewStyle */
3168 * Retrieves the handle to the header control.
3171 * [I] HWND : window handle
3176 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3178 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3180 return infoPtr->hwndHeader;
3183 /* LISTVIEW_GetHotCursor */
3184 /* LISTVIEW_GetHotItem */
3185 /* LISTVIEW_GetHoverTime */
3189 * Retrieves an image list handle.
3192 * [I] HWND : window handle
3193 * [I] INT : image list identifier
3196 * SUCCESS : image list handle
3199 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3201 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3202 HIMAGELIST himl = NULL;
3207 himl = infoPtr->himlNormal;
3210 himl = infoPtr->himlSmall;
3213 himl = infoPtr->himlState;
3217 return (LRESULT)himl;
3220 /* LISTVIEW_GetISearchString */
3224 * Retrieves item attributes.
3227 * [I] HWND : window handle
3228 * [IO] LPLVITEMA : item info
3234 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
3236 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3237 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3238 BOOL bResult = FALSE;
3239 NMLVDISPINFOA dispInfo;
3240 LISTVIEW_SUBITEM *lpSubItem;
3241 LISTVIEW_ITEM *lpItem;
3244 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3246 if (lpLVItem != NULL)
3248 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
3250 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3251 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3252 if (hdpaSubItems != NULL)
3254 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3258 if (lpLVItem->iSubItem == 0)
3260 if ((lpItem->iImage == I_IMAGECALLBACK) &&
3261 (lpLVItem->mask & LVIF_IMAGE))
3263 dispInfo.item.mask |= LVIF_IMAGE;
3266 if ((lpItem->pszText == LPSTR_TEXTCALLBACKA) &&
3267 (lpLVItem->mask & LVIF_TEXT))
3269 dispInfo.item.mask |= LVIF_TEXT;
3270 ZeroMemory(lpLVItem->pszText, sizeof(CHAR)*lpLVItem->cchTextMax);
3271 dispInfo.item.pszText = lpLVItem->pszText;
3272 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3275 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3277 dispInfo.item.mask |= LVIF_STATE;
3278 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3281 if (dispInfo.item.mask != 0)
3283 dispInfo.hdr.hwndFrom = hwnd;
3284 dispInfo.hdr.idFrom = lCtrlId;
3285 dispInfo.hdr.code = LVN_GETDISPINFOA;
3286 dispInfo.item.iItem = lpLVItem->iItem;
3287 dispInfo.item.iSubItem = 0;
3288 dispInfo.item.lParam = lpItem->lParam;
3289 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3292 if (dispInfo.item.mask & LVIF_IMAGE)
3294 lpLVItem->iImage = dispInfo.item.iImage;
3296 else if (lpLVItem->mask & LVIF_IMAGE)
3298 lpLVItem->iImage = lpItem->iImage;
3301 if (dispInfo.item.mask & LVIF_TEXT)
3303 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3305 Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
3307 lpLVItem->pszText = dispInfo.item.pszText;
3309 else if (lpLVItem->mask & LVIF_TEXT)
3311 lpLVItem->pszText = lpItem->pszText;
3314 if (dispInfo.item.mask & LVIF_STATE)
3316 lpLVItem->state = lpItem->state;
3317 lpLVItem->state &= ~dispInfo.item.stateMask;
3318 lpLVItem->state |= (dispInfo.item.state &
3319 dispInfo.item.stateMask);
3321 else if (lpLVItem->mask & LVIF_STATE)
3323 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3326 if (lpLVItem->mask & LVIF_PARAM)
3328 lpLVItem->lParam = lpItem->lParam;
3331 if (lpLVItem->mask & LVIF_INDENT)
3333 lpLVItem->iIndent = lpItem->iIndent;
3338 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems,
3339 lpLVItem->iSubItem);
3340 if (lpSubItem != NULL)
3342 if ((lpSubItem->iImage == I_IMAGECALLBACK) &&
3343 (lpLVItem->mask & LVIF_IMAGE))
3345 dispInfo.item.mask |= LVIF_IMAGE;
3348 if ((lpSubItem->pszText == LPSTR_TEXTCALLBACKA) &&
3349 (lpLVItem->mask & LVIF_TEXT))
3351 dispInfo.item.mask |= LVIF_TEXT;
3352 ZeroMemory(lpLVItem->pszText,
3353 sizeof(CHAR)*lpLVItem->cchTextMax);
3354 dispInfo.item.pszText = lpLVItem->pszText;
3355 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3360 if (lpLVItem->mask & LVIF_IMAGE)
3362 dispInfo.item.mask |= LVIF_IMAGE;
3365 if (lpLVItem->mask & LVIF_TEXT)
3367 dispInfo.item.mask |= LVIF_TEXT;
3368 ZeroMemory(lpLVItem->pszText,
3369 sizeof(CHAR)*lpLVItem->cchTextMax);
3370 dispInfo.item.pszText = lpLVItem->pszText;
3371 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3375 if (dispInfo.item.mask != 0)
3377 dispInfo.hdr.hwndFrom = hwnd;
3378 dispInfo.hdr.idFrom = lCtrlId;
3379 dispInfo.hdr.code = LVN_GETDISPINFOA;
3380 dispInfo.item.iItem = lpLVItem->iItem;
3381 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3382 dispInfo.item.lParam = lpItem->lParam;
3383 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3386 if (dispInfo.item.mask & LVIF_IMAGE)
3388 lpLVItem->iImage = dispInfo.item.iImage;
3390 else if (lpLVItem->mask & LVIF_IMAGE)
3392 lpLVItem->iImage = lpItem->iImage;
3395 if (dispInfo.item.mask & LVIF_TEXT)
3397 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3400 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
3402 lpLVItem->pszText = dispInfo.item.pszText;
3404 else if (lpLVItem->mask & LVIF_TEXT)
3406 lpLVItem->pszText = lpSubItem->pszText;
3417 /* LISTVIEW_GetItemW */
3418 /* LISTVIEW_GetHotCursor */
3419 /* LISTVIEW_GetHotItem */
3420 /* LISTVIEW_GetHoverTime> */
3424 * Retrieves the number of items in the listview control.
3427 * [I] HWND : window handle
3432 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3434 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3436 return GETITEMCOUNT(infoPtr);
3441 * Retrieves the position (upper-left) of the listview control item.
3444 * [I] HWND : window handle
3445 * [I] INT : item index
3446 * [O] LPPOINT : coordinate information
3452 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3453 LPPOINT lpptPosition)
3455 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3456 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3457 BOOL bResult = FALSE;
3459 LISTVIEW_ITEM *lpItem;
3460 INT nCountPerColumn;
3463 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3466 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3467 (lpptPosition != NULL))
3469 if (uView == LVS_LIST)
3472 nItem = nItem - ListView_GetTopIndex(hwnd);
3473 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3476 nRow = nItem % nCountPerColumn;
3479 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3480 lpptPosition->y = 0;
3484 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3485 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3490 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3491 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3494 else if (uView == LVS_REPORT)
3497 lpptPosition->x = REPORT_MARGINX;
3498 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3499 infoPtr->nItemHeight) + infoPtr->rcList.top;
3503 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3504 if (hdpaSubItems != NULL)
3506 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3510 lpptPosition->x = lpItem->ptPosition.x;
3511 lpptPosition->y = lpItem->ptPosition.y;
3522 * Retrieves the bounding rectangle for a listview control item.
3525 * [I] HWND : window handle
3526 * [I] INT : item index
3527 * [IO] LPRECT : bounding rectangle coordinates
3533 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3535 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3536 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3537 BOOL bResult = FALSE;
3546 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3548 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3550 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3555 if (uView == LVS_ICON)
3557 if (infoPtr->himlNormal != NULL)
3559 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3562 lprc->left = ptItem.x + ptOrigin.x;
3563 lprc->top = ptItem.y + ptOrigin.y;
3564 lprc->right = lprc->left + infoPtr->iconSize.cx;
3565 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3566 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3570 else if (uView == LVS_SMALLICON)
3572 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3575 lprc->left = ptItem.x + ptOrigin.x;
3576 lprc->top = ptItem.y + ptOrigin.y;
3577 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3579 if (infoPtr->himlState != NULL)
3580 lprc->left += infoPtr->iconSize.cx;
3582 if (infoPtr->himlSmall != NULL)
3583 lprc->right = lprc->left + infoPtr->iconSize.cx;
3585 lprc->right = lprc->left;
3591 lprc->left = ptItem.x;
3592 lprc->top = ptItem.y;
3593 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3595 if (infoPtr->himlState != NULL)
3597 lprc->left += infoPtr->iconSize.cx;
3600 if (infoPtr->himlSmall != NULL)
3602 lprc->right = lprc->left + infoPtr->iconSize.cx;
3606 lprc->right = lprc->left;
3612 if (uView == LVS_ICON)
3614 if (infoPtr->himlNormal != NULL)
3616 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3619 lprc->left = ptItem.x + ptOrigin.x;
3620 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3621 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3622 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3623 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3625 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3626 lprc->right = lprc->left + nLabelWidth;
3631 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3635 hOldFont = SelectObject(hdc, infoPtr->hFont);
3636 GetTextMetricsA(hdc, &tm);
3637 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3638 SelectObject(hdc, hOldFont);
3639 ReleaseDC(hwnd, hdc);
3643 else if (uView == LVS_SMALLICON)
3645 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3648 nMaxWidth = lprc->left = ptItem.x + ptOrigin.x;
3649 lprc->top = ptItem.y + ptOrigin.y;
3650 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3652 if (infoPtr->himlState != NULL)
3654 lprc->left += infoPtr->iconSize.cx;
3657 if (infoPtr->himlSmall != NULL)
3659 lprc->left += infoPtr->iconSize.cx;
3662 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3663 if (lprc->left + nLabelWidth < nMaxWidth + infoPtr->nItemWidth)
3665 lprc->right = lprc->left + nLabelWidth;
3669 lprc->right = nMaxWidth + infoPtr->nItemWidth;
3676 lprc->left = ptItem.x;
3677 lprc->top = ptItem.y;
3678 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3680 if (infoPtr->himlState != NULL)
3682 lprc->left += infoPtr->iconSize.cx;
3685 if (infoPtr->himlSmall != NULL)
3687 lprc->left += infoPtr->iconSize.cx;
3690 lprc->right = lprc->left + LISTVIEW_GetLabelWidth(hwnd, nItem);
3695 if (uView == LVS_ICON)
3697 if (infoPtr->himlNormal != NULL)
3699 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3702 lprc->left = ptItem.x + ptOrigin.x;
3703 lprc->top = ptItem.y + ptOrigin.y;
3704 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3705 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3709 else if (uView == LVS_SMALLICON)
3711 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3714 lprc->left = ptItem.x + ptOrigin.x;
3715 lprc->right = lprc->left;
3716 lprc->top = ptItem.y + ptOrigin.y;
3717 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3718 if (infoPtr->himlState != NULL)
3719 lprc->right += infoPtr->iconSize.cx;
3720 if (infoPtr->himlSmall != NULL)
3721 lprc->right += infoPtr->iconSize.cx;
3722 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3728 lprc->left = ptItem.x;
3729 lprc->right = lprc->left;
3730 lprc->top = ptItem.y;
3731 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3733 if (infoPtr->himlState != NULL)
3735 lprc->right += infoPtr->iconSize.cx;
3738 if (infoPtr->himlSmall != NULL)
3740 lprc->right += infoPtr->iconSize.cx;
3743 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3747 case LVIR_SELECTBOUNDS:
3748 if (uView == LVS_ICON)
3750 if (infoPtr->himlNormal != NULL)
3752 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3755 lprc->left = ptItem.x + ptOrigin.x;
3756 lprc->top = ptItem.y + ptOrigin.y;
3757 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3758 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3762 else if (uView == LVS_SMALLICON)
3764 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3767 lprc->left = ptItem.x + ptOrigin.x;
3768 lprc->top = ptItem.y + ptOrigin.y;
3769 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3771 if (infoPtr->himlState != NULL)
3773 lprc->left += infoPtr->iconSize.cx;
3776 lprc->right = lprc->left;
3778 if (infoPtr->himlSmall != NULL)
3780 lprc->right += infoPtr->iconSize.cx;
3783 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3789 lprc->left = ptItem.x;
3790 lprc->top = ptItem.y;
3791 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3793 if (infoPtr->himlState != NULL)
3795 lprc->left += infoPtr->iconSize.cx;
3798 lprc->right = lprc->left;
3800 if (infoPtr->himlSmall != NULL)
3802 lprc->right += infoPtr->iconSize.cx;
3805 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3817 * Retrieves the width of a label.
3820 * [I] HWND : window handle
3823 * SUCCESS : string width (in pixels)
3826 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
3828 CHAR szDispText[DISP_TEXT_SIZE];
3829 INT nLabelWidth = 0;
3832 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
3834 ZeroMemory(&lvItem, sizeof(LVITEMA));
3835 lvItem.mask = LVIF_TEXT;
3836 lvItem.iItem = nItem;
3837 lvItem.cchTextMax = DISP_TEXT_SIZE;
3838 lvItem.pszText = szDispText;
3839 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3841 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3849 * Retrieves the spacing between listview control items.
3852 * [I] HWND : window handle
3853 * [I] BOOL : flag for small or large icon
3856 * Horizontal + vertical spacing
3858 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
3860 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3863 if (bSmall == FALSE)
3865 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
3869 /* TODO: need to store width of smallicon item */
3870 lResult = MAKELONG(0, infoPtr->nItemHeight);
3878 * Retrieves the state of a listview control item.
3881 * [I] HWND : window handle
3882 * [I] INT : item index
3883 * [I] UINT : state mask
3886 * State specified by the mask.
3888 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
3890 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3894 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3896 ZeroMemory(&lvItem, sizeof(LVITEMA));
3897 lvItem.iItem = nItem;
3898 lvItem.stateMask = uMask;
3899 lvItem.mask = LVIF_STATE;
3900 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3902 uState = lvItem.state;
3911 * Retrieves the text of a listview control item or subitem.
3914 * [I] HWND : window handle
3915 * [I] INT : item index
3916 * [IO] LPLVITEMA : item information
3919 * SUCCESS : string length
3922 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
3924 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3927 if (lpLVItem != NULL)
3929 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3931 lpLVItem->mask = LVIF_TEXT;
3932 lpLVItem->iItem = nItem;
3933 if (ListView_GetItemA(hwnd, lpLVItem) != FALSE)
3935 nLength = lstrlenA(lpLVItem->pszText);
3945 * Searches for an item based on properties + relationships.
3948 * [I] HWND : window handle
3949 * [I] INT : item index
3950 * [I] INT : relationship flag
3953 * SUCCESS : item index
3956 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
3958 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3959 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3961 LVFINDINFO lvFindInfo;
3962 INT nCountPerColumn;
3965 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
3967 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
3969 if (uFlags & LVNI_CUT)
3972 if (uFlags & LVNI_DROPHILITED)
3973 uMask |= LVIS_DROPHILITED;
3975 if (uFlags & LVNI_FOCUSED)
3976 uMask |= LVIS_FOCUSED;
3978 if (uFlags & LVNI_SELECTED)
3979 uMask |= LVIS_SELECTED;
3981 if (uFlags & LVNI_ABOVE)
3983 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
3988 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
3994 lvFindInfo.flags = LVFI_NEARESTXY;
3995 lvFindInfo.vkDirection = VK_UP;
3996 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
3997 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
3999 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4004 else if (uFlags & LVNI_BELOW)
4006 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4008 while (nItem < GETITEMCOUNT(infoPtr))
4011 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4017 lvFindInfo.flags = LVFI_NEARESTXY;
4018 lvFindInfo.vkDirection = VK_DOWN;
4019 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4020 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4022 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4027 else if (uFlags & LVNI_TOLEFT)
4029 if (uView == LVS_LIST)
4031 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4032 while (nItem - nCountPerColumn >= 0)
4034 nItem -= nCountPerColumn;
4035 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4039 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4041 lvFindInfo.flags = LVFI_NEARESTXY;
4042 lvFindInfo.vkDirection = VK_LEFT;
4043 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4044 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4046 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4051 else if (uFlags & LVNI_TORIGHT)
4053 if (uView == LVS_LIST)
4055 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4056 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4058 nItem += nCountPerColumn;
4059 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4063 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4065 lvFindInfo.flags = LVFI_NEARESTXY;
4066 lvFindInfo.vkDirection = VK_RIGHT;
4067 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4068 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4070 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4079 /* search by index */
4080 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4082 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4091 /* LISTVIEW_GetNumberOfWorkAreas */
4095 * Retrieves the origin coordinates when in icon or small icon display mode.
4098 * [I] HWND : window handle
4099 * [O] LPPOINT : coordinate information
4105 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4107 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4108 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4109 UINT uView = lStyle & LVS_TYPEMASK;
4110 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
4111 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
4112 BOOL bResult = FALSE;
4114 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4116 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4118 SCROLLINFO scrollInfo;
4119 ZeroMemory(lpptOrigin, sizeof(POINT));
4120 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4121 scrollInfo.cbSize = sizeof(SCROLLINFO);
4123 if (lStyle & WS_HSCROLL)
4125 scrollInfo.fMask = SIF_POS;
4126 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4128 lpptOrigin->x = -scrollInfo.nPos * max(nListWidth / 10, 1);
4132 if (lStyle & WS_VSCROLL)
4134 scrollInfo.fMask = SIF_POS;
4135 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4137 lpptOrigin->y = -scrollInfo.nPos * max(nListHeight / 10, 1);
4149 * Retrieves the number of items that are marked as selected.
4152 * [I] HWND : window handle
4155 * Number of items selected.
4157 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4159 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4160 INT nSelectedCount = 0;
4163 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4165 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4171 return nSelectedCount;
4176 * Retrieves item index that marks the start of a multiple selection.
4179 * [I] HWND : window handle
4182 * Index number or -1 if there is no selection mark.
4184 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4186 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4188 return infoPtr->nSelectionMark;
4193 * Retrieves the width of a string.
4196 * [I] HWND : window handle
4199 * SUCCESS : string width (in pixels)
4202 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4204 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4205 HFONT hFont, hOldFont;
4209 ZeroMemory(&stringSize, sizeof(SIZE));
4210 if (lpszText != NULL)
4212 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4214 hOldFont = SelectObject(hdc, hFont);
4215 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4216 SelectObject(hdc, hOldFont);
4217 ReleaseDC(hwnd, hdc);
4220 return stringSize.cx;
4225 * Retrieves the text backgound color.
4228 * [I] HWND : window handle
4231 * COLORREF associated with the the background.
4233 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4235 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4237 return infoPtr->clrTextBk;
4242 * Retrieves the text color.
4245 * [I] HWND : window handle
4248 * COLORREF associated with the text.
4250 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4252 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4254 return infoPtr->clrText;
4259 * Determines which section of the item was selected (if any).
4262 * [I] HWND : window handle
4263 * [IO] LPLVHITTESTINFO : hit test information
4266 * SUCCESS : item index
4269 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4271 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4275 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4276 lpHitTestInfo->pt.y);
4278 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4280 rcItem.left = LVIR_BOUNDS;
4281 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4283 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4285 rcItem.left = LVIR_ICON;
4286 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4288 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4290 lpHitTestInfo->flags = LVHT_ONITEMICON;
4291 lpHitTestInfo->iItem = i;
4292 lpHitTestInfo->iSubItem = 0;
4297 rcItem.left = LVIR_LABEL;
4298 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4300 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4302 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4303 lpHitTestInfo->iItem = i;
4304 lpHitTestInfo->iSubItem = 0;
4309 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4310 lpHitTestInfo->iItem = i;
4311 lpHitTestInfo->iSubItem = 0;
4317 lpHitTestInfo->flags = LVHT_NOWHERE;
4324 * Determines which listview item is located at the specified position.
4327 * [I] HWND : window handle
4328 * [IO} LPLVHITTESTINFO : hit test information
4331 * SUCCESS : item index
4334 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4336 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4339 lpHitTestInfo->flags = 0;
4341 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4343 lpHitTestInfo->flags = LVHT_TOLEFT;
4345 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4347 lpHitTestInfo->flags = LVHT_TORIGHT;
4349 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4351 lpHitTestInfo->flags |= LVHT_ABOVE;
4353 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4355 lpHitTestInfo->flags |= LVHT_BELOW;
4358 if (lpHitTestInfo->flags == 0)
4360 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4368 * Inserts a new column.
4371 * [I] HWND : window handle
4372 * [I] INT : column index
4373 * [I] LPLVCOLUMNA : column information
4376 * SUCCESS : new column index
4379 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4380 LPLVCOLUMNA lpColumn)
4382 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4384 INT nNewColumn = -1;
4386 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4389 if (lpColumn != NULL)
4391 /* initialize memory */
4392 ZeroMemory(&hdi, sizeof(HDITEMA));
4394 if (lpColumn->mask & LVCF_FMT)
4396 /* format member is valid */
4397 hdi.mask |= HDI_FORMAT;
4399 /* set text alignment (leftmost column must be left-aligned) */
4402 hdi.fmt |= HDF_LEFT;
4406 if (lpColumn->fmt & LVCFMT_LEFT)
4408 hdi.fmt |= HDF_LEFT;
4410 else if (lpColumn->fmt & LVCFMT_RIGHT)
4412 hdi.fmt |= HDF_RIGHT;
4414 else if (lpColumn->fmt & LVCFMT_CENTER)
4416 hdi.fmt |= HDF_CENTER;
4420 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4422 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4426 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4431 if (lpColumn->fmt & LVCFMT_IMAGE)
4433 hdi.fmt |= HDF_IMAGE;
4434 hdi.iImage = I_IMAGECALLBACK;
4438 if (lpColumn->mask & LVCF_WIDTH)
4440 hdi.mask |= HDI_WIDTH;
4441 hdi.cxy = lpColumn->cx;
4444 if (lpColumn->mask & LVCF_TEXT)
4446 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4447 hdi.pszText = lpColumn->pszText;
4448 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4449 hdi.fmt |= HDF_STRING;
4452 if (lpColumn->mask & LVCF_IMAGE)
4454 hdi.mask |= HDI_IMAGE;
4455 hdi.iImage = lpColumn->iImage;
4458 if (lpColumn->mask & LVCF_ORDER)
4460 hdi.mask |= HDI_ORDER;
4461 hdi.iOrder = lpColumn->iOrder;
4464 /* insert item in header control */
4465 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4466 (WPARAM)nColumn, (LPARAM)&hdi);
4468 LISTVIEW_UpdateScroll(hwnd);
4469 InvalidateRect(hwnd, NULL, FALSE);
4475 /* LISTVIEW_InsertColumnW */
4479 * Inserts a new item in the listview control.
4482 * [I] HWND : window handle
4483 * [I] LPLVITEMA : item information
4486 * SUCCESS : new item index
4489 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4491 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4492 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4493 UINT uView = lStyle & LVS_TYPEMASK;
4494 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4498 LISTVIEW_ITEM *lpItem = NULL;
4500 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4502 if (lpLVItem != NULL)
4504 /* make sure it's not a subitem; cannot insert a subitem */
4505 if (lpLVItem->iSubItem == 0)
4507 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4510 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4511 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4513 /* insert item in listview control data structure */
4514 hdpaSubItems = DPA_Create(8);
4515 if (hdpaSubItems != NULL)
4517 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4520 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4524 /* manage item focus */
4525 if (lpLVItem->mask & LVIF_STATE)
4527 if (lpLVItem->stateMask & LVIS_FOCUSED)
4529 LISTVIEW_SetItemFocus(hwnd, nItem);
4533 /* send LVN_INSERTITEM notification */
4534 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4535 nmlv.hdr.hwndFrom = hwnd;
4536 nmlv.hdr.idFrom = lCtrlId;
4537 nmlv.hdr.code = LVN_INSERTITEM;
4539 nmlv.lParam = lpItem->lParam;;
4540 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4542 /* align items (set position of each item) */
4543 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4545 if (lStyle & LVS_ALIGNLEFT)
4547 LISTVIEW_AlignLeft(hwnd);
4551 LISTVIEW_AlignTop(hwnd);
4555 LISTVIEW_UpdateScroll(hwnd);
4556 /* refresh client area */
4557 InvalidateRect(hwnd, NULL, FALSE);
4566 /* free memory if unsuccessful */
4567 if ((nItem == -1) && (lpItem != NULL))
4569 COMCTL32_Free(lpItem);
4575 /* LISTVIEW_InsertItemW */
4579 * Redraws a range of items.
4582 * [I] HWND : window handle
4583 * [I] INT : first item
4584 * [I] INT : last item
4590 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4592 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4593 BOOL bResult = FALSE;
4596 if (nFirst <= nLast)
4598 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4600 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4603 InvalidateRect(hwnd, &rc, FALSE);
4611 /* LISTVIEW_Scroll */
4615 * Sets the background color.
4618 * [I] HWND : window handle
4619 * [I] COLORREF : background color
4625 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
4627 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4629 infoPtr->clrBk = clrBk;
4630 InvalidateRect(hwnd, NULL, TRUE);
4637 * Sets the callback mask. This mask will be used when the parent
4638 * window stores state information (some or all).
4641 * [I] HWND : window handle
4642 * [I] UINT : state mask
4648 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
4650 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4652 infoPtr->uCallbackMask = uMask;
4659 * Sets the attributes of a header item.
4662 * [I] HWND : window handle
4663 * [I] INT : column index
4664 * [I] LPLVCOLUMNA : column attributes
4670 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
4671 LPLVCOLUMNA lpColumn)
4673 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4674 BOOL bResult = FALSE;
4675 HDITEMA hdi, hdiget;
4677 if ((lpColumn != NULL) && (nColumn >= 0) &&
4678 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
4680 /* initialize memory */
4681 ZeroMemory(&hdi, sizeof(HDITEMA));
4683 if (lpColumn->mask & LVCF_FMT)
4685 /* format member is valid */
4686 hdi.mask |= HDI_FORMAT;
4688 /* get current format first */
4689 hdiget.mask = HDI_FORMAT;
4690 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
4691 /* preserve HDF_STRING if present */
4692 hdi.fmt = hdiget.fmt & HDF_STRING;
4694 /* set text alignment (leftmost column must be left-aligned) */
4697 hdi.fmt |= HDF_LEFT;
4701 if (lpColumn->fmt & LVCFMT_LEFT)
4703 hdi.fmt |= HDF_LEFT;
4705 else if (lpColumn->fmt & LVCFMT_RIGHT)
4707 hdi.fmt |= HDF_RIGHT;
4709 else if (lpColumn->fmt & LVCFMT_CENTER)
4711 hdi.fmt |= HDF_CENTER;
4715 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4717 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4720 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4722 hdi.fmt |= HDF_IMAGE;
4725 if (lpColumn->fmt & LVCFMT_IMAGE)
4727 hdi.fmt |= HDF_IMAGE;
4728 hdi.iImage = I_IMAGECALLBACK;
4732 if (lpColumn->mask & LVCF_WIDTH)
4734 hdi.mask |= HDI_WIDTH;
4735 hdi.cxy = lpColumn->cx;
4738 if (lpColumn->mask & LVCF_TEXT)
4740 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4741 hdi.pszText = lpColumn->pszText;
4742 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4743 hdi.fmt |= HDF_STRING;
4746 if (lpColumn->mask & LVCF_IMAGE)
4748 hdi.mask |= HDI_IMAGE;
4749 hdi.iImage = lpColumn->iImage;
4752 if (lpColumn->mask & LVCF_ORDER)
4754 hdi.mask |= HDI_ORDER;
4755 hdi.iOrder = lpColumn->iOrder;
4758 /* set header item attributes */
4759 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
4767 * Sets the width of a column
4770 * [I] HWND : window handle
4771 * [I] INT : column index
4772 * [I] INT : column width
4778 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
4780 LISTVIEW_INFO *infoPtr;
4785 /* set column width only if in report mode */
4786 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4787 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
4790 /* make sure we can get the listview info */
4791 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4793 if (!infoPtr->hwndHeader) /* make sure we have a header */
4796 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
4797 * LVSCV_AUTOSIZE_USEHEADER (-2)
4802 hdi.mask = HDI_WIDTH;
4805 /* call header to update the column change */
4806 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
4808 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4810 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
4820 * [I] HWND : window handle
4821 * [I] INT : image list type
4822 * [I] HIMAGELIST : image list handle
4825 * SUCCESS : old image list
4828 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
4830 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4831 HIMAGELIST himlTemp = 0;
4836 himlTemp = infoPtr->himlNormal;
4837 infoPtr->himlNormal = himl;
4838 return (LRESULT)himlTemp;
4841 himlTemp = infoPtr->himlSmall;
4842 infoPtr->himlSmall = himl;
4843 return (LRESULT)himlTemp;
4846 himlTemp = infoPtr->himlState;
4847 infoPtr->himlState = himl;
4848 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
4849 return (LRESULT)himlTemp;
4852 return (LRESULT)NULL;
4858 * Sets the attributes of an item.
4861 * [I] HWND : window handle
4862 * [I] LPLVITEM : item information
4868 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
4870 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4871 BOOL bResult = FALSE;
4873 if (lpLVItem != NULL)
4875 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
4877 if (lpLVItem->iSubItem == 0)
4879 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
4883 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
4892 /* LISTVIEW_SetItemW */
4896 * Preallocates memory.
4899 * [I] HWND : window handle
4900 * [I] INT : item count (prjected number of items)
4905 static VOID LISTVIEW_SetItemCount(HWND hwnd, INT nItemCount)
4907 FIXME("empty stub!\n");
4912 * Sets the position of an item.
4915 * [I] HWND : window handle
4916 * [I] INT : item index
4917 * [I] INT : x coordinate
4918 * [I] INT : y coordinate
4924 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
4925 INT nPosX, INT nPosY)
4927 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4928 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4929 LISTVIEW_ITEM *lpItem;
4931 BOOL bResult = FALSE;
4933 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
4935 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
4937 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
4939 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
4940 if (hdpaSubItems != NULL)
4942 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4946 lpItem->ptPosition.x = nPosX;
4947 lpItem->ptPosition.y = nPosY;
4958 * Sets the state of one or many items.
4961 * [I] HWND : window handle
4962 * [I]INT : item index
4963 * [I] LPLVITEM : item or subitem info
4969 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4971 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4972 BOOL bResult = FALSE;
4979 ZeroMemory(&lvItem, sizeof(LVITEMA));
4980 lvItem.mask = LVIF_STATE;
4981 lvItem.state = lpLVItem->state;
4982 lvItem.stateMask = lpLVItem->stateMask ;
4984 /* apply to all items */
4985 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
4988 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
4996 ZeroMemory(&lvItem, sizeof(LVITEMA));
4997 lvItem.mask = LVIF_STATE;
4998 lvItem.state = lpLVItem->state;
4999 lvItem.stateMask = lpLVItem->stateMask;
5000 lvItem.iItem = nItem;
5001 bResult = ListView_SetItemA(hwnd, &lvItem);
5009 * Sets the text of an item or subitem.
5012 * [I] HWND : window handle
5013 * [I] INT : item index
5014 * [I] LPLVITEMA : item or subitem info
5020 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5022 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5023 BOOL bResult = FALSE;
5026 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5028 ZeroMemory(&lvItem, sizeof(LVITEMA));
5029 lvItem.mask = LVIF_TEXT;
5030 lvItem.pszText = lpLVItem->pszText;
5031 lvItem.iItem = nItem;
5032 lvItem.iSubItem = lpLVItem->iSubItem;
5033 bResult = ListView_SetItemA(hwnd, &lvItem);
5041 * Sets the text background color.
5044 * [I] HWND : window handle
5045 * [I] COLORREF : text background color
5051 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5053 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5055 infoPtr->clrTextBk = clrTextBk;
5056 InvalidateRect(hwnd, NULL, TRUE);
5063 * Sets the text foreground color.
5066 * [I] HWND : window handle
5067 * [I] COLORREF : text color
5073 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5075 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5077 infoPtr->clrText = clrText;
5078 InvalidateRect(hwnd, NULL, TRUE);
5086 * Callback internally used by LISTVIEW_SortItems()
5089 * [I] LPVOID : first LISTVIEW_ITEM to compare
5090 * [I] LPVOID : second LISTVIEW_ITEM to compare
5091 * [I] LPARAM : HWND of control
5094 * if first comes before second : negative
5095 * if first comes after second : positive
5096 * if first and second are equivalent : zero
5098 static INT WINAPI LISTVIEW_CallBackCompare(
5103 /* Forward the call to the client defined callback */
5104 HWND hwnd = (HWND)lParam;
5105 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5107 return (infoPtr->pfnCompare)(
5108 ((LISTVIEW_ITEM *)first)->lParam,
5109 ((LISTVIEW_ITEM *)second)->lParam,
5110 infoPtr->lParamSort);
5115 * Sorts the listview items.
5118 * [I] HWND : window handle
5119 * [I] WPARAM : application-defined value
5120 * [I] LPARAM : pointer to comparision callback
5126 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5128 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5130 LISTVIEW_ITEM *lpItem;
5134 if (!infoPtr || !infoPtr->hdpaItems)
5137 nCount = GETITEMCOUNT(infoPtr);
5138 /* if there are 0 or 1 items, there is no need to sort */
5141 sortList = DPA_Create(nCount);
5143 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5144 infoPtr->lParamSort = (LPARAM)wParam;
5146 /* append pointers one by one to sortList */
5147 for (i = 0; i < nCount; i++)
5149 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5150 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5151 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5154 /* sort the sortList */
5155 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5157 /* copy the pointers back */
5158 for (i = 0; i < nCount; i++)
5160 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5161 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5162 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5165 DPA_Destroy(sortList);
5173 * Updates an items or rearranges the listview control.
5176 * [I] HWND : window handle
5177 * [I] INT : item index
5183 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5185 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5186 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5187 BOOL bResult = FALSE;
5190 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5194 /* rearrange with default alignment style */
5195 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5196 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5198 ListView_Arrange(hwnd, 0);
5202 /* get item bounding rectangle */
5203 rc.left = LVIR_BOUNDS;
5204 ListView_GetItemRect(hwnd, nItem, &rc);
5205 InvalidateRect(hwnd, &rc, TRUE);
5214 * Creates the listview control.
5217 * [I] HWND : window handle
5222 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5224 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5225 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5226 UINT uView = lpcs->style & LVS_TYPEMASK;
5229 /* initialize info pointer */
5230 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5232 /* determine the type of structures to use */
5233 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5234 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5235 if (infoPtr->notifyFormat != NFR_ANSI)
5237 FIXME("ANSI notify format is NOT used\n");
5240 /* initialize color information */
5241 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5242 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5243 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5245 /* set default values */
5246 infoPtr->uCallbackMask = 0;
5247 infoPtr->nFocusedItem = -1;
5248 infoPtr->nSelectionMark = -1;
5249 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5250 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5251 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5253 /* get default font (icon title) */
5254 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5255 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5256 infoPtr->hFont = infoPtr->hDefaultFont;
5259 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5260 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5261 0, 0, 0, 0, hwnd, (HMENU)0,
5262 lpcs->hInstance, NULL);
5264 /* set header font */
5265 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5268 if (uView == LVS_ICON)
5270 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5271 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5273 else if (uView == LVS_REPORT)
5275 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5277 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5280 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5281 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5285 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5286 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5289 /* display unsupported listview window styles */
5290 LISTVIEW_UnsupportedStyles(lpcs->style);
5292 /* allocate memory for the data structure */
5293 infoPtr->hdpaItems = DPA_Create(10);
5295 /* initialize size of items */
5296 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5297 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
5304 * Erases the background of the listview control.
5307 * [I] HWND : window handle
5308 * [I] WPARAM : device context handle
5309 * [I] LPARAM : not used
5315 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5318 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5321 if (infoPtr->clrBk == CLR_NONE)
5323 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5328 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5329 GetClientRect(hwnd, &rc);
5330 FillRect((HDC)wParam, &rc, hBrush);
5331 DeleteObject(hBrush);
5340 * Retrieves the listview control font.
5343 * [I] HWND : window handle
5348 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5350 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5352 return infoPtr->hFont;
5357 * Performs vertical scrolling.
5360 * [I] HWND : window handle
5361 * [I] INT : scroll code
5362 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5364 * [I] HWND : scrollbar control window handle
5369 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5372 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5373 SCROLLINFO scrollInfo;
5375 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5376 scrollInfo.cbSize = sizeof(SCROLLINFO);
5377 scrollInfo.fMask = /*SIF_PAGE |*/ SIF_POS | SIF_RANGE;
5379 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5381 INT nOldScrollPos = scrollInfo.nPos;
5382 switch (nScrollCode)
5385 if (scrollInfo.nPos > scrollInfo.nMin)
5392 if (scrollInfo.nPos < scrollInfo.nMax)
5399 if (scrollInfo.nPos > scrollInfo.nMin)
5403 if (uView == LVS_REPORT)
5405 nPage = LISTVIEW_GetCountPerColumn(hwnd);
5407 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5412 if (scrollInfo.nPos >= nPage)
5414 scrollInfo.nPos -= nPage;
5418 scrollInfo.nPos = scrollInfo.nMin;
5424 if (scrollInfo.nPos < scrollInfo.nMax)
5428 if (uView == LVS_REPORT)
5430 nPage = LISTVIEW_GetCountPerColumn(hwnd);
5432 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5437 if (scrollInfo.nPos <= scrollInfo.nMax - nPage)
5439 scrollInfo.nPos += nPage;
5443 scrollInfo.nPos = scrollInfo.nMax;
5448 case SB_THUMBPOSITION:
5452 if (nOldScrollPos != scrollInfo.nPos)
5454 scrollInfo.fMask = SIF_POS;
5455 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
5456 InvalidateRect(hwnd, NULL, TRUE);
5465 * Performs horizontal scrolling.
5468 * [I] HWND : window handle
5469 * [I] INT : scroll code
5470 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5472 * [I] HWND : scrollbar control window handle
5477 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5480 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5481 SCROLLINFO scrollInfo;
5483 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5484 scrollInfo.cbSize = sizeof(SCROLLINFO);
5485 scrollInfo.fMask = /*SIF_PAGE |*/ SIF_POS | SIF_RANGE;
5487 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5489 INT nOldScrollPos = scrollInfo.nPos;
5491 switch (nScrollCode)
5494 if (scrollInfo.nPos > scrollInfo.nMin)
5501 if (scrollInfo.nPos < scrollInfo.nMax)
5508 if (scrollInfo.nPos > scrollInfo.nMin)
5512 if (uView == LVS_LIST)
5514 nPage = LISTVIEW_GetCountPerRow(hwnd);
5516 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5521 if (scrollInfo.nPos >= nPage)
5523 scrollInfo.nPos -= nPage;
5527 scrollInfo.nPos = scrollInfo.nMin;
5533 if (scrollInfo.nPos < scrollInfo.nMax)
5537 if (uView == LVS_LIST)
5539 nPage = LISTVIEW_GetCountPerRow(hwnd);
5541 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5546 if (scrollInfo.nPos <= scrollInfo.nMax - nPage)
5548 scrollInfo.nPos += nPage;
5552 scrollInfo.nPos = scrollInfo.nMax;
5557 case SB_THUMBPOSITION:
5561 if (nOldScrollPos != scrollInfo.nPos)
5563 scrollInfo.fMask = SIF_POS;
5564 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
5565 InvalidateRect(hwnd, NULL, TRUE);
5577 * [I] HWND : window handle
5578 * [I] INT : virtual key
5579 * [I] LONG : key data
5584 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
5586 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5587 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5588 HWND hwndParent = GetParent(hwnd);
5589 NMLVKEYDOWN nmKeyDown;
5592 BOOL bRedraw = FALSE;
5594 /* send LVN_KEYDOWN notification */
5595 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
5596 nmKeyDown.hdr.hwndFrom = hwnd;
5597 nmKeyDown.hdr.idFrom = nCtrlId;
5598 nmKeyDown.hdr.code = LVN_KEYDOWN;
5599 nmKeyDown.wVKey = nVirtualKey;
5600 nmKeyDown.flags = 0;
5601 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
5604 nmh.hwndFrom = hwnd;
5605 nmh.idFrom = nCtrlId;
5607 switch (nVirtualKey)
5610 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
5612 /* send NM_RETURN notification */
5613 nmh.code = NM_RETURN;
5614 ListView_Notify(hwndParent, nCtrlId, &nmh);
5616 /* send LVN_ITEMACTIVATE notification */
5617 nmh.code = LVN_ITEMACTIVATE;
5618 ListView_Notify(hwndParent, nCtrlId, &nmh);
5623 if (GETITEMCOUNT(infoPtr) > 0)
5630 if (GETITEMCOUNT(infoPtr) > 0)
5632 nItem = GETITEMCOUNT(infoPtr) - 1;
5637 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
5641 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
5645 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
5649 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
5661 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
5663 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
5664 if (bRedraw != FALSE)
5666 /* refresh client area */
5667 InvalidateRect(hwnd, NULL, TRUE);
5680 * [I] HWND : window handle
5685 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
5687 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5688 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5691 /* send NM_KILLFOCUS notification */
5692 nmh.hwndFrom = hwnd;
5693 nmh.idFrom = nCtrlId;
5694 nmh.code = NM_KILLFOCUS;
5695 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5697 /* set window focus flag */
5698 infoPtr->bFocus = FALSE;
5700 /* NEED drawing optimization ; redraw the selected items */
5701 InvalidateRect(hwnd, NULL, FALSE);
5708 * Processes double click messages (left mouse button).
5711 * [I] HWND : window handle
5712 * [I] WORD : key flag
5713 * [I] WORD : x coordinate
5714 * [I] WORD : y coordinate
5719 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
5722 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5725 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5727 /* send NM_DBLCLK notification */
5728 nmh.hwndFrom = hwnd;
5729 nmh.idFrom = nCtrlId;
5730 nmh.code = NM_DBLCLK;
5731 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5733 /* send LVN_ITEMACTIVATE notification */
5734 nmh.code = LVN_ITEMACTIVATE;
5735 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5742 * Processes mouse down messages (left mouse button).
5745 * [I] HWND : window handle
5746 * [I] WORD : key flag
5747 * [I] WORD : x coordinate
5748 * [I] WORD : y coordinate
5753 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
5756 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5757 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5758 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5759 static BOOL bGroupSelect = TRUE;
5764 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
5767 /* send NM_RELEASEDCAPTURE notification */
5768 nmh.hwndFrom = hwnd;
5769 nmh.idFrom = nCtrlId;
5770 nmh.code = NM_RELEASEDCAPTURE;
5771 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5773 if (infoPtr->bFocus == FALSE)
5778 /* set left button down flag */
5779 infoPtr->bLButtonDown = TRUE;
5781 ptPosition.x = wPosX;
5782 ptPosition.y = wPosY;
5783 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
5784 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5786 if (lStyle & LVS_SINGLESEL)
5788 LISTVIEW_SetSelection(hwnd, nItem);
5792 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
5794 if (bGroupSelect != FALSE)
5796 LISTVIEW_AddGroupSelection(hwnd, nItem);
5800 LISTVIEW_AddSelection(hwnd, nItem);
5803 else if (wKey & MK_CONTROL)
5805 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
5807 else if (wKey & MK_SHIFT)
5809 LISTVIEW_SetGroupSelection(hwnd, nItem);
5813 LISTVIEW_SetSelection(hwnd, nItem);
5819 /* remove all selections */
5820 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
5823 InvalidateRect(hwnd, NULL, TRUE);
5830 * Processes mouse up messages (left mouse button).
5833 * [I] HWND : window handle
5834 * [I] WORD : key flag
5835 * [I] WORD : x coordinate
5836 * [I] WORD : y coordinate
5841 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
5844 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5846 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5848 if (infoPtr->bLButtonDown != FALSE)
5850 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5853 /* send NM_CLICK notification */
5854 nmh.hwndFrom = hwnd;
5855 nmh.idFrom = nCtrlId;
5856 nmh.code = NM_CLICK;
5857 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5859 /* set left button flag */
5860 infoPtr->bLButtonDown = FALSE;
5868 * Creates the listview control (called before WM_CREATE).
5871 * [I] HWND : window handle
5872 * [I] WPARAM : unhandled
5873 * [I] LPARAM : widow creation info
5878 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
5880 LISTVIEW_INFO *infoPtr;
5882 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
5884 /* allocate memory for info structure */
5885 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
5886 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
5887 if (infoPtr == NULL)
5889 ERR("could not allocate info memory!\n");
5893 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
5895 ERR("pointer assignment error!\n");
5899 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
5904 * Destroys the listview control (called after WM_DESTROY).
5907 * [I] HWND : window handle
5912 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
5914 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5916 TRACE("(hwnd=%x)\n", hwnd);
5918 /* delete all items */
5919 LISTVIEW_DeleteAllItems(hwnd);
5921 /* destroy data structure */
5922 DPA_Destroy(infoPtr->hdpaItems);
5925 infoPtr->hFont = (HFONT)0;
5926 if (infoPtr->hDefaultFont)
5928 DeleteObject(infoPtr->hDefaultFont);
5931 /* free listview info pointer*/
5932 COMCTL32_Free(infoPtr);
5939 * Handles notifications from children.
5942 * [I] HWND : window handle
5943 * [I] INT : control identifier
5944 * [I] LPNMHDR : notification information
5949 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
5951 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5953 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
5955 /* handle notification from header control */
5956 if (lpnmh->code == HDN_ENDTRACKA)
5958 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5959 InvalidateRect(hwnd, NULL, TRUE);
5968 * Determines the type of structure to use.
5971 * [I] HWND : window handle of the sender
5972 * [I] HWND : listview window handle
5973 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
5978 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
5980 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5982 if (nCommand == NF_REQUERY)
5984 /* determine the type of structure to use */
5985 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
5986 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5987 if (infoPtr->notifyFormat == NFR_UNICODE)
5989 FIXME("NO support for unicode structures");
5998 * Paints/Repaints the listview control.
6001 * [I] HWND : window handle
6002 * [I] HDC : device context handle
6007 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6011 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6015 hdc = BeginPaint(hwnd, &ps);
6016 LISTVIEW_Refresh(hwnd, hdc);
6017 EndPaint(hwnd, &ps);
6021 LISTVIEW_Refresh(hwnd, hdc);
6029 * Processes double click messages (right mouse button).
6032 * [I] HWND : window handle
6033 * [I] WORD : key flag
6034 * [I] WORD : x coordinate
6035 * [I] WORD : y coordinate
6040 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6043 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6046 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6048 /* send NM_RELEASEDCAPTURE notification */
6049 nmh.hwndFrom = hwnd;
6050 nmh.idFrom = nCtrlId;
6051 nmh.code = NM_RELEASEDCAPTURE;
6052 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6054 /* send NM_RDBLCLK notification */
6055 nmh.code = NM_RDBLCLK;
6056 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6063 * Processes mouse down messages (right mouse button).
6066 * [I] HWND : window handle
6067 * [I] WORD : key flag
6068 * [I] WORD : x coordinate
6069 * [I] WORD : y coordinate
6074 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6077 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6078 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6083 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6085 /* send NM_RELEASEDCAPTURE notification */
6086 nmh.hwndFrom = hwnd;
6087 nmh.idFrom = nCtrlId;
6088 nmh.code = NM_RELEASEDCAPTURE;
6089 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6091 /* make sure the listview control window has the focus */
6092 if (infoPtr->bFocus == FALSE)
6097 /* set right button down flag */
6098 infoPtr->bRButtonDown = TRUE;
6100 /* determine the index of the selected item */
6101 ptPosition.x = wPosX;
6102 ptPosition.y = wPosY;
6103 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6104 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6106 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6108 LISTVIEW_SetSelection(hwnd, nItem);
6113 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6121 * Processes mouse up messages (right mouse button).
6124 * [I] HWND : window handle
6125 * [I] WORD : key flag
6126 * [I] WORD : x coordinate
6127 * [I] WORD : y coordinate
6132 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6135 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6136 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6139 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6141 if (infoPtr->bRButtonDown != FALSE)
6143 /* send NM_RClICK notification */
6144 ZeroMemory(&nmh, sizeof(NMHDR));
6145 nmh.hwndFrom = hwnd;
6146 nmh.idFrom = nCtrlId;
6147 nmh.code = NM_RCLICK;
6148 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6150 /* set button flag */
6151 infoPtr->bRButtonDown = FALSE;
6162 * [I] HWND : window handle
6163 * [I] HWND : window handle of previously focused window
6168 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6170 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6171 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6174 /* send NM_SETFOCUS notification */
6175 nmh.hwndFrom = hwnd;
6176 nmh.idFrom = nCtrlId;
6177 nmh.code = NM_SETFOCUS;
6178 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6180 /* set window focus flag */
6181 infoPtr->bFocus = TRUE;
6191 * [I] HWND : window handle
6192 * [I] HFONT : font handle
6193 * [I] WORD : redraw flag
6198 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6200 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6201 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6203 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6207 infoPtr->hFont = infoPtr->hDefaultFont;
6211 infoPtr->hFont = hFont;
6214 if (uView == LVS_REPORT)
6216 /* set header font */
6217 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6218 MAKELPARAM(fRedraw, 0));
6221 /* invalidate listview control client area */
6222 InvalidateRect(hwnd, NULL, TRUE);
6224 if (fRedraw != FALSE)
6234 * Resizes the listview control. This function processes WM_SIZE
6235 * messages. At this time, the width and height are not used.
6238 * [I] HWND : window handle
6239 * [I] WORD : new width
6240 * [I] WORD : new height
6245 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6247 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6248 UINT uView = lStyle & LVS_TYPEMASK;
6250 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
6252 LISTVIEW_UpdateSize(hwnd);
6254 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6256 if (lStyle & LVS_ALIGNLEFT)
6258 LISTVIEW_AlignLeft(hwnd);
6262 LISTVIEW_AlignTop(hwnd);
6266 LISTVIEW_UpdateScroll(hwnd);
6268 /* invalidate client area + erase background */
6269 InvalidateRect(hwnd, NULL, TRUE);
6276 * Sets the size information.
6279 * [I] HWND : window handle
6284 static VOID LISTVIEW_UpdateSize(HWND hwnd)
6286 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6287 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6288 UINT uView = lStyle & LVS_TYPEMASK;
6291 GetClientRect(hwnd, &rcList);
6292 infoPtr->rcList.left = 0;
6293 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
6294 infoPtr->rcList.top = 0;
6295 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
6297 if (uView == LVS_LIST)
6299 if ((lStyle & WS_HSCROLL) == 0)
6301 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6302 if (infoPtr->rcList.bottom > nHScrollHeight)
6304 infoPtr->rcList.bottom -= nHScrollHeight;
6308 else if (uView == LVS_REPORT)
6315 Header_Layout(infoPtr->hwndHeader, &hl);
6316 if (!(LVS_NOCOLUMNHEADER & lStyle))
6318 infoPtr->rcList.top = max(wp.cy, 0);
6325 * Processes WM_STYLECHANGED messages.
6328 * [I] HWND : window handle
6329 * [I] WPARAM : window style type (normal or extended)
6330 * [I] LPSTYLESTRUCT : window style information
6335 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6338 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6339 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
6340 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
6341 RECT rcList = infoPtr->rcList;
6343 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
6344 hwnd, wStyleType, lpss);
6346 if (wStyleType == GWL_STYLE)
6348 if (uOldView == LVS_REPORT)
6350 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6353 if ((lpss->styleOld & WS_HSCROLL) != 0)
6355 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6358 if ((lpss->styleOld & WS_VSCROLL) != 0)
6360 ShowScrollBar(hwnd, SB_VERT, FALSE);
6363 if (uNewView == LVS_ICON)
6365 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6366 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6367 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6368 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6369 if (lpss->styleNew & LVS_ALIGNLEFT)
6371 LISTVIEW_AlignLeft(hwnd);
6375 LISTVIEW_AlignTop(hwnd);
6378 else if (uNewView == LVS_REPORT)
6385 Header_Layout(infoPtr->hwndHeader, &hl);
6386 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
6388 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
6390 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6392 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6393 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6394 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6395 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6397 else if (uNewView == LVS_LIST)
6399 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6400 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6401 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6402 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6406 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6407 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6408 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6409 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6410 if (lpss->styleNew & LVS_ALIGNLEFT)
6412 LISTVIEW_AlignLeft(hwnd);
6416 LISTVIEW_AlignTop(hwnd);
6420 /* update the size of the client area */
6421 LISTVIEW_UpdateSize(hwnd);
6423 /* add scrollbars if needed */
6424 LISTVIEW_UpdateScroll(hwnd);
6426 /* invalidate client area + erase background */
6427 InvalidateRect(hwnd, NULL, TRUE);
6429 /* print the list of unsupported window styles */
6430 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6438 * Window procedure of the listview control.
6441 LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6446 case LVM_APPROXIMATEVIEWRECT:
6447 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6448 LOWORD(lParam), HIWORD(lParam));
6450 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6452 /* case LVM_CREATEDRAGIMAGE: */
6454 case LVM_DELETEALLITEMS:
6455 return LISTVIEW_DeleteAllItems(hwnd);
6457 case LVM_DELETECOLUMN:
6458 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6460 case LVM_DELETEITEM:
6461 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6463 /* case LVM_EDITLABEL: */
6465 case LVM_ENSUREVISIBLE:
6466 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6469 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6471 case LVM_GETBKCOLOR:
6472 return LISTVIEW_GetBkColor(hwnd);
6474 /* case LVM_GETBKIMAGE: */
6476 case LVM_GETCALLBACKMASK:
6477 return LISTVIEW_GetCallbackMask(hwnd);
6479 case LVM_GETCOLUMNA:
6480 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6482 /* case LVM_GETCOLUMNW: */
6483 /* case LVM_GETCOLUMNORDERARRAY: */
6485 case LVM_GETCOLUMNWIDTH:
6486 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
6488 case LVM_GETCOUNTPERPAGE:
6489 return LISTVIEW_GetCountPerPage(hwnd);
6491 /* case LVM_GETEDITCONTROL: */
6492 /* case LVM_GETEXTENDEDLISTVIEWSTYLE: */
6495 return LISTVIEW_GetHeader(hwnd);
6497 /* case LVM_GETHOTCURSOR: */
6498 /* case LVM_GETHOTITEM: */
6499 /* case LVM_GETHOVERTIME: */
6501 case LVM_GETIMAGELIST:
6502 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
6504 /* case LVM_GETISEARCHSTRING: */
6507 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
6509 /* case LVM_GETITEMW: */
6511 case LVM_GETITEMCOUNT:
6512 return LISTVIEW_GetItemCount(hwnd);
6514 case LVM_GETITEMPOSITION:
6515 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
6517 case LVM_GETITEMRECT:
6518 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
6520 case LVM_GETITEMSPACING:
6521 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
6523 case LVM_GETITEMSTATE:
6524 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
6526 case LVM_GETITEMTEXTA:
6527 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6530 /* case LVM_GETITEMTEXTW: */
6532 case LVM_GETNEXTITEM:
6533 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
6535 /* case LVM_GETNUMBEROFWORKAREAS: */
6538 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
6540 case LVM_GETSELECTEDCOUNT:
6541 return LISTVIEW_GetSelectedCount(hwnd);
6543 case LVM_GETSELECTIONMARK:
6544 return LISTVIEW_GetSelectionMark(hwnd);
6546 case LVM_GETSTRINGWIDTHA:
6547 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
6549 /* case LVM_GETSTRINGWIDTHW: */
6550 /* case LVM_GETSUBITEMRECT: */
6552 case LVM_GETTEXTBKCOLOR:
6553 return LISTVIEW_GetTextBkColor(hwnd);
6555 case LVM_GETTEXTCOLOR:
6556 return LISTVIEW_GetTextColor(hwnd);
6558 /* case LVM_GETTOOLTIPS: */
6560 case LVM_GETTOPINDEX:
6561 return LISTVIEW_GetTopIndex(hwnd);
6563 /* case LVM_GETUNICODEFORMAT: */
6565 case LVM_GETVIEWRECT:
6566 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
6568 /* case LVM_GETWORKAREAS: */
6571 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
6573 case LVM_INSERTCOLUMNA:
6574 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam,
6575 (LPLVCOLUMNA)lParam);
6577 /* case LVM_INSERTCOLUMNW: */
6579 case LVM_INSERTITEMA:
6580 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
6582 /* case LVM_INSERTITEMW: */
6584 case LVM_REDRAWITEMS:
6585 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
6587 /* case LVM_SCROLL: */
6588 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
6590 case LVM_SETBKCOLOR:
6591 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
6593 /* case LVM_SETBKIMAGE: */
6595 case LVM_SETCALLBACKMASK:
6596 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
6598 case LVM_SETCOLUMNA:
6599 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6601 /* case LVM_SETCOLUMNW: */
6602 /* case LVM_SETCOLUMNORDERARRAY: */
6604 case LVM_SETCOLUMNWIDTH:
6605 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
6607 /* case LVM_SETEXTENDEDLISTVIEWSTYLE: */
6608 /* case LVM_SETHOTCURSOR: */
6609 /* case LVM_SETHOTITEM: */
6610 /* case LVM_SETHOVERTIME: */
6611 /* case LVM_SETICONSPACING: */
6613 case LVM_SETIMAGELIST:
6614 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
6617 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
6619 /* case LVM_SETITEMW: */
6621 case LVM_SETITEMCOUNT:
6622 LISTVIEW_SetItemCount(hwnd, (INT)wParam);
6625 case LVM_SETITEMPOSITION:
6626 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
6627 (INT)HIWORD(lParam));
6629 /* case LVM_SETITEMPOSITION: */
6631 case LVM_SETITEMSTATE:
6632 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6634 case LVM_SETITEMTEXTA:
6635 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6637 /* case LVM_SETSELECTIONMARK: */
6639 case LVM_SETTEXTBKCOLOR:
6640 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
6642 case LVM_SETTEXTCOLOR:
6643 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
6645 /* case LVM_SETTOOLTIPS: */
6646 /* case LVM_SETUNICODEFORMAT: */
6647 /* case LVM_SETWORKAREAS: */
6650 return LISTVIEW_SortItems(hwnd, wParam, lParam);
6652 /* case LVM_SUBITEMHITTEST: */
6655 return LISTVIEW_Update(hwnd, (INT)wParam);
6658 /* case WM_COMMAND: */
6661 return LISTVIEW_Create(hwnd, wParam, lParam);
6664 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
6667 return DLGC_WANTTAB | DLGC_WANTARROWS;
6670 return LISTVIEW_GetFont(hwnd);
6673 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
6674 (INT)HIWORD(wParam), (HWND)lParam);
6677 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
6680 return LISTVIEW_KillFocus(hwnd);
6682 case WM_LBUTTONDBLCLK:
6683 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6686 case WM_LBUTTONDOWN:
6687 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6690 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6693 /* case WM_MOUSEMOVE: */
6694 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
6697 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
6700 return LISTVIEW_NCDestroy(hwnd);
6703 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
6705 case WM_NOTIFYFORMAT:
6706 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
6709 return LISTVIEW_Paint(hwnd, (HDC)wParam);
6711 case WM_RBUTTONDBLCLK:
6712 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6715 case WM_RBUTTONDOWN:
6716 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6720 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6724 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
6727 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
6729 /* case WM_SETREDRAW: */
6732 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
6734 case WM_STYLECHANGED:
6735 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
6737 /* case WM_TIMER: */
6740 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
6741 (INT)HIWORD(wParam), (HWND)lParam);
6743 /* case WM_WINDOWPOSCHANGED: */
6744 /* case WM_WININICHANGE: */
6747 if (uMsg >= WM_USER)
6749 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
6753 /* call default window procedure */
6754 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
6762 * Registers the window class.
6770 VOID LISTVIEW_Register(VOID)
6774 if (!GlobalFindAtomA(WC_LISTVIEWA))
6776 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
6777 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
6778 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
6779 wndClass.cbClsExtra = 0;
6780 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
6781 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
6782 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
6783 wndClass.lpszClassName = WC_LISTVIEWA;
6784 RegisterClassA(&wndClass);
6790 * Unregisters the window class.
6798 VOID LISTVIEW_Unregister(VOID)
6800 if (GlobalFindAtomA(WC_LISTVIEWA))
6802 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);