4 * Copyright 1998 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
8 * Listview control implementation.
11 * LISTVIEW_GetMaxItemWidth : large icon view
12 * LISTVIEW_Notify : notification from children
13 * LISTVIEW_KeyDown : key press messages
14 * LISTVIEW_HScroll : small icon and icon
15 * LISTVIEW_VScroll : small icon and icon
16 * LISTVIEW_SortItems : empty stub
17 * LISTVIEW_SetItemPosition : small icon and icon
18 * LISTVIEW_SetItemCount : empty stub
19 * LISTVIEW_SetItem32W : no unicode yet!
20 * LISTVIEW_SetColumn32A : DOUBLE CHECK
21 * LISTVIEW_Scroll : scrolling in pixels
22 * LISTVIEW_RedrawItems : define bounding rect
23 * LISTVIEW_InsertItem32W : no unicode yet!
24 * LISTVIEW_InsertColumn32W : no unicode yet!
25 * LISTVIEW_GetViewRect : small icon and icon
26 * LISTVIEW_GetOrigin : small icon and icon
27 * LISTVIEW_GetNumberOfWorkAreas : small icon and icon
28 * LISTVIEW_GetNextItem : all
29 * LISTVIEW_SetScroll : scrolling in pixels
30 * LISTVIEW_GetItemRect : all
31 * LISTVIEW_GetHotCursor : all
32 * LISTVIEW_GetHotItem : all
33 * LISTVIEW_GetHoverTime : all
34 * LISTVIEW_GetISearchString : all
35 * LISTVIEW_GetBkImage : all
36 * LISTVIEW_FindItem : all
37 * LISTVIEW_EnsureVisible : some
38 * LISTVIEW_EditLabel : REPORT (need to implement a timer)
39 * LISTVIEW_GetItemPosition : small icon and icon
40 * LISTVIEW_GetItemRect : some
41 * LISTVIEW_Arrange : small icon and icon
42 * LISTVIEW_ApproximateViewRect : report, small icon and icon
43 * LISTVIEW_RefreshIcon : large icon draw function
55 #define DISP_TEXT_SIZE 128
56 #define WIDTH_PADDING 12
57 #define HEIGHT_PADDING 2
58 #define MIN_COLUMN_WIDTH 96
61 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
62 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
63 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
64 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
65 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
67 /* forward declarations */
68 static VOID
LISTVIEW_SetSize(HWND hwnd
, LONG lStyle
, LONG lWidth
,
70 static VOID
LISTVIEW_SetViewInfo(HWND hwnd
);
71 static VOID
LISTVIEW_SetScroll(HWND hwnd
);
72 static VOID
LISTVIEW_AddGroupSelection(HWND hwnd
, INT nItem
);
73 static VOID
LISTVIEW_AddSelection(HWND hwnd
, INT nItem
);
74 static BOOL
LISTVIEW_ToggleSelection(HWND hwnd
, INT nItem
);
75 static VOID
LISTVIEW_SetGroupSelection(HWND hwnd
, INT nItem
);
76 static VOID
LISTVIEW_SetSelection(HWND hwnd
, INT nItem
);
77 static VOID
LISTVIEW_RemoveSelections(HWND hwnd
, INT nFirst
, INT nLast
);
78 static VOID
LISTVIEW_SetItemFocus(HWND hwnd
, INT nItem
);
79 static BOOL
LISTVIEW_RemoveSubItem(HDPA hdpaSubItems
, INT nSubItem
);
80 static BOOL
LISTVIEW_RemoveColumn(HDPA hdpaItems
, INT nColumn
);
81 static BOOL
LISTVIEW_InitItem(HWND hwnd
, LISTVIEW_ITEM
*lpItem
,
83 static BOOL
LISTVIEW_InitSubItem(HWND hwnd
, LISTVIEW_SUBITEM
*lpSubItem
,
85 static BOOL
LISTVIEW_AddSubItem(HWND hwnd
, LPLVITEMA lpLVItem
);
86 static BOOL
LISTVIEW_SetItem(HWND hwnd
, LPLVITEMA lpLVItem
);
87 static BOOL
LISTVIEW_SetSubItem(HWND hwnd
, LPLVITEMA lpLVItem
);
88 static INT
LISTVIEW_FindInsertPosition(HDPA hdpaSubItems
, INT nSubItem
);
89 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA hdpaSubItems
, INT nSubItem
);
94 * Prints a message for unsupported window styles.
97 * [I] LONG : window style
102 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
)
104 if ((LVS_TYPEMASK
& lStyle
) == LVS_ALIGNLEFT
)
106 FIXME(listview
, " LVS_ALIGNLEFT\n");
109 if ((LVS_TYPEMASK
& lStyle
) == LVS_ALIGNTOP
)
111 FIXME(listview
, " LVS_ALIGNTOP\n");
114 if ((LVS_TYPEMASK
& lStyle
) == LVS_AUTOARRANGE
)
116 FIXME(listview
, " LVS_AUTOARRANGE\n");
119 if ((LVS_TYPEMASK
& lStyle
) == LVS_EDITLABELS
)
121 FIXME(listview
, " LVS_EDITLABELS\n");
124 if ((LVS_TYPEMASK
& lStyle
) == LVS_ICON
)
126 FIXME(listview
, " LVS_ICON\n");
129 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOCOLUMNHEADER
)
131 FIXME(listview
, " LVS_SORTDESCENDING\n");
134 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOLABELWRAP
)
136 FIXME(listview
, " LVS_NOLABELWRAP\n");
139 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOSCROLL
)
141 FIXME(listview
, " LVS_NOSCROLL\n");
144 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOSORTHEADER
)
146 FIXME(listview
, " LVS_NOSORTHEADER\n");
149 if ((LVS_TYPEMASK
& lStyle
) == LVS_OWNERDRAWFIXED
)
151 FIXME(listview
, " LVS_OWNERDRAWFIXED\n");
154 if ((LVS_TYPEMASK
& lStyle
) == LVS_SHAREIMAGELISTS
)
156 FIXME(listview
, " LVS_SHAREIMAGELISTS\n");
159 if ((LVS_TYPEMASK
& lStyle
) == LVS_SHOWSELALWAYS
)
161 FIXME(listview
, " LVS_SHOWSELALWAYS\n");
164 if ((LVS_TYPEMASK
& lStyle
) == LVS_SINGLESEL
)
166 FIXME(listview
, " LVS_SINGLESEL\n");
169 if ((LVS_TYPEMASK
& lStyle
) == LVS_SMALLICON
)
171 FIXME(listview
, " LVS_SMALLICON\n");
174 if ((LVS_TYPEMASK
& lStyle
) == LVS_SORTDESCENDING
)
176 FIXME(listview
, " LVS_SORTDESCENDING\n");
179 if ((LVS_TYPEMASK
& lStyle
) == LVS_SORTDESCENDING
)
181 FIXME(listview
, " LVS_SORTDESCENDING\n");
187 * Retrieves display information.
190 * [I] HWND : window handle
191 * [I] LISTVIEW_ITEM* : listview control item
192 * [O] INT : image index
193 * [O] UINT : state value
194 * [O] CHAR** : string
195 * [I] INT : size of string
200 static VOID
LISTVIEW_GetItemDispInfo(HWND hwnd
, INT nItem
,
201 LISTVIEW_ITEM
*lpItem
, INT
*pnDispImage
,
202 UINT
*puState
, CHAR
**ppszDispText
,
205 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
206 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
207 NMLVDISPINFOA dispInfo
;
208 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
210 if ((pnDispImage
!= NULL
) && (lpItem
->iImage
== I_IMAGECALLBACK
))
212 dispInfo
.item
.mask
|= LVIF_IMAGE
;
215 if ((ppszDispText
!= NULL
) && (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
))
217 ZeroMemory(*ppszDispText
, sizeof(CHAR
)*nDispTextSize
);
218 dispInfo
.item
.mask
|= LVIF_TEXT
;
219 dispInfo
.item
.pszText
= *ppszDispText
;
220 dispInfo
.item
.cchTextMax
= nDispTextSize
;
223 if ((puState
!= NULL
) && (infoPtr
->uCallbackMask
!= 0))
225 dispInfo
.item
.mask
|= LVIF_STATE
;
226 dispInfo
.item
.stateMask
= infoPtr
->uCallbackMask
;
229 if (dispInfo
.item
.mask
!= 0)
231 dispInfo
.hdr
.hwndFrom
= hwnd
;
232 dispInfo
.hdr
.idFrom
= lCtrlId
;
233 dispInfo
.hdr
.code
= LVN_GETDISPINFOA
;
234 dispInfo
.item
.iItem
= nItem
;
235 dispInfo
.item
.iSubItem
= 0;
236 dispInfo
.item
.lParam
= lpItem
->lParam
;
237 ListView_Notify(GetParent(hwnd
), lCtrlId
, &dispInfo
);
240 if (pnDispImage
!= NULL
)
242 if (dispInfo
.item
.mask
& LVIF_IMAGE
)
244 *pnDispImage
= dispInfo
.item
.iImage
;
248 *pnDispImage
= lpItem
->iImage
;
252 if (ppszDispText
!= NULL
)
254 if (dispInfo
.item
.mask
& LVIF_TEXT
)
256 if (dispInfo
.item
.mask
& LVIF_DI_SETITEM
)
258 Str_SetPtrA(&lpItem
->pszText
, dispInfo
.item
.pszText
);
260 *ppszDispText
= dispInfo
.item
.pszText
;
264 *ppszDispText
= lpItem
->pszText
;
270 if (dispInfo
.item
.mask
& LVIF_STATE
)
272 *puState
= lpItem
->state
;
273 *puState
&= ~dispInfo
.item
.stateMask
;
274 *puState
|= (dispInfo
.item
.state
& dispInfo
.item
.stateMask
);
278 *puState
= lpItem
->state
;
285 * Retrieves display information.
288 * [I] HWND : window handle
289 * [I] LISTVIEW_SUBITEM* : listview control subitem
290 * [O] INT : image index
291 * [O] UINT : state value
292 * [O] CHAR** : string
293 * [I] INT : size of string
298 static VOID
LISTVIEW_GetSubItemDispInfo(HWND hwnd
, INT nItem
, LPARAM lParam
,
299 LISTVIEW_SUBITEM
*lpSubItem
,
300 INT nColumn
, INT
*pnDispImage
,
301 CHAR
**ppszDispText
, INT nDispTextSize
)
303 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
304 NMLVDISPINFOA dispInfo
;
305 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
307 if (lpSubItem
== NULL
)
309 ZeroMemory(*ppszDispText
, sizeof(CHAR
)*nDispTextSize
);
310 dispInfo
.item
.mask
|= LVIF_TEXT
;
311 dispInfo
.item
.pszText
= *ppszDispText
;
312 dispInfo
.item
.cchTextMax
= nDispTextSize
;
313 dispInfo
.hdr
.hwndFrom
= hwnd
;
314 dispInfo
.hdr
.idFrom
= lCtrlId
;
315 dispInfo
.hdr
.code
= LVN_GETDISPINFOA
;
316 dispInfo
.item
.iItem
= nItem
;
317 dispInfo
.item
.iSubItem
= nColumn
;
318 dispInfo
.item
.lParam
= lParam
;
319 ListView_Notify(GetParent(hwnd
), lCtrlId
, &dispInfo
);
320 if (dispInfo
.item
.mask
& LVIF_DI_SETITEM
)
322 Str_SetPtrA(&lpSubItem
->pszText
, dispInfo
.item
.pszText
);
324 *ppszDispText
= dispInfo
.item
.pszText
;
328 if ((pnDispImage
!= NULL
) && (lpSubItem
->iImage
== I_IMAGECALLBACK
))
330 dispInfo
.item
.mask
|= LVIF_IMAGE
;
333 if ((ppszDispText
!= NULL
) && (lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
))
335 ZeroMemory(*ppszDispText
, sizeof(CHAR
)*nDispTextSize
);
336 dispInfo
.item
.mask
|= LVIF_TEXT
;
337 dispInfo
.item
.pszText
= *ppszDispText
;
338 dispInfo
.item
.cchTextMax
= nDispTextSize
;
341 if (dispInfo
.item
.mask
!= 0)
343 dispInfo
.hdr
.hwndFrom
= hwnd
;
344 dispInfo
.hdr
.idFrom
= lCtrlId
;
345 dispInfo
.hdr
.code
= LVN_GETDISPINFOA
;
346 dispInfo
.item
.iItem
= nItem
;
347 dispInfo
.item
.iSubItem
= lpSubItem
->iSubItem
;
348 dispInfo
.item
.lParam
= lParam
;
349 ListView_Notify(GetParent(hwnd
), lCtrlId
, &dispInfo
);
352 if (pnDispImage
!= NULL
)
354 if (dispInfo
.item
.mask
& LVIF_IMAGE
)
356 *pnDispImage
= dispInfo
.item
.iImage
;
360 *pnDispImage
= lpSubItem
->iImage
;
364 if (ppszDispText
!= NULL
)
366 if (dispInfo
.item
.mask
& LVIF_TEXT
)
368 if (dispInfo
.item
.mask
& LVIF_DI_SETITEM
)
370 Str_SetPtrA(&lpSubItem
->pszText
, dispInfo
.item
.pszText
);
372 *ppszDispText
= dispInfo
.item
.pszText
;
376 *ppszDispText
= lpSubItem
->pszText
;
384 * Calculates a new column width.
387 * [I] HWND : window handle
390 * Returns item width.
392 static INT
LISTVIEW_GetMaxItemWidth(HWND hwnd
)
394 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
395 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
396 LISTVIEW_ITEM
*lpItem
;
399 INT nMaxItemWidth
= 0;
402 if ((LVS_TYPEMASK
& lStyle
) == LVS_ICON
)
408 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
410 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
411 if (hdpaSubItems
!= NULL
)
413 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
416 CHAR szDispText
[DISP_TEXT_SIZE
];
418 pszDispText
= szDispText
;
419 LISTVIEW_GetItemDispInfo(hwnd
, i
, lpItem
, NULL
, NULL
, &pszDispText
,
421 nStringWidth
= ListView_GetStringWidthA(hwnd
, pszDispText
);
422 nMaxItemWidth
= max(nMaxItemWidth
, nStringWidth
);
427 /* add arbitrary padding for separating columns */
428 nMaxItemWidth
+= WIDTH_PADDING
;
430 if (infoPtr
->himlSmall
!= NULL
)
432 nMaxItemWidth
+= infoPtr
->iconSize
.cx
;
435 if (infoPtr
->himlState
!= NULL
)
437 nMaxItemWidth
+= infoPtr
->iconSize
.cx
;
441 nMaxItemWidth
= max(MIN_COLUMN_WIDTH
, nMaxItemWidth
);
443 return nMaxItemWidth
;
448 * Sets diplay information (needed for drawing and calculations).
451 * [I] HWND : window handle
456 static VOID
LISTVIEW_SetViewInfo(HWND hwnd
)
458 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
459 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
466 /* get text height */
468 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
469 GetTextMetricsA(hdc
, &tm
);
471 nHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
472 nWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
474 switch (LVS_TYPEMASK
& lStyle
)
477 infoPtr
->nColumnWidth
= LISTVIEW_GetMaxItemWidth(hwnd
);
478 infoPtr
->nItemHeight
= (max(tm
.tmHeight
, infoPtr
->iconSize
.cy
) +
481 infoPtr
->nCountPerColumn
= nHeight
/ infoPtr
->nItemHeight
;
482 if (infoPtr
->nCountPerColumn
== 0)
484 infoPtr
->nCountPerColumn
= 1;
487 infoPtr
->nCountPerRow
= nWidth
/ infoPtr
->nColumnWidth
;
488 if (infoPtr
->nCountPerRow
== 0)
490 infoPtr
->nCountPerRow
= 1;
495 infoPtr
->nItemHeight
= (max(tm
.tmHeight
, infoPtr
->iconSize
.cy
) +
497 infoPtr
->nCountPerRow
= 1;
498 infoPtr
->nCountPerColumn
= nHeight
/ infoPtr
->nItemHeight
;
499 if (infoPtr
->nCountPerColumn
== 0)
501 infoPtr
->nCountPerColumn
= 1;
507 SelectObject(hdc
, hOldFont
);
508 ReleaseDC(hwnd
, hdc
);
513 * Adds a block of selections.
516 * [I] HWND : window handle
517 * [I] INT : item index
522 static VOID
LISTVIEW_AddGroupSelection(HWND hwnd
, INT nItem
)
524 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
525 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
526 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
530 lvItem
.state
= LVIS_SELECTED
;
531 lvItem
.stateMask
= LVIS_SELECTED
;
533 for (i
= nFirst
; i
<= nLast
; i
++)
535 ListView_SetItemState(hwnd
, i
, &lvItem
);
538 LISTVIEW_SetItemFocus(hwnd
, nItem
);
539 infoPtr
->nSelectionMark
= nItem
;
544 * Adds a single selection.
547 * [I] HWND : window handle
548 * [I] INT : item index
553 static VOID
LISTVIEW_AddSelection(HWND hwnd
, INT nItem
)
555 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
558 lvItem
.state
= LVIS_SELECTED
;
559 lvItem
.stateMask
= LVIS_SELECTED
;
561 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
563 LISTVIEW_SetItemFocus(hwnd
, nItem
);
564 infoPtr
->nSelectionMark
= nItem
;
569 * Selects or unselects an item.
572 * [I] HWND : window handle
573 * [I] INT : item index
579 static BOOL
LISTVIEW_ToggleSelection(HWND hwnd
, INT nItem
)
581 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
585 lvItem
.stateMask
= LVIS_SELECTED
;
587 if (ListView_GetItemState(hwnd
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
)
590 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
595 lvItem
.state
= LVIS_SELECTED
;
596 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
600 LISTVIEW_SetItemFocus(hwnd
, nItem
);
601 infoPtr
->nSelectionMark
= nItem
;
608 * Reinitilizes the listview items.
611 * [I] HWND : window handle
612 * [I] INT : item index
617 static VOID
LISTVIEW_SetGroupSelection(HWND hwnd
, INT nItem
)
619 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
620 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
621 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
627 LISTVIEW_RemoveSelections(hwnd
, 0, nFirst
- 1);
630 if (nLast
< GETITEMCOUNT(infoPtr
))
632 LISTVIEW_RemoveSelections(hwnd
, nLast
+ 1, GETITEMCOUNT(infoPtr
));
635 lvItem
.state
= LVIS_SELECTED
;
636 lvItem
.stateMask
= LVIS_SELECTED
;
638 for (i
= nFirst
; i
<= nLast
; i
++)
640 ListView_SetItemState(hwnd
, i
, &lvItem
);
643 LISTVIEW_SetItemFocus(hwnd
, nItem
);
648 * Manages the item focus.
651 * [I] HWND : window handle
652 * [I] INT : item index
657 static VOID
LISTVIEW_SetItemFocus(HWND hwnd
, INT nItem
)
659 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
663 lvItem
.stateMask
= LVIS_FOCUSED
;
664 ListView_SetItemState(hwnd
, infoPtr
->nFocusedItem
, &lvItem
);
666 lvItem
.state
= LVIS_FOCUSED
;
667 lvItem
.stateMask
= LVIS_FOCUSED
;
668 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
670 infoPtr
->nFocusedItem
= nItem
;
672 /* if multiple selection is allowed */
673 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
678 * Reinitilizes the listview items.
681 * [I] HWND : window handle
682 * [I] INT : item index
687 static VOID
LISTVIEW_SetSelection(HWND hwnd
, INT nItem
)
689 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
694 LISTVIEW_RemoveSelections(hwnd
, 0, nItem
- 1);
697 if (nItem
< GETITEMCOUNT(infoPtr
))
699 LISTVIEW_RemoveSelections(hwnd
, nItem
+ 1, GETITEMCOUNT(infoPtr
));
703 lvItem
.stateMask
= LVIS_FOCUSED
;
704 ListView_SetItemState(hwnd
, infoPtr
->nFocusedItem
, &lvItem
);
706 lvItem
.state
= LVIS_SELECTED
| LVIS_FOCUSED
;
707 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
708 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
710 infoPtr
->nFocusedItem
= nItem
;
711 infoPtr
->nSelectionMark
= nItem
;
716 * Reinitilizes the listview items.
719 * [I] HWND : window handle
720 * [I] INT : item index
725 static VOID
LISTVIEW_KeySelection(HWND hwnd
, INT nItem
)
727 WORD wShift
= HIWORD(GetKeyState(VK_SHIFT
));
728 WORD wCtrl
= HIWORD(GetKeyState(VK_CONTROL
));
732 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
736 LISTVIEW_SetItemFocus(hwnd
, nItem
);
740 LISTVIEW_SetSelection(hwnd
, nItem
);
742 /* if multiple selection is allowed */
743 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
749 * Removes all selection states.
752 * [I] HWND : window handle
753 * [I] INT : item index
759 static VOID
LISTVIEW_RemoveSelections(HWND hwnd
, INT nFirst
, INT nLast
)
765 lvItem
.stateMask
= LVIS_SELECTED
;
767 for (i
= nFirst
; i
<= nLast
; i
++)
769 ListView_SetItemState(hwnd
, i
, &lvItem
);
778 * [IO] HDPA : dynamic pointer array handle
779 * [I] INT : column index (subitem index)
785 static BOOL
LISTVIEW_RemoveColumn(HDPA hdpaItems
, INT nSubItem
)
791 for (i
= 0; i
< hdpaItems
->nItemCount
; i
++)
793 hdpaSubItems
= (HDPA
)DPA_GetPtr(hdpaItems
, i
);
794 if (hdpaSubItems
!= NULL
)
796 if (LISTVIEW_RemoveSubItem(hdpaSubItems
, nSubItem
) == FALSE
)
808 * Removes a subitem at a given position.
811 * [IO] HDPA : dynamic pointer array handle
812 * [I] INT : subitem index
818 static BOOL
LISTVIEW_RemoveSubItem(HDPA hdpaSubItems
, INT nSubItem
)
820 LISTVIEW_SUBITEM
*lpSubItem
;
823 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
825 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
826 if (lpSubItem
!= NULL
)
828 if (lpSubItem
->iSubItem
== nSubItem
)
831 if ((lpSubItem
->pszText
!= NULL
) &&
832 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
834 COMCTL32_Free(lpSubItem
->pszText
);
838 COMCTL32_Free(lpSubItem
);
840 /* free dpa memory */
841 if (DPA_DeletePtr(hdpaSubItems
, i
) == NULL
)
846 else if (lpSubItem
->iSubItem
> nSubItem
)
858 * Compares the item information.
861 * [I] LISTVIEW_ITEM *: destination item
862 * [I] LPLVITEM : source item
865 * SUCCCESS : TRUE (EQUAL)
866 * FAILURE : FALSE (NOT EQUAL)
868 static UINT
LISTVIEW_GetItemChanges(LISTVIEW_ITEM
*lpItem
, LPLVITEMA lpLVItem
)
872 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
874 if (lpLVItem
->mask
& LVIF_STATE
)
876 if ((lpItem
->state
& lpLVItem
->stateMask
) !=
877 (lpLVItem
->state
& lpLVItem
->stateMask
))
879 uChanged
|= LVIF_STATE
;
883 if (lpLVItem
->mask
& LVIF_IMAGE
)
885 if (lpItem
->iImage
!= lpLVItem
->iImage
)
887 uChanged
|= LVIF_IMAGE
;
891 if (lpLVItem
->mask
& LVIF_PARAM
)
893 if (lpItem
->lParam
!= lpLVItem
->lParam
)
895 uChanged
|= LVIF_PARAM
;
899 if (lpLVItem
->mask
& LVIF_INDENT
)
901 if (lpItem
->iIndent
!= lpLVItem
->iIndent
)
903 uChanged
|= LVIF_INDENT
;
907 if (lpLVItem
->mask
& LVIF_TEXT
)
909 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
911 if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
)
913 uChanged
|= LVIF_TEXT
;
918 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
920 uChanged
|= LVIF_TEXT
;
931 * Initializes item attributes.
934 * [I] HWND : window handle
935 * [O] LISTVIEW_ITEM *: destination item
936 * [I] LPLVITEM : source item
942 static BOOL
LISTVIEW_InitItem(HWND hwnd
, LISTVIEW_ITEM
*lpItem
,
945 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
946 BOOL bResult
= FALSE
;
948 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
952 if (lpLVItem
->mask
& LVIF_STATE
)
954 lpItem
->state
&= ~lpLVItem
->stateMask
;
955 lpItem
->state
|= (lpLVItem
->state
& lpLVItem
->stateMask
);
958 if (lpLVItem
->mask
& LVIF_IMAGE
)
960 lpItem
->iImage
= lpLVItem
->iImage
;
963 if (lpLVItem
->mask
& LVIF_PARAM
)
965 lpItem
->lParam
= lpLVItem
->lParam
;
968 if (lpLVItem
->mask
& LVIF_INDENT
)
970 lpItem
->iIndent
= lpLVItem
->iIndent
;
973 if (lpLVItem
->mask
& LVIF_TEXT
)
975 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
977 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
982 if ((lpItem
->pszText
!= NULL
) &&
983 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
985 COMCTL32_Free(lpItem
->pszText
);
988 lpItem
->pszText
= LPSTR_TEXTCALLBACKA
;
992 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
994 lpItem
->pszText
= NULL
;
997 bResult
= Str_SetPtrA(&lpItem
->pszText
, lpLVItem
->pszText
);
1007 * Initializes subitem attributes.
1009 * NOTE: the documentation specifies that the operation fails if the user
1010 * tries to set the indent of a subitem.
1013 * [I] HWND : window handle
1014 * [O] LISTVIEW_SUBITEM *: destination subitem
1015 * [I] LPLVITEM : source subitem
1021 static BOOL
LISTVIEW_InitSubItem(HWND hwnd
, LISTVIEW_SUBITEM
*lpSubItem
,
1024 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1025 BOOL bResult
= FALSE
;
1027 if ((lpSubItem
!= NULL
) && (lpLVItem
!= NULL
))
1029 if (!(lpLVItem
->mask
& LVIF_INDENT
))
1032 ZeroMemory(lpSubItem
, sizeof(LISTVIEW_SUBITEM
));
1034 lpSubItem
->iSubItem
= lpLVItem
->iSubItem
;
1036 if (lpLVItem
->mask
& LVIF_IMAGE
)
1038 lpSubItem
->iImage
= lpLVItem
->iImage
;
1041 if (lpLVItem
->mask
& LVIF_TEXT
)
1043 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1045 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
1050 if ((lpSubItem
->pszText
!= NULL
) &&
1051 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1053 COMCTL32_Free(lpSubItem
->pszText
);
1056 lpSubItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1060 if (lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1062 lpSubItem
->pszText
= NULL
;
1065 bResult
= Str_SetPtrA(&lpSubItem
->pszText
, lpLVItem
->pszText
);
1076 * Adds a subitem at a given position (column index).
1079 * [I] HWND : window handle
1080 * [I] LPLVITEM : new subitem atttributes
1086 static BOOL
LISTVIEW_AddSubItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1088 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1089 BOOL bResult
= FALSE
;
1091 LISTVIEW_SUBITEM
*lpSubItem
= NULL
;
1092 INT nPosition
, nItem
;
1094 if (lpLVItem
!= NULL
)
1096 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
1097 if (hdpaSubItems
!= NULL
)
1099 lpSubItem
= (LISTVIEW_SUBITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM
));
1100 if (lpSubItem
!= NULL
)
1102 if (LISTVIEW_InitSubItem(hwnd
, lpSubItem
, lpLVItem
) == TRUE
)
1104 nPosition
= LISTVIEW_FindInsertPosition(hdpaSubItems
,
1105 lpSubItem
->iSubItem
);
1106 nItem
= DPA_InsertPtr(hdpaSubItems
, nPosition
, lpSubItem
);
1116 /* cleanup if unsuccessful */
1117 if ((bResult
== FALSE
) && (lpSubItem
!= NULL
))
1119 COMCTL32_Free(lpSubItem
);
1127 * Finds the dpa insert position (array index).
1130 * [I] HWND : window handle
1131 * [I] INT : subitem index
1137 static INT
LISTVIEW_FindInsertPosition(HDPA hdpaSubItems
, INT nSubItem
)
1139 LISTVIEW_SUBITEM
*lpSubItem
;
1142 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
1144 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
1145 if (lpSubItem
!= NULL
)
1147 if (lpSubItem
->iSubItem
> nSubItem
)
1154 return hdpaSubItems
->nItemCount
;
1159 * Retrieves a listview subitem at a given position (column index).
1162 * [I] HWND : window handle
1163 * [I] INT : subitem index
1169 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA hdpaSubItems
, INT nSubItem
)
1171 LISTVIEW_SUBITEM
*lpSubItem
;
1174 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
1176 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
1177 if (lpSubItem
!= NULL
)
1179 if (lpSubItem
->iSubItem
== nSubItem
)
1183 else if (lpSubItem
->iSubItem
> nSubItem
)
1195 * Sets item attributes.
1198 * [I] HWND : window handle
1199 * [I] LPLVITEM : new item atttributes
1205 static BOOL
LISTVIEW_SetItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1207 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1208 BOOL bResult
= FALSE
;
1210 LISTVIEW_ITEM
*lpItem
;
1213 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
1215 if (lpLVItem
!= NULL
)
1217 if (lpLVItem
->iSubItem
== 0)
1219 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
1220 if (hdpaSubItems
!= NULL
)
1222 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
1225 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
1226 nmlv
.hdr
.hwndFrom
= hwnd
;
1227 nmlv
.hdr
.idFrom
= lCtrlId
;
1228 nmlv
.hdr
.code
= LVN_ITEMCHANGING
;
1229 nmlv
.lParam
= lpItem
->lParam
;
1230 uChanged
= LISTVIEW_GetItemChanges(lpItem
, lpLVItem
);
1233 if (uChanged
& LVIF_STATE
)
1235 nmlv
.uNewState
= lpLVItem
->state
& lpLVItem
->stateMask
;
1236 nmlv
.uOldState
= lpItem
->state
& lpLVItem
->stateMask
;
1239 nmlv
.uChanged
= uChanged
;
1240 nmlv
.iItem
= lpLVItem
->iItem
;
1241 nmlv
.lParam
= lpItem
->lParam
;
1242 /* send LVN_ITEMCHANGING notification */
1243 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
1245 /* copy information */
1246 bResult
= LISTVIEW_InitItem(hwnd
, lpItem
, lpLVItem
);
1248 /* send LVN_ITEMCHANGED notification */
1249 nmlv
.hdr
.code
= LVN_ITEMCHANGED
;
1250 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
1257 InvalidateRect(hwnd
, NULL
, FALSE
);
1268 * Sets subitem attributes.
1271 * [I] HWND : window handle
1272 * [I] LPLVITEM : new subitem atttributes
1278 static BOOL
LISTVIEW_SetSubItem(HWND hwnd
, LPLVITEMA lpLVItem
)
1280 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1281 BOOL bResult
= FALSE
;
1283 LISTVIEW_SUBITEM
*lpSubItem
;
1285 if (lpLVItem
!= NULL
)
1287 if (lpLVItem
->iSubItem
> 0)
1289 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
1290 if (hdpaSubItems
!= NULL
)
1292 /* set subitem only if column is present */
1293 if (Header_GetItemCount(infoPtr
->hwndHeader
) > lpLVItem
->iSubItem
)
1295 lpSubItem
= LISTVIEW_GetSubItem(hdpaSubItems
, lpLVItem
->iSubItem
);
1296 if (lpSubItem
!= NULL
)
1298 bResult
= LISTVIEW_InitSubItem(hwnd
, lpSubItem
, lpLVItem
);
1302 bResult
= LISTVIEW_AddSubItem(hwnd
, lpLVItem
);
1305 InvalidateRect(hwnd
, NULL
, FALSE
);
1316 * Retrieves the index of the item at coordinate (0, 0) of the client area.
1319 * [I] HWND : window handle
1324 static INT
LISTVIEW_GetTopIndex(HWND hwnd
)
1326 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*) GetWindowLongA(hwnd
, 0);
1327 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1330 switch (LVS_TYPEMASK
& lStyle
)
1333 if (lStyle
& WS_HSCROLL
)
1335 nItem
= GetScrollPos(hwnd
, SB_HORZ
) * infoPtr
->nCountPerColumn
;
1340 if (lStyle
& WS_VSCROLL
)
1342 nItem
= GetScrollPos(hwnd
, SB_VERT
);
1352 * Sets scrollbar(s).
1355 * [I] HWND : window handle
1358 * TRUE if scrollbars were added, modified or removed.
1360 static VOID
LISTVIEW_SetVScroll(HWND hwnd
)
1362 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1363 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1367 switch (LVS_TYPEMASK
& lStyle
)
1370 nMaxRange
= GETITEMCOUNT(infoPtr
) - infoPtr
->nCountPerColumn
;
1371 SetScrollRange(hwnd
, SB_VERT
, 0, nMaxRange
, FALSE
);
1372 nScrollPos
= ListView_GetTopIndex(hwnd
);
1373 SetScrollPos(hwnd
, SB_VERT
, nScrollPos
, TRUE
);
1381 static VOID
LISTVIEW_SetHScroll(HWND hwnd
)
1383 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
1384 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1385 /* INT nScrollPos; */
1386 /* INT nMaxRange; */
1388 switch (LVS_TYPEMASK
& lStyle
)
1399 static VOID
LISTVIEW_SetScroll(HWND hwnd
)
1401 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1402 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1403 INT nHiddenItemCount
;
1408 BOOL bHScroll
= FALSE
;
1409 BOOL bVScroll
= FALSE
;
1410 INT nHeaderWidth
= 0;
1414 switch (LVS_TYPEMASK
& lStyle
)
1417 nCountPerPage
= infoPtr
->nCountPerRow
* infoPtr
->nCountPerColumn
;
1418 if (nCountPerPage
< GETITEMCOUNT(infoPtr
))
1420 /* add scrollbar if not already present */
1421 if (!(lStyle
& WS_HSCROLL
))
1423 ShowScrollBar(hwnd
, SB_HORZ
, TRUE
);
1426 /* calculate new scrollbar range */
1427 nHiddenItemCount
= GETITEMCOUNT(infoPtr
) - nCountPerPage
;
1428 if ((nHiddenItemCount
% infoPtr
->nCountPerColumn
) == 0)
1430 nMaxRange
= nHiddenItemCount
/ infoPtr
->nCountPerColumn
;
1434 nMaxRange
= nHiddenItemCount
/ infoPtr
->nCountPerColumn
+ 1;
1437 SetScrollRange(hwnd
, SB_HORZ
, 0, nMaxRange
, FALSE
);
1438 nScrollPos
= ListView_GetTopIndex(hwnd
) / infoPtr
->nCountPerColumn
;
1439 SetScrollPos(hwnd
, SB_HORZ
, nScrollPos
, TRUE
);
1443 /* remove scrollbar if present */
1444 if (lStyle
& WS_HSCROLL
)
1446 /* hide scrollbar */
1447 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
1453 nItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1454 for (i
= 0; i
< nItemCount
; i
++)
1456 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rc
) != 0)
1458 nHeaderWidth
+= (rc
.right
- rc
.left
);
1462 if (nHeaderWidth
> (infoPtr
->rcList
.right
- infoPtr
->rcList
.left
))
1466 /* add horizontal scrollbar if not present */
1467 if (!(lStyle
& WS_HSCROLL
))
1469 /* display scrollbar */
1470 ShowScrollBar(hwnd
, SB_HORZ
, TRUE
);
1475 /* remove scrollbar if present */
1476 if (lStyle
& WS_HSCROLL
)
1478 /* hide scrollbar */
1479 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
1483 if (infoPtr
->nCountPerColumn
< GETITEMCOUNT(infoPtr
))
1487 /* add scrollbar if not already present */
1488 if (!(lStyle
& WS_VSCROLL
))
1490 /* display scrollbar */
1491 ShowScrollBar(hwnd
, SB_VERT
, TRUE
);
1496 /* remove scrollbar if present */
1497 if (lStyle
& WS_VSCROLL
)
1499 /* hide scrollbar */
1500 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
1509 /* set range and position */
1510 GetClientRect(hwnd
, &rc
);
1511 if ((bHScroll
== TRUE
) || (bVScroll
== TRUE
))
1513 LISTVIEW_SetSize(hwnd
, lStyle
, rc
.right
, rc
.bottom
);
1514 LISTVIEW_SetViewInfo(hwnd
);
1515 if (bHScroll
== TRUE
)
1517 LISTVIEW_SetHScroll(hwnd
);
1520 if (bVScroll
== TRUE
)
1522 LISTVIEW_SetVScroll(hwnd
);
1532 * [I] HDC : device context handle
1533 * [I] LISTVIEW_INFO * : listview information
1534 * [I] LISTVIEW_SUBITEM * : subitem
1535 * [I] RECT * : clipping rectangle
1540 static VOID
LISTVIEW_DrawSubItem(HWND hwnd
, HDC hdc
, INT nItem
, LPARAM lParam
,
1541 LISTVIEW_SUBITEM
*lpSubItem
, INT nColumn
,
1544 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1545 CHAR szDispText
[DISP_TEXT_SIZE
];
1546 LPSTR pszDispText
= NULL
;
1548 /* set item colors */
1549 SetBkColor(hdc
, infoPtr
->clrTextBk
);
1550 SetTextColor(hdc
, infoPtr
->clrText
);
1552 pszDispText
= szDispText
;
1553 LISTVIEW_GetSubItemDispInfo(hwnd
, nItem
, lParam
, lpSubItem
, nColumn
, NULL
,
1554 &pszDispText
, DISP_TEXT_SIZE
);
1556 /* draw text : using arbitrary offset of 10 pixels */
1557 ExtTextOutA(hdc
, lprc
->left
+ 10, lprc
->top
, ETO_OPAQUE
|ETO_CLIPPED
,
1558 lprc
, pszDispText
, lstrlenA(pszDispText
), NULL
);
1566 * [I] HDC : device context handle
1567 * [I] LISTVIEW_INFO * : listview information
1568 * [I] LISTVIEW_ITEM * : item
1569 * [I] RECT * : clipping rectangle
1574 static VOID
LISTVIEW_DrawItem(HWND hwnd
, HDC hdc
, LISTVIEW_ITEM
*lpItem
,
1575 INT nItem
, RECT
*lprc
)
1577 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1581 CHAR szDispText
[DISP_TEXT_SIZE
];
1582 LPSTR pszDispText
= NULL
;
1585 pszDispText
= szDispText
;
1586 LISTVIEW_GetItemDispInfo(hwnd
, nItem
, lpItem
, &nImage
, &uState
, &pszDispText
,
1588 if (uState
& LVIS_SELECTED
)
1592 /* set item colors */
1593 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1594 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1596 /* set raster mode */
1597 SetROP2(hdc
, R2_XORPEN
);
1603 /* set item colors */
1604 SetBkColor(hdc
, infoPtr
->clrTextBk
);
1605 SetTextColor(hdc
, infoPtr
->clrText
);
1607 /* set raster mode */
1608 SetROP2(hdc
, R2_COPYPEN
);
1612 if (infoPtr
->himlState
!= NULL
)
1614 /* right shift 12 bits to obtain index in image list */
1615 if (bSelected
== TRUE
)
1617 ImageList_Draw(infoPtr
->himlState
, uState
>> 12, hdc
, lprc
->left
,
1618 lprc
->top
, ILD_SELECTED
);
1622 ImageList_Draw(infoPtr
->himlState
, uState
>> 12, hdc
, lprc
->left
,
1623 lprc
->top
, ILD_NORMAL
);
1626 lprc
->left
+= infoPtr
->iconSize
.cx
;
1630 if (infoPtr
->himlSmall
!= NULL
)
1632 if (bSelected
== TRUE
)
1634 ImageList_Draw(infoPtr
->himlSmall
, nImage
, hdc
, lprc
->left
,
1635 lprc
->top
, ILD_SELECTED
);
1639 ImageList_Draw(infoPtr
->himlSmall
, nImage
, hdc
, lprc
->left
,
1640 lprc
->top
, ILD_NORMAL
);
1643 lprc
->left
+= infoPtr
->iconSize
.cx
;
1646 nLabelWidth
= ListView_GetStringWidthA(hwnd
, pszDispText
);
1647 if (lprc
->left
+ nLabelWidth
< lprc
->right
)
1649 lprc
->right
= lprc
->left
+ nLabelWidth
;
1653 ExtTextOutA(hdc
, lprc
->left
+ 1, lprc
->top
+ 1, ETO_OPAQUE
|ETO_CLIPPED
,
1654 lprc
, pszDispText
, lstrlenA(pszDispText
), NULL
);
1656 if (lpItem
->state
& LVIS_FOCUSED
)
1658 Rectangle(hdc
, lprc
->left
, lprc
->top
, lprc
->right
, lprc
->bottom
);
1664 * Draws listview items when in report display mode.
1667 * [I] HWND : window handle
1668 * [I] HDC : device context handle
1673 static VOID
LISTVIEW_RefreshReport(HWND hwnd
, HDC hdc
)
1675 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
1676 INT nDrawPosY
= infoPtr
->rcList
.top
;
1677 LISTVIEW_ITEM
*lpItem
;
1678 LISTVIEW_SUBITEM
*lpSubItem
= NULL
;
1685 BOOL bNeedSubItem
= TRUE
;
1687 nItem
= ListView_GetTopIndex(hwnd
);
1688 nLast
= nItem
+ infoPtr
->nCountPerColumn
;
1689 while (nItem
<= nLast
)
1691 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
1692 if (hdpaSubItems
!= NULL
)
1694 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
1697 Header_GetItemRect(infoPtr
->hwndHeader
, 0, &rc
);
1699 rc
.bottom
= rc
.top
+ infoPtr
->nItemHeight
;
1701 /* draw state icon + icon + text */
1702 LISTVIEW_DrawItem(hwnd
, hdc
, lpItem
, nItem
, &rc
);
1705 nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1706 for (k
= 1, j
= 1; j
< nColumnCount
; j
++)
1708 Header_GetItemRect(infoPtr
->hwndHeader
, j
, &rc
);
1710 rc
.bottom
= rc
.top
+ infoPtr
->nItemHeight
;
1712 if (k
< hdpaSubItems
->nItemCount
)
1714 if (bNeedSubItem
== TRUE
)
1716 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, k
);
1720 if (lpSubItem
!= NULL
)
1722 if (lpSubItem
->iSubItem
== j
)
1724 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, lpItem
->lParam
, lpSubItem
,
1726 bNeedSubItem
= TRUE
;
1730 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, lpItem
->lParam
, NULL
, j
,
1732 bNeedSubItem
= FALSE
;
1737 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, lpItem
->lParam
, NULL
, j
,
1739 bNeedSubItem
= TRUE
;
1744 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, lpItem
->lParam
, NULL
, j
, &rc
);
1749 nDrawPosY
+= infoPtr
->nItemHeight
;
1756 * Draws listview items when in list display mode.
1759 * [I] HWND : window handle
1760 * [I] HDC : device context handle
1765 static VOID
LISTVIEW_RefreshList(HWND hwnd
, HDC hdc
)
1767 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1768 LISTVIEW_ITEM
*lpItem
;
1773 INT nItem
= ListView_GetTopIndex(hwnd
);
1775 if (infoPtr
->rcList
.right
> 0)
1777 /* get number of display columns */
1778 if (infoPtr
->rcList
.right
% infoPtr
->nColumnWidth
== 0)
1780 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nColumnWidth
;
1784 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nColumnWidth
+ 1;
1787 for (i
= 0; i
< nColumnCount
; i
++)
1790 while ((nItem
< GETITEMCOUNT(infoPtr
)) && (j
< infoPtr
->nCountPerColumn
))
1792 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
1793 if (hdpaSubItems
!= NULL
)
1795 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
1798 rc
.top
= j
* infoPtr
->nItemHeight
;
1799 rc
.left
= i
* infoPtr
->nColumnWidth
;
1800 rc
.bottom
= rc
.top
+ infoPtr
->nItemHeight
;
1801 rc
.right
= rc
.left
+ infoPtr
->nColumnWidth
;
1803 /* draw state icon + icon + text */
1804 LISTVIEW_DrawItem(hwnd
, hdc
, lpItem
, nItem
, &rc
);
1817 * Draws listview items when in small icon display mode.
1820 * [I] HWND : window handle
1821 * [I] HDC : device context handle
1826 static VOID
LISTVIEW_RefreshSmallIcon(HWND hwnd
, HDC hdc
)
1828 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1829 LISTVIEW_ITEM
*lpItem
;
1833 INT nItem
= ListView_GetTopIndex(hwnd
);
1835 for (i
= 0; i
< infoPtr
->nCountPerColumn
; i
++)
1838 while ((nItem
< GETITEMCOUNT(infoPtr
)) && (j
< infoPtr
->nCountPerRow
))
1840 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
1841 if (hdpaSubItems
!= NULL
)
1843 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
1846 rc
.top
= i
* infoPtr
->nItemHeight
;
1847 rc
.left
= j
* infoPtr
->nColumnWidth
;
1848 rc
.bottom
= rc
.top
+ infoPtr
->nItemHeight
;
1849 rc
.right
= rc
.left
+ infoPtr
->nColumnWidth
;
1851 /* draw state icon + icon + text */
1852 LISTVIEW_DrawItem(hwnd
, hdc
, lpItem
, nItem
, &rc
);
1864 * Draws listview items when in icon display mode.
1867 * [I] HWND : window handle
1868 * [I] HDC : device context handle
1873 static VOID
LISTVIEW_RefreshIcon(HWND hwnd
, HDC hdc
)
1880 * Draws listview items.
1883 * [I] HWND : window handle
1884 * [I] HDC : device context handle
1889 static VOID
LISTVIEW_Refresh(HWND hwnd
, HDC hdc
)
1891 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1892 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1897 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
1899 /* select the doted pen (for drawing the focus box) */
1900 hPen
= CreatePen(PS_DOT
, 1, 0);
1901 hOldPen
= SelectObject(hdc
, hPen
);
1903 /* select transparent brush (for drawing the focus box) */
1904 SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
1906 switch (LVS_TYPEMASK
& lStyle
)
1909 LISTVIEW_RefreshList(hwnd
, hdc
);
1912 LISTVIEW_RefreshReport(hwnd
, hdc
);
1915 LISTVIEW_RefreshSmallIcon(hwnd
, hdc
);
1918 LISTVIEW_RefreshIcon(hwnd
, hdc
);
1921 /* unselect objects */
1922 SelectObject(hdc
, hOldFont
);
1923 SelectObject(hdc
, hOldPen
);
1932 * Calculates the approximate width and height of a given number of items.
1935 * [I] HWND : window handle
1936 * [I] INT : number of items
1941 * Returns a DWORD. The width in the low word and the height in high word.
1943 static LRESULT
LISTVIEW_ApproximateViewRect(HWND hwnd
, INT nItemCount
,
1944 WORD wWidth
, WORD wHeight
)
1946 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1947 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1948 INT nItemCountPerColumn
= 1;
1949 INT nColumnCount
= 0;
1950 DWORD dwViewRect
= 0;
1952 if (nItemCount
== -1)
1953 nItemCount
= GETITEMCOUNT(infoPtr
);
1955 if (lStyle
& LVS_LIST
)
1957 if (wHeight
== 0xFFFF)
1959 /* use current height */
1960 wHeight
= infoPtr
->rcList
.bottom
;
1963 if (wHeight
< infoPtr
->nItemHeight
)
1965 wHeight
= infoPtr
->nItemHeight
;
1970 if (infoPtr
->nItemHeight
> 0)
1972 nItemCountPerColumn
= wHeight
/ infoPtr
->nItemHeight
;
1973 if (nItemCountPerColumn
== 0)
1974 nItemCountPerColumn
= 1;
1976 if (nItemCount
% nItemCountPerColumn
!= 0)
1977 nColumnCount
= nItemCount
/ nItemCountPerColumn
;
1979 nColumnCount
= nItemCount
/ nItemCountPerColumn
+ 1;
1983 /* Microsoft padding magic */
1984 wHeight
= nItemCountPerColumn
* infoPtr
->nItemHeight
+ 2;
1985 wWidth
= nColumnCount
* infoPtr
->nColumnWidth
+ 2;
1987 dwViewRect
= MAKELONG(wWidth
, wHeight
);
1989 else if (lStyle
& LVS_REPORT
)
1993 else if (lStyle
& LVS_SMALLICON
)
1997 else if (lStyle
& LVS_ICON
)
2007 * Arranges listview items in icon display mode.
2010 * [I] HWND : window handle
2011 * [I] INT : alignment code
2017 static LRESULT
LISTVIEW_Arrange(HWND hwnd
, INT nAlignCode
)
2019 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2020 BOOL bResult
= FALSE
;
2022 if (((LVS_TYPEMASK
& lStyle
) == LVS_ICON
) ||
2023 ((LVS_TYPEMASK
& lStyle
) == LVS_SMALLICON
))
2036 case LVA_SNAPTOGRID
:
2044 /* << LISTVIEW_CreateDragImage >> */
2048 * Removes all listview items and subitems.
2051 * [I] HWND : window handle
2057 static LRESULT
LISTVIEW_DeleteAllItems(HWND hwnd
)
2059 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2060 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2061 LISTVIEW_ITEM
*lpItem
;
2062 LISTVIEW_SUBITEM
*lpSubItem
;
2065 BOOL bResult
= FALSE
;
2070 if (GETITEMCOUNT(infoPtr
) > 0)
2072 /* initialize memory */
2073 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2075 /* send LVN_DELETEALLITEMS notification */
2076 nmlv
.hdr
.hwndFrom
= hwnd
;
2077 nmlv
.hdr
.idFrom
= lCtrlId
;
2078 nmlv
.hdr
.code
= LVN_DELETEALLITEMS
;
2081 /* verify if subsequent LVN_DELETEITEM notifications should be
2083 bSuppress
= ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
2085 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
2087 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
2088 if (hdpaSubItems
!= NULL
)
2090 for (j
= 1; j
< hdpaSubItems
->nItemCount
; j
++)
2092 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, j
);
2093 if (lpSubItem
!= NULL
)
2095 /* free subitem string */
2096 if ((lpSubItem
->pszText
!= NULL
) &&
2097 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2099 COMCTL32_Free(lpSubItem
->pszText
);
2103 COMCTL32_Free(lpSubItem
);
2107 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2110 if (bSuppress
== FALSE
)
2112 /* send LVN_DELETEITEM notification */
2113 nmlv
.hdr
.code
= LVN_DELETEITEM
;
2115 nmlv
.lParam
= lpItem
->lParam
;
2116 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
2119 /* free item string */
2120 if ((lpItem
->pszText
!= NULL
) &&
2121 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2123 COMCTL32_Free(lpItem
->pszText
);
2127 COMCTL32_Free(lpItem
);
2130 DPA_Destroy(hdpaSubItems
);
2134 /* reinitialize listview memory */
2135 bResult
= DPA_DeleteAllPtrs(infoPtr
->hdpaItems
);
2137 /* reset scroll parameters */
2138 LISTVIEW_SetScroll(hwnd
);
2140 /* invalidate client area (optimization needed) */
2141 InvalidateRect(hwnd
, NULL
, FALSE
);
2149 * Removes a column from the listview control.
2152 * [I] HWND : window handle
2153 * [I] INT : column index
2159 static LRESULT
LISTVIEW_DeleteColumn(HWND hwnd
, INT nColumn
)
2161 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2162 BOOL bResult
= FALSE
;
2164 if (Header_DeleteItem(infoPtr
->hwndHeader
, nColumn
) == TRUE
)
2166 bResult
= LISTVIEW_RemoveColumn(infoPtr
->hdpaItems
, nColumn
);
2169 /* reset scroll parameters */
2170 LISTVIEW_SetScroll(hwnd
);
2172 /* refresh client area */
2173 InvalidateRect(hwnd
, NULL
, FALSE
);
2180 * Removes an item from the listview control.
2183 * [I] HWND : window handle
2184 * [I] INT : item index
2190 static LRESULT
LISTVIEW_DeleteItem(HWND hwnd
, INT nItem
)
2192 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2193 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2195 BOOL bResult
= FALSE
;
2197 LISTVIEW_ITEM
*lpItem
;
2198 LISTVIEW_SUBITEM
*lpSubItem
;
2201 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
2203 /* initialize memory */
2204 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2206 hdpaSubItems
= (HDPA
)DPA_DeletePtr(infoPtr
->hdpaItems
, nItem
);
2207 if (hdpaSubItems
!= NULL
)
2209 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2211 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2212 if (lpSubItem
!= NULL
)
2214 /* free item string */
2215 if ((lpSubItem
->pszText
!= NULL
) &&
2216 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2218 COMCTL32_Free(lpSubItem
->pszText
);
2222 COMCTL32_Free(lpSubItem
);
2226 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2229 /* send LVN_DELETEITEM notification */
2230 nmlv
.hdr
.hwndFrom
= hwnd
;
2231 nmlv
.hdr
.idFrom
= lCtrlId
;
2232 nmlv
.hdr
.code
= LVN_DELETEITEM
;
2234 nmlv
.lParam
= lpItem
->lParam
;
2235 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
2238 /* free item string */
2239 if ((lpItem
->pszText
!= NULL
) &&
2240 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2242 COMCTL32_Free(lpItem
->pszText
);
2246 COMCTL32_Free(lpItem
);
2249 bResult
= DPA_Destroy(hdpaSubItems
);
2252 /* refresh client area */
2253 InvalidateRect(hwnd
, NULL
, FALSE
);
2259 /* << LISTVIEW_EditLabel >> */
2263 * Ensures the specified item is visible, scrolling into view if necessary.
2266 * [I] HWND : window handle
2267 * [I] INT : item index
2268 * [I] BOOL : partially or entirely visible
2274 static BOOL
LISTVIEW_EnsureVisible(HWND hwnd
, INT nItem
, BOOL bPartial
)
2276 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2277 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2281 BOOL bResult
= TRUE
;
2283 switch (LVS_TYPEMASK
& lStyle
)
2286 if (lStyle
& WS_HSCROLL
)
2288 nFirst
= ListView_GetTopIndex(hwnd
);
2290 /* calculate last fully visible item index */
2291 nLast
= infoPtr
->nCountPerColumn
* infoPtr
->nCountPerRow
+ nFirst
- 1;
2295 /* calculate new scroll position based on item index */
2296 if (((nItem
- nLast
) % infoPtr
->nCountPerColumn
) == 0)
2298 nScrollPos
= (nItem
- nLast
) / infoPtr
->nCountPerColumn
;
2302 nScrollPos
= (nItem
- nLast
) / infoPtr
->nCountPerColumn
+ 1;
2305 bResult
= ListView_Scroll(hwnd
, nScrollPos
, 0);
2307 else if (nItem
< nFirst
)
2309 /* calculate new scroll position based on item index */
2310 if (((nItem
- nFirst
) % infoPtr
->nCountPerColumn
) == 0)
2312 nScrollPos
= (nItem
- nFirst
) / infoPtr
->nCountPerColumn
;
2316 nScrollPos
= (nItem
- nFirst
) / infoPtr
->nCountPerColumn
-1;
2319 bResult
= ListView_Scroll(hwnd
, nScrollPos
, 0);
2325 if (lStyle
& WS_VSCROLL
)
2327 nFirst
= ListView_GetTopIndex(hwnd
);
2329 /* calculate last fully visible item index */
2330 nLast
= infoPtr
->nCountPerColumn
+ nFirst
- 1;
2333 nScrollPos
= nItem
- nLast
;
2334 bResult
= ListView_Scroll(hwnd
, 0, nScrollPos
);
2336 else if (nItem
< nFirst
)
2338 nScrollPos
= nItem
- nFirst
;
2339 bResult
= ListView_Scroll(hwnd
, 0, nScrollPos
);
2357 * Searches for an item with specific characteristics.
2360 * [I] HWND : window handle
2361 * [I] INT : base item index
2362 * [I] LPLVFINDINFO : item information to look for
2365 * SUCCESS : index of item
2368 static LRESULT
LISTVIEW_FindItem(HWND hwnd
, INT nStart
,
2369 LPLVFINDINFO lpFindInfo
)
2371 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
2372 /* LISTVIEW_ITEM *lpItem; */
2374 /* INT nEnd = GETITEMCOUNT(infoPtr); */
2375 /* BOOL bWrap = FALSE; */
2376 /* if (nStart == -1) */
2380 /* if (lpFindInfo->flags & LVFI_PARAM) */
2382 /* for (nItem = nStart; nItem < nEnd; nItem++) */
2384 /* get item pointer */
2385 /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
2386 /* if (lpItem != NULL) */
2388 /* if (lpFindInfo->lParam == lpItem->lParam) */
2395 /* if (lpFindInfo->flags & LVFI_PARTIAL) */
2397 /* for (nItem = nStart; nItem < nEnd; nItem++) */
2399 /* get item pointer */
2400 /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
2403 /* if (strncmp(lpItem->pszText, lpFindInfo->psz, strlen(lpFindInfo->psz)) */
2410 /* if (lpFindInfo->flags & LVFI_STRING) */
2412 /* for (nItem = nStart; nItem < nEnd; nItem++) */
2414 /* get item pointer */
2415 /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
2416 /* if (lpItem != NULL) */
2418 /* if (strcmp(lpItem->pszText, lpFindInfo->psz) == 0) */
2424 /* if ((lpFindInfo->flags & LVFI_WRAP) && nStart) */
2426 /* nEnd = nStart; */
2431 /* bWrap = FALSE; */
2438 * Retrieves the background color of the listview control.
2441 * [I] HWND : window handle
2444 * COLORREF associated with the background.
2446 static LRESULT
LISTVIEW_GetBkColor(HWND hwnd
)
2448 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2450 return infoPtr
->clrBk
;
2455 * Retrieves the background image of the listview control.
2458 * [I] HWND : window handle
2459 * [O] LPLVMKBIMAGE : background image attributes
2465 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
2472 * Retrieves the callback mask.
2475 * [I] HWND : window handle
2480 static UINT
LISTVIEW_GetCallbackMask(HWND hwnd
)
2482 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2484 return infoPtr
->uCallbackMask
;
2489 * Retrieves column attributes.
2492 * [I] HWND : window handle
2493 * [I] INT : column index
2494 * [IO] LPLVCOLUMNA : column information
2500 static LRESULT
LISTVIEW_GetColumnA(HWND hwnd
, INT nItem
,
2501 LPLVCOLUMNA lpColumn
)
2503 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2505 BOOL bResult
= FALSE
;
2507 if (lpColumn
!= NULL
)
2509 /* initialize memory */
2510 ZeroMemory(&hdi
, sizeof(HDITEMA
));
2512 if (lpColumn
->mask
& LVCF_FMT
)
2514 hdi
.mask
|= HDI_FORMAT
;
2517 if (lpColumn
->mask
& LVCF_WIDTH
)
2519 hdi
.mask
|= HDI_WIDTH
;
2522 if (lpColumn
->mask
& LVCF_TEXT
)
2524 hdi
.mask
|= (HDI_TEXT
| HDI_FORMAT
);
2527 if (lpColumn
->mask
& LVCF_IMAGE
)
2529 hdi
.mask
|= HDI_IMAGE
;
2532 if (lpColumn
->mask
& LVCF_ORDER
)
2534 hdi
.mask
|= HDI_ORDER
;
2537 bResult
= Header_GetItemA(infoPtr
->hwndHeader
, nItem
, &hdi
);
2538 if (bResult
== TRUE
)
2540 if (lpColumn
->mask
& LVCF_FMT
)
2544 if (hdi
.fmt
& HDF_LEFT
)
2546 lpColumn
->fmt
|= LVCFMT_LEFT
;
2548 else if (hdi
.fmt
& HDF_RIGHT
)
2550 lpColumn
->fmt
|= LVCFMT_RIGHT
;
2552 else if (hdi
.fmt
& HDF_CENTER
)
2554 lpColumn
->fmt
|= LVCFMT_CENTER
;
2557 if (hdi
.fmt
& HDF_IMAGE
)
2559 lpColumn
->fmt
|= LVCFMT_COL_HAS_IMAGES
;
2563 if (lpColumn
->mask
& LVCF_WIDTH
)
2565 lpColumn
->cx
= hdi
.cxy
;
2568 if ((lpColumn
->mask
& LVCF_TEXT
) && (lpColumn
->pszText
) && (hdi
.pszText
))
2570 lstrcpynA (lpColumn
->pszText
, hdi
.pszText
, lpColumn
->cchTextMax
);
2573 if (lpColumn
->mask
& LVCF_IMAGE
)
2575 lpColumn
->iImage
= hdi
.iImage
;
2578 if (lpColumn
->mask
& LVCF_ORDER
)
2580 lpColumn
->iOrder
= hdi
.iOrder
;
2588 /* << LISTVIEW_GetColumnW >> */
2589 /* << LISTVIEW_GetColumnOrderArray >> */
2593 * Retrieves the column width.
2596 * [I] HWND : window handle
2597 * [I] int : column index
2600 * SUCCESS : column width
2603 static LRESULT
LISTVIEW_GetColumnWidth(HWND hwnd
, INT nColumn
)
2605 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2606 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2608 INT nColumnWidth
= 0;
2610 if ((LVS_TYPEMASK
& lStyle
) == LVS_LIST
)
2612 nColumnWidth
= infoPtr
->nColumnWidth
;
2614 else if ((LVS_TYPEMASK
& lStyle
) == LVS_REPORT
)
2616 /* get column width from header */
2617 ZeroMemory(&hdi
, sizeof(HDITEMA
));
2618 hdi
.mask
= HDI_WIDTH
;
2619 if (Header_GetItemA(infoPtr
->hwndHeader
, nColumn
, &hdi
) == TRUE
)
2621 nColumnWidth
= hdi
.cxy
;
2625 return nColumnWidth
;
2630 * In list or report display mode, retrieves the number of items that can fit
2631 * vertically in the visible area. In icon or small icon display mode,
2632 * retrieves the total number of visible items.
2635 * [I] HWND : window handle
2638 * Number of fully visible items.
2640 static LRESULT
LISTVIEW_GetCountPerPage(HWND hwnd
)
2642 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2643 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2646 switch (LVS_TYPEMASK
& lStyle
)
2649 if (infoPtr
->rcList
.right
/ infoPtr
->nColumnWidth
)
2651 nItemCount
= infoPtr
->nCountPerRow
* infoPtr
->nCountPerColumn
;
2656 nItemCount
= infoPtr
->nCountPerColumn
;
2660 nItemCount
= GETITEMCOUNT(infoPtr
);
2666 /* << LISTVIEW_GetEditControl >> */
2667 /* << LISTVIEW_GetExtendedListViewStyle >> */
2671 * Retrieves a header handle.
2674 * [I] HWND : window handle
2679 static LRESULT
LISTVIEW_GetHeader(HWND hwnd
)
2681 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2683 return infoPtr
->hwndHeader
;
2686 /* << LISTVIEW_GetHotCursor >> */
2687 /* << LISTVIEW_GetHotItem >> */
2688 /* << LISTVIEW_GetHoverTime >> */
2692 * Retrieves an image list handle.
2695 * [I] HWND : window handle
2696 * [I] INT : image list identifier
2699 * SUCCESS : image list handle
2702 static LRESULT
LISTVIEW_GetImageList(HWND hwnd
, INT nImageList
)
2704 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2705 HIMAGELIST himl
= NULL
;
2710 himl
= infoPtr
->himlNormal
;
2713 himl
= infoPtr
->himlSmall
;
2716 himl
= infoPtr
->himlState
;
2720 return (LRESULT
)himl
;
2723 /* << LISTVIEW_GetISearchString >> */
2727 * Retrieves item attributes.
2730 * [I] HWND : window handle
2731 * [IO] LPLVITEMA : item info
2737 static LRESULT
LISTVIEW_GetItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
2739 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2740 LISTVIEW_ITEM
*lpItem
;
2741 LISTVIEW_SUBITEM
*lpSubItem
;
2743 BOOL bResult
= FALSE
;
2745 if (lpLVItem
!= NULL
)
2747 if ((lpLVItem
->iItem
>= 0) && (lpLVItem
->iItem
< GETITEMCOUNT(infoPtr
)))
2749 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2750 if (hdpaSubItems
!= NULL
)
2752 if (lpLVItem
->iSubItem
== 0)
2754 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2759 /* retrieve valid data */
2760 if (lpLVItem
->mask
& LVIF_STATE
)
2762 lpLVItem
->state
= lpItem
->state
& lpLVItem
->stateMask
;
2765 if (lpLVItem
->mask
& LVIF_TEXT
)
2767 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2769 lpLVItem
->pszText
= LPSTR_TEXTCALLBACKA
;
2773 bResult
= Str_GetPtrA(lpItem
->pszText
, lpLVItem
->pszText
,
2774 lpLVItem
->cchTextMax
);
2778 if (lpLVItem
->mask
& LVIF_IMAGE
)
2780 lpLVItem
->iImage
= lpItem
->iImage
;
2783 if (lpLVItem
->mask
& LVIF_PARAM
)
2785 lpLVItem
->lParam
= lpItem
->lParam
;
2788 if (lpLVItem
->mask
& LVIF_INDENT
)
2790 lpLVItem
->iIndent
= lpItem
->iIndent
;
2796 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
,
2797 lpLVItem
->iSubItem
);
2798 if (lpSubItem
!= NULL
)
2802 if (lpLVItem
->mask
& LVIF_TEXT
)
2804 if (lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2806 lpLVItem
->pszText
= LPSTR_TEXTCALLBACKA
;
2810 bResult
= Str_GetPtrA(lpSubItem
->pszText
, lpLVItem
->pszText
,
2811 lpLVItem
->cchTextMax
);
2815 if (lpLVItem
->mask
& LVIF_IMAGE
)
2817 lpLVItem
->iImage
= lpSubItem
->iImage
;
2828 /* << LISTVIEW_GetItemW >> */
2829 /* << LISTVIEW_GetHotCursor >> */
2830 /* << LISTVIEW_GetHotItem >> */
2831 /* << LISTVIEW_GetHoverTime >> */
2835 * Retrieves the number of items in the listview control.
2838 * [I] HWND : window handle
2843 static LRESULT
LISTVIEW_GetItemCount(HWND hwnd
)
2845 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2847 return GETITEMCOUNT(infoPtr
);
2852 * Retrieves the position (upper-left) of the listview control item.
2855 * [I] HWND : window handle
2856 * [I] INT : item index
2857 * [O] LPPOINT : coordinate information
2863 static LRESULT
LISTVIEW_GetItemPosition(HWND hwnd
, INT nItem
,
2866 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2867 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2870 BOOL bResult
= FALSE
;
2874 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) && (lppt
!= NULL
))
2876 switch (LVS_TYPEMASK
& lStyle
)
2879 nFirst
= ListView_GetTopIndex(hwnd
);
2880 nLast
= infoPtr
->nCountPerColumn
* infoPtr
->nCountPerRow
+ nFirst
- 1;
2882 if ((nItem
>= nFirst
) || (nItem
<= nLast
))
2887 nColumn
= nItem
/ infoPtr
->nCountPerColumn
;
2890 nRow
= nItem
% infoPtr
->nCountPerColumn
;
2892 /* X coordinate of the column */
2893 lppt
->x
= nColumn
* infoPtr
->nColumnWidth
+ infoPtr
->rcList
.left
;
2895 /* Y coordinate of the item */
2896 lppt
->y
= nRow
* infoPtr
->nItemHeight
+ infoPtr
->rcList
.top
;
2903 nFirst
= ListView_GetTopIndex(hwnd
);
2904 nLast
= infoPtr
->nCountPerColumn
* infoPtr
->nCountPerRow
+ nFirst
- 1;
2907 nColumn
= nItem
/ infoPtr
->nCountPerColumn
;
2910 nRow
= nItem
% infoPtr
->nCountPerColumn
;
2912 if ((nItem
>= nFirst
) || (nItem
<= nLast
))
2917 nColumn
= nItem
/ infoPtr
->nCountPerColumn
;
2920 nRow
= nItem
% infoPtr
->nCountPerColumn
;
2922 /* X coordinate of the column */
2923 lppt
->x
= infoPtr
->rcList
.left
;
2925 /* Y coordinate of the item */
2926 lppt
->y
= nRow
* infoPtr
->nItemHeight
+ infoPtr
->rcList
.top
;
2941 * Retrieves the bounding rectangle for a listview control item.
2944 * [I] HWND : window handle
2945 * [I] INT : item index
2946 * [IO] LPRECT : bounding rectangle coordinates
2952 static LRESULT
LISTVIEW_GetItemRect(HWND hwnd
, INT nItem
, LPRECT lprc
)
2954 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2955 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2956 LISTVIEW_ITEM
*lpItem
;
2958 INT nLabelWidth
= 0;
2959 INT nStateWidth
= 0;
2961 BOOL bResult
= FALSE
;
2962 CHAR szDispText
[DISP_TEXT_SIZE
];
2967 pszDispText
= szDispText
;
2969 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) && (lprc
!= NULL
))
2971 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
2972 if (hdpaSubItems
!= NULL
)
2974 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
2977 if ((LVS_TYPEMASK
& lStyle
) == LVS_ICON
)
2983 if (ListView_GetItemPosition(hwnd
, nItem
, &pt
) == TRUE
)
2985 /* get width of label in pixels */
2986 LISTVIEW_GetItemDispInfo(hwnd
, nItem
, lpItem
, NULL
, NULL
,
2987 &pszDispText
, DISP_TEXT_SIZE
);
2988 nLabelWidth
= ListView_GetStringWidthA(hwnd
, pszDispText
);
2991 if (infoPtr
->himlState
!= NULL
)
2993 nStateWidth
= infoPtr
->iconSize
.cx
;
2996 if (infoPtr
->himlSmall
== NULL
)
2998 nIconWidth
= infoPtr
->iconSize
.cx
;
3006 lprc
->right
= lprc
->left
+ nStateWidth
+ nIconWidth
+ nLabelWidth
;
3007 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
3011 lprc
->left
= pt
.x
+ nStateWidth
;
3013 lprc
->right
= lprc
->left
+ nIconWidth
;
3014 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
3018 lprc
->left
= pt
.x
+ nIconWidth
+ nStateWidth
;
3020 lprc
->right
= lprc
->left
+ nLabelWidth
;
3021 lprc
->bottom
= infoPtr
->nItemHeight
;
3024 case LVIR_SELECTBOUNDS
:
3025 lprc
->left
= pt
.x
+ nStateWidth
;
3027 lprc
->right
= lprc
->left
+ nIconWidth
+ nLabelWidth
;
3028 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
3041 * Retrieves the spacing between listview control items.
3044 * [I] HWND : window handle
3045 * [I] BOOL : flag for small or large icon
3048 * Horizontal + vertical spacing
3050 static LRESULT
LISTVIEW_GetItemSpacing(HWND hwnd
, BOOL bSmall
)
3052 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3057 lResult
= MAKELONG(infoPtr
->largeIconSpacing
.cx
,
3058 infoPtr
->largeIconSpacing
.cy
);
3062 lResult
= MAKELONG(infoPtr
->smallIconSpacing
.cx
,
3063 infoPtr
->smallIconSpacing
.cy
);
3071 * Retrieves the state of a listview control item.
3074 * [I] HWND : window handle
3075 * [I] INT : item index
3076 * [I] UINT : state mask
3079 * State specified by the mask.
3081 static LRESULT
LISTVIEW_GetItemState(HWND hwnd
, INT nItem
, UINT uMask
)
3083 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3087 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
3089 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
3090 lvItem
.iItem
= nItem
;
3091 lvItem
.stateMask
= uMask
;
3092 lvItem
.mask
= LVIF_STATE
;
3093 if (ListView_GetItemA(hwnd
, &lvItem
) == TRUE
)
3095 uState
= lvItem
.state
;
3104 * Retrieves the text of a listview control item or subitem.
3107 * [I] HWND : window handle
3108 * [I] INT : item index
3109 * [IO] LPLVITEMA : item information
3114 static LRESULT
LISTVIEW_GetItemTextA(HWND hwnd
, INT nItem
,
3117 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3118 LISTVIEW_ITEM
*lpItem
;
3119 LISTVIEW_SUBITEM
*lpSubItem
;
3123 if (lpLVItem
!= NULL
)
3125 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
3127 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
3128 if (hdpaSubItems
!= NULL
)
3130 if (lpLVItem
->iSubItem
== 0)
3132 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
3135 if (lpLVItem
->mask
& LVIF_TEXT
)
3137 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
3139 lpLVItem
->pszText
= LPSTR_TEXTCALLBACKA
;
3143 nLength
= Str_GetPtrA(lpItem
->pszText
, lpLVItem
->pszText
,
3144 lpLVItem
->cchTextMax
);
3151 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
,
3152 lpLVItem
->iSubItem
);
3153 if (lpSubItem
!= NULL
)
3155 if (lpLVItem
->mask
& LVIF_TEXT
)
3157 if (lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
)
3159 lpLVItem
->pszText
= LPSTR_TEXTCALLBACKA
;
3163 nLength
= Str_GetPtrA(lpSubItem
->pszText
, lpLVItem
->pszText
,
3164 lpLVItem
->cchTextMax
);
3178 * Searches for an item based on properties + relationships.
3181 * [I] HWND : window handle
3182 * [I] INT : item index
3183 * [I] UINT : relationship flag
3186 * SUCCESS : item index
3189 static LRESULT
LISTVIEW_GetNextItem(HWND hwnd
, INT nItem
, UINT uFlags
)
3191 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3196 /* start at begin */
3201 /* exclude specified item */
3205 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
3213 /* << LISTVIEW_GetNumberOfWorkAreas >> */
3217 * Retrieves the current origin when in icon or small icon display mode.
3220 * [I] HWND : window handle
3221 * [O] LPPOINT : coordinate information
3227 static LRESULT
LISTVIEW_GetOrigin(HWND hwnd
, LPPOINT lpOrigin
)
3229 LONG lStyle
= GetWindowLongA(hwnd
, GWL_ID
);
3230 BOOL bResult
= FALSE
;
3232 if ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)
3238 else if ((lStyle
& LVS_TYPEMASK
) == LVS_ICON
)
3250 * Retrieves the number of items that are marked as selected.
3253 * [I] HWND : window handle
3256 * Number of items selected.
3258 static LRESULT
LISTVIEW_GetSelectedCount(HWND hwnd
)
3260 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3261 INT nSelectedCount
= 0;
3264 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
3266 if (ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
) & LVIS_SELECTED
)
3272 return nSelectedCount
;
3277 * Retrieves item index that marks the start of a multiple selection.
3280 * [I] HWND : window handle
3283 * Index number or -1 if there is no selection mark.
3285 static LRESULT
LISTVIEW_GetSelectionMark(HWND hwnd
)
3287 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3289 return infoPtr
->nSelectionMark
;
3294 * Retrieves the width of a string.
3297 * [I] HWND : window handle
3300 * SUCCESS : string width (in pixels)
3303 static LRESULT
LISTVIEW_GetStringWidthA(HWND hwnd
, LPCSTR lpsz
)
3305 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3306 HFONT hFont
, hOldFont
;
3311 ZeroMemory(&textSize
, sizeof(SIZE
));
3314 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
;
3316 hOldFont
= SelectObject(hdc
, hFont
);
3317 GetTextExtentPointA(hdc
, lpsz
, lstrlenA(lpsz
), &textSize
);
3318 SelectObject(hdc
, hOldFont
);
3319 ReleaseDC(hwnd
, hdc
);
3327 * Retrieves the text backgound color.
3330 * [I] HWND : window handle
3333 * COLORREF associated with the the background.
3335 static LRESULT
LISTVIEW_GetTextBkColor(HWND hwnd
)
3337 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3339 return infoPtr
->clrTextBk
;
3344 * Retrieves the text color.
3347 * [I] HWND : window handle
3350 * COLORREF associated with the text.
3352 static LRESULT
LISTVIEW_GetTextColor(HWND hwnd
)
3354 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3356 return infoPtr
->clrText
;
3361 * Retrieves the bounding rectangle of all the items.
3364 * [I] HWND : window handle
3365 * [O] LPRECT : bounding rectangle
3371 static LRESULT
LISTVIEW_GetViewRect(HWND hwnd
, LPRECT lprc
)
3373 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3374 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3375 BOOL bResult
= FALSE
;
3379 if (((lStyle
& LVS_TYPEMASK
) == LVS_ICON
) ||
3380 ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
))
3391 * Determines which section of the item was selected (if any).
3394 * [I] HWND : window handle
3395 * [I] INT : item index
3396 * [IO] LPLVHITTESTINFO : hit test information
3399 * SUCCESS : item index
3402 static INT
LISTVIEW_HitTestItem(HWND hwnd
, INT nItem
,
3403 LPLVHITTESTINFO lpHitTestInfo
)
3405 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3406 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3408 LISTVIEW_ITEM
*lpItem
;
3412 CHAR szDispText
[DISP_TEXT_SIZE
];
3416 pszDispText
= szDispText
;
3418 if ((LVS_TYPEMASK
& lStyle
) == LVS_LIST
)
3420 /* calculate offset from start of item (in pixels) */
3421 nOffset
= lpHitTestInfo
->pt
.x
% infoPtr
->nColumnWidth
;
3425 nOffset
= lpHitTestInfo
->pt
.x
;
3428 /* verify existance of item */
3429 if (nItem
< GETITEMCOUNT(infoPtr
))
3432 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
3433 if (hdpaSubItems
!= NULL
)
3435 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
3438 if (infoPtr
->himlState
!= NULL
)
3440 nPosX
+= infoPtr
->iconSize
.cx
;
3441 if (nOffset
<= nPosX
)
3443 lpHitTestInfo
->flags
= LVHT_ONITEMSTATEICON
| LVHT_ONITEM
;
3444 lpHitTestInfo
->iItem
= nItem
;
3445 lpHitTestInfo
->iSubItem
= 0;
3450 if (infoPtr
->himlSmall
!= NULL
)
3452 nPosX
+= infoPtr
->iconSize
.cx
;
3453 if (nOffset
<= nPosX
)
3455 lpHitTestInfo
->flags
= LVHT_ONITEMICON
| LVHT_ONITEM
;
3456 lpHitTestInfo
->iItem
= nItem
;
3457 lpHitTestInfo
->iSubItem
= 0;
3462 /* get width of label in pixels */
3463 LISTVIEW_GetItemDispInfo(hwnd
, nItem
, lpItem
, NULL
, NULL
,
3464 &pszDispText
, DISP_TEXT_SIZE
);
3465 nLabelWidth
= ListView_GetStringWidthA(hwnd
, pszDispText
);
3466 nLabelWidth
+= nPosX
;
3468 if (nOffset
<= nLabelWidth
)
3470 lpHitTestInfo
->flags
= LVHT_ONITEMLABEL
| LVHT_ONITEM
;
3471 lpHitTestInfo
->iItem
= nItem
;
3472 lpHitTestInfo
->iSubItem
= 0;
3479 /* hit is not on item */
3480 lpHitTestInfo
->flags
= LVHT_NOWHERE
;
3487 * Determines wich listview item is located at the specified position.
3490 * [I] HWND : window handle
3491 * [IO} LPLVHITTESTINFO : hit test information
3494 * SUCCESS : item index
3497 static LRESULT
LISTVIEW_HitTest(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
3499 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3500 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3506 lpHitTestInfo
->flags
= 0;
3507 if (infoPtr
->rcList
.left
> lpHitTestInfo
->pt
.x
)
3509 lpHitTestInfo
->flags
= LVHT_TOLEFT
;
3511 else if (infoPtr
->rcList
.right
< lpHitTestInfo
->pt
.x
)
3513 lpHitTestInfo
->flags
= LVHT_TORIGHT
;
3516 if (infoPtr
->rcList
.top
> lpHitTestInfo
->pt
.y
)
3518 lpHitTestInfo
->flags
|= LVHT_ABOVE
;
3520 else if (infoPtr
->rcList
.bottom
< lpHitTestInfo
->pt
.y
)
3522 lpHitTestInfo
->flags
|= LVHT_BELOW
;
3525 if (lpHitTestInfo
->flags
== 0)
3527 switch (LVS_TYPEMASK
& lStyle
)
3530 /* get current column */
3531 nColumn
= lpHitTestInfo
->pt
.x
/ infoPtr
->nColumnWidth
;
3533 /* get current row */
3534 nRow
= lpHitTestInfo
->pt
.y
/ infoPtr
->nItemHeight
;
3536 /* get the index of the first visible item */
3537 nTopIndex
= ListView_GetTopIndex(hwnd
);
3539 nItem
= nColumn
* infoPtr
->nCountPerColumn
+ nTopIndex
+ nRow
;
3540 nItem
= LISTVIEW_HitTestItem(hwnd
, nItem
, lpHitTestInfo
);
3544 /* get current row */
3545 nRow
= ((lpHitTestInfo
->pt
.y
- infoPtr
->rcList
.top
) /
3546 infoPtr
->nItemHeight
);
3548 /* get the index of the first visible item */
3549 nTopIndex
= ListView_GetTopIndex(hwnd
);
3551 nItem
= nTopIndex
+ nRow
;
3552 nItem
= LISTVIEW_HitTestItem(hwnd
, nItem
, lpHitTestInfo
);
3556 /* nItem = LISTVIEW_HitTestItem(hwnd, nItem, lpHitTestInfo); */
3565 * Inserts a new column.
3568 * [I] HWND : window handle
3569 * [I] INT : column index
3570 * [I] LPLVCOLUMNA : column information
3573 * SUCCESS : new column index
3576 static LRESULT
LISTVIEW_InsertColumnA(HWND hwnd
, INT nColumn
,
3577 LPLVCOLUMNA lpColumn
)
3579 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3581 INT nNewColumn
= -1;
3583 if (lpColumn
!= NULL
)
3585 /* initialize memory */
3586 ZeroMemory(&hdi
, sizeof(HDITEMA
));
3588 if (lpColumn
->mask
& LVCF_FMT
)
3590 /* format member is valid */
3591 hdi
.mask
|= HDI_FORMAT
;
3593 /* set text alignment (leftmost column must be left-aligned) */
3596 hdi
.fmt
|= HDF_LEFT
;
3600 if (lpColumn
->fmt
& LVCFMT_LEFT
)
3602 hdi
.fmt
|= HDF_LEFT
;
3604 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
3606 hdi
.fmt
|= HDF_RIGHT
;
3608 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
3610 hdi
.fmt
|= HDF_CENTER
;
3614 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
3616 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
3620 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
3625 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
3627 hdi
.fmt
|= HDF_IMAGE
;
3628 hdi
.iImage
= I_IMAGECALLBACK
;
3632 if (lpColumn
->mask
& LVCF_WIDTH
)
3634 hdi
.mask
|= HDI_WIDTH
;
3635 hdi
.cxy
= lpColumn
->cx
;
3638 if (lpColumn
->mask
& LVCF_TEXT
)
3640 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
3641 hdi
.pszText
= lpColumn
->pszText
;
3642 hdi
.cchTextMax
= lstrlenA(lpColumn
->pszText
);
3643 hdi
.fmt
|= HDF_STRING
;
3646 if (lpColumn
->mask
& LVCF_IMAGE
)
3648 hdi
.mask
|= HDI_IMAGE
;
3649 hdi
.iImage
= lpColumn
->iImage
;
3652 if (lpColumn
->mask
& LVCF_ORDER
)
3654 hdi
.mask
|= HDI_ORDER
;
3655 hdi
.iOrder
= lpColumn
->iOrder
;
3658 /* insert item in header control */
3659 nNewColumn
= SendMessageA(infoPtr
->hwndHeader
, HDM_INSERTITEMA
,
3660 (WPARAM
)nColumn
, (LPARAM
)&hdi
);
3662 LISTVIEW_SetScroll(hwnd
);
3663 InvalidateRect(hwnd
, NULL
, FALSE
);
3669 /* << LISTVIEW_InsertColumnW >> */
3673 * Inserts a new item in the listview control.
3676 * [I] HWND : window handle
3677 * [I] LPLVITEMA : item information
3680 * SUCCESS : new item index
3683 static LRESULT
LISTVIEW_InsertItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
3685 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3686 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3690 LISTVIEW_ITEM
*lpItem
= NULL
;
3692 if (lpLVItem
!= NULL
)
3694 /* make sure it's not a subitem; cannot insert a subitem */
3695 if (lpLVItem
->iSubItem
== 0)
3697 lpItem
= (LISTVIEW_ITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM
));
3700 ZeroMemory(lpItem
, sizeof(LISTVIEW_ITEM
));
3701 if (LISTVIEW_InitItem(hwnd
, lpItem
, lpLVItem
) == TRUE
)
3703 /* insert item in listview control data structure */
3704 hdpaSubItems
= DPA_Create(8);
3705 if (hdpaSubItems
!= NULL
)
3707 nItem
= DPA_InsertPtr(hdpaSubItems
, 0, lpItem
);
3710 nItem
= DPA_InsertPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
,
3714 /* manage item focus */
3715 if (lpLVItem
->mask
& LVIF_STATE
)
3717 if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
3719 LISTVIEW_SetItemFocus(hwnd
, nItem
);
3723 /* send LVN_INSERTITEM notification */
3724 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
3725 nmlv
.hdr
.hwndFrom
= hwnd
;
3726 nmlv
.hdr
.idFrom
= lCtrlId
;
3727 nmlv
.hdr
.code
= LVN_INSERTITEM
;
3729 nmlv
.lParam
= lpItem
->lParam
;;
3730 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
3732 /* set scrolling parameters */
3733 LISTVIEW_SetScroll(hwnd
);
3735 /* refresh client area */
3736 InvalidateRect(hwnd
, NULL
, FALSE
);
3745 /* free memory if unsuccessful */
3746 if ((nItem
== -1) && (lpItem
!= NULL
))
3748 COMCTL32_Free(lpItem
);
3754 /* << LISTVIEW_InsertItemW >> */
3758 * Redraws a range of items.
3761 * [I] HWND : window handle
3762 * [I] INT : first item
3763 * [I] INT : last item
3769 static LRESULT
LISTVIEW_RedrawItems(HWND hwnd
, INT nFirst
, INT nLast
)
3771 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3772 BOOL bResult
= FALSE
;
3775 if (nFirst
<= nLast
)
3777 if ((nFirst
>= 0) && (nFirst
< GETITEMCOUNT(infoPtr
)))
3779 if ((nLast
>= 0) && (nLast
< GETITEMCOUNT(infoPtr
)))
3782 InvalidateRect(hwnd
, &rc
, FALSE
);
3792 * Scrolls the content of a listview.
3795 * [I] HWND : window handle
3796 * [I] INT : amount of horizontal scrolling
3797 * [I] INT : amount of vertical scrolling
3803 static LRESULT
LISTVIEW_Scroll(HWND hwnd
, INT nHScroll
, INT nVScroll
)
3805 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3807 BOOL bResult
= FALSE
;
3811 if (lStyle
& WS_HSCROLL
)
3813 nScrollPos
= GetScrollPos(hwnd
, SB_HORZ
);
3814 GetScrollRange(hwnd
, SB_HORZ
, &nMinRange
, &nMaxRange
);
3815 nScrollPos
+= nHScroll
;
3817 if ((LVS_TYPEMASK
& lStyle
) == LVS_LIST
)
3819 nScrollPos
= GetScrollPos(hwnd
, SB_HORZ
);
3820 GetScrollRange(hwnd
, SB_HORZ
, &nMinRange
, &nMaxRange
);
3821 nScrollPos
+= nHScroll
;
3822 if ((nMinRange
<= nScrollPos
) && (nScrollPos
<= nMaxRange
))
3825 SetScrollPos(hwnd
, SB_HORZ
, nScrollPos
, TRUE
);
3834 if (lStyle
& WS_VSCROLL
)
3836 if ((LVS_TYPEMASK
& lStyle
) == LVS_REPORT
)
3838 nScrollPos
= GetScrollPos(hwnd
, SB_VERT
);
3839 GetScrollRange(hwnd
, SB_VERT
, &nMinRange
, &nMaxRange
);
3840 nScrollPos
+= nVScroll
;
3841 if ((nMinRange
<= nScrollPos
) && (nScrollPos
<= nMaxRange
))
3844 SetScrollPos(hwnd
, SB_VERT
, nScrollPos
, TRUE
);
3853 if (bResult
== TRUE
)
3855 /* refresh client area */
3856 InvalidateRect(hwnd
, NULL
, TRUE
);
3864 * Sets the background color.
3867 * [I] HWND : window handle
3868 * [I] COLORREF : background color
3874 static LRESULT
LISTVIEW_SetBkColor(HWND hwnd
, COLORREF clrBk
)
3876 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3878 infoPtr
->clrBk
= clrBk
;
3879 InvalidateRect(hwnd
, NULL
, TRUE
);
3886 * Sets the callback mask. This mask will be used when the parent
3887 * window stores the state information (some or all).
3890 * [I] HWND : window handle
3891 * [I] UINT : state mask
3897 static BOOL
LISTVIEW_SetCallbackMask(HWND hwnd
, UINT uMask
)
3899 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3901 infoPtr
->uCallbackMask
= uMask
;
3908 * Sets column attributes.
3911 * [I] HWND : window handle
3912 * [I] INT : column index
3913 * [I] LPLVCOLUMNA : column attributes
3919 static LRESULT
LISTVIEW_SetColumnA(HWND hwnd
, INT nColumn
,
3920 LPLVCOLUMNA lpColumn
)
3922 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3924 BOOL bResult
= FALSE
;
3926 if ((lpColumn
!= NULL
) && (nColumn
>= 0) &&
3927 (nColumn
< Header_GetItemCount(infoPtr
->hwndHeader
)))
3929 /* initialize memory */
3930 ZeroMemory(&hdi
, sizeof(HDITEMA
));
3932 if (lpColumn
->mask
& LVCF_FMT
)
3934 /* format member is valid */
3935 hdi
.mask
|= HDI_FORMAT
;
3937 /* set text alignment (leftmost column must be left-aligned) */
3940 hdi
.fmt
|= HDF_LEFT
;
3944 if (lpColumn
->fmt
& LVCFMT_LEFT
)
3946 hdi
.fmt
|= HDF_LEFT
;
3948 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
3950 hdi
.fmt
|= HDF_RIGHT
;
3952 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
3954 hdi
.fmt
|= HDF_CENTER
;
3958 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
3960 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
3963 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
3965 hdi
.fmt
|= HDF_IMAGE
;
3968 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
3970 hdi
.fmt
|= HDF_IMAGE
;
3971 hdi
.iImage
= I_IMAGECALLBACK
;
3975 if (lpColumn
->mask
& LVCF_WIDTH
)
3977 hdi
.mask
|= HDI_WIDTH
;
3978 hdi
.cxy
= lpColumn
->cx
;
3981 if (lpColumn
->mask
& LVCF_TEXT
)
3983 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
3984 hdi
.pszText
= lpColumn
->pszText
;
3985 hdi
.cchTextMax
= lstrlenA(lpColumn
->pszText
);
3986 hdi
.fmt
|= HDF_STRING
;
3989 if (lpColumn
->mask
& LVCF_IMAGE
)
3991 hdi
.mask
|= HDI_IMAGE
;
3992 hdi
.iImage
= lpColumn
->iImage
;
3995 if (lpColumn
->mask
& LVCF_ORDER
)
3997 hdi
.mask
|= HDI_ORDER
;
3998 hdi
.iOrder
= lpColumn
->iOrder
;
4001 /* set header item attributes */
4002 bResult
= Header_SetItemA(infoPtr
->hwndHeader
, nColumn
, &hdi
);
4013 * [I] HWND : window handle
4014 * [I] INT : image list type
4015 * [I] HIMAGELIST : image list handle
4018 * SUCCESS : old image list
4021 static LRESULT
LISTVIEW_SetImageList(HWND hwnd
, INT nType
, HIMAGELIST himl
)
4023 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4024 HIMAGELIST himlTemp
= 0;
4029 himlTemp
= infoPtr
->himlNormal
;
4030 infoPtr
->himlNormal
= himl
;
4031 return (LRESULT
)himlTemp
;
4034 himlTemp
= infoPtr
->himlSmall
;
4035 infoPtr
->himlSmall
= himl
;
4036 return (LRESULT
)himlTemp
;
4039 himlTemp
= infoPtr
->himlState
;
4040 infoPtr
->himlState
= himl
;
4041 return (LRESULT
)himlTemp
;
4044 return (LRESULT
)NULL
;
4050 * Sets item attributes.
4053 * [I] HWND : window handle
4054 * [I] LPLVITEM : item information
4060 static LRESULT
LISTVIEW_SetItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
4062 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4063 BOOL bResult
= FALSE
;
4065 if (lpLVItem
!= NULL
)
4067 if ((lpLVItem
->iItem
>= 0) && (lpLVItem
->iItem
< GETITEMCOUNT(infoPtr
)))
4069 if (lpLVItem
->iSubItem
== 0)
4071 bResult
= LISTVIEW_SetItem(hwnd
, lpLVItem
);
4075 bResult
= LISTVIEW_SetSubItem(hwnd
, lpLVItem
);
4084 /* << LISTVIEW_SetItemW >> */
4088 * Preallocates memory.
4091 * [I] HWND : window handle
4092 * [I] INT : item count (prjected number of items)
4097 static VOID
LISTVIEW_SetItemCount(HWND hwnd
, INT nItemCount
)
4104 * Sets item position.
4107 * [I] HWND : window handle
4108 * [I] INT : item index
4109 * [I] INT : x coordinate
4110 * [I] INT : y coordinate
4116 static LRESULT
LISTVIEW_SetItemPosition(HWND hwnd
, INT nItem
,
4117 INT nPosX
, INT nPosY
)
4119 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4120 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4121 BOOL bResult
= FALSE
;
4123 if ((nItem
>= 0) || (nItem
< GETITEMCOUNT(infoPtr
)))
4125 if (((lStyle
& LVS_TYPEMASK
) == LVS_ICON
) ||
4126 ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
))
4137 * Sets the state of one or many items.
4140 * [I] HWND : window handle
4141 * [I]INT : item index
4142 * [I] LPLVITEM : item or subitem info
4148 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
,
4151 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4152 BOOL bResult
= FALSE
;
4159 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
4160 lvItem
.mask
= LVIF_STATE
;
4161 lvItem
.state
= lpLVItem
->state
;
4162 lvItem
.stateMask
= lpLVItem
->stateMask
;
4164 /* apply to all items */
4165 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
4168 if (ListView_SetItemA(hwnd
, &lvItem
) == FALSE
)
4176 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
4177 lvItem
.mask
= LVIF_STATE
;
4178 lvItem
.state
= lpLVItem
->state
;
4179 lvItem
.stateMask
= lpLVItem
->stateMask
;
4180 lvItem
.iItem
= nItem
;
4181 bResult
= ListView_SetItemA(hwnd
, &lvItem
);
4189 * Sets the text of an item or subitem.
4192 * [I] HWND : window handle
4193 * [I] INT : item index
4194 * [I] LPLVITEMA : item or subitem info
4200 static BOOL
LISTVIEW_SetItemTextA(HWND hwnd
, INT nItem
,
4203 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4204 BOOL bResult
= FALSE
;
4207 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4209 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
4210 lvItem
.mask
= LVIF_TEXT
;
4211 lvItem
.pszText
= lpLVItem
->pszText
;
4212 lvItem
.iItem
= nItem
;
4213 lvItem
.iSubItem
= lpLVItem
->iSubItem
;
4214 bResult
= ListView_SetItemA(hwnd
, &lvItem
);
4222 * Sets the text background color.
4225 * [I] HWND : window handle
4226 * [I] COLORREF : text background color
4232 static LRESULT
LISTVIEW_SetTextBkColor(HWND hwnd
, COLORREF clrTextBk
)
4234 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4236 infoPtr
->clrTextBk
= clrTextBk
;
4243 * Sets the text background color.
4246 * [I] HWND : window handle
4247 * [I] COLORREF : text color
4253 static LRESULT
LISTVIEW_SetTextColor (HWND hwnd
, COLORREF clrText
)
4255 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4257 infoPtr
->clrText
= clrText
;
4267 * [I] HWND : window handle
4273 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
4275 FIXME (listview
, "empty stub!\n");
4282 * Updates an items or rearranges the listview control.
4285 * [I] HWND : window handle
4286 * [I] INT : item index
4292 static LRESULT
LISTVIEW_Update(HWND hwnd
, INT nItem
)
4294 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4295 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4296 BOOL bResult
= FALSE
;
4299 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4303 /* rearrange with default alignment style */
4304 if ((lStyle
& LVS_AUTOARRANGE
) && (((lStyle
& LVS_TYPEMASK
) == LVS_ICON
) ||
4305 ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)))
4307 ListView_Arrange(hwnd
, 0);
4311 /* get item bounding rectangle */
4312 rc
.left
= LVIR_BOUNDS
;
4313 ListView_GetItemRect(hwnd
, nItem
, &rc
);
4314 InvalidateRect(hwnd
, &rc
, FALSE
);
4323 * Creates a listview control.
4326 * [I] HWND : window handle
4331 static LRESULT
LISTVIEW_Create(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
4333 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4334 LPCREATESTRUCTA lpcs
= (LPCREATESTRUCTA
)lParam
;
4339 /* determine the type of structures to use */
4340 infoPtr
->notifyFormat
= SendMessageA(GetParent(hwnd
), WM_NOTIFYFORMAT
,
4341 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
4342 if (infoPtr
->notifyFormat
!= NFR_ANSI
)
4344 FIXME (listview
, "ANSI notify format is NOT used\n");
4347 /* initialize color information */
4348 infoPtr
->clrBk
= GetSysColor(COLOR_WINDOW
);
4349 infoPtr
->clrText
= GetSysColor(COLOR_WINDOWTEXT
);
4350 infoPtr
->clrTextBk
= GetSysColor(COLOR_WINDOW
);
4352 /* set default values */
4353 infoPtr
->uCallbackMask
= 0;
4354 infoPtr
->nFocusedItem
= -1;
4355 infoPtr
->nSelectionMark
= -1;
4356 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
4357 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
4358 ZeroMemory(&infoPtr
->rcList
, sizeof(RECT
));
4360 /* get default font (icon title) */
4361 SystemParametersInfoA(SPI_GETICONTITLELOGFONT
, 0, &logFont
, 0);
4362 infoPtr
->hDefaultFont
= CreateFontIndirectA(&logFont
);
4363 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
4366 infoPtr
->hwndHeader
= CreateWindowA(WC_HEADERA
, (LPCSTR
)NULL
,
4367 WS_CHILD
| HDS_HORZ
| HDS_BUTTONS
,
4368 0, 0, 0, 0, hwnd
, (HMENU
)0,
4369 lpcs
->hInstance
, NULL
);
4371 /* set header font */
4372 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)infoPtr
->hFont
,
4375 switch (lpcs
->style
& LVS_TYPEMASK
)
4379 hl
.prc
= &infoPtr
->rcList
;
4381 Header_Layout(infoPtr
->hwndHeader
, &hl
);
4382 SetWindowPos(infoPtr
->hwndHeader
, hwnd
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
,
4385 /* set new top coord */
4386 infoPtr
->rcList
.top
= wp
.cy
;
4388 /* display header */
4389 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
4396 /* temporary (until there is support) */
4397 SetWindowLongA(hwnd
, GWL_STYLE
,
4398 (lpcs
->style
& ~LVS_TYPEMASK
) | LVS_LIST
);
4402 LISTVIEW_UnsupportedStyles(lpcs
->style
);
4404 /* allocate memory */
4405 infoPtr
->hdpaItems
= DPA_Create(10);
4407 /* set view dependent information */
4408 LISTVIEW_SetViewInfo(hwnd
);
4416 * Destroys the window
4419 * [I] HWND : window handle
4424 static LRESULT
LISTVIEW_Destroy(HWND hwnd
)
4426 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4428 /* delete all items */
4429 LISTVIEW_DeleteAllItems(hwnd
);
4432 DPA_Destroy(infoPtr
->hdpaItems
);
4434 /* destroy header */
4435 if (infoPtr
->hwndHeader
)
4437 DestroyWindow(infoPtr
->hwndHeader
);
4441 infoPtr
->hFont
= (HFONT
)0;
4442 if (infoPtr
->hDefaultFont
)
4444 DeleteObject(infoPtr
->hDefaultFont
);
4452 * Erases the background of the listview control
4455 * [I] HWND : window handle
4456 * [I] WPARAM : device context handle
4457 * [I] LPARAM : not used
4463 static LRESULT
LISTVIEW_EraseBackground(HWND hwnd
, WPARAM wParam
,
4466 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4469 if (infoPtr
->clrBk
== CLR_NONE
)
4471 bResult
= SendMessageA(GetParent(hwnd
), WM_ERASEBKGND
, wParam
, lParam
);
4475 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
4476 FillRect((HDC
)wParam
, &infoPtr
->rcList
, hBrush
);
4477 DeleteObject(hBrush
);
4486 * Gets the listview control font.
4489 * [I] HWND : window handle
4494 static LRESULT
LISTVIEW_GetFont(HWND hwnd
)
4496 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4498 return infoPtr
->hFont
;
4503 * Performs horizontal scrolling.
4506 * [I] HWND : window handle
4507 * [I] INT : scroll code
4508 * [I] INT : scroll position
4509 * [I] HWND : scrollbar control window handle
4514 static LRESULT
LISTVIEW_VScroll(HWND hwnd
, INT nScrollCode
,
4515 INT nScroll
, HWND hScrollWnd
)
4517 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4518 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4519 INT nScrollPos
, nOldScrollPos
;
4523 GetScrollRange(hwnd
, SB_VERT
, &nMinRange
, &nMaxRange
);
4524 nOldScrollPos
= nScrollPos
= GetScrollPos(hwnd
, SB_VERT
);
4526 switch (LVS_TYPEMASK
& lStyle
)
4529 switch (nScrollCode
)
4532 if (nScrollPos
> nMinRange
)
4538 if (nScrollPos
< nMaxRange
)
4544 if (nScrollPos
> nMinRange
+ infoPtr
->nCountPerColumn
)
4546 nScrollPos
-= infoPtr
->nCountPerColumn
;
4550 nScrollPos
= nMinRange
;
4554 if (nScrollPos
< nMaxRange
- infoPtr
->nCountPerColumn
)
4556 nScrollPos
+= infoPtr
->nCountPerColumn
;
4560 nScrollPos
= nMaxRange
;
4563 case SB_THUMBPOSITION
:
4564 nScrollPos
= nScroll
;
4573 /* set new scroll position */
4574 if (nScrollPos
!= nOldScrollPos
)
4576 SetScrollPos(hwnd
, SB_VERT
, nScrollPos
, TRUE
);
4578 /* refresh client area */
4579 InvalidateRect(hwnd
, NULL
, TRUE
);
4588 * Performs horizontal scrolling.
4591 * [I] HWND : window handle
4592 * [I] INT : scroll code
4593 * [I] INT : scroll position
4594 * [I] HWND : scrollbar control window handle
4599 static LRESULT
LISTVIEW_HScroll(HWND hwnd
, INT nScrollCode
,
4600 INT nScroll
, HWND hScrollWnd
)
4602 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4603 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4604 INT nScrollPos
, nOldScrollPos
;
4608 GetScrollRange(hwnd
, SB_HORZ
, &nMinRange
, &nMaxRange
);
4609 nOldScrollPos
= nScrollPos
= GetScrollPos(hwnd
, SB_HORZ
);
4611 switch (LVS_TYPEMASK
& lStyle
)
4615 /* list display mode horizontal scrolling */
4616 switch (nScrollCode
)
4619 if (nScrollPos
> nMinRange
)
4625 if (nScrollPos
< nMaxRange
)
4631 if (nScrollPos
> nMinRange
)
4633 nScrollPos
= max(nMinRange
, nScrollPos
- infoPtr
->nCountPerRow
);
4637 nScrollPos
= nMinRange
;
4641 if (nScrollPos
< nMaxRange
- 1)
4643 nScrollPos
= min(nMaxRange
, nScrollPos
+ infoPtr
->nCountPerRow
);
4647 nScrollPos
= nMaxRange
;
4650 case SB_THUMBPOSITION
:
4651 nScrollPos
= nScroll
;
4658 /* report/details display mode horizontal scrolling */
4659 switch (nScrollCode
)
4662 if (nScrollPos
> nMinRange
)
4668 if (nScrollPos
< nMaxRange
)
4674 if (nScrollPos
> nMinRange
)
4676 nScrollPos
= max(nMinRange
, nScrollPos
- infoPtr
->rcList
.right
);
4680 nScrollPos
= nMinRange
;
4684 if (nScrollPos
< nMaxRange
)
4686 nScrollPos
= min(nMaxRange
, nScrollPos
+ infoPtr
->rcList
.right
);
4690 nScrollPos
= nMaxRange
;
4693 case SB_THUMBPOSITION
:
4694 nScrollPos
= nScroll
;
4703 /* set new scroll position */
4704 if (nScrollPos
!= nOldScrollPos
)
4706 SetScrollPos(hwnd
, SB_HORZ
, nScrollPos
, TRUE
);
4708 /* refresh client area */
4709 InvalidateRect(hwnd
, NULL
, TRUE
);
4720 * [I] HWND : window handle
4721 * [I] INT : virtual key
4722 * [I] LONG : key data
4727 static LRESULT
LISTVIEW_KeyDown(HWND hwnd
, INT nVirtualKey
, LONG lKeyData
)
4729 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4730 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4731 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4732 HWND hwndParent
= GetParent(hwnd
);
4733 NMLVKEYDOWN nmKeyDown
;
4736 /* send LVN_KEYDOWN notification */
4737 ZeroMemory(&nmKeyDown
, sizeof(NMLVKEYDOWN
));
4738 nmKeyDown
.hdr
.hwndFrom
= hwnd
;
4739 nmKeyDown
.hdr
.idFrom
= nCtrlId
;
4740 nmKeyDown
.hdr
.code
= LVN_KEYDOWN
;
4741 nmKeyDown
.wVKey
= nVirtualKey
;
4742 nmKeyDown
.flags
= 0;
4743 SendMessageA(hwndParent
, WM_NOTIFY
, (WPARAM
)nCtrlId
, (LPARAM
)&nmKeyDown
);
4746 nmh
.hwndFrom
= hwnd
;
4747 nmh
.idFrom
= nCtrlId
;
4749 switch (nVirtualKey
)
4752 if ((GETITEMCOUNT(infoPtr
) > 0) && (infoPtr
->nFocusedItem
!= -1))
4754 /* send NM_RETURN notification */
4755 nmh
.code
= NM_RETURN
;
4756 ListView_Notify(hwndParent
, nCtrlId
, &nmh
);
4758 /* send LVN_ITEMACTIVATE notification */
4759 nmh
.code
= LVN_ITEMACTIVATE
;
4760 ListView_Notify(hwndParent
, nCtrlId
, &nmh
);
4765 if (GETITEMCOUNT(infoPtr
) > 0)
4767 LISTVIEW_KeySelection(hwnd
, 0);
4772 if (GETITEMCOUNT(infoPtr
) > 0)
4774 LISTVIEW_KeySelection(hwnd
, GETITEMCOUNT(infoPtr
) - 1);
4779 switch (LVS_TYPEMASK
& lStyle
)
4782 if (infoPtr
->nFocusedItem
>= infoPtr
->nCountPerColumn
)
4784 LISTVIEW_KeySelection(hwnd
, infoPtr
->nFocusedItem
- infoPtr
->nCountPerColumn
);
4791 if (infoPtr
->nFocusedItem
% infoPtr
->nCountPerRow
!= 0)
4793 LISTVIEW_SetSelection(hwnd
, infoPtr
->nFocusedItem
- 1);
4799 switch (LVS_TYPEMASK
& lStyle
)
4803 if (infoPtr
->nFocusedItem
> 0)
4805 LISTVIEW_KeySelection(hwnd
, infoPtr
->nFocusedItem
- 1);
4810 if (infoPtr
->nFocusedItem
>= infoPtr
->nCountPerRow
)
4812 LISTVIEW_SetSelection(hwnd
, infoPtr
->nFocusedItem
-
4813 infoPtr
->nCountPerRow
);
4819 switch (LVS_TYPEMASK
& lStyle
)
4822 if (infoPtr
->nFocusedItem
<
4823 (GETITEMCOUNT(infoPtr
) - infoPtr
->nCountPerColumn
))
4825 LISTVIEW_KeySelection(hwnd
, infoPtr
->nFocusedItem
+
4826 infoPtr
->nCountPerColumn
);
4832 if (infoPtr
->nCountPerRow
> 0)
4839 switch (LVS_TYPEMASK
& lStyle
)
4843 if (infoPtr
->nFocusedItem
< GETITEMCOUNT(infoPtr
) - 1)
4845 LISTVIEW_KeySelection(hwnd
, infoPtr
->nFocusedItem
+ 1);
4848 if (infoPtr
->nCountPerRow
> 0)
4861 /* refresh client area */
4862 InvalidateRect(hwnd
, NULL
, TRUE
);
4872 * [I] HWND : window handle
4877 static LRESULT
LISTVIEW_KillFocus(HWND hwnd
)
4879 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4880 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4883 /* send NM_KILLFOCUS notification */
4884 nmh
.hwndFrom
= hwnd
;
4885 nmh
.idFrom
= nCtrlId
;
4886 nmh
.code
= NM_KILLFOCUS
;
4887 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
4889 /* set window focus flag */
4890 infoPtr
->bFocus
= FALSE
;
4897 * Left mouse button double click.
4900 * [I] HWND : window handle
4901 * [I] WORD : key flag
4902 * [I] WORD : x coordinate
4903 * [I] WORD : y coordinate
4908 static LRESULT
LISTVIEW_LButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
4911 LONG nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4914 /* send NM_DBLCLK notification */
4915 nmh
.hwndFrom
= hwnd
;
4916 nmh
.idFrom
= nCtrlId
;
4917 nmh
.code
= NM_DBLCLK
;
4918 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
4920 /* send LVN_ITEMACTIVATE notification */
4921 nmh
.code
= LVN_ITEMACTIVATE
;
4922 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
4929 * Left mouse button down.
4932 * [I] HWND : window handle
4933 * [I] WORD : key flag
4934 * [I] WORD : x coordinate
4935 * [I] WORD : y coordinate
4940 static LRESULT
LISTVIEW_LButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
4943 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4944 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4945 LVHITTESTINFO hitTestInfo
;
4948 static BOOL bGroupSelect
= TRUE
;
4950 /* send NM_RELEASEDCAPTURE notification */
4951 nmh
.hwndFrom
= hwnd
;
4952 nmh
.idFrom
= nCtrlId
;
4953 nmh
.code
= NM_RELEASEDCAPTURE
;
4954 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
4956 if (infoPtr
->bFocus
== FALSE
)
4961 /* set left button down flag */
4962 infoPtr
->bLButtonDown
= TRUE
;
4964 /* set left button hit coordinates */
4965 hitTestInfo
.pt
.x
= wPosX
;
4966 hitTestInfo
.pt
.y
= wPosY
;
4968 /* perform hit test */
4969 nItem
= ListView_HitTest(hwnd
, &hitTestInfo
);
4970 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4972 if ((wKey
& MK_CONTROL
) && (wKey
& MK_SHIFT
))
4974 if (bGroupSelect
== TRUE
)
4976 LISTVIEW_AddGroupSelection(hwnd
, nItem
);
4980 LISTVIEW_AddSelection(hwnd
, nItem
);
4983 else if (wKey
& MK_CONTROL
)
4985 bGroupSelect
= LISTVIEW_ToggleSelection(hwnd
, nItem
);
4987 else if (wKey
& MK_SHIFT
)
4989 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
4993 LISTVIEW_SetSelection(hwnd
, nItem
);
4998 /* remove all selections */
4999 LISTVIEW_RemoveSelections(hwnd
, 0, GETITEMCOUNT(infoPtr
));
5002 InvalidateRect(hwnd
, NULL
, TRUE
);
5009 * Left mouse button up.
5012 * [I] HWND : window handle
5013 * [I] WORD : key flag
5014 * [I] WORD : x coordinate
5015 * [I] WORD : y coordinate
5020 static LRESULT
LISTVIEW_LButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
5023 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5024 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
5027 if (infoPtr
->bLButtonDown
== TRUE
)
5029 /* send NM_CLICK notification */
5030 nmh
.hwndFrom
= hwnd
;
5031 nmh
.idFrom
= nCtrlId
;
5032 nmh
.code
= NM_CLICK
;
5033 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
5035 /* set left button flag */
5036 infoPtr
->bLButtonDown
= FALSE
;
5044 * Creates the listview control (called before WM_CREATE).
5047 * [I] HWND : window handle
5048 * [I] WPARAM : unhandled
5049 * [I] LPARAM : widow creation info
5054 static LRESULT
LISTVIEW_NCCreate(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
5056 LISTVIEW_INFO
*infoPtr
;
5058 /* allocate memory for info structure */
5059 infoPtr
= (LISTVIEW_INFO
*)COMCTL32_Alloc(sizeof(LISTVIEW_INFO
));
5060 SetWindowLongA(hwnd
, 0, (LONG
)infoPtr
);
5061 if (infoPtr
== NULL
)
5063 ERR(listview
, "could not allocate info memory!\n");
5067 if ((LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0) != infoPtr
)
5069 ERR(listview
, "pointer assignment error!\n");
5073 return DefWindowProcA(hwnd
, WM_NCCREATE
, wParam
, lParam
);
5078 * Destroys the listview control (called after WM_DESTROY).
5081 * [I] HWND : window handle
5086 static LRESULT
LISTVIEW_NCDestroy(HWND hwnd
)
5088 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5090 /* free listview info */
5091 COMCTL32_Free(infoPtr
);
5098 * Handles notification from children.
5101 * [I] HWND : window handle
5102 * [I] INT : control identifier
5103 * [I] LPNMHDR : notification information
5108 static LRESULT
LISTVIEW_Notify(HWND hwnd
, INT nCtrlId
, LPNMHDR lpnmh
)
5110 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5112 if (lpnmh
->hwndFrom
== infoPtr
->hwndHeader
)
5114 /* handle notification from header control */
5115 if (lpnmh
->code
== HDN_ENDTRACKA
)
5117 InvalidateRect(hwnd
, NULL
, TRUE
);
5124 static LRESULT
LISTVIEW_NotifyFormat(HWND hwndFrom
, HWND hwnd
, INT nCommand
)
5126 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5128 if (nCommand
== NF_REQUERY
)
5130 /* determine the type of structures to use */
5131 infoPtr
->notifyFormat
= SendMessageA(hwndFrom
, WM_NOTIFYFORMAT
,
5132 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
5133 if (infoPtr
->notifyFormat
== NFR_UNICODE
)
5135 FIXME (listview
, "NO support for unicode structures");
5144 * Draws the listview control.
5147 * [I] HWND : window handle
5148 * [I] HDC : device context handle
5153 static LRESULT
LISTVIEW_Paint(HWND hwnd
, HDC hdc
)
5159 hdc
= BeginPaint(hwnd
, &ps
);
5160 LISTVIEW_Refresh(hwnd
, hdc
);
5161 EndPaint(hwnd
, &ps
);
5165 LISTVIEW_Refresh(hwnd
, hdc
);
5173 * Right mouse button double click.
5176 * [I] HWND : window handle
5177 * [I] WORD : key flag
5178 * [I] WORD : x coordinate
5179 * [I] WORD : y coordinate
5184 static LRESULT
LISTVIEW_RButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
5187 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
5190 /* send NM_RELEASEDCAPTURE notification */
5191 nmh
.hwndFrom
= hwnd
;
5192 nmh
.idFrom
= nCtrlId
;
5193 nmh
.code
= NM_RELEASEDCAPTURE
;
5194 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
5196 /* send NM_RDBLCLK notification */
5197 nmh
.code
= NM_RDBLCLK
;
5198 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
5205 * Right mouse button input.
5208 * [I] HWND : window handle
5209 * [I] WORD : key flag
5210 * [I] WORD : x coordinate
5211 * [I] WORD : y coordinate
5216 static LRESULT
LISTVIEW_RButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
5219 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5220 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
5221 LVHITTESTINFO hitTestInfo
;
5225 /* send NM_RELEASEDCAPTURE notification */
5226 nmh
.hwndFrom
= hwnd
;
5227 nmh
.idFrom
= nCtrlId
;
5228 nmh
.code
= NM_RELEASEDCAPTURE
;
5229 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
5231 /* make sure the listview control window has the focus */
5232 if (infoPtr
->bFocus
== FALSE
)
5237 /* set right button down flag */
5238 infoPtr
->bRButtonDown
= TRUE
;
5240 /* set hit coordinates */
5241 hitTestInfo
.pt
.x
= wPosX
;
5242 hitTestInfo
.pt
.y
= wPosY
;
5244 /* perform hit test */
5245 nItem
= ListView_HitTest(hwnd
, &hitTestInfo
);
5246 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
5248 if (!((wKey
& MK_SHIFT
) || (wKey
& MK_CONTROL
)))
5250 LISTVIEW_SetSelection(hwnd
, nItem
);
5255 LISTVIEW_RemoveSelections(hwnd
, 0, GETITEMCOUNT(infoPtr
));
5263 * Right mouse button up.
5266 * [I] HWND : window handle
5267 * [I] WORD : key flag
5268 * [I] WORD : x coordinate
5269 * [I] WORD : y coordinate
5274 static LRESULT
LISTVIEW_RButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
5277 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5278 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
5281 if (infoPtr
->bRButtonDown
== TRUE
)
5283 /* send NM_RClICK notification */
5284 ZeroMemory(&nmh
, sizeof(NMHDR
));
5285 nmh
.hwndFrom
= hwnd
;
5286 nmh
.idFrom
= nCtrlId
;
5287 nmh
.code
= NM_RCLICK
;
5288 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
5290 /* set button flag */
5291 infoPtr
->bRButtonDown
= FALSE
;
5302 * [I] HWND : window handle
5303 * [I] HWND : window handle of previously focused window
5308 static LRESULT
LISTVIEW_SetFocus(HWND hwnd
, HWND hwndLoseFocus
)
5310 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5311 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
5314 /* send NM_SETFOCUS notification */
5315 nmh
.hwndFrom
= hwnd
;
5316 nmh
.idFrom
= nCtrlId
;
5317 nmh
.code
= NM_SETFOCUS
;
5318 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
5320 /* set window focus flag */
5321 infoPtr
->bFocus
= TRUE
;
5331 * [I] HWND : window handle
5332 * [I] HFONT : font handle
5333 * [I] WORD : redraw flag
5338 static LRESULT
LISTVIEW_SetFont(HWND hwnd
, HFONT hFont
, WORD fRedraw
)
5340 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5341 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
5345 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
5349 infoPtr
->hFont
= hFont
;
5352 if ((LVS_TYPEMASK
& lStyle
) == LVS_REPORT
)
5354 /* set header font */
5355 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)hFont
,
5356 MAKELPARAM(fRedraw
, 0));
5359 /* invalidate listview control client area */
5360 InvalidateRect(hwnd
, NULL
, FALSE
);
5362 if (fRedraw
== TRUE
)
5372 * Resizes the listview control.
5375 * [I] HWND : window handle
5376 * [I] WORD : new width
5377 * [I] WORD : new height
5382 static LRESULT
LISTVIEW_Size(HWND hwnd
, WORD wWidth
, WORD wHeight
)
5384 LISTVIEW_SetSize(hwnd
, GetWindowLongA(hwnd
, GWL_STYLE
), wWidth
, wHeight
);
5385 LISTVIEW_SetViewInfo(hwnd
);
5386 LISTVIEW_SetScroll(hwnd
);
5388 /* invalidate + erase background */
5389 InvalidateRect(hwnd
, NULL
, TRUE
);
5396 * Sets the size information for a given style.
5399 * [I] HWND : window handle
5400 * [I] LONG : window style
5401 * [I] WORD : new width
5402 * [I] WORD : new height
5407 static VOID
LISTVIEW_SetSize(HWND hwnd
, LONG lStyle
, LONG lWidth
, LONG lHeight
)
5409 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5415 switch (lStyle
& LVS_TYPEMASK
)
5418 if ((lStyle
& LVS_TYPEMASK
) == LVS_LIST
)
5420 if (!(lStyle
& WS_HSCROLL
))
5424 nHScrollHeight
= GetSystemMetrics(SM_CYHSCROLL
);
5425 if (lHeight
> nHScrollHeight
)
5427 lHeight
-= nHScrollHeight
;
5437 rc
.bottom
= lHeight
;
5440 Header_Layout(infoPtr
->hwndHeader
, &hl
);
5445 infoPtr
->rcList
.top
= lTop
;
5446 infoPtr
->rcList
.left
= 0;
5447 infoPtr
->rcList
.bottom
= lHeight
;
5448 infoPtr
->rcList
.right
= lWidth
;
5453 * Notification sent when the window style is modified.
5456 * [I] HWND : window handle
5457 * [I] WPARAM : window style type (normal or extended)
5458 * [I] LPSTYLESTRUCT : window style information
5463 static INT
LISTVIEW_StyleChanged(HWND hwnd
, WPARAM wStyleType
,
5466 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5473 if (wStyleType
== GWL_STYLE
)
5475 /* remove vertical scrollbar */
5476 if (lpss
->styleOld
& WS_VSCROLL
)
5478 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
5481 /* remove horizontal scrollbar */
5482 if (lpss
->styleOld
& WS_HSCROLL
)
5484 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
5487 if ((LVS_TYPEMASK
& lpss
->styleOld
) == LVS_REPORT
)
5490 ShowWindow(infoPtr
->hwndHeader
, SW_HIDE
);
5493 /* erase everything */
5494 GetClientRect(hwnd
, &rc
);
5496 hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
5497 FillRect(hdc
, &rc
, hBrush
);
5498 DeleteObject(hBrush
);
5499 ReleaseDC(hwnd
, hdc
);
5501 if ((lpss
->styleNew
& LVS_TYPEMASK
) == LVS_REPORT
)
5505 Header_Layout(infoPtr
->hwndHeader
, &hl
);
5506 SetWindowPos(infoPtr
->hwndHeader
, hwnd
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
,
5508 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
5510 else if (((lpss
->styleNew
& LVS_TYPEMASK
) == LVS_ICON
) ||
5511 ((lpss
->styleNew
& LVS_TYPEMASK
) == LVS_SMALLICON
))
5513 /* for NOW (it's only temporary) */
5514 SetWindowLongA(hwnd
, GWL_STYLE
, (lpss
->styleNew
&~LVS_TYPEMASK
)|LVS_LIST
);
5518 LISTVIEW_UnsupportedStyles(lpss
->styleNew
);
5521 LISTVIEW_SetSize(hwnd
, lpss
->styleNew
, rc
.right
, rc
.bottom
);
5523 /* recalculate attributes */
5524 LISTVIEW_SetViewInfo(hwnd
);
5526 /* set scrollbars, if needed */
5527 LISTVIEW_SetScroll(hwnd
);
5529 /* invalidate + erase background */
5530 InvalidateRect(hwnd
, NULL
, TRUE
);
5538 * Window procedure of the listview control.
5549 LRESULT WINAPI
LISTVIEW_WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
,
5554 case LVM_APPROXIMATEVIEWRECT
:
5555 return LISTVIEW_ApproximateViewRect(hwnd
, (INT
)wParam
,
5556 LOWORD(lParam
), HIWORD(lParam
));
5558 return LISTVIEW_Arrange(hwnd
, (INT
)wParam
);
5560 /* case LVM_CREATEDRAGIMAGE: */
5562 case LVM_DELETEALLITEMS
:
5563 return LISTVIEW_DeleteAllItems(hwnd
);
5565 case LVM_DELETECOLUMN
:
5566 return LISTVIEW_DeleteColumn(hwnd
, (INT
)wParam
);
5568 case LVM_DELETEITEM
:
5569 return LISTVIEW_DeleteItem(hwnd
, (INT
)wParam
);
5571 /* case LVM_EDITLABEL: */
5573 case LVM_ENSUREVISIBLE
:
5574 return LISTVIEW_EnsureVisible(hwnd
, (INT
)wParam
, (BOOL
)lParam
);
5577 return LISTVIEW_FindItem(hwnd
, (INT
)wParam
, (LPLVFINDINFO
)lParam
);
5579 case LVM_GETBKCOLOR
:
5580 return LISTVIEW_GetBkColor(hwnd
);
5582 /* case LVM_GETBKIMAGE: */
5584 case LVM_GETCALLBACKMASK
:
5585 return LISTVIEW_GetCallbackMask(hwnd
);
5587 case LVM_GETCOLUMNA
:
5588 return LISTVIEW_GetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
5590 /* case LVM_GETCOLUMNW: */
5591 /* case LVM_GETCOLUMNORDERARRAY: */
5593 case LVM_GETCOLUMNWIDTH
:
5594 return LISTVIEW_GetColumnWidth(hwnd
, (INT
)wParam
);
5596 case LVM_GETCOUNTPERPAGE
:
5597 return LISTVIEW_GetCountPerPage(hwnd
);
5599 /* case LVM_GETEDITCONTROL: */
5600 /* case LVM_GETEXTENDEDLISTVIEWSTYLE: */
5603 return LISTVIEW_GetHeader(hwnd
);
5605 /* case LVM_GETHOTCURSOR: */
5606 /* case LVM_GETHOTITEM: */
5607 /* case LVM_GETHOVERTIME: */
5609 case LVM_GETIMAGELIST
:
5610 return LISTVIEW_GetImageList(hwnd
, (INT
)wParam
);
5612 /* case LVM_GETISEARCHSTRING: */
5615 return LISTVIEW_GetItemA(hwnd
, (LPLVITEMA
)lParam
);
5617 /* case LVM_GETITEMW: */
5619 case LVM_GETITEMCOUNT
:
5620 return LISTVIEW_GetItemCount(hwnd
);
5622 case LVM_GETITEMPOSITION
:
5623 return LISTVIEW_GetItemPosition(hwnd
, (INT
)wParam
, (LPPOINT
)lParam
);
5625 case LVM_GETITEMRECT
:
5626 return LISTVIEW_GetItemRect(hwnd
, (INT
)wParam
, (LPRECT
)lParam
);
5628 case LVM_GETITEMSPACING
:
5629 return LISTVIEW_GetItemSpacing(hwnd
, (BOOL
)wParam
);
5631 case LVM_GETITEMSTATE
:
5632 return LISTVIEW_GetItemState(hwnd
, (INT
)wParam
, (UINT
)lParam
);
5634 case LVM_GETITEMTEXTA
:
5635 LISTVIEW_GetItemTextA(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
5638 /* case LVM_GETITEMTEXTW: */
5640 case LVM_GETNEXTITEM
:
5641 return LISTVIEW_GetNextItem(hwnd
, (INT
)wParam
, LOWORD(lParam
));
5643 /* case LVM_GETNUMBEROFWORKAREAS: */
5645 return LISTVIEW_GetOrigin(hwnd
, (LPPOINT
)lParam
);
5647 case LVM_GETSELECTEDCOUNT
:
5648 return LISTVIEW_GetSelectedCount(hwnd
);
5650 case LVM_GETSELECTIONMARK
:
5651 return LISTVIEW_GetSelectionMark(hwnd
);
5653 case LVM_GETSTRINGWIDTHA
:
5654 return LISTVIEW_GetStringWidthA (hwnd
, (LPCSTR
)lParam
);
5656 /* case LVM_GETSTRINGWIDTHW: */
5657 /* case LVM_GETSUBITEMRECT: */
5659 case LVM_GETTEXTBKCOLOR
:
5660 return LISTVIEW_GetTextBkColor(hwnd
);
5662 case LVM_GETTEXTCOLOR
:
5663 return LISTVIEW_GetTextColor(hwnd
);
5665 /* case LVM_GETTOOLTIPS: */
5667 case LVM_GETTOPINDEX
:
5668 return LISTVIEW_GetTopIndex(hwnd
);
5670 /* case LVM_GETUNICODEFORMAT: */
5672 case LVM_GETVIEWRECT
:
5673 return LISTVIEW_GetViewRect(hwnd
, (LPRECT
)lParam
);
5675 /* case LVM_GETWORKAREAS: */
5678 return LISTVIEW_HitTest(hwnd
, (LPLVHITTESTINFO
)lParam
);
5680 case LVM_INSERTCOLUMNA
:
5681 return LISTVIEW_InsertColumnA(hwnd
, (INT
)wParam
,
5682 (LPLVCOLUMNA
)lParam
);
5684 /* case LVM_INSERTCOLUMNW: */
5686 case LVM_INSERTITEMA
:
5687 return LISTVIEW_InsertItemA(hwnd
, (LPLVITEMA
)lParam
);
5689 /* case LVM_INSERTITEMW: */
5691 case LVM_REDRAWITEMS
:
5692 return LISTVIEW_RedrawItems(hwnd
, (INT
)wParam
, (INT
)lParam
);
5695 return LISTVIEW_Scroll(hwnd
, (INT
)wParam
, (INT
)lParam
);
5697 case LVM_SETBKCOLOR
:
5698 return LISTVIEW_SetBkColor(hwnd
, (COLORREF
)lParam
);
5700 /* case LVM_SETBKIMAGE: */
5702 case LVM_SETCALLBACKMASK
:
5703 return LISTVIEW_SetCallbackMask(hwnd
, (UINT
)wParam
);
5705 case LVM_SETCOLUMNA
:
5706 return LISTVIEW_SetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
5708 /* case LVM_SETCOLUMNW: */
5709 /* case LVM_SETCOLUMNORDERARRAY: */
5710 /* case LVM_SETCOLUMNWIDTH: */
5711 /* case LVM_SETEXTENDEDLISTVIEWSTYLE: */
5712 /* case LVM_SETHOTCURSOR: */
5713 /* case LVM_SETHOTITEM: */
5714 /* case LVM_SETHOVERTIME: */
5715 /* case LVM_SETICONSPACING: */
5717 case LVM_SETIMAGELIST
:
5718 return LISTVIEW_SetImageList(hwnd
, (INT
)wParam
, (HIMAGELIST
)lParam
);
5721 return LISTVIEW_SetItemA(hwnd
, (LPLVITEMA
)lParam
);
5723 /* case LVM_SETITEMW: */
5725 case LVM_SETITEMCOUNT
:
5726 LISTVIEW_SetItemCount(hwnd
, (INT
)wParam
);
5729 case LVM_SETITEMPOSITION
:
5730 return LISTVIEW_SetItemPosition(hwnd
, (INT
)wParam
, (INT
)LOWORD(lParam
),
5731 (INT
)HIWORD(lParam
));
5733 /* case LVM_SETITEMPOSITION: */
5735 case LVM_SETITEMSTATE
:
5736 return LISTVIEW_SetItemState(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
5738 case LVM_SETITEMTEXTA
:
5739 return LISTVIEW_SetItemTextA(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
5741 /* case LVM_SETSELECTIONMARK: */
5743 case LVM_SETTEXTBKCOLOR
:
5744 return LISTVIEW_SetTextBkColor(hwnd
, (COLORREF
)lParam
);
5746 case LVM_SETTEXTCOLOR
:
5747 return LISTVIEW_SetTextColor(hwnd
, (COLORREF
)lParam
);
5749 /* case LVM_SETTOOLTIPS: */
5750 /* case LVM_SETUNICODEFORMAT: */
5751 /* case LVM_SETWORKAREAS: */
5754 return LISTVIEW_SortItems(hwnd
, wParam
, lParam
);
5756 /* case LVM_SUBITEMHITTEST: */
5759 return LISTVIEW_Update(hwnd
, (INT
)wParam
);
5762 /* case WM_COMMAND: */
5765 return LISTVIEW_Create(hwnd
, wParam
, lParam
);
5768 return LISTVIEW_Destroy(hwnd
);
5771 return LISTVIEW_EraseBackground(hwnd
, wParam
, lParam
);
5774 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
5777 return LISTVIEW_GetFont(hwnd
);
5780 return LISTVIEW_HScroll(hwnd
, (INT
)LOWORD(wParam
),
5781 (INT
)HIWORD(wParam
), (HWND
)lParam
);
5784 return LISTVIEW_KeyDown(hwnd
, (INT
)wParam
, (LONG
)lParam
);
5787 return LISTVIEW_KillFocus(hwnd
);
5789 case WM_LBUTTONDBLCLK
:
5790 return LISTVIEW_LButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
5793 case WM_LBUTTONDOWN
:
5794 return LISTVIEW_LButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
5797 return LISTVIEW_LButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
5800 /* case WM_MOUSEMOVE: */
5801 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
5804 return LISTVIEW_NCCreate(hwnd
, wParam
, lParam
);
5807 return LISTVIEW_NCDestroy(hwnd
);
5810 return LISTVIEW_Notify(hwnd
, (INT
)wParam
, (LPNMHDR
)lParam
);
5812 case WM_NOTIFYFORMAT
:
5813 return LISTVIEW_NotifyFormat(hwnd
, (HWND
)wParam
, (INT
)lParam
);
5816 return LISTVIEW_Paint(hwnd
, (HDC
)wParam
);
5818 case WM_RBUTTONDBLCLK
:
5819 return LISTVIEW_RButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
5822 case WM_RBUTTONDOWN
:
5823 return LISTVIEW_RButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
5827 return LISTVIEW_RButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
5831 return LISTVIEW_SetFocus(hwnd
, (HWND
)wParam
);
5834 return LISTVIEW_SetFont(hwnd
, (HFONT
)wParam
, (WORD
)lParam
);
5836 /* case WM_SETREDRAW: */
5839 return LISTVIEW_Size(hwnd
, LOWORD(lParam
), HIWORD(lParam
));
5841 case WM_STYLECHANGED
:
5842 return LISTVIEW_StyleChanged(hwnd
, wParam
, (LPSTYLESTRUCT
)lParam
);
5844 /* case WM_TIMER: */
5847 return LISTVIEW_VScroll(hwnd
, (INT
)LOWORD(wParam
),
5848 (INT
)HIWORD(wParam
), (HWND
)lParam
);
5850 /* case WM_WINDOWPOSCHANGED: */
5851 /* case WM_WININICHANGE: */
5854 if (uMsg
>= WM_USER
)
5856 ERR(listview
, "unknown msg %04x wp=%08x lp=%08lx\n",
5857 uMsg
, wParam
, lParam
);
5860 /* call default window procedure */
5861 return DefWindowProcA(hwnd
, uMsg
, wParam
, lParam
);
5869 * Registers the window class.
5877 VOID
LISTVIEW_Register(VOID
)
5881 if (!GlobalFindAtomA(WC_LISTVIEWA
))
5883 ZeroMemory(&wndClass
, sizeof(WNDCLASSA
));
5884 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
5885 wndClass
.lpfnWndProc
= (WNDPROC
)LISTVIEW_WindowProc
;
5886 wndClass
.cbClsExtra
= 0;
5887 wndClass
.cbWndExtra
= sizeof(LISTVIEW_INFO
*);
5888 wndClass
.hCursor
= LoadCursorA(0, IDC_ARROWA
);
5889 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
5890 wndClass
.lpszClassName
= WC_LISTVIEWA
;
5891 RegisterClassA (&wndClass
);
5897 * Unregisters the window class.
5905 VOID
LISTVIEW_Unregister(VOID
)
5907 if (GlobalFindAtomA(WC_LISTVIEWA
))
5908 UnregisterClassA(WC_LISTVIEWA
, (HINSTANCE
)NULL
);