4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
8 * Listview control implementation.
11 * 1. No horizontal scrolling when header is larger than the client area.
12 * 2. Drawing optimizations.
13 * 3. Hot item handling.
16 * LISTVIEW_Notify : most notifications from children (editbox and header)
19 * LISTVIEW_SetItemCount : empty stub
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
48 #include "debugtools.h"
50 DEFAULT_DEBUG_CHANNEL(listview
)
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
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)
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
);
132 * Update the scrollbars. This functions should be called whenever
133 * the content, size or view changes.
136 * [I] HWND : window handle
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
;
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
);
178 if (lStyle
& WS_HSCROLL
)
180 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
184 else if (uView
== LVS_REPORT
)
186 /* update vertical scrollbar */
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) */
197 /* scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; */
198 /* SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE); */
201 /* horizontal scrolling has not been implemented yet! I experienced some
202 problems when performing child window scrolling. */
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
)
216 INT nScrollPosWidth
= nListWidth
/ 10;
218 if (nScrollPosWidth
== 0)
221 nHiddenWidth
= nViewWidth
- nListWidth
;
225 nHiddenWidth
= nViewWidth
- nScrollPosWidth
* 10;
228 scrollInfo
.fMask
= SIF_POS
;
229 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) == FALSE
)
234 if (nHiddenWidth
% nScrollPosWidth
== 0)
236 scrollInfo
.nMax
= nHiddenWidth
/ nScrollPosWidth
;
240 scrollInfo
.nMax
= nHiddenWidth
/ nScrollPosWidth
+ 1;
244 /*scrollInfo.nPage = 10;*/
245 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
/*| SIF_PAGE*/;
246 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
250 if (lStyle
& WS_HSCROLL
)
252 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
256 if (nViewHeight
> nListHeight
)
259 INT nScrollPosHeight
= nListHeight
/ 10;
261 if (nScrollPosHeight
== 0)
263 nScrollPosHeight
= 1;
264 nHiddenHeight
= nViewHeight
- nListHeight
;
268 nHiddenHeight
= nViewHeight
- nScrollPosHeight
* 10;
271 scrollInfo
.fMask
= SIF_POS
;
272 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) == FALSE
)
277 if (nHiddenHeight
% nScrollPosHeight
== 0)
279 scrollInfo
.nMax
= nHiddenHeight
/ nScrollPosHeight
;
283 scrollInfo
.nMax
= nHiddenHeight
/ nScrollPosHeight
+ 1;
287 /*scrollInfo.nPage = 10;*/
288 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
/*| SIF_PAGE*/;
289 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
293 if (lStyle
& WS_VSCROLL
)
295 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
304 * Prints a message for unsupported window styles.
305 * A kind of TODO list for window styles.
308 * [I] LONG : window style
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");
358 * Aligns the items with the top edge of the window.
361 * [I] HWND : window handle
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
;
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
)
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
;
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
);
415 * Aligns the items with the left edge of the window.
418 * [I] HWND : window handle
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
;
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
)
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
;
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
);
472 * Set the bounding rectangle of all the items.
475 * [I] HWND : window handle
476 * [I] LPRECT : bounding rectangle
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
)
493 infoPtr
->rcView
.left
= lprcView
->left
;
494 infoPtr
->rcView
.top
= lprcView
->top
;
495 infoPtr
->rcView
.right
= lprcView
->right
;
496 infoPtr
->rcView
.bottom
= lprcView
->bottom
;
504 * Retrieves the bounding rectangle of all the items.
507 * [I] HWND : window handle
508 * [O] LPRECT : bounding rectangle
514 static LRESULT
LISTVIEW_GetViewRect(HWND hwnd
, LPRECT lprcView
)
516 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
517 BOOL bResult
= FALSE
;
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
);
542 * Retrieves the subitem pointer associated with the subitem index.
545 * [I] HDPA : DPA handle for a specific item
546 * [I] INT : index of subitem
549 * SUCCESS : subitem pointer
552 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems
,
555 LISTVIEW_SUBITEM
*lpSubItem
;
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
)
575 * Calculates the width of an item.
578 * [I] HWND : window handle
579 * [I] LONG : window style
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
;
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
);
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
;
629 nItemWidth
= DEFAULT_LABEL_WIDTH
;
634 nItemWidth
+= WIDTH_PADDING
;
636 if (infoPtr
->himlSmall
!= NULL
)
638 nItemWidth
+= infoPtr
->iconSize
.cx
;
641 if (infoPtr
->himlState
!= NULL
)
643 nItemWidth
+= infoPtr
->iconSize
.cx
;
654 * Calculates the height of an item.
657 * [I] HWND : window handle
658 * [I] LONG : window style
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
;
669 if (uView
== LVS_ICON
)
671 nItemHeight
= infoPtr
->iconSpacing
.cy
;
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
);
689 * Adds a block of selections.
692 * [I] HWND : window handle
693 * [I] INT : item index
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
);
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
;
720 * Adds a single selection.
723 * [I] HWND : window handle
724 * [I] INT : item index
729 static VOID
LISTVIEW_AddSelection(HWND hwnd
, INT nItem
)
731 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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
;
745 * Selects or unselects an item.
748 * [I] HWND : window handle
749 * [I] INT : item index
755 static BOOL
LISTVIEW_ToggleSelection(HWND hwnd
, INT nItem
)
757 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
761 lvItem
.stateMask
= LVIS_SELECTED
;
763 if (ListView_GetItemState(hwnd
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
)
766 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
771 lvItem
.state
= LVIS_SELECTED
;
772 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
776 LISTVIEW_SetItemFocus(hwnd
, nItem
);
777 infoPtr
->nSelectionMark
= nItem
;
784 * Selects items based on view coorddiantes.
787 * [I] HWND : window handle
788 * [I] RECT : selection rectangle
793 static VOID
LISTVIEW_SetSelectionRect(HWND hwnd
, RECT rcSelRect
)
795 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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
;
814 ListView_SetItemState(hwnd
, i
, &lvItem
);
820 * Sets a single group selection.
823 * [I] HWND : window handle
824 * [I] INT : item index
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
;
835 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
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
))
850 lvItem
.state
= LVIS_SELECTED
;
853 ListView_SetItemState(hwnd
, i
, &lvItem
);
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
);
875 * Manages the item focus.
878 * [I] HWND : window handle
879 * [I] INT : item index
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
;
891 if (infoPtr
->nFocusedItem
!= nItem
)
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
);
911 * Sets a single selection.
914 * [I] HWND : window handle
915 * [I] INT : item index
920 static VOID
LISTVIEW_SetSelection(HWND hwnd
, INT nItem
)
922 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 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
;
949 * Set selection(s) with keyboard.
952 * [I] HWND : window handle
953 * [I] INT : item index
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
)
972 LISTVIEW_SetSelection(hwnd
, nItem
);
973 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
980 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
984 bResult
= LISTVIEW_SetItemFocus(hwnd
, nItem
);
989 LISTVIEW_SetSelection(hwnd
, nItem
);
990 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
1000 * Selects an item based on coordinates.
1003 * [I] HWND : window handle
1004 * [I] POINT : mouse click ccordinates
1007 * SUCCESS : item index
1010 static LRESULT
LISTVIEW_MouseSelection(HWND hwnd
, POINT pt
)
1012 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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
)
1033 * Removes all selection states.
1036 * [I] HWND : window handle
1037 * [I] INT : item index
1043 static VOID
LISTVIEW_RemoveSelections(HWND hwnd
, INT nFirst
, INT nLast
)
1049 lvItem
.stateMask
= LVIS_SELECTED
;
1051 for (i
= nFirst
; i
<= nLast
; i
++)
1053 ListView_SetItemState(hwnd
, i
, &lvItem
);
1062 * [IO] HDPA : dynamic pointer array handle
1063 * [I] INT : column index (subitem index)
1069 static BOOL
LISTVIEW_RemoveColumn(HDPA hdpaItems
, INT nSubItem
)
1071 BOOL bResult
= TRUE
;
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
)
1092 * Removes a subitem at a given position.
1095 * [IO] HDPA : dynamic pointer array handle
1096 * [I] INT : subitem index
1102 static BOOL
LISTVIEW_RemoveSubItem(HDPA hdpaSubItems
, INT nSubItem
)
1104 LISTVIEW_SUBITEM
*lpSubItem
;
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
)
1115 if ((lpSubItem
->pszText
!= NULL
) &&
1116 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1118 COMCTL32_Free(lpSubItem
->pszText
);
1122 COMCTL32_Free(lpSubItem
);
1124 /* free dpa memory */
1125 if (DPA_DeletePtr(hdpaSubItems
, i
) == NULL
)
1130 else if (lpSubItem
->iSubItem
> nSubItem
)
1142 * Compares the item information.
1145 * [I] LISTVIEW_ITEM *: destination item
1146 * [I] LPLVITEM : source item
1149 * SUCCCESS : TRUE (EQUAL)
1150 * FAILURE : FALSE (NOT EQUAL)
1152 static UINT
LISTVIEW_GetItemChanges(LISTVIEW_ITEM
*lpItem
, LPLVITEMA lpLVItem
)
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
;
1202 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1204 uChanged
|= LVIF_TEXT
;
1208 if (lpLVItem
->pszText
)
1210 if (lpItem
->pszText
)
1212 if (strcmp(lpLVItem
->pszText
, lpItem
->pszText
) != 0)
1214 uChanged
|= LVIF_TEXT
;
1219 uChanged
|= LVIF_TEXT
;
1224 if (lpItem
->pszText
)
1226 uChanged
|= LVIF_TEXT
;
1238 * Initializes item attributes.
1241 * [I] HWND : window handle
1242 * [O] LISTVIEW_ITEM *: destination item
1243 * [I] LPLVITEM : source item
1249 static BOOL
LISTVIEW_InitItem(HWND hwnd
, LISTVIEW_ITEM
*lpItem
,
1252 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1253 BOOL bResult
= FALSE
;
1255 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
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
))
1289 if ((lpItem
->pszText
!= NULL
) &&
1290 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1292 COMCTL32_Free(lpItem
->pszText
);
1295 lpItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1299 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1301 lpItem
->pszText
= NULL
;
1304 bResult
= Str_SetPtrA(&lpItem
->pszText
, lpLVItem
->pszText
);
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.
1320 * [I] HWND : window handle
1321 * [O] LISTVIEW_SUBITEM *: destination subitem
1322 * [I] LPLVITEM : source subitem
1328 static BOOL
LISTVIEW_InitSubItem(HWND hwnd
, LISTVIEW_SUBITEM
*lpSubItem
,
1331 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1332 BOOL bResult
= FALSE
;
1334 if ((lpSubItem
!= NULL
) && (lpLVItem
!= NULL
))
1336 if (!(lpLVItem
->mask
& LVIF_INDENT
))
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
))
1357 if ((lpSubItem
->pszText
!= NULL
) &&
1358 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1360 COMCTL32_Free(lpSubItem
->pszText
);
1363 lpSubItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1367 if (lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1369 lpSubItem
->pszText
= NULL
;
1372 bResult
= Str_SetPtrA(&lpSubItem
->pszText
, lpLVItem
->pszText
);
1383 * Adds a subitem at a given position (column index).
1386 * [I] HWND : window handle
1387 * [I] LPLVITEM : new subitem atttributes
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
;
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
);
1423 /* cleanup if unsuccessful */
1424 if ((bResult
== FALSE
) && (lpSubItem
!= NULL
))
1426 COMCTL32_Free(lpSubItem
);
1434 * Finds the dpa insert position (array index).
1437 * [I] HWND : window handle
1438 * [I] INT : subitem index
1444 static INT
LISTVIEW_FindInsertPosition(HDPA hdpaSubItems
, INT nSubItem
)
1446 LISTVIEW_SUBITEM
*lpSubItem
;
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
)
1461 return hdpaSubItems
->nItemCount
;
1466 * Retrieves a listview subitem at a given position (column index).
1469 * [I] HWND : window handle
1470 * [I] INT : subitem index
1476 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA hdpaSubItems
, INT nSubItem
)
1478 LISTVIEW_SUBITEM
*lpSubItem
;
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
)
1490 else if (lpSubItem
->iSubItem
> nSubItem
)
1502 * Sets item attributes.
1505 * [I] HWND : window handle
1506 * [I] LPLVITEM : new item atttributes
1512 static BOOL
LISTVIEW_SetItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1514 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1515 BOOL bResult
= FALSE
;
1517 LISTVIEW_ITEM
*lpItem
;
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
);
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
);
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
);
1564 InvalidateRect(hwnd
, NULL
, FALSE
);
1575 * Sets subitem attributes.
1578 * [I] HWND : window handle
1579 * [I] LPLVITEM : new subitem atttributes
1585 static BOOL
LISTVIEW_SetSubItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1587 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1588 BOOL bResult
= FALSE
;
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
);
1609 bResult
= LISTVIEW_AddSubItem(hwnd
, lpLVItem
);
1612 InvalidateRect(hwnd
, NULL
, FALSE
);
1623 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1626 * [I] HWND : window handle
1631 static INT
LISTVIEW_GetTopIndex(HWND hwnd
)
1633 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1634 UINT uView
= lStyle
& LVS_TYPEMASK
;
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
;
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
1680 static VOID
LISTVIEW_DrawSubItem(HWND hwnd
, HDC hdc
, INT nItem
, INT nSubItem
,
1683 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1684 CHAR szDispText
[DISP_TEXT_SIZE
];
1687 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd
, hdc
,
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
);
1713 * [I] HWND : window handle
1714 * [I] HDC : device context handle
1715 * [I] INT : item index
1716 * [I] RECT * : clipping rectangle
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
];
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
);
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
;
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
);
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
);
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
;
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
);
1817 SetROP2(hdc
, R2_COPYPEN
);
1818 SetBkColor(hdc
, infoPtr
->clrTextBk
);
1819 SetTextColor(hdc
, infoPtr
->clrText
);
1825 * Draws an item when in large icon display mode.
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
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
;
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
,
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
);
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
);
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
;
1898 rcItem
.left
+= nDrawPosX
/ 2;
1899 rcItem
.right
= rcItem
.left
+ nLabelWidth
;
1904 rcItem
.right
= rcItem
.left
+ infoPtr
->iconSpacing
.cx
- 1;
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
);
1921 * Draws listview items when in report display mode.
1924 * [I] HWND : window handle
1925 * [I] HDC : device context handle
1930 static VOID
LISTVIEW_RefreshReport(HWND hwnd
, HDC hdc
)
1932 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
1933 INT nDrawPosY
= infoPtr
->rcList
.top
;
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
;
1957 LISTVIEW_DrawItem(hwnd
, hdc
, nItem
, rcItem
);
1961 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, j
, rcItem
);
1965 nDrawPosY
+= infoPtr
->nItemHeight
;
1971 * Retrieves the number of items that can fit vertically in the client area.
1974 * [I] HWND : window handle
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;
1988 if (uView
== LVS_REPORT
)
1994 nCountPerRow
= nListWidth
/ infoPtr
->nItemWidth
;
1995 if (nCountPerRow
== 0)
2002 return nCountPerRow
;
2007 * Retrieves the number of items that can fit horizontally in the client
2011 * [I] HWND : window handle
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
;
2036 * Retrieves the number of columns needed to display all the items when in
2037 * list display mode.
2040 * [I] HWND : window handle
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
;
2059 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nItemWidth
+ 1;
2063 return nColumnCount
;
2069 * Draws listview items when in list display mode.
2072 * [I] HWND : window handle
2073 * [I] HDC : device context handle
2078 static VOID
LISTVIEW_RefreshList(HWND hwnd
, HDC hdc
)
2080 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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
))
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
);
2110 * Draws listview items when in icon or small icon display mode.
2113 * [I] HWND : window handle
2114 * [I] HDC : device context handle
2119 static VOID
LISTVIEW_RefreshIcon(HWND hwnd
, HDC hdc
, BOOL bSmall
)
2121 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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
);
2152 LISTVIEW_DrawItem(hwnd
, hdc
, i
, rcItem
);
2163 * Draws listview items.
2166 * [I] HWND : window handle
2167 * [I] HDC : device context handle
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
;
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
);
2217 * Calculates the approximate width and height of a given number of items.
2220 * [I] HWND : window handle
2221 * [I] INT : number of items
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
;
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
;
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
)
2286 else if (uView
== LVS_SMALLICON
)
2290 else if (uView
== LVS_ICON
)
2300 * Arranges listview items in icon display mode.
2303 * [I] HWND : window handle
2304 * [I] INT : alignment code
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
))
2328 case LVA_SNAPTOGRID
:
2337 /* << LISTVIEW_CreateDragImage >> */
2341 * Removes all listview items and subitems.
2344 * [I] HWND : window handle
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
;
2360 BOOL bResult
= FALSE
;
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
;
2378 /* verify if subsequent LVN_DELETEITEM notifications should be
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
);
2400 COMCTL32_Free(lpSubItem
);
2404 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2407 if (bSuppress
== FALSE
)
2409 /* send LVN_DELETEITEM notification */
2410 nmlv
.hdr
.code
= LVN_DELETEITEM
;
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
);
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
);
2443 LISTVIEW_AlignTop(hwnd
);
2447 LISTVIEW_UpdateScroll(hwnd
);
2449 /* invalidate client area (optimization needed) */
2450 InvalidateRect(hwnd
, NULL
, TRUE
);
2458 * Removes a column from the listview control.
2461 * [I] HWND : window handle
2462 * [I] INT : column index
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
);
2494 * Removes an item from the listview control.
2497 * [I] HWND : window handle
2498 * [I] INT : item index
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
);
2511 BOOL bResult
= FALSE
;
2513 LISTVIEW_ITEM
*lpItem
;
2514 LISTVIEW_SUBITEM
*lpSubItem
;
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
);
2540 COMCTL32_Free(lpSubItem
);
2544 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2547 /* send LVN_DELETEITEM notification */
2548 nmlv
.hdr
.hwndFrom
= hwnd
;
2549 nmlv
.hdr
.idFrom
= lCtrlId
;
2550 nmlv
.hdr
.code
= LVN_DELETEITEM
;
2552 nmlv
.lParam
= lpItem
->lParam
;
2553 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
2556 /* free item string */
2557 if ((lpItem
->pszText
!= NULL
) &&
2558 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2560 COMCTL32_Free(lpItem
->pszText
);
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
);
2579 LISTVIEW_AlignTop(hwnd
);
2583 LISTVIEW_UpdateScroll(hwnd
);
2585 /* refresh client area */
2586 InvalidateRect(hwnd
, NULL
, TRUE
);
2592 /* LISTVIEW_EditLabel */
2596 * Ensures the specified item is visible, scrolling into view if necessary.
2599 * [I] HWND : window handle
2600 * [I] INT : item index
2601 * [I] BOOL : partially or entirely visible
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
;
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
)
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
;
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
)
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
;
2677 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
+ 1;
2680 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
2684 if (rcItem
.top
< infoPtr
->rcList
.top
)
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
;
2706 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
- 1;
2709 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
2712 else if (rcItem
.bottom
> infoPtr
->rcList
.bottom
)
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
;
2734 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
+ 1;
2737 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
2747 * Retrieves the nearest item, given a position and a direction.
2750 * [I] HWND : window handle
2751 * [I] POINT : start position
2752 * [I] UINT : direction
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
;
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
)
2796 nItem
= LISTVIEW_HitTestItem(hwnd
, &lvHitTestInfo
);
2800 while (nItem
== -1);
2808 * Searches for an item with specific characteristics.
2811 * [I] HWND : window handle
2812 * [I] INT : base item index
2813 * [I] LPLVFINDINFO : item information to look for
2816 * SUCCESS : index of item
2819 static LRESULT
LISTVIEW_FindItem(HWND hwnd
, INT nStart
,
2820 LPLVFINDINFO lpFindInfo
)
2822 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2824 CHAR szDispText
[DISP_TEXT_SIZE
];
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
)
2858 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
2860 ptItem
.x
= lpFindInfo
->pt
.x
;
2861 ptItem
.y
= lpFindInfo
->pt
.y
;
2866 while (nItem
< nLast
)
2868 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
2870 nItem
= LISTVIEW_GetNearestItem(hwnd
, ptItem
,
2871 lpFindInfo
->vkDirection
);
2874 /* get position of the new item index */
2875 if (ListView_GetItemPosition(hwnd
, nItem
, &ptItem
) == FALSE
)
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
)
2899 if (strcmp(lvItem
.pszText
, lpFindInfo
->psz
) != 0)
2904 if (lvItem
.mask
& LVIF_PARAM
)
2906 if (lpFindInfo
->lParam
!= lvItem
.lParam
)
2932 * Retrieves the background color of the listview control.
2935 * [I] HWND : window handle
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
;
2949 * Retrieves the background image of the listview control.
2952 * [I] HWND : window handle
2953 * [O] LPLVMKBIMAGE : background image attributes
2959 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
2961 /* FIXME (listview, "empty stub!\n"); */
2967 * Retrieves the callback mask.
2970 * [I] HWND : window handle
2975 static UINT
LISTVIEW_GetCallbackMask(HWND hwnd
)
2977 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2979 return infoPtr
->uCallbackMask
;
2984 * Retrieves column attributes.
2987 * [I] HWND : window handle
2988 * [I] INT : column index
2989 * [IO] LPLVCOLUMNA : column information
2995 static LRESULT
LISTVIEW_GetColumnA(HWND hwnd
, INT nItem
, LPLVCOLUMNA lpColumn
)
2997 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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
)
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
;
3087 /* LISTVIEW_GetColumnW */
3088 /* LISTVIEW_GetColumnOrderArray */
3092 * Retrieves the column width.
3095 * [I] HWND : window handle
3096 * [I] int : column index
3099 * SUCCESS : column width
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;
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
;
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.
3134 * [I] HWND : window handle
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
;
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
);
3159 nItemCount
= GETITEMCOUNT(infoPtr
);
3165 /* LISTVIEW_GetEditControl */
3169 * Retrieves the extended listview style.
3172 * [I] HWND : window handle
3175 * SUCCESS : previous style
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)))
3186 return (infoPtr
->dwExStyle
);
3191 * Retrieves the handle to the header control.
3194 * [I] HWND : window 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 */
3212 * Retrieves an image list handle.
3215 * [I] HWND : window handle
3216 * [I] INT : image list identifier
3219 * SUCCESS : image list handle
3222 static LRESULT
LISTVIEW_GetImageList(HWND hwnd
, INT nImageList
)
3224 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3225 HIMAGELIST himl
= NULL
;
3230 himl
= infoPtr
->himlNormal
;
3233 himl
= infoPtr
->himlSmall
;
3236 himl
= infoPtr
->himlState
;
3240 return (LRESULT
)himl
;
3243 /* LISTVIEW_GetISearchString */
3247 * Retrieves item attributes.
3250 * [I] HWND : window handle
3251 * [IO] LPLVITEMA : item info
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
;
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);
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
;
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
;
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
)
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
;
3440 /* LISTVIEW_GetItemW */
3441 /* LISTVIEW_GetHotCursor */
3445 * Retrieves the index of the hot item.
3448 * [I] HWND : window handle
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)))
3462 return (infoPtr
->nHotItem
);
3465 /* LISTVIEW_GetHoverTime */
3469 * Retrieves the number of items in the listview control.
3472 * [I] HWND : window handle
3477 static LRESULT
LISTVIEW_GetItemCount(HWND hwnd
)
3479 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3481 return GETITEMCOUNT(infoPtr
);
3486 * Retrieves the position (upper-left) of the listview control item.
3489 * [I] HWND : window handle
3490 * [I] INT : item index
3491 * [O] LPPOINT : coordinate information
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
;
3504 LISTVIEW_ITEM
*lpItem
;
3505 INT nCountPerColumn
;
3508 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd
, nItem
,
3511 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) &&
3512 (lpptPosition
!= NULL
))
3514 if (uView
== LVS_LIST
)
3517 nItem
= nItem
- ListView_GetTopIndex(hwnd
);
3518 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
3521 nRow
= nItem
% nCountPerColumn
;
3524 lpptPosition
->x
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
3525 lpptPosition
->y
= 0;
3529 lpptPosition
->x
= (nItem
/ nCountPerColumn
-1) * infoPtr
->nItemWidth
;
3530 lpptPosition
->y
= (nRow
+ nCountPerColumn
) * infoPtr
->nItemHeight
;
3535 lpptPosition
->x
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
3536 lpptPosition
->y
= nItem
% nCountPerColumn
* infoPtr
->nItemHeight
;
3539 else if (uView
== LVS_REPORT
)
3542 lpptPosition
->x
= REPORT_MARGINX
;
3543 lpptPosition
->y
= ((nItem
- ListView_GetTopIndex(hwnd
)) *
3544 infoPtr
->nItemHeight
) + infoPtr
->rcList
.top
;
3548 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
3549 if (hdpaSubItems
!= NULL
)
3551 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
3555 lpptPosition
->x
= lpItem
->ptPosition
.x
;
3556 lpptPosition
->y
= lpItem
->ptPosition
.y
;
3567 * Retrieves the bounding rectangle for a listview control item.
3570 * [I] HWND : window handle
3571 * [I] INT : item index
3572 * [IO] LPRECT : bounding rectangle coordinates
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
;
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
)
3600 if (uView
== LVS_ICON
)
3602 if (infoPtr
->himlNormal
!= NULL
)
3604 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
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
)
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
;
3630 lprc
->right
= lprc
->left
;
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
;
3651 lprc
->right
= lprc
->left
;
3657 if (uView
== LVS_ICON
)
3659 if (infoPtr
->himlNormal
!= NULL
)
3661 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
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
;
3676 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
- 1;
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
)
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
;
3714 lprc
->right
= nMaxWidth
+ infoPtr
->nItemWidth
;
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
);
3740 if (uView
== LVS_ICON
)
3742 if (infoPtr
->himlNormal
!= NULL
)
3744 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
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
)
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
);
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
);
3792 case LVIR_SELECTBOUNDS
:
3793 if (uView
== LVS_ICON
)
3795 if (infoPtr
->himlNormal
!= NULL
)
3797 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
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
)
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
);
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
);
3862 * Retrieves the width of a label.
3865 * [I] HWND : window handle
3868 * SUCCESS : string width (in pixels)
3871 static INT
LISTVIEW_GetLabelWidth(HWND hwnd
, INT nItem
)
3873 CHAR szDispText
[DISP_TEXT_SIZE
];
3874 INT nLabelWidth
= 0;
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
);
3894 * Retrieves the spacing between listview control items.
3897 * [I] HWND : window handle
3898 * [I] BOOL : flag for small or large icon
3901 * Horizontal + vertical spacing
3903 static LRESULT
LISTVIEW_GetItemSpacing(HWND hwnd
, BOOL bSmall
)
3905 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3908 if (bSmall
== FALSE
)
3910 lResult
= MAKELONG(infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
3914 /* TODO: need to store width of smallicon item */
3915 lResult
= MAKELONG(0, infoPtr
->nItemHeight
);
3923 * Retrieves the state of a listview control item.
3926 * [I] HWND : window handle
3927 * [I] INT : item index
3928 * [I] UINT : state mask
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);
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
;
3956 * Retrieves the text of a listview control item or subitem.
3959 * [I] HWND : window handle
3960 * [I] INT : item index
3961 * [IO] LPLVITEMA : item information
3964 * SUCCESS : string length
3967 static LRESULT
LISTVIEW_GetItemTextA(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
3969 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 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
);
3990 * Searches for an item based on properties + relationships.
3993 * [I] HWND : window handle
3994 * [I] INT : item index
3995 * [I] INT : relationship flag
3998 * SUCCESS : item index
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
;
4006 LVFINDINFO lvFindInfo
;
4007 INT nCountPerColumn
;
4010 if ((nItem
>= -1) && (nItem
< GETITEMCOUNT(infoPtr
)))
4012 ZeroMemory(&lvFindInfo
, sizeof(LVFINDINFO
));
4014 if (uFlags
& LVNI_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
))
4033 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
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
)
4049 else if (uFlags
& LVNI_BELOW
)
4051 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
4053 while (nItem
< GETITEMCOUNT(infoPtr
))
4056 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
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
)
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
)
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
)
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
)
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
)
4124 /* search by index */
4125 for (i
= nItem
; i
< GETITEMCOUNT(infoPtr
); i
++)
4127 if ((ListView_GetItemState(hwnd
, i
, uMask
) & uMask
) == uMask
)
4136 /* LISTVIEW_GetNumberOfWorkAreas */
4140 * Retrieves the origin coordinates when in icon or small icon display mode.
4143 * [I] HWND : window handle
4144 * [O] LPPOINT : coordinate information
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);
4194 * Retrieves the number of items that are marked as selected.
4197 * [I] HWND : window handle
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;
4208 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
4210 if (ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
) & LVIS_SELECTED
)
4216 return nSelectedCount
;
4221 * Retrieves item index that marks the start of a multiple selection.
4224 * [I] HWND : window handle
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
;
4238 * Retrieves the width of a string.
4241 * [I] HWND : window handle
4244 * SUCCESS : string width (in pixels)
4247 static LRESULT
LISTVIEW_GetStringWidthA(HWND hwnd
, LPCSTR lpszText
)
4249 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4250 HFONT hFont
, hOldFont
;
4254 ZeroMemory(&stringSize
, sizeof(SIZE
));
4255 if (lpszText
!= NULL
)
4257 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
;
4259 hOldFont
= SelectObject(hdc
, hFont
);
4260 GetTextExtentPointA(hdc
, lpszText
, lstrlenA(lpszText
), &stringSize
);
4261 SelectObject(hdc
, hOldFont
);
4262 ReleaseDC(hwnd
, hdc
);
4265 return stringSize
.cx
;
4270 * Retrieves the text backgound color.
4273 * [I] HWND : window handle
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
;
4287 * Retrieves the text color.
4290 * [I] HWND : window handle
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
;
4304 * Determines which section of the item was selected (if any).
4307 * [I] HWND : window handle
4308 * [IO] LPLVHITTESTINFO : hit test information
4311 * SUCCESS : item index
4314 static INT
LISTVIEW_HitTestItem(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
4316 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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;
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;
4354 lpHitTestInfo
->flags
= LVHT_ONITEMSTATEICON
;
4355 lpHitTestInfo
->iItem
= i
;
4356 lpHitTestInfo
->iSubItem
= 0;
4362 lpHitTestInfo
->flags
= LVHT_NOWHERE
;
4369 * Determines which listview item is located at the specified position.
4372 * [I] HWND : window handle
4373 * [IO} LPLVHITTESTINFO : hit test information
4376 * SUCCESS : item index
4379 static LRESULT
LISTVIEW_HitTest(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
4381 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
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
);
4413 * Inserts a new column.
4416 * [I] HWND : window handle
4417 * [I] INT : column index
4418 * [I] LPLVCOLUMNA : column information
4421 * SUCCESS : new column index
4424 static LRESULT
LISTVIEW_InsertColumnA(HWND hwnd
, INT nColumn
,
4425 LPLVCOLUMNA lpColumn
)
4427 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4429 INT nNewColumn
= -1;
4431 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd
, nColumn
,
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) */
4447 hdi
.fmt
|= HDF_LEFT
;
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
;
4471 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
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
);
4520 /* LISTVIEW_InsertColumnW */
4524 * Inserts a new item in the listview control.
4527 * [I] HWND : window handle
4528 * [I] LPLVITEMA : item information
4531 * SUCCESS : new item index
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
);
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
));
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
);
4565 nItem
= DPA_InsertPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
,
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
;
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
);
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
);
4620 /* LISTVIEW_InsertItemW */
4624 * Redraws a range of items.
4627 * [I] HWND : window handle
4628 * [I] INT : first item
4629 * [I] INT : last item
4635 static LRESULT
LISTVIEW_RedrawItems(HWND hwnd
, INT nFirst
, INT nLast
)
4637 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4638 BOOL bResult
= FALSE
;
4641 if (nFirst
<= nLast
)
4643 if ((nFirst
>= 0) && (nFirst
< GETITEMCOUNT(infoPtr
)))
4645 if ((nLast
>= 0) && (nLast
< GETITEMCOUNT(infoPtr
)))
4648 InvalidateRect(hwnd
, &rc
, FALSE
);
4656 /* LISTVIEW_Scroll */
4660 * Sets the background color.
4663 * [I] HWND : window handle
4664 * [I] COLORREF : background color
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
);
4680 /* LISTVIEW_SetBkImage */
4684 * Sets the callback mask. This mask will be used when the parent
4685 * window stores state information (some or all).
4688 * [I] HWND : window handle
4689 * [I] UINT : state mask
4695 static BOOL
LISTVIEW_SetCallbackMask(HWND hwnd
, UINT uMask
)
4697 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4699 infoPtr
->uCallbackMask
= uMask
;
4706 * Sets the attributes of a header item.
4709 * [I] HWND : window handle
4710 * [I] INT : column index
4711 * [I] LPLVCOLUMNA : column attributes
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) */
4744 hdi
.fmt
|= HDF_LEFT
;
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
);
4812 /* LISTVIEW_SetColumnW */
4813 /* LISTVIEW_SetColumnOrderArray */
4817 * Sets the width of a column
4820 * [I] HWND : window handle
4821 * [I] INT : column index
4822 * [I] INT : column width
4828 static LRESULT
LISTVIEW_SetColumnWidth(HWND hwnd
, INT iCol
, INT cx
)
4830 LISTVIEW_INFO
*infoPtr
;
4835 /* set column width only if in report mode */
4836 lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4837 if ((lStyle
& LVS_TYPEMASK
) != LVS_REPORT
)
4840 /* make sure we can get the listview info */
4841 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
4843 if (!infoPtr
->hwndHeader
) /* make sure we have a header */
4846 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
4847 * LVSCV_AUTOSIZE_USEHEADER (-2)
4852 hdi
.mask
= HDI_WIDTH
;
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 */
4867 * Sets the extended listview style.
4870 * [I] HWND : window handle
4875 * SUCCESS : previous style
4878 static LRESULT
LISTVIEW_SetExtendedListViewStyle(HWND hwnd
, DWORD dwMask
, DWORD dwStyle
)
4880 LISTVIEW_INFO
*infoPtr
;
4883 /* make sure we can get the listview info */
4884 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
4887 /* store previous style */
4888 dwOldStyle
= infoPtr
->dwExStyle
;
4891 infoPtr
->dwExStyle
= (dwOldStyle
& ~dwMask
) | (dwStyle
& dwMask
);
4893 return (dwOldStyle
);
4896 /* LISTVIEW_SetHotCursor */
4900 * Sets the hot item index.
4903 * [I] HWND : window handle
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
;
4915 /* make sure we can get the listview info */
4916 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
4919 /* store previous index */
4920 iOldIndex
= infoPtr
->nHotItem
;
4923 infoPtr
->nHotItem
= iIndex
;
4928 /* LISTVIEW_SetIconSpacing */
4935 * [I] HWND : window handle
4936 * [I] INT : image list type
4937 * [I] HIMAGELIST : image list handle
4940 * SUCCESS : old image list
4943 static LRESULT
LISTVIEW_SetImageList(HWND hwnd
, INT nType
, HIMAGELIST himl
)
4945 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4946 HIMAGELIST himlTemp
= 0;
4951 himlTemp
= infoPtr
->himlNormal
;
4952 infoPtr
->himlNormal
= himl
;
4953 return (LRESULT
)himlTemp
;
4956 himlTemp
= infoPtr
->himlSmall
;
4957 infoPtr
->himlSmall
= himl
;
4958 return (LRESULT
)himlTemp
;
4961 himlTemp
= infoPtr
->himlState
;
4962 infoPtr
->himlState
= himl
;
4963 ImageList_SetBkColor(infoPtr
->himlState
, CLR_NONE
);
4964 return (LRESULT
)himlTemp
;
4967 return (LRESULT
)NULL
;
4973 * Sets the attributes of an item.
4976 * [I] HWND : window handle
4977 * [I] LPLVITEM : item information
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
);
4998 bResult
= LISTVIEW_SetSubItem(hwnd
, lpLVItem
);
5007 /* LISTVIEW_SetItemW */
5011 * Preallocates memory.
5014 * [I] HWND : window handle
5015 * [I] INT : item count (prjected number of items)
5016 * [I] DWORD : update flags
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
);
5029 return LISTVIEW_DeleteAllItems (hwnd
);
5031 if (nItems
> GETITEMCOUNT(infoPtr
))
5034 FIXME("append items\n");
5037 else if (nItems
< GETITEMCOUNT(infoPtr
))
5040 FIXME("remove items\n");
5049 * Sets the position of an item.
5052 * [I] HWND : window handle
5053 * [I] INT : item index
5054 * [I] INT : x coordinate
5055 * [I] INT : y coordinate
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
;
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);
5083 lpItem
->ptPosition
.x
= nPosX
;
5084 lpItem
->ptPosition
.y
= nPosY
;
5093 /* LISTVIEW_SetItemPosition32 */
5097 * Sets the state of one or many items.
5100 * [I] HWND : window handle
5101 * [I]INT : item index
5102 * [I] LPLVITEM : item or subitem info
5108 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
5110 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5111 BOOL bResult
= FALSE
;
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
++)
5127 if (ListView_SetItemA(hwnd
, &lvItem
) == FALSE
)
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
);
5148 * Sets the text of an item or subitem.
5151 * [I] HWND : window handle
5152 * [I] INT : item index
5153 * [I] LPLVITEMA : item or subitem info
5159 static BOOL
LISTVIEW_SetItemTextA(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
5161 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5162 BOOL bResult
= FALSE
;
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
);
5178 /* LISTVIEW_SetItemTextW */
5182 * Set item index that marks the start of a multiple selection.
5185 * [I] HWND : window handle
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
;
5203 * Sets the text background color.
5206 * [I] HWND : window handle
5207 * [I] COLORREF : text background color
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
);
5225 * Sets the text foreground color.
5228 * [I] HWND : window handle
5229 * [I] COLORREF : text color
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
);
5245 /* LISTVIEW_SetToolTips */
5246 /* LISTVIEW_SetUnicodeFormat */
5247 /* LISTVIEW_SetWorkAreas */
5251 * Callback internally used by LISTVIEW_SortItems()
5254 * [I] LPVOID : first LISTVIEW_ITEM to compare
5255 * [I] LPVOID : second LISTVIEW_ITEM to compare
5256 * [I] LPARAM : HWND of control
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(
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
);
5280 * Sorts the listview items.
5283 * [I] HWND : window handle
5284 * [I] WPARAM : application-defined value
5285 * [I] LPARAM : pointer to comparision callback
5291 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
5293 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5295 LISTVIEW_ITEM
*lpItem
;
5299 if (!infoPtr
|| !infoPtr
->hdpaItems
)
5302 nCount
= GETITEMCOUNT(infoPtr
);
5303 /* if there are 0 or 1 items, there is no need to sort */
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
);
5336 /* LISTVIEW_SubItemHitTest */
5340 * Updates an items or rearranges the listview control.
5343 * [I] HWND : window handle
5344 * [I] INT : item index
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
;
5357 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
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);
5369 /* get item bounding rectangle */
5370 rc
.left
= LVIR_BOUNDS
;
5371 ListView_GetItemRect(hwnd
, nItem
, &rc
);
5372 InvalidateRect(hwnd
, &rc
, TRUE
);
5381 * Creates the listview control.
5384 * [I] HWND : window handle
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
;
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
;
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
,
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
);
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
);
5472 * Erases the background of the listview control.
5475 * [I] HWND : window handle
5476 * [I] WPARAM : device context handle
5477 * [I] LPARAM : not used
5483 static LRESULT
LISTVIEW_EraseBackground(HWND hwnd
, WPARAM wParam
,
5486 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5489 if (infoPtr
->clrBk
== CLR_NONE
)
5491 bResult
= SendMessageA(GetParent(hwnd
), WM_ERASEBKGND
, wParam
, lParam
);
5496 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
5497 GetClientRect(hwnd
, &rc
);
5498 FillRect((HDC
)wParam
, &rc
, hBrush
);
5499 DeleteObject(hBrush
);
5508 * Retrieves the listview control font.
5511 * [I] HWND : window handle
5516 static LRESULT
LISTVIEW_GetFont(HWND hwnd
)
5518 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5520 return infoPtr
->hFont
;
5525 * Performs vertical scrolling.
5528 * [I] HWND : window handle
5529 * [I] INT : scroll code
5530 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5532 * [I] HWND : scrollbar control window handle
5537 static LRESULT
LISTVIEW_VScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
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
)
5553 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5560 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
5567 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5571 if (uView
== LVS_REPORT
)
5573 nPage
= LISTVIEW_GetCountPerColumn(hwnd
);
5575 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
5580 if (scrollInfo
.nPos
>= nPage
)
5582 scrollInfo
.nPos
-= nPage
;
5586 scrollInfo
.nPos
= scrollInfo
.nMin
;
5592 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
5596 if (uView
== LVS_REPORT
)
5598 nPage
= LISTVIEW_GetCountPerColumn(hwnd
);
5600 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
5605 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- nPage
)
5607 scrollInfo
.nPos
+= nPage
;
5611 scrollInfo
.nPos
= scrollInfo
.nMax
;
5616 case SB_THUMBPOSITION
:
5620 if (nOldScrollPos
!= scrollInfo
.nPos
)
5622 scrollInfo
.fMask
= SIF_POS
;
5623 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
5624 InvalidateRect(hwnd
, NULL
, TRUE
);
5633 * Performs horizontal scrolling.
5636 * [I] HWND : window handle
5637 * [I] INT : scroll code
5638 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5640 * [I] HWND : scrollbar control window handle
5645 static LRESULT
LISTVIEW_HScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
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
)
5662 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5669 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
5676 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5680 if (uView
== LVS_LIST
)
5682 nPage
= LISTVIEW_GetCountPerRow(hwnd
);
5684 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
5689 if (scrollInfo
.nPos
>= nPage
)
5691 scrollInfo
.nPos
-= nPage
;
5695 scrollInfo
.nPos
= scrollInfo
.nMin
;
5701 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
5705 if (uView
== LVS_LIST
)
5707 nPage
= LISTVIEW_GetCountPerRow(hwnd
);
5709 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
5714 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- nPage
)
5716 scrollInfo
.nPos
+= nPage
;
5720 scrollInfo
.nPos
= scrollInfo
.nMax
;
5725 case SB_THUMBPOSITION
:
5729 if (nOldScrollPos
!= scrollInfo
.nPos
)
5731 scrollInfo
.fMask
= SIF_POS
;
5732 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
5733 InvalidateRect(hwnd
, NULL
, TRUE
);
5745 * [I] HWND : window handle
5746 * [I] INT : virtual key
5747 * [I] LONG : key data
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
;
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
);
5772 nmh
.hwndFrom
= hwnd
;
5773 nmh
.idFrom
= nCtrlId
;
5775 switch (nVirtualKey
)
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
);
5791 if (GETITEMCOUNT(infoPtr
) > 0)
5798 if (GETITEMCOUNT(infoPtr
) > 0)
5800 nItem
= GETITEMCOUNT(infoPtr
) - 1;
5805 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TOLEFT
);
5809 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_ABOVE
);
5813 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TORIGHT
);
5817 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_BELOW
);
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
);
5848 * [I] HWND : window handle
5853 static LRESULT
LISTVIEW_KillFocus(HWND hwnd
)
5855 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5856 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
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
);
5876 * Processes double click messages (left mouse button).
5879 * [I] HWND : window handle
5880 * [I] WORD : key flag
5881 * [I] WORD : x coordinate
5882 * [I] WORD : y coordinate
5887 static LRESULT
LISTVIEW_LButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
5890 LONG nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
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
);
5910 * Processes mouse down messages (left mouse button).
5913 * [I] HWND : window handle
5914 * [I] WORD : key flag
5915 * [I] WORD : x coordinate
5916 * [I] WORD : y coordinate
5921 static LRESULT
LISTVIEW_LButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
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
;
5932 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd
, wKey
, wPosX
,
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
)
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
);
5960 if ((wKey
& MK_CONTROL
) && (wKey
& MK_SHIFT
))
5962 if (bGroupSelect
!= FALSE
)
5964 LISTVIEW_AddGroupSelection(hwnd
, nItem
);
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
);
5981 LISTVIEW_SetSelection(hwnd
, nItem
);
5987 /* remove all selections */
5988 LISTVIEW_RemoveSelections(hwnd
, 0, GETITEMCOUNT(infoPtr
));
5991 InvalidateRect(hwnd
, NULL
, TRUE
);
5998 * Processes mouse up messages (left mouse button).
6001 * [I] HWND : window handle
6002 * [I] WORD : key flag
6003 * [I] WORD : x coordinate
6004 * [I] WORD : y coordinate
6009 static LRESULT
LISTVIEW_LButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
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
);
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
;
6036 * Creates the listview control (called before WM_CREATE).
6039 * [I] HWND : window handle
6040 * [I] WPARAM : unhandled
6041 * [I] LPARAM : widow creation info
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");
6061 if ((LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0) != infoPtr
)
6063 ERR("pointer assignment error!\n");
6067 return DefWindowProcA(hwnd
, WM_NCCREATE
, wParam
, lParam
);
6072 * Destroys the listview control (called after WM_DESTROY).
6075 * [I] HWND : window handle
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
);
6093 infoPtr
->hFont
= (HFONT
)0;
6094 if (infoPtr
->hDefaultFont
)
6096 DeleteObject(infoPtr
->hDefaultFont
);
6099 /* free listview info pointer*/
6100 COMCTL32_Free(infoPtr
);
6107 * Handles notifications from children.
6110 * [I] HWND : window handle
6111 * [I] INT : control identifier
6112 * [I] LPNMHDR : notification information
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
);
6136 * Determines the type of structure to use.
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
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");
6166 * Paints/Repaints the listview control.
6169 * [I] HWND : window handle
6170 * [I] HDC : device context handle
6175 static LRESULT
LISTVIEW_Paint(HWND hwnd
, HDC hdc
)
6179 TRACE("(hwnd=%x,hdc=%x)\n", hwnd
, hdc
);
6183 hdc
= BeginPaint(hwnd
, &ps
);
6184 LISTVIEW_Refresh(hwnd
, hdc
);
6185 EndPaint(hwnd
, &ps
);
6189 LISTVIEW_Refresh(hwnd
, hdc
);
6197 * Processes double click messages (right mouse button).
6200 * [I] HWND : window handle
6201 * [I] WORD : key flag
6202 * [I] WORD : x coordinate
6203 * [I] WORD : y coordinate
6208 static LRESULT
LISTVIEW_RButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
6211 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
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
);
6231 * Processes mouse down messages (right mouse button).
6234 * [I] HWND : window handle
6235 * [I] WORD : key flag
6236 * [I] WORD : x coordinate
6237 * [I] WORD : y coordinate
6242 static LRESULT
LISTVIEW_RButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
6245 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6246 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
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
)
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
);
6281 LISTVIEW_RemoveSelections(hwnd
, 0, GETITEMCOUNT(infoPtr
));
6289 * Processes mouse up messages (right mouse button).
6292 * [I] HWND : window handle
6293 * [I] WORD : key flag
6294 * [I] WORD : x coordinate
6295 * [I] WORD : y coordinate
6300 static LRESULT
LISTVIEW_RButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
6303 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6304 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
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
;
6330 * [I] HWND : window handle
6331 * [I] HWND : window handle of previously focused window
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
);
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
;
6359 * [I] HWND : window handle
6360 * [I] HFONT : font handle
6361 * [I] WORD : redraw flag
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
);
6375 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
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
)
6402 * Resizes the listview control. This function processes WM_SIZE
6403 * messages. At this time, the width and height are not used.
6406 * [I] HWND : window handle
6407 * [I] WORD : new width
6408 * [I] WORD : new height
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
);
6430 LISTVIEW_AlignTop(hwnd
);
6434 LISTVIEW_UpdateScroll(hwnd
);
6436 /* invalidate client area + erase background */
6437 InvalidateRect(hwnd
, NULL
, TRUE
);
6444 * Sets the size information.
6447 * [I] HWND : window handle
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
;
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
)
6483 Header_Layout(infoPtr
->hwndHeader
, &hl
);
6484 if (!(LVS_NOCOLUMNHEADER
& lStyle
))
6486 infoPtr
->rcList
.top
= max(wp
.cy
, 0);
6493 * Processes WM_STYLECHANGED messages.
6496 * [I] HWND : window handle
6497 * [I] WPARAM : window style type (normal or extended)
6498 * [I] LPSTYLESTRUCT : window style information
6503 static INT
LISTVIEW_StyleChanged(HWND hwnd
, WPARAM wStyleType
,
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
);
6543 LISTVIEW_AlignTop(hwnd
);
6546 else if (uNewView
== LVS_REPORT
)
6553 Header_Layout(infoPtr
->hwndHeader
, &hl
);
6554 SetWindowPos(infoPtr
->hwndHeader
, hwnd
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
,
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
);
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
);
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
);
6606 * Window procedure of the listview control.
6609 LRESULT WINAPI
LISTVIEW_WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
,
6614 case LVM_APPROXIMATEVIEWRECT
:
6615 return LISTVIEW_ApproximateViewRect(hwnd
, (INT
)wParam
,
6616 LOWORD(lParam
), HIWORD(lParam
));
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
);
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");
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
);
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: */
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
);
6706 /* case LVM_GETITEMTEXTW: */
6708 case LVM_GETNEXTITEM
:
6709 return LISTVIEW_GetNextItem(hwnd
, (INT
)wParam
, LOWORD(lParam
));
6711 /* case LVM_GETNUMBEROFWORKAREAS: */
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: */
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");
6781 case LVM_SETCOLUMNORDERARRAY
:
6782 FIXME("Unimplemented msg LVM_SETCOLUMNORDERARRAY\n");
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
);
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: */
6838 return LISTVIEW_SortItems(hwnd
, wParam
, lParam
);
6840 /* case LVM_SUBITEMHITTEST: */
6843 return LISTVIEW_Update(hwnd
, (INT
)wParam
);
6846 /* case WM_COMMAND: */
6849 return LISTVIEW_Create(hwnd
, wParam
, lParam
);
6852 return LISTVIEW_EraseBackground(hwnd
, wParam
, lParam
);
6855 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
6858 return LISTVIEW_GetFont(hwnd
);
6861 return LISTVIEW_HScroll(hwnd
, (INT
)LOWORD(wParam
),
6862 (INT
)HIWORD(wParam
), (HWND
)lParam
);
6865 return LISTVIEW_KeyDown(hwnd
, (INT
)wParam
, (LONG
)lParam
);
6868 return LISTVIEW_KillFocus(hwnd
);
6870 case WM_LBUTTONDBLCLK
:
6871 return LISTVIEW_LButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
6874 case WM_LBUTTONDOWN
:
6875 return LISTVIEW_LButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
6878 return LISTVIEW_LButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
6881 /* case WM_MOUSEMOVE: */
6882 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
6885 return LISTVIEW_NCCreate(hwnd
, wParam
, lParam
);
6888 return LISTVIEW_NCDestroy(hwnd
);
6891 return LISTVIEW_Notify(hwnd
, (INT
)wParam
, (LPNMHDR
)lParam
);
6893 case WM_NOTIFYFORMAT
:
6894 return LISTVIEW_NotifyFormat(hwnd
, (HWND
)wParam
, (INT
)lParam
);
6897 return LISTVIEW_Paint(hwnd
, (HDC
)wParam
);
6899 case WM_RBUTTONDBLCLK
:
6900 return LISTVIEW_RButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
6903 case WM_RBUTTONDOWN
:
6904 return LISTVIEW_RButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
6908 return LISTVIEW_RButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
6912 return LISTVIEW_SetFocus(hwnd
, (HWND
)wParam
);
6915 return LISTVIEW_SetFont(hwnd
, (HFONT
)wParam
, (WORD
)lParam
);
6917 /* case WM_SETREDRAW: */
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: */
6928 return LISTVIEW_VScroll(hwnd
, (INT
)LOWORD(wParam
),
6929 (INT
)HIWORD(wParam
), (HWND
)lParam
);
6931 /* case WM_WINDOWPOSCHANGED: */
6932 /* case WM_WININICHANGE: */
6935 if (uMsg
>= WM_USER
)
6937 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
,
6941 /* call default window procedure */
6942 return DefWindowProcA(hwnd
, uMsg
, wParam
, lParam
);
6950 * Registers the window class.
6958 VOID
LISTVIEW_Register(void)
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
);
6978 * Unregisters the window class.
6986 VOID
LISTVIEW_Unregister(void)
6988 if (GlobalFindAtomA(WC_LISTVIEWA
))
6990 UnregisterClassA(WC_LISTVIEWA
, (HINSTANCE
)NULL
);