Some more messages.
[wine/multimedia.git] / dlls / comctl32 / listview.c
blob2950b4b6ce3621ae81fbb603c8d8782fdd81cd3a
1 /*
2 * Listview control
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
7 * NOTES
8 * Listview control implementation.
10 * TODO:
11 * 1. No horizontal scrolling when header is larger than the client area.
12 * 2. Drawing optimizations.
13 * 3. Hot item handling.
15 * Notifications:
16 * LISTVIEW_Notify : most notifications from children (editbox and header)
18 * Data structure:
19 * LISTVIEW_SetItemCount : empty stub
21 * Unicode:
22 * LISTVIEW_SetItemW : no unicode support
23 * LISTVIEW_InsertItemW : no unicode support
24 * LISTVIEW_InsertColumnW : no unicode support
25 * LISTVIEW_GetColumnW : no unicode support
26 * LISTVIEW_SetColumnW : no unicode support
28 * Advanced functionality:
29 * LISTVIEW_GetNumberOfWorkAreas : not implemented
30 * LISTVIEW_GetHotCursor : not implemented
31 * LISTVIEW_GetHoverTime : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_EditLabel : REPORT (need to implement a timer)
35 * LISTVIEW_GetColumnOrderArray : not implemented
36 * LISTVIEW_SetColumnOrderArray : not implemented
37 * LISTVIEW_Arrange : empty stub
38 * LISTVIEW_ApproximateViewRect : incomplete
39 * LISTVIEW_Scroll : not implemented
40 * LISTVIEW_RedrawItems : empty stub
41 * LISTVIEW_Update : not completed
44 #include <string.h>
45 #include "winbase.h"
46 #include "commctrl.h"
47 #include "listview.h"
48 #include "debugtools.h"
50 DEFAULT_DEBUG_CHANNEL(listview)
53 * constants
56 /* maximum size of a label */
57 #define DISP_TEXT_SIZE 128
59 /* padding for items in list and small icon display modes */
60 #define WIDTH_PADDING 12
62 /* padding for items in list, report and small icon display modes */
63 #define HEIGHT_PADDING 1
65 /* offset of items in report display mode */
66 #define REPORT_MARGINX 2
68 /* padding for icon in large icon display mode */
69 #define ICON_TOP_PADDING 2
70 #define ICON_BOTTOM_PADDING 2
72 /* padding for label in large icon display mode */
73 #define LABEL_VERT_OFFSET 2
75 /* default label width for items in list and small icon display modes */
76 #define DEFAULT_LABEL_WIDTH 40
78 /* default column width for items in list display mode */
79 #define DEFAULT_COLUMN_WIDTH 96
81 /*
82 * macros
84 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
85 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
86 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
87 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
88 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
89 /* retrieve the number of items in the listview */
90 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
92 /*
93 * forward declarations
95 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
96 static INT LISTVIEW_GetCountPerRow(HWND);
97 static INT LISTVIEW_GetCountPerColumn(HWND);
98 static VOID LISTVIEW_AlignLeft(HWND);
99 static VOID LISTVIEW_AlignTop(HWND);
100 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
101 static VOID LISTVIEW_AddSelection(HWND, INT);
102 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
103 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
104 static INT LISTVIEW_GetItemHeight(HWND);
105 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
106 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
107 static INT LISTVIEW_GetItemWidth(HWND);
108 static INT LISTVIEW_GetLabelWidth(HWND, INT);
109 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
110 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
111 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
112 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
113 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
114 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
115 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
116 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
117 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
118 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
119 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
120 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
121 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
122 static VOID LISTVIEW_UpdateScroll(HWND);
123 static VOID LISTVIEW_SetSelection(HWND, INT);
124 static VOID LISTVIEW_UpdateSize(HWND);
125 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
126 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
127 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
128 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
130 /***
131 * DESCRIPTION:
132 * Update the scrollbars. This functions should be called whenever
133 * the content, size or view changes.
135 * PARAMETER(S):
136 * [I] HWND : window handle
138 * RETURN:
139 * None
141 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
143 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
144 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
145 UINT uView = lStyle & LVS_TYPEMASK;
146 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
147 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
148 SCROLLINFO scrollInfo;
150 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
151 scrollInfo.cbSize = sizeof(SCROLLINFO);
153 if (uView == LVS_LIST)
155 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
156 INT nCountPerPage = LISTVIEW_GetCountPerRow(hwnd) * nCountPerColumn;
157 if (nCountPerPage < GETITEMCOUNT(infoPtr))
159 /* calculate new scrollbar range */
160 INT nHiddenItemCount = GETITEMCOUNT(infoPtr) - nCountPerPage;
161 if (nHiddenItemCount % nCountPerColumn == 0)
163 scrollInfo.nMax = nHiddenItemCount / nCountPerColumn;
165 else
167 scrollInfo.nMax = nHiddenItemCount / nCountPerColumn + 1;
170 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
171 /*scrollInfo.nPage = LISTVIEW_GetCountPerRow(hwnd);*/
172 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
173 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
175 else
177 /* hide scrollbar */
178 if (lStyle & WS_HSCROLL)
180 ShowScrollBar(hwnd, SB_HORZ, FALSE);
184 else if (uView == LVS_REPORT)
186 /* update vertical scrollbar */
187 scrollInfo.nMin = 0;
188 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - LISTVIEW_GetCountPerColumn(hwnd);
189 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
190 /*scrollInfo.nPage = nCountPerColumn;*/
191 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
192 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
194 /* update horizontal scrollbar */
195 /* if (infoPtr->nItemWidth > nListWidth) */
196 /* { */
197 /* scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; */
198 /* SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE); */
199 /* } */
201 /* horizontal scrolling has not been implemented yet! I experienced some
202 problems when performing child window scrolling. */
204 else
206 RECT rcView;
208 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
210 INT nViewWidth = rcView.right - rcView.left;
211 INT nViewHeight = rcView.bottom - rcView.top;
213 if (nViewWidth > nListWidth)
215 INT nHiddenWidth;
216 INT nScrollPosWidth = nListWidth / 10;
218 if (nScrollPosWidth == 0)
220 nScrollPosWidth = 1;
221 nHiddenWidth = nViewWidth - nListWidth;
223 else
225 nHiddenWidth = nViewWidth - nScrollPosWidth * 10;
228 scrollInfo.fMask = SIF_POS;
229 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE)
231 scrollInfo.nPos = 0;
234 if (nHiddenWidth % nScrollPosWidth == 0)
236 scrollInfo.nMax = nHiddenWidth / nScrollPosWidth;
238 else
240 scrollInfo.nMax = nHiddenWidth / nScrollPosWidth + 1;
243 scrollInfo.nMin = 0;
244 /*scrollInfo.nPage = 10;*/
245 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
246 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
248 else
250 if (lStyle & WS_HSCROLL)
252 ShowScrollBar(hwnd, SB_HORZ, FALSE);
256 if (nViewHeight > nListHeight)
258 INT nHiddenHeight;
259 INT nScrollPosHeight = nListHeight / 10;
261 if (nScrollPosHeight == 0)
263 nScrollPosHeight = 1;
264 nHiddenHeight = nViewHeight - nListHeight;
266 else
268 nHiddenHeight = nViewHeight - nScrollPosHeight * 10;
271 scrollInfo.fMask = SIF_POS;
272 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE)
274 scrollInfo.nPos = 0;
277 if (nHiddenHeight % nScrollPosHeight == 0)
279 scrollInfo.nMax = nHiddenHeight / nScrollPosHeight;
281 else
283 scrollInfo.nMax = nHiddenHeight / nScrollPosHeight + 1;
286 scrollInfo.nMin = 0;
287 /*scrollInfo.nPage = 10;*/
288 scrollInfo.fMask = SIF_RANGE | SIF_POS /*| SIF_PAGE*/;
289 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
291 else
293 if (lStyle & WS_VSCROLL)
295 ShowScrollBar(hwnd, SB_VERT, FALSE);
302 /***
303 * DESCRIPTION:
304 * Prints a message for unsupported window styles.
305 * A kind of TODO list for window styles.
307 * PARAMETER(S):
308 * [I] LONG : window style
310 * RETURN:
311 * None
313 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
315 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
317 FIXME(" LVS_EDITLABELS\n");
320 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
322 FIXME(" LVS_NOLABELWRAP\n");
325 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
327 FIXME(" LVS_NOSCROLL\n");
330 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
332 FIXME(" LVS_NOSORTHEADER\n");
335 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
337 FIXME(" LVS_OWNERDRAWFIXED\n");
340 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
342 FIXME(" LVS_SHAREIMAGELISTS\n");
345 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
347 FIXME(" LVS_SORTASCENDING\n");
350 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
352 FIXME(" LVS_SORTDESCENDING\n");
356 /***
357 * DESCRIPTION:
358 * Aligns the items with the top edge of the window.
360 * PARAMETER(S):
361 * [I] HWND : window handle
363 * RETURN:
364 * None
366 static VOID LISTVIEW_AlignTop(HWND hwnd)
368 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
369 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
370 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
371 POINT ptItem;
372 RECT rcView;
373 INT i;
375 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
377 ZeroMemory(&ptItem, sizeof(POINT));
378 ZeroMemory(&rcView, sizeof(RECT));
380 if (nListWidth > infoPtr->nItemWidth)
382 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
384 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
386 ptItem.x = 0;
387 ptItem.y += infoPtr->nItemHeight;
390 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
391 ptItem.x += infoPtr->nItemWidth;
392 rcView.right = max(rcView.right, ptItem.x);
395 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
397 else
399 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
401 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
402 ptItem.y += infoPtr->nItemHeight;
405 rcView.right = infoPtr->nItemWidth;
406 rcView.bottom = ptItem.y;
409 LISTVIEW_SetViewRect(hwnd, &rcView);
413 /***
414 * DESCRIPTION:
415 * Aligns the items with the left edge of the window.
417 * PARAMETER(S):
418 * [I] HWND : window handle
420 * RETURN:
421 * None
423 static VOID LISTVIEW_AlignLeft(HWND hwnd)
425 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
426 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
427 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
428 POINT ptItem;
429 RECT rcView;
430 INT i;
432 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
434 ZeroMemory(&ptItem, sizeof(POINT));
435 ZeroMemory(&rcView, sizeof(RECT));
437 if (nListHeight > infoPtr->nItemHeight)
439 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
441 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
443 ptItem.y = 0;
444 ptItem.x += infoPtr->nItemWidth;
447 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
448 ptItem.y += infoPtr->nItemHeight;
449 rcView.bottom = max(rcView.bottom, ptItem.y);
452 rcView.right = ptItem.x + infoPtr->nItemWidth;
454 else
456 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
458 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
459 ptItem.x += infoPtr->nItemWidth;
462 rcView.bottom = infoPtr->nItemHeight;
463 rcView.right = ptItem.x;
466 LISTVIEW_SetViewRect(hwnd, &rcView);
470 /***
471 * DESCRIPTION:
472 * Set the bounding rectangle of all the items.
474 * PARAMETER(S):
475 * [I] HWND : window handle
476 * [I] LPRECT : bounding rectangle
478 * RETURN:
479 * SUCCESS : TRUE
480 * FAILURE : FALSE
482 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
484 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
485 BOOL bResult = FALSE;
487 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
488 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
490 if (lprcView != NULL)
492 bResult = TRUE;
493 infoPtr->rcView.left = lprcView->left;
494 infoPtr->rcView.top = lprcView->top;
495 infoPtr->rcView.right = lprcView->right;
496 infoPtr->rcView.bottom = lprcView->bottom;
499 return bResult;
502 /***
503 * DESCRIPTION:
504 * Retrieves the bounding rectangle of all the items.
506 * PARAMETER(S):
507 * [I] HWND : window handle
508 * [O] LPRECT : bounding rectangle
510 * RETURN:
511 * SUCCESS : TRUE
512 * FAILURE : FALSE
514 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
516 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
517 BOOL bResult = FALSE;
518 POINT ptOrigin;
520 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
522 if (lprcView != NULL)
524 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
525 if (bResult != FALSE)
527 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
528 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
529 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
530 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
533 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
534 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
537 return bResult;
540 /***
541 * DESCRIPTION:
542 * Retrieves the subitem pointer associated with the subitem index.
544 * PARAMETER(S):
545 * [I] HDPA : DPA handle for a specific item
546 * [I] INT : index of subitem
548 * RETURN:
549 * SUCCESS : subitem pointer
550 * FAILURE : NULL
552 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
553 INT nSubItem)
555 LISTVIEW_SUBITEM *lpSubItem;
556 INT i;
558 for (i = 1; i < hdpaSubItems->nItemCount; i++)
560 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
561 if (lpSubItem != NULL)
563 if (lpSubItem->iSubItem == nSubItem)
565 return lpSubItem;
570 return NULL;
573 /***
574 * DESCRIPTION:
575 * Calculates the width of an item.
577 * PARAMETER(S):
578 * [I] HWND : window handle
579 * [I] LONG : window style
581 * RETURN:
582 * Returns item width.
584 static INT LISTVIEW_GetItemWidth(HWND hwnd)
586 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
587 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
588 INT nHeaderItemCount;
589 RECT rcHeaderItem;
590 INT nItemWidth = 0;
591 INT nLabelWidth;
592 INT i;
594 TRACE("(hwnd=%x)\n", hwnd);
596 if (uView == LVS_ICON)
598 nItemWidth = infoPtr->iconSpacing.cx;
600 else if (uView == LVS_REPORT)
602 /* calculate width of header */
603 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
604 for (i = 0; i < nHeaderItemCount; i++)
606 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
608 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
612 else
614 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
616 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
617 nItemWidth = max(nItemWidth, nLabelWidth);
620 /* default label size */
621 if (GETITEMCOUNT(infoPtr) == 0)
623 nItemWidth = DEFAULT_COLUMN_WIDTH;
625 else
627 if (nItemWidth == 0)
629 nItemWidth = DEFAULT_LABEL_WIDTH;
631 else
633 /* add padding */
634 nItemWidth += WIDTH_PADDING;
636 if (infoPtr->himlSmall != NULL)
638 nItemWidth += infoPtr->iconSize.cx;
641 if (infoPtr->himlState != NULL)
643 nItemWidth += infoPtr->iconSize.cx;
649 return nItemWidth;
652 /***
653 * DESCRIPTION:
654 * Calculates the height of an item.
656 * PARAMETER(S):
657 * [I] HWND : window handle
658 * [I] LONG : window style
660 * RETURN:
661 * Returns item height.
663 static INT LISTVIEW_GetItemHeight(HWND hwnd)
665 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
666 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
667 INT nItemHeight = 0;
669 if (uView == LVS_ICON)
671 nItemHeight = infoPtr->iconSpacing.cy;
673 else
675 TEXTMETRICA tm;
676 HDC hdc = GetDC(hwnd);
677 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
678 GetTextMetricsA(hdc, &tm);
679 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
680 SelectObject(hdc, hOldFont);
681 ReleaseDC(hwnd, hdc);
684 return nItemHeight;
687 /***
688 * DESCRIPTION:
689 * Adds a block of selections.
691 * PARAMETER(S):
692 * [I] HWND : window handle
693 * [I] INT : item index
695 * RETURN:
696 * None
698 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
700 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
701 INT nFirst = min(infoPtr->nSelectionMark, nItem);
702 INT nLast = max(infoPtr->nSelectionMark, nItem);
703 LVITEMA lvItem;
704 INT i;
706 lvItem.state = LVIS_SELECTED;
707 lvItem.stateMask= LVIS_SELECTED;
709 for (i = nFirst; i <= nLast; i++)
711 ListView_SetItemState(hwnd, i, &lvItem);
714 LISTVIEW_SetItemFocus(hwnd, nItem);
715 infoPtr->nSelectionMark = nItem;
718 /***
719 * DESCRIPTION:
720 * Adds a single selection.
722 * PARAMETER(S):
723 * [I] HWND : window handle
724 * [I] INT : item index
726 * RETURN:
727 * None
729 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
731 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
732 LVITEMA lvItem;
734 lvItem.state = LVIS_SELECTED;
735 lvItem.stateMask= LVIS_SELECTED;
737 ListView_SetItemState(hwnd, nItem, &lvItem);
739 LISTVIEW_SetItemFocus(hwnd, nItem);
740 infoPtr->nSelectionMark = nItem;
743 /***
744 * DESCRIPTION:
745 * Selects or unselects an item.
747 * PARAMETER(S):
748 * [I] HWND : window handle
749 * [I] INT : item index
751 * RETURN:
752 * SELECT: TRUE
753 * UNSELECT : FALSE
755 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
757 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
758 BOOL bResult;
759 LVITEMA lvItem;
761 lvItem.stateMask= LVIS_SELECTED;
763 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
765 lvItem.state = 0;
766 ListView_SetItemState(hwnd, nItem, &lvItem);
767 bResult = FALSE;
769 else
771 lvItem.state = LVIS_SELECTED;
772 ListView_SetItemState(hwnd, nItem, &lvItem);
773 bResult = TRUE;
776 LISTVIEW_SetItemFocus(hwnd, nItem);
777 infoPtr->nSelectionMark = nItem;
779 return bResult;
782 /***
783 * DESCRIPTION:
784 * Selects items based on view coorddiantes.
786 * PARAMETER(S):
787 * [I] HWND : window handle
788 * [I] RECT : selection rectangle
790 * RETURN:
791 * None
793 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
795 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
796 LVITEMA lvItem;
797 POINT ptItem;
798 INT i;
800 lvItem.stateMask = LVIS_SELECTED;
802 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
804 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
805 if (PtInRect(&rcSelRect, ptItem) != FALSE)
807 lvItem.state = LVIS_SELECTED;
809 else
811 lvItem.state = 0;
814 ListView_SetItemState(hwnd, i, &lvItem);
818 /***
819 * DESCRIPTION:
820 * Sets a single group selection.
822 * PARAMETER(S):
823 * [I] HWND : window handle
824 * [I] INT : item index
826 * RETURN:
827 * None
829 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
831 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
832 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
833 LVITEMA lvItem;
835 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
837 INT i;
838 INT nFirst = min(infoPtr->nSelectionMark, nItem);
839 INT nLast = max(infoPtr->nSelectionMark, nItem);
840 lvItem.stateMask = LVIS_SELECTED;
842 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
844 if ((i < nFirst) || (i > nLast))
846 lvItem.state = 0;
848 else
850 lvItem.state = LVIS_SELECTED;
853 ListView_SetItemState(hwnd, i, &lvItem);
856 else
858 POINT ptItem;
859 POINT ptSelMark;
860 RECT rcSel;
861 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
862 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
863 rcSel.left = min(ptSelMark.x, ptItem.x);
864 rcSel.top = min(ptSelMark.y, ptItem.y);
865 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
866 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
867 LISTVIEW_SetSelectionRect(hwnd, rcSel);
870 LISTVIEW_SetItemFocus(hwnd, nItem);
873 /***
874 * DESCRIPTION:
875 * Manages the item focus.
877 * PARAMETER(S):
878 * [I] HWND : window handle
879 * [I] INT : item index
881 * RETURN:
882 * TRUE : focused item changed
883 * FALSE : focused item has NOT changed
885 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
887 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
888 BOOL bResult = FALSE;
889 LVITEMA lvItem;
891 if (infoPtr->nFocusedItem != nItem)
893 bResult = TRUE;
894 ZeroMemory(&lvItem, sizeof(LVITEMA));
895 lvItem.stateMask = LVIS_FOCUSED;
896 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
898 lvItem.state = LVIS_FOCUSED;
899 lvItem.stateMask = LVIS_FOCUSED;
900 ListView_SetItemState(hwnd, nItem, &lvItem);
902 infoPtr->nFocusedItem = nItem;
903 ListView_EnsureVisible(hwnd, nItem, FALSE);
906 return bResult;
909 /***
910 * DESCRIPTION:
911 * Sets a single selection.
913 * PARAMETER(S):
914 * [I] HWND : window handle
915 * [I] INT : item index
917 * RETURN:
918 * None
920 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
922 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
923 LVITEMA lvItem;
925 if (nItem > 0)
927 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
930 if (nItem < GETITEMCOUNT(infoPtr))
932 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
935 ZeroMemory(&lvItem, sizeof(LVITEMA));
936 lvItem.stateMask = LVIS_FOCUSED;
937 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
939 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
940 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
941 ListView_SetItemState(hwnd, nItem, &lvItem);
943 infoPtr->nFocusedItem = nItem;
944 infoPtr->nSelectionMark = nItem;
947 /***
948 * DESCRIPTION:
949 * Set selection(s) with keyboard.
951 * PARAMETER(S):
952 * [I] HWND : window handle
953 * [I] INT : item index
955 * RETURN:
956 * SUCCESS : TRUE (needs to be repainted)
957 * FAILURE : FALSE (nothing has changed)
959 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
961 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
962 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
963 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
964 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
965 BOOL bResult = FALSE;
967 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
969 if (lStyle & LVS_SINGLESEL)
971 bResult = TRUE;
972 LISTVIEW_SetSelection(hwnd, nItem);
973 ListView_EnsureVisible(hwnd, nItem, FALSE);
975 else
977 if (wShift)
979 bResult = TRUE;
980 LISTVIEW_SetGroupSelection(hwnd, nItem);
982 else if (wCtrl)
984 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
986 else
988 bResult = TRUE;
989 LISTVIEW_SetSelection(hwnd, nItem);
990 ListView_EnsureVisible(hwnd, nItem, FALSE);
995 return bResult;
998 /***
999 * DESCRIPTION:
1000 * Selects an item based on coordinates.
1002 * PARAMETER(S):
1003 * [I] HWND : window handle
1004 * [I] POINT : mouse click ccordinates
1006 * RETURN:
1007 * SUCCESS : item index
1008 * FAILURE : -1
1010 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1012 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1013 RECT rcItem;
1014 INT i;
1016 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1018 rcItem.left = LVIR_SELECTBOUNDS;
1019 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1021 if (PtInRect(&rcItem, pt) != FALSE)
1023 return i;
1028 return -1;
1031 /***
1032 * DESCRIPTION:
1033 * Removes all selection states.
1035 * PARAMETER(S):
1036 * [I] HWND : window handle
1037 * [I] INT : item index
1039 * RETURN:
1040 * SUCCCESS : TRUE
1041 * FAILURE : FALSE
1043 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1045 LVITEMA lvItem;
1046 INT i;
1048 lvItem.state = 0;
1049 lvItem.stateMask = LVIS_SELECTED;
1051 for (i = nFirst; i <= nLast; i++)
1053 ListView_SetItemState(hwnd, i, &lvItem);
1057 /***
1058 * DESCRIPTION:
1059 * Removes a column.
1061 * PARAMETER(S):
1062 * [IO] HDPA : dynamic pointer array handle
1063 * [I] INT : column index (subitem index)
1065 * RETURN:
1066 * SUCCCESS : TRUE
1067 * FAILURE : FALSE
1069 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1071 BOOL bResult = TRUE;
1072 HDPA hdpaSubItems;
1073 INT i;
1075 for (i = 0; i < hdpaItems->nItemCount; i++)
1077 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1078 if (hdpaSubItems != NULL)
1080 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1082 bResult = FALSE;
1087 return bResult;
1090 /***
1091 * DESCRIPTION:
1092 * Removes a subitem at a given position.
1094 * PARAMETER(S):
1095 * [IO] HDPA : dynamic pointer array handle
1096 * [I] INT : subitem index
1098 * RETURN:
1099 * SUCCCESS : TRUE
1100 * FAILURE : FALSE
1102 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1104 LISTVIEW_SUBITEM *lpSubItem;
1105 INT i;
1107 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1109 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1110 if (lpSubItem != NULL)
1112 if (lpSubItem->iSubItem == nSubItem)
1114 /* free string */
1115 if ((lpSubItem->pszText != NULL) &&
1116 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1118 COMCTL32_Free(lpSubItem->pszText);
1121 /* free item */
1122 COMCTL32_Free(lpSubItem);
1124 /* free dpa memory */
1125 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1127 return FALSE;
1130 else if (lpSubItem->iSubItem > nSubItem)
1132 return TRUE;
1137 return TRUE;
1140 /***
1141 * DESCRIPTION:
1142 * Compares the item information.
1144 * PARAMETER(S):
1145 * [I] LISTVIEW_ITEM *: destination item
1146 * [I] LPLVITEM : source item
1148 * RETURN:
1149 * SUCCCESS : TRUE (EQUAL)
1150 * FAILURE : FALSE (NOT EQUAL)
1152 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1154 UINT uChanged = 0;
1156 if ((lpItem != NULL) && (lpLVItem != NULL))
1158 if (lpLVItem->mask & LVIF_STATE)
1160 if ((lpItem->state & lpLVItem->stateMask) !=
1161 (lpLVItem->state & lpLVItem->stateMask))
1163 uChanged |= LVIF_STATE;
1167 if (lpLVItem->mask & LVIF_IMAGE)
1169 if (lpItem->iImage != lpLVItem->iImage)
1171 uChanged |= LVIF_IMAGE;
1175 if (lpLVItem->mask & LVIF_PARAM)
1177 if (lpItem->lParam != lpLVItem->lParam)
1179 uChanged |= LVIF_PARAM;
1183 if (lpLVItem->mask & LVIF_INDENT)
1185 if (lpItem->iIndent != lpLVItem->iIndent)
1187 uChanged |= LVIF_INDENT;
1191 if (lpLVItem->mask & LVIF_TEXT)
1193 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1195 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1197 uChanged |= LVIF_TEXT;
1200 else
1202 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1204 uChanged |= LVIF_TEXT;
1206 else
1208 if (lpLVItem->pszText)
1210 if (lpItem->pszText)
1212 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1214 uChanged |= LVIF_TEXT;
1217 else
1219 uChanged |= LVIF_TEXT;
1222 else
1224 if (lpItem->pszText)
1226 uChanged |= LVIF_TEXT;
1233 return uChanged;
1236 /***
1237 * DESCRIPTION:
1238 * Initializes item attributes.
1240 * PARAMETER(S):
1241 * [I] HWND : window handle
1242 * [O] LISTVIEW_ITEM *: destination item
1243 * [I] LPLVITEM : source item
1245 * RETURN:
1246 * SUCCCESS : TRUE
1247 * FAILURE : FALSE
1249 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1250 LPLVITEMA lpLVItem)
1252 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1253 BOOL bResult = FALSE;
1255 if ((lpItem != NULL) && (lpLVItem != NULL))
1257 bResult = TRUE;
1259 if (lpLVItem->mask & LVIF_STATE)
1261 lpItem->state &= ~lpLVItem->stateMask;
1262 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1265 if (lpLVItem->mask & LVIF_IMAGE)
1267 lpItem->iImage = lpLVItem->iImage;
1270 if (lpLVItem->mask & LVIF_PARAM)
1272 lpItem->lParam = lpLVItem->lParam;
1275 if (lpLVItem->mask & LVIF_INDENT)
1277 lpItem->iIndent = lpLVItem->iIndent;
1280 if (lpLVItem->mask & LVIF_TEXT)
1282 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1284 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1286 return FALSE;
1289 if ((lpItem->pszText != NULL) &&
1290 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1292 COMCTL32_Free(lpItem->pszText);
1295 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1297 else
1299 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1301 lpItem->pszText = NULL;
1304 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1309 return bResult;
1312 /***
1313 * DESCRIPTION:
1314 * Initializes subitem attributes.
1316 * NOTE: The documentation specifies that the operation fails if the user
1317 * tries to set the indent of a subitem.
1319 * PARAMETER(S):
1320 * [I] HWND : window handle
1321 * [O] LISTVIEW_SUBITEM *: destination subitem
1322 * [I] LPLVITEM : source subitem
1324 * RETURN:
1325 * SUCCCESS : TRUE
1326 * FAILURE : FALSE
1328 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1329 LPLVITEMA lpLVItem)
1331 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1332 BOOL bResult = FALSE;
1334 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1336 if (!(lpLVItem->mask & LVIF_INDENT))
1338 bResult = TRUE;
1339 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1341 lpSubItem->iSubItem = lpLVItem->iSubItem;
1343 if (lpLVItem->mask & LVIF_IMAGE)
1345 lpSubItem->iImage = lpLVItem->iImage;
1348 if (lpLVItem->mask & LVIF_TEXT)
1350 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1352 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1354 return FALSE;
1357 if ((lpSubItem->pszText != NULL) &&
1358 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1360 COMCTL32_Free(lpSubItem->pszText);
1363 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1365 else
1367 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1369 lpSubItem->pszText = NULL;
1372 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1378 return bResult;
1381 /***
1382 * DESCRIPTION:
1383 * Adds a subitem at a given position (column index).
1385 * PARAMETER(S):
1386 * [I] HWND : window handle
1387 * [I] LPLVITEM : new subitem atttributes
1389 * RETURN:
1390 * SUCCESS : TRUE
1391 * FAILURE : FALSE
1393 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1395 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1396 LISTVIEW_SUBITEM *lpSubItem = NULL;
1397 BOOL bResult = FALSE;
1398 HDPA hdpaSubItems;
1399 INT nPosition, nItem;
1401 if (lpLVItem != NULL)
1403 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1404 if (hdpaSubItems != NULL)
1406 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1407 if (lpSubItem != NULL)
1409 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1411 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1412 lpSubItem->iSubItem);
1413 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1414 if (nItem != -1)
1416 bResult = TRUE;
1423 /* cleanup if unsuccessful */
1424 if ((bResult == FALSE) && (lpSubItem != NULL))
1426 COMCTL32_Free(lpSubItem);
1429 return bResult;
1432 /***
1433 * DESCRIPTION:
1434 * Finds the dpa insert position (array index).
1436 * PARAMETER(S):
1437 * [I] HWND : window handle
1438 * [I] INT : subitem index
1440 * RETURN:
1441 * SUCCESS : TRUE
1442 * FAILURE : FALSE
1444 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1446 LISTVIEW_SUBITEM *lpSubItem;
1447 INT i;
1449 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1451 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1452 if (lpSubItem != NULL)
1454 if (lpSubItem->iSubItem > nSubItem)
1456 return i;
1461 return hdpaSubItems->nItemCount;
1464 /***
1465 * DESCRIPTION:
1466 * Retrieves a listview subitem at a given position (column index).
1468 * PARAMETER(S):
1469 * [I] HWND : window handle
1470 * [I] INT : subitem index
1472 * RETURN:
1473 * SUCCESS : TRUE
1474 * FAILURE : FALSE
1476 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1478 LISTVIEW_SUBITEM *lpSubItem;
1479 INT i;
1481 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1483 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1484 if (lpSubItem != NULL)
1486 if (lpSubItem->iSubItem == nSubItem)
1488 return lpSubItem;
1490 else if (lpSubItem->iSubItem > nSubItem)
1492 return NULL;
1497 return NULL;
1500 /***
1501 * DESCRIPTION:
1502 * Sets item attributes.
1504 * PARAMETER(S):
1505 * [I] HWND : window handle
1506 * [I] LPLVITEM : new item atttributes
1508 * RETURN:
1509 * SUCCESS : TRUE
1510 * FAILURE : FALSE
1512 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1514 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1515 BOOL bResult = FALSE;
1516 HDPA hdpaSubItems;
1517 LISTVIEW_ITEM *lpItem;
1518 NMLISTVIEW nmlv;
1519 UINT uChanged;
1520 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1522 if (lpLVItem != NULL)
1524 if (lpLVItem->iSubItem == 0)
1526 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1527 if (hdpaSubItems != NULL)
1529 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1530 if (lpItem != NULL)
1532 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1533 nmlv.hdr.hwndFrom = hwnd;
1534 nmlv.hdr.idFrom = lCtrlId;
1535 nmlv.hdr.code = LVN_ITEMCHANGING;
1536 nmlv.lParam = lpItem->lParam;
1537 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1538 if (uChanged != 0)
1540 if (uChanged & LVIF_STATE)
1542 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1543 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1546 nmlv.uChanged = uChanged;
1547 nmlv.iItem = lpLVItem->iItem;
1548 nmlv.lParam = lpItem->lParam;
1549 /* send LVN_ITEMCHANGING notification */
1550 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1552 /* copy information */
1553 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1555 /* send LVN_ITEMCHANGED notification */
1556 nmlv.hdr.code = LVN_ITEMCHANGED;
1557 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1559 else
1561 bResult = TRUE;
1564 InvalidateRect(hwnd, NULL, FALSE);
1570 return bResult;
1573 /***
1574 * DESCRIPTION:
1575 * Sets subitem attributes.
1577 * PARAMETER(S):
1578 * [I] HWND : window handle
1579 * [I] LPLVITEM : new subitem atttributes
1581 * RETURN:
1582 * SUCCESS : TRUE
1583 * FAILURE : FALSE
1585 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1587 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1588 BOOL bResult = FALSE;
1589 HDPA hdpaSubItems;
1590 LISTVIEW_SUBITEM *lpSubItem;
1592 if (lpLVItem != NULL)
1594 if (lpLVItem->iSubItem > 0)
1596 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1597 if (hdpaSubItems != NULL)
1599 /* set subitem only if column is present */
1600 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
1602 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
1603 if (lpSubItem != NULL)
1605 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
1607 else
1609 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
1612 InvalidateRect(hwnd, NULL, FALSE);
1618 return bResult;
1621 /***
1622 * DESCRIPTION:
1623 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1625 * PARAMETER(S):
1626 * [I] HWND : window handle
1628 * RETURN:
1629 * item index
1631 static INT LISTVIEW_GetTopIndex(HWND hwnd)
1633 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1634 UINT uView = lStyle & LVS_TYPEMASK;
1635 INT nItem = 0;
1636 SCROLLINFO scrollInfo;
1638 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
1639 scrollInfo.cbSize = sizeof(SCROLLINFO);
1640 scrollInfo.fMask = SIF_POS;
1642 if (uView == LVS_LIST)
1644 if (lStyle & WS_HSCROLL)
1646 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
1648 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
1652 else if (uView == LVS_REPORT)
1654 if (lStyle & WS_VSCROLL)
1656 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
1658 nItem = scrollInfo.nPos;
1663 return nItem;
1666 /***
1667 * DESCRIPTION:
1668 * Draws a subitem.
1670 * PARAMETER(S):
1671 * [I] HWND : window handle
1672 * [I] HDC : device context handle
1673 * [I] INT : item index
1674 * [I] INT : subitem index
1675 * [I] RECT * : clipping rectangle
1677 * RETURN:
1678 * None
1680 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
1681 RECT rcItem)
1683 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1684 CHAR szDispText[DISP_TEXT_SIZE];
1685 LVITEMA lvItem;
1687 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd, hdc,
1688 nItem, nSubItem);
1690 /* get information needed for drawing the item */
1691 ZeroMemory(&lvItem, sizeof(LVITEMA));
1692 lvItem.mask = LVIF_TEXT;
1693 lvItem.iItem = nItem;
1694 lvItem.iSubItem = nSubItem;
1695 lvItem.cchTextMax = DISP_TEXT_SIZE;
1696 lvItem.pszText = szDispText;
1697 ListView_GetItemA(hwnd, &lvItem);
1699 /* set item colors */
1700 SetBkColor(hdc, infoPtr->clrTextBk);
1701 SetTextColor(hdc, infoPtr->clrText);
1703 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1704 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1708 /***
1709 * DESCRIPTION:
1710 * Draws an item.
1712 * PARAMETER(S):
1713 * [I] HWND : window handle
1714 * [I] HDC : device context handle
1715 * [I] INT : item index
1716 * [I] RECT * : clipping rectangle
1718 * RETURN:
1719 * None
1721 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1723 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1724 CHAR szDispText[DISP_TEXT_SIZE];
1725 INT nLabelWidth;
1726 LVITEMA lvItem;
1727 INT nMixMode;
1728 DWORD dwBkColor;
1729 DWORD dwTextColor;
1731 TRACE("(hwnd=%x, hdc=%x, nItem=%d\n", hwnd, hdc, nItem);
1733 /* get information needed for drawing the item */
1734 ZeroMemory(&lvItem, sizeof(LVITEMA));
1735 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
1736 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
1737 lvItem.iItem = nItem;
1738 lvItem.iSubItem = 0;
1739 lvItem.cchTextMax = DISP_TEXT_SIZE;
1740 lvItem.pszText = szDispText;
1741 ListView_GetItemA(hwnd, &lvItem);
1743 /* state icons */
1744 if (infoPtr->himlState != NULL)
1746 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
1747 if (uStateImage != 0)
1749 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
1750 rcItem.top, ILD_NORMAL);
1753 rcItem.left += infoPtr->iconSize.cx;
1756 /* small icons */
1757 if (infoPtr->himlSmall != NULL)
1759 if (lvItem.state & LVIS_SELECTED)
1761 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1762 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1763 rcItem.top, ILD_SELECTED);
1765 else
1767 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
1768 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
1769 rcItem.top, ILD_NORMAL);
1772 rcItem.left += infoPtr->iconSize.cx;
1775 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
1777 /* set item colors */
1778 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1779 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1780 /* set raster mode */
1781 nMixMode = SetROP2(hdc, R2_XORPEN);
1783 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
1784 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
1786 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
1787 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
1788 /* set raster mode */
1789 nMixMode = SetROP2(hdc, R2_COPYPEN);
1791 else
1793 /* set item colors */
1794 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
1795 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
1796 /* set raster mode */
1797 nMixMode = SetROP2(hdc, R2_COPYPEN);
1800 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1801 if (rcItem.left + nLabelWidth < rcItem.right)
1803 rcItem.right = rcItem.left + nLabelWidth;
1806 /* draw label */
1807 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1808 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1810 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
1812 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1815 if (nMixMode != 0)
1817 SetROP2(hdc, R2_COPYPEN);
1818 SetBkColor(hdc, infoPtr->clrTextBk);
1819 SetTextColor(hdc, infoPtr->clrText);
1823 /***
1824 * DESCRIPTION:
1825 * Draws an item when in large icon display mode.
1827 * PARAMETER(S):
1828 * [I] HWND : window handle
1829 * [I] HDC : device context handle
1830 * [I] LISTVIEW_ITEM * : item
1831 * [I] INT : item index
1832 * [I] RECT * : clipping rectangle
1834 * RETURN:
1835 * None
1837 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
1839 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1840 CHAR szDispText[DISP_TEXT_SIZE];
1841 INT nDrawPosX = rcItem.left;
1842 INT nLabelWidth;
1843 TEXTMETRICA tm;
1844 LVITEMA lvItem;
1846 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1847 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
1848 rcItem.bottom);
1850 /* get information needed for drawing the item */
1851 ZeroMemory(&lvItem, sizeof(LVITEMA));
1852 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
1853 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1854 lvItem.iItem = nItem;
1855 lvItem.iSubItem = 0;
1856 lvItem.cchTextMax = DISP_TEXT_SIZE;
1857 lvItem.pszText = szDispText;
1858 ListView_GetItemA(hwnd, &lvItem);
1860 if (lvItem.state & LVIS_SELECTED)
1862 /* set item colors */
1863 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1864 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1865 /* set raster mode */
1866 SetROP2(hdc, R2_XORPEN);
1868 else
1870 /* set item colors */
1871 SetBkColor(hdc, infoPtr->clrTextBk);
1872 SetTextColor(hdc, infoPtr->clrText);
1873 /* set raster mode */
1874 SetROP2(hdc, R2_COPYPEN);
1877 if (infoPtr->himlNormal != NULL)
1879 rcItem.top += ICON_TOP_PADDING;
1880 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
1881 if (lvItem.state & LVIS_SELECTED)
1883 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1884 rcItem.top, ILD_SELECTED);
1886 else
1888 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
1889 rcItem.top, ILD_NORMAL);
1893 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
1894 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
1895 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
1896 if (nDrawPosX > 1)
1898 rcItem.left += nDrawPosX / 2;
1899 rcItem.right = rcItem.left + nLabelWidth;
1901 else
1903 rcItem.left += 1;
1904 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
1907 /* draw label */
1908 GetTextMetricsA(hdc, &tm);
1909 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
1910 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
1911 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
1913 if (lvItem.state & LVIS_FOCUSED)
1915 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
1919 /***
1920 * DESCRIPTION:
1921 * Draws listview items when in report display mode.
1923 * PARAMETER(S):
1924 * [I] HWND : window handle
1925 * [I] HDC : device context handle
1927 * RETURN:
1928 * None
1930 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
1932 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
1933 INT nDrawPosY = infoPtr->rcList.top;
1934 INT nColumnCount;
1935 RECT rcItem;
1936 INT j;
1937 INT nItem;
1938 INT nLast;
1940 nItem = ListView_GetTopIndex(hwnd);
1942 /* add 1 for displaying a partial item at the bottom */
1943 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
1944 nLast = min(nLast, GETITEMCOUNT(infoPtr));
1945 for (; nItem < nLast; nItem++)
1947 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
1948 for (j = 0; j < nColumnCount; j++)
1950 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
1951 rcItem.left += REPORT_MARGINX;
1952 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
1953 rcItem.top = nDrawPosY;
1954 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
1955 if (j == 0)
1957 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
1959 else
1961 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
1965 nDrawPosY += infoPtr->nItemHeight;
1969 /***
1970 * DESCRIPTION:
1971 * Retrieves the number of items that can fit vertically in the client area.
1973 * PARAMETER(S):
1974 * [I] HWND : window handle
1976 * RETURN:
1977 * Number of items per row.
1979 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
1981 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
1982 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1983 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
1984 INT nCountPerRow = 1;
1986 if (nListWidth > 0)
1988 if (uView == LVS_REPORT)
1990 nCountPerRow = 1;
1992 else
1994 nCountPerRow = nListWidth / infoPtr->nItemWidth;
1995 if (nCountPerRow == 0)
1997 nCountPerRow = 1;
2002 return nCountPerRow;
2005 /***
2006 * DESCRIPTION:
2007 * Retrieves the number of items that can fit horizontally in the client
2008 * area.
2010 * PARAMETER(S):
2011 * [I] HWND : window handle
2013 * RETURN:
2014 * Number of items per column.
2016 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2018 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2019 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2020 INT nCountPerColumn = 1;
2022 if (nListHeight > 0)
2024 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2025 if (nCountPerColumn == 0)
2027 nCountPerColumn = 1;
2031 return nCountPerColumn;
2034 /***
2035 * DESCRIPTION:
2036 * Retrieves the number of columns needed to display all the items when in
2037 * list display mode.
2039 * PARAMETER(S):
2040 * [I] HWND : window handle
2042 * RETURN:
2043 * Number of columns.
2045 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2047 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2048 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2049 INT nColumnCount = 0;
2051 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2053 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2055 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2057 else
2059 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2063 return nColumnCount;
2067 /***
2068 * DESCRIPTION:
2069 * Draws listview items when in list display mode.
2071 * PARAMETER(S):
2072 * [I] HWND : window handle
2073 * [I] HDC : device context handle
2075 * RETURN:
2076 * None
2078 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2080 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2081 RECT rcItem;
2082 INT i, j;
2083 INT nItem;
2084 INT nColumnCount;
2085 INT nCountPerColumn;
2087 /* get number of fully visible columns */
2088 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2089 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2090 nItem = ListView_GetTopIndex(hwnd);
2092 for (i = 0; i < nColumnCount; i++)
2094 for (j = 0; j < nCountPerColumn; j++, nItem++)
2096 if (nItem >= GETITEMCOUNT(infoPtr))
2097 return;
2099 rcItem.top = j * infoPtr->nItemHeight;
2100 rcItem.left = i * infoPtr->nItemWidth;
2101 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2102 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2103 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2108 /***
2109 * DESCRIPTION:
2110 * Draws listview items when in icon or small icon display mode.
2112 * PARAMETER(S):
2113 * [I] HWND : window handle
2114 * [I] HDC : device context handle
2116 * RETURN:
2117 * None
2119 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2121 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2122 POINT ptPosition;
2123 POINT ptOrigin;
2124 RECT rcItem;
2125 INT i;
2127 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2128 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2130 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2131 ptPosition.x += ptOrigin.x;
2132 ptPosition.y += ptOrigin.y;
2134 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2136 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2138 if (ptPosition.y < infoPtr->rcList.bottom)
2140 if (ptPosition.x < infoPtr->rcList.right)
2142 rcItem.top = ptPosition.y;
2143 rcItem.left = ptPosition.x;
2144 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2145 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2146 if (bSmall == FALSE)
2148 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2150 else
2152 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2161 /***
2162 * DESCRIPTION:
2163 * Draws listview items.
2165 * PARAMETER(S):
2166 * [I] HWND : window handle
2167 * [I] HDC : device context handle
2169 * RETURN:
2170 * NoneX
2172 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2174 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2175 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2176 HFONT hOldFont;
2177 HPEN hPen, hOldPen;
2179 /* select font */
2180 hOldFont = SelectObject(hdc, infoPtr->hFont);
2182 /* select the doted pen (for drawing the focus box) */
2183 hPen = CreatePen(PS_DOT, 1, 0);
2184 hOldPen = SelectObject(hdc, hPen);
2186 /* select transparent brush (for drawing the focus box) */
2187 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2189 if (uView == LVS_LIST)
2191 LISTVIEW_RefreshList(hwnd, hdc);
2193 else if (uView == LVS_REPORT)
2195 LISTVIEW_RefreshReport(hwnd, hdc);
2197 else if (uView == LVS_SMALLICON)
2199 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2201 else if (uView == LVS_ICON)
2203 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2206 /* unselect objects */
2207 SelectObject(hdc, hOldFont);
2208 SelectObject(hdc, hOldPen);
2210 /* delete pen */
2211 DeleteObject(hPen);
2215 /***
2216 * DESCRIPTION:
2217 * Calculates the approximate width and height of a given number of items.
2219 * PARAMETER(S):
2220 * [I] HWND : window handle
2221 * [I] INT : number of items
2222 * [I] INT : width
2223 * [I] INT : height
2225 * RETURN:
2226 * Returns a DWORD. The width in the low word and the height in high word.
2228 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2229 WORD wWidth, WORD wHeight)
2231 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2232 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2233 INT nItemCountPerColumn = 1;
2234 INT nColumnCount = 0;
2235 DWORD dwViewRect = 0;
2237 if (nItemCount == -1)
2239 nItemCount = GETITEMCOUNT(infoPtr);
2242 if (uView == LVS_LIST)
2244 if (wHeight == 0xFFFF)
2246 /* use current height */
2247 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2250 if (wHeight < infoPtr->nItemHeight)
2252 wHeight = infoPtr->nItemHeight;
2255 if (nItemCount > 0)
2257 if (infoPtr->nItemHeight > 0)
2259 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2260 if (nItemCountPerColumn == 0)
2262 nItemCountPerColumn = 1;
2265 if (nItemCount % nItemCountPerColumn != 0)
2267 nColumnCount = nItemCount / nItemCountPerColumn;
2269 else
2271 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2276 /* Microsoft padding magic */
2277 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2278 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2280 dwViewRect = MAKELONG(wWidth, wHeight);
2282 else if (uView == LVS_REPORT)
2284 /* TO DO */
2286 else if (uView == LVS_SMALLICON)
2288 /* TO DO */
2290 else if (uView == LVS_ICON)
2292 /* TO DO */
2295 return dwViewRect;
2298 /***
2299 * DESCRIPTION:
2300 * Arranges listview items in icon display mode.
2302 * PARAMETER(S):
2303 * [I] HWND : window handle
2304 * [I] INT : alignment code
2306 * RETURN:
2307 * SUCCESS : TRUE
2308 * FAILURE : FALSE
2310 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2312 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2313 BOOL bResult = FALSE;
2315 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2317 switch (nAlignCode)
2319 case LVA_ALIGNLEFT:
2320 /* TO DO */
2321 break;
2322 case LVA_ALIGNTOP:
2323 /* TO DO */
2324 break;
2325 case LVA_DEFAULT:
2326 /* TO DO */
2327 break;
2328 case LVA_SNAPTOGRID:
2329 /* TO DO */
2330 break;
2334 return bResult;
2337 /* << LISTVIEW_CreateDragImage >> */
2339 /***
2340 * DESCRIPTION:
2341 * Removes all listview items and subitems.
2343 * PARAMETER(S):
2344 * [I] HWND : window handle
2346 * RETURN:
2347 * SUCCESS : TRUE
2348 * FAILURE : FALSE
2350 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2352 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2353 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2354 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2355 UINT uView = lStyle & LVS_TYPEMASK;
2356 LISTVIEW_ITEM *lpItem;
2357 LISTVIEW_SUBITEM *lpSubItem;
2358 NMLISTVIEW nmlv;
2359 BOOL bSuppress;
2360 BOOL bResult = FALSE;
2361 INT i;
2362 INT j;
2363 HDPA hdpaSubItems;
2365 TRACE("(hwnd=%x,)\n", hwnd);
2367 if (GETITEMCOUNT(infoPtr) > 0)
2369 /* initialize memory */
2370 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2372 /* send LVN_DELETEALLITEMS notification */
2373 nmlv.hdr.hwndFrom = hwnd;
2374 nmlv.hdr.idFrom = lCtrlId;
2375 nmlv.hdr.code = LVN_DELETEALLITEMS;
2376 nmlv.iItem = -1;
2378 /* verify if subsequent LVN_DELETEITEM notifications should be
2379 suppressed */
2380 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2382 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2384 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2385 if (hdpaSubItems != NULL)
2387 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2389 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2390 if (lpSubItem != NULL)
2392 /* free subitem string */
2393 if ((lpSubItem->pszText != NULL) &&
2394 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2396 COMCTL32_Free(lpSubItem->pszText);
2399 /* free subitem */
2400 COMCTL32_Free(lpSubItem);
2404 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2405 if (lpItem != NULL)
2407 if (bSuppress == FALSE)
2409 /* send LVN_DELETEITEM notification */
2410 nmlv.hdr.code = LVN_DELETEITEM;
2411 nmlv.iItem = i;
2412 nmlv.lParam = lpItem->lParam;
2413 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2416 /* free item string */
2417 if ((lpItem->pszText != NULL) &&
2418 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2420 COMCTL32_Free(lpItem->pszText);
2423 /* free item */
2424 COMCTL32_Free(lpItem);
2427 DPA_Destroy(hdpaSubItems);
2431 /* reinitialize listview memory */
2432 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2434 /* align items (set position of each item) */
2435 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2437 if (lStyle & LVS_ALIGNLEFT)
2439 LISTVIEW_AlignLeft(hwnd);
2441 else
2443 LISTVIEW_AlignTop(hwnd);
2447 LISTVIEW_UpdateScroll(hwnd);
2449 /* invalidate client area (optimization needed) */
2450 InvalidateRect(hwnd, NULL, TRUE);
2453 return bResult;
2456 /***
2457 * DESCRIPTION:
2458 * Removes a column from the listview control.
2460 * PARAMETER(S):
2461 * [I] HWND : window handle
2462 * [I] INT : column index
2464 * RETURN:
2465 * SUCCESS : TRUE
2466 * FAILURE : FALSE
2468 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2470 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2471 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2472 BOOL bResult = FALSE;
2474 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2476 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2478 /* reset scroll parameters */
2479 if (uView == LVS_REPORT)
2481 /* update scrollbar(s) */
2482 LISTVIEW_UpdateScroll(hwnd);
2484 /* refresh client area */
2485 InvalidateRect(hwnd, NULL, FALSE);
2489 return bResult;
2492 /***
2493 * DESCRIPTION:
2494 * Removes an item from the listview control.
2496 * PARAMETER(S):
2497 * [I] HWND : window handle
2498 * [I] INT : item index
2500 * RETURN:
2501 * SUCCESS : TRUE
2502 * FAILURE : FALSE
2504 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2506 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2507 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2508 UINT uView = lStyle & LVS_TYPEMASK;
2509 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2510 NMLISTVIEW nmlv;
2511 BOOL bResult = FALSE;
2512 HDPA hdpaSubItems;
2513 LISTVIEW_ITEM *lpItem;
2514 LISTVIEW_SUBITEM *lpSubItem;
2515 INT i;
2517 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2519 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2521 /* initialize memory */
2522 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2524 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2525 if (hdpaSubItems != NULL)
2527 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2529 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2530 if (lpSubItem != NULL)
2532 /* free item string */
2533 if ((lpSubItem->pszText != NULL) &&
2534 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2536 COMCTL32_Free(lpSubItem->pszText);
2539 /* free item */
2540 COMCTL32_Free(lpSubItem);
2544 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2545 if (lpItem != NULL)
2547 /* send LVN_DELETEITEM notification */
2548 nmlv.hdr.hwndFrom = hwnd;
2549 nmlv.hdr.idFrom = lCtrlId;
2550 nmlv.hdr.code = LVN_DELETEITEM;
2551 nmlv.iItem = nItem;
2552 nmlv.lParam = lpItem->lParam;
2553 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2554 (LPARAM)&nmlv);
2556 /* free item string */
2557 if ((lpItem->pszText != NULL) &&
2558 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2560 COMCTL32_Free(lpItem->pszText);
2563 /* free item */
2564 COMCTL32_Free(lpItem);
2567 bResult = DPA_Destroy(hdpaSubItems);
2570 /* align items (set position of each item) */
2571 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2573 if (lStyle & LVS_ALIGNLEFT)
2575 LISTVIEW_AlignLeft(hwnd);
2577 else
2579 LISTVIEW_AlignTop(hwnd);
2583 LISTVIEW_UpdateScroll(hwnd);
2585 /* refresh client area */
2586 InvalidateRect(hwnd, NULL, TRUE);
2589 return bResult;
2592 /* LISTVIEW_EditLabel */
2594 /***
2595 * DESCRIPTION:
2596 * Ensures the specified item is visible, scrolling into view if necessary.
2598 * PARAMETER(S):
2599 * [I] HWND : window handle
2600 * [I] INT : item index
2601 * [I] BOOL : partially or entirely visible
2603 * RETURN:
2604 * SUCCESS : TRUE
2605 * FAILURE : FALSE
2607 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
2609 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2610 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2611 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2612 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2613 INT nScrollPosHeight = 0;
2614 INT nScrollPosWidth = 0;
2615 SCROLLINFO scrollInfo;
2616 RECT rcItem;
2618 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2619 scrollInfo.cbSize = sizeof(SCROLLINFO);
2620 scrollInfo.fMask = SIF_POS;
2622 /* ALWAYS bPartial == FALSE, FOR NOW! */
2624 rcItem.left = LVIR_BOUNDS;
2625 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
2627 if (rcItem.left < infoPtr->rcList.left)
2629 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2631 /* scroll left */
2632 if (uView == LVS_LIST)
2634 nScrollPosWidth = infoPtr->nItemWidth;
2635 rcItem.left += infoPtr->rcList.left;
2637 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2639 nScrollPosWidth = max(1, nListWidth / 10);
2640 rcItem.left += infoPtr->rcList.left;
2643 if (rcItem.left % nScrollPosWidth == 0)
2645 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
2647 else
2649 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
2652 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2655 else if (rcItem.right > infoPtr->rcList.right)
2657 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2659 /* scroll right */
2660 if (uView == LVS_LIST)
2662 rcItem.right -= infoPtr->rcList.right;
2663 nScrollPosWidth = infoPtr->nItemWidth;
2665 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
2667 rcItem.right -= infoPtr->rcList.right;
2668 nScrollPosWidth = max(1, nListWidth / 10);
2671 if (rcItem.right % nScrollPosWidth == 0)
2673 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
2675 else
2677 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
2680 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
2684 if (rcItem.top < infoPtr->rcList.top)
2686 /* scroll up */
2687 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2689 if (uView == LVS_REPORT)
2691 rcItem.top -= infoPtr->rcList.top;
2692 nScrollPosHeight = infoPtr->nItemHeight;
2694 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2696 nScrollPosHeight = max(1, nListHeight / 10);
2697 rcItem.top += infoPtr->rcList.top;
2700 if (rcItem.top % nScrollPosHeight == 0)
2702 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
2704 else
2706 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
2709 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2712 else if (rcItem.bottom > infoPtr->rcList.bottom)
2714 /* scroll down */
2715 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2717 if (uView == LVS_REPORT)
2719 rcItem.bottom -= infoPtr->rcList.bottom;
2720 nScrollPosHeight = infoPtr->nItemHeight;
2722 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2724 nScrollPosHeight = max(1, nListHeight / 10);
2725 rcItem.bottom -= infoPtr->rcList.bottom;
2728 if (rcItem.bottom % nScrollPosHeight == 0)
2730 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
2732 else
2734 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
2737 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
2742 return TRUE;
2745 /***
2746 * DESCRIPTION:
2747 * Retrieves the nearest item, given a position and a direction.
2749 * PARAMETER(S):
2750 * [I] HWND : window handle
2751 * [I] POINT : start position
2752 * [I] UINT : direction
2754 * RETURN:
2755 * Item index if successdful, -1 otherwise.
2757 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
2759 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2760 LVHITTESTINFO lvHitTestInfo;
2761 INT nItem = -1;
2762 RECT rcView;
2764 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
2766 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
2767 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
2768 lvHitTestInfo.pt.x += pt.x;
2769 lvHitTestInfo.pt.y += pt.y;
2773 if (vkDirection == VK_DOWN)
2775 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
2777 else if (vkDirection == VK_UP)
2779 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
2781 else if (vkDirection == VK_LEFT)
2783 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
2785 else if (vkDirection == VK_RIGHT)
2787 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
2790 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
2792 return -1;
2794 else
2796 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
2800 while (nItem == -1);
2803 return nItem;
2806 /***
2807 * DESCRIPTION:
2808 * Searches for an item with specific characteristics.
2810 * PARAMETER(S):
2811 * [I] HWND : window handle
2812 * [I] INT : base item index
2813 * [I] LPLVFINDINFO : item information to look for
2815 * RETURN:
2816 * SUCCESS : index of item
2817 * FAILURE : -1
2819 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
2820 LPLVFINDINFO lpFindInfo)
2822 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2823 POINT ptItem;
2824 CHAR szDispText[DISP_TEXT_SIZE];
2825 LVITEMA lvItem;
2826 BOOL bWrap = FALSE;
2827 INT nItem = nStart;
2828 INT nLast = GETITEMCOUNT(infoPtr);
2830 if ((nItem >= -1) && (lpFindInfo != NULL))
2832 ZeroMemory(&lvItem, sizeof(LVITEMA));
2834 if (lpFindInfo->flags & LVFI_PARAM)
2836 lvItem.mask |= LVIF_PARAM;
2839 if (lpFindInfo->flags & LVFI_STRING)
2841 lvItem.mask |= LVIF_TEXT;
2842 lvItem.pszText = szDispText;
2843 lvItem.cchTextMax = DISP_TEXT_SIZE;
2846 if (lpFindInfo->flags & LVFI_PARTIAL)
2848 lvItem.mask |= LVIF_TEXT;
2849 lvItem.pszText = szDispText;
2850 lvItem.cchTextMax = DISP_TEXT_SIZE;
2853 if (lpFindInfo->flags & LVFI_WRAP)
2855 bWrap = TRUE;
2858 if (lpFindInfo->flags & LVFI_NEARESTXY)
2860 ptItem.x = lpFindInfo->pt.x;
2861 ptItem.y = lpFindInfo->pt.y;
2864 while (1)
2866 while (nItem < nLast)
2868 if (lpFindInfo->flags & LVFI_NEARESTXY)
2870 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
2871 lpFindInfo->vkDirection);
2872 if (nItem != -1)
2874 /* get position of the new item index */
2875 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
2876 return -1;
2878 else
2879 return -1;
2881 else
2883 nItem++;
2886 lvItem.iItem = nItem;
2887 lvItem.iSubItem = 0;
2888 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
2890 if (lvItem.mask & LVIF_TEXT)
2892 if (lpFindInfo->flags & LVFI_PARTIAL)
2894 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
2895 continue;
2897 else
2899 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
2900 continue;
2904 if (lvItem.mask & LVIF_PARAM)
2906 if (lpFindInfo->lParam != lvItem.lParam)
2907 continue;
2910 return nItem;
2914 if (bWrap != FALSE)
2916 nItem = -1;
2917 nLast = nStart + 1;
2918 bWrap = FALSE;
2920 else
2922 return -1;
2927 return -1;
2930 /***
2931 * DESCRIPTION:
2932 * Retrieves the background color of the listview control.
2934 * PARAMETER(S):
2935 * [I] HWND : window handle
2937 * RETURN:
2938 * COLORREF associated with the background.
2940 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
2942 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2944 return infoPtr->clrBk;
2947 /***
2948 * DESCRIPTION:
2949 * Retrieves the background image of the listview control.
2951 * PARAMETER(S):
2952 * [I] HWND : window handle
2953 * [O] LPLVMKBIMAGE : background image attributes
2955 * RETURN:
2956 * SUCCESS : TRUE
2957 * FAILURE : FALSE`
2959 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
2960 /* { */
2961 /* FIXME (listview, "empty stub!\n"); */
2962 /* return FALSE; */
2963 /* } */
2965 /***
2966 * DESCRIPTION:
2967 * Retrieves the callback mask.
2969 * PARAMETER(S):
2970 * [I] HWND : window handle
2972 * RETURN:
2973 * Value of mask
2975 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
2977 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2979 return infoPtr->uCallbackMask;
2982 /***
2983 * DESCRIPTION:
2984 * Retrieves column attributes.
2986 * PARAMETER(S):
2987 * [I] HWND : window handle
2988 * [I] INT : column index
2989 * [IO] LPLVCOLUMNA : column information
2991 * RETURN:
2992 * SUCCESS : TRUE
2993 * FAILURE : FALSE
2995 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
2997 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2998 HDITEMA hdi;
2999 BOOL bResult = FALSE;
3001 if (lpColumn != NULL)
3003 /* initialize memory */
3004 ZeroMemory(&hdi, sizeof(HDITEMA));
3006 if (lpColumn->mask & LVCF_FMT)
3008 hdi.mask |= HDI_FORMAT;
3011 if (lpColumn->mask & LVCF_WIDTH)
3013 hdi.mask |= HDI_WIDTH;
3016 if (lpColumn->mask & LVCF_TEXT)
3018 hdi.mask |= (HDI_TEXT | HDI_FORMAT);
3021 if (lpColumn->mask & LVCF_IMAGE)
3023 hdi.mask |= HDI_IMAGE;
3026 if (lpColumn->mask & LVCF_ORDER)
3028 hdi.mask |= HDI_ORDER;
3031 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3032 if (bResult != FALSE)
3034 if (lpColumn->mask & LVCF_FMT)
3036 lpColumn->fmt = 0;
3038 if (hdi.fmt & HDF_LEFT)
3040 lpColumn->fmt |= LVCFMT_LEFT;
3042 else if (hdi.fmt & HDF_RIGHT)
3044 lpColumn->fmt |= LVCFMT_RIGHT;
3046 else if (hdi.fmt & HDF_CENTER)
3048 lpColumn->fmt |= LVCFMT_CENTER;
3051 if (hdi.fmt & HDF_IMAGE)
3053 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3056 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3058 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3062 if (lpColumn->mask & LVCF_WIDTH)
3064 lpColumn->cx = hdi.cxy;
3067 if ((lpColumn->mask & LVCF_TEXT) && (lpColumn->pszText) && (hdi.pszText))
3069 lstrcpynA (lpColumn->pszText, hdi.pszText, lpColumn->cchTextMax);
3072 if (lpColumn->mask & LVCF_IMAGE)
3074 lpColumn->iImage = hdi.iImage;
3077 if (lpColumn->mask & LVCF_ORDER)
3079 lpColumn->iOrder = hdi.iOrder;
3084 return bResult;
3087 /* LISTVIEW_GetColumnW */
3088 /* LISTVIEW_GetColumnOrderArray */
3090 /***
3091 * DESCRIPTION:
3092 * Retrieves the column width.
3094 * PARAMETER(S):
3095 * [I] HWND : window handle
3096 * [I] int : column index
3098 * RETURN:
3099 * SUCCESS : column width
3100 * FAILURE : zero
3102 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3104 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3105 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3106 INT nColumnWidth = 0;
3107 HDITEMA hdi;
3109 if (uView == LVS_LIST)
3111 nColumnWidth = infoPtr->nItemWidth;
3113 else if (uView == LVS_REPORT)
3115 /* get column width from header */
3116 ZeroMemory(&hdi, sizeof(HDITEMA));
3117 hdi.mask = HDI_WIDTH;
3118 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3120 nColumnWidth = hdi.cxy;
3124 return nColumnWidth;
3127 /***
3128 * DESCRIPTION:
3129 * In list or report display mode, retrieves the number of items that can fit
3130 * vertically in the visible area. In icon or small icon display mode,
3131 * retrieves the total number of visible items.
3133 * PARAMETER(S):
3134 * [I] HWND : window handle
3136 * RETURN:
3137 * Number of fully visible items.
3139 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3141 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3142 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3143 INT nItemCount = 0;
3145 if (uView == LVS_LIST)
3147 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3149 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3150 LISTVIEW_GetCountPerColumn(hwnd);
3153 else if (uView == LVS_REPORT)
3155 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3157 else
3159 nItemCount = GETITEMCOUNT(infoPtr);
3162 return nItemCount;
3165 /* LISTVIEW_GetEditControl */
3167 /***
3168 * DESCRIPTION:
3169 * Retrieves the extended listview style.
3171 * PARAMETERS:
3172 * [I] HWND : window handle
3174 * RETURN:
3175 * SUCCESS : previous style
3176 * FAILURE : 0
3178 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3180 LISTVIEW_INFO *infoPtr;
3182 /* make sure we can get the listview info */
3183 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3184 return (0);
3186 return (infoPtr->dwExStyle);
3189 /***
3190 * DESCRIPTION:
3191 * Retrieves the handle to the header control.
3193 * PARAMETER(S):
3194 * [I] HWND : window handle
3196 * RETURN:
3197 * Header handle.
3199 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3201 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3203 return infoPtr->hwndHeader;
3206 /* LISTVIEW_GetHotCursor */
3207 /* LISTVIEW_GetHotItem */
3208 /* LISTVIEW_GetHoverTime */
3210 /***
3211 * DESCRIPTION:
3212 * Retrieves an image list handle.
3214 * PARAMETER(S):
3215 * [I] HWND : window handle
3216 * [I] INT : image list identifier
3218 * RETURN:
3219 * SUCCESS : image list handle
3220 * FAILURE : NULL
3222 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3224 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3225 HIMAGELIST himl = NULL;
3227 switch (nImageList)
3229 case LVSIL_NORMAL:
3230 himl = infoPtr->himlNormal;
3231 break;
3232 case LVSIL_SMALL:
3233 himl = infoPtr->himlSmall;
3234 break;
3235 case LVSIL_STATE:
3236 himl = infoPtr->himlState;
3237 break;
3240 return (LRESULT)himl;
3243 /* LISTVIEW_GetISearchString */
3245 /***
3246 * DESCRIPTION:
3247 * Retrieves item attributes.
3249 * PARAMETER(S):
3250 * [I] HWND : window handle
3251 * [IO] LPLVITEMA : item info
3253 * RETURN:
3254 * SUCCESS : TRUE
3255 * FAILURE : FALSE
3257 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem)
3259 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3260 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3261 BOOL bResult = FALSE;
3262 NMLVDISPINFOA dispInfo;
3263 LISTVIEW_SUBITEM *lpSubItem;
3264 LISTVIEW_ITEM *lpItem;
3265 HDPA hdpaSubItems;
3267 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3269 if (lpLVItem != NULL)
3271 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
3273 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3274 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3275 if (hdpaSubItems != NULL)
3277 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3278 if (lpItem != NULL)
3280 bResult = TRUE;
3281 if (lpLVItem->iSubItem == 0)
3283 if ((lpItem->iImage == I_IMAGECALLBACK) &&
3284 (lpLVItem->mask & LVIF_IMAGE))
3286 dispInfo.item.mask |= LVIF_IMAGE;
3289 if ((lpItem->pszText == LPSTR_TEXTCALLBACKA) &&
3290 (lpLVItem->mask & LVIF_TEXT))
3292 dispInfo.item.mask |= LVIF_TEXT;
3293 ZeroMemory(lpLVItem->pszText, sizeof(CHAR)*lpLVItem->cchTextMax);
3294 dispInfo.item.pszText = lpLVItem->pszText;
3295 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3298 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3300 dispInfo.item.mask |= LVIF_STATE;
3301 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3304 if (dispInfo.item.mask != 0)
3306 dispInfo.hdr.hwndFrom = hwnd;
3307 dispInfo.hdr.idFrom = lCtrlId;
3308 dispInfo.hdr.code = LVN_GETDISPINFOA;
3309 dispInfo.item.iItem = lpLVItem->iItem;
3310 dispInfo.item.iSubItem = 0;
3311 dispInfo.item.lParam = lpItem->lParam;
3312 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3315 if (dispInfo.item.mask & LVIF_IMAGE)
3317 lpLVItem->iImage = dispInfo.item.iImage;
3319 else if (lpLVItem->mask & LVIF_IMAGE)
3321 lpLVItem->iImage = lpItem->iImage;
3324 if (dispInfo.item.mask & LVIF_TEXT)
3326 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3328 Str_SetPtrA(&lpItem->pszText, dispInfo.item.pszText);
3330 lpLVItem->pszText = dispInfo.item.pszText;
3332 else if (lpLVItem->mask & LVIF_TEXT)
3334 lpLVItem->pszText = lpItem->pszText;
3337 if (dispInfo.item.mask & LVIF_STATE)
3339 lpLVItem->state = lpItem->state;
3340 lpLVItem->state &= ~dispInfo.item.stateMask;
3341 lpLVItem->state |= (dispInfo.item.state &
3342 dispInfo.item.stateMask);
3344 else if (lpLVItem->mask & LVIF_STATE)
3346 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
3349 if (lpLVItem->mask & LVIF_PARAM)
3351 lpLVItem->lParam = lpItem->lParam;
3354 if (lpLVItem->mask & LVIF_INDENT)
3356 lpLVItem->iIndent = lpItem->iIndent;
3359 else
3361 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems,
3362 lpLVItem->iSubItem);
3363 if (lpSubItem != NULL)
3365 if ((lpSubItem->iImage == I_IMAGECALLBACK) &&
3366 (lpLVItem->mask & LVIF_IMAGE))
3368 dispInfo.item.mask |= LVIF_IMAGE;
3371 if ((lpSubItem->pszText == LPSTR_TEXTCALLBACKA) &&
3372 (lpLVItem->mask & LVIF_TEXT))
3374 dispInfo.item.mask |= LVIF_TEXT;
3375 ZeroMemory(lpLVItem->pszText,
3376 sizeof(CHAR)*lpLVItem->cchTextMax);
3377 dispInfo.item.pszText = lpLVItem->pszText;
3378 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3381 else
3383 if (lpLVItem->mask & LVIF_IMAGE)
3385 dispInfo.item.mask |= LVIF_IMAGE;
3388 if (lpLVItem->mask & LVIF_TEXT)
3390 dispInfo.item.mask |= LVIF_TEXT;
3391 ZeroMemory(lpLVItem->pszText,
3392 sizeof(CHAR)*lpLVItem->cchTextMax);
3393 dispInfo.item.pszText = lpLVItem->pszText;
3394 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3398 if (dispInfo.item.mask != 0)
3400 dispInfo.hdr.hwndFrom = hwnd;
3401 dispInfo.hdr.idFrom = lCtrlId;
3402 dispInfo.hdr.code = LVN_GETDISPINFOA;
3403 dispInfo.item.iItem = lpLVItem->iItem;
3404 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3405 dispInfo.item.lParam = lpItem->lParam;
3406 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3409 if (dispInfo.item.mask & LVIF_IMAGE)
3411 lpLVItem->iImage = dispInfo.item.iImage;
3413 else if (lpLVItem->mask & LVIF_IMAGE)
3415 lpLVItem->iImage = lpItem->iImage;
3418 if (dispInfo.item.mask & LVIF_TEXT)
3420 if (dispInfo.item.mask & LVIF_DI_SETITEM)
3422 if (lpSubItem)
3423 Str_SetPtrA(&lpSubItem->pszText, dispInfo.item.pszText);
3425 lpLVItem->pszText = dispInfo.item.pszText;
3427 else if (lpLVItem->mask & LVIF_TEXT)
3429 lpLVItem->pszText = lpSubItem->pszText;
3437 return bResult;
3440 /* LISTVIEW_GetItemW */
3441 /* LISTVIEW_GetHotCursor */
3443 /***
3444 * DESCRIPTION:
3445 * Retrieves the index of the hot item.
3447 * PARAMETERS:
3448 * [I] HWND : window handle
3450 * RETURN:
3451 * SUCCESS : hot item index
3452 * FAILURE : -1 (no hot item)
3454 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
3456 LISTVIEW_INFO *infoPtr;
3458 /* make sure we can get the listview info */
3459 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3460 return (-1);
3462 return (infoPtr->nHotItem);
3465 /* LISTVIEW_GetHoverTime */
3467 /***
3468 * DESCRIPTION:
3469 * Retrieves the number of items in the listview control.
3471 * PARAMETER(S):
3472 * [I] HWND : window handle
3474 * RETURN:
3475 * Number of items.
3477 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
3479 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3481 return GETITEMCOUNT(infoPtr);
3484 /***
3485 * DESCRIPTION:
3486 * Retrieves the position (upper-left) of the listview control item.
3488 * PARAMETER(S):
3489 * [I] HWND : window handle
3490 * [I] INT : item index
3491 * [O] LPPOINT : coordinate information
3493 * RETURN:
3494 * SUCCESS : TRUE
3495 * FAILURE : FALSE
3497 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
3498 LPPOINT lpptPosition)
3500 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3501 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3502 BOOL bResult = FALSE;
3503 HDPA hdpaSubItems;
3504 LISTVIEW_ITEM *lpItem;
3505 INT nCountPerColumn;
3506 INT nRow;
3508 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
3509 lpptPosition);
3511 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
3512 (lpptPosition != NULL))
3514 if (uView == LVS_LIST)
3516 bResult = TRUE;
3517 nItem = nItem - ListView_GetTopIndex(hwnd);
3518 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
3519 if (nItem < 0)
3521 nRow = nItem % nCountPerColumn;
3522 if (nRow == 0)
3524 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3525 lpptPosition->y = 0;
3527 else
3529 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
3530 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
3533 else
3535 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
3536 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
3539 else if (uView == LVS_REPORT)
3541 bResult = TRUE;
3542 lpptPosition->x = REPORT_MARGINX;
3543 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
3544 infoPtr->nItemHeight) + infoPtr->rcList.top;
3546 else
3548 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
3549 if (hdpaSubItems != NULL)
3551 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3552 if (lpItem != NULL)
3554 bResult = TRUE;
3555 lpptPosition->x = lpItem->ptPosition.x;
3556 lpptPosition->y = lpItem->ptPosition.y;
3562 return bResult;
3565 /***
3566 * DESCRIPTION:
3567 * Retrieves the bounding rectangle for a listview control item.
3569 * PARAMETER(S):
3570 * [I] HWND : window handle
3571 * [I] INT : item index
3572 * [IO] LPRECT : bounding rectangle coordinates
3574 * RETURN:
3575 * SUCCESS : TRUE
3576 * FAILURE : FALSE
3578 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
3580 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3581 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3582 BOOL bResult = FALSE;
3583 POINT ptOrigin;
3584 POINT ptItem;
3585 HDC hdc;
3586 HFONT hOldFont;
3587 INT nMaxWidth;
3588 INT nLabelWidth;
3589 TEXTMETRICA tm;
3591 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
3593 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
3595 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
3597 switch(lprc->left)
3599 case LVIR_ICON:
3600 if (uView == LVS_ICON)
3602 if (infoPtr->himlNormal != NULL)
3604 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3606 bResult = TRUE;
3607 lprc->left = ptItem.x + ptOrigin.x;
3608 lprc->top = ptItem.y + ptOrigin.y;
3609 lprc->right = lprc->left + infoPtr->iconSize.cx;
3610 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
3611 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3615 else if (uView == LVS_SMALLICON)
3617 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3619 bResult = TRUE;
3620 lprc->left = ptItem.x + ptOrigin.x;
3621 lprc->top = ptItem.y + ptOrigin.y;
3622 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3624 if (infoPtr->himlState != NULL)
3625 lprc->left += infoPtr->iconSize.cx;
3627 if (infoPtr->himlSmall != NULL)
3628 lprc->right = lprc->left + infoPtr->iconSize.cx;
3629 else
3630 lprc->right = lprc->left;
3633 else
3635 bResult = TRUE;
3636 lprc->left = ptItem.x;
3637 lprc->top = ptItem.y;
3638 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3640 if (infoPtr->himlState != NULL)
3642 lprc->left += infoPtr->iconSize.cx;
3645 if (infoPtr->himlSmall != NULL)
3647 lprc->right = lprc->left + infoPtr->iconSize.cx;
3649 else
3651 lprc->right = lprc->left;
3654 break;
3656 case LVIR_LABEL:
3657 if (uView == LVS_ICON)
3659 if (infoPtr->himlNormal != NULL)
3661 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3663 bResult = TRUE;
3664 lprc->left = ptItem.x + ptOrigin.x;
3665 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
3666 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
3667 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3668 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
3670 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
3671 lprc->right = lprc->left + nLabelWidth;
3673 else
3675 lprc->left += 1;
3676 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
3679 hdc = GetDC(hwnd);
3680 hOldFont = SelectObject(hdc, infoPtr->hFont);
3681 GetTextMetricsA(hdc, &tm);
3682 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
3683 SelectObject(hdc, hOldFont);
3684 ReleaseDC(hwnd, hdc);
3688 else if (uView == LVS_SMALLICON)
3690 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3692 bResult = TRUE;
3693 nMaxWidth = lprc->left = ptItem.x + ptOrigin.x;
3694 lprc->top = ptItem.y + ptOrigin.y;
3695 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3697 if (infoPtr->himlState != NULL)
3699 lprc->left += infoPtr->iconSize.cx;
3702 if (infoPtr->himlSmall != NULL)
3704 lprc->left += infoPtr->iconSize.cx;
3707 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
3708 if (lprc->left + nLabelWidth < nMaxWidth + infoPtr->nItemWidth)
3710 lprc->right = lprc->left + nLabelWidth;
3712 else
3714 lprc->right = nMaxWidth + infoPtr->nItemWidth;
3718 else
3720 bResult = TRUE;
3721 lprc->left = ptItem.x;
3722 lprc->top = ptItem.y;
3723 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3725 if (infoPtr->himlState != NULL)
3727 lprc->left += infoPtr->iconSize.cx;
3730 if (infoPtr->himlSmall != NULL)
3732 lprc->left += infoPtr->iconSize.cx;
3735 lprc->right = lprc->left + LISTVIEW_GetLabelWidth(hwnd, nItem);
3737 break;
3739 case LVIR_BOUNDS:
3740 if (uView == LVS_ICON)
3742 if (infoPtr->himlNormal != NULL)
3744 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3746 bResult = TRUE;
3747 lprc->left = ptItem.x + ptOrigin.x;
3748 lprc->top = ptItem.y + ptOrigin.y;
3749 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3750 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3754 else if (uView == LVS_SMALLICON)
3756 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3758 bResult = TRUE;
3759 lprc->left = ptItem.x + ptOrigin.x;
3760 lprc->right = lprc->left;
3761 lprc->top = ptItem.y + ptOrigin.y;
3762 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3763 if (infoPtr->himlState != NULL)
3764 lprc->right += infoPtr->iconSize.cx;
3765 if (infoPtr->himlSmall != NULL)
3766 lprc->right += infoPtr->iconSize.cx;
3767 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3770 else
3772 bResult = TRUE;
3773 lprc->left = ptItem.x;
3774 lprc->right = lprc->left;
3775 lprc->top = ptItem.y;
3776 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3778 if (infoPtr->himlState != NULL)
3780 lprc->right += infoPtr->iconSize.cx;
3783 if (infoPtr->himlSmall != NULL)
3785 lprc->right += infoPtr->iconSize.cx;
3788 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3790 break;
3792 case LVIR_SELECTBOUNDS:
3793 if (uView == LVS_ICON)
3795 if (infoPtr->himlNormal != NULL)
3797 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3799 bResult = TRUE;
3800 lprc->left = ptItem.x + ptOrigin.x;
3801 lprc->top = ptItem.y + ptOrigin.y;
3802 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
3803 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
3807 else if (uView == LVS_SMALLICON)
3809 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
3811 bResult = TRUE;
3812 lprc->left = ptItem.x + ptOrigin.x;
3813 lprc->top = ptItem.y + ptOrigin.y;
3814 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3816 if (infoPtr->himlState != NULL)
3818 lprc->left += infoPtr->iconSize.cx;
3821 lprc->right = lprc->left;
3823 if (infoPtr->himlSmall != NULL)
3825 lprc->right += infoPtr->iconSize.cx;
3828 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3831 else
3833 bResult = TRUE;
3834 lprc->left = ptItem.x;
3835 lprc->top = ptItem.y;
3836 lprc->bottom = lprc->top + infoPtr->nItemHeight;
3838 if (infoPtr->himlState != NULL)
3840 lprc->left += infoPtr->iconSize.cx;
3843 lprc->right = lprc->left;
3845 if (infoPtr->himlSmall != NULL)
3847 lprc->right += infoPtr->iconSize.cx;
3850 lprc->right += LISTVIEW_GetLabelWidth(hwnd, nItem);
3852 break;
3857 return bResult;
3860 /***
3861 * DESCRIPTION:
3862 * Retrieves the width of a label.
3864 * PARAMETER(S):
3865 * [I] HWND : window handle
3867 * RETURN:
3868 * SUCCESS : string width (in pixels)
3869 * FAILURE : zero
3871 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
3873 CHAR szDispText[DISP_TEXT_SIZE];
3874 INT nLabelWidth = 0;
3875 LVITEMA lvItem;
3877 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
3879 ZeroMemory(&lvItem, sizeof(LVITEMA));
3880 lvItem.mask = LVIF_TEXT;
3881 lvItem.iItem = nItem;
3882 lvItem.cchTextMax = DISP_TEXT_SIZE;
3883 lvItem.pszText = szDispText;
3884 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3886 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
3889 return nLabelWidth;
3892 /***
3893 * DESCRIPTION:
3894 * Retrieves the spacing between listview control items.
3896 * PARAMETER(S):
3897 * [I] HWND : window handle
3898 * [I] BOOL : flag for small or large icon
3900 * RETURN:
3901 * Horizontal + vertical spacing
3903 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
3905 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3906 LONG lResult;
3908 if (bSmall == FALSE)
3910 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
3912 else
3914 /* TODO: need to store width of smallicon item */
3915 lResult = MAKELONG(0, infoPtr->nItemHeight);
3918 return lResult;
3921 /***
3922 * DESCRIPTION:
3923 * Retrieves the state of a listview control item.
3925 * PARAMETER(S):
3926 * [I] HWND : window handle
3927 * [I] INT : item index
3928 * [I] UINT : state mask
3930 * RETURN:
3931 * State specified by the mask.
3933 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
3935 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3936 LVITEMA lvItem;
3937 UINT uState = 0;
3939 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3941 ZeroMemory(&lvItem, sizeof(LVITEMA));
3942 lvItem.iItem = nItem;
3943 lvItem.stateMask = uMask;
3944 lvItem.mask = LVIF_STATE;
3945 if (ListView_GetItemA(hwnd, &lvItem) != FALSE)
3947 uState = lvItem.state;
3951 return uState;
3954 /***
3955 * DESCRIPTION:
3956 * Retrieves the text of a listview control item or subitem.
3958 * PARAMETER(S):
3959 * [I] HWND : window handle
3960 * [I] INT : item index
3961 * [IO] LPLVITEMA : item information
3963 * RETURN:
3964 * SUCCESS : string length
3965 * FAILURE : 0
3967 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
3969 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3970 INT nLength = 0;
3972 if (lpLVItem != NULL)
3974 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
3976 lpLVItem->mask = LVIF_TEXT;
3977 lpLVItem->iItem = nItem;
3978 if (ListView_GetItemA(hwnd, lpLVItem) != FALSE)
3980 nLength = lstrlenA(lpLVItem->pszText);
3985 return nLength;
3988 /***
3989 * DESCRIPTION:
3990 * Searches for an item based on properties + relationships.
3992 * PARAMETER(S):
3993 * [I] HWND : window handle
3994 * [I] INT : item index
3995 * [I] INT : relationship flag
3997 * RETURN:
3998 * SUCCESS : item index
3999 * FAILURE : -1
4001 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4003 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4004 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4005 UINT uMask = 0;
4006 LVFINDINFO lvFindInfo;
4007 INT nCountPerColumn;
4008 INT i;
4010 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4012 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4014 if (uFlags & LVNI_CUT)
4015 uMask |= LVIS_CUT;
4017 if (uFlags & LVNI_DROPHILITED)
4018 uMask |= LVIS_DROPHILITED;
4020 if (uFlags & LVNI_FOCUSED)
4021 uMask |= LVIS_FOCUSED;
4023 if (uFlags & LVNI_SELECTED)
4024 uMask |= LVIS_SELECTED;
4026 if (uFlags & LVNI_ABOVE)
4028 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4030 while (nItem >= 0)
4032 nItem--;
4033 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4034 return nItem;
4037 else
4039 lvFindInfo.flags = LVFI_NEARESTXY;
4040 lvFindInfo.vkDirection = VK_UP;
4041 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4042 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4044 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4045 return nItem;
4049 else if (uFlags & LVNI_BELOW)
4051 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4053 while (nItem < GETITEMCOUNT(infoPtr))
4055 nItem++;
4056 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4057 return nItem;
4060 else
4062 lvFindInfo.flags = LVFI_NEARESTXY;
4063 lvFindInfo.vkDirection = VK_DOWN;
4064 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4065 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4067 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4068 return nItem;
4072 else if (uFlags & LVNI_TOLEFT)
4074 if (uView == LVS_LIST)
4076 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4077 while (nItem - nCountPerColumn >= 0)
4079 nItem -= nCountPerColumn;
4080 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4081 return nItem;
4084 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4086 lvFindInfo.flags = LVFI_NEARESTXY;
4087 lvFindInfo.vkDirection = VK_LEFT;
4088 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4089 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4091 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4092 return nItem;
4096 else if (uFlags & LVNI_TORIGHT)
4098 if (uView == LVS_LIST)
4100 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4101 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4103 nItem += nCountPerColumn;
4104 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4105 return nItem;
4108 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4110 lvFindInfo.flags = LVFI_NEARESTXY;
4111 lvFindInfo.vkDirection = VK_RIGHT;
4112 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4113 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4115 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4116 return nItem;
4120 else
4122 nItem++;
4124 /* search by index */
4125 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4127 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4128 return i;
4133 return -1;
4136 /* LISTVIEW_GetNumberOfWorkAreas */
4138 /***
4139 * DESCRIPTION:
4140 * Retrieves the origin coordinates when in icon or small icon display mode.
4142 * PARAMETER(S):
4143 * [I] HWND : window handle
4144 * [O] LPPOINT : coordinate information
4146 * RETURN:
4147 * SUCCESS : TRUE
4148 * FAILURE : FALSE
4150 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4152 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4153 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4154 UINT uView = lStyle & LVS_TYPEMASK;
4155 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
4156 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
4157 BOOL bResult = FALSE;
4159 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4161 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4163 SCROLLINFO scrollInfo;
4164 ZeroMemory(lpptOrigin, sizeof(POINT));
4165 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4166 scrollInfo.cbSize = sizeof(SCROLLINFO);
4168 if (lStyle & WS_HSCROLL)
4170 scrollInfo.fMask = SIF_POS;
4171 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4173 lpptOrigin->x = -scrollInfo.nPos * max(nListWidth / 10, 1);
4177 if (lStyle & WS_VSCROLL)
4179 scrollInfo.fMask = SIF_POS;
4180 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4182 lpptOrigin->y = -scrollInfo.nPos * max(nListHeight / 10, 1);
4186 bResult = TRUE;
4189 return bResult;
4192 /***
4193 * DESCRIPTION:
4194 * Retrieves the number of items that are marked as selected.
4196 * PARAMETER(S):
4197 * [I] HWND : window handle
4199 * RETURN:
4200 * Number of items selected.
4202 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4204 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4205 INT nSelectedCount = 0;
4206 INT i;
4208 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4210 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4212 nSelectedCount++;
4216 return nSelectedCount;
4219 /***
4220 * DESCRIPTION:
4221 * Retrieves item index that marks the start of a multiple selection.
4223 * PARAMETER(S):
4224 * [I] HWND : window handle
4226 * RETURN:
4227 * Index number or -1 if there is no selection mark.
4229 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4231 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4233 return infoPtr->nSelectionMark;
4236 /***
4237 * DESCRIPTION:
4238 * Retrieves the width of a string.
4240 * PARAMETER(S):
4241 * [I] HWND : window handle
4243 * RETURN:
4244 * SUCCESS : string width (in pixels)
4245 * FAILURE : zero
4247 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4249 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4250 HFONT hFont, hOldFont;
4251 SIZE stringSize;
4252 HDC hdc;
4254 ZeroMemory(&stringSize, sizeof(SIZE));
4255 if (lpszText != NULL)
4257 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4258 hdc = GetDC(hwnd);
4259 hOldFont = SelectObject(hdc, hFont);
4260 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4261 SelectObject(hdc, hOldFont);
4262 ReleaseDC(hwnd, hdc);
4265 return stringSize.cx;
4268 /***
4269 * DESCRIPTION:
4270 * Retrieves the text backgound color.
4272 * PARAMETER(S):
4273 * [I] HWND : window handle
4275 * RETURN:
4276 * COLORREF associated with the the background.
4278 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4280 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4282 return infoPtr->clrTextBk;
4285 /***
4286 * DESCRIPTION:
4287 * Retrieves the text color.
4289 * PARAMETER(S):
4290 * [I] HWND : window handle
4292 * RETURN:
4293 * COLORREF associated with the text.
4295 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4297 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4299 return infoPtr->clrText;
4302 /***
4303 * DESCRIPTION:
4304 * Determines which section of the item was selected (if any).
4306 * PARAMETER(S):
4307 * [I] HWND : window handle
4308 * [IO] LPLVHITTESTINFO : hit test information
4310 * RETURN:
4311 * SUCCESS : item index
4312 * FAILURE : -1
4314 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4316 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4317 RECT rcItem;
4318 INT i;
4320 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4321 lpHitTestInfo->pt.y);
4323 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4325 rcItem.left = LVIR_BOUNDS;
4326 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4328 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4330 rcItem.left = LVIR_ICON;
4331 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4333 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4335 lpHitTestInfo->flags = LVHT_ONITEMICON;
4336 lpHitTestInfo->iItem = i;
4337 lpHitTestInfo->iSubItem = 0;
4338 return i;
4342 rcItem.left = LVIR_LABEL;
4343 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4345 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4347 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
4348 lpHitTestInfo->iItem = i;
4349 lpHitTestInfo->iSubItem = 0;
4350 return i;
4354 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
4355 lpHitTestInfo->iItem = i;
4356 lpHitTestInfo->iSubItem = 0;
4357 return i;
4362 lpHitTestInfo->flags = LVHT_NOWHERE;
4364 return -1;
4367 /***
4368 * DESCRIPTION:
4369 * Determines which listview item is located at the specified position.
4371 * PARAMETER(S):
4372 * [I] HWND : window handle
4373 * [IO} LPLVHITTESTINFO : hit test information
4375 * RETURN:
4376 * SUCCESS : item index
4377 * FAILURE : -1
4379 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4381 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4382 INT nItem = -1;
4384 lpHitTestInfo->flags = 0;
4386 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
4388 lpHitTestInfo->flags = LVHT_TOLEFT;
4390 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
4392 lpHitTestInfo->flags = LVHT_TORIGHT;
4394 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
4396 lpHitTestInfo->flags |= LVHT_ABOVE;
4398 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
4400 lpHitTestInfo->flags |= LVHT_BELOW;
4403 if (lpHitTestInfo->flags == 0)
4405 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
4408 return nItem;
4411 /***
4412 * DESCRIPTION:
4413 * Inserts a new column.
4415 * PARAMETER(S):
4416 * [I] HWND : window handle
4417 * [I] INT : column index
4418 * [I] LPLVCOLUMNA : column information
4420 * RETURN:
4421 * SUCCESS : new column index
4422 * FAILURE : -1
4424 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
4425 LPLVCOLUMNA lpColumn)
4427 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4428 HDITEMA hdi;
4429 INT nNewColumn = -1;
4431 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
4432 lpColumn);
4434 if (lpColumn != NULL)
4436 /* initialize memory */
4437 ZeroMemory(&hdi, sizeof(HDITEMA));
4439 if (lpColumn->mask & LVCF_FMT)
4441 /* format member is valid */
4442 hdi.mask |= HDI_FORMAT;
4444 /* set text alignment (leftmost column must be left-aligned) */
4445 if (nColumn == 0)
4447 hdi.fmt |= HDF_LEFT;
4449 else
4451 if (lpColumn->fmt & LVCFMT_LEFT)
4453 hdi.fmt |= HDF_LEFT;
4455 else if (lpColumn->fmt & LVCFMT_RIGHT)
4457 hdi.fmt |= HDF_RIGHT;
4459 else if (lpColumn->fmt & LVCFMT_CENTER)
4461 hdi.fmt |= HDF_CENTER;
4465 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4467 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4468 /* ??? */
4471 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4473 /* ??? */
4476 if (lpColumn->fmt & LVCFMT_IMAGE)
4478 hdi.fmt |= HDF_IMAGE;
4479 hdi.iImage = I_IMAGECALLBACK;
4483 if (lpColumn->mask & LVCF_WIDTH)
4485 hdi.mask |= HDI_WIDTH;
4486 hdi.cxy = lpColumn->cx;
4489 if (lpColumn->mask & LVCF_TEXT)
4491 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4492 hdi.pszText = lpColumn->pszText;
4493 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4494 hdi.fmt |= HDF_STRING;
4497 if (lpColumn->mask & LVCF_IMAGE)
4499 hdi.mask |= HDI_IMAGE;
4500 hdi.iImage = lpColumn->iImage;
4503 if (lpColumn->mask & LVCF_ORDER)
4505 hdi.mask |= HDI_ORDER;
4506 hdi.iOrder = lpColumn->iOrder;
4509 /* insert item in header control */
4510 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
4511 (WPARAM)nColumn, (LPARAM)&hdi);
4513 LISTVIEW_UpdateScroll(hwnd);
4514 InvalidateRect(hwnd, NULL, FALSE);
4517 return nNewColumn;
4520 /* LISTVIEW_InsertColumnW */
4522 /***
4523 * DESCRIPTION:
4524 * Inserts a new item in the listview control.
4526 * PARAMETER(S):
4527 * [I] HWND : window handle
4528 * [I] LPLVITEMA : item information
4530 * RETURN:
4531 * SUCCESS : new item index
4532 * FAILURE : -1
4534 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
4536 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4537 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4538 UINT uView = lStyle & LVS_TYPEMASK;
4539 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
4540 NMLISTVIEW nmlv;
4541 INT nItem = -1;
4542 HDPA hdpaSubItems;
4543 LISTVIEW_ITEM *lpItem = NULL;
4545 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
4547 if (lpLVItem != NULL)
4549 /* make sure it's not a subitem; cannot insert a subitem */
4550 if (lpLVItem->iSubItem == 0)
4552 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
4553 if (lpItem != NULL)
4555 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
4556 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
4558 /* insert item in listview control data structure */
4559 hdpaSubItems = DPA_Create(8);
4560 if (hdpaSubItems != NULL)
4562 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
4563 if (nItem != -1)
4565 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
4566 hdpaSubItems);
4567 if (nItem != -1)
4569 /* manage item focus */
4570 if (lpLVItem->mask & LVIF_STATE)
4572 if (lpLVItem->stateMask & LVIS_FOCUSED)
4574 LISTVIEW_SetItemFocus(hwnd, nItem);
4578 /* send LVN_INSERTITEM notification */
4579 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
4580 nmlv.hdr.hwndFrom = hwnd;
4581 nmlv.hdr.idFrom = lCtrlId;
4582 nmlv.hdr.code = LVN_INSERTITEM;
4583 nmlv.iItem = nItem;
4584 nmlv.lParam = lpItem->lParam;;
4585 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
4587 /* align items (set position of each item) */
4588 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4590 if (lStyle & LVS_ALIGNLEFT)
4592 LISTVIEW_AlignLeft(hwnd);
4594 else
4596 LISTVIEW_AlignTop(hwnd);
4600 LISTVIEW_UpdateScroll(hwnd);
4601 /* refresh client area */
4602 InvalidateRect(hwnd, NULL, FALSE);
4611 /* free memory if unsuccessful */
4612 if ((nItem == -1) && (lpItem != NULL))
4614 COMCTL32_Free(lpItem);
4617 return nItem;
4620 /* LISTVIEW_InsertItemW */
4622 /***
4623 * DESCRIPTION:
4624 * Redraws a range of items.
4626 * PARAMETER(S):
4627 * [I] HWND : window handle
4628 * [I] INT : first item
4629 * [I] INT : last item
4631 * RETURN:
4632 * SUCCESS : TRUE
4633 * FAILURE : FALSE
4635 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
4637 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4638 BOOL bResult = FALSE;
4639 RECT rc;
4641 if (nFirst <= nLast)
4643 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
4645 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
4647 /* bResult = */
4648 InvalidateRect(hwnd, &rc, FALSE);
4653 return bResult;
4656 /* LISTVIEW_Scroll */
4658 /***
4659 * DESCRIPTION:
4660 * Sets the background color.
4662 * PARAMETER(S):
4663 * [I] HWND : window handle
4664 * [I] COLORREF : background color
4666 * RETURN:
4667 * SUCCESS : TRUE
4668 * FAILURE : FALSE
4670 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
4672 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4674 infoPtr->clrBk = clrBk;
4675 InvalidateRect(hwnd, NULL, TRUE);
4677 return TRUE;
4680 /* LISTVIEW_SetBkImage */
4682 /***
4683 * DESCRIPTION:
4684 * Sets the callback mask. This mask will be used when the parent
4685 * window stores state information (some or all).
4687 * PARAMETER(S):
4688 * [I] HWND : window handle
4689 * [I] UINT : state mask
4691 * RETURN:
4692 * SUCCESS : TRUE
4693 * FAILURE : FALSE
4695 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
4697 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4699 infoPtr->uCallbackMask = uMask;
4701 return TRUE;
4704 /***
4705 * DESCRIPTION:
4706 * Sets the attributes of a header item.
4708 * PARAMETER(S):
4709 * [I] HWND : window handle
4710 * [I] INT : column index
4711 * [I] LPLVCOLUMNA : column attributes
4713 * RETURN:
4714 * SUCCESS : TRUE
4715 * FAILURE : FALSE
4717 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
4718 LPLVCOLUMNA lpColumn)
4720 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4721 BOOL bResult = FALSE;
4722 HDITEMA hdi, hdiget;
4724 if ((lpColumn != NULL) && (nColumn >= 0) &&
4725 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
4727 /* initialize memory */
4728 ZeroMemory(&hdi, sizeof(HDITEMA));
4730 if (lpColumn->mask & LVCF_FMT)
4732 /* format member is valid */
4733 hdi.mask |= HDI_FORMAT;
4735 /* get current format first */
4736 hdiget.mask = HDI_FORMAT;
4737 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
4738 /* preserve HDF_STRING if present */
4739 hdi.fmt = hdiget.fmt & HDF_STRING;
4741 /* set text alignment (leftmost column must be left-aligned) */
4742 if (nColumn == 0)
4744 hdi.fmt |= HDF_LEFT;
4746 else
4748 if (lpColumn->fmt & LVCFMT_LEFT)
4750 hdi.fmt |= HDF_LEFT;
4752 else if (lpColumn->fmt & LVCFMT_RIGHT)
4754 hdi.fmt |= HDF_RIGHT;
4756 else if (lpColumn->fmt & LVCFMT_CENTER)
4758 hdi.fmt |= HDF_CENTER;
4762 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
4764 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
4767 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
4769 hdi.fmt |= HDF_IMAGE;
4772 if (lpColumn->fmt & LVCFMT_IMAGE)
4774 hdi.fmt |= HDF_IMAGE;
4775 hdi.iImage = I_IMAGECALLBACK;
4779 if (lpColumn->mask & LVCF_WIDTH)
4781 hdi.mask |= HDI_WIDTH;
4782 hdi.cxy = lpColumn->cx;
4785 if (lpColumn->mask & LVCF_TEXT)
4787 hdi.mask |= HDI_TEXT | HDI_FORMAT;
4788 hdi.pszText = lpColumn->pszText;
4789 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
4790 hdi.fmt |= HDF_STRING;
4793 if (lpColumn->mask & LVCF_IMAGE)
4795 hdi.mask |= HDI_IMAGE;
4796 hdi.iImage = lpColumn->iImage;
4799 if (lpColumn->mask & LVCF_ORDER)
4801 hdi.mask |= HDI_ORDER;
4802 hdi.iOrder = lpColumn->iOrder;
4805 /* set header item attributes */
4806 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
4809 return bResult;
4812 /* LISTVIEW_SetColumnW */
4813 /* LISTVIEW_SetColumnOrderArray */
4815 /***
4816 * DESCRIPTION:
4817 * Sets the width of a column
4819 * PARAMETERS:
4820 * [I] HWND : window handle
4821 * [I] INT : column index
4822 * [I] INT : column width
4824 * RETURN:
4825 * SUCCESS : TRUE
4826 * FAILURE : FALSE
4828 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
4830 LISTVIEW_INFO *infoPtr;
4831 HDITEMA hdi;
4832 LRESULT lret;
4833 LONG lStyle;
4835 /* set column width only if in report mode */
4836 lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4837 if ((lStyle & LVS_TYPEMASK) != LVS_REPORT)
4838 return (FALSE);
4840 /* make sure we can get the listview info */
4841 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4842 return (FALSE);
4843 if (!infoPtr->hwndHeader) /* make sure we have a header */
4844 return (FALSE);
4846 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
4847 * LVSCV_AUTOSIZE_USEHEADER (-2)
4849 if (cx < 0)
4850 return (FALSE);
4852 hdi.mask = HDI_WIDTH;
4853 hdi.cxy = cx;
4855 /* call header to update the column change */
4856 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
4858 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
4860 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
4862 return lret;
4865 /***
4866 * DESCRIPTION:
4867 * Sets the extended listview style.
4869 * PARAMETERS:
4870 * [I] HWND : window handle
4871 * [I] DWORD : mask
4872 * [I] DWORD : style
4874 * RETURN:
4875 * SUCCESS : previous style
4876 * FAILURE : 0
4878 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
4880 LISTVIEW_INFO *infoPtr;
4881 DWORD dwOldStyle;
4883 /* make sure we can get the listview info */
4884 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4885 return (0);
4887 /* store previous style */
4888 dwOldStyle = infoPtr->dwExStyle;
4890 /* set new style */
4891 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
4893 return (dwOldStyle);
4896 /* LISTVIEW_SetHotCursor */
4898 /***
4899 * DESCRIPTION:
4900 * Sets the hot item index.
4902 * PARAMETERS:
4903 * [I] HWND : window handle
4904 * [I] INT : index
4906 * RETURN:
4907 * SUCCESS : previous hot item index
4908 * FAILURE : -1 (no hot item)
4910 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
4912 LISTVIEW_INFO *infoPtr;
4913 INT iOldIndex;
4915 /* make sure we can get the listview info */
4916 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4917 return (-1);
4919 /* store previous index */
4920 iOldIndex = infoPtr->nHotItem;
4922 /* set new style */
4923 infoPtr->nHotItem = iIndex;
4925 return (iOldIndex);
4928 /* LISTVIEW_SetIconSpacing */
4930 /***
4931 * DESCRIPTION:
4932 * Sets image lists.
4934 * PARAMETER(S):
4935 * [I] HWND : window handle
4936 * [I] INT : image list type
4937 * [I] HIMAGELIST : image list handle
4939 * RETURN:
4940 * SUCCESS : old image list
4941 * FAILURE : NULL
4943 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
4945 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4946 HIMAGELIST himlTemp = 0;
4948 switch (nType)
4950 case LVSIL_NORMAL:
4951 himlTemp = infoPtr->himlNormal;
4952 infoPtr->himlNormal = himl;
4953 return (LRESULT)himlTemp;
4955 case LVSIL_SMALL:
4956 himlTemp = infoPtr->himlSmall;
4957 infoPtr->himlSmall = himl;
4958 return (LRESULT)himlTemp;
4960 case LVSIL_STATE:
4961 himlTemp = infoPtr->himlState;
4962 infoPtr->himlState = himl;
4963 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
4964 return (LRESULT)himlTemp;
4967 return (LRESULT)NULL;
4971 /***
4972 * DESCRIPTION:
4973 * Sets the attributes of an item.
4975 * PARAMETER(S):
4976 * [I] HWND : window handle
4977 * [I] LPLVITEM : item information
4979 * RETURN:
4980 * SUCCESS : TRUE
4981 * FAILURE : FALSE
4983 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
4985 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4986 BOOL bResult = FALSE;
4988 if (lpLVItem != NULL)
4990 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
4992 if (lpLVItem->iSubItem == 0)
4994 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
4996 else
4998 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5004 return bResult;
5007 /* LISTVIEW_SetItemW */
5009 /***
5010 * DESCRIPTION:
5011 * Preallocates memory.
5013 * PARAMETER(S):
5014 * [I] HWND : window handle
5015 * [I] INT : item count (prjected number of items)
5016 * [I] DWORD : update flags
5018 * RETURN:
5019 * SUCCESS : TRUE
5020 * FAILURE : FALSE
5022 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5024 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5026 FIXME("(%d %08lx)empty stub!\n", nItems, dwFlags);
5028 if (nItems == 0)
5029 return LISTVIEW_DeleteAllItems (hwnd);
5031 if (nItems > GETITEMCOUNT(infoPtr))
5033 /* append items */
5034 FIXME("append items\n");
5037 else if (nItems < GETITEMCOUNT(infoPtr))
5039 /* remove items */
5040 FIXME("remove items\n");
5044 return TRUE;
5047 /***
5048 * DESCRIPTION:
5049 * Sets the position of an item.
5051 * PARAMETER(S):
5052 * [I] HWND : window handle
5053 * [I] INT : item index
5054 * [I] INT : x coordinate
5055 * [I] INT : y coordinate
5057 * RETURN:
5058 * SUCCESS : TRUE
5059 * FAILURE : FALSE
5061 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5062 INT nPosX, INT nPosY)
5064 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5065 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5066 LISTVIEW_ITEM *lpItem;
5067 HDPA hdpaSubItems;
5068 BOOL bResult = FALSE;
5070 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5072 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5074 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5076 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5077 if (hdpaSubItems != NULL)
5079 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5080 if (lpItem != NULL)
5082 bResult = TRUE;
5083 lpItem->ptPosition.x = nPosX;
5084 lpItem->ptPosition.y = nPosY;
5090 return bResult;
5093 /* LISTVIEW_SetItemPosition32 */
5095 /***
5096 * DESCRIPTION:
5097 * Sets the state of one or many items.
5099 * PARAMETER(S):
5100 * [I] HWND : window handle
5101 * [I]INT : item index
5102 * [I] LPLVITEM : item or subitem info
5104 * RETURN:
5105 * SUCCESS : TRUE
5106 * FAILURE : FALSE
5108 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5110 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5111 BOOL bResult = FALSE;
5112 LVITEMA lvItem;
5113 INT i;
5115 if (nItem == -1)
5117 bResult = TRUE;
5118 ZeroMemory(&lvItem, sizeof(LVITEMA));
5119 lvItem.mask = LVIF_STATE;
5120 lvItem.state = lpLVItem->state;
5121 lvItem.stateMask = lpLVItem->stateMask ;
5123 /* apply to all items */
5124 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
5126 lvItem.iItem = i;
5127 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
5129 bResult = FALSE;
5133 else
5135 ZeroMemory(&lvItem, sizeof(LVITEMA));
5136 lvItem.mask = LVIF_STATE;
5137 lvItem.state = lpLVItem->state;
5138 lvItem.stateMask = lpLVItem->stateMask;
5139 lvItem.iItem = nItem;
5140 bResult = ListView_SetItemA(hwnd, &lvItem);
5143 return bResult;
5146 /***
5147 * DESCRIPTION:
5148 * Sets the text of an item or subitem.
5150 * PARAMETER(S):
5151 * [I] HWND : window handle
5152 * [I] INT : item index
5153 * [I] LPLVITEMA : item or subitem info
5155 * RETURN:
5156 * SUCCESS : TRUE
5157 * FAILURE : FALSE
5159 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5161 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5162 BOOL bResult = FALSE;
5163 LVITEMA lvItem;
5165 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5167 ZeroMemory(&lvItem, sizeof(LVITEMA));
5168 lvItem.mask = LVIF_TEXT;
5169 lvItem.pszText = lpLVItem->pszText;
5170 lvItem.iItem = nItem;
5171 lvItem.iSubItem = lpLVItem->iSubItem;
5172 bResult = ListView_SetItemA(hwnd, &lvItem);
5175 return bResult;
5178 /* LISTVIEW_SetItemTextW */
5180 /***
5181 * DESCRIPTION:
5182 * Set item index that marks the start of a multiple selection.
5184 * PARAMETER(S):
5185 * [I] HWND : window handle
5186 * [I] INT : index
5188 * RETURN:
5189 * Index number or -1 if there is no selection mark.
5191 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
5193 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5194 INT nOldIndex = infoPtr->nSelectionMark;
5196 infoPtr->nSelectionMark = nIndex;
5198 return nOldIndex;
5201 /***
5202 * DESCRIPTION:
5203 * Sets the text background color.
5205 * PARAMETER(S):
5206 * [I] HWND : window handle
5207 * [I] COLORREF : text background color
5209 * RETURN:
5210 * SUCCESS : TRUE
5211 * FAILURE : FALSE
5213 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
5215 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5217 infoPtr->clrTextBk = clrTextBk;
5218 InvalidateRect(hwnd, NULL, TRUE);
5220 return TRUE;
5223 /***
5224 * DESCRIPTION:
5225 * Sets the text foreground color.
5227 * PARAMETER(S):
5228 * [I] HWND : window handle
5229 * [I] COLORREF : text color
5231 * RETURN:
5232 * SUCCESS : TRUE
5233 * FAILURE : FALSE
5235 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
5237 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5239 infoPtr->clrText = clrText;
5240 InvalidateRect(hwnd, NULL, TRUE);
5242 return TRUE;
5245 /* LISTVIEW_SetToolTips */
5246 /* LISTVIEW_SetUnicodeFormat */
5247 /* LISTVIEW_SetWorkAreas */
5249 /***
5250 * DESCRIPTION:
5251 * Callback internally used by LISTVIEW_SortItems()
5253 * PARAMETER(S):
5254 * [I] LPVOID : first LISTVIEW_ITEM to compare
5255 * [I] LPVOID : second LISTVIEW_ITEM to compare
5256 * [I] LPARAM : HWND of control
5258 * RETURN:
5259 * if first comes before second : negative
5260 * if first comes after second : positive
5261 * if first and second are equivalent : zero
5263 static INT WINAPI LISTVIEW_CallBackCompare(
5264 LPVOID first,
5265 LPVOID second,
5266 LPARAM lParam)
5268 /* Forward the call to the client defined callback */
5269 HWND hwnd = (HWND)lParam;
5270 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5272 return (infoPtr->pfnCompare)(
5273 ((LISTVIEW_ITEM *)first)->lParam,
5274 ((LISTVIEW_ITEM *)second)->lParam,
5275 infoPtr->lParamSort);
5278 /***
5279 * DESCRIPTION:
5280 * Sorts the listview items.
5282 * PARAMETER(S):
5283 * [I] HWND : window handle
5284 * [I] WPARAM : application-defined value
5285 * [I] LPARAM : pointer to comparision callback
5287 * RETURN:
5288 * SUCCESS : TRUE
5289 * FAILURE : FALSE
5291 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
5293 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5294 HDPA hdpaSubItems;
5295 LISTVIEW_ITEM *lpItem;
5296 int nCount, i;
5297 HDPA sortList;
5299 if (!infoPtr || !infoPtr->hdpaItems)
5300 return FALSE;
5302 nCount = GETITEMCOUNT(infoPtr);
5303 /* if there are 0 or 1 items, there is no need to sort */
5304 if (nCount > 1)
5306 sortList = DPA_Create(nCount);
5308 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
5309 infoPtr->lParamSort = (LPARAM)wParam;
5311 /* append pointers one by one to sortList */
5312 for (i = 0; i < nCount; i++)
5314 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
5315 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
5316 DPA_InsertPtr(sortList, nCount + 1, lpItem);
5319 /* sort the sortList */
5320 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
5322 /* copy the pointers back */
5323 for (i = 0; i < nCount; i++)
5325 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
5326 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
5327 DPA_SetPtr(hdpaSubItems, 0, lpItem);
5330 DPA_Destroy(sortList);
5333 return TRUE;
5336 /* LISTVIEW_SubItemHitTest */
5338 /***
5339 * DESCRIPTION:
5340 * Updates an items or rearranges the listview control.
5342 * PARAMETER(S):
5343 * [I] HWND : window handle
5344 * [I] INT : item index
5346 * RETURN:
5347 * SUCCESS : TRUE
5348 * FAILURE : FALSE
5350 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
5352 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5353 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5354 BOOL bResult = FALSE;
5355 RECT rc;
5357 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5359 bResult = TRUE;
5361 /* rearrange with default alignment style */
5362 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
5363 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
5365 ListView_Arrange(hwnd, 0);
5367 else
5369 /* get item bounding rectangle */
5370 rc.left = LVIR_BOUNDS;
5371 ListView_GetItemRect(hwnd, nItem, &rc);
5372 InvalidateRect(hwnd, &rc, TRUE);
5376 return bResult;
5379 /***
5380 * DESCRIPTION:
5381 * Creates the listview control.
5383 * PARAMETER(S):
5384 * [I] HWND : window handle
5386 * RETURN:
5387 * Zero
5389 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
5391 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5392 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
5393 UINT uView = lpcs->style & LVS_TYPEMASK;
5394 LOGFONTA logFont;
5396 /* initialize info pointer */
5397 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
5399 /* determine the type of structures to use */
5400 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
5401 (WPARAM)hwnd, (LPARAM)NF_QUERY);
5402 if (infoPtr->notifyFormat != NFR_ANSI)
5404 FIXME("ANSI notify format is NOT used\n");
5407 /* initialize color information */
5408 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
5409 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
5410 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
5412 /* set default values */
5413 infoPtr->uCallbackMask = 0;
5414 infoPtr->nFocusedItem = -1;
5415 infoPtr->nSelectionMark = -1;
5416 infoPtr->nHotItem = -1;
5417 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
5418 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
5419 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
5421 /* get default font (icon title) */
5422 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5423 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
5424 infoPtr->hFont = infoPtr->hDefaultFont;
5426 /* create header */
5427 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
5428 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
5429 0, 0, 0, 0, hwnd, (HMENU)0,
5430 lpcs->hInstance, NULL);
5432 /* set header font */
5433 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
5434 (LPARAM)TRUE);
5436 if (uView == LVS_ICON)
5438 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
5439 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
5441 else if (uView == LVS_REPORT)
5443 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
5445 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
5448 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5449 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5451 else
5453 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
5454 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
5457 /* display unsupported listview window styles */
5458 LISTVIEW_UnsupportedStyles(lpcs->style);
5460 /* allocate memory for the data structure */
5461 infoPtr->hdpaItems = DPA_Create(10);
5463 /* initialize size of items */
5464 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5465 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
5467 return 0;
5470 /***
5471 * DESCRIPTION:
5472 * Erases the background of the listview control.
5474 * PARAMETER(S):
5475 * [I] HWND : window handle
5476 * [I] WPARAM : device context handle
5477 * [I] LPARAM : not used
5479 * RETURN:
5480 * SUCCESS : TRUE
5481 * FAILURE : FALSE
5483 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
5484 LPARAM lParam)
5486 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5487 BOOL bResult;
5489 if (infoPtr->clrBk == CLR_NONE)
5491 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
5493 else
5495 RECT rc;
5496 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
5497 GetClientRect(hwnd, &rc);
5498 FillRect((HDC)wParam, &rc, hBrush);
5499 DeleteObject(hBrush);
5500 bResult = TRUE;
5503 return bResult;
5506 /***
5507 * DESCRIPTION:
5508 * Retrieves the listview control font.
5510 * PARAMETER(S):
5511 * [I] HWND : window handle
5513 * RETURN:
5514 * Font handle.
5516 static LRESULT LISTVIEW_GetFont(HWND hwnd)
5518 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5520 return infoPtr->hFont;
5523 /***
5524 * DESCRIPTION:
5525 * Performs vertical scrolling.
5527 * PARAMETER(S):
5528 * [I] HWND : window handle
5529 * [I] INT : scroll code
5530 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5531 * or SB_THUMBTRACK.
5532 * [I] HWND : scrollbar control window handle
5534 * RETURN:
5535 * Zero
5537 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5538 HWND hScrollWnd)
5540 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5541 SCROLLINFO scrollInfo;
5543 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5544 scrollInfo.cbSize = sizeof(SCROLLINFO);
5545 scrollInfo.fMask = /*SIF_PAGE |*/ SIF_POS | SIF_RANGE;
5547 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
5549 INT nOldScrollPos = scrollInfo.nPos;
5550 switch (nScrollCode)
5552 case SB_LINEUP:
5553 if (scrollInfo.nPos > scrollInfo.nMin)
5555 scrollInfo.nPos--;
5557 break;
5559 case SB_LINEDOWN:
5560 if (scrollInfo.nPos < scrollInfo.nMax)
5562 scrollInfo.nPos++;
5564 break;
5566 case SB_PAGEUP:
5567 if (scrollInfo.nPos > scrollInfo.nMin)
5569 INT nPage = 0;
5571 if (uView == LVS_REPORT)
5573 nPage = LISTVIEW_GetCountPerColumn(hwnd);
5575 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5577 nPage = 10;
5580 if (scrollInfo.nPos >= nPage)
5582 scrollInfo.nPos -= nPage;
5584 else
5586 scrollInfo.nPos = scrollInfo.nMin;
5589 break;
5591 case SB_PAGEDOWN:
5592 if (scrollInfo.nPos < scrollInfo.nMax)
5594 INT nPage = 0;
5596 if (uView == LVS_REPORT)
5598 nPage = LISTVIEW_GetCountPerColumn(hwnd);
5600 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5602 nPage = 10;
5605 if (scrollInfo.nPos <= scrollInfo.nMax - nPage)
5607 scrollInfo.nPos += nPage;
5609 else
5611 scrollInfo.nPos = scrollInfo.nMax;
5614 break;
5616 case SB_THUMBPOSITION:
5617 break;
5620 if (nOldScrollPos != scrollInfo.nPos)
5622 scrollInfo.fMask = SIF_POS;
5623 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
5624 InvalidateRect(hwnd, NULL, TRUE);
5628 return 0;
5631 /***
5632 * DESCRIPTION:
5633 * Performs horizontal scrolling.
5635 * PARAMETER(S):
5636 * [I] HWND : window handle
5637 * [I] INT : scroll code
5638 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5639 * or SB_THUMBTRACK.
5640 * [I] HWND : scrollbar control window handle
5642 * RETURN:
5643 * Zero
5645 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
5646 HWND hScrollWnd)
5648 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5649 SCROLLINFO scrollInfo;
5651 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
5652 scrollInfo.cbSize = sizeof(SCROLLINFO);
5653 scrollInfo.fMask = /*SIF_PAGE |*/ SIF_POS | SIF_RANGE;
5655 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
5657 INT nOldScrollPos = scrollInfo.nPos;
5659 switch (nScrollCode)
5661 case SB_LINELEFT:
5662 if (scrollInfo.nPos > scrollInfo.nMin)
5664 scrollInfo.nPos--;
5666 break;
5668 case SB_LINERIGHT:
5669 if (scrollInfo.nPos < scrollInfo.nMax)
5671 scrollInfo.nPos++;
5673 break;
5675 case SB_PAGELEFT:
5676 if (scrollInfo.nPos > scrollInfo.nMin)
5678 INT nPage = 0;
5680 if (uView == LVS_LIST)
5682 nPage = LISTVIEW_GetCountPerRow(hwnd);
5684 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5686 nPage = 10;
5689 if (scrollInfo.nPos >= nPage)
5691 scrollInfo.nPos -= nPage;
5693 else
5695 scrollInfo.nPos = scrollInfo.nMin;
5698 break;
5700 case SB_PAGERIGHT:
5701 if (scrollInfo.nPos < scrollInfo.nMax)
5703 INT nPage = 0;
5705 if (uView == LVS_LIST)
5707 nPage = LISTVIEW_GetCountPerRow(hwnd);
5709 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5711 nPage = 10;
5714 if (scrollInfo.nPos <= scrollInfo.nMax - nPage)
5716 scrollInfo.nPos += nPage;
5718 else
5720 scrollInfo.nPos = scrollInfo.nMax;
5723 break;
5725 case SB_THUMBPOSITION:
5726 break;
5729 if (nOldScrollPos != scrollInfo.nPos)
5731 scrollInfo.fMask = SIF_POS;
5732 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
5733 InvalidateRect(hwnd, NULL, TRUE);
5737 return 0;
5740 /***
5741 * DESCRIPTION:
5742 * ???
5744 * PARAMETER(S):
5745 * [I] HWND : window handle
5746 * [I] INT : virtual key
5747 * [I] LONG : key data
5749 * RETURN:
5750 * Zero
5752 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
5754 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5755 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5756 HWND hwndParent = GetParent(hwnd);
5757 NMLVKEYDOWN nmKeyDown;
5758 NMHDR nmh;
5759 INT nItem = -1;
5760 BOOL bRedraw = FALSE;
5762 /* send LVN_KEYDOWN notification */
5763 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
5764 nmKeyDown.hdr.hwndFrom = hwnd;
5765 nmKeyDown.hdr.idFrom = nCtrlId;
5766 nmKeyDown.hdr.code = LVN_KEYDOWN;
5767 nmKeyDown.wVKey = nVirtualKey;
5768 nmKeyDown.flags = 0;
5769 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
5771 /* initialize */
5772 nmh.hwndFrom = hwnd;
5773 nmh.idFrom = nCtrlId;
5775 switch (nVirtualKey)
5777 case VK_RETURN:
5778 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
5780 /* send NM_RETURN notification */
5781 nmh.code = NM_RETURN;
5782 ListView_Notify(hwndParent, nCtrlId, &nmh);
5784 /* send LVN_ITEMACTIVATE notification */
5785 nmh.code = LVN_ITEMACTIVATE;
5786 ListView_Notify(hwndParent, nCtrlId, &nmh);
5788 break;
5790 case VK_HOME:
5791 if (GETITEMCOUNT(infoPtr) > 0)
5793 nItem = 0;
5795 break;
5797 case VK_END:
5798 if (GETITEMCOUNT(infoPtr) > 0)
5800 nItem = GETITEMCOUNT(infoPtr) - 1;
5802 break;
5804 case VK_LEFT:
5805 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
5806 break;
5808 case VK_UP:
5809 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
5810 break;
5812 case VK_RIGHT:
5813 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
5814 break;
5816 case VK_DOWN:
5817 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
5818 break;
5820 case VK_PRIOR:
5821 /* TO DO */
5822 break;
5824 case VK_NEXT:
5825 /* TO DO */
5826 break;
5829 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
5831 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
5832 if (bRedraw != FALSE)
5834 /* refresh client area */
5835 InvalidateRect(hwnd, NULL, TRUE);
5836 UpdateWindow(hwnd);
5840 return 0;
5843 /***
5844 * DESCRIPTION:
5845 * Kills the focus.
5847 * PARAMETER(S):
5848 * [I] HWND : window handle
5850 * RETURN:
5851 * Zero
5853 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
5855 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5856 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5857 NMHDR nmh;
5859 /* send NM_KILLFOCUS notification */
5860 nmh.hwndFrom = hwnd;
5861 nmh.idFrom = nCtrlId;
5862 nmh.code = NM_KILLFOCUS;
5863 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5865 /* set window focus flag */
5866 infoPtr->bFocus = FALSE;
5868 /* NEED drawing optimization ; redraw the selected items */
5869 InvalidateRect(hwnd, NULL, FALSE);
5871 return 0;
5874 /***
5875 * DESCRIPTION:
5876 * Processes double click messages (left mouse button).
5878 * PARAMETER(S):
5879 * [I] HWND : window handle
5880 * [I] WORD : key flag
5881 * [I] WORD : x coordinate
5882 * [I] WORD : y coordinate
5884 * RETURN:
5885 * Zero
5887 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
5888 WORD wPosY)
5890 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5891 NMHDR nmh;
5893 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
5895 /* send NM_DBLCLK notification */
5896 nmh.hwndFrom = hwnd;
5897 nmh.idFrom = nCtrlId;
5898 nmh.code = NM_DBLCLK;
5899 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5901 /* send LVN_ITEMACTIVATE notification */
5902 nmh.code = LVN_ITEMACTIVATE;
5903 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5905 return 0;
5908 /***
5909 * DESCRIPTION:
5910 * Processes mouse down messages (left mouse button).
5912 * PARAMETER(S):
5913 * [I] HWND : window handle
5914 * [I] WORD : key flag
5915 * [I] WORD : x coordinate
5916 * [I] WORD : y coordinate
5918 * RETURN:
5919 * Zero
5921 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
5922 WORD wPosY)
5924 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5925 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5926 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
5927 static BOOL bGroupSelect = TRUE;
5928 POINT ptPosition;
5929 NMHDR nmh;
5930 INT nItem;
5932 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
5933 wPosY);
5935 /* send NM_RELEASEDCAPTURE notification */
5936 nmh.hwndFrom = hwnd;
5937 nmh.idFrom = nCtrlId;
5938 nmh.code = NM_RELEASEDCAPTURE;
5939 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
5941 if (infoPtr->bFocus == FALSE)
5943 SetFocus(hwnd);
5946 /* set left button down flag */
5947 infoPtr->bLButtonDown = TRUE;
5949 ptPosition.x = wPosX;
5950 ptPosition.y = wPosY;
5951 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
5952 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
5954 if (lStyle & LVS_SINGLESEL)
5956 LISTVIEW_SetSelection(hwnd, nItem);
5958 else
5960 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
5962 if (bGroupSelect != FALSE)
5964 LISTVIEW_AddGroupSelection(hwnd, nItem);
5966 else
5968 LISTVIEW_AddSelection(hwnd, nItem);
5971 else if (wKey & MK_CONTROL)
5973 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
5975 else if (wKey & MK_SHIFT)
5977 LISTVIEW_SetGroupSelection(hwnd, nItem);
5979 else
5981 LISTVIEW_SetSelection(hwnd, nItem);
5985 else
5987 /* remove all selections */
5988 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
5991 InvalidateRect(hwnd, NULL, TRUE);
5993 return 0;
5996 /***
5997 * DESCRIPTION:
5998 * Processes mouse up messages (left mouse button).
6000 * PARAMETER(S):
6001 * [I] HWND : window handle
6002 * [I] WORD : key flag
6003 * [I] WORD : x coordinate
6004 * [I] WORD : y coordinate
6006 * RETURN:
6007 * Zero
6009 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6010 WORD wPosY)
6012 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6014 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6016 if (infoPtr->bLButtonDown != FALSE)
6018 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6019 NMHDR nmh;
6021 /* send NM_CLICK notification */
6022 nmh.hwndFrom = hwnd;
6023 nmh.idFrom = nCtrlId;
6024 nmh.code = NM_CLICK;
6025 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6027 /* set left button flag */
6028 infoPtr->bLButtonDown = FALSE;
6031 return 0;
6034 /***
6035 * DESCRIPTION:
6036 * Creates the listview control (called before WM_CREATE).
6038 * PARAMETER(S):
6039 * [I] HWND : window handle
6040 * [I] WPARAM : unhandled
6041 * [I] LPARAM : widow creation info
6043 * RETURN:
6044 * Zero
6046 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
6048 LISTVIEW_INFO *infoPtr;
6050 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
6052 /* allocate memory for info structure */
6053 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
6054 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
6055 if (infoPtr == NULL)
6057 ERR("could not allocate info memory!\n");
6058 return 0;
6061 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
6063 ERR("pointer assignment error!\n");
6064 return 0;
6067 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
6070 /***
6071 * DESCRIPTION:
6072 * Destroys the listview control (called after WM_DESTROY).
6074 * PARAMETER(S):
6075 * [I] HWND : window handle
6077 * RETURN:
6078 * Zero
6080 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
6082 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6084 TRACE("(hwnd=%x)\n", hwnd);
6086 /* delete all items */
6087 LISTVIEW_DeleteAllItems(hwnd);
6089 /* destroy data structure */
6090 DPA_Destroy(infoPtr->hdpaItems);
6092 /* destroy font */
6093 infoPtr->hFont = (HFONT)0;
6094 if (infoPtr->hDefaultFont)
6096 DeleteObject(infoPtr->hDefaultFont);
6099 /* free listview info pointer*/
6100 COMCTL32_Free(infoPtr);
6102 return 0;
6105 /***
6106 * DESCRIPTION:
6107 * Handles notifications from children.
6109 * PARAMETER(S):
6110 * [I] HWND : window handle
6111 * [I] INT : control identifier
6112 * [I] LPNMHDR : notification information
6114 * RETURN:
6115 * Zero
6117 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
6119 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6121 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
6123 /* handle notification from header control */
6124 if (lpnmh->code == HDN_ENDTRACKA)
6126 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6127 InvalidateRect(hwnd, NULL, TRUE);
6131 return 0;
6134 /***
6135 * DESCRIPTION:
6136 * Determines the type of structure to use.
6138 * PARAMETER(S):
6139 * [I] HWND : window handle of the sender
6140 * [I] HWND : listview window handle
6141 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6143 * RETURN:
6144 * Zero
6146 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
6148 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6150 if (nCommand == NF_REQUERY)
6152 /* determine the type of structure to use */
6153 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
6154 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6155 if (infoPtr->notifyFormat == NFR_UNICODE)
6157 FIXME("NO support for unicode structures");
6161 return 0;
6164 /***
6165 * DESCRIPTION:
6166 * Paints/Repaints the listview control.
6168 * PARAMETER(S):
6169 * [I] HWND : window handle
6170 * [I] HDC : device context handle
6172 * RETURN:
6173 * Zero
6175 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
6177 PAINTSTRUCT ps;
6179 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
6181 if (hdc == 0)
6183 hdc = BeginPaint(hwnd, &ps);
6184 LISTVIEW_Refresh(hwnd, hdc);
6185 EndPaint(hwnd, &ps);
6187 else
6189 LISTVIEW_Refresh(hwnd, hdc);
6192 return 0;
6195 /***
6196 * DESCRIPTION:
6197 * Processes double click messages (right mouse button).
6199 * PARAMETER(S):
6200 * [I] HWND : window handle
6201 * [I] WORD : key flag
6202 * [I] WORD : x coordinate
6203 * [I] WORD : y coordinate
6205 * RETURN:
6206 * Zero
6208 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6209 WORD wPosY)
6211 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6212 NMHDR nmh;
6214 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6216 /* send NM_RELEASEDCAPTURE notification */
6217 nmh.hwndFrom = hwnd;
6218 nmh.idFrom = nCtrlId;
6219 nmh.code = NM_RELEASEDCAPTURE;
6220 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6222 /* send NM_RDBLCLK notification */
6223 nmh.code = NM_RDBLCLK;
6224 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6226 return 0;
6229 /***
6230 * DESCRIPTION:
6231 * Processes mouse down messages (right mouse button).
6233 * PARAMETER(S):
6234 * [I] HWND : window handle
6235 * [I] WORD : key flag
6236 * [I] WORD : x coordinate
6237 * [I] WORD : y coordinate
6239 * RETURN:
6240 * Zero
6242 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6243 WORD wPosY)
6245 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6246 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6247 POINT ptPosition;
6248 NMHDR nmh;
6249 INT nItem;
6251 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6253 /* send NM_RELEASEDCAPTURE notification */
6254 nmh.hwndFrom = hwnd;
6255 nmh.idFrom = nCtrlId;
6256 nmh.code = NM_RELEASEDCAPTURE;
6257 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6259 /* make sure the listview control window has the focus */
6260 if (infoPtr->bFocus == FALSE)
6262 SetFocus(hwnd);
6265 /* set right button down flag */
6266 infoPtr->bRButtonDown = TRUE;
6268 /* determine the index of the selected item */
6269 ptPosition.x = wPosX;
6270 ptPosition.y = wPosY;
6271 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6272 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6274 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
6276 LISTVIEW_SetSelection(hwnd, nItem);
6279 else
6281 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6284 return 0;
6287 /***
6288 * DESCRIPTION:
6289 * Processes mouse up messages (right mouse button).
6291 * PARAMETER(S):
6292 * [I] HWND : window handle
6293 * [I] WORD : key flag
6294 * [I] WORD : x coordinate
6295 * [I] WORD : y coordinate
6297 * RETURN:
6298 * Zero
6300 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6301 WORD wPosY)
6303 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6304 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6305 NMHDR nmh;
6307 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6309 if (infoPtr->bRButtonDown != FALSE)
6311 /* send NM_RClICK notification */
6312 ZeroMemory(&nmh, sizeof(NMHDR));
6313 nmh.hwndFrom = hwnd;
6314 nmh.idFrom = nCtrlId;
6315 nmh.code = NM_RCLICK;
6316 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6318 /* set button flag */
6319 infoPtr->bRButtonDown = FALSE;
6322 return 0;
6325 /***
6326 * DESCRIPTION:
6327 * Sets the focus.
6329 * PARAMETER(S):
6330 * [I] HWND : window handle
6331 * [I] HWND : window handle of previously focused window
6333 * RETURN:
6334 * Zero
6336 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
6338 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6339 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6340 NMHDR nmh;
6342 /* send NM_SETFOCUS notification */
6343 nmh.hwndFrom = hwnd;
6344 nmh.idFrom = nCtrlId;
6345 nmh.code = NM_SETFOCUS;
6346 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6348 /* set window focus flag */
6349 infoPtr->bFocus = TRUE;
6351 return 0;
6354 /***
6355 * DESCRIPTION:
6356 * Sets the font.
6358 * PARAMETER(S):
6359 * [I] HWND : window handle
6360 * [I] HFONT : font handle
6361 * [I] WORD : redraw flag
6363 * RETURN:
6364 * Zero
6366 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
6368 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6369 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6371 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
6373 if (hFont == 0)
6375 infoPtr->hFont = infoPtr->hDefaultFont;
6377 else
6379 infoPtr->hFont = hFont;
6382 if (uView == LVS_REPORT)
6384 /* set header font */
6385 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
6386 MAKELPARAM(fRedraw, 0));
6389 /* invalidate listview control client area */
6390 InvalidateRect(hwnd, NULL, TRUE);
6392 if (fRedraw != FALSE)
6394 UpdateWindow(hwnd);
6397 return 0;
6400 /***
6401 * DESCRIPTION:
6402 * Resizes the listview control. This function processes WM_SIZE
6403 * messages. At this time, the width and height are not used.
6405 * PARAMETER(S):
6406 * [I] HWND : window handle
6407 * [I] WORD : new width
6408 * [I] WORD : new height
6410 * RETURN:
6411 * Zero
6413 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
6415 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6416 UINT uView = lStyle & LVS_TYPEMASK;
6418 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
6420 LISTVIEW_UpdateSize(hwnd);
6422 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
6424 if (lStyle & LVS_ALIGNLEFT)
6426 LISTVIEW_AlignLeft(hwnd);
6428 else
6430 LISTVIEW_AlignTop(hwnd);
6434 LISTVIEW_UpdateScroll(hwnd);
6436 /* invalidate client area + erase background */
6437 InvalidateRect(hwnd, NULL, TRUE);
6439 return 0;
6442 /***
6443 * DESCRIPTION:
6444 * Sets the size information.
6446 * PARAMETER(S):
6447 * [I] HWND : window handle
6449 * RETURN:
6450 * Zero
6452 static VOID LISTVIEW_UpdateSize(HWND hwnd)
6454 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6455 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6456 UINT uView = lStyle & LVS_TYPEMASK;
6457 RECT rcList;
6459 GetClientRect(hwnd, &rcList);
6460 infoPtr->rcList.left = 0;
6461 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
6462 infoPtr->rcList.top = 0;
6463 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
6465 if (uView == LVS_LIST)
6467 if ((lStyle & WS_HSCROLL) == 0)
6469 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
6470 if (infoPtr->rcList.bottom > nHScrollHeight)
6472 infoPtr->rcList.bottom -= nHScrollHeight;
6476 else if (uView == LVS_REPORT)
6478 HDLAYOUT hl;
6479 WINDOWPOS wp;
6481 hl.prc = &rcList;
6482 hl.pwpos = &wp;
6483 Header_Layout(infoPtr->hwndHeader, &hl);
6484 if (!(LVS_NOCOLUMNHEADER & lStyle))
6486 infoPtr->rcList.top = max(wp.cy, 0);
6491 /***
6492 * DESCRIPTION:
6493 * Processes WM_STYLECHANGED messages.
6495 * PARAMETER(S):
6496 * [I] HWND : window handle
6497 * [I] WPARAM : window style type (normal or extended)
6498 * [I] LPSTYLESTRUCT : window style information
6500 * RETURN:
6501 * Zero
6503 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
6504 LPSTYLESTRUCT lpss)
6506 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6507 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
6508 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
6509 RECT rcList = infoPtr->rcList;
6511 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
6512 hwnd, wStyleType, lpss);
6514 if (wStyleType == GWL_STYLE)
6516 if (uOldView == LVS_REPORT)
6518 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
6521 if ((lpss->styleOld & WS_HSCROLL) != 0)
6523 ShowScrollBar(hwnd, SB_HORZ, FALSE);
6526 if ((lpss->styleOld & WS_VSCROLL) != 0)
6528 ShowScrollBar(hwnd, SB_VERT, FALSE);
6531 if (uNewView == LVS_ICON)
6533 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6534 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6535 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6536 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6537 if (lpss->styleNew & LVS_ALIGNLEFT)
6539 LISTVIEW_AlignLeft(hwnd);
6541 else
6543 LISTVIEW_AlignTop(hwnd);
6546 else if (uNewView == LVS_REPORT)
6548 HDLAYOUT hl;
6549 WINDOWPOS wp;
6551 hl.prc = &rcList;
6552 hl.pwpos = &wp;
6553 Header_Layout(infoPtr->hwndHeader, &hl);
6554 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
6555 wp.flags);
6556 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
6558 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6560 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6561 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6562 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6563 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6565 else if (uNewView == LVS_LIST)
6567 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6568 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6569 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6570 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6572 else
6574 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6575 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6576 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6577 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6578 if (lpss->styleNew & LVS_ALIGNLEFT)
6580 LISTVIEW_AlignLeft(hwnd);
6582 else
6584 LISTVIEW_AlignTop(hwnd);
6588 /* update the size of the client area */
6589 LISTVIEW_UpdateSize(hwnd);
6591 /* add scrollbars if needed */
6592 LISTVIEW_UpdateScroll(hwnd);
6594 /* invalidate client area + erase background */
6595 InvalidateRect(hwnd, NULL, TRUE);
6597 /* print the list of unsupported window styles */
6598 LISTVIEW_UnsupportedStyles(lpss->styleNew);
6601 return 0;
6604 /***
6605 * DESCRIPTION:
6606 * Window procedure of the listview control.
6609 LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
6610 LPARAM lParam)
6612 switch (uMsg)
6614 case LVM_APPROXIMATEVIEWRECT:
6615 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
6616 LOWORD(lParam), HIWORD(lParam));
6617 case LVM_ARRANGE:
6618 return LISTVIEW_Arrange(hwnd, (INT)wParam);
6620 /* case LVM_CREATEDRAGIMAGE: */
6622 case LVM_DELETEALLITEMS:
6623 return LISTVIEW_DeleteAllItems(hwnd);
6625 case LVM_DELETECOLUMN:
6626 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
6628 case LVM_DELETEITEM:
6629 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
6631 /* case LVM_EDITLABEL: */
6633 case LVM_ENSUREVISIBLE:
6634 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
6636 case LVM_FINDITEMA:
6637 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
6639 case LVM_GETBKCOLOR:
6640 return LISTVIEW_GetBkColor(hwnd);
6642 /* case LVM_GETBKIMAGE: */
6644 case LVM_GETCALLBACKMASK:
6645 return LISTVIEW_GetCallbackMask(hwnd);
6647 case LVM_GETCOLUMNA:
6648 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6650 /* case LVM_GETCOLUMNW: */
6652 case LVM_GETCOLUMNORDERARRAY:
6653 FIXME("Unimplemented msg LVM_GETCOLUMNORDERARRAY\n");
6654 return 0;
6656 case LVM_GETCOLUMNWIDTH:
6657 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
6659 case LVM_GETCOUNTPERPAGE:
6660 return LISTVIEW_GetCountPerPage(hwnd);
6662 /* case LVM_GETEDITCONTROL: */
6664 case LVM_GETEXTENDEDLISTVIEWSTYLE:
6665 return LISTVIEW_GetExtendedListViewStyle(hwnd);
6667 case LVM_GETHEADER:
6668 return LISTVIEW_GetHeader(hwnd);
6670 /* case LVM_GETHOTCURSOR: */
6672 case LVM_GETHOTITEM:
6673 return LISTVIEW_GetHotItem(hwnd);
6675 /* case LVM_GETHOVERTIME: */
6677 case LVM_GETIMAGELIST:
6678 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
6680 /* case LVM_GETISEARCHSTRING: */
6682 case LVM_GETITEMA:
6683 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam);
6685 /* case LVM_GETITEMW: */
6687 case LVM_GETITEMCOUNT:
6688 return LISTVIEW_GetItemCount(hwnd);
6690 case LVM_GETITEMPOSITION:
6691 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
6693 case LVM_GETITEMRECT:
6694 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
6696 case LVM_GETITEMSPACING:
6697 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
6699 case LVM_GETITEMSTATE:
6700 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
6702 case LVM_GETITEMTEXTA:
6703 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6704 break;
6706 /* case LVM_GETITEMTEXTW: */
6708 case LVM_GETNEXTITEM:
6709 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
6711 /* case LVM_GETNUMBEROFWORKAREAS: */
6713 case LVM_GETORIGIN:
6714 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
6716 case LVM_GETSELECTEDCOUNT:
6717 return LISTVIEW_GetSelectedCount(hwnd);
6719 case LVM_GETSELECTIONMARK:
6720 return LISTVIEW_GetSelectionMark(hwnd);
6722 case LVM_GETSTRINGWIDTHA:
6723 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
6725 /* case LVM_GETSTRINGWIDTHW: */
6726 /* case LVM_GETSUBITEMRECT: */
6728 case LVM_GETTEXTBKCOLOR:
6729 return LISTVIEW_GetTextBkColor(hwnd);
6731 case LVM_GETTEXTCOLOR:
6732 return LISTVIEW_GetTextColor(hwnd);
6734 /* case LVM_GETTOOLTIPS: */
6736 case LVM_GETTOPINDEX:
6737 return LISTVIEW_GetTopIndex(hwnd);
6739 /* case LVM_GETUNICODEFORMAT: */
6741 case LVM_GETVIEWRECT:
6742 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
6744 /* case LVM_GETWORKAREAS: */
6746 case LVM_HITTEST:
6747 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
6749 case LVM_INSERTCOLUMNA:
6750 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam,
6751 (LPLVCOLUMNA)lParam);
6753 /* case LVM_INSERTCOLUMNW: */
6755 case LVM_INSERTITEMA:
6756 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
6758 /* case LVM_INSERTITEMW: */
6760 case LVM_REDRAWITEMS:
6761 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
6763 /* case LVM_SCROLL: */
6764 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
6766 case LVM_SETBKCOLOR:
6767 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
6769 /* case LVM_SETBKIMAGE: */
6771 case LVM_SETCALLBACKMASK:
6772 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
6774 case LVM_SETCOLUMNA:
6775 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
6777 case LVM_SETCOLUMNW:
6778 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
6779 return 0;
6781 case LVM_SETCOLUMNORDERARRAY:
6782 FIXME("Unimplemented msg LVM_SETCOLUMNORDERARRAY\n");
6783 return 0;
6785 case LVM_SETCOLUMNWIDTH:
6786 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, (INT)lParam);
6788 case LVM_SETEXTENDEDLISTVIEWSTYLE:
6789 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
6791 /* case LVM_SETHOTCURSOR: */
6793 case LVM_SETHOTITEM:
6794 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
6796 /* case LVM_SETHOVERTIME: */
6797 /* case LVM_SETICONSPACING: */
6799 case LVM_SETIMAGELIST:
6800 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
6802 case LVM_SETITEMA:
6803 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
6805 /* case LVM_SETITEMW: */
6807 case LVM_SETITEMCOUNT:
6808 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
6810 case LVM_SETITEMPOSITION:
6811 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
6812 (INT)HIWORD(lParam));
6814 /* case LVM_SETITEMPOSITION32: */
6816 case LVM_SETITEMSTATE:
6817 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6819 case LVM_SETITEMTEXTA:
6820 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
6822 /* case LVM_SETITEMTEXTW: */
6824 case LVM_SETSELECTIONMARK:
6825 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
6827 case LVM_SETTEXTBKCOLOR:
6828 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
6830 case LVM_SETTEXTCOLOR:
6831 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
6833 /* case LVM_SETTOOLTIPS: */
6834 /* case LVM_SETUNICODEFORMAT: */
6835 /* case LVM_SETWORKAREAS: */
6837 case LVM_SORTITEMS:
6838 return LISTVIEW_SortItems(hwnd, wParam, lParam);
6840 /* case LVM_SUBITEMHITTEST: */
6842 case LVM_UPDATE:
6843 return LISTVIEW_Update(hwnd, (INT)wParam);
6845 /* case WM_CHAR: */
6846 /* case WM_COMMAND: */
6848 case WM_CREATE:
6849 return LISTVIEW_Create(hwnd, wParam, lParam);
6851 case WM_ERASEBKGND:
6852 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
6854 case WM_GETDLGCODE:
6855 return DLGC_WANTTAB | DLGC_WANTARROWS;
6857 case WM_GETFONT:
6858 return LISTVIEW_GetFont(hwnd);
6860 case WM_HSCROLL:
6861 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
6862 (INT)HIWORD(wParam), (HWND)lParam);
6864 case WM_KEYDOWN:
6865 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
6867 case WM_KILLFOCUS:
6868 return LISTVIEW_KillFocus(hwnd);
6870 case WM_LBUTTONDBLCLK:
6871 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6872 HIWORD(lParam));
6874 case WM_LBUTTONDOWN:
6875 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6876 HIWORD(lParam));
6877 case WM_LBUTTONUP:
6878 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6879 HIWORD(lParam));
6881 /* case WM_MOUSEMOVE: */
6882 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
6884 case WM_NCCREATE:
6885 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
6887 case WM_NCDESTROY:
6888 return LISTVIEW_NCDestroy(hwnd);
6890 case WM_NOTIFY:
6891 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
6893 case WM_NOTIFYFORMAT:
6894 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
6896 case WM_PAINT:
6897 return LISTVIEW_Paint(hwnd, (HDC)wParam);
6899 case WM_RBUTTONDBLCLK:
6900 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
6901 HIWORD(lParam));
6903 case WM_RBUTTONDOWN:
6904 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
6905 HIWORD(lParam));
6907 case WM_RBUTTONUP:
6908 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
6909 HIWORD(lParam));
6911 case WM_SETFOCUS:
6912 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
6914 case WM_SETFONT:
6915 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
6917 /* case WM_SETREDRAW: */
6919 case WM_SIZE:
6920 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
6922 case WM_STYLECHANGED:
6923 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
6925 /* case WM_TIMER: */
6927 case WM_VSCROLL:
6928 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
6929 (INT)HIWORD(wParam), (HWND)lParam);
6931 /* case WM_WINDOWPOSCHANGED: */
6932 /* case WM_WININICHANGE: */
6934 default:
6935 if (uMsg >= WM_USER)
6937 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
6938 lParam);
6941 /* call default window procedure */
6942 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
6945 return 0;
6948 /***
6949 * DESCRIPTION:
6950 * Registers the window class.
6952 * PARAMETER(S):
6953 * None
6955 * RETURN:
6956 * None
6958 VOID LISTVIEW_Register(void)
6960 WNDCLASSA wndClass;
6962 if (!GlobalFindAtomA(WC_LISTVIEWA))
6964 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
6965 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
6966 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
6967 wndClass.cbClsExtra = 0;
6968 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
6969 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
6970 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
6971 wndClass.lpszClassName = WC_LISTVIEWA;
6972 RegisterClassA(&wndClass);
6976 /***
6977 * DESCRIPTION:
6978 * Unregisters the window class.
6980 * PARAMETER(S):
6981 * None
6983 * RETURN:
6984 * None
6986 VOID LISTVIEW_Unregister(void)
6988 if (GlobalFindAtomA(WC_LISTVIEWA))
6990 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);