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_GetColumnOrderArray : not implemented
35 * LISTVIEW_SetColumnOrderArray : not implemented
36 * LISTVIEW_Arrange : empty stub
37 * LISTVIEW_ApproximateViewRect : incomplete
38 * LISTVIEW_Scroll : not implemented
39 * LISTVIEW_RedrawItems : empty stub
40 * 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
81 /* Increment size of the horizontal scroll bar */
82 #define LISTVIEW_SCROLL_DIV_SIZE 10
87 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
88 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
89 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
90 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
91 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
92 /* retrieve the number of items in the listview */
93 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
95 HWND
CreateEditLabel(LPCSTR text
, DWORD style
, INT x
, INT y
,
96 INT width
, INT height
, HWND parent
, HINSTANCE hinst
,
97 EditlblCallback EditLblCb
, DWORD param
);
100 * forward declarations
102 static INT
LISTVIEW_HitTestItem(HWND
, LPLVHITTESTINFO
);
103 static INT
LISTVIEW_GetCountPerRow(HWND
);
104 static INT
LISTVIEW_GetCountPerColumn(HWND
);
105 static VOID
LISTVIEW_AlignLeft(HWND
);
106 static VOID
LISTVIEW_AlignTop(HWND
);
107 static VOID
LISTVIEW_AddGroupSelection(HWND
, INT
);
108 static VOID
LISTVIEW_AddSelection(HWND
, INT
);
109 static BOOL
LISTVIEW_AddSubItem(HWND
, LPLVITEMA
);
110 static INT
LISTVIEW_FindInsertPosition(HDPA
, INT
);
111 static INT
LISTVIEW_GetItemHeight(HWND
);
112 static BOOL
LISTVIEW_GetItemPosition(HWND
, INT
, LPPOINT
);
113 static LRESULT
LISTVIEW_GetItemRect(HWND
, INT
, LPRECT
);
114 static INT
LISTVIEW_GetItemWidth(HWND
);
115 static INT
LISTVIEW_GetLabelWidth(HWND
, INT
);
116 static LRESULT
LISTVIEW_GetOrigin(HWND
, LPPOINT
);
117 static INT
LISTVIEW_CalculateWidth(HWND hwnd
, INT nItem
);
118 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA
, INT
);
119 static LRESULT
LISTVIEW_GetViewRect(HWND
, LPRECT
);
120 static BOOL
LISTVIEW_InitItem(HWND
, LISTVIEW_ITEM
*, LPLVITEMA
);
121 static BOOL
LISTVIEW_InitSubItem(HWND
, LISTVIEW_SUBITEM
*, LPLVITEMA
);
122 static LRESULT
LISTVIEW_MouseSelection(HWND
, POINT
);
123 static BOOL
LISTVIEW_RemoveColumn(HDPA
, INT
);
124 static VOID
LISTVIEW_RemoveSelections(HWND
, INT
, INT
);
125 static BOOL
LISTVIEW_RemoveSubItem(HDPA
, INT
);
126 static VOID
LISTVIEW_SetGroupSelection(HWND
, INT
);
127 static BOOL
LISTVIEW_SetItem(HWND
, LPLVITEMA
);
128 static BOOL
LISTVIEW_SetItemFocus(HWND
, INT
);
129 static BOOL
LISTVIEW_SetItemPosition(HWND
, INT
, INT
, INT
);
130 static VOID
LISTVIEW_UpdateScroll(HWND
);
131 static VOID
LISTVIEW_SetSelection(HWND
, INT
);
132 static VOID
LISTVIEW_UpdateSize(HWND
);
133 static BOOL
LISTVIEW_SetSubItem(HWND
, LPLVITEMA
);
134 static LRESULT
LISTVIEW_SetViewRect(HWND
, LPRECT
);
135 static BOOL
LISTVIEW_ToggleSelection(HWND
, INT
);
136 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
);
137 static HWND
LISTVIEW_EditLabelA(HWND hwnd
, INT nItem
);
138 static BOOL
LISTVIEW_EndEditLabel(HWND hwnd
, LPSTR pszText
, DWORD nItem
);
139 static LRESULT
LISTVIEW_Command(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
141 /*************************************************************************
142 * LISTVIEW_UpdateHeaderSize [Internal]
144 * Function to resize the header control
147 * hwnd [I] handle to a window
148 * nNewScrollPos [I] Scroll Pos to Set
155 static VOID
LISTVIEW_UpdateHeaderSize(HWND hwnd
, INT nNewScrollPos
)
157 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
161 GetWindowRect(infoPtr
->hwndHeader
, &winRect
);
162 point
[0].x
= winRect
.left
;
163 point
[0].y
= winRect
.top
;
164 point
[1].x
= winRect
.right
;
165 point
[1].y
= winRect
.bottom
;
167 MapWindowPoints(HWND_DESKTOP
, hwnd
, point
, 2);
168 point
[0].x
= -(nNewScrollPos
* LISTVIEW_SCROLL_DIV_SIZE
);
169 point
[1].x
+= (nNewScrollPos
* LISTVIEW_SCROLL_DIV_SIZE
);
171 SetWindowPos(infoPtr
->hwndHeader
,0,
172 point
[0].x
,point
[0].y
,point
[1].x
,point
[1].y
,
173 SWP_NOZORDER
| SWP_NOACTIVATE
);
178 * Update the scrollbars. This functions should be called whenever
179 * the content, size or view changes.
182 * [I] HWND : window handle
187 static VOID
LISTVIEW_UpdateScroll(HWND hwnd
)
189 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
190 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
191 UINT uView
= lStyle
& LVS_TYPEMASK
;
192 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
193 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
194 SCROLLINFO scrollInfo
;
196 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
197 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
199 if (uView
== LVS_LIST
)
201 /* update horizontal scrollbar */
203 INT nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
204 INT nCountPerRow
= LISTVIEW_GetCountPerRow(hwnd
);
205 INT nCountPerPage
= nCountPerRow
* nCountPerColumn
;
206 INT nNumOfItems
= GETITEMCOUNT(infoPtr
);
208 if (nCountPerPage
< GETITEMCOUNT(infoPtr
))
210 scrollInfo
.nMax
= nNumOfItems
/ nCountPerColumn
;
211 if((nNumOfItems
% nCountPerColumn
) == 0)
215 scrollInfo
.nPos
= ListView_GetTopIndex(hwnd
) / nCountPerColumn
;
216 scrollInfo
.nPage
= nCountPerRow
;
217 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
218 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
223 if (lStyle
& WS_HSCROLL
)
225 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
229 else if (uView
== LVS_REPORT
)
231 /* update vertical scrollbar */
233 scrollInfo
.nMax
= GETITEMCOUNT(infoPtr
) - 1;
234 scrollInfo
.nPos
= ListView_GetTopIndex(hwnd
);
235 scrollInfo
.nPage
= LISTVIEW_GetCountPerColumn(hwnd
);
236 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
237 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
239 /* update horizontal scrollbar */
240 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) == FALSE
)
245 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
246 scrollInfo
.nPage
= nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
;
247 scrollInfo
.nMax
= max(infoPtr
->nItemWidth
/ LISTVIEW_SCROLL_DIV_SIZE
, 0)-1;
248 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
250 /* Update the Header Control */
251 scrollInfo
.fMask
= SIF_POS
;
252 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
253 LISTVIEW_UpdateHeaderSize(hwnd
, scrollInfo
.nPos
);
260 if (LISTVIEW_GetViewRect(hwnd
, &rcView
) != FALSE
)
262 INT nViewWidth
= rcView
.right
- rcView
.left
;
263 INT nViewHeight
= rcView
.bottom
- rcView
.top
;
265 if (nViewWidth
> nListWidth
)
267 scrollInfo
.fMask
= SIF_POS
;
268 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) == FALSE
)
272 scrollInfo
.nMax
= max(nViewWidth
/ LISTVIEW_SCROLL_DIV_SIZE
, 0)-1;
274 scrollInfo
.nPage
= nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
;
275 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
276 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
280 if (lStyle
& WS_HSCROLL
)
282 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
286 if (nViewHeight
> nListHeight
)
288 scrollInfo
.fMask
= SIF_POS
;
289 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) == FALSE
)
293 scrollInfo
.nMax
= max(nViewHeight
/ LISTVIEW_SCROLL_DIV_SIZE
,0)-1;
295 scrollInfo
.nPage
= nListHeight
/ LISTVIEW_SCROLL_DIV_SIZE
;
296 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
297 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
301 if (lStyle
& WS_VSCROLL
)
303 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
312 * Prints a message for unsupported window styles.
313 * A kind of TODO list for window styles.
316 * [I] LONG : window style
321 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
)
323 if ((LVS_TYPEMASK
& lStyle
) == LVS_EDITLABELS
)
325 FIXME(" LVS_EDITLABELS\n");
328 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOLABELWRAP
)
330 FIXME(" LVS_NOLABELWRAP\n");
333 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOSCROLL
)
335 FIXME(" LVS_NOSCROLL\n");
338 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOSORTHEADER
)
340 FIXME(" LVS_NOSORTHEADER\n");
343 if ((LVS_TYPEMASK
& lStyle
) == LVS_OWNERDRAWFIXED
)
345 FIXME(" LVS_OWNERDRAWFIXED\n");
348 if ((LVS_TYPEMASK
& lStyle
) == LVS_SHAREIMAGELISTS
)
350 FIXME(" LVS_SHAREIMAGELISTS\n");
353 if ((LVS_TYPEMASK
& lStyle
) == LVS_SORTASCENDING
)
355 FIXME(" LVS_SORTASCENDING\n");
358 if ((LVS_TYPEMASK
& lStyle
) == LVS_SORTDESCENDING
)
360 FIXME(" LVS_SORTDESCENDING\n");
366 * Aligns the items with the top edge of the window.
369 * [I] HWND : window handle
374 static VOID
LISTVIEW_AlignTop(HWND hwnd
)
376 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
377 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
378 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
383 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
385 ZeroMemory(&ptItem
, sizeof(POINT
));
386 ZeroMemory(&rcView
, sizeof(RECT
));
388 if (nListWidth
> infoPtr
->nItemWidth
)
390 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
392 if (ptItem
.x
+ infoPtr
->nItemWidth
> nListWidth
)
395 ptItem
.y
+= infoPtr
->nItemHeight
;
398 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
399 ptItem
.x
+= infoPtr
->nItemWidth
;
400 rcView
.right
= max(rcView
.right
, ptItem
.x
);
403 rcView
.bottom
= ptItem
.y
+ infoPtr
->nItemHeight
;
407 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
409 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
410 ptItem
.y
+= infoPtr
->nItemHeight
;
413 rcView
.right
= infoPtr
->nItemWidth
;
414 rcView
.bottom
= ptItem
.y
;
417 LISTVIEW_SetViewRect(hwnd
, &rcView
);
423 * Aligns the items with the left edge of the window.
426 * [I] HWND : window handle
431 static VOID
LISTVIEW_AlignLeft(HWND hwnd
)
433 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
434 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
435 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
440 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
442 ZeroMemory(&ptItem
, sizeof(POINT
));
443 ZeroMemory(&rcView
, sizeof(RECT
));
445 if (nListHeight
> infoPtr
->nItemHeight
)
447 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
449 if (ptItem
.y
+ infoPtr
->nItemHeight
> nListHeight
)
452 ptItem
.x
+= infoPtr
->nItemWidth
;
455 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
456 ptItem
.y
+= infoPtr
->nItemHeight
;
457 rcView
.bottom
= max(rcView
.bottom
, ptItem
.y
);
460 rcView
.right
= ptItem
.x
+ infoPtr
->nItemWidth
;
464 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
466 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
467 ptItem
.x
+= infoPtr
->nItemWidth
;
470 rcView
.bottom
= infoPtr
->nItemHeight
;
471 rcView
.right
= ptItem
.x
;
474 LISTVIEW_SetViewRect(hwnd
, &rcView
);
480 * Set the bounding rectangle of all the items.
483 * [I] HWND : window handle
484 * [I] LPRECT : bounding rectangle
490 static LRESULT
LISTVIEW_SetViewRect(HWND hwnd
, LPRECT lprcView
)
492 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
493 BOOL bResult
= FALSE
;
495 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd
,
496 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
498 if (lprcView
!= NULL
)
501 infoPtr
->rcView
.left
= lprcView
->left
;
502 infoPtr
->rcView
.top
= lprcView
->top
;
503 infoPtr
->rcView
.right
= lprcView
->right
;
504 infoPtr
->rcView
.bottom
= lprcView
->bottom
;
512 * Retrieves the bounding rectangle of all the items.
515 * [I] HWND : window handle
516 * [O] LPRECT : bounding rectangle
522 static LRESULT
LISTVIEW_GetViewRect(HWND hwnd
, LPRECT lprcView
)
524 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
525 BOOL bResult
= FALSE
;
528 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd
, lprcView
);
530 if (lprcView
!= NULL
)
532 bResult
= LISTVIEW_GetOrigin(hwnd
, &ptOrigin
);
533 if (bResult
!= FALSE
)
535 lprcView
->left
= infoPtr
->rcView
.left
+ ptOrigin
.x
;
536 lprcView
->top
= infoPtr
->rcView
.top
+ ptOrigin
.y
;
537 lprcView
->right
= infoPtr
->rcView
.right
+ ptOrigin
.x
;
538 lprcView
->bottom
= infoPtr
->rcView
.bottom
+ ptOrigin
.y
;
541 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
542 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
550 * Retrieves the subitem pointer associated with the subitem index.
553 * [I] HDPA : DPA handle for a specific item
554 * [I] INT : index of subitem
557 * SUCCESS : subitem pointer
560 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems
,
563 LISTVIEW_SUBITEM
*lpSubItem
;
566 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
568 lpSubItem
= (LISTVIEW_SUBITEM
*) DPA_GetPtr(hdpaSubItems
, i
);
569 if (lpSubItem
!= NULL
)
571 if (lpSubItem
->iSubItem
== nSubItem
)
583 * Calculates the width of an item.
586 * [I] HWND : window handle
587 * [I] LONG : window style
590 * Returns item width.
592 static INT
LISTVIEW_GetItemWidth(HWND hwnd
)
594 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
595 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
596 INT nHeaderItemCount
;
602 TRACE("(hwnd=%x)\n", hwnd
);
604 if (uView
== LVS_ICON
)
606 nItemWidth
= infoPtr
->iconSpacing
.cx
;
608 else if (uView
== LVS_REPORT
)
610 /* calculate width of header */
611 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
612 for (i
= 0; i
< nHeaderItemCount
; i
++)
614 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
616 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
622 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
624 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, i
);
625 nItemWidth
= max(nItemWidth
, nLabelWidth
);
628 /* default label size */
629 if (GETITEMCOUNT(infoPtr
) == 0)
631 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
637 nItemWidth
= DEFAULT_LABEL_WIDTH
;
642 nItemWidth
+= WIDTH_PADDING
;
644 if (infoPtr
->himlSmall
!= NULL
)
646 nItemWidth
+= infoPtr
->iconSize
.cx
;
649 if (infoPtr
->himlState
!= NULL
)
651 nItemWidth
+= infoPtr
->iconSize
.cx
;
662 * Calculates the width of a specific item.
665 * [I] HWND : window handle
669 * Returns the width of an item width a specified string.
671 static INT
LISTVIEW_CalculateWidth(HWND hwnd
, INT nItem
)
673 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
674 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
675 INT nHeaderItemCount
;
680 TRACE("(hwnd=%x)\n", hwnd
);
682 if (uView
== LVS_ICON
)
684 nItemWidth
= infoPtr
->iconSpacing
.cx
;
686 else if (uView
== LVS_REPORT
)
688 /* calculate width of header */
689 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
690 for (i
= 0; i
< nHeaderItemCount
; i
++)
692 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
694 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
700 /* get width of string */
701 nItemWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
703 /* default label size */
704 if (GETITEMCOUNT(infoPtr
) == 0)
706 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
712 nItemWidth
= DEFAULT_LABEL_WIDTH
;
717 nItemWidth
+= WIDTH_PADDING
;
719 if (infoPtr
->himlSmall
!= NULL
)
721 nItemWidth
+= infoPtr
->iconSize
.cx
;
724 if (infoPtr
->himlState
!= NULL
)
726 nItemWidth
+= infoPtr
->iconSize
.cx
;
737 * Calculates the height of an item.
740 * [I] HWND : window handle
741 * [I] LONG : window style
744 * Returns item height.
746 static INT
LISTVIEW_GetItemHeight(HWND hwnd
)
748 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
749 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
752 if (uView
== LVS_ICON
)
754 nItemHeight
= infoPtr
->iconSpacing
.cy
;
759 HDC hdc
= GetDC(hwnd
);
760 HFONT hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
761 GetTextMetricsA(hdc
, &tm
);
762 nItemHeight
= max(tm
.tmHeight
, infoPtr
->iconSize
.cy
) + HEIGHT_PADDING
;
763 SelectObject(hdc
, hOldFont
);
764 ReleaseDC(hwnd
, hdc
);
772 * Adds a block of selections.
775 * [I] HWND : window handle
776 * [I] INT : item index
781 static VOID
LISTVIEW_AddGroupSelection(HWND hwnd
, INT nItem
)
783 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
784 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
785 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
789 lvItem
.state
= LVIS_SELECTED
;
790 lvItem
.stateMask
= LVIS_SELECTED
;
792 for (i
= nFirst
; i
<= nLast
; i
++)
794 ListView_SetItemState(hwnd
, i
, &lvItem
);
797 LISTVIEW_SetItemFocus(hwnd
, nItem
);
798 infoPtr
->nSelectionMark
= nItem
;
803 * Adds a single selection.
806 * [I] HWND : window handle
807 * [I] INT : item index
812 static VOID
LISTVIEW_AddSelection(HWND hwnd
, INT nItem
)
814 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
817 lvItem
.state
= LVIS_SELECTED
;
818 lvItem
.stateMask
= LVIS_SELECTED
;
820 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
822 LISTVIEW_SetItemFocus(hwnd
, nItem
);
823 infoPtr
->nSelectionMark
= nItem
;
828 * Selects or unselects an item.
831 * [I] HWND : window handle
832 * [I] INT : item index
838 static BOOL
LISTVIEW_ToggleSelection(HWND hwnd
, INT nItem
)
840 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
844 lvItem
.stateMask
= LVIS_SELECTED
;
846 if (ListView_GetItemState(hwnd
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
)
849 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
854 lvItem
.state
= LVIS_SELECTED
;
855 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
859 LISTVIEW_SetItemFocus(hwnd
, nItem
);
860 infoPtr
->nSelectionMark
= nItem
;
867 * Selects items based on view coorddiantes.
870 * [I] HWND : window handle
871 * [I] RECT : selection rectangle
876 static VOID
LISTVIEW_SetSelectionRect(HWND hwnd
, RECT rcSelRect
)
878 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
883 lvItem
.stateMask
= LVIS_SELECTED
;
885 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
887 LISTVIEW_GetItemPosition(hwnd
, i
, &ptItem
);
888 if (PtInRect(&rcSelRect
, ptItem
) != FALSE
)
890 lvItem
.state
= LVIS_SELECTED
;
897 ListView_SetItemState(hwnd
, i
, &lvItem
);
903 * Sets a single group selection.
906 * [I] HWND : window handle
907 * [I] INT : item index
912 static VOID
LISTVIEW_SetGroupSelection(HWND hwnd
, INT nItem
)
914 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
915 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
918 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
921 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
922 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
923 lvItem
.stateMask
= LVIS_SELECTED
;
925 for (i
= 0; i
<= GETITEMCOUNT(infoPtr
); i
++)
927 if ((i
< nFirst
) || (i
> nLast
))
933 lvItem
.state
= LVIS_SELECTED
;
936 ListView_SetItemState(hwnd
, i
, &lvItem
);
944 LISTVIEW_GetItemPosition(hwnd
, nItem
, &ptItem
);
945 LISTVIEW_GetItemPosition(hwnd
, infoPtr
->nSelectionMark
, &ptSelMark
);
946 rcSel
.left
= min(ptSelMark
.x
, ptItem
.x
);
947 rcSel
.top
= min(ptSelMark
.y
, ptItem
.y
);
948 rcSel
.right
= max(ptSelMark
.x
, ptItem
.x
) + infoPtr
->nItemWidth
;
949 rcSel
.bottom
= max(ptSelMark
.y
, ptItem
.y
) + infoPtr
->nItemHeight
;
950 LISTVIEW_SetSelectionRect(hwnd
, rcSel
);
953 LISTVIEW_SetItemFocus(hwnd
, nItem
);
958 * Manages the item focus.
961 * [I] HWND : window handle
962 * [I] INT : item index
965 * TRUE : focused item changed
966 * FALSE : focused item has NOT changed
968 static BOOL
LISTVIEW_SetItemFocus(HWND hwnd
, INT nItem
)
970 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
971 BOOL bResult
= FALSE
;
974 if (infoPtr
->nFocusedItem
!= nItem
)
977 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
978 lvItem
.stateMask
= LVIS_FOCUSED
;
979 ListView_SetItemState(hwnd
, infoPtr
->nFocusedItem
, &lvItem
);
981 lvItem
.state
= LVIS_FOCUSED
;
982 lvItem
.stateMask
= LVIS_FOCUSED
;
983 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
985 infoPtr
->nFocusedItem
= nItem
;
986 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
994 * Sets a single selection.
997 * [I] HWND : window handle
998 * [I] INT : item index
1003 static VOID
LISTVIEW_SetSelection(HWND hwnd
, INT nItem
)
1005 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1010 LISTVIEW_RemoveSelections(hwnd
, 0, nItem
- 1);
1013 if (nItem
< GETITEMCOUNT(infoPtr
))
1015 LISTVIEW_RemoveSelections(hwnd
, nItem
+ 1, GETITEMCOUNT(infoPtr
));
1018 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
1019 lvItem
.stateMask
= LVIS_FOCUSED
;
1020 ListView_SetItemState(hwnd
, infoPtr
->nFocusedItem
, &lvItem
);
1022 lvItem
.state
= LVIS_SELECTED
| LVIS_FOCUSED
;
1023 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
1024 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
1026 infoPtr
->nFocusedItem
= nItem
;
1027 infoPtr
->nSelectionMark
= nItem
;
1032 * Set selection(s) with keyboard.
1035 * [I] HWND : window handle
1036 * [I] INT : item index
1039 * SUCCESS : TRUE (needs to be repainted)
1040 * FAILURE : FALSE (nothing has changed)
1042 static BOOL
LISTVIEW_KeySelection(HWND hwnd
, INT nItem
)
1044 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1045 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1046 WORD wShift
= HIWORD(GetKeyState(VK_SHIFT
));
1047 WORD wCtrl
= HIWORD(GetKeyState(VK_CONTROL
));
1048 BOOL bResult
= FALSE
;
1050 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
1052 if (lStyle
& LVS_SINGLESEL
)
1055 LISTVIEW_SetSelection(hwnd
, nItem
);
1056 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
1063 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
1067 bResult
= LISTVIEW_SetItemFocus(hwnd
, nItem
);
1072 LISTVIEW_SetSelection(hwnd
, nItem
);
1073 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
1083 * Selects an item based on coordinates.
1086 * [I] HWND : window handle
1087 * [I] POINT : mouse click ccordinates
1090 * SUCCESS : item index
1093 static LRESULT
LISTVIEW_MouseSelection(HWND hwnd
, POINT pt
)
1095 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1099 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1101 rcItem
.left
= LVIR_SELECTBOUNDS
;
1102 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) == TRUE
)
1104 if (PtInRect(&rcItem
, pt
) != FALSE
)
1116 * Removes all selection states.
1119 * [I] HWND : window handle
1120 * [I] INT : item index
1126 static VOID
LISTVIEW_RemoveSelections(HWND hwnd
, INT nFirst
, INT nLast
)
1132 lvItem
.stateMask
= LVIS_SELECTED
;
1134 for (i
= nFirst
; i
<= nLast
; i
++)
1136 ListView_SetItemState(hwnd
, i
, &lvItem
);
1145 * [IO] HDPA : dynamic pointer array handle
1146 * [I] INT : column index (subitem index)
1152 static BOOL
LISTVIEW_RemoveColumn(HDPA hdpaItems
, INT nSubItem
)
1154 BOOL bResult
= TRUE
;
1158 for (i
= 0; i
< hdpaItems
->nItemCount
; i
++)
1160 hdpaSubItems
= (HDPA
)DPA_GetPtr(hdpaItems
, i
);
1161 if (hdpaSubItems
!= NULL
)
1163 if (LISTVIEW_RemoveSubItem(hdpaSubItems
, nSubItem
) == FALSE
)
1175 * Removes a subitem at a given position.
1178 * [IO] HDPA : dynamic pointer array handle
1179 * [I] INT : subitem index
1185 static BOOL
LISTVIEW_RemoveSubItem(HDPA hdpaSubItems
, INT nSubItem
)
1187 LISTVIEW_SUBITEM
*lpSubItem
;
1190 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
1192 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
1193 if (lpSubItem
!= NULL
)
1195 if (lpSubItem
->iSubItem
== nSubItem
)
1198 if ((lpSubItem
->pszText
!= NULL
) &&
1199 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1201 COMCTL32_Free(lpSubItem
->pszText
);
1205 COMCTL32_Free(lpSubItem
);
1207 /* free dpa memory */
1208 if (DPA_DeletePtr(hdpaSubItems
, i
) == NULL
)
1213 else if (lpSubItem
->iSubItem
> nSubItem
)
1225 * Compares the item information.
1228 * [I] LISTVIEW_ITEM *: destination item
1229 * [I] LPLVITEM : source item
1232 * SUCCCESS : TRUE (EQUAL)
1233 * FAILURE : FALSE (NOT EQUAL)
1235 static UINT
LISTVIEW_GetItemChanges(LISTVIEW_ITEM
*lpItem
, LPLVITEMA lpLVItem
)
1239 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
1241 if (lpLVItem
->mask
& LVIF_STATE
)
1243 if ((lpItem
->state
& lpLVItem
->stateMask
) !=
1244 (lpLVItem
->state
& lpLVItem
->stateMask
))
1246 uChanged
|= LVIF_STATE
;
1250 if (lpLVItem
->mask
& LVIF_IMAGE
)
1252 if (lpItem
->iImage
!= lpLVItem
->iImage
)
1254 uChanged
|= LVIF_IMAGE
;
1258 if (lpLVItem
->mask
& LVIF_PARAM
)
1260 if (lpItem
->lParam
!= lpLVItem
->lParam
)
1262 uChanged
|= LVIF_PARAM
;
1266 if (lpLVItem
->mask
& LVIF_INDENT
)
1268 if (lpItem
->iIndent
!= lpLVItem
->iIndent
)
1270 uChanged
|= LVIF_INDENT
;
1274 if (lpLVItem
->mask
& LVIF_TEXT
)
1276 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1278 if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
)
1280 uChanged
|= LVIF_TEXT
;
1285 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1287 uChanged
|= LVIF_TEXT
;
1291 if (lpLVItem
->pszText
)
1293 if (lpItem
->pszText
)
1295 if (strcmp(lpLVItem
->pszText
, lpItem
->pszText
) != 0)
1297 uChanged
|= LVIF_TEXT
;
1302 uChanged
|= LVIF_TEXT
;
1307 if (lpItem
->pszText
)
1309 uChanged
|= LVIF_TEXT
;
1321 * Initializes item attributes.
1324 * [I] HWND : window handle
1325 * [O] LISTVIEW_ITEM *: destination item
1326 * [I] LPLVITEM : source item
1332 static BOOL
LISTVIEW_InitItem(HWND hwnd
, LISTVIEW_ITEM
*lpItem
,
1335 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1336 BOOL bResult
= FALSE
;
1338 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
1342 if (lpLVItem
->mask
& LVIF_STATE
)
1344 lpItem
->state
&= ~lpLVItem
->stateMask
;
1345 lpItem
->state
|= (lpLVItem
->state
& lpLVItem
->stateMask
);
1348 if (lpLVItem
->mask
& LVIF_IMAGE
)
1350 lpItem
->iImage
= lpLVItem
->iImage
;
1353 if (lpLVItem
->mask
& LVIF_PARAM
)
1355 lpItem
->lParam
= lpLVItem
->lParam
;
1358 if (lpLVItem
->mask
& LVIF_INDENT
)
1360 lpItem
->iIndent
= lpLVItem
->iIndent
;
1363 if (lpLVItem
->mask
& LVIF_TEXT
)
1365 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1367 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
1372 if ((lpItem
->pszText
!= NULL
) &&
1373 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1375 COMCTL32_Free(lpItem
->pszText
);
1378 lpItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1382 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1384 lpItem
->pszText
= NULL
;
1387 bResult
= Str_SetPtrA(&lpItem
->pszText
, lpLVItem
->pszText
);
1397 * Initializes subitem attributes.
1399 * NOTE: The documentation specifies that the operation fails if the user
1400 * tries to set the indent of a subitem.
1403 * [I] HWND : window handle
1404 * [O] LISTVIEW_SUBITEM *: destination subitem
1405 * [I] LPLVITEM : source subitem
1411 static BOOL
LISTVIEW_InitSubItem(HWND hwnd
, LISTVIEW_SUBITEM
*lpSubItem
,
1414 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1415 BOOL bResult
= FALSE
;
1417 if ((lpSubItem
!= NULL
) && (lpLVItem
!= NULL
))
1419 if (!(lpLVItem
->mask
& LVIF_INDENT
))
1422 ZeroMemory(lpSubItem
, sizeof(LISTVIEW_SUBITEM
));
1424 lpSubItem
->iSubItem
= lpLVItem
->iSubItem
;
1426 if (lpLVItem
->mask
& LVIF_IMAGE
)
1428 lpSubItem
->iImage
= lpLVItem
->iImage
;
1431 if (lpLVItem
->mask
& LVIF_TEXT
)
1433 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1435 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
1440 if ((lpSubItem
->pszText
!= NULL
) &&
1441 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1443 COMCTL32_Free(lpSubItem
->pszText
);
1446 lpSubItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1450 if (lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1452 lpSubItem
->pszText
= NULL
;
1455 bResult
= Str_SetPtrA(&lpSubItem
->pszText
, lpLVItem
->pszText
);
1466 * Adds a subitem at a given position (column index).
1469 * [I] HWND : window handle
1470 * [I] LPLVITEM : new subitem atttributes
1476 static BOOL
LISTVIEW_AddSubItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1478 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1479 LISTVIEW_SUBITEM
*lpSubItem
= NULL
;
1480 BOOL bResult
= FALSE
;
1482 INT nPosition
, nItem
;
1484 if (lpLVItem
!= NULL
)
1486 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
1487 if (hdpaSubItems
!= NULL
)
1489 lpSubItem
= (LISTVIEW_SUBITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM
));
1490 if (lpSubItem
!= NULL
)
1492 if (LISTVIEW_InitSubItem(hwnd
, lpSubItem
, lpLVItem
) != FALSE
)
1494 nPosition
= LISTVIEW_FindInsertPosition(hdpaSubItems
,
1495 lpSubItem
->iSubItem
);
1496 nItem
= DPA_InsertPtr(hdpaSubItems
, nPosition
, lpSubItem
);
1506 /* cleanup if unsuccessful */
1507 if ((bResult
== FALSE
) && (lpSubItem
!= NULL
))
1509 COMCTL32_Free(lpSubItem
);
1517 * Finds the dpa insert position (array index).
1520 * [I] HWND : window handle
1521 * [I] INT : subitem index
1527 static INT
LISTVIEW_FindInsertPosition(HDPA hdpaSubItems
, INT nSubItem
)
1529 LISTVIEW_SUBITEM
*lpSubItem
;
1532 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
1534 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
1535 if (lpSubItem
!= NULL
)
1537 if (lpSubItem
->iSubItem
> nSubItem
)
1544 return hdpaSubItems
->nItemCount
;
1549 * Retrieves a listview subitem at a given position (column index).
1552 * [I] HWND : window handle
1553 * [I] INT : subitem index
1559 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA hdpaSubItems
, INT nSubItem
)
1561 LISTVIEW_SUBITEM
*lpSubItem
;
1564 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
1566 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
1567 if (lpSubItem
!= NULL
)
1569 if (lpSubItem
->iSubItem
== nSubItem
)
1573 else if (lpSubItem
->iSubItem
> nSubItem
)
1585 * Sets item attributes.
1588 * [I] HWND : window handle
1589 * [I] LPLVITEM : new item atttributes
1595 static BOOL
LISTVIEW_SetItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1597 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1598 BOOL bResult
= FALSE
;
1600 LISTVIEW_ITEM
*lpItem
;
1603 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
1605 if (lpLVItem
!= NULL
)
1607 if (lpLVItem
->iSubItem
== 0)
1609 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
1610 if (hdpaSubItems
!= NULL
)
1612 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
1615 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
1616 nmlv
.hdr
.hwndFrom
= hwnd
;
1617 nmlv
.hdr
.idFrom
= lCtrlId
;
1618 nmlv
.hdr
.code
= LVN_ITEMCHANGING
;
1619 nmlv
.lParam
= lpItem
->lParam
;
1620 uChanged
= LISTVIEW_GetItemChanges(lpItem
, lpLVItem
);
1623 if (uChanged
& LVIF_STATE
)
1625 nmlv
.uNewState
= lpLVItem
->state
& lpLVItem
->stateMask
;
1626 nmlv
.uOldState
= lpItem
->state
& lpLVItem
->stateMask
;
1629 nmlv
.uChanged
= uChanged
;
1630 nmlv
.iItem
= lpLVItem
->iItem
;
1631 nmlv
.lParam
= lpItem
->lParam
;
1632 /* send LVN_ITEMCHANGING notification */
1633 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
1635 /* copy information */
1636 bResult
= LISTVIEW_InitItem(hwnd
, lpItem
, lpLVItem
);
1638 /* send LVN_ITEMCHANGED notification */
1639 nmlv
.hdr
.code
= LVN_ITEMCHANGED
;
1640 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
1647 InvalidateRect(hwnd
, NULL
, FALSE
);
1658 * Sets subitem attributes.
1661 * [I] HWND : window handle
1662 * [I] LPLVITEM : new subitem atttributes
1668 static BOOL
LISTVIEW_SetSubItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1670 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1671 BOOL bResult
= FALSE
;
1673 LISTVIEW_SUBITEM
*lpSubItem
;
1675 if (lpLVItem
!= NULL
)
1677 if (lpLVItem
->iSubItem
> 0)
1679 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
1680 if (hdpaSubItems
!= NULL
)
1682 /* set subitem only if column is present */
1683 if (Header_GetItemCount(infoPtr
->hwndHeader
) > lpLVItem
->iSubItem
)
1685 lpSubItem
= LISTVIEW_GetSubItem(hdpaSubItems
, lpLVItem
->iSubItem
);
1686 if (lpSubItem
!= NULL
)
1688 bResult
= LISTVIEW_InitSubItem(hwnd
, lpSubItem
, lpLVItem
);
1692 bResult
= LISTVIEW_AddSubItem(hwnd
, lpLVItem
);
1695 InvalidateRect(hwnd
, NULL
, FALSE
);
1706 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1709 * [I] HWND : window handle
1714 static INT
LISTVIEW_GetTopIndex(HWND hwnd
)
1716 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1717 UINT uView
= lStyle
& LVS_TYPEMASK
;
1719 SCROLLINFO scrollInfo
;
1721 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
1722 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
1723 scrollInfo
.fMask
= SIF_POS
;
1725 if (uView
== LVS_LIST
)
1727 if (lStyle
& WS_HSCROLL
)
1729 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
1731 nItem
= scrollInfo
.nPos
* LISTVIEW_GetCountPerColumn(hwnd
);
1735 else if (uView
== LVS_REPORT
)
1737 if (lStyle
& WS_VSCROLL
)
1739 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
1741 nItem
= scrollInfo
.nPos
;
1754 * [I] HWND : window handle
1755 * [I] HDC : device context handle
1756 * [I] INT : item index
1757 * [I] INT : subitem index
1758 * [I] RECT * : clipping rectangle
1763 static VOID
LISTVIEW_DrawSubItem(HWND hwnd
, HDC hdc
, INT nItem
, INT nSubItem
,
1766 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1767 CHAR szDispText
[DISP_TEXT_SIZE
];
1770 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d\n", hwnd
, hdc
,
1773 /* get information needed for drawing the item */
1774 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
1775 lvItem
.mask
= LVIF_TEXT
;
1776 lvItem
.iItem
= nItem
;
1777 lvItem
.iSubItem
= nSubItem
;
1778 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
1779 lvItem
.pszText
= szDispText
;
1780 ListView_GetItemA(hwnd
, &lvItem
);
1782 /* set item colors */
1783 SetBkColor(hdc
, infoPtr
->clrTextBk
);
1784 SetTextColor(hdc
, infoPtr
->clrText
);
1786 ExtTextOutA(hdc
, rcItem
.left
, rcItem
.top
, ETO_OPAQUE
| ETO_CLIPPED
,
1787 &rcItem
, lvItem
.pszText
, lstrlenA(lvItem
.pszText
), NULL
);
1796 * [I] HWND : window handle
1797 * [I] HDC : device context handle
1798 * [I] INT : item index
1799 * [I] RECT * : clipping rectangle
1804 static VOID
LISTVIEW_DrawItem(HWND hwnd
, HDC hdc
, INT nItem
, RECT rcItem
)
1806 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1807 CHAR szDispText
[DISP_TEXT_SIZE
];
1814 TRACE("(hwnd=%x, hdc=%x, nItem=%d\n", hwnd
, hdc
, nItem
);
1816 /* get information needed for drawing the item */
1817 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
1818 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
| LVIF_INDENT
;
1819 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
| LVIS_STATEIMAGEMASK
;
1820 lvItem
.iItem
= nItem
;
1821 lvItem
.iSubItem
= 0;
1822 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
1823 lvItem
.pszText
= szDispText
;
1824 ListView_GetItemA(hwnd
, &lvItem
);
1827 if (infoPtr
->himlState
!= NULL
)
1829 UINT uStateImage
= (lvItem
.state
& LVIS_STATEIMAGEMASK
) >> 12;
1830 if (uStateImage
!= 0)
1832 ImageList_Draw(infoPtr
->himlState
, uStateImage
- 1, hdc
, rcItem
.left
,
1833 rcItem
.top
, ILD_NORMAL
);
1836 rcItem
.left
+= infoPtr
->iconSize
.cx
;
1840 if (infoPtr
->himlSmall
!= NULL
)
1842 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
!= FALSE
))
1844 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
1845 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
1846 rcItem
.top
, ILD_SELECTED
);
1850 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
1851 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
1852 rcItem
.top
, ILD_NORMAL
);
1855 rcItem
.left
+= infoPtr
->iconSize
.cx
;
1858 /* Don't bother painting item being edited */
1859 if (infoPtr
->hwndEdit
&& lvItem
.state
& LVIS_FOCUSED
)
1862 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
!= FALSE
))
1864 /* set item colors */
1865 dwBkColor
= SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1866 dwTextColor
= SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1867 /* set raster mode */
1868 nMixMode
= SetROP2(hdc
, R2_XORPEN
);
1870 else if ((GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_SHOWSELALWAYS
) &&
1871 (lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
== FALSE
))
1873 dwBkColor
= SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
1874 dwTextColor
= SetTextColor(hdc
, GetSysColor(COLOR_BTNTEXT
));
1875 /* set raster mode */
1876 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
1880 /* set item colors */
1881 dwBkColor
= SetBkColor(hdc
, infoPtr
->clrTextBk
);
1882 dwTextColor
= SetTextColor(hdc
, infoPtr
->clrText
);
1883 /* set raster mode */
1884 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
1887 nLabelWidth
= ListView_GetStringWidthA(hwnd
, lvItem
.pszText
);
1888 if (rcItem
.left
+ nLabelWidth
< rcItem
.right
)
1890 rcItem
.right
= rcItem
.left
+ nLabelWidth
;
1894 ExtTextOutA(hdc
, rcItem
.left
, rcItem
.top
, ETO_OPAQUE
| ETO_CLIPPED
,
1895 &rcItem
, lvItem
.pszText
, lstrlenA(lvItem
.pszText
), NULL
);
1897 if ((lvItem
.state
& LVIS_FOCUSED
) && (infoPtr
->bFocus
== TRUE
))
1899 Rectangle(hdc
, rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
);
1904 SetROP2(hdc
, R2_COPYPEN
);
1905 SetBkColor(hdc
, infoPtr
->clrTextBk
);
1906 SetTextColor(hdc
, infoPtr
->clrText
);
1912 * Draws an item when in large icon display mode.
1915 * [I] HWND : window handle
1916 * [I] HDC : device context handle
1917 * [I] LISTVIEW_ITEM * : item
1918 * [I] INT : item index
1919 * [I] RECT * : clipping rectangle
1924 static VOID
LISTVIEW_DrawLargeItem(HWND hwnd
, HDC hdc
, INT nItem
, RECT rcItem
)
1926 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1927 CHAR szDispText
[DISP_TEXT_SIZE
];
1928 INT nDrawPosX
= rcItem
.left
;
1933 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
1934 bottom=%d)\n", hwnd
, hdc
, nItem
, rcItem
.left
, rcItem
.top
, rcItem
.right
,
1937 /* get information needed for drawing the item */
1938 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
1939 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
;
1940 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
1941 lvItem
.iItem
= nItem
;
1942 lvItem
.iSubItem
= 0;
1943 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
1944 lvItem
.pszText
= szDispText
;
1945 ListView_GetItemA(hwnd
, &lvItem
);
1947 if (lvItem
.state
& LVIS_SELECTED
)
1949 /* set item colors */
1950 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1951 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1952 /* set raster mode */
1953 SetROP2(hdc
, R2_XORPEN
);
1957 /* set item colors */
1958 SetBkColor(hdc
, infoPtr
->clrTextBk
);
1959 SetTextColor(hdc
, infoPtr
->clrText
);
1960 /* set raster mode */
1961 SetROP2(hdc
, R2_COPYPEN
);
1964 if (infoPtr
->himlNormal
!= NULL
)
1966 rcItem
.top
+= ICON_TOP_PADDING
;
1967 nDrawPosX
+= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
1968 if (lvItem
.state
& LVIS_SELECTED
)
1970 ImageList_Draw(infoPtr
->himlNormal
, lvItem
.iImage
, hdc
, nDrawPosX
,
1971 rcItem
.top
, ILD_SELECTED
);
1975 ImageList_Draw(infoPtr
->himlNormal
, lvItem
.iImage
, hdc
, nDrawPosX
,
1976 rcItem
.top
, ILD_NORMAL
);
1980 rcItem
.top
+= infoPtr
->iconSize
.cy
+ ICON_BOTTOM_PADDING
;
1981 nLabelWidth
= ListView_GetStringWidthA(hwnd
, lvItem
.pszText
);
1982 nDrawPosX
= infoPtr
->iconSpacing
.cx
- nLabelWidth
;
1985 rcItem
.left
+= nDrawPosX
/ 2;
1986 rcItem
.right
= rcItem
.left
+ nLabelWidth
;
1991 rcItem
.right
= rcItem
.left
+ infoPtr
->iconSpacing
.cx
- 1;
1995 GetTextMetricsA(hdc
, &tm
);
1996 rcItem
.bottom
= rcItem
.top
+ tm
.tmHeight
+ HEIGHT_PADDING
;
1997 ExtTextOutA(hdc
, rcItem
.left
, rcItem
.top
, ETO_OPAQUE
| ETO_CLIPPED
,
1998 &rcItem
, lvItem
.pszText
, lstrlenA(lvItem
.pszText
), NULL
);
2000 if (lvItem
.state
& LVIS_FOCUSED
)
2002 Rectangle(hdc
, rcItem
.left
, rcItem
.top
, rcItem
.right
, rcItem
.bottom
);
2008 * Draws listview items when in report display mode.
2011 * [I] HWND : window handle
2012 * [I] HDC : device context handle
2017 static VOID
LISTVIEW_RefreshReport(HWND hwnd
, HDC hdc
)
2019 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
2020 SCROLLINFO scrollInfo
;
2021 INT nDrawPosY
= infoPtr
->rcList
.top
;
2028 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
2029 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
2030 scrollInfo
.fMask
= SIF_POS
;
2032 nItem
= ListView_GetTopIndex(hwnd
);
2034 /* add 1 for displaying a partial item at the bottom */
2035 nLast
= nItem
+ LISTVIEW_GetCountPerColumn(hwnd
) + 1;
2036 nLast
= min(nLast
, GETITEMCOUNT(infoPtr
));
2037 for (; nItem
< nLast
; nItem
++)
2039 nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
2040 for (j
= 0; j
< nColumnCount
; j
++)
2042 Header_GetItemRect(infoPtr
->hwndHeader
, j
, &rcItem
);
2043 rcItem
.left
+= REPORT_MARGINX
;
2044 rcItem
.right
= max(rcItem
.left
, rcItem
.right
- REPORT_MARGINX
);
2045 rcItem
.top
= nDrawPosY
;
2046 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
2048 /* Offset the Scroll Bar Pos */
2049 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
2051 rcItem
.left
-= (scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
);
2052 rcItem
.right
-= (scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
);
2057 LISTVIEW_DrawItem(hwnd
, hdc
, nItem
, rcItem
);
2061 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, j
, rcItem
);
2065 nDrawPosY
+= infoPtr
->nItemHeight
;
2071 * Retrieves the number of items that can fit vertically in the client area.
2074 * [I] HWND : window handle
2077 * Number of items per row.
2079 static INT
LISTVIEW_GetCountPerRow(HWND hwnd
)
2081 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
2082 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
2083 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
2084 INT nCountPerRow
= 1;
2088 if (uView
== LVS_REPORT
)
2094 nCountPerRow
= nListWidth
/ infoPtr
->nItemWidth
;
2095 if (nCountPerRow
== 0)
2102 return nCountPerRow
;
2107 * Retrieves the number of items that can fit horizontally in the client
2111 * [I] HWND : window handle
2114 * Number of items per column.
2116 static INT
LISTVIEW_GetCountPerColumn(HWND hwnd
)
2118 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
2119 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
2120 INT nCountPerColumn
= 1;
2122 if (nListHeight
> 0)
2124 nCountPerColumn
= nListHeight
/ infoPtr
->nItemHeight
;
2125 if (nCountPerColumn
== 0)
2127 nCountPerColumn
= 1;
2131 return nCountPerColumn
;
2136 * Retrieves the number of columns needed to display all the items when in
2137 * list display mode.
2140 * [I] HWND : window handle
2143 * Number of columns.
2145 static INT
LISTVIEW_GetColumnCount(HWND hwnd
)
2147 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2148 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2149 INT nColumnCount
= 0;
2151 if ((lStyle
& LVS_TYPEMASK
) == LVS_LIST
)
2153 if (infoPtr
->rcList
.right
% infoPtr
->nItemWidth
== 0)
2155 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nItemWidth
;
2159 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nItemWidth
+ 1;
2163 return nColumnCount
;
2169 * Draws listview items when in list display mode.
2172 * [I] HWND : window handle
2173 * [I] HDC : device context handle
2178 static VOID
LISTVIEW_RefreshList(HWND hwnd
, HDC hdc
)
2180 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2185 INT nCountPerColumn
;
2186 INT nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
2187 INT nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
2189 /* get number of fully visible columns */
2190 nColumnCount
= LISTVIEW_GetColumnCount(hwnd
);
2191 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
2192 nItem
= ListView_GetTopIndex(hwnd
);
2194 for (i
= 0; i
< nColumnCount
; i
++)
2196 for (j
= 0; j
< nCountPerColumn
; j
++, nItem
++)
2198 if (nItem
>= GETITEMCOUNT(infoPtr
))
2201 rcItem
.top
= j
* nItemHeight
;
2202 rcItem
.left
= i
* nItemWidth
;
2203 rcItem
.bottom
= rcItem
.top
+ nItemHeight
;
2204 rcItem
.right
= rcItem
.left
+ nItemWidth
;
2205 LISTVIEW_DrawItem(hwnd
, hdc
, nItem
, rcItem
);
2212 * Draws listview items when in icon or small icon display mode.
2215 * [I] HWND : window handle
2216 * [I] HDC : device context handle
2221 static VOID
LISTVIEW_RefreshIcon(HWND hwnd
, HDC hdc
, BOOL bSmall
)
2223 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2229 LISTVIEW_GetOrigin(hwnd
, &ptOrigin
);
2230 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
2232 LISTVIEW_GetItemPosition(hwnd
, i
, &ptPosition
);
2233 ptPosition
.x
+= ptOrigin
.x
;
2234 ptPosition
.y
+= ptOrigin
.y
;
2236 if (ptPosition
.y
+ infoPtr
->nItemHeight
> infoPtr
->rcList
.top
)
2238 if (ptPosition
.x
+ infoPtr
->nItemWidth
> infoPtr
->rcList
.left
)
2240 if (ptPosition
.y
< infoPtr
->rcList
.bottom
)
2242 if (ptPosition
.x
< infoPtr
->rcList
.right
)
2244 rcItem
.top
= ptPosition
.y
;
2245 rcItem
.left
= ptPosition
.x
;
2246 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
2247 rcItem
.right
= rcItem
.left
+ infoPtr
->nItemWidth
;
2248 if (bSmall
== FALSE
)
2250 LISTVIEW_DrawLargeItem(hwnd
, hdc
, i
, rcItem
);
2254 LISTVIEW_DrawItem(hwnd
, hdc
, i
, rcItem
);
2265 * Draws listview items.
2268 * [I] HWND : window handle
2269 * [I] HDC : device context handle
2274 static VOID
LISTVIEW_Refresh(HWND hwnd
, HDC hdc
)
2276 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2277 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
2282 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
2284 /* select the doted pen (for drawing the focus box) */
2285 hPen
= CreatePen(PS_DOT
, 1, 0);
2286 hOldPen
= SelectObject(hdc
, hPen
);
2288 /* select transparent brush (for drawing the focus box) */
2289 SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
2291 if (uView
== LVS_LIST
)
2293 LISTVIEW_RefreshList(hwnd
, hdc
);
2295 else if (uView
== LVS_REPORT
)
2297 LISTVIEW_RefreshReport(hwnd
, hdc
);
2299 else if (uView
== LVS_SMALLICON
)
2301 LISTVIEW_RefreshIcon(hwnd
, hdc
, TRUE
);
2303 else if (uView
== LVS_ICON
)
2305 LISTVIEW_RefreshIcon(hwnd
, hdc
, FALSE
);
2308 /* unselect objects */
2309 SelectObject(hdc
, hOldFont
);
2310 SelectObject(hdc
, hOldPen
);
2319 * Calculates the approximate width and height of a given number of items.
2322 * [I] HWND : window handle
2323 * [I] INT : number of items
2328 * Returns a DWORD. The width in the low word and the height in high word.
2330 static LRESULT
LISTVIEW_ApproximateViewRect(HWND hwnd
, INT nItemCount
,
2331 WORD wWidth
, WORD wHeight
)
2333 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2334 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
2335 INT nItemCountPerColumn
= 1;
2336 INT nColumnCount
= 0;
2337 DWORD dwViewRect
= 0;
2339 if (nItemCount
== -1)
2341 nItemCount
= GETITEMCOUNT(infoPtr
);
2344 if (uView
== LVS_LIST
)
2346 if (wHeight
== 0xFFFF)
2348 /* use current height */
2349 wHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
2352 if (wHeight
< infoPtr
->nItemHeight
)
2354 wHeight
= infoPtr
->nItemHeight
;
2359 if (infoPtr
->nItemHeight
> 0)
2361 nItemCountPerColumn
= wHeight
/ infoPtr
->nItemHeight
;
2362 if (nItemCountPerColumn
== 0)
2364 nItemCountPerColumn
= 1;
2367 if (nItemCount
% nItemCountPerColumn
!= 0)
2369 nColumnCount
= nItemCount
/ nItemCountPerColumn
;
2373 nColumnCount
= nItemCount
/ nItemCountPerColumn
+ 1;
2378 /* Microsoft padding magic */
2379 wHeight
= nItemCountPerColumn
* infoPtr
->nItemHeight
+ 2;
2380 wWidth
= nColumnCount
* infoPtr
->nItemWidth
+ 2;
2382 dwViewRect
= MAKELONG(wWidth
, wHeight
);
2384 else if (uView
== LVS_REPORT
)
2388 else if (uView
== LVS_SMALLICON
)
2392 else if (uView
== LVS_ICON
)
2402 * Arranges listview items in icon display mode.
2405 * [I] HWND : window handle
2406 * [I] INT : alignment code
2412 static LRESULT
LISTVIEW_Arrange(HWND hwnd
, INT nAlignCode
)
2414 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
2415 BOOL bResult
= FALSE
;
2417 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
2430 case LVA_SNAPTOGRID
:
2439 /* << LISTVIEW_CreateDragImage >> */
2443 * Removes all listview items and subitems.
2446 * [I] HWND : window handle
2452 static LRESULT
LISTVIEW_DeleteAllItems(HWND hwnd
)
2454 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2455 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2456 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2457 UINT uView
= lStyle
& LVS_TYPEMASK
;
2458 LISTVIEW_ITEM
*lpItem
;
2459 LISTVIEW_SUBITEM
*lpSubItem
;
2462 BOOL bResult
= FALSE
;
2467 TRACE("(hwnd=%x,)\n", hwnd
);
2469 if (GETITEMCOUNT(infoPtr
) > 0)
2471 /* initialize memory */
2472 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2474 /* send LVN_DELETEALLITEMS notification */
2475 nmlv
.hdr
.hwndFrom
= hwnd
;
2476 nmlv
.hdr
.idFrom
= lCtrlId
;
2477 nmlv
.hdr
.code
= LVN_DELETEALLITEMS
;
2480 /* verify if subsequent LVN_DELETEITEM notifications should be
2482 bSuppress
= ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
2484 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
2486 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
2487 if (hdpaSubItems
!= NULL
)
2489 for (j
= 1; j
< hdpaSubItems
->nItemCount
; j
++)
2491 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, j
);
2492 if (lpSubItem
!= NULL
)
2494 /* free subitem string */
2495 if ((lpSubItem
->pszText
!= NULL
) &&
2496 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2498 COMCTL32_Free(lpSubItem
->pszText
);
2502 COMCTL32_Free(lpSubItem
);
2506 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2509 if (bSuppress
== FALSE
)
2511 /* send LVN_DELETEITEM notification */
2512 nmlv
.hdr
.code
= LVN_DELETEITEM
;
2514 nmlv
.lParam
= lpItem
->lParam
;
2515 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
2518 /* free item string */
2519 if ((lpItem
->pszText
!= NULL
) &&
2520 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2522 COMCTL32_Free(lpItem
->pszText
);
2526 COMCTL32_Free(lpItem
);
2529 DPA_Destroy(hdpaSubItems
);
2533 /* reinitialize listview memory */
2534 bResult
= DPA_DeleteAllPtrs(infoPtr
->hdpaItems
);
2536 /* align items (set position of each item) */
2537 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
2539 if (lStyle
& LVS_ALIGNLEFT
)
2541 LISTVIEW_AlignLeft(hwnd
);
2545 LISTVIEW_AlignTop(hwnd
);
2549 LISTVIEW_UpdateScroll(hwnd
);
2551 /* invalidate client area (optimization needed) */
2552 InvalidateRect(hwnd
, NULL
, TRUE
);
2560 * Removes a column from the listview control.
2563 * [I] HWND : window handle
2564 * [I] INT : column index
2570 static LRESULT
LISTVIEW_DeleteColumn(HWND hwnd
, INT nColumn
)
2572 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2573 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
2574 BOOL bResult
= FALSE
;
2576 if (Header_DeleteItem(infoPtr
->hwndHeader
, nColumn
) != FALSE
)
2578 bResult
= LISTVIEW_RemoveColumn(infoPtr
->hdpaItems
, nColumn
);
2580 /* Need to reset the item width when deleting a column */
2581 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
2583 /* reset scroll parameters */
2584 if (uView
== LVS_REPORT
)
2586 /* update scrollbar(s) */
2587 LISTVIEW_UpdateScroll(hwnd
);
2589 /* refresh client area */
2590 InvalidateRect(hwnd
, NULL
, FALSE
);
2599 * Removes an item from the listview control.
2602 * [I] HWND : window handle
2603 * [I] INT : item index
2609 static LRESULT
LISTVIEW_DeleteItem(HWND hwnd
, INT nItem
)
2611 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2612 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2613 UINT uView
= lStyle
& LVS_TYPEMASK
;
2614 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2616 BOOL bResult
= FALSE
;
2618 LISTVIEW_ITEM
*lpItem
;
2619 LISTVIEW_SUBITEM
*lpSubItem
;
2622 TRACE("(hwnd=%x,nItem=%d)\n", hwnd
, nItem
);
2624 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
2626 /* initialize memory */
2627 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2629 hdpaSubItems
= (HDPA
)DPA_DeletePtr(infoPtr
->hdpaItems
, nItem
);
2630 if (hdpaSubItems
!= NULL
)
2632 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2634 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2635 if (lpSubItem
!= NULL
)
2637 /* free item string */
2638 if ((lpSubItem
->pszText
!= NULL
) &&
2639 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2641 COMCTL32_Free(lpSubItem
->pszText
);
2645 COMCTL32_Free(lpSubItem
);
2649 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2652 /* send LVN_DELETEITEM notification */
2653 nmlv
.hdr
.hwndFrom
= hwnd
;
2654 nmlv
.hdr
.idFrom
= lCtrlId
;
2655 nmlv
.hdr
.code
= LVN_DELETEITEM
;
2657 nmlv
.lParam
= lpItem
->lParam
;
2658 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
2661 /* free item string */
2662 if ((lpItem
->pszText
!= NULL
) &&
2663 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2665 COMCTL32_Free(lpItem
->pszText
);
2669 COMCTL32_Free(lpItem
);
2672 bResult
= DPA_Destroy(hdpaSubItems
);
2675 /* align items (set position of each item) */
2676 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
2678 if (lStyle
& LVS_ALIGNLEFT
)
2680 LISTVIEW_AlignLeft(hwnd
);
2684 LISTVIEW_AlignTop(hwnd
);
2688 /* If this item had focus change focus to next or previous item */
2689 if (GETITEMCOUNT(infoPtr
) > 0)
2691 int sItem
= nItem
< GETITEMCOUNT(infoPtr
) ? nItem
: nItem
- 1;
2692 if (infoPtr
->nFocusedItem
== nItem
)
2693 LISTVIEW_SetItemFocus(hwnd
, sItem
);
2696 infoPtr
->nFocusedItem
= -1;
2698 LISTVIEW_UpdateScroll(hwnd
);
2700 /* refresh client area */
2701 InvalidateRect(hwnd
, NULL
, TRUE
);
2710 * Return edit control handle of current edit label
2713 * [I] HWND : window handle
2719 static LRESULT
LISTVIEW_GetEditControl(hwnd
)
2721 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2722 return infoPtr
->hwndEdit
;
2728 * Callback implementation for editlabel control
2731 * [I] HWND : window handle
2732 * [I] LPSTR : modified text
2733 * [I] DWORD : item index
2740 static BOOL
LISTVIEW_EndEditLabel(HWND hwnd
, LPSTR pszText
, DWORD nItem
)
2742 NMLVDISPINFOA dispInfo
;
2743 LISTVIEW_ITEM
*lpItem
;
2744 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2745 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2748 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
2750 if (NULL
== (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
2753 if (NULL
== (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
2756 dispInfo
.hdr
.hwndFrom
= hwnd
;
2757 dispInfo
.hdr
.idFrom
= nCtrlId
;
2758 dispInfo
.hdr
.code
= LVN_ENDLABELEDITA
;
2759 dispInfo
.item
.mask
= 0;
2760 dispInfo
.item
.iItem
= nItem
;
2761 dispInfo
.item
.state
= lpItem
->state
;
2762 dispInfo
.item
.stateMask
= 0;
2763 dispInfo
.item
.pszText
= pszText
;
2764 dispInfo
.item
.cchTextMax
= pszText
? strlen(pszText
) : 0;
2765 dispInfo
.item
.iImage
= lpItem
->iImage
;
2766 dispInfo
.item
.lParam
= lpItem
->lParam
;
2768 ListView_Notify(GetParent(hwnd
), nCtrlId
, &dispInfo
);
2769 infoPtr
->hwndEdit
= 0;
2776 * Begin in place editing of specified list view item
2779 * [I] HWND : window handle
2780 * [I] INT : item index
2787 static HWND
LISTVIEW_EditLabelA(HWND hwnd
, INT nItem
)
2789 NMLVDISPINFOA dispInfo
;
2791 LISTVIEW_ITEM
*lpItem
;
2793 HINSTANCE hinst
= GetWindowLongA(hwnd
, GWL_HINSTANCE
);
2794 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2795 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2798 if (~GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_EDITLABELS
)
2801 LISTVIEW_SetSelection(hwnd
, nItem
);
2802 LISTVIEW_SetItemFocus(hwnd
, nItem
);
2804 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
2805 if (NULL
== (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
2808 if (NULL
== (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
2811 dispInfo
.hdr
.hwndFrom
= hwnd
;
2812 dispInfo
.hdr
.idFrom
= nCtrlId
;
2813 dispInfo
.hdr
.code
= LVN_BEGINLABELEDITA
;
2814 dispInfo
.item
.mask
= 0;
2815 dispInfo
.item
.iItem
= nItem
;
2816 dispInfo
.item
.state
= lpItem
->state
;
2817 dispInfo
.item
.stateMask
= 0;
2818 dispInfo
.item
.pszText
= lpItem
->pszText
;
2819 dispInfo
.item
.cchTextMax
= strlen(lpItem
->pszText
);
2820 dispInfo
.item
.iImage
= lpItem
->iImage
;
2821 dispInfo
.item
.lParam
= lpItem
->lParam
;
2823 if (ListView_LVNotify(GetParent(hwnd
), nCtrlId
, &dispInfo
))
2826 rect
.left
= LVIR_LABEL
;
2827 if (!LISTVIEW_GetItemRect(hwnd
, nItem
, &rect
))
2830 if (!(hedit
= CreateEditLabel(dispInfo
.item
.pszText
, WS_VISIBLE
,
2831 rect
.left
, rect
.top
, rect
.right
- rect
.left
+ 15,
2832 rect
.bottom
- rect
.top
,
2833 hwnd
, hinst
, LISTVIEW_EndEditLabel
, nItem
)))
2836 infoPtr
->hwndEdit
= hedit
;
2838 SendMessageA(hedit
, EM_SETSEL
, 0, -1);
2846 * Ensures the specified item is visible, scrolling into view if necessary.
2849 * [I] HWND : window handle
2850 * [I] INT : item index
2851 * [I] BOOL : partially or entirely visible
2857 static BOOL
LISTVIEW_EnsureVisible(HWND hwnd
, INT nItem
, BOOL bPartial
)
2859 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2860 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
2861 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
2862 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
2863 INT nScrollPosHeight
= 0;
2864 INT nScrollPosWidth
= 0;
2865 SCROLLINFO scrollInfo
;
2868 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
2869 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
2870 scrollInfo
.fMask
= SIF_POS
;
2872 /* ALWAYS bPartial == FALSE, FOR NOW! */
2874 rcItem
.left
= LVIR_BOUNDS
;
2875 if (LISTVIEW_GetItemRect(hwnd
, nItem
, &rcItem
) != FALSE
)
2877 if (rcItem
.left
< infoPtr
->rcList
.left
)
2879 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
2882 if (uView
== LVS_LIST
)
2884 nScrollPosWidth
= infoPtr
->nItemWidth
;
2885 rcItem
.left
+= infoPtr
->rcList
.left
;
2887 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
2889 nScrollPosWidth
= max(1, nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
);
2890 rcItem
.left
+= infoPtr
->rcList
.left
;
2893 if (rcItem
.left
% nScrollPosWidth
== 0)
2895 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
;
2899 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
- 1;
2902 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
2905 else if (rcItem
.right
> infoPtr
->rcList
.right
)
2907 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
2910 if (uView
== LVS_LIST
)
2912 rcItem
.right
-= infoPtr
->rcList
.right
;
2913 nScrollPosWidth
= infoPtr
->nItemWidth
;
2915 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
2917 rcItem
.right
-= infoPtr
->rcList
.right
;
2918 nScrollPosWidth
= max(1, nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
);
2921 if (rcItem
.right
% nScrollPosWidth
== 0)
2923 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
;
2927 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
+ 1;
2930 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
2934 if (rcItem
.top
< infoPtr
->rcList
.top
)
2937 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
2939 if (uView
== LVS_REPORT
)
2941 rcItem
.top
-= infoPtr
->rcList
.top
;
2942 nScrollPosHeight
= infoPtr
->nItemHeight
;
2944 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
2946 nScrollPosHeight
= max(1, nListHeight
/ LISTVIEW_SCROLL_DIV_SIZE
);
2947 rcItem
.top
+= infoPtr
->rcList
.top
;
2950 if (rcItem
.top
% nScrollPosHeight
== 0)
2952 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
;
2956 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
- 1;
2959 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
2962 else if (rcItem
.bottom
> infoPtr
->rcList
.bottom
)
2965 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
2967 if (uView
== LVS_REPORT
)
2969 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
2970 nScrollPosHeight
= infoPtr
->nItemHeight
;
2972 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
2974 nScrollPosHeight
= max(1, nListHeight
/ LISTVIEW_SCROLL_DIV_SIZE
);
2975 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
2978 if (rcItem
.bottom
% nScrollPosHeight
== 0)
2980 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
;
2984 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
+ 1;
2987 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
2997 * Retrieves the nearest item, given a position and a direction.
3000 * [I] HWND : window handle
3001 * [I] POINT : start position
3002 * [I] UINT : direction
3005 * Item index if successdful, -1 otherwise.
3007 static INT
LISTVIEW_GetNearestItem(HWND hwnd
, POINT pt
, UINT vkDirection
)
3009 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3010 LVHITTESTINFO lvHitTestInfo
;
3014 if (LISTVIEW_GetViewRect(hwnd
, &rcView
) != FALSE
)
3016 ZeroMemory(&lvHitTestInfo
, sizeof(LVHITTESTINFO
));
3017 LISTVIEW_GetOrigin(hwnd
, &lvHitTestInfo
.pt
);
3018 lvHitTestInfo
.pt
.x
+= pt
.x
;
3019 lvHitTestInfo
.pt
.y
+= pt
.y
;
3023 if (vkDirection
== VK_DOWN
)
3025 lvHitTestInfo
.pt
.y
+= infoPtr
->nItemHeight
;
3027 else if (vkDirection
== VK_UP
)
3029 lvHitTestInfo
.pt
.y
-= infoPtr
->nItemHeight
;
3031 else if (vkDirection
== VK_LEFT
)
3033 lvHitTestInfo
.pt
.x
-= infoPtr
->nItemWidth
;
3035 else if (vkDirection
== VK_RIGHT
)
3037 lvHitTestInfo
.pt
.x
+= infoPtr
->nItemWidth
;
3040 if (PtInRect(&rcView
, lvHitTestInfo
.pt
) == FALSE
)
3046 nItem
= LISTVIEW_HitTestItem(hwnd
, &lvHitTestInfo
);
3050 while (nItem
== -1);
3058 * Searches for an item with specific characteristics.
3061 * [I] HWND : window handle
3062 * [I] INT : base item index
3063 * [I] LPLVFINDINFO : item information to look for
3066 * SUCCESS : index of item
3069 static LRESULT
LISTVIEW_FindItem(HWND hwnd
, INT nStart
,
3070 LPLVFINDINFO lpFindInfo
)
3072 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3074 CHAR szDispText
[DISP_TEXT_SIZE
];
3078 INT nLast
= GETITEMCOUNT(infoPtr
);
3080 if ((nItem
>= -1) && (lpFindInfo
!= NULL
))
3082 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
3084 if (lpFindInfo
->flags
& LVFI_PARAM
)
3086 lvItem
.mask
|= LVIF_PARAM
;
3089 if (lpFindInfo
->flags
& LVFI_STRING
)
3091 lvItem
.mask
|= LVIF_TEXT
;
3092 lvItem
.pszText
= szDispText
;
3093 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3096 if (lpFindInfo
->flags
& LVFI_PARTIAL
)
3098 lvItem
.mask
|= LVIF_TEXT
;
3099 lvItem
.pszText
= szDispText
;
3100 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3103 if (lpFindInfo
->flags
& LVFI_WRAP
)
3108 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
3110 ptItem
.x
= lpFindInfo
->pt
.x
;
3111 ptItem
.y
= lpFindInfo
->pt
.y
;
3116 while (nItem
< nLast
)
3118 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
3120 nItem
= LISTVIEW_GetNearestItem(hwnd
, ptItem
,
3121 lpFindInfo
->vkDirection
);
3124 /* get position of the new item index */
3125 if (ListView_GetItemPosition(hwnd
, nItem
, &ptItem
) == FALSE
)
3136 lvItem
.iItem
= nItem
;
3137 lvItem
.iSubItem
= 0;
3138 if (ListView_GetItemA(hwnd
, &lvItem
) != FALSE
)
3140 if (lvItem
.mask
& LVIF_TEXT
)
3142 if (lpFindInfo
->flags
& LVFI_PARTIAL
)
3144 if (strstr(lvItem
.pszText
, lpFindInfo
->psz
) == NULL
)
3149 if (strcmp(lvItem
.pszText
, lpFindInfo
->psz
) != 0)
3154 if (lvItem
.mask
& LVIF_PARAM
)
3156 if (lpFindInfo
->lParam
!= lvItem
.lParam
)
3182 * Retrieves the background color of the listview control.
3185 * [I] HWND : window handle
3188 * COLORREF associated with the background.
3190 static LRESULT
LISTVIEW_GetBkColor(HWND hwnd
)
3192 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3194 return infoPtr
->clrBk
;
3199 * Retrieves the background image of the listview control.
3202 * [I] HWND : window handle
3203 * [O] LPLVMKBIMAGE : background image attributes
3209 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3211 /* FIXME (listview, "empty stub!\n"); */
3217 * Retrieves the callback mask.
3220 * [I] HWND : window handle
3225 static UINT
LISTVIEW_GetCallbackMask(HWND hwnd
)
3227 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3229 return infoPtr
->uCallbackMask
;
3234 * Retrieves column attributes.
3237 * [I] HWND : window handle
3238 * [I] INT : column index
3239 * [IO] LPLVCOLUMNA : column information
3245 static LRESULT
LISTVIEW_GetColumnA(HWND hwnd
, INT nItem
, LPLVCOLUMNA lpColumn
)
3247 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3249 BOOL bResult
= FALSE
;
3251 if (lpColumn
!= NULL
)
3253 /* initialize memory */
3254 ZeroMemory(&hdi
, sizeof(HDITEMA
));
3256 if (lpColumn
->mask
& LVCF_FMT
)
3258 hdi
.mask
|= HDI_FORMAT
;
3261 if (lpColumn
->mask
& LVCF_WIDTH
)
3263 hdi
.mask
|= HDI_WIDTH
;
3266 if (lpColumn
->mask
& LVCF_TEXT
)
3268 hdi
.mask
|= (HDI_TEXT
| HDI_FORMAT
);
3271 if (lpColumn
->mask
& LVCF_IMAGE
)
3273 hdi
.mask
|= HDI_IMAGE
;
3276 if (lpColumn
->mask
& LVCF_ORDER
)
3278 hdi
.mask
|= HDI_ORDER
;
3281 bResult
= Header_GetItemA(infoPtr
->hwndHeader
, nItem
, &hdi
);
3282 if (bResult
!= FALSE
)
3284 if (lpColumn
->mask
& LVCF_FMT
)
3288 if (hdi
.fmt
& HDF_LEFT
)
3290 lpColumn
->fmt
|= LVCFMT_LEFT
;
3292 else if (hdi
.fmt
& HDF_RIGHT
)
3294 lpColumn
->fmt
|= LVCFMT_RIGHT
;
3296 else if (hdi
.fmt
& HDF_CENTER
)
3298 lpColumn
->fmt
|= LVCFMT_CENTER
;
3301 if (hdi
.fmt
& HDF_IMAGE
)
3303 lpColumn
->fmt
|= LVCFMT_COL_HAS_IMAGES
;
3306 if (hdi
.fmt
& HDF_BITMAP_ON_RIGHT
)
3308 lpColumn
->fmt
|= LVCFMT_BITMAP_ON_RIGHT
;
3312 if (lpColumn
->mask
& LVCF_WIDTH
)
3314 lpColumn
->cx
= hdi
.cxy
;
3317 if ((lpColumn
->mask
& LVCF_TEXT
) && (lpColumn
->pszText
) && (hdi
.pszText
))
3319 lstrcpynA (lpColumn
->pszText
, hdi
.pszText
, lpColumn
->cchTextMax
);
3322 if (lpColumn
->mask
& LVCF_IMAGE
)
3324 lpColumn
->iImage
= hdi
.iImage
;
3327 if (lpColumn
->mask
& LVCF_ORDER
)
3329 lpColumn
->iOrder
= hdi
.iOrder
;
3337 /* LISTVIEW_GetColumnW */
3338 /* LISTVIEW_GetColumnOrderArray */
3342 * Retrieves the column width.
3345 * [I] HWND : window handle
3346 * [I] int : column index
3349 * SUCCESS : column width
3352 static LRESULT
LISTVIEW_GetColumnWidth(HWND hwnd
, INT nColumn
)
3354 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3355 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3356 INT nColumnWidth
= 0;
3359 if (uView
== LVS_LIST
)
3361 nColumnWidth
= infoPtr
->nItemWidth
;
3363 else if (uView
== LVS_REPORT
)
3365 /* get column width from header */
3366 ZeroMemory(&hdi
, sizeof(HDITEMA
));
3367 hdi
.mask
= HDI_WIDTH
;
3368 if (Header_GetItemA(infoPtr
->hwndHeader
, nColumn
, &hdi
) != FALSE
)
3370 nColumnWidth
= hdi
.cxy
;
3374 return nColumnWidth
;
3379 * In list or report display mode, retrieves the number of items that can fit
3380 * vertically in the visible area. In icon or small icon display mode,
3381 * retrieves the total number of visible items.
3384 * [I] HWND : window handle
3387 * Number of fully visible items.
3389 static LRESULT
LISTVIEW_GetCountPerPage(HWND hwnd
)
3391 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3392 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3395 if (uView
== LVS_LIST
)
3397 if (infoPtr
->rcList
.right
> infoPtr
->nItemWidth
)
3399 nItemCount
= LISTVIEW_GetCountPerRow(hwnd
) *
3400 LISTVIEW_GetCountPerColumn(hwnd
);
3403 else if (uView
== LVS_REPORT
)
3405 nItemCount
= LISTVIEW_GetCountPerColumn(hwnd
);
3409 nItemCount
= GETITEMCOUNT(infoPtr
);
3415 /* LISTVIEW_GetEditControl */
3419 * Retrieves the extended listview style.
3422 * [I] HWND : window handle
3425 * SUCCESS : previous style
3428 static LRESULT
LISTVIEW_GetExtendedListViewStyle(HWND hwnd
)
3430 LISTVIEW_INFO
*infoPtr
;
3432 /* make sure we can get the listview info */
3433 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
3436 return (infoPtr
->dwExStyle
);
3441 * Retrieves the handle to the header control.
3444 * [I] HWND : window handle
3449 static LRESULT
LISTVIEW_GetHeader(HWND hwnd
)
3451 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3453 return infoPtr
->hwndHeader
;
3456 /* LISTVIEW_GetHotCursor */
3457 /* LISTVIEW_GetHotItem */
3458 /* LISTVIEW_GetHoverTime */
3462 * Retrieves an image list handle.
3465 * [I] HWND : window handle
3466 * [I] INT : image list identifier
3469 * SUCCESS : image list handle
3472 static LRESULT
LISTVIEW_GetImageList(HWND hwnd
, INT nImageList
)
3474 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3475 HIMAGELIST himl
= NULL
;
3480 himl
= infoPtr
->himlNormal
;
3483 himl
= infoPtr
->himlSmall
;
3486 himl
= infoPtr
->himlState
;
3490 return (LRESULT
)himl
;
3493 /* LISTVIEW_GetISearchString */
3497 * Retrieves item attributes.
3500 * [I] HWND : window handle
3501 * [IO] LPLVITEMA : item info
3507 static LRESULT
LISTVIEW_GetItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
3509 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3510 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3511 BOOL bResult
= FALSE
;
3512 NMLVDISPINFOA dispInfo
;
3513 LISTVIEW_SUBITEM
*lpSubItem
;
3514 LISTVIEW_ITEM
*lpItem
;
3517 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd
, lpLVItem
);
3519 if (lpLVItem
!= NULL
)
3521 if ((lpLVItem
->iItem
>= 0) && (lpLVItem
->iItem
< GETITEMCOUNT(infoPtr
)))
3523 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
3524 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
3525 if (hdpaSubItems
!= NULL
)
3527 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
3531 if (lpLVItem
->iSubItem
== 0)
3533 if ((lpItem
->iImage
== I_IMAGECALLBACK
) &&
3534 (lpLVItem
->mask
& LVIF_IMAGE
))
3536 dispInfo
.item
.mask
|= LVIF_IMAGE
;
3539 if ((lpItem
->pszText
== LPSTR_TEXTCALLBACKA
) &&
3540 (lpLVItem
->mask
& LVIF_TEXT
))
3542 dispInfo
.item
.mask
|= LVIF_TEXT
;
3543 ZeroMemory(lpLVItem
->pszText
, sizeof(CHAR
)*lpLVItem
->cchTextMax
);
3544 dispInfo
.item
.pszText
= lpLVItem
->pszText
;
3545 dispInfo
.item
.cchTextMax
= lpLVItem
->cchTextMax
;
3548 if ((infoPtr
->uCallbackMask
!= 0) && (lpLVItem
->mask
& LVIF_STATE
))
3550 dispInfo
.item
.mask
|= LVIF_STATE
;
3551 dispInfo
.item
.stateMask
= infoPtr
->uCallbackMask
;
3554 if (dispInfo
.item
.mask
!= 0)
3556 dispInfo
.hdr
.hwndFrom
= hwnd
;
3557 dispInfo
.hdr
.idFrom
= lCtrlId
;
3558 dispInfo
.hdr
.code
= LVN_GETDISPINFOA
;
3559 dispInfo
.item
.iItem
= lpLVItem
->iItem
;
3560 dispInfo
.item
.iSubItem
= 0;
3561 dispInfo
.item
.lParam
= lpItem
->lParam
;
3562 ListView_Notify(GetParent(hwnd
), lCtrlId
, &dispInfo
);
3565 if (dispInfo
.item
.mask
& LVIF_IMAGE
)
3567 lpLVItem
->iImage
= dispInfo
.item
.iImage
;
3569 else if (lpLVItem
->mask
& LVIF_IMAGE
)
3571 lpLVItem
->iImage
= lpItem
->iImage
;
3574 if (dispInfo
.item
.mask
& LVIF_TEXT
)
3576 if (dispInfo
.item
.mask
& LVIF_DI_SETITEM
)
3578 Str_SetPtrA(&lpItem
->pszText
, dispInfo
.item
.pszText
);
3580 strncpy(lpLVItem
->pszText
, dispInfo
.item
.pszText
, lpLVItem
->cchTextMax
);
3582 else if (lpLVItem
->mask
& LVIF_TEXT
)
3584 strncpy(lpLVItem
->pszText
, lpItem
->pszText
, lpLVItem
->cchTextMax
);
3587 if (dispInfo
.item
.mask
& LVIF_STATE
)
3589 lpLVItem
->state
= lpItem
->state
;
3590 lpLVItem
->state
&= ~dispInfo
.item
.stateMask
;
3591 lpLVItem
->state
|= (dispInfo
.item
.state
&
3592 dispInfo
.item
.stateMask
);
3594 else if (lpLVItem
->mask
& LVIF_STATE
)
3596 lpLVItem
->state
= lpItem
->state
& lpLVItem
->stateMask
;
3599 if (lpLVItem
->mask
& LVIF_PARAM
)
3601 lpLVItem
->lParam
= lpItem
->lParam
;
3604 if (lpLVItem
->mask
& LVIF_INDENT
)
3606 lpLVItem
->iIndent
= lpItem
->iIndent
;
3611 lpSubItem
= LISTVIEW_GetSubItemPtr(hdpaSubItems
,
3612 lpLVItem
->iSubItem
);
3613 if (lpSubItem
!= NULL
)
3615 if ((lpSubItem
->iImage
== I_IMAGECALLBACK
) &&
3616 (lpLVItem
->mask
& LVIF_IMAGE
))
3618 dispInfo
.item
.mask
|= LVIF_IMAGE
;
3621 if ((lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
) &&
3622 (lpLVItem
->mask
& LVIF_TEXT
))
3624 dispInfo
.item
.mask
|= LVIF_TEXT
;
3625 ZeroMemory(lpLVItem
->pszText
,
3626 sizeof(CHAR
)*lpLVItem
->cchTextMax
);
3627 dispInfo
.item
.pszText
= lpLVItem
->pszText
;
3628 dispInfo
.item
.cchTextMax
= lpLVItem
->cchTextMax
;
3633 if (lpLVItem
->mask
& LVIF_IMAGE
)
3635 dispInfo
.item
.mask
|= LVIF_IMAGE
;
3638 if (lpLVItem
->mask
& LVIF_TEXT
)
3640 dispInfo
.item
.mask
|= LVIF_TEXT
;
3641 ZeroMemory(lpLVItem
->pszText
,
3642 sizeof(CHAR
)*lpLVItem
->cchTextMax
);
3643 dispInfo
.item
.pszText
= lpLVItem
->pszText
;
3644 dispInfo
.item
.cchTextMax
= lpLVItem
->cchTextMax
;
3648 if (dispInfo
.item
.mask
!= 0)
3650 dispInfo
.hdr
.hwndFrom
= hwnd
;
3651 dispInfo
.hdr
.idFrom
= lCtrlId
;
3652 dispInfo
.hdr
.code
= LVN_GETDISPINFOA
;
3653 dispInfo
.item
.iItem
= lpLVItem
->iItem
;
3654 dispInfo
.item
.iSubItem
= lpLVItem
->iSubItem
;
3655 dispInfo
.item
.lParam
= lpItem
->lParam
;
3656 ListView_Notify(GetParent(hwnd
), lCtrlId
, &dispInfo
);
3659 if (dispInfo
.item
.mask
& LVIF_IMAGE
)
3661 lpLVItem
->iImage
= dispInfo
.item
.iImage
;
3663 else if (lpLVItem
->mask
& LVIF_IMAGE
)
3665 lpLVItem
->iImage
= lpItem
->iImage
;
3668 if (dispInfo
.item
.mask
& LVIF_TEXT
)
3670 if (dispInfo
.item
.mask
& LVIF_DI_SETITEM
)
3673 Str_SetPtrA(&lpSubItem
->pszText
, dispInfo
.item
.pszText
);
3675 strncpy(lpLVItem
->pszText
, dispInfo
.item
.pszText
, lpLVItem
->cchTextMax
);
3677 else if (lpLVItem
->mask
& LVIF_TEXT
)
3679 strncpy(lpLVItem
->pszText
, lpSubItem
->pszText
, lpLVItem
->cchTextMax
);
3690 /* LISTVIEW_GetItemW */
3691 /* LISTVIEW_GetHotCursor */
3695 * Retrieves the index of the hot item.
3698 * [I] HWND : window handle
3701 * SUCCESS : hot item index
3702 * FAILURE : -1 (no hot item)
3704 static LRESULT
LISTVIEW_GetHotItem(HWND hwnd
)
3706 LISTVIEW_INFO
*infoPtr
;
3708 /* make sure we can get the listview info */
3709 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
3712 return (infoPtr
->nHotItem
);
3715 /* LISTVIEW_GetHoverTime */
3719 * Retrieves the number of items in the listview control.
3722 * [I] HWND : window handle
3727 static LRESULT
LISTVIEW_GetItemCount(HWND hwnd
)
3729 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3731 return GETITEMCOUNT(infoPtr
);
3736 * Retrieves the position (upper-left) of the listview control item.
3739 * [I] HWND : window handle
3740 * [I] INT : item index
3741 * [O] LPPOINT : coordinate information
3747 static BOOL
LISTVIEW_GetItemPosition(HWND hwnd
, INT nItem
,
3748 LPPOINT lpptPosition
)
3750 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3751 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3752 BOOL bResult
= FALSE
;
3754 LISTVIEW_ITEM
*lpItem
;
3755 INT nCountPerColumn
;
3758 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd
, nItem
,
3761 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) &&
3762 (lpptPosition
!= NULL
))
3764 if (uView
== LVS_LIST
)
3767 nItem
= nItem
- ListView_GetTopIndex(hwnd
);
3768 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
3771 nRow
= nItem
% nCountPerColumn
;
3774 lpptPosition
->x
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
3775 lpptPosition
->y
= 0;
3779 lpptPosition
->x
= (nItem
/ nCountPerColumn
-1) * infoPtr
->nItemWidth
;
3780 lpptPosition
->y
= (nRow
+ nCountPerColumn
) * infoPtr
->nItemHeight
;
3785 lpptPosition
->x
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
3786 lpptPosition
->y
= nItem
% nCountPerColumn
* infoPtr
->nItemHeight
;
3789 else if (uView
== LVS_REPORT
)
3792 lpptPosition
->x
= REPORT_MARGINX
;
3793 lpptPosition
->y
= ((nItem
- ListView_GetTopIndex(hwnd
)) *
3794 infoPtr
->nItemHeight
) + infoPtr
->rcList
.top
;
3798 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
3799 if (hdpaSubItems
!= NULL
)
3801 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
3805 lpptPosition
->x
= lpItem
->ptPosition
.x
;
3806 lpptPosition
->y
= lpItem
->ptPosition
.y
;
3817 * Retrieves the bounding rectangle for a listview control item.
3820 * [I] HWND : window handle
3821 * [I] INT : item index
3822 * [IO] LPRECT : bounding rectangle coordinates
3828 static LRESULT
LISTVIEW_GetItemRect(HWND hwnd
, INT nItem
, LPRECT lprc
)
3830 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3831 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3832 BOOL bResult
= FALSE
;
3841 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd
, nItem
, lprc
);
3843 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) && (lprc
!= NULL
))
3845 if (ListView_GetItemPosition(hwnd
, nItem
, &ptItem
) != FALSE
)
3850 if (uView
== LVS_ICON
)
3852 if (infoPtr
->himlNormal
!= NULL
)
3854 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
3857 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
3858 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
3859 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
3860 lprc
->bottom
= (lprc
->top
+ infoPtr
->iconSize
.cy
+
3861 ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
);
3865 else if (uView
== LVS_SMALLICON
)
3867 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
3870 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
3871 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
3872 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
3874 if (infoPtr
->himlState
!= NULL
)
3875 lprc
->left
+= infoPtr
->iconSize
.cx
;
3877 if (infoPtr
->himlSmall
!= NULL
)
3878 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
3880 lprc
->right
= lprc
->left
;
3886 lprc
->left
= ptItem
.x
;
3887 lprc
->top
= ptItem
.y
;
3888 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
3890 if (infoPtr
->himlState
!= NULL
)
3892 lprc
->left
+= infoPtr
->iconSize
.cx
;
3895 if (infoPtr
->himlSmall
!= NULL
)
3897 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
3901 lprc
->right
= lprc
->left
;
3907 if (uView
== LVS_ICON
)
3909 if (infoPtr
->himlNormal
!= NULL
)
3911 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
3914 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
3915 lprc
->top
= (ptItem
.y
+ ptOrigin
.y
+ infoPtr
->iconSize
.cy
+
3916 ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
);
3917 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
3918 if (infoPtr
->iconSpacing
.cx
- nLabelWidth
> 1)
3920 lprc
->left
+= (infoPtr
->iconSpacing
.cx
- nLabelWidth
) / 2;
3921 lprc
->right
= lprc
->left
+ nLabelWidth
;
3926 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
- 1;
3930 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
3931 GetTextMetricsA(hdc
, &tm
);
3932 lprc
->bottom
= lprc
->top
+ tm
.tmHeight
+ HEIGHT_PADDING
;
3933 SelectObject(hdc
, hOldFont
);
3934 ReleaseDC(hwnd
, hdc
);
3938 else if (uView
== LVS_SMALLICON
)
3940 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
3943 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
3944 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
3945 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
3947 if (infoPtr
->himlState
!= NULL
)
3949 lprc
->left
+= infoPtr
->iconSize
.cx
;
3952 if (infoPtr
->himlSmall
!= NULL
)
3954 lprc
->left
+= infoPtr
->iconSize
.cx
;
3957 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
3958 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
3960 lprc
->right
= lprc
->left
+ nLabelWidth
;
3964 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
3971 nLeftPos
= lprc
->left
= ptItem
.x
;
3972 lprc
->top
= ptItem
.y
;
3973 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
3975 if (infoPtr
->himlState
!= NULL
)
3977 lprc
->left
+= infoPtr
->iconSize
.cx
;
3980 if (infoPtr
->himlSmall
!= NULL
)
3982 lprc
->left
+= infoPtr
->iconSize
.cx
;
3985 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
3986 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
3988 lprc
->right
= lprc
->left
+ nLabelWidth
;
3992 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
3998 if (uView
== LVS_ICON
)
4000 if (infoPtr
->himlNormal
!= NULL
)
4002 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
4005 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
4006 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
4007 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
;
4008 lprc
->bottom
= lprc
->top
+ infoPtr
->iconSpacing
.cy
;
4012 else if (uView
== LVS_SMALLICON
)
4014 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
4017 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
4018 lprc
->right
= lprc
->left
;
4019 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
4020 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
4021 if (infoPtr
->himlState
!= NULL
)
4022 lprc
->right
+= infoPtr
->iconSize
.cx
;
4023 if (infoPtr
->himlSmall
!= NULL
)
4024 lprc
->right
+= infoPtr
->iconSize
.cx
;
4026 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
4027 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
4029 lprc
->right
+= nLabelWidth
;
4033 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
4040 lprc
->left
= ptItem
.x
;
4041 lprc
->right
= lprc
->left
;
4042 lprc
->top
= ptItem
.y
;
4043 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
4045 if (infoPtr
->himlState
!= NULL
)
4047 lprc
->right
+= infoPtr
->iconSize
.cx
;
4050 if (infoPtr
->himlSmall
!= NULL
)
4052 lprc
->right
+= infoPtr
->iconSize
.cx
;
4055 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
4056 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
4058 lprc
->right
+= nLabelWidth
;
4062 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
4067 case LVIR_SELECTBOUNDS
:
4068 if (uView
== LVS_ICON
)
4070 if (infoPtr
->himlNormal
!= NULL
)
4072 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
4075 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
4076 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
4077 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
;
4078 lprc
->bottom
= lprc
->top
+ infoPtr
->iconSpacing
.cy
;
4082 else if (uView
== LVS_SMALLICON
)
4084 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
4087 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
4088 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
4089 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
4091 if (infoPtr
->himlState
!= NULL
)
4093 lprc
->left
+= infoPtr
->iconSize
.cx
;
4096 lprc
->right
= lprc
->left
;
4098 if (infoPtr
->himlSmall
!= NULL
)
4100 lprc
->right
+= infoPtr
->iconSize
.cx
;
4103 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
4104 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
4106 lprc
->right
+= nLabelWidth
;
4110 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
4117 nLeftPos
= lprc
->left
= ptItem
.x
;
4118 lprc
->top
= ptItem
.y
;
4119 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
4121 if (infoPtr
->himlState
!= NULL
)
4123 lprc
->left
+= infoPtr
->iconSize
.cx
;
4126 lprc
->right
= lprc
->left
;
4128 if (infoPtr
->himlSmall
!= NULL
)
4130 lprc
->right
+= infoPtr
->iconSize
.cx
;
4133 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
4134 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
4136 lprc
->right
+= nLabelWidth
;
4140 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
4153 * Retrieves the width of a label.
4156 * [I] HWND : window handle
4159 * SUCCESS : string width (in pixels)
4162 static INT
LISTVIEW_GetLabelWidth(HWND hwnd
, INT nItem
)
4164 CHAR szDispText
[DISP_TEXT_SIZE
];
4165 INT nLabelWidth
= 0;
4168 TRACE("(hwnd=%x, nItem=%d)\n", hwnd
, nItem
);
4170 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
4171 lvItem
.mask
= LVIF_TEXT
;
4172 lvItem
.iItem
= nItem
;
4173 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4174 lvItem
.pszText
= szDispText
;
4175 if (ListView_GetItemA(hwnd
, &lvItem
) != FALSE
)
4177 nLabelWidth
= ListView_GetStringWidthA(hwnd
, lvItem
.pszText
);
4185 * Retrieves the spacing between listview control items.
4188 * [I] HWND : window handle
4189 * [I] BOOL : flag for small or large icon
4192 * Horizontal + vertical spacing
4194 static LRESULT
LISTVIEW_GetItemSpacing(HWND hwnd
, BOOL bSmall
)
4196 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4199 if (bSmall
== FALSE
)
4201 lResult
= MAKELONG(infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
4205 /* TODO: need to store width of smallicon item */
4206 lResult
= MAKELONG(0, infoPtr
->nItemHeight
);
4214 * Retrieves the state of a listview control item.
4217 * [I] HWND : window handle
4218 * [I] INT : item index
4219 * [I] UINT : state mask
4222 * State specified by the mask.
4224 static LRESULT
LISTVIEW_GetItemState(HWND hwnd
, INT nItem
, UINT uMask
)
4226 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4230 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4232 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
4233 lvItem
.iItem
= nItem
;
4234 lvItem
.stateMask
= uMask
;
4235 lvItem
.mask
= LVIF_STATE
;
4236 if (ListView_GetItemA(hwnd
, &lvItem
) != FALSE
)
4238 uState
= lvItem
.state
;
4247 * Retrieves the text of a listview control item or subitem.
4250 * [I] HWND : window handle
4251 * [I] INT : item index
4252 * [IO] LPLVITEMA : item information
4255 * SUCCESS : string length
4258 static LRESULT
LISTVIEW_GetItemTextA(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
4260 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4263 if (lpLVItem
!= NULL
)
4265 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4267 lpLVItem
->mask
= LVIF_TEXT
;
4268 lpLVItem
->iItem
= nItem
;
4269 if (ListView_GetItemA(hwnd
, lpLVItem
) != FALSE
)
4271 nLength
= lstrlenA(lpLVItem
->pszText
);
4281 * Searches for an item based on properties + relationships.
4284 * [I] HWND : window handle
4285 * [I] INT : item index
4286 * [I] INT : relationship flag
4289 * SUCCESS : item index
4292 static LRESULT
LISTVIEW_GetNextItem(HWND hwnd
, INT nItem
, UINT uFlags
)
4294 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4295 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
4297 LVFINDINFO lvFindInfo
;
4298 INT nCountPerColumn
;
4301 if ((nItem
>= -1) && (nItem
< GETITEMCOUNT(infoPtr
)))
4303 ZeroMemory(&lvFindInfo
, sizeof(LVFINDINFO
));
4305 if (uFlags
& LVNI_CUT
)
4308 if (uFlags
& LVNI_DROPHILITED
)
4309 uMask
|= LVIS_DROPHILITED
;
4311 if (uFlags
& LVNI_FOCUSED
)
4312 uMask
|= LVIS_FOCUSED
;
4314 if (uFlags
& LVNI_SELECTED
)
4315 uMask
|= LVIS_SELECTED
;
4317 if (uFlags
& LVNI_ABOVE
)
4319 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
4324 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4330 lvFindInfo
.flags
= LVFI_NEARESTXY
;
4331 lvFindInfo
.vkDirection
= VK_UP
;
4332 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
4333 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
4335 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4340 else if (uFlags
& LVNI_BELOW
)
4342 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
4344 while (nItem
< GETITEMCOUNT(infoPtr
))
4347 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4353 lvFindInfo
.flags
= LVFI_NEARESTXY
;
4354 lvFindInfo
.vkDirection
= VK_DOWN
;
4355 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
4356 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
4358 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4363 else if (uFlags
& LVNI_TOLEFT
)
4365 if (uView
== LVS_LIST
)
4367 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
4368 while (nItem
- nCountPerColumn
>= 0)
4370 nItem
-= nCountPerColumn
;
4371 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4375 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4377 lvFindInfo
.flags
= LVFI_NEARESTXY
;
4378 lvFindInfo
.vkDirection
= VK_LEFT
;
4379 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
4380 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
4382 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4387 else if (uFlags
& LVNI_TORIGHT
)
4389 if (uView
== LVS_LIST
)
4391 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
4392 while (nItem
+ nCountPerColumn
< GETITEMCOUNT(infoPtr
))
4394 nItem
+= nCountPerColumn
;
4395 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4399 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4401 lvFindInfo
.flags
= LVFI_NEARESTXY
;
4402 lvFindInfo
.vkDirection
= VK_RIGHT
;
4403 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
4404 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
4406 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
4415 /* search by index */
4416 for (i
= nItem
; i
< GETITEMCOUNT(infoPtr
); i
++)
4418 if ((ListView_GetItemState(hwnd
, i
, uMask
) & uMask
) == uMask
)
4427 /* LISTVIEW_GetNumberOfWorkAreas */
4431 * Retrieves the origin coordinates when in icon or small icon display mode.
4434 * [I] HWND : window handle
4435 * [O] LPPOINT : coordinate information
4441 static LRESULT
LISTVIEW_GetOrigin(HWND hwnd
, LPPOINT lpptOrigin
)
4443 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4444 UINT uView
= lStyle
& LVS_TYPEMASK
;
4445 BOOL bResult
= FALSE
;
4447 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd
, lpptOrigin
);
4449 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4451 SCROLLINFO scrollInfo
;
4452 ZeroMemory(lpptOrigin
, sizeof(POINT
));
4453 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
4454 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
4456 if (lStyle
& WS_HSCROLL
)
4458 scrollInfo
.fMask
= SIF_POS
;
4459 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
4461 lpptOrigin
->x
= -scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
4465 if (lStyle
& WS_VSCROLL
)
4467 scrollInfo
.fMask
= SIF_POS
;
4468 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
4470 lpptOrigin
->y
= -scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
4482 * Retrieves the number of items that are marked as selected.
4485 * [I] HWND : window handle
4488 * Number of items selected.
4490 static LRESULT
LISTVIEW_GetSelectedCount(HWND hwnd
)
4492 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4493 INT nSelectedCount
= 0;
4496 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
4498 if (ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
) & LVIS_SELECTED
)
4504 return nSelectedCount
;
4509 * Retrieves item index that marks the start of a multiple selection.
4512 * [I] HWND : window handle
4515 * Index number or -1 if there is no selection mark.
4517 static LRESULT
LISTVIEW_GetSelectionMark(HWND hwnd
)
4519 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4521 return infoPtr
->nSelectionMark
;
4526 * Retrieves the width of a string.
4529 * [I] HWND : window handle
4532 * SUCCESS : string width (in pixels)
4535 static LRESULT
LISTVIEW_GetStringWidthA(HWND hwnd
, LPCSTR lpszText
)
4537 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4538 HFONT hFont
, hOldFont
;
4542 ZeroMemory(&stringSize
, sizeof(SIZE
));
4543 if (lpszText
!= NULL
)
4545 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
;
4547 hOldFont
= SelectObject(hdc
, hFont
);
4548 GetTextExtentPointA(hdc
, lpszText
, lstrlenA(lpszText
), &stringSize
);
4549 SelectObject(hdc
, hOldFont
);
4550 ReleaseDC(hwnd
, hdc
);
4553 return stringSize
.cx
;
4558 * Retrieves the text backgound color.
4561 * [I] HWND : window handle
4564 * COLORREF associated with the the background.
4566 static LRESULT
LISTVIEW_GetTextBkColor(HWND hwnd
)
4568 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4570 return infoPtr
->clrTextBk
;
4575 * Retrieves the text color.
4578 * [I] HWND : window handle
4581 * COLORREF associated with the text.
4583 static LRESULT
LISTVIEW_GetTextColor(HWND hwnd
)
4585 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4587 return infoPtr
->clrText
;
4592 * Determines which section of the item was selected (if any).
4595 * [I] HWND : window handle
4596 * [IO] LPLVHITTESTINFO : hit test information
4599 * SUCCESS : item index
4602 static INT
LISTVIEW_HitTestItem(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
4604 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4608 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd
, lpHitTestInfo
->pt
.x
,
4609 lpHitTestInfo
->pt
.y
);
4611 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
4613 rcItem
.left
= LVIR_BOUNDS
;
4614 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) != FALSE
)
4616 if (PtInRect(&rcItem
, lpHitTestInfo
->pt
) != FALSE
)
4618 rcItem
.left
= LVIR_ICON
;
4619 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) != FALSE
)
4621 if (PtInRect(&rcItem
, lpHitTestInfo
->pt
) != FALSE
)
4623 lpHitTestInfo
->flags
= LVHT_ONITEMICON
;
4624 lpHitTestInfo
->iItem
= i
;
4625 lpHitTestInfo
->iSubItem
= 0;
4630 rcItem
.left
= LVIR_LABEL
;
4631 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) != FALSE
)
4633 if (PtInRect(&rcItem
, lpHitTestInfo
->pt
) != FALSE
)
4635 lpHitTestInfo
->flags
= LVHT_ONITEMLABEL
;
4636 lpHitTestInfo
->iItem
= i
;
4637 lpHitTestInfo
->iSubItem
= 0;
4642 lpHitTestInfo
->flags
= LVHT_ONITEMSTATEICON
;
4643 lpHitTestInfo
->iItem
= i
;
4644 lpHitTestInfo
->iSubItem
= 0;
4650 lpHitTestInfo
->flags
= LVHT_NOWHERE
;
4657 * Determines which listview item is located at the specified position.
4660 * [I] HWND : window handle
4661 * [IO} LPLVHITTESTINFO : hit test information
4664 * SUCCESS : item index
4667 static LRESULT
LISTVIEW_HitTest(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
4669 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4672 lpHitTestInfo
->flags
= 0;
4674 if (infoPtr
->rcList
.left
> lpHitTestInfo
->pt
.x
)
4676 lpHitTestInfo
->flags
= LVHT_TOLEFT
;
4678 else if (infoPtr
->rcList
.right
< lpHitTestInfo
->pt
.x
)
4680 lpHitTestInfo
->flags
= LVHT_TORIGHT
;
4682 if (infoPtr
->rcList
.top
> lpHitTestInfo
->pt
.y
)
4684 lpHitTestInfo
->flags
|= LVHT_ABOVE
;
4686 else if (infoPtr
->rcList
.bottom
< lpHitTestInfo
->pt
.y
)
4688 lpHitTestInfo
->flags
|= LVHT_BELOW
;
4691 if (lpHitTestInfo
->flags
== 0)
4693 nItem
= LISTVIEW_HitTestItem(hwnd
, lpHitTestInfo
);
4701 * Inserts a new column.
4704 * [I] HWND : window handle
4705 * [I] INT : column index
4706 * [I] LPLVCOLUMNA : column information
4709 * SUCCESS : new column index
4712 static LRESULT
LISTVIEW_InsertColumnA(HWND hwnd
, INT nColumn
,
4713 LPLVCOLUMNA lpColumn
)
4715 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4717 INT nNewColumn
= -1;
4719 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd
, nColumn
,
4722 if (lpColumn
!= NULL
)
4724 /* initialize memory */
4725 ZeroMemory(&hdi
, sizeof(HDITEMA
));
4727 if (lpColumn
->mask
& LVCF_FMT
)
4729 /* format member is valid */
4730 hdi
.mask
|= HDI_FORMAT
;
4732 /* set text alignment (leftmost column must be left-aligned) */
4735 hdi
.fmt
|= HDF_LEFT
;
4739 if (lpColumn
->fmt
& LVCFMT_LEFT
)
4741 hdi
.fmt
|= HDF_LEFT
;
4743 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
4745 hdi
.fmt
|= HDF_RIGHT
;
4747 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
4749 hdi
.fmt
|= HDF_CENTER
;
4753 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
4755 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
4759 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
4764 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
4766 hdi
.fmt
|= HDF_IMAGE
;
4767 hdi
.iImage
= I_IMAGECALLBACK
;
4771 if (lpColumn
->mask
& LVCF_WIDTH
)
4773 hdi
.mask
|= HDI_WIDTH
;
4774 hdi
.cxy
= lpColumn
->cx
;
4777 if (lpColumn
->mask
& LVCF_TEXT
)
4779 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
4780 hdi
.pszText
= lpColumn
->pszText
;
4781 hdi
.cchTextMax
= lstrlenA(lpColumn
->pszText
);
4782 hdi
.fmt
|= HDF_STRING
;
4785 if (lpColumn
->mask
& LVCF_IMAGE
)
4787 hdi
.mask
|= HDI_IMAGE
;
4788 hdi
.iImage
= lpColumn
->iImage
;
4791 if (lpColumn
->mask
& LVCF_ORDER
)
4793 hdi
.mask
|= HDI_ORDER
;
4794 hdi
.iOrder
= lpColumn
->iOrder
;
4797 /* insert item in header control */
4798 nNewColumn
= SendMessageA(infoPtr
->hwndHeader
, HDM_INSERTITEMA
,
4799 (WPARAM
)nColumn
, (LPARAM
)&hdi
);
4801 /* Need to reset the item width when inserting a new column */
4802 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
4804 LISTVIEW_UpdateScroll(hwnd
);
4805 InvalidateRect(hwnd
, NULL
, FALSE
);
4811 static LRESULT
LISTVIEW_InsertColumnW(HWND hwnd
, INT nColumn
,
4812 LPLVCOLUMNW lpColumn
)
4817 memcpy(&lvca
,lpColumn
,sizeof(lvca
));
4818 if (lpColumn
->mask
& LVCF_TEXT
)
4819 lvca
.pszText
= HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn
->pszText
);
4820 lres
= LISTVIEW_InsertColumnA(hwnd
,nColumn
,&lvca
);
4821 if (lpColumn
->mask
& LVCF_TEXT
)
4822 HeapFree(GetProcessHeap(),0,lvca
.pszText
);
4829 * Inserts a new item in the listview control.
4832 * [I] HWND : window handle
4833 * [I] LPLVITEMA : item information
4836 * SUCCESS : new item index
4839 static LRESULT
LISTVIEW_InsertItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
4841 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4842 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4843 UINT uView
= lStyle
& LVS_TYPEMASK
;
4844 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4849 LISTVIEW_ITEM
*lpItem
= NULL
;
4851 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd
, lpLVItem
);
4853 if (lpLVItem
!= NULL
)
4855 /* make sure it's not a subitem; cannot insert a subitem */
4856 if (lpLVItem
->iSubItem
== 0)
4858 lpItem
= (LISTVIEW_ITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM
));
4861 ZeroMemory(lpItem
, sizeof(LISTVIEW_ITEM
));
4862 if (LISTVIEW_InitItem(hwnd
, lpItem
, lpLVItem
) != FALSE
)
4864 /* insert item in listview control data structure */
4865 hdpaSubItems
= DPA_Create(8);
4866 if (hdpaSubItems
!= NULL
)
4868 nItem
= DPA_InsertPtr(hdpaSubItems
, 0, lpItem
);
4871 nItem
= DPA_InsertPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
,
4875 /* manage item focus */
4876 if (lpLVItem
->mask
& LVIF_STATE
)
4878 if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
4880 LISTVIEW_SetItemFocus(hwnd
, nItem
);
4884 /* send LVN_INSERTITEM notification */
4885 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
4886 nmlv
.hdr
.hwndFrom
= hwnd
;
4887 nmlv
.hdr
.idFrom
= lCtrlId
;
4888 nmlv
.hdr
.code
= LVN_INSERTITEM
;
4890 nmlv
.lParam
= lpItem
->lParam
;;
4891 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
4893 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_LIST
))
4895 nItemWidth
= LISTVIEW_CalculateWidth(hwnd
, lpLVItem
->iItem
);
4896 if (nItemWidth
> infoPtr
->nItemWidth
)
4898 infoPtr
->nItemWidth
= nItemWidth
;
4902 /* align items (set position of each item) */
4903 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4905 if (lStyle
& LVS_ALIGNLEFT
)
4907 LISTVIEW_AlignLeft(hwnd
);
4911 LISTVIEW_AlignTop(hwnd
);
4915 LISTVIEW_UpdateScroll(hwnd
);
4916 /* refresh client area */
4917 InvalidateRect(hwnd
, NULL
, FALSE
);
4926 /* free memory if unsuccessful */
4927 if ((nItem
== -1) && (lpItem
!= NULL
))
4929 COMCTL32_Free(lpItem
);
4935 static LRESULT
LISTVIEW_InsertItemW(HWND hwnd
, LPLVITEMW lpLVItem
) {
4939 memcpy(&lvia
,lpLVItem
,sizeof(LVITEMA
));
4940 if (lvia
.mask
& LVIF_TEXT
) {
4941 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
4942 lvia
.pszText
= LPSTR_TEXTCALLBACKA
;
4944 lvia
.pszText
= HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem
->pszText
);
4946 lres
= LISTVIEW_InsertItemA(hwnd
, &lvia
);
4947 if (lvia
.mask
& LVIF_TEXT
) {
4948 if (lpLVItem
->pszText
!= LPSTR_TEXTCALLBACKW
)
4949 HeapFree(GetProcessHeap(),0,lvia
.pszText
);
4954 /* LISTVIEW_InsertItemW */
4958 * Redraws a range of items.
4961 * [I] HWND : window handle
4962 * [I] INT : first item
4963 * [I] INT : last item
4969 static LRESULT
LISTVIEW_RedrawItems(HWND hwnd
, INT nFirst
, INT nLast
)
4971 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4972 BOOL bResult
= FALSE
;
4975 if (nFirst
<= nLast
)
4977 if ((nFirst
>= 0) && (nFirst
< GETITEMCOUNT(infoPtr
)))
4979 if ((nLast
>= 0) && (nLast
< GETITEMCOUNT(infoPtr
)))
4982 InvalidateRect(hwnd
, &rc
, FALSE
);
4990 /* LISTVIEW_Scroll */
4994 * Sets the background color.
4997 * [I] HWND : window handle
4998 * [I] COLORREF : background color
5004 static LRESULT
LISTVIEW_SetBkColor(HWND hwnd
, COLORREF clrBk
)
5006 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5008 infoPtr
->clrBk
= clrBk
;
5009 InvalidateRect(hwnd
, NULL
, TRUE
);
5014 /* LISTVIEW_SetBkImage */
5018 * Sets the callback mask. This mask will be used when the parent
5019 * window stores state information (some or all).
5022 * [I] HWND : window handle
5023 * [I] UINT : state mask
5029 static BOOL
LISTVIEW_SetCallbackMask(HWND hwnd
, UINT uMask
)
5031 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5033 infoPtr
->uCallbackMask
= uMask
;
5040 * Sets the attributes of a header item.
5043 * [I] HWND : window handle
5044 * [I] INT : column index
5045 * [I] LPLVCOLUMNA : column attributes
5051 static LRESULT
LISTVIEW_SetColumnA(HWND hwnd
, INT nColumn
,
5052 LPLVCOLUMNA lpColumn
)
5054 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5055 BOOL bResult
= FALSE
;
5056 HDITEMA hdi
, hdiget
;
5058 if ((lpColumn
!= NULL
) && (nColumn
>= 0) &&
5059 (nColumn
< Header_GetItemCount(infoPtr
->hwndHeader
)))
5061 /* initialize memory */
5062 ZeroMemory(&hdi
, sizeof(HDITEMA
));
5064 if (lpColumn
->mask
& LVCF_FMT
)
5066 /* format member is valid */
5067 hdi
.mask
|= HDI_FORMAT
;
5069 /* get current format first */
5070 hdiget
.mask
= HDI_FORMAT
;
5071 if (Header_GetItemA(infoPtr
->hwndHeader
, nColumn
, &hdiget
))
5072 /* preserve HDF_STRING if present */
5073 hdi
.fmt
= hdiget
.fmt
& HDF_STRING
;
5075 /* set text alignment (leftmost column must be left-aligned) */
5078 hdi
.fmt
|= HDF_LEFT
;
5082 if (lpColumn
->fmt
& LVCFMT_LEFT
)
5084 hdi
.fmt
|= HDF_LEFT
;
5086 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
5088 hdi
.fmt
|= HDF_RIGHT
;
5090 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
5092 hdi
.fmt
|= HDF_CENTER
;
5096 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
5098 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
5101 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
5103 hdi
.fmt
|= HDF_IMAGE
;
5106 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
5108 hdi
.fmt
|= HDF_IMAGE
;
5109 hdi
.iImage
= I_IMAGECALLBACK
;
5113 if (lpColumn
->mask
& LVCF_WIDTH
)
5115 hdi
.mask
|= HDI_WIDTH
;
5116 hdi
.cxy
= lpColumn
->cx
;
5119 if (lpColumn
->mask
& LVCF_TEXT
)
5121 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
5122 hdi
.pszText
= lpColumn
->pszText
;
5123 hdi
.cchTextMax
= lstrlenA(lpColumn
->pszText
);
5124 hdi
.fmt
|= HDF_STRING
;
5127 if (lpColumn
->mask
& LVCF_IMAGE
)
5129 hdi
.mask
|= HDI_IMAGE
;
5130 hdi
.iImage
= lpColumn
->iImage
;
5133 if (lpColumn
->mask
& LVCF_ORDER
)
5135 hdi
.mask
|= HDI_ORDER
;
5136 hdi
.iOrder
= lpColumn
->iOrder
;
5139 /* set header item attributes */
5140 bResult
= Header_SetItemA(infoPtr
->hwndHeader
, nColumn
, &hdi
);
5146 /* LISTVIEW_SetColumnW */
5147 /* LISTVIEW_SetColumnOrderArray */
5151 * Sets the width of a column
5154 * [I] HWND : window handle
5155 * [I] INT : column index
5156 * [I] INT : column width
5162 static LRESULT
LISTVIEW_SetColumnWidth(HWND hwnd
, INT iCol
, INT cx
)
5164 LISTVIEW_INFO
*infoPtr
;
5169 /* set column width only if in report mode */
5170 lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
5171 if ((lStyle
& LVS_TYPEMASK
) != LVS_REPORT
)
5174 /* make sure we can get the listview info */
5175 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
5177 if (!infoPtr
->hwndHeader
) /* make sure we have a header */
5180 /* FIXME: currently ignoring LVSCW_AUTOSIZE (-1) and
5181 * LVSCV_AUTOSIZE_USEHEADER (-2)
5186 hdi
.mask
= HDI_WIDTH
;
5189 /* call header to update the column change */
5190 lret
= Header_SetItemA(infoPtr
->hwndHeader
, (WPARAM
)iCol
, (LPARAM
)&hdi
);
5192 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
5194 InvalidateRect(hwnd
, NULL
, TRUE
); /* force redraw of the listview */
5201 * Sets the extended listview style.
5204 * [I] HWND : window handle
5209 * SUCCESS : previous style
5212 static LRESULT
LISTVIEW_SetExtendedListViewStyle(HWND hwnd
, DWORD dwMask
, DWORD dwStyle
)
5214 LISTVIEW_INFO
*infoPtr
;
5217 /* make sure we can get the listview info */
5218 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
5221 /* store previous style */
5222 dwOldStyle
= infoPtr
->dwExStyle
;
5225 infoPtr
->dwExStyle
= (dwOldStyle
& ~dwMask
) | (dwStyle
& dwMask
);
5227 return (dwOldStyle
);
5230 /* LISTVIEW_SetHotCursor */
5234 * Sets the hot item index.
5237 * [I] HWND : window handle
5241 * SUCCESS : previous hot item index
5242 * FAILURE : -1 (no hot item)
5244 static LRESULT
LISTVIEW_SetHotItem(HWND hwnd
, INT iIndex
)
5246 LISTVIEW_INFO
*infoPtr
;
5249 /* make sure we can get the listview info */
5250 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
5253 /* store previous index */
5254 iOldIndex
= infoPtr
->nHotItem
;
5257 infoPtr
->nHotItem
= iIndex
;
5262 /* LISTVIEW_SetIconSpacing */
5269 * [I] HWND : window handle
5270 * [I] INT : image list type
5271 * [I] HIMAGELIST : image list handle
5274 * SUCCESS : old image list
5277 static LRESULT
LISTVIEW_SetImageList(HWND hwnd
, INT nType
, HIMAGELIST himl
)
5279 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5280 HIMAGELIST himlTemp
= 0;
5285 himlTemp
= infoPtr
->himlNormal
;
5286 infoPtr
->himlNormal
= himl
;
5287 return (LRESULT
)himlTemp
;
5290 himlTemp
= infoPtr
->himlSmall
;
5291 infoPtr
->himlSmall
= himl
;
5292 return (LRESULT
)himlTemp
;
5295 himlTemp
= infoPtr
->himlState
;
5296 infoPtr
->himlState
= himl
;
5297 ImageList_SetBkColor(infoPtr
->himlState
, CLR_NONE
);
5298 return (LRESULT
)himlTemp
;
5301 return (LRESULT
)NULL
;
5307 * Sets the attributes of an item.
5310 * [I] HWND : window handle
5311 * [I] LPLVITEM : item information
5317 static LRESULT
LISTVIEW_SetItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
5319 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5320 BOOL bResult
= FALSE
;
5322 if (lpLVItem
!= NULL
)
5324 if ((lpLVItem
->iItem
>= 0) && (lpLVItem
->iItem
< GETITEMCOUNT(infoPtr
)))
5326 if (lpLVItem
->iSubItem
== 0)
5328 bResult
= LISTVIEW_SetItem(hwnd
, lpLVItem
);
5332 bResult
= LISTVIEW_SetSubItem(hwnd
, lpLVItem
);
5341 /* LISTVIEW_SetItemW */
5345 * Preallocates memory.
5348 * [I] HWND : window handle
5349 * [I] INT : item count (prjected number of items)
5350 * [I] DWORD : update flags
5356 static BOOL
LISTVIEW_SetItemCount(HWND hwnd
, INT nItems
, DWORD dwFlags
)
5358 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5360 FIXME("(%d %08lx)empty stub!\n", nItems
, dwFlags
);
5363 return LISTVIEW_DeleteAllItems (hwnd
);
5365 if (nItems
> GETITEMCOUNT(infoPtr
))
5368 FIXME("append items\n");
5371 else if (nItems
< GETITEMCOUNT(infoPtr
))
5374 FIXME("remove items\n");
5383 * Sets the position of an item.
5386 * [I] HWND : window handle
5387 * [I] INT : item index
5388 * [I] INT : x coordinate
5389 * [I] INT : y coordinate
5395 static BOOL
LISTVIEW_SetItemPosition(HWND hwnd
, INT nItem
,
5396 INT nPosX
, INT nPosY
)
5398 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5399 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5400 LISTVIEW_ITEM
*lpItem
;
5402 BOOL bResult
= FALSE
;
5404 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd
, nItem
, nPosX
, nPosY
);
5406 if ((nItem
>= 0) || (nItem
< GETITEMCOUNT(infoPtr
)))
5408 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
5410 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
5411 if (hdpaSubItems
!= NULL
)
5413 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
5417 lpItem
->ptPosition
.x
= nPosX
;
5418 lpItem
->ptPosition
.y
= nPosY
;
5427 /* LISTVIEW_SetItemPosition32 */
5431 * Sets the state of one or many items.
5434 * [I] HWND : window handle
5435 * [I]INT : item index
5436 * [I] LPLVITEM : item or subitem info
5442 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
5444 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5445 BOOL bResult
= FALSE
;
5452 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
5453 lvItem
.mask
= LVIF_STATE
;
5454 lvItem
.state
= lpLVItem
->state
;
5455 lvItem
.stateMask
= lpLVItem
->stateMask
;
5457 /* apply to all items */
5458 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
5461 if (ListView_SetItemA(hwnd
, &lvItem
) == FALSE
)
5469 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
5470 lvItem
.mask
= LVIF_STATE
;
5471 lvItem
.state
= lpLVItem
->state
;
5472 lvItem
.stateMask
= lpLVItem
->stateMask
;
5473 lvItem
.iItem
= nItem
;
5474 bResult
= ListView_SetItemA(hwnd
, &lvItem
);
5482 * Sets the text of an item or subitem.
5485 * [I] HWND : window handle
5486 * [I] INT : item index
5487 * [I] LPLVITEMA : item or subitem info
5493 static BOOL
LISTVIEW_SetItemTextA(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
5495 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5496 BOOL bResult
= FALSE
;
5499 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
5501 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
5502 lvItem
.mask
= LVIF_TEXT
;
5503 lvItem
.pszText
= lpLVItem
->pszText
;
5504 lvItem
.iItem
= nItem
;
5505 lvItem
.iSubItem
= lpLVItem
->iSubItem
;
5506 bResult
= ListView_SetItemA(hwnd
, &lvItem
);
5512 /* LISTVIEW_SetItemTextW */
5516 * Set item index that marks the start of a multiple selection.
5519 * [I] HWND : window handle
5523 * Index number or -1 if there is no selection mark.
5525 static LRESULT
LISTVIEW_SetSelectionMark(HWND hwnd
, INT nIndex
)
5527 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5528 INT nOldIndex
= infoPtr
->nSelectionMark
;
5530 infoPtr
->nSelectionMark
= nIndex
;
5537 * Sets the text background color.
5540 * [I] HWND : window handle
5541 * [I] COLORREF : text background color
5547 static LRESULT
LISTVIEW_SetTextBkColor(HWND hwnd
, COLORREF clrTextBk
)
5549 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5551 infoPtr
->clrTextBk
= clrTextBk
;
5552 InvalidateRect(hwnd
, NULL
, TRUE
);
5559 * Sets the text foreground color.
5562 * [I] HWND : window handle
5563 * [I] COLORREF : text color
5569 static LRESULT
LISTVIEW_SetTextColor (HWND hwnd
, COLORREF clrText
)
5571 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5573 infoPtr
->clrText
= clrText
;
5574 InvalidateRect(hwnd
, NULL
, TRUE
);
5579 /* LISTVIEW_SetToolTips */
5580 /* LISTVIEW_SetUnicodeFormat */
5581 /* LISTVIEW_SetWorkAreas */
5585 * Callback internally used by LISTVIEW_SortItems()
5588 * [I] LPVOID : first LISTVIEW_ITEM to compare
5589 * [I] LPVOID : second LISTVIEW_ITEM to compare
5590 * [I] LPARAM : HWND of control
5593 * if first comes before second : negative
5594 * if first comes after second : positive
5595 * if first and second are equivalent : zero
5597 static INT WINAPI
LISTVIEW_CallBackCompare(
5602 /* Forward the call to the client defined callback */
5603 HWND hwnd
= (HWND
)lParam
;
5604 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5606 return (infoPtr
->pfnCompare
)(
5607 ((LISTVIEW_ITEM
*)first
)->lParam
,
5608 ((LISTVIEW_ITEM
*)second
)->lParam
,
5609 infoPtr
->lParamSort
);
5614 * Sorts the listview items.
5617 * [I] HWND : window handle
5618 * [I] WPARAM : application-defined value
5619 * [I] LPARAM : pointer to comparision callback
5625 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
5627 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5629 LISTVIEW_ITEM
*lpItem
;
5633 if (!infoPtr
|| !infoPtr
->hdpaItems
)
5636 nCount
= GETITEMCOUNT(infoPtr
);
5637 /* if there are 0 or 1 items, there is no need to sort */
5640 sortList
= DPA_Create(nCount
);
5642 infoPtr
->pfnCompare
= (PFNLVCOMPARE
)lParam
;
5643 infoPtr
->lParamSort
= (LPARAM
)wParam
;
5645 /* append pointers one by one to sortList */
5646 for (i
= 0; i
< nCount
; i
++)
5648 if ((hdpaSubItems
= (HDPA
) DPA_GetPtr(infoPtr
->hdpaItems
, i
)))
5649 if ((lpItem
= (LISTVIEW_ITEM
*) DPA_GetPtr(hdpaSubItems
, 0)))
5650 DPA_InsertPtr(sortList
, nCount
+ 1, lpItem
);
5653 /* sort the sortList */
5654 DPA_Sort(sortList
, LISTVIEW_CallBackCompare
, hwnd
);
5656 /* copy the pointers back */
5657 for (i
= 0; i
< nCount
; i
++)
5659 if ((hdpaSubItems
= (HDPA
) DPA_GetPtr(infoPtr
->hdpaItems
, i
)) &&
5660 (lpItem
= (LISTVIEW_ITEM
*) DPA_GetPtr(sortList
, i
)))
5661 DPA_SetPtr(hdpaSubItems
, 0, lpItem
);
5664 DPA_Destroy(sortList
);
5670 /* LISTVIEW_SubItemHitTest */
5674 * Updates an items or rearranges the listview control.
5677 * [I] HWND : window handle
5678 * [I] INT : item index
5684 static LRESULT
LISTVIEW_Update(HWND hwnd
, INT nItem
)
5686 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5687 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
5688 BOOL bResult
= FALSE
;
5691 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
5695 /* rearrange with default alignment style */
5696 if ((lStyle
& LVS_AUTOARRANGE
) && (((lStyle
& LVS_TYPEMASK
) == LVS_ICON
) ||
5697 ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)))
5699 ListView_Arrange(hwnd
, 0);
5703 /* get item bounding rectangle */
5704 rc
.left
= LVIR_BOUNDS
;
5705 ListView_GetItemRect(hwnd
, nItem
, &rc
);
5706 InvalidateRect(hwnd
, &rc
, TRUE
);
5715 * Creates the listview control.
5718 * [I] HWND : window handle
5723 static LRESULT
LISTVIEW_Create(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
5725 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5726 LPCREATESTRUCTA lpcs
= (LPCREATESTRUCTA
)lParam
;
5727 UINT uView
= lpcs
->style
& LVS_TYPEMASK
;
5730 /* initialize info pointer */
5731 ZeroMemory(infoPtr
, sizeof(LISTVIEW_INFO
));
5733 /* determine the type of structures to use */
5734 infoPtr
->notifyFormat
= SendMessageA(GetParent(hwnd
), WM_NOTIFYFORMAT
,
5735 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
5736 if (infoPtr
->notifyFormat
!= NFR_ANSI
)
5738 FIXME("ANSI notify format is NOT used\n");
5741 /* initialize color information */
5742 infoPtr
->clrBk
= GetSysColor(COLOR_WINDOW
);
5743 infoPtr
->clrText
= GetSysColor(COLOR_WINDOWTEXT
);
5744 infoPtr
->clrTextBk
= GetSysColor(COLOR_WINDOW
);
5746 /* set default values */
5747 infoPtr
->uCallbackMask
= 0;
5748 infoPtr
->nFocusedItem
= -1;
5749 infoPtr
->nSelectionMark
= -1;
5750 infoPtr
->nHotItem
= -1;
5751 infoPtr
->iconSpacing
.cx
= GetSystemMetrics(SM_CXICONSPACING
);
5752 infoPtr
->iconSpacing
.cy
= GetSystemMetrics(SM_CYICONSPACING
);
5753 ZeroMemory(&infoPtr
->rcList
, sizeof(RECT
));
5754 infoPtr
->hwndEdit
= 0;
5755 infoPtr
->pedititem
= NULL
;
5757 /* get default font (icon title) */
5758 SystemParametersInfoA(SPI_GETICONTITLELOGFONT
, 0, &logFont
, 0);
5759 infoPtr
->hDefaultFont
= CreateFontIndirectA(&logFont
);
5760 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
5763 infoPtr
->hwndHeader
= CreateWindowA(WC_HEADERA
, (LPCSTR
)NULL
,
5764 WS_CHILD
| HDS_HORZ
| HDS_BUTTONS
,
5765 0, 0, 0, 0, hwnd
, (HMENU
)0,
5766 lpcs
->hInstance
, NULL
);
5768 /* set header font */
5769 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)infoPtr
->hFont
,
5772 if (uView
== LVS_ICON
)
5774 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
5775 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
5777 else if (uView
== LVS_REPORT
)
5779 if (!(LVS_NOCOLUMNHEADER
& lpcs
->style
))
5781 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
5784 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
5785 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
5789 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
5790 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
5793 /* display unsupported listview window styles */
5794 LISTVIEW_UnsupportedStyles(lpcs
->style
);
5796 /* allocate memory for the data structure */
5797 infoPtr
->hdpaItems
= DPA_Create(10);
5799 /* initialize size of items */
5800 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
5801 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
5808 * Erases the background of the listview control.
5811 * [I] HWND : window handle
5812 * [I] WPARAM : device context handle
5813 * [I] LPARAM : not used
5819 static LRESULT
LISTVIEW_EraseBackground(HWND hwnd
, WPARAM wParam
,
5822 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5825 if (infoPtr
->clrBk
== CLR_NONE
)
5827 bResult
= SendMessageA(GetParent(hwnd
), WM_ERASEBKGND
, wParam
, lParam
);
5832 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
5833 GetClientRect(hwnd
, &rc
);
5834 FillRect((HDC
)wParam
, &rc
, hBrush
);
5835 DeleteObject(hBrush
);
5844 * Retrieves the listview control font.
5847 * [I] HWND : window handle
5852 static LRESULT
LISTVIEW_GetFont(HWND hwnd
)
5854 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5856 return infoPtr
->hFont
;
5861 * Performs vertical scrolling.
5864 * [I] HWND : window handle
5865 * [I] INT : scroll code
5866 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5868 * [I] HWND : scrollbar control window handle
5873 static LRESULT
LISTVIEW_VScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
5876 SCROLLINFO scrollInfo
;
5878 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
5879 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
5880 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
5882 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
5884 INT nOldScrollPos
= scrollInfo
.nPos
;
5885 switch (nScrollCode
)
5888 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5895 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
5902 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5905 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
5907 scrollInfo
.nPos
-= scrollInfo
.nPage
;
5911 scrollInfo
.nPos
= scrollInfo
.nMin
;
5917 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
5919 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
5921 scrollInfo
.nPos
+= scrollInfo
.nPage
;
5925 scrollInfo
.nPos
= scrollInfo
.nMax
;
5931 scrollInfo
.nPos
= nCurrentPos
;
5935 if (nOldScrollPos
!= scrollInfo
.nPos
)
5937 scrollInfo
.fMask
= SIF_POS
;
5938 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
5939 InvalidateRect(hwnd
, NULL
, TRUE
);
5948 * Performs horizontal scrolling.
5951 * [I] HWND : window handle
5952 * [I] INT : scroll code
5953 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
5955 * [I] HWND : scrollbar control window handle
5960 static LRESULT
LISTVIEW_HScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
5963 SCROLLINFO scrollInfo
;
5965 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
5966 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
5967 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
5969 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
5971 INT nOldScrollPos
= scrollInfo
.nPos
;
5973 switch (nScrollCode
)
5976 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5983 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
5990 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
5992 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
5994 scrollInfo
.nPos
-= scrollInfo
.nPage
;
5998 scrollInfo
.nPos
= scrollInfo
.nMin
;
6004 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
6006 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
6008 scrollInfo
.nPos
+= scrollInfo
.nPage
;
6012 scrollInfo
.nPos
= scrollInfo
.nMax
;
6018 scrollInfo
.nPos
= nCurrentPos
;
6022 if (nOldScrollPos
!= scrollInfo
.nPos
)
6024 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
6025 scrollInfo
.fMask
= SIF_POS
;
6026 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
6027 if(uView
== LVS_REPORT
)
6029 scrollInfo
.fMask
= SIF_POS
;
6030 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
6031 LISTVIEW_UpdateHeaderSize(hwnd
, scrollInfo
.nPos
);
6033 InvalidateRect(hwnd
, NULL
, TRUE
);
6045 * [I] HWND : window handle
6046 * [I] INT : virtual key
6047 * [I] LONG : key data
6052 static LRESULT
LISTVIEW_KeyDown(HWND hwnd
, INT nVirtualKey
, LONG lKeyData
)
6054 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6055 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6056 HWND hwndParent
= GetParent(hwnd
);
6057 NMLVKEYDOWN nmKeyDown
;
6060 BOOL bRedraw
= FALSE
;
6062 /* send LVN_KEYDOWN notification */
6063 ZeroMemory(&nmKeyDown
, sizeof(NMLVKEYDOWN
));
6064 nmKeyDown
.hdr
.hwndFrom
= hwnd
;
6065 nmKeyDown
.hdr
.idFrom
= nCtrlId
;
6066 nmKeyDown
.hdr
.code
= LVN_KEYDOWN
;
6067 nmKeyDown
.wVKey
= nVirtualKey
;
6068 nmKeyDown
.flags
= 0;
6069 SendMessageA(hwndParent
, WM_NOTIFY
, (WPARAM
)nCtrlId
, (LPARAM
)&nmKeyDown
);
6072 nmh
.hwndFrom
= hwnd
;
6073 nmh
.idFrom
= nCtrlId
;
6075 switch (nVirtualKey
)
6078 if ((GETITEMCOUNT(infoPtr
) > 0) && (infoPtr
->nFocusedItem
!= -1))
6080 /* send NM_RETURN notification */
6081 nmh
.code
= NM_RETURN
;
6082 ListView_Notify(hwndParent
, nCtrlId
, &nmh
);
6084 /* send LVN_ITEMACTIVATE notification */
6085 nmh
.code
= LVN_ITEMACTIVATE
;
6086 ListView_Notify(hwndParent
, nCtrlId
, &nmh
);
6091 if (GETITEMCOUNT(infoPtr
) > 0)
6098 if (GETITEMCOUNT(infoPtr
) > 0)
6100 nItem
= GETITEMCOUNT(infoPtr
) - 1;
6105 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TOLEFT
);
6109 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_ABOVE
);
6113 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TORIGHT
);
6117 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_BELOW
);
6129 if ((nItem
!= -1) && (nItem
!= infoPtr
->nFocusedItem
))
6131 bRedraw
= LISTVIEW_KeySelection(hwnd
, nItem
);
6132 if (bRedraw
!= FALSE
)
6134 /* refresh client area */
6135 InvalidateRect(hwnd
, NULL
, TRUE
);
6148 * [I] HWND : window handle
6153 static LRESULT
LISTVIEW_KillFocus(HWND hwnd
)
6155 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6156 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6159 TRACE("(hwnd=%x)\n", hwnd
);
6161 /* send NM_KILLFOCUS notification */
6162 nmh
.hwndFrom
= hwnd
;
6163 nmh
.idFrom
= nCtrlId
;
6164 nmh
.code
= NM_KILLFOCUS
;
6165 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6167 /* set window focus flag */
6168 infoPtr
->bFocus
= FALSE
;
6170 /* NEED drawing optimization ; redraw the selected items */
6171 InvalidateRect(hwnd
, NULL
, FALSE
);
6178 * Processes double click messages (left mouse button).
6181 * [I] HWND : window handle
6182 * [I] WORD : key flag
6183 * [I] WORD : x coordinate
6184 * [I] WORD : y coordinate
6189 static LRESULT
LISTVIEW_LButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
6192 LONG nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6195 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
6197 /* send NM_DBLCLK notification */
6198 nmh
.hwndFrom
= hwnd
;
6199 nmh
.idFrom
= nCtrlId
;
6200 nmh
.code
= NM_DBLCLK
;
6201 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6203 /* send LVN_ITEMACTIVATE notification */
6204 nmh
.code
= LVN_ITEMACTIVATE
;
6205 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6212 * Processes mouse down messages (left mouse button).
6215 * [I] HWND : window handle
6216 * [I] WORD : key flag
6217 * [I] WORD : x coordinate
6218 * [I] WORD : y coordinate
6223 static LRESULT
LISTVIEW_LButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
6226 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6227 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
6228 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6229 static BOOL bGroupSelect
= TRUE
;
6234 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd
, wKey
, wPosX
,
6237 /* send NM_RELEASEDCAPTURE notification */
6238 nmh
.hwndFrom
= hwnd
;
6239 nmh
.idFrom
= nCtrlId
;
6240 nmh
.code
= NM_RELEASEDCAPTURE
;
6241 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6243 if (infoPtr
->bFocus
== FALSE
)
6248 /* set left button down flag */
6249 infoPtr
->bLButtonDown
= TRUE
;
6251 ptPosition
.x
= wPosX
;
6252 ptPosition
.y
= wPosY
;
6253 nItem
= LISTVIEW_MouseSelection(hwnd
, ptPosition
);
6254 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
6256 if (lStyle
& LVS_SINGLESEL
)
6258 LISTVIEW_SetSelection(hwnd
, nItem
);
6262 if ((wKey
& MK_CONTROL
) && (wKey
& MK_SHIFT
))
6264 if (bGroupSelect
!= FALSE
)
6266 LISTVIEW_AddGroupSelection(hwnd
, nItem
);
6270 LISTVIEW_AddSelection(hwnd
, nItem
);
6273 else if (wKey
& MK_CONTROL
)
6275 bGroupSelect
= LISTVIEW_ToggleSelection(hwnd
, nItem
);
6277 else if (wKey
& MK_SHIFT
)
6279 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
6283 LISTVIEW_SetSelection(hwnd
, nItem
);
6289 /* remove all selections */
6290 LISTVIEW_RemoveSelections(hwnd
, 0, GETITEMCOUNT(infoPtr
));
6293 InvalidateRect(hwnd
, NULL
, TRUE
);
6300 * Processes mouse up messages (left mouse button).
6303 * [I] HWND : window handle
6304 * [I] WORD : key flag
6305 * [I] WORD : x coordinate
6306 * [I] WORD : y coordinate
6311 static LRESULT
LISTVIEW_LButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
6314 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6316 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
6318 if (infoPtr
->bLButtonDown
!= FALSE
)
6320 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6323 /* send NM_CLICK notification */
6324 nmh
.hwndFrom
= hwnd
;
6325 nmh
.idFrom
= nCtrlId
;
6326 nmh
.code
= NM_CLICK
;
6327 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6329 /* set left button flag */
6330 infoPtr
->bLButtonDown
= FALSE
;
6338 * Creates the listview control (called before WM_CREATE).
6341 * [I] HWND : window handle
6342 * [I] WPARAM : unhandled
6343 * [I] LPARAM : widow creation info
6348 static LRESULT
LISTVIEW_NCCreate(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
6350 LISTVIEW_INFO
*infoPtr
;
6352 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd
, wParam
, lParam
);
6354 /* allocate memory for info structure */
6355 infoPtr
= (LISTVIEW_INFO
*)COMCTL32_Alloc(sizeof(LISTVIEW_INFO
));
6356 SetWindowLongA(hwnd
, 0, (LONG
)infoPtr
);
6357 if (infoPtr
== NULL
)
6359 ERR("could not allocate info memory!\n");
6363 if ((LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0) != infoPtr
)
6365 ERR("pointer assignment error!\n");
6369 return DefWindowProcA(hwnd
, WM_NCCREATE
, wParam
, lParam
);
6374 * Destroys the listview control (called after WM_DESTROY).
6377 * [I] HWND : window handle
6382 static LRESULT
LISTVIEW_NCDestroy(HWND hwnd
)
6384 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6386 TRACE("(hwnd=%x)\n", hwnd
);
6388 /* delete all items */
6389 LISTVIEW_DeleteAllItems(hwnd
);
6391 /* destroy data structure */
6392 DPA_Destroy(infoPtr
->hdpaItems
);
6395 infoPtr
->hFont
= (HFONT
)0;
6396 if (infoPtr
->hDefaultFont
)
6398 DeleteObject(infoPtr
->hDefaultFont
);
6401 /* free listview info pointer*/
6402 COMCTL32_Free(infoPtr
);
6409 * Handles notifications from children.
6412 * [I] HWND : window handle
6413 * [I] INT : control identifier
6414 * [I] LPNMHDR : notification information
6419 static LRESULT
LISTVIEW_Notify(HWND hwnd
, INT nCtrlId
, LPNMHDR lpnmh
)
6421 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6423 if (lpnmh
->hwndFrom
== infoPtr
->hwndHeader
)
6425 /* handle notification from header control */
6426 if (lpnmh
->code
== HDN_ENDTRACKA
)
6428 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6429 InvalidateRect(hwnd
, NULL
, TRUE
);
6431 else if(lpnmh
->code
== HDN_ITEMCLICKA
)
6433 /* Handle sorting by Header Column */
6435 LPNMHEADERA pnmHeader
= (LPNMHEADERA
) lpnmh
;
6436 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6438 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
6439 nmlv
.hdr
.hwndFrom
= hwnd
;
6440 nmlv
.hdr
.idFrom
= lCtrlId
;
6441 nmlv
.hdr
.code
= LVN_COLUMNCLICK
;
6443 nmlv
.iSubItem
= pnmHeader
->iItem
;
6445 ListView_LVNotify(GetParent(hwnd
),lCtrlId
, &nmlv
);
6448 else if(lpnmh
->code
== NM_RELEASEDCAPTURE
)
6450 /* Idealy this should be done in HDN_ENDTRACKA
6451 * but since SetItemBounds in Header.c is called after
6452 * the notification is sent, it is neccessary to handle the
6453 * update of the scroll bar here (Header.c works fine as it is,
6454 * no need to disturb it)
6456 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6457 LISTVIEW_UpdateScroll(hwnd
);
6458 InvalidateRect(hwnd
, NULL
, TRUE
);
6468 * Determines the type of structure to use.
6471 * [I] HWND : window handle of the sender
6472 * [I] HWND : listview window handle
6473 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
6478 static LRESULT
LISTVIEW_NotifyFormat(HWND hwndFrom
, HWND hwnd
, INT nCommand
)
6480 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6482 if (nCommand
== NF_REQUERY
)
6484 /* determine the type of structure to use */
6485 infoPtr
->notifyFormat
= SendMessageA(hwndFrom
, WM_NOTIFYFORMAT
,
6486 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
6487 if (infoPtr
->notifyFormat
== NFR_UNICODE
)
6489 FIXME("NO support for unicode structures");
6498 * Paints/Repaints the listview control.
6501 * [I] HWND : window handle
6502 * [I] HDC : device context handle
6507 static LRESULT
LISTVIEW_Paint(HWND hwnd
, HDC hdc
)
6511 TRACE("(hwnd=%x,hdc=%x)\n", hwnd
, hdc
);
6515 hdc
= BeginPaint(hwnd
, &ps
);
6516 LISTVIEW_Refresh(hwnd
, hdc
);
6517 EndPaint(hwnd
, &ps
);
6521 LISTVIEW_Refresh(hwnd
, hdc
);
6529 * Processes double click messages (right mouse button).
6532 * [I] HWND : window handle
6533 * [I] WORD : key flag
6534 * [I] WORD : x coordinate
6535 * [I] WORD : y coordinate
6540 static LRESULT
LISTVIEW_RButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
6543 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6546 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
6548 /* send NM_RELEASEDCAPTURE notification */
6549 nmh
.hwndFrom
= hwnd
;
6550 nmh
.idFrom
= nCtrlId
;
6551 nmh
.code
= NM_RELEASEDCAPTURE
;
6552 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6554 /* send NM_RDBLCLK notification */
6555 nmh
.code
= NM_RDBLCLK
;
6556 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6563 * Processes mouse down messages (right mouse button).
6566 * [I] HWND : window handle
6567 * [I] WORD : key flag
6568 * [I] WORD : x coordinate
6569 * [I] WORD : y coordinate
6574 static LRESULT
LISTVIEW_RButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
6577 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6578 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6583 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
6585 /* send NM_RELEASEDCAPTURE notification */
6586 nmh
.hwndFrom
= hwnd
;
6587 nmh
.idFrom
= nCtrlId
;
6588 nmh
.code
= NM_RELEASEDCAPTURE
;
6589 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6591 /* make sure the listview control window has the focus */
6592 if (infoPtr
->bFocus
== FALSE
)
6597 /* set right button down flag */
6598 infoPtr
->bRButtonDown
= TRUE
;
6600 /* determine the index of the selected item */
6601 ptPosition
.x
= wPosX
;
6602 ptPosition
.y
= wPosY
;
6603 nItem
= LISTVIEW_MouseSelection(hwnd
, ptPosition
);
6604 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
6606 if (!((wKey
& MK_SHIFT
) || (wKey
& MK_CONTROL
)))
6608 LISTVIEW_SetSelection(hwnd
, nItem
);
6613 LISTVIEW_RemoveSelections(hwnd
, 0, GETITEMCOUNT(infoPtr
));
6621 * Processes mouse up messages (right mouse button).
6624 * [I] HWND : window handle
6625 * [I] WORD : key flag
6626 * [I] WORD : x coordinate
6627 * [I] WORD : y coordinate
6632 static LRESULT
LISTVIEW_RButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
6635 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6636 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6639 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
6641 if (infoPtr
->bRButtonDown
!= FALSE
)
6643 /* send NM_RClICK notification */
6644 ZeroMemory(&nmh
, sizeof(NMHDR
));
6645 nmh
.hwndFrom
= hwnd
;
6646 nmh
.idFrom
= nCtrlId
;
6647 nmh
.code
= NM_RCLICK
;
6648 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6650 /* set button flag */
6651 infoPtr
->bRButtonDown
= FALSE
;
6662 * [I] HWND : window handle
6663 * [I] HWND : window handle of previously focused window
6668 static LRESULT
LISTVIEW_SetFocus(HWND hwnd
, HWND hwndLoseFocus
)
6670 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6671 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6674 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd
, hwndLoseFocus
);
6676 /* send NM_SETFOCUS notification */
6677 nmh
.hwndFrom
= hwnd
;
6678 nmh
.idFrom
= nCtrlId
;
6679 nmh
.code
= NM_SETFOCUS
;
6680 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
6682 /* set window focus flag */
6683 infoPtr
->bFocus
= TRUE
;
6685 InvalidateRect(hwnd
, NULL
, TRUE
);
6696 * [I] HWND : window handle
6697 * [I] HFONT : font handle
6698 * [I] WORD : redraw flag
6703 static LRESULT
LISTVIEW_SetFont(HWND hwnd
, HFONT hFont
, WORD fRedraw
)
6705 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6706 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
6708 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd
, hFont
, fRedraw
);
6712 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
6716 infoPtr
->hFont
= hFont
;
6719 if (uView
== LVS_REPORT
)
6721 /* set header font */
6722 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)hFont
,
6723 MAKELPARAM(fRedraw
, 0));
6726 /* invalidate listview control client area */
6727 InvalidateRect(hwnd
, NULL
, TRUE
);
6729 if (fRedraw
!= FALSE
)
6739 * Resizes the listview control. This function processes WM_SIZE
6740 * messages. At this time, the width and height are not used.
6743 * [I] HWND : window handle
6744 * [I] WORD : new width
6745 * [I] WORD : new height
6750 static LRESULT
LISTVIEW_Size(HWND hwnd
, int Width
, int Height
)
6752 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
6753 UINT uView
= lStyle
& LVS_TYPEMASK
;
6755 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd
, Width
, Height
);
6757 LISTVIEW_UpdateSize(hwnd
);
6759 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6761 if (lStyle
& LVS_ALIGNLEFT
)
6763 LISTVIEW_AlignLeft(hwnd
);
6767 LISTVIEW_AlignTop(hwnd
);
6771 LISTVIEW_UpdateScroll(hwnd
);
6773 /* invalidate client area + erase background */
6774 InvalidateRect(hwnd
, NULL
, TRUE
);
6781 * Sets the size information.
6784 * [I] HWND : window handle
6789 static VOID
LISTVIEW_UpdateSize(HWND hwnd
)
6791 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6792 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
6793 UINT uView
= lStyle
& LVS_TYPEMASK
;
6796 GetClientRect(hwnd
, &rcList
);
6797 infoPtr
->rcList
.left
= 0;
6798 infoPtr
->rcList
.right
= max(rcList
.right
- rcList
.left
, 1);
6799 infoPtr
->rcList
.top
= 0;
6800 infoPtr
->rcList
.bottom
= max(rcList
.bottom
- rcList
.top
, 1);
6802 if (uView
== LVS_LIST
)
6804 if ((lStyle
& WS_HSCROLL
) == 0)
6806 INT nHScrollHeight
= GetSystemMetrics(SM_CYHSCROLL
);
6807 if (infoPtr
->rcList
.bottom
> nHScrollHeight
)
6809 infoPtr
->rcList
.bottom
-= nHScrollHeight
;
6813 else if (uView
== LVS_REPORT
)
6820 Header_Layout(infoPtr
->hwndHeader
, &hl
);
6821 if (!(LVS_NOCOLUMNHEADER
& lStyle
))
6823 infoPtr
->rcList
.top
= max(wp
.cy
, 0);
6830 * Processes WM_STYLECHANGED messages.
6833 * [I] HWND : window handle
6834 * [I] WPARAM : window style type (normal or extended)
6835 * [I] LPSTYLESTRUCT : window style information
6840 static INT
LISTVIEW_StyleChanged(HWND hwnd
, WPARAM wStyleType
,
6843 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6844 UINT uNewView
= lpss
->styleNew
& LVS_TYPEMASK
;
6845 UINT uOldView
= lpss
->styleOld
& LVS_TYPEMASK
;
6846 RECT rcList
= infoPtr
->rcList
;
6848 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
6849 hwnd
, wStyleType
, lpss
);
6851 if (wStyleType
== GWL_STYLE
)
6853 if (uOldView
== LVS_REPORT
)
6855 ShowWindow(infoPtr
->hwndHeader
, SW_HIDE
);
6858 if ((lpss
->styleOld
& WS_HSCROLL
) != 0)
6860 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
6863 if ((lpss
->styleOld
& WS_VSCROLL
) != 0)
6865 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
6868 if (uNewView
== LVS_ICON
)
6870 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
6871 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
6872 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6873 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
6874 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
6876 LISTVIEW_AlignLeft(hwnd
);
6880 LISTVIEW_AlignTop(hwnd
);
6883 else if (uNewView
== LVS_REPORT
)
6890 Header_Layout(infoPtr
->hwndHeader
, &hl
);
6891 SetWindowPos(infoPtr
->hwndHeader
, hwnd
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
,
6893 if (!(LVS_NOCOLUMNHEADER
& lpss
->styleNew
))
6895 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
6897 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
6898 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
6899 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6900 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
6902 else if (uNewView
== LVS_LIST
)
6904 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
6905 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
6906 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6907 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
6911 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
6912 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
6913 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6914 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
6915 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
6917 LISTVIEW_AlignLeft(hwnd
);
6921 LISTVIEW_AlignTop(hwnd
);
6925 /* update the size of the client area */
6926 LISTVIEW_UpdateSize(hwnd
);
6928 /* add scrollbars if needed */
6929 LISTVIEW_UpdateScroll(hwnd
);
6931 /* invalidate client area + erase background */
6932 InvalidateRect(hwnd
, NULL
, TRUE
);
6934 /* print the list of unsupported window styles */
6935 LISTVIEW_UnsupportedStyles(lpss
->styleNew
);
6943 * Window procedure of the listview control.
6946 static LRESULT WINAPI
LISTVIEW_WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
,
6951 case LVM_APPROXIMATEVIEWRECT
:
6952 return LISTVIEW_ApproximateViewRect(hwnd
, (INT
)wParam
,
6953 LOWORD(lParam
), HIWORD(lParam
));
6955 return LISTVIEW_Arrange(hwnd
, (INT
)wParam
);
6957 /* case LVM_CREATEDRAGIMAGE: */
6959 case LVM_DELETEALLITEMS
:
6960 return LISTVIEW_DeleteAllItems(hwnd
);
6962 case LVM_DELETECOLUMN
:
6963 return LISTVIEW_DeleteColumn(hwnd
, (INT
)wParam
);
6965 case LVM_DELETEITEM
:
6966 return LISTVIEW_DeleteItem(hwnd
, (INT
)wParam
);
6968 case LVM_EDITLABELW
:
6969 case LVM_EDITLABELA
:
6970 return LISTVIEW_EditLabelA(hwnd
, (INT
)wParam
);
6972 case LVM_ENSUREVISIBLE
:
6973 return LISTVIEW_EnsureVisible(hwnd
, (INT
)wParam
, (BOOL
)lParam
);
6976 return LISTVIEW_FindItem(hwnd
, (INT
)wParam
, (LPLVFINDINFO
)lParam
);
6978 case LVM_GETBKCOLOR
:
6979 return LISTVIEW_GetBkColor(hwnd
);
6981 /* case LVM_GETBKIMAGE: */
6983 case LVM_GETCALLBACKMASK
:
6984 return LISTVIEW_GetCallbackMask(hwnd
);
6986 case LVM_GETCOLUMNA
:
6987 return LISTVIEW_GetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
6989 /* case LVM_GETCOLUMNW: */
6991 case LVM_GETCOLUMNORDERARRAY
:
6992 FIXME("Unimplemented msg LVM_GETCOLUMNORDERARRAY\n");
6995 case LVM_GETCOLUMNWIDTH
:
6996 return LISTVIEW_GetColumnWidth(hwnd
, (INT
)wParam
);
6998 case LVM_GETCOUNTPERPAGE
:
6999 return LISTVIEW_GetCountPerPage(hwnd
);
7001 case LVM_GETEDITCONTROL
:
7002 return LISTVIEW_GetEditControl(hwnd
);
7004 case LVM_GETEXTENDEDLISTVIEWSTYLE
:
7005 return LISTVIEW_GetExtendedListViewStyle(hwnd
);
7008 return LISTVIEW_GetHeader(hwnd
);
7010 /* case LVM_GETHOTCURSOR: */
7012 case LVM_GETHOTITEM
:
7013 return LISTVIEW_GetHotItem(hwnd
);
7015 /* case LVM_GETHOVERTIME: */
7017 case LVM_GETIMAGELIST
:
7018 return LISTVIEW_GetImageList(hwnd
, (INT
)wParam
);
7020 /* case LVM_GETISEARCHSTRING: */
7023 return LISTVIEW_GetItemA(hwnd
, (LPLVITEMA
)lParam
);
7025 /* case LVM_GETITEMW: */
7027 case LVM_GETITEMCOUNT
:
7028 return LISTVIEW_GetItemCount(hwnd
);
7030 case LVM_GETITEMPOSITION
:
7031 return LISTVIEW_GetItemPosition(hwnd
, (INT
)wParam
, (LPPOINT
)lParam
);
7033 case LVM_GETITEMRECT
:
7034 return LISTVIEW_GetItemRect(hwnd
, (INT
)wParam
, (LPRECT
)lParam
);
7036 case LVM_GETITEMSPACING
:
7037 return LISTVIEW_GetItemSpacing(hwnd
, (BOOL
)wParam
);
7039 case LVM_GETITEMSTATE
:
7040 return LISTVIEW_GetItemState(hwnd
, (INT
)wParam
, (UINT
)lParam
);
7042 case LVM_GETITEMTEXTA
:
7043 LISTVIEW_GetItemTextA(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
7046 /* case LVM_GETITEMTEXTW: */
7048 case LVM_GETNEXTITEM
:
7049 return LISTVIEW_GetNextItem(hwnd
, (INT
)wParam
, LOWORD(lParam
));
7051 /* case LVM_GETNUMBEROFWORKAREAS: */
7054 return LISTVIEW_GetOrigin(hwnd
, (LPPOINT
)lParam
);
7056 case LVM_GETSELECTEDCOUNT
:
7057 return LISTVIEW_GetSelectedCount(hwnd
);
7059 case LVM_GETSELECTIONMARK
:
7060 return LISTVIEW_GetSelectionMark(hwnd
);
7062 case LVM_GETSTRINGWIDTHA
:
7063 return LISTVIEW_GetStringWidthA (hwnd
, (LPCSTR
)lParam
);
7065 /* case LVM_GETSTRINGWIDTHW: */
7066 /* case LVM_GETSUBITEMRECT: */
7068 case LVM_GETTEXTBKCOLOR
:
7069 return LISTVIEW_GetTextBkColor(hwnd
);
7071 case LVM_GETTEXTCOLOR
:
7072 return LISTVIEW_GetTextColor(hwnd
);
7074 /* case LVM_GETTOOLTIPS: */
7076 case LVM_GETTOPINDEX
:
7077 return LISTVIEW_GetTopIndex(hwnd
);
7079 /* case LVM_GETUNICODEFORMAT: */
7081 case LVM_GETVIEWRECT
:
7082 return LISTVIEW_GetViewRect(hwnd
, (LPRECT
)lParam
);
7084 /* case LVM_GETWORKAREAS: */
7087 return LISTVIEW_HitTest(hwnd
, (LPLVHITTESTINFO
)lParam
);
7089 case LVM_INSERTCOLUMNA
:
7090 return LISTVIEW_InsertColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
7092 case LVM_INSERTCOLUMNW
:
7093 return LISTVIEW_InsertColumnW(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
);
7095 case LVM_INSERTITEMA
:
7096 return LISTVIEW_InsertItemA(hwnd
, (LPLVITEMA
)lParam
);
7098 case LVM_INSERTITEMW
:
7099 return LISTVIEW_InsertItemW(hwnd
, (LPLVITEMW
)lParam
);
7101 case LVM_REDRAWITEMS
:
7102 return LISTVIEW_RedrawItems(hwnd
, (INT
)wParam
, (INT
)lParam
);
7104 /* case LVM_SCROLL: */
7105 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7107 case LVM_SETBKCOLOR
:
7108 return LISTVIEW_SetBkColor(hwnd
, (COLORREF
)lParam
);
7110 /* case LVM_SETBKIMAGE: */
7112 case LVM_SETCALLBACKMASK
:
7113 return LISTVIEW_SetCallbackMask(hwnd
, (UINT
)wParam
);
7115 case LVM_SETCOLUMNA
:
7116 return LISTVIEW_SetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
7118 case LVM_SETCOLUMNW
:
7119 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7122 case LVM_SETCOLUMNORDERARRAY
:
7123 FIXME("Unimplemented msg LVM_SETCOLUMNORDERARRAY\n");
7126 case LVM_SETCOLUMNWIDTH
:
7127 return LISTVIEW_SetColumnWidth(hwnd
, (INT
)wParam
, (INT
)lParam
);
7129 case LVM_SETEXTENDEDLISTVIEWSTYLE
:
7130 return LISTVIEW_SetExtendedListViewStyle(hwnd
, (DWORD
)wParam
, (DWORD
)lParam
);
7132 /* case LVM_SETHOTCURSOR: */
7134 case LVM_SETHOTITEM
:
7135 return LISTVIEW_SetHotItem(hwnd
, (INT
)wParam
);
7137 /* case LVM_SETHOVERTIME: */
7138 /* case LVM_SETICONSPACING: */
7140 case LVM_SETIMAGELIST
:
7141 return LISTVIEW_SetImageList(hwnd
, (INT
)wParam
, (HIMAGELIST
)lParam
);
7144 return LISTVIEW_SetItemA(hwnd
, (LPLVITEMA
)lParam
);
7146 /* case LVM_SETITEMW: */
7148 case LVM_SETITEMCOUNT
:
7149 return LISTVIEW_SetItemCount(hwnd
, (INT
)wParam
, (DWORD
)lParam
);
7151 case LVM_SETITEMPOSITION
:
7152 return LISTVIEW_SetItemPosition(hwnd
, (INT
)wParam
, (INT
)LOWORD(lParam
),
7153 (INT
)HIWORD(lParam
));
7155 /* case LVM_SETITEMPOSITION32: */
7157 case LVM_SETITEMSTATE
:
7158 return LISTVIEW_SetItemState(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
7160 case LVM_SETITEMTEXTA
:
7161 return LISTVIEW_SetItemTextA(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
7163 /* case LVM_SETITEMTEXTW: */
7165 case LVM_SETSELECTIONMARK
:
7166 return LISTVIEW_SetSelectionMark(hwnd
, (INT
)lParam
);
7168 case LVM_SETTEXTBKCOLOR
:
7169 return LISTVIEW_SetTextBkColor(hwnd
, (COLORREF
)lParam
);
7171 case LVM_SETTEXTCOLOR
:
7172 return LISTVIEW_SetTextColor(hwnd
, (COLORREF
)lParam
);
7174 /* case LVM_SETTOOLTIPS: */
7175 /* case LVM_SETUNICODEFORMAT: */
7176 /* case LVM_SETWORKAREAS: */
7179 return LISTVIEW_SortItems(hwnd
, wParam
, lParam
);
7181 /* case LVM_SUBITEMHITTEST: */
7184 return LISTVIEW_Update(hwnd
, (INT
)wParam
);
7188 return LISTVIEW_Command(hwnd
, wParam
, lParam
);
7191 return LISTVIEW_Create(hwnd
, wParam
, lParam
);
7194 return LISTVIEW_EraseBackground(hwnd
, wParam
, lParam
);
7197 return DLGC_WANTCHARS
| DLGC_WANTARROWS
;
7200 return LISTVIEW_GetFont(hwnd
);
7203 return LISTVIEW_HScroll(hwnd
, (INT
)LOWORD(wParam
),
7204 (INT
)HIWORD(wParam
), (HWND
)lParam
);
7207 return LISTVIEW_KeyDown(hwnd
, (INT
)wParam
, (LONG
)lParam
);
7210 return LISTVIEW_KillFocus(hwnd
);
7212 case WM_LBUTTONDBLCLK
:
7213 return LISTVIEW_LButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
7216 case WM_LBUTTONDOWN
:
7217 return LISTVIEW_LButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
7220 return LISTVIEW_LButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
7223 /* case WM_MOUSEMOVE: */
7224 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
7227 return LISTVIEW_NCCreate(hwnd
, wParam
, lParam
);
7230 return LISTVIEW_NCDestroy(hwnd
);
7233 return LISTVIEW_Notify(hwnd
, (INT
)wParam
, (LPNMHDR
)lParam
);
7235 case WM_NOTIFYFORMAT
:
7236 return LISTVIEW_NotifyFormat(hwnd
, (HWND
)wParam
, (INT
)lParam
);
7239 return LISTVIEW_Paint(hwnd
, (HDC
)wParam
);
7241 case WM_RBUTTONDBLCLK
:
7242 return LISTVIEW_RButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
7245 case WM_RBUTTONDOWN
:
7246 return LISTVIEW_RButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
7250 return LISTVIEW_RButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
7254 return LISTVIEW_SetFocus(hwnd
, (HWND
)wParam
);
7257 return LISTVIEW_SetFont(hwnd
, (HFONT
)wParam
, (WORD
)lParam
);
7259 /* case WM_SETREDRAW: */
7262 return LISTVIEW_Size(hwnd
, (int)SLOWORD(lParam
), (int)SHIWORD(lParam
));
7264 case WM_STYLECHANGED
:
7265 return LISTVIEW_StyleChanged(hwnd
, wParam
, (LPSTYLESTRUCT
)lParam
);
7267 /* case WM_TIMER: */
7270 return LISTVIEW_VScroll(hwnd
, (INT
)LOWORD(wParam
),
7271 (INT
)HIWORD(wParam
), (HWND
)lParam
);
7273 /* case WM_WINDOWPOSCHANGED: */
7274 /* case WM_WININICHANGE: */
7277 if (uMsg
>= WM_USER
)
7279 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
,
7283 /* call default window procedure */
7284 return DefWindowProcA(hwnd
, uMsg
, wParam
, lParam
);
7292 * Registers the window class.
7300 VOID
LISTVIEW_Register(void)
7304 if (!GlobalFindAtomA(WC_LISTVIEWA
))
7306 ZeroMemory(&wndClass
, sizeof(WNDCLASSA
));
7307 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
7308 wndClass
.lpfnWndProc
= (WNDPROC
)LISTVIEW_WindowProc
;
7309 wndClass
.cbClsExtra
= 0;
7310 wndClass
.cbWndExtra
= sizeof(LISTVIEW_INFO
*);
7311 wndClass
.hCursor
= LoadCursorA(0, IDC_ARROWA
);
7312 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
7313 wndClass
.lpszClassName
= WC_LISTVIEWA
;
7314 RegisterClassA(&wndClass
);
7320 * Unregisters the window class.
7328 VOID
LISTVIEW_Unregister(void)
7330 if (GlobalFindAtomA(WC_LISTVIEWA
))
7332 UnregisterClassA(WC_LISTVIEWA
, (HINSTANCE
)NULL
);
7338 * Handle any WM_COMMAND messages
7344 static LRESULT
LISTVIEW_Command(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
7346 switch (HIWORD(wParam
))
7351 * Adjust the edit window size
7354 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7355 HDC hdc
= GetDC(infoPtr
->hwndEdit
);
7359 GetWindowTextA(infoPtr
->hwndEdit
, buffer
, 1024);
7360 GetWindowRect(infoPtr
->hwndEdit
, &rect
);
7361 if (GetTextExtentPoint32A(hdc
, buffer
, strlen(buffer
), &sz
))
7369 rect
.bottom
- rect
.top
,
7370 SWP_DRAWFRAME
|SWP_NOMOVE
);
7372 ReleaseDC(hwnd
, hdc
);
7378 return SendMessageA (GetParent (hwnd
), WM_COMMAND
, wParam
, lParam
);
7387 * Subclassed edit control windproc function
7393 LRESULT CALLBACK
EditLblWndProc(HWND hwnd
, UINT uMsg
,
7394 WPARAM wParam
, LPARAM lParam
)
7397 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(GetParent(hwnd
), 0);
7398 EDITLABEL_ITEM
*einfo
= infoPtr
->pedititem
;
7403 return DLGC_WANTARROWS
| DLGC_WANTALLKEYS
;
7410 WNDPROC editProc
= einfo
->EditWndProc
;
7411 SetWindowLongA(hwnd
, GWL_WNDPROC
, (LONG
)editProc
);
7412 COMCTL32_Free(einfo
);
7413 infoPtr
->pedititem
= NULL
;
7414 return CallWindowProcA(editProc
, hwnd
, uMsg
, wParam
, lParam
);
7418 if (VK_RETURN
== (INT
)wParam
)
7423 else if (VK_ESCAPE
== (INT
)wParam
)
7427 return CallWindowProcA(einfo
->EditWndProc
, hwnd
,
7428 uMsg
, wParam
, lParam
);
7431 if (einfo
->EditLblCb
)
7433 char *buffer
= NULL
;
7437 int len
= 1 + GetWindowTextLengthA(hwnd
);
7441 if (NULL
!= (buffer
= (char *)COMCTL32_Alloc(len
*sizeof(char))))
7443 GetWindowTextA(hwnd
, buffer
, len
);
7448 einfo
->EditLblCb(GetParent(hwnd
), buffer
, einfo
->param
);
7451 COMCTL32_Free(buffer
);
7453 einfo
->EditLblCb
= NULL
;
7456 SendMessageA(hwnd
, WM_CLOSE
, 0, 0);
7463 * Creates a subclassed edit cotrol
7469 HWND
CreateEditLabel(LPCSTR text
, DWORD style
, INT x
, INT y
,
7470 INT width
, INT height
, HWND parent
, HINSTANCE hinst
,
7471 EditlblCallback EditLblCb
, DWORD param
)
7474 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(parent
, 0);
7475 if (NULL
== (infoPtr
->pedititem
= COMCTL32_Alloc(sizeof(EDITLABEL_ITEM
))))
7478 style
|= WS_CHILDWINDOW
|WS_CLIPSIBLINGS
|ES_LEFT
|WS_BORDER
;
7479 if (!(hedit
= CreateWindowA("Edit", text
, style
, x
, y
, width
, height
,
7480 parent
, 0, hinst
, 0)))
7482 COMCTL32_Free(infoPtr
->pedititem
);
7486 infoPtr
->pedititem
->param
= param
;
7487 infoPtr
->pedititem
->EditLblCb
= EditLblCb
;
7488 infoPtr
->pedititem
->EditWndProc
= (WNDPROC
)SetWindowLongA(hedit
,
7489 GWL_WNDPROC
, (LONG
) EditLblWndProc
);