4 * Copyright 1998 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
8 * Listview control implementation. The behavior conforms to version 4.70
9 * and earlier of the listview contol.
12 * Most messages and notifications
13 * Report, small icon and icon display modes
24 static INT
LISTVIEW_GetItemCountPerColumn(HWND hwnd
);
25 static INT
LISTVIEW_GetItemCountPerRow(HWND hwnd
);
26 static INT
LISTVIEW_GetFirstVisibleItem(HWND hwnd
);
27 static VOID
LISTVIEW_SetVisible(HWND hwnd
, INT nItem
);
32 * Scrolls the specified item into the visible area.
35 * [I] HWND32 : window handle
36 * [I] INT32 : item index
41 static VOID
LISTVIEW_SetVisible(HWND hwnd
, INT nItem
)
43 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
45 INT nItemCountPerColumn
;
51 /* retrieve the index of the first visible fully item */
52 nFirstItem
= LISTVIEW_GetFirstVisibleItem(hwnd
);
54 /* nunber of fully visible items per row */
55 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
57 /* nunber of fully visible items per column */
58 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
60 if ((nItemCountPerRow
> 0) && (nItemCountPerColumn
> 0))
62 if (lStyle
& LVS_LIST
)
64 if (lStyle
& WS_HSCROLL
)
66 /* last visible item index */
67 nLastItem
= nItemCountPerColumn
* nItemCountPerRow
+ nFirstItem
- 1;
68 if (nItem
> nLastItem
)
70 /* calculate new scroll position based on item index */
71 if (((nItem
- nLastItem
) % nItemCountPerColumn
) == 0)
72 nHScrollPos
= (nItem
- nLastItem
) / nItemCountPerColumn
;
74 nHScrollPos
= (nItem
- nLastItem
) / nItemCountPerColumn
+ 1;
75 SendMessageA(hwnd
, LVM_SCROLL
, (WPARAM
)nHScrollPos
, (LPARAM
)0);
77 else if (nItem
< nFirstItem
)
79 /* calculate new scroll position based on item index */
80 if (((nItem
- nFirstItem
) % nItemCountPerColumn
) == 0)
81 nHScrollPos
= (nItem
- nFirstItem
) / nItemCountPerColumn
;
83 nHScrollPos
= (nItem
- nFirstItem
) / nItemCountPerColumn
- 1;
84 SendMessageA(hwnd
, LVM_SCROLL
, (WPARAM
)nHScrollPos
, (LPARAM
)0);
88 else if (lStyle
& LVS_REPORT
)
90 if (lStyle
& WS_VSCROLL
)
94 nLastItem
= nItemCountPerColumn
+ nFirstItem
;
98 nLastItem
= nItemCountPerColumn
+ nFirstItem
- 1;
101 if (nItem
> nLastItem
)
103 /* calculate new scroll position based on item index */
104 nVScrollPos
= nItem
- nLastItem
;
105 SendMessageA(hwnd
, LVM_SCROLL
, (WPARAM
)0, (LPARAM
)nVScrollPos
);
107 else if (nItem
< nFirstItem
)
109 /* calculate new scroll position based on item index */
110 nVScrollPos
= nItem
- nFirstItem
;
111 SendMessageA(hwnd
, LVM_SCROLL
, (WPARAM
)0, (LPARAM
)nVScrollPos
);
115 else if ((lStyle
& LVS_SMALLICON
) || (lStyle
& LVS_ICON
))
117 if (lStyle
& WS_VSCROLL
)
119 /* last visible item index */
120 nLastItem
= nItemCountPerColumn
* nItemCountPerRow
+ nFirstItem
- 1;
121 if (nItem
> nLastItem
)
123 /* calculate new scroll position based on item index */
124 nVScrollPos
= (nItem
- nLastItem
) / nItemCountPerRow
+ 1;
125 SendMessageA(hwnd
, LVM_SCROLL
, (WPARAM
)0, (LPARAM
)nVScrollPos
);
127 else if (nItem
< nFirstItem
)
129 /* calculate new scroll position based on item index */
130 nHScrollPos
= (nItem
- nFirstItem
) / nItemCountPerRow
- 1;
131 SendMessageA(hwnd
, LVM_SCROLL
, (WPARAM
)0, (LPARAM
)nHScrollPos
);
136 /* refresh display */
137 InvalidateRect(hwnd
, NULL
, FALSE
);
145 * Retrieves the index of the item at coordinate (0, 0) of the client area.
148 * [I] HWND32 : window handle
153 static INT
LISTVIEW_GetFirstVisibleItem(HWND hwnd
)
155 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
156 INT nItemCountPerRow
;
157 INT nItemCountPerColumn
;
161 /* INT32 nVScrollPos; */
164 /* get number of items per column */
165 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
167 /* get number of fully visble items per row */
168 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
170 if ((nItemCountPerRow
> 0) && (nItemCountPerColumn
> 0))
172 if (lStyle
& LVS_LIST
)
174 if (lStyle
& WS_HSCROLL
)
176 GetScrollRange(hwnd
, SB_HORZ
, &nMinRange
, &nMaxRange
);
177 nHScrollPos
= GetScrollPos(hwnd
, SB_HORZ
);
178 if (nMinRange
< nHScrollPos
)
180 nItem
= ((nHScrollPos
- nMinRange
) * nItemCountPerColumn
*
185 else if (lStyle
& LVS_REPORT
)
189 else if (lStyle
& LVS_SMALLICON
)
193 else if (lStyle
& LVS_ICON
)
204 * Retrieves the number of items per row. In other words, the number
205 * visible display columns.
208 * [I] HWND32 : window handle
211 * Number of items per row.
213 static INT
LISTVIEW_GetItemCountPerRow(HWND hwnd
)
215 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
216 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
217 INT nItemCountPerRow
= 0;
219 if (infoPtr
->nWidth
> 0)
221 if (lStyle
& LVS_LIST
)
223 if (infoPtr
->nColumnWidth
> 0)
225 nItemCountPerRow
= infoPtr
->nWidth
/ infoPtr
->nColumnWidth
;
226 if (nItemCountPerRow
== 0)
227 nItemCountPerRow
= 1;
230 else if (lStyle
& LVS_REPORT
)
234 else if (lStyle
& LVS_SMALLICON
)
238 else if (lStyle
& LVS_ICON
)
244 return nItemCountPerRow
;
249 * Retrieves the number of items that can be displayed vertically in
253 * [I] HWND32 : window handle
256 * Number of items per column.
258 static INT
LISTVIEW_GetItemCountPerColumn(HWND hwnd
)
260 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
261 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
262 INT nItemCountPerColumn
= 0;
264 if (infoPtr
->nHeight
> 0)
266 if (lStyle
& LVS_LIST
)
268 if (infoPtr
->nItemHeight
> 0)
269 nItemCountPerColumn
= infoPtr
->nHeight
/ infoPtr
->nItemHeight
;
271 else if (lStyle
& LVS_REPORT
)
275 else if (lStyle
& LVS_SMALLICON
)
279 else if (lStyle
& LVS_ICON
)
285 return nItemCountPerColumn
;
290 * Retrieves the number of columns needed to display
291 * all the items in listview.
294 * [I] HWND32 : window handle
299 static INT
LISTVIEW_GetColumnCount(HWND hwnd
)
301 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
302 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
303 INT nColumnCount
= 0;
304 INT nItemCountPerColumn
;
306 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
308 if ((infoPtr
->nItemCount
> 0) && (nItemCountPerColumn
> 0))
310 if (lStyle
& LVS_LIST
)
312 if ((infoPtr
->nItemCount
% nItemCountPerColumn
) == 0)
314 nColumnCount
= infoPtr
->nItemCount
/ nItemCountPerColumn
;
318 nColumnCount
= infoPtr
->nItemCount
/ nItemCountPerColumn
+ 1;
321 else if (lStyle
& LVS_REPORT
)
325 else if (lStyle
& LVS_SMALLICON
)
329 else if (lStyle
& LVS_ICON
)
340 * Sets the scrolling parameters.
343 * [I] HWND32 : window handle
348 static VOID
LISTVIEW_SetScroll(HWND hwnd
)
350 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
351 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
353 INT nItemCountPerRow
;
354 INT nItemCountPerColumn
;
355 INT nMinRange
, nMaxRange
;
357 /* INT32 nVScrollPos; */
359 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
360 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
362 if ((nItemCountPerColumn
> 0) && (nItemCountPerRow
> 0))
364 if (lStyle
& LVS_LIST
)
366 /* get number of columns needed to display all the listview items */
367 nColumnCount
= LISTVIEW_GetColumnCount(hwnd
);
368 if (nColumnCount
> 0)
370 if (nColumnCount
> nItemCountPerRow
)
372 /* add scrollbar if not already present */
373 if (!(lStyle
& WS_HSCROLL
))
375 /* display scrollbar */
376 ShowScrollBar(hwnd
, SB_HORZ
, TRUE
);
378 /* set scrollbar range and position */
379 nMaxRange
= nColumnCount
- nItemCountPerRow
;
380 SetScrollRange(hwnd
, SB_HORZ
, 0, nMaxRange
, FALSE
);
381 SetScrollPos(hwnd
, SB_HORZ
, 0, TRUE
);
385 nHScrollPos
= GetScrollPos(hwnd
, SB_HORZ
);
386 GetScrollRange(hwnd
, SB_HORZ
, &nMinRange
, &nMaxRange
);
387 if (nMaxRange
!= nColumnCount
- nItemCountPerRow
)
389 nMaxRange
= nColumnCount
- nItemCountPerRow
;
390 SetScrollRange(hwnd
, SB_HORZ
, nMinRange
, nMaxRange
, FALSE
);
392 if (nHScrollPos
> nMaxRange
)
393 nHScrollPos
= nMaxRange
;
395 SetScrollPos(hwnd
, SB_HORZ
, nHScrollPos
, TRUE
);
399 /* refresh the client area */
400 InvalidateRect(hwnd
,NULL
, TRUE
);
405 /* remove scrollbar if present */
406 if (lStyle
& WS_HSCROLL
)
409 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
411 /* refresh the client area */
412 InvalidateRect(hwnd
,NULL
, TRUE
);
418 else if (lStyle
& LVS_REPORT
)
426 rc
.right
= infoPtr
->nWidth
;
427 rc
.bottom
= infoPtr
->nHeight
;
431 SendMessageA(infoPtr
->hwndHeader
, HDM_LAYOUT
, 0, (LPARAM
)&hl
);
433 SetWindowPos(infoPtr
->hwndHeader
, hwnd
,
434 wp
.x
, wp
.y
, wp
.cx
, wp
.cy
, wp
.flags
);
436 /* infoPtr->rcList.top += wp.cy; */
438 else if (lStyle
& LVS_SMALLICON
)
442 else if (lStyle
& LVS_ICON
)
451 * Modifies the state (selected and focused) of the listview items.
454 * [I] HWND32 : window handle
455 * [I] INT32 : focused item index
456 * [I] BOOL32 : flag for determining weither the control keys are used or not
457 * [I] BOOL32 : flag for determining the input type (mouse or keyboard)
462 static VOID
LISTVIEW_SetItemStates(HWND hwnd
, INT nFocusedItem
,
463 BOOL bVirtualKeys
, BOOL bMouseInput
)
465 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
466 WORD wShift
= HIWORD(GetKeyState(VK_SHIFT
));
467 WORD wCtrl
= HIWORD(GetKeyState(VK_CONTROL
));
471 /* initialize memory */
472 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
474 if (wShift
&& (bVirtualKeys
== TRUE
))
476 /* reset the selected and focused states of all the items */
477 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
479 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)-1, (LPARAM
)&lvItem
);
481 if (infoPtr
->nSelectionMark
> nFocusedItem
)
483 for (i
= infoPtr
->nSelectionMark
; i
> nFocusedItem
; i
--)
486 lvItem
.stateMask
= LVIS_SELECTED
;
487 lvItem
.state
= LVIS_SELECTED
;
488 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)i
, (LPARAM
)&lvItem
);
493 for (i
= infoPtr
->nSelectionMark
; i
< nFocusedItem
; i
++)
496 lvItem
.stateMask
= LVIS_SELECTED
;
497 lvItem
.state
= LVIS_SELECTED
;
498 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)i
, (LPARAM
)&lvItem
);
502 /* select anf focus item */
503 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
504 lvItem
.state
= LVIS_SELECTED
| LVIS_FOCUSED
;
505 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)i
, (LPARAM
)&lvItem
);
509 if (wCtrl
&& (bVirtualKeys
== TRUE
))
511 /* make sure the focus is lost */
512 lvItem
.stateMask
= LVIS_FOCUSED
;
514 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)-1, (LPARAM
)&lvItem
);
516 if (bMouseInput
== TRUE
)
518 if (SendMessageA(hwnd
, LVM_GETITEMSTATE
, (WPARAM
)nFocusedItem
,
519 (LPARAM
)LVIS_SELECTED
) & LVIS_SELECTED
)
521 /* focus and unselect (toggle selection) */
522 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
523 lvItem
.state
= LVIS_FOCUSED
;
524 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)nFocusedItem
,
529 /* select and focus */
530 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
531 lvItem
.state
= LVIS_SELECTED
| LVIS_FOCUSED
;
532 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)nFocusedItem
,
536 /* set the group selection start position */
537 infoPtr
->nSelectionMark
= nFocusedItem
;
542 lvItem
.stateMask
= LVIS_FOCUSED
;
543 lvItem
.state
= LVIS_FOCUSED
;
544 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)nFocusedItem
,
550 /* clear selection and focus for all the items */
551 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
553 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)-1, (LPARAM
)&lvItem
);
555 /* set select and focus for this particular item */
556 lvItem
.stateMask
= LVIS_FOCUSED
| LVIS_SELECTED
;
557 lvItem
.state
= LVIS_FOCUSED
| LVIS_SELECTED
;
558 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)nFocusedItem
,
561 /* set the new group selection start position */
562 infoPtr
->nSelectionMark
= nFocusedItem
;
569 * Draws listview items when in list display maode.
572 * [I] HWND32 : window handle
573 * [I] HDC32 : device context handle
578 static VOID
LISTVIEW_RefreshList(HWND hwnd
, HDC hdc
)
580 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
581 LISTVIEW_ITEM
*lpItem
;
584 INT nItemCountPerColumn
;
585 INT nItemCountPerRow
;
592 COLORREF clrHighlight
;
593 COLORREF clrHighlightText
;
599 /* get number of items per column */
600 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
602 /* get number of items per row */
603 nItemCountPerRow
= LISTVIEW_GetItemCountPerColumn(hwnd
);
605 if ((nItemCountPerColumn
> 0) && (nItemCountPerRow
> 0))
608 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
610 /* inititialize system dependent information */
611 clrHighlight
= GetSysColor(COLOR_HIGHLIGHT
);
612 clrHighlightText
= GetSysColor(COLOR_HIGHLIGHTTEXT
);
613 nSmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
615 /* select transparent brush (for drawing the focus box) */
616 SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
618 /* select the doted pen (for drawing the focus box) */
619 hPen
= CreatePen(PS_DOT
, 1, 0);
620 hOldPen
= SelectObject(hdc
, hPen
);
622 /* get starting index */
623 i
= LISTVIEW_GetFirstVisibleItem(hwnd
);
626 for (j
= 0; i
< infoPtr
->nItemCount
; i
++, j
++)
628 /* set draw position for current item */
629 nRow
= j
% nItemCountPerColumn
;
630 nColumn
= j
/ nItemCountPerColumn
;
634 nDrawPosY
+= infoPtr
->nItemHeight
;
636 nDrawPosX
= nColumn
* infoPtr
->nColumnWidth
;
639 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
642 if (lpItem
->state
& LVIS_SELECTED
)
646 /* set item colors */
647 SetBkColor(hdc
, clrHighlight
);
648 SetTextColor(hdc
, clrHighlightText
);
650 /* set raster mode */
651 SetROP2(hdc
, R2_XORPEN
);
657 /* set item colors */
658 SetBkColor(hdc
, infoPtr
->clrTextBk
);
659 SetTextColor(hdc
, infoPtr
->clrText
);
661 /* set raster mode */
662 SetROP2(hdc
, R2_COPYPEN
);
666 if (infoPtr
->himlState
!= NULL
)
668 /* right shift 12 bits to obtain index in image list */
669 if (bSelected
== TRUE
)
670 ImageList_Draw(infoPtr
->himlState
, lpItem
->state
>> 12, hdc
,
671 nDrawPosX
, nDrawPosY
, ILD_SELECTED
);
673 ImageList_Draw(infoPtr
->himlState
, lpItem
->state
>> 12, hdc
,
674 nDrawPosX
, nDrawPosY
, ILD_NORMAL
);
676 nDrawPosX
+= nSmallIconWidth
;
680 if (infoPtr
->himlSmall
!= NULL
)
682 if (bSelected
== TRUE
)
683 ImageList_Draw(infoPtr
->himlSmall
, lpItem
->iImage
, hdc
, nDrawPosX
,
684 nDrawPosY
, ILD_SELECTED
);
686 ImageList_Draw(infoPtr
->himlSmall
, lpItem
->iImage
, hdc
, nDrawPosX
,
687 nDrawPosY
, ILD_NORMAL
);
689 nDrawPosX
+= nSmallIconWidth
;
692 /* get string size (in pixels) */
693 GetTextExtentPoint32A(hdc
, lpItem
->pszText
,
694 lstrlenA(lpItem
->pszText
), &labelSize
);
696 /* define a bounding box */
697 rcBoundingBox
.left
= nDrawPosX
;
698 rcBoundingBox
.top
= nDrawPosY
;
700 /* 2 pixels for padding purposes */
701 rcBoundingBox
.right
= nDrawPosX
+ labelSize
.cx
+ 2;
703 /* padding already included in infoPtr->nItemHeight */
704 rcBoundingBox
.bottom
= nDrawPosY
+ infoPtr
->nItemHeight
;
707 ExtTextOutA(hdc
, nDrawPosX
+ 1, nDrawPosY
+ 1,
708 ETO_OPAQUE
|ETO_CLIPPED
, &rcBoundingBox
,
709 lpItem
->pszText
, lstrlenA(lpItem
->pszText
), NULL
);
711 if (lpItem
->state
& LVIS_FOCUSED
)
712 Rectangle(hdc
, rcBoundingBox
.left
, rcBoundingBox
.top
,
713 rcBoundingBox
.right
, rcBoundingBox
.bottom
);
717 /* unselect objects */
718 SelectObject(hdc
, hOldFont
);
719 SelectObject(hdc
, hOldPen
);
728 * Draws listview items when in report display mode.
731 * [I] HWND32 : window handle
732 * [I] HDC32 : device context handle
737 static VOID
LISTVIEW_RefreshReport(HWND hwnd
, HDC hdc
)
744 * Draws listview items when in small icon display mode.
747 * [I] HWND32 : window handle
748 * [I] HDC32 : device context handle
753 static VOID
LISTVIEW_RefreshSmallIcon(HWND hwnd
, HDC hdc
)
760 * Draws listview items when in icon display mode.
763 * [I] HWND32 : window handle
764 * [I] HDC32 : device context handle
769 static VOID
LISTVIEW_RefreshIcon(HWND hwnd
, HDC hdc
)
776 * Draws listview items.
779 * [I] HWND32 : window handle
780 * [I] HDC32 : device context handle
785 static VOID
LISTVIEW_Refresh(HWND hwnd
, HDC hdc
)
787 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
789 if (lStyle
& LVS_LIST
)
791 LISTVIEW_RefreshList(hwnd
, hdc
);
793 else if (lStyle
& LVS_REPORT
)
795 LISTVIEW_RefreshReport(hwnd
, hdc
);
797 else if (lStyle
& LVS_SMALLICON
)
799 LISTVIEW_RefreshSmallIcon(hwnd
, hdc
);
801 else if (lStyle
& LVS_ICON
)
803 LISTVIEW_RefreshIcon(hwnd
, hdc
);
810 * Calculates the approximate width and height of a given number of items.
813 * [I] HWND32 : window handle
814 * [I] INT32 : number of items
819 * Returns a DWORD. The width in the low word and the height in high word.
821 static LRESULT
LISTVIEW_ApproximateViewRect(HWND hwnd
, INT nItemCount
,
822 WORD wWidth
, WORD wHeight
)
824 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
825 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
826 INT nItemCountPerColumn
= 1;
827 INT nColumnCount
= 0;
828 DWORD dwViewRect
= 0;
830 if (nItemCount
== -1)
831 nItemCount
= infoPtr
->nItemCount
;
833 if (lStyle
& LVS_LIST
)
835 if (wHeight
== 0xFFFF)
837 /* use current height */
838 wHeight
= infoPtr
->nHeight
;
841 if (wHeight
< infoPtr
->nItemHeight
)
843 wHeight
= infoPtr
->nItemHeight
;
848 if (infoPtr
->nItemHeight
> 0)
850 nItemCountPerColumn
= wHeight
/ infoPtr
->nItemHeight
;
851 if (nItemCountPerColumn
== 0)
852 nItemCountPerColumn
= 1;
854 if (nItemCount
% nItemCountPerColumn
!= 0)
855 nColumnCount
= nItemCount
/ nItemCountPerColumn
;
857 nColumnCount
= nItemCount
/ nItemCountPerColumn
+ 1;
861 wHeight
= nItemCountPerColumn
* infoPtr
->nItemHeight
+ 2;
862 wWidth
= nColumnCount
* infoPtr
->nColumnWidth
+ 2;
864 dwViewRect
= MAKELONG(wWidth
, wHeight
);
866 else if (lStyle
& LVS_REPORT
)
870 else if (lStyle
& LVS_SMALLICON
)
874 else if (lStyle
& LVS_ICON
)
884 * Arranges listview items in icon display mode.
887 * [I] HWND32 : window handle
888 * [I] INT32 : alignment code
894 static LRESULT
LISTVIEW_Arrange(HWND hwnd
, INT nAlignCode
)
896 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
897 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
898 BOOL bResult
= FALSE
;
900 if (lStyle
& LVS_ICON
)
921 /* << LISTVIEW_CreateDragImage >> */
925 * Removes all listview items.
928 * [I] HWND32 : window handle
934 static LRESULT
LISTVIEW_DeleteAllItems(HWND hwnd
)
936 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
937 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
938 LISTVIEW_ITEM
*lpItem
;
944 if (infoPtr
->nItemCount
> 0)
946 /* send LVN_DELETEALLITEMS notification */
947 ZeroMemory (&nmlv
, sizeof (NMLISTVIEW
));
948 nmlv
.hdr
.hwndFrom
= hwnd
;
949 nmlv
.hdr
.idFrom
= lCtrlId
;
950 nmlv
.hdr
.code
= LVN_DELETEALLITEMS
;
952 bNotify
= !(BOOL
)SendMessageA(GetParent(hwnd
), WM_NOTIFY
,
953 (WPARAM
)lCtrlId
, (LPARAM
)&nmlv
);
955 nmlv
.hdr
.code
= LVN_DELETEITEM
;
957 for (i
= 0; i
< infoPtr
->nItemCount
; i
++)
961 /* send LVN_DELETEITEM notification */
963 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
968 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
971 /* free item string */
972 if ((lpItem
->pszText
!= NULL
) &&
973 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
974 COMCTL32_Free (lpItem
->pszText
);
977 COMCTL32_Free (lpItem
);
981 /* ???? needs follow up */
982 DPA_DeleteAllPtrs (infoPtr
->hdpaItems
);
984 /* reset item counter */
985 infoPtr
->nItemCount
= 0;
987 /* reset scrollbar */
988 LISTVIEW_SetScroll(hwnd
);
996 * Removes a column from the listview control.
999 * [I] HWND32 : window handle
1000 * [I] INT32 : column index
1006 static LRESULT
LISTVIEW_DeleteColumn(HWND hwnd
, INT nColumn
)
1008 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
1011 /* if (infoPtr->nItemCount > 0) */
1013 /* if (!SendMessage32A(infoPtr->hwndHeader, HDM_DELETEITEM, wParam, 0)) */
1015 /* infoPtr->nColumnCount--; */
1016 /* FIXME (listview, "semi stub!\n"); */
1023 * Removes an item from the listview control.
1026 * [I] HWND32 : window handle
1027 * [I] INT32 : item index
1033 static LRESULT
LISTVIEW_DeleteItem(HWND hwnd
, INT nItem
)
1035 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1036 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
1037 LISTVIEW_ITEM
*lpItem
;
1039 BOOL bResult
= FALSE
;
1041 if ((nItem
>= 0) && (nItem
< infoPtr
->nItemCount
))
1043 /* send LVN_DELETEITEM notification */
1044 ZeroMemory (&nmlv
, sizeof (NMLISTVIEW
));
1045 nmlv
.hdr
.hwndFrom
= hwnd
;
1046 nmlv
.hdr
.idFrom
= lCtrlId
;
1047 nmlv
.hdr
.code
= LVN_DELETEITEM
;
1049 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
1053 lpItem
= (LISTVIEW_ITEM
*)DPA_DeletePtr (infoPtr
->hdpaItems
, nItem
);
1056 /* free item string */
1057 if ((lpItem
->pszText
!= NULL
) &&
1058 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
1059 COMCTL32_Free (lpItem
->pszText
);
1062 COMCTL32_Free (lpItem
);
1065 /* decrement item counter */
1066 infoPtr
->nItemCount
--;
1068 /* reset some of the draw data */
1069 LISTVIEW_SetScroll(hwnd
);
1077 /* << LISTVIEW_EditLabel >> */
1078 /* << LISTVIEW_EnsureVisible >> */
1082 * Searches for an item with specific characteristics.
1085 * [I] HWND32 : window handle
1086 * [I] INT32 : base item index
1087 * [I] LPLVFINDINFO : item information to look for
1090 * SUCCESS : index of item
1093 static LRESULT
LISTVIEW_FindItem(HWND hwnd
, INT nStart
,
1094 LPLVFINDINFO lpFindInfo
)
1096 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
1097 /* LISTVIEW_ITEM *lpItem; */
1099 /* INT32 nEnd = infoPtr->nItemCount; */
1100 /* BOOL32 bWrap = FALSE; */
1101 /* if (nStart == -1) */
1105 /* if (lpFindInfo->flags & LVFI_PARAM) */
1107 /* for (nItem = nStart; nItem < nEnd; nItem++) */
1109 /* get item pointer */
1110 /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
1111 /* if (lpItem != NULL) */
1113 /* if (lpFindInfo->lParam == lpItem->lParam) */
1120 /* if (lpFindInfo->flags & LVFI_PARTIAL) */
1122 /* for (nItem = nStart; nItem < nEnd; nItem++) */
1124 /* get item pointer */
1125 /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
1128 /* if (strncmp(lpItem->pszText, lpFindInfo->psz, strlen(lpFindInfo->psz)) */
1135 /* if (lpFindInfo->flags & LVFI_STRING) */
1137 /* for (nItem = nStart; nItem < nEnd; nItem++) */
1139 /* get item pointer */
1140 /* lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(infoPtr->hdpaItems, nItem); */
1141 /* if (lpItem != NULL) */
1143 /* if (strcmp(lpItem->pszText, lpFindInfo->psz) == 0) */
1149 /* if ((lpFindInfo->flags & LVFI_WRAP) && nStart) */
1151 /* nEnd = nStart; */
1156 /* bWrap = FALSE; */
1163 * Retrieves the background color of the listview control.
1166 * [I] HWND32 : window handle
1169 * COLORREF associated with the background.
1171 static LRESULT
LISTVIEW_GetBkColor(HWND hwnd
)
1173 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1175 return infoPtr
->clrBk
;
1180 * Retrieves the background image of the listview control.
1183 * [I] HWND32 : window handle
1184 * [O] LPLVMKBIMAGE : background image information
1190 /* static LRESULT LISTVIEW_GetBkImage(HWND32 hwnd, LPLVBKIMAGE lpBkImage) */
1195 /* << LISTVIEW_GetCallbackMask >> */
1199 * Retrieves column attributes.
1202 * [I] HWND32 : window handle
1203 * [I] INT32 : column index
1204 * [IO] LPLVCOLUMN32A : column information
1210 static LRESULT
LISTVIEW_GetColumnA(HWND hwnd
, INT nIndex
,
1211 LPLVCOLUMNA lpColumn
)
1213 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1216 if (lpColumn
== NULL
)
1219 ZeroMemory (&hdi
, sizeof(HDITEMA
));
1221 if (lpColumn
->mask
& LVCF_FMT
)
1222 hdi
.mask
|= HDI_FORMAT
;
1224 if (lpColumn
->mask
& LVCF_WIDTH
)
1225 hdi
.mask
|= HDI_WIDTH
;
1227 if (lpColumn
->mask
& LVCF_TEXT
)
1228 hdi
.mask
|= (HDI_TEXT
| HDI_FORMAT
);
1230 if (lpColumn
->mask
& LVCF_IMAGE
)
1231 hdi
.mask
|= HDI_IMAGE
;
1233 if (lpColumn
->mask
& LVCF_ORDER
)
1234 hdi
.mask
|= HDI_ORDER
;
1236 if (!SendMessageA (infoPtr
->hwndHeader
, HDM_GETITEMA
,
1237 (WPARAM
)nIndex
, (LPARAM
)&hdi
))
1240 if (lpColumn
->mask
& LVCF_FMT
)
1244 if (hdi
.fmt
& HDF_LEFT
)
1245 lpColumn
->fmt
|= LVCFMT_LEFT
;
1246 else if (hdi
.fmt
& HDF_RIGHT
)
1247 lpColumn
->fmt
|= LVCFMT_RIGHT
;
1248 else if (hdi
.fmt
& HDF_CENTER
)
1249 lpColumn
->fmt
|= LVCFMT_CENTER
;
1251 if (hdi
.fmt
& HDF_IMAGE
)
1252 lpColumn
->fmt
|= LVCFMT_COL_HAS_IMAGES
;
1255 if (lpColumn
->mask
& LVCF_WIDTH
)
1256 lpColumn
->cx
= hdi
.cxy
;
1258 if ((lpColumn
->mask
& LVCF_TEXT
) && (lpColumn
->pszText
) && (hdi
.pszText
))
1259 lstrcpynA (lpColumn
->pszText
, hdi
.pszText
, lpColumn
->cchTextMax
);
1261 if (lpColumn
->mask
& LVCF_IMAGE
)
1262 lpColumn
->iImage
= hdi
.iImage
;
1264 if (lpColumn
->mask
& LVCF_ORDER
)
1265 lpColumn
->iOrder
= hdi
.iOrder
;
1270 /* << LISTVIEW_GetColumn32W >> */
1271 /* << LISTVIEW_GetColumnOrderArray >> */
1275 * Retrieves the column width when list or report display mode.
1278 * [I] HWND32 : window handle
1279 * [I] int32 : column index
1282 * SUCCESS : column width
1285 static LRESULT
LISTVIEW_GetColumnWidth(HWND hwnd
, INT nColumn
)
1287 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1288 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1290 INT nColumnWidth
= 0;
1292 if ((lStyle
& LVS_LIST
) || (lStyle
& LVS_SMALLICON
) || (lStyle
& LVS_ICON
))
1294 nColumnWidth
= infoPtr
->nColumnWidth
;
1296 else if (lStyle
& LVS_REPORT
)
1298 /* verify validity of index */
1299 if ((nColumn
>= 0) && (nColumn
< infoPtr
->nColumnCount
))
1301 /* get column width from header */
1302 hdi
.mask
= HDI_WIDTH
;
1303 if (SendMessageA (infoPtr
->hwndHeader
, HDM_GETITEMA
,
1304 (WPARAM
)nColumn
, (LPARAM
)&hdi
))
1305 nColumnWidth
= hdi
.cxy
;
1309 return nColumnWidth
;
1314 * In list or report display mode, retrieves the number of items that can fit
1315 * vertically in the visible area. In icon or small icon display mode,
1316 * retrieves the total number of visible items.
1319 * [I] HWND32 : window handle
1322 * Number of fully visible items.
1324 static LRESULT
LISTVIEW_GetCountPerPage(HWND hwnd
)
1326 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1327 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1329 INT nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
1330 INT nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
1332 if (lStyle
& LVS_LIST
)
1334 if ((nItemCountPerRow
> 0) && (nItemCountPerColumn
> 0))
1336 nItemCount
= nItemCountPerRow
* nItemCountPerColumn
;
1339 else if (lStyle
& LVS_REPORT
)
1341 nItemCount
= nItemCountPerColumn
;
1343 else if ((lStyle
& LVS_SMALLICON
) || (lStyle
& LVS_ICON
))
1345 nItemCount
= infoPtr
->nItemCount
;
1351 /* << LISTVIEW_GetEditControl >> */
1352 /* << LISTVIEW_GetExtendedListViewStyle >> */
1356 * Retrieves a header handle.
1359 * [I] HWND32 : window handle
1364 static LRESULT
LISTVIEW_GetHeader(HWND hwnd
)
1366 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1368 return infoPtr
->hwndHeader
;
1371 /* << LISTVIEW_GetHotCursor >> */
1372 /* << LISTVIEW_GetHotItem >> */
1373 /* << LISTVIEW_GetHoverTime >> */
1377 * Retrieves an image list handle.
1380 * [I] HWND32 : window handle
1381 * [I] INT32 : image list identifier
1384 * SUCCESS : image list handle
1387 static LRESULT
LISTVIEW_GetImageList(HWND hwnd
, INT nImageList
)
1389 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1390 HIMAGELIST himl
= NULL
;
1395 himl
= infoPtr
->himlNormal
;
1397 himl
= infoPtr
->himlSmall
;
1399 himl
= infoPtr
->himlState
;
1402 return (LRESULT
)himl
;
1406 /* << LISTVIEW_GetISearchString >> */
1410 * Retrieves item attributes.
1413 * [I] HWND32 : window handle
1414 * [IO] LPLVITEM32A : item info
1420 static LRESULT
LISTVIEW_GetItemA(HWND hwnd
, LPLVITEMA lpItem
)
1422 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1423 LISTVIEW_ITEM
*lpListItem
;
1424 BOOL bResult
= FALSE
;
1428 if ((lpItem
->iItem
>= 0) && (lpItem
->iItem
< infoPtr
->nItemCount
))
1431 lpListItem
= DPA_GetPtr(infoPtr
->hdpaItems
, lpItem
->iItem
);
1432 if (lpListItem
!= NULL
)
1434 /* not tested for subitem > 0 */
1435 lpListItem
+= lpItem
->iSubItem
;
1436 if (lpListItem
!= NULL
)
1438 /* retrieve valid data */
1439 if (lpItem
->mask
& LVIF_STATE
)
1440 lpItem
->state
= lpListItem
->state
& lpItem
->stateMask
;
1442 if (lpItem
->mask
& LVIF_TEXT
)
1444 if (lpListItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1445 lpItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1447 Str_GetPtrA(lpListItem
->pszText
, lpItem
->pszText
,
1448 lpItem
->cchTextMax
);
1451 if (lpItem
->mask
& LVIF_IMAGE
)
1452 lpItem
->iImage
= lpListItem
->iImage
;
1454 if (lpItem
->mask
& LVIF_PARAM
)
1455 lpItem
->lParam
= lpListItem
->lParam
;
1457 if (lpItem
->mask
& LVIF_INDENT
)
1458 lpItem
->iIndent
= lpListItem
->iIndent
;
1469 /* << LISTVIEW_GetItem32W >> */
1470 /* << LISTVIEW_GetHotCursor >> */
1471 /* << LISTVIEW_GetHotItem >> */
1472 /* << LISTVIEW_GetHoverTime >> */
1476 * Retrieves the number of items in the listview control.
1479 * [I] HWND32 : window handle
1484 static LRESULT
LISTVIEW_GetItemCount(HWND hwnd
)
1486 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1488 return infoPtr
->nItemCount
;
1493 * Retrieves the position (upper-left) of the listview control item.
1496 * [I] HWND32 : window handle
1497 * [I] INT32 : item index
1498 * [O] LPPOINT32 : coordinate information
1504 static LRESULT
LISTVIEW_GetItemPosition(HWND hwnd
, INT nItem
,
1507 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1508 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1511 BOOL bResult
= FALSE
;
1512 INT nItemCountPerColumn
;
1513 INT nItemCountPerRow
;
1517 if ((nItem
>= 0) && (nItem
< infoPtr
->nItemCount
) && (lpPt
!= NULL
))
1519 if (lStyle
& LVS_LIST
)
1521 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
1522 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
1524 if ((nItemCountPerColumn
> 0) && (nItemCountPerRow
> 0))
1526 nFirstItem
= LISTVIEW_GetFirstVisibleItem(hwnd
);
1527 nLastItem
= nFirstItem
+ nItemCountPerRow
* nItemCountPerRow
- 1;
1529 if ((nItem
>= nFirstItem
) || (nItem
<= nLastItem
))
1531 nItem
-= nFirstItem
;
1534 nColumn
= nItem
/ nItemCountPerColumn
;
1537 nRow
= nItem
% nItemCountPerColumn
;
1539 /* X coordinate of the column */
1540 lpPt
->x
= nColumn
* infoPtr
->nColumnWidth
;
1542 /* Y coordinate of the item */
1543 lpPt
->y
= nRow
* infoPtr
->nItemHeight
;
1548 else if (lStyle
& LVS_REPORT
)
1552 else if (lStyle
& LVS_SMALLICON
)
1556 else if (lStyle
& LVS_ICON
)
1568 * Retrieves the bounding rectangle for a listview control item.
1571 * [I] HWND32 : window handle
1572 * [I] INT32 : item index
1573 * [IO] LPRECT32 : bounding rectangle coordinates
1579 static LRESULT
LISTVIEW_GetItemRect(HWND hwnd
, INT nItem
, LPRECT lpRect
)
1581 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1582 LISTVIEW_ITEM
*lpItem
;
1585 BOOL bResult
= FALSE
;
1586 INT nSmallIconWidth
;
1588 nSmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
1590 if ((nItem
< 0) || (nItem
>= infoPtr
->nItemCount
) || (lpRect
== NULL
))
1594 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
1598 if (!SendMessageA(hwnd
, LVM_GETITEMPOSITION
, (WPARAM
)nItem
, (LPARAM
)&pt
))
1601 nLabelWidth
= SendMessageA(hwnd
, LVM_GETSTRINGWIDTHA
, (WPARAM
)0,
1602 (LPARAM
)lpItem
->pszText
);
1603 switch(lpRect
->left
)
1606 lpRect
->left
= pt
.x
;
1608 lpRect
->right
= lpRect
->left
+ nSmallIconWidth
+ nLabelWidth
;
1609 lpRect
->bottom
= lpRect
->top
+ infoPtr
->nItemHeight
;
1613 lpRect
->left
= pt
.x
;
1615 lpRect
->right
= lpRect
->left
+ nSmallIconWidth
;
1616 lpRect
->bottom
= lpRect
->top
+ infoPtr
->nItemHeight
;
1620 lpRect
->left
= pt
.x
+ nSmallIconWidth
;
1622 lpRect
->right
= lpRect
->left
+ nLabelWidth
;
1623 lpRect
->bottom
= infoPtr
->nItemHeight
;
1626 case LVIR_SELECTBOUNDS
:
1636 * Retrieves the spacing between listview control items.
1639 * [I] HWND32 : window handle
1640 * [I] BOOL32 : small icon (TRUE) or large icon (FALSE)
1643 * Horizontal + vertical spacing
1645 static LRESULT
LISTVIEW_GetItemSpacing(HWND hwnd
, BOOL bSmall
)
1647 INT nSmallIconHSpacing
;
1648 INT nSmallIconVSpacing
;
1656 nSmallIconHSpacing
= 0;
1657 nSmallIconVSpacing
= 0;
1658 lResult
= MAKELONG(nSmallIconHSpacing
, nSmallIconVSpacing
);
1662 nIconHSpacing
= GetSystemMetrics(SM_CXICONSPACING
);
1663 nIconVSpacing
= GetSystemMetrics(SM_CYICONSPACING
);
1664 lResult
= MAKELONG(nIconHSpacing
, nIconVSpacing
);
1672 * Retrieves the state of a listview control item.
1675 * [I] HWND32 : window handle
1676 * [I] INT32 : item index
1677 * [I] UINT32 : state mask
1680 * State specified by the mask.
1682 static LRESULT
LISTVIEW_GetItemState(HWND hwnd
, INT nItem
, UINT uMask
)
1684 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1685 LISTVIEW_ITEM
*lpItem
;
1688 if ((nItem
>= 0) && (nItem
< infoPtr
->nItemCount
))
1690 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
1692 nState
= lpItem
->state
& uMask
;
1700 * Retrieves the text of a listview control item or subitem.
1703 * [I] HWND32 : window handle
1704 * [I] INT32 : item index
1705 * [IO] LPLVITEM32A : item information
1710 static VOID
LISTVIEW_GetItemTextA(HWND hwnd
, INT nItem
,
1713 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1714 LISTVIEW_ITEM
*lpListItem
;
1716 if ((nItem
< 0) || (nItem
>= infoPtr
->nItemCount
) || (lpItem
== NULL
))
1719 lpListItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
1720 if (lpListItem
== NULL
)
1723 lpListItem
+= lpItem
->iSubItem
;
1724 if (lpListItem
== NULL
)
1727 if (lpListItem
->pszText
== LPSTR_TEXTCALLBACKA
)
1728 lpItem
->pszText
= LPSTR_TEXTCALLBACKA
;
1730 Str_GetPtrA(lpListItem
->pszText
, lpItem
->pszText
, lpItem
->cchTextMax
);
1735 * Searches for an item based on properties + relationships.
1738 * [I] HWND32 : window handle
1739 * [I] INT32 : item index
1740 * [I] UINT32 : relationship flag
1743 * SUCCESS : item index
1746 static LRESULT
LISTVIEW_GetNextItem (HWND hwnd
, INT nItem
, UINT uFlags
)
1748 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1751 /* start at begin */
1755 if ((nItem
>= 0) && (nItem
< infoPtr
->nItemCount
))
1763 /* << LISTVIEW_GetNumberOfWorkAreas >> */
1767 * Retrieves the current origin when in icon or small icon display mode.
1770 * [I] HWND32 : window handle
1771 * [O] LPPOINT32 : coordinate information
1777 static LRESULT
LISTVIEW_GetOrigin(HWND hwnd
, LPPOINT lpOrigin
)
1779 LONG lStyle
= GetWindowLongA(hwnd
, GWL_ID
);
1780 BOOL bResult
= FALSE
;
1782 if (lStyle
& LVS_SMALLICON
)
1786 else if (lStyle
& LVS_ICON
)
1796 * Retrieves the number of items that are marked as selected.
1799 * [I] HWND32 : window handle
1802 * Number of items selected.
1804 static LRESULT
LISTVIEW_GetSelectedCount(HWND hwnd
)
1806 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1807 LISTVIEW_ITEM
*lpItem
;
1808 INT nSelectedCount
= 0;
1811 for (i
= 0; i
< infoPtr
->nItemCount
; i
++)
1813 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
1816 if (lpItem
->state
& LVIS_SELECTED
)
1821 return nSelectedCount
;
1826 * Retrieves item index that marks the start of a multiple selection.
1829 * [I] HWND32 : window handle
1832 * Index number or -1 if there is no selection mark.
1834 static LRESULT
LISTVIEW_GetSelectionMark(HWND hwnd
)
1836 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1839 if (SendMessageA(hwnd
, LVM_GETSELECTEDCOUNT
, (WPARAM
)0, (LPARAM
)0) != 0)
1840 nResult
= infoPtr
->nSelectionMark
;
1847 * Retrieves the width of a string.
1850 * [I] HWND32 : window handle
1853 * SUCCESS : string width (in pixels)
1856 static LRESULT
LISTVIEW_GetStringWidthA(HWND hwnd
, LPCSTR lpsz
)
1858 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1859 HFONT hFont
, hOldFont
;
1866 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
1868 hOldFont
= SelectObject (hdc
, hFont
);
1869 GetTextExtentPoint32A(hdc
, lpsz
, lstrlenA(lpsz
), &textSize
);
1870 SelectObject (hdc
, hOldFont
);
1871 ReleaseDC(hwnd
, hdc
);
1872 nResult
= textSize
.cx
;
1880 * Retrieves the text backgound color.
1883 * [I] HWND32 : window handle
1886 * COLORREF associated with the the background.
1888 static LRESULT
LISTVIEW_GetTextBkColor(HWND hwnd
)
1890 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1892 return infoPtr
->clrTextBk
;
1897 * Retrieves the text color.
1900 * [I] HWND32 : window handle
1903 * COLORREF associated with the text.
1905 static LRESULT
LISTVIEW_GetTextColor(HWND hwnd
)
1907 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1909 return infoPtr
->clrText
;
1914 * Retrieves the bounding rectangle of all the items.
1917 * [I] HWND32 : window handle
1918 * [O] LPRECT32 : bounding rectangle
1924 static LRESULT
LISTVIEW_GetViewRect(HWND hwnd
, LPRECT lpBoundingRect
)
1926 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLong32A(hwnd, 0); */
1927 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1928 BOOL bResult
= FALSE
;
1930 if (lpBoundingRect
!= NULL
)
1932 if ((lStyle
& LVS_ICON
) || (lStyle
& LVS_SMALLICON
))
1943 * Determines item index when in small icon view.
1946 * [I] HWND32 : window handle
1947 * [IO] LPLVHITTESTINFO : hit test information
1950 * SUCCESS : item index
1953 static LRESULT
HitTestSmallIconView(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
1955 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1956 LISTVIEW_ITEM
*lpItem
;
1963 INT nSmallIconWidth
;
1964 INT nItemCountPerRow
;
1967 nColumn
= lpHitTestInfo
->pt
.x
/ infoPtr
->nColumnWidth
;
1970 nRow
= lpHitTestInfo
->pt
.y
/ infoPtr
->nItemHeight
;
1972 /* calculate offset from start of column (in pixels) */
1973 nOffset
= lpHitTestInfo
->pt
.x
% infoPtr
->nColumnWidth
;
1975 /* get recommended width of a small icon */
1976 nSmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
1978 /* calculate index */
1979 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
1980 nItem
= nRow
* nItemCountPerRow
+ LISTVIEW_GetFirstVisibleItem(hwnd
) + nColumn
;
1982 /* verify existance of item */
1983 if (nItem
< infoPtr
->nItemCount
)
1986 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
1989 if (infoPtr
->himlState
!= NULL
)
1991 nPosX
+= nSmallIconWidth
;
1992 if (nOffset
<= nPosX
)
1994 lpHitTestInfo
->flags
= LVHT_ONITEMSTATEICON
| LVHT_ONITEM
;
1995 lpHitTestInfo
->iItem
= nItem
;
1996 lpHitTestInfo
->iSubItem
= 0;
2001 if (infoPtr
->himlSmall
!= NULL
)
2003 nPosX
+= nSmallIconWidth
;
2004 if (nOffset
<= nPosX
)
2006 lpHitTestInfo
->flags
= LVHT_ONITEMICON
| LVHT_ONITEM
;
2007 lpHitTestInfo
->iItem
= nItem
;
2008 lpHitTestInfo
->iSubItem
= 0;
2013 /* get width of label in pixels */
2014 nLabelWidth
= SendMessageA(hwnd
, LVM_GETSTRINGWIDTHA
, (WPARAM
)0,
2015 (LPARAM
)lpItem
->pszText
);
2016 nLabelWidth
+= nPosX
;
2018 if (nOffset
<= nLabelWidth
)
2020 lpHitTestInfo
->flags
= LVHT_ONITEMLABEL
| LVHT_ONITEM
;
2021 lpHitTestInfo
->iItem
= nItem
;
2022 lpHitTestInfo
->iSubItem
= 0;
2028 /* hit is not on an item */
2029 lpHitTestInfo
->flags
= LVHT_NOWHERE
;
2036 * Determines item index when in list display mode.
2039 * [I] HWND32 : window handle
2040 * [IO] LPLVHITTESTINFO : hit test information
2043 * SUCCESS : item index
2046 static LRESULT
HitTestListView(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
2048 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2049 LISTVIEW_ITEM
*lpItem
;
2056 INT nSmallIconWidth
;
2057 INT nItemCountPerColumn
;
2060 nColumn
= lpHitTestInfo
->pt
.x
/ infoPtr
->nColumnWidth
;
2063 nRow
= lpHitTestInfo
->pt
.y
/ infoPtr
->nItemHeight
;
2065 /* calculate offset from start of column (in pixels) */
2066 nOffset
= lpHitTestInfo
->pt
.x
% infoPtr
->nColumnWidth
;
2068 /* get recommended width of a small icon */
2069 nSmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
2071 /* calculate index */
2072 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
2073 nItem
= (nColumn
* nItemCountPerColumn
+ LISTVIEW_GetFirstVisibleItem(hwnd
)
2076 /* verify existance of item */
2077 if (nItem
< infoPtr
->nItemCount
)
2080 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
2083 if (infoPtr
->himlState
!= NULL
)
2085 nPosX
+= nSmallIconWidth
;
2086 if (nOffset
<= nPosX
)
2088 lpHitTestInfo
->flags
= LVHT_ONITEMSTATEICON
| LVHT_ONITEM
;
2089 lpHitTestInfo
->iItem
= nItem
;
2090 lpHitTestInfo
->iSubItem
= 0;
2095 if (infoPtr
->himlSmall
!= NULL
)
2097 nPosX
+= nSmallIconWidth
;
2098 if (nOffset
<= nPosX
)
2100 lpHitTestInfo
->flags
= LVHT_ONITEMICON
| LVHT_ONITEM
;
2101 lpHitTestInfo
->iItem
= nItem
;
2102 lpHitTestInfo
->iSubItem
= 0;
2107 /* get width of label in pixels */
2108 nLabelWidth
= SendMessageA(hwnd
, LVM_GETSTRINGWIDTHA
, (WPARAM
)0,
2109 (LPARAM
)lpItem
->pszText
);
2110 nLabelWidth
+= nPosX
;
2112 if (nOffset
<= nLabelWidth
)
2114 lpHitTestInfo
->flags
= LVHT_ONITEMLABEL
| LVHT_ONITEM
;
2115 lpHitTestInfo
->iItem
= nItem
;
2116 lpHitTestInfo
->iSubItem
= 0;
2122 /* hit is not on an item */
2123 lpHitTestInfo
->flags
= LVHT_NOWHERE
;
2130 * Determines wich listview item is located at the specified position.
2133 * [I] HWND32 : window handle
2134 * [IO} LPLVHITTESTINFO : hit test information
2137 * SUCCESS : item index
2140 static LRESULT
LISTVIEW_HitTest(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
2142 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2144 if (lStyle
& LVS_LIST
)
2145 return HitTestListView(hwnd
, lpHitTestInfo
);
2146 else if (lStyle
& LVS_REPORT
)
2150 else if (lStyle
& LVS_SMALLICON
)
2152 return HitTestSmallIconView(hwnd
, lpHitTestInfo
);
2154 else if (lStyle
& LVS_ICON
)
2164 * Inserts a new column.
2167 * [I] HWND32 : window handle
2168 * [I] INT32 : column index
2169 * [I] LPLVCOLUMN32A : column information
2172 * SUCCESS : new column index
2175 static LRESULT
LISTVIEW_InsertColumnA(HWND hwnd
, INT nIndex
,
2176 LPLVCOLUMNA lpColumn
)
2178 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2182 if ((lpColumn
== NULL
) || (infoPtr
->nItemCount
> 0))
2185 FIXME (listview
, "(%d %p): semi stub!\n", nIndex
, lpColumn
);
2187 /* initialize memory */
2188 ZeroMemory (&hdi
, sizeof(HDITEMA
));
2190 if (lpColumn
->mask
& LVCF_FMT
)
2193 hdi
.fmt
|= HDF_LEFT
;
2194 else if (lpColumn
->fmt
& LVCFMT_LEFT
)
2195 hdi
.fmt
|= HDF_LEFT
;
2196 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
2197 hdi
.fmt
|= HDF_RIGHT
;
2198 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
2199 hdi
.fmt
|= HDF_CENTER
;
2200 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
2201 hdi
.fmt
|= HDF_IMAGE
;
2203 hdi
.mask
|= HDI_FORMAT
;
2206 if (lpColumn
->mask
& LVCF_WIDTH
)
2208 hdi
.mask
|= HDI_WIDTH
;
2209 hdi
.cxy
= lpColumn
->cx
;
2212 if (lpColumn
->mask
& LVCF_TEXT
)
2214 hdi
.mask
|= (HDI_TEXT
| HDI_FORMAT
);
2215 hdi
.pszText
= lpColumn
->pszText
;
2216 hdi
.fmt
|= HDF_STRING
;
2219 if (lpColumn
->mask
& LVCF_IMAGE
)
2221 hdi
.mask
|= HDI_IMAGE
;
2222 hdi
.iImage
= lpColumn
->iImage
;
2225 if (lpColumn
->mask
& LVCF_ORDER
)
2227 hdi
.mask
|= HDI_ORDER
;
2228 hdi
.iOrder
= lpColumn
->iOrder
;
2231 nResult
= SendMessageA (infoPtr
->hwndHeader
, HDM_INSERTITEMA
,
2232 (WPARAM
)nIndex
, (LPARAM
)&hdi
);
2236 /* increment column counter */
2237 infoPtr
->nColumnCount
++;
2242 /* << LISTVIEW_InsertColumn32W >> */
2246 * Inserts a new item in the listview control.
2249 * [I] HWND32 : window handle
2250 * [I] LPLVITEM32A : item information
2253 * SUCCESS : new item index
2256 static LRESULT
LISTVIEW_InsertItemA(HWND hwnd
, LPLVITEMA lpItem
)
2258 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2259 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2260 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2261 LISTVIEW_ITEM
*lpListItem
;
2265 INT nColumnWidth
= 0;
2266 INT nSmallIconWidth
;
2271 if (lpItem
->iSubItem
!= 0)
2274 /* allocate memory */
2275 lpListItem
= (LISTVIEW_ITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM
));
2276 if (lpListItem
== NULL
)
2279 nSmallIconWidth
= GetSystemMetrics(SM_CXSMICON
);
2281 /* initialize listview control item */
2282 ZeroMemory(lpListItem
, sizeof(LISTVIEW_ITEM
));
2284 /* copy only valid data */
2285 if (lpItem
->mask
& LVIF_TEXT
)
2287 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2289 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
2292 lpListItem
->pszText
= LPSTR_TEXTCALLBACKA
;
2296 nColumnWidth
= SendMessageA(hwnd
, LVM_GETSTRINGWIDTHA
,
2297 (WPARAM
)0, (LPARAM
)lpItem
->pszText
);
2299 /* add padding for separating columns */
2302 /* calculate column width; make sure it's at least 96 pixels */
2303 if (nColumnWidth
< 96)
2306 Str_SetPtrA(&lpListItem
->pszText
, lpItem
->pszText
);
2310 if (lpItem
->mask
& LVIF_STATE
)
2312 if (lpItem
->stateMask
& LVIS_FOCUSED
)
2314 /* clear LVIS_FOCUSED states */
2315 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
2316 lvItem
.stateMask
= LVIS_FOCUSED
;
2318 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)-1, (LPARAM
)&lvItem
);
2320 /* set focused item index */
2321 infoPtr
->nFocusedItem
= lpItem
->iItem
;
2324 lpListItem
->state
= lpItem
->state
& lpItem
->stateMask
;
2327 if (lpItem
->mask
& LVIF_IMAGE
)
2328 lpListItem
->iImage
= lpItem
->iImage
;
2330 if (lpItem
->mask
& LVIF_PARAM
)
2331 lpListItem
->lParam
= lpItem
->lParam
;
2333 if (lpItem
->mask
& LVIF_INDENT
)
2334 lpListItem
->iIndent
= lpItem
->iIndent
;
2336 /* insert item in listview control data structure */
2337 nItem
= DPA_InsertPtr(infoPtr
->hdpaItems
, lpItem
->iItem
, lpListItem
);
2341 /* increment item counter */
2342 infoPtr
->nItemCount
++;
2344 /* calculate column width */
2345 if (infoPtr
->himlSmall
!= NULL
)
2346 nColumnWidth
+= nSmallIconWidth
;
2348 /* calculate column width */
2349 if (infoPtr
->himlState
!= NULL
)
2350 nColumnWidth
+= nSmallIconWidth
;
2352 /* set column width */
2353 if (nColumnWidth
> infoPtr
->nColumnWidth
)
2354 infoPtr
->nColumnWidth
= nColumnWidth
;
2356 /* set drawing data */
2357 LISTVIEW_SetScroll(hwnd
);
2359 /* send LVN_INSERTITEM notification */
2360 ZeroMemory (&nmlv
, sizeof (NMLISTVIEW
));
2361 nmlv
.hdr
.hwndFrom
= hwnd
;
2362 nmlv
.hdr
.idFrom
= lCtrlId
;
2363 nmlv
.hdr
.code
= LVN_INSERTITEM
;
2365 SendMessageA(GetParent (hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
2368 InvalidateRect(hwnd
, NULL
, FALSE
);
2374 /* << LISTVIEW_InsertItem32W >> */
2378 * Redraws a range of items.
2381 * [I] HWND32 : window handle
2382 * [I] INT32 : first item
2383 * [I] INT32 : last item
2389 static LRESULT
LISTVIEW_RedrawItems(HWND hwnd
, INT nFirst
, INT nLast
)
2391 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2396 if ((nFirst
< 0) || (nFirst
>= infoPtr
->nItemCount
))
2399 if ((nLast
< 0) || (nLast
>= infoPtr
->nItemCount
))
2409 * Scrolls the content of a listview.
2412 * [I] HWND32 : window handle
2413 * [I] INT32 : amount of horizontal scrolling
2414 * [I] INT32 : amount of vertical scrolling
2420 static LRESULT
LISTVIEW_Scroll(HWND hwnd
, INT nHScroll
, INT nVScroll
)
2422 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2423 BOOL bResult
= FALSE
;
2428 if (lStyle
& LVS_LIST
)
2430 nHScrollPos
= GetScrollPos(hwnd
, SB_HORZ
);
2431 GetScrollRange(hwnd
, SB_HORZ
, &nMinRange
, &nMaxRange
);
2433 if ((nMinRange
<= nHScrollPos
+ nHScroll
) &&
2434 (nHScrollPos
+ nHScroll
<= nMaxRange
))
2437 nHScrollPos
+= nHScroll
;
2438 SetScrollPos(hwnd
, SB_HORZ
, nHScrollPos
, TRUE
);
2440 /* refresh client area */
2441 InvalidateRect(hwnd
, NULL
, TRUE
);
2445 else if (lStyle
& LVS_REPORT
)
2449 else if (lStyle
& LVS_SMALLICON
)
2453 else if (lStyle
& LVS_ICON
)
2463 * Sets the background color.
2466 * [I] HWND32 : window handle
2467 * [I] COLORREF : background color
2473 static LRESULT
LISTVIEW_SetBkColor(HWND hwnd
, COLORREF clrBk
)
2475 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2477 infoPtr
->clrBk
= clrBk
;
2478 InvalidateRect(hwnd
, NULL
, TRUE
);
2485 * Sets column attributes.
2488 * [I] HWND32 : window handle
2489 * [I] INT32 : column index
2490 * [I] LPLVCOLUMN32A : column information
2496 static LRESULT
LISTVIEW_SetColumnA(HWND hwnd
, INT nIndex
,
2497 LPLVCOLUMNA lpColumn
)
2499 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2502 if (lpColumn
== NULL
)
2505 /* initialize memory */
2506 ZeroMemory (&hdi
, sizeof(HDITEMA
));
2508 if (lpColumn
->mask
& LVCF_FMT
)
2511 hdi
.fmt
|= HDF_LEFT
;
2512 else if (lpColumn
->fmt
& LVCFMT_LEFT
)
2513 hdi
.fmt
|= HDF_LEFT
;
2514 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
2515 hdi
.fmt
|= HDF_RIGHT
;
2516 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
2517 hdi
.fmt
|= HDF_CENTER
;
2519 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
2520 hdi
.fmt
|= HDF_IMAGE
;
2522 hdi
.mask
|= HDI_FORMAT
;
2525 if (lpColumn
->mask
& LVCF_WIDTH
)
2527 hdi
.mask
|= HDI_WIDTH
;
2528 hdi
.cxy
= lpColumn
->cx
;
2531 if (lpColumn
->mask
& LVCF_TEXT
)
2533 hdi
.mask
|= (HDI_TEXT
| HDI_FORMAT
);
2534 hdi
.pszText
= lpColumn
->pszText
;
2535 hdi
.fmt
|= HDF_STRING
;
2538 if (lpColumn
->mask
& LVCF_IMAGE
)
2540 hdi
.mask
|= HDI_IMAGE
;
2541 hdi
.iImage
= lpColumn
->iImage
;
2544 if (lpColumn
->mask
& LVCF_ORDER
)
2546 hdi
.mask
|= HDI_ORDER
;
2547 hdi
.iOrder
= lpColumn
->iOrder
;
2550 return (LRESULT
)SendMessageA (infoPtr
->hwndHeader
, HDM_SETITEMA
,
2551 (WPARAM
)nIndex
, (LPARAM
)&hdi
);
2559 * [I] HWND32 : window handle
2560 * [I] INT32 : image list type
2561 * [I] HIMAGELIST : image list handle
2564 * SUCCESS : old image list
2567 static LRESULT
LISTVIEW_SetImageList(HWND hwnd
, INT nType
, HIMAGELIST himl
)
2569 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2570 HIMAGELIST himlTemp
= 0;
2575 himlTemp
= infoPtr
->himlNormal
;
2576 infoPtr
->himlNormal
= himl
;
2577 return (LRESULT
)himlTemp
;
2579 himlTemp
= infoPtr
->himlSmall
;
2580 infoPtr
->himlSmall
= himl
;
2581 return (LRESULT
)himlTemp
;
2583 himlTemp
= infoPtr
->himlState
;
2584 infoPtr
->himlState
= himl
;
2585 return (LRESULT
)himlTemp
;
2588 return (LRESULT
)NULL
;
2594 * Sets item attributes.
2597 * [I] HWND32 : window handle
2598 * [I] LPLVITEM32 : item information
2604 static LRESULT
LISTVIEW_SetItemA(HWND hwnd
, LPLVITEMA lpItem
)
2606 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2607 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2608 LISTVIEW_ITEM
*lpListItem
;
2614 if ((lpItem
->iItem
< 0) || (lpItem
->iItem
>= infoPtr
->nItemCount
))
2617 /* send LVN_ITEMCHANGING notification */
2618 ZeroMemory (&nmlv
, sizeof (NMLISTVIEW
));
2619 nmlv
.hdr
.hwndFrom
= hwnd
;
2620 nmlv
.hdr
.idFrom
= lCtrlId
;
2621 nmlv
.hdr
.code
= LVN_ITEMCHANGING
;
2622 nmlv
.iItem
= lpItem
->iItem
;
2623 nmlv
.iSubItem
= lpItem
->iSubItem
;
2624 nmlv
.uChanged
= lpItem
->mask
;
2625 if (SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
2626 (LPARAM
)&nmlv
) == FALSE
)
2630 lpListItem
= DPA_GetPtr(infoPtr
->hdpaItems
, lpItem
->iItem
);
2631 if (lpListItem
== NULL
)
2634 /* copy valid data */
2635 if (lpItem
->iSubItem
> 0)
2637 /* verify existance of sub-item */
2638 lpListItem
+= lpItem
->iSubItem
;
2639 if (lpListItem
== NULL
)
2642 /* exit if indent attribute is valid */
2643 if (lpItem
->mask
& LVIF_INDENT
)
2646 if (lpItem
->mask
& LVIF_IMAGE
)
2648 /* set sub-item attribute */
2654 if (lpItem
->mask
& LVIF_STATE
)
2656 lpListItem
->state
&= ~lpItem
->stateMask
;
2657 lpListItem
->state
|= (lpItem
->state
& lpItem
->stateMask
);
2660 if (lpItem
->mask
& LVIF_IMAGE
)
2661 lpListItem
->iImage
= lpItem
->iImage
;
2663 if (lpItem
->mask
& LVIF_PARAM
)
2664 lpListItem
->lParam
= lpItem
->lParam
;
2666 if (lpItem
->mask
& LVIF_INDENT
)
2667 lpListItem
->iIndent
= lpItem
->iIndent
;
2670 if (lpItem
->mask
& LVIF_TEXT
)
2672 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2674 if ((lpListItem
->pszText
!= NULL
) &&
2675 (lpListItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2676 COMCTL32_Free (lpListItem
->pszText
);
2678 lpListItem
->pszText
= LPSTR_TEXTCALLBACKA
;
2682 if (lpListItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2683 lpListItem
->pszText
= NULL
;
2685 if (Str_SetPtrA(&lpListItem
->pszText
, lpItem
->pszText
) == FALSE
)
2690 /* send LVN_ITEMCHANGED notification */
2691 nmlv
.hdr
.code
= LVN_ITEMCHANGED
;
2692 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
2698 /* << LISTVIEW_SetItem32W >> */
2700 /* LISTVIEW_SetItemCount*/
2704 * Sets item position.
2707 * [I] HWND32 : window handle
2708 * [I] INT32 : item index
2709 * [I] INT32 : x coordinate
2710 * [I] INT32 : y coordinate
2716 static LRESULT
LISTVIEW_SetItemPosition(HWND hwnd
, INT nItem
,
2717 INT nPosX
, INT nPosY
)
2719 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2720 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2722 if ((nItem
< 0) || (nItem
>= infoPtr
->nItemCount
))
2725 if ((lStyle
& LVS_ICON
) && (lStyle
& LVS_SMALLICON
))
2729 /* set position of item */
2732 if (lStyle
& LVS_AUTOARRANGE
)
2734 InvalidateRect(hwnd
, NULL
, FALSE
);
2746 * Sets the state of one or many items.
2749 * [I] HWND32 : window handle
2750 * [I]INT32 : item index
2751 * [I] LPLVITEM32 : item information
2757 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
,
2760 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2761 LISTVIEW_ITEM
*lpListItem
;
2766 /* apply to all the items */
2767 for (i
= 0; i
< infoPtr
->nItemCount
; i
++)
2769 lpListItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
2770 if (lpListItem
== NULL
)
2773 lpListItem
->state
&= ~lpItem
->stateMask
;
2774 lpListItem
->state
|= (lpItem
->state
& lpItem
->stateMask
);
2777 else if ((nItem
>= 0) && (nItem
< infoPtr
->nItemCount
))
2779 lpListItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
2780 if (lpListItem
== NULL
)
2784 lpListItem
->state
&= ~lpItem
->stateMask
;
2785 lpListItem
->state
|= (lpItem
->state
& lpItem
->stateMask
);
2795 * Sets the text background color.
2798 * [I] HWND32 : window handle
2799 * [I] COLORREF : text background color
2805 static LRESULT
LISTVIEW_SetTextBkColor(HWND hwnd
, COLORREF clrTextBk
)
2807 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2809 infoPtr
->clrTextBk
= clrTextBk
;
2816 * Sets the text background color.
2819 * [I] HWND32 : window handle
2820 * [I] COLORREF : text color
2826 static LRESULT
LISTVIEW_SetTextColor (HWND hwnd
, COLORREF clrText
)
2828 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2830 infoPtr
->clrText
= clrText
;
2840 * [I] HWND32 : window handle
2846 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2848 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLong32A(hwnd, 0); */
2850 FIXME (listview
, "empty stub!\n");
2860 * [I] HWND32 : window handle
2861 * [I] INT32 : item index
2867 static LRESULT
LISTVIEW_Update(HWND hwnd
, INT nItem
)
2869 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2870 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2872 BOOL bResult
= FALSE
;
2874 if ((nItem
>= 0) || (nItem
< infoPtr
->nItemCount
))
2876 /* get item bounding rectangle */
2877 rcItemRect
.left
= LVIR_BOUNDS
;
2878 SendMessageA(hwnd
, LVM_GETITEMRECT
, (WPARAM
)nItem
,
2879 (LPARAM
)&rcItemRect
);
2881 InvalidateRect(hwnd
, &rcItemRect
, FALSE
);
2883 /* rearrange with default alignment style */
2884 if ((lStyle
& LVS_AUTOARRANGE
) &&
2885 ((lStyle
& LVS_ICON
) || (lStyle
& LVS_SMALLICON
)))
2886 SendMessageA(hwnd
, LVM_ARRANGE
, (WPARAM
)LVA_DEFAULT
, (LPARAM
)0);
2894 * Creates a listview control.
2897 * [I] HWND32 : window handle
2902 static LRESULT
LISTVIEW_Create(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2904 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2905 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2910 INT nSmallIconHeight
;
2912 /* initialize color information */
2913 infoPtr
->clrBk
= GetSysColor(COLOR_WINDOW
);
2914 infoPtr
->clrText
= GetSysColor(COLOR_WINDOWTEXT
);
2915 infoPtr
->clrTextBk
= GetSysColor(COLOR_WINDOW
);
2917 /* get default font (icon title) */
2918 SystemParametersInfoA (SPI_GETICONTITLELOGFONT
, 0, &logFont
, 0);
2919 infoPtr
->hDefaultFont
= CreateFontIndirectA (&logFont
);
2920 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
2922 /* initialize column width */
2923 infoPtr
->nColumnWidth
= 96;
2925 /* get text height */
2927 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
2928 GetTextMetricsA(hdc
, &tm
);
2930 /* initialize item height with padding */
2931 if (!(lStyle
& LVS_ICON
))
2933 nSmallIconHeight
= GetSystemMetrics(SM_CYSMICON
);
2934 infoPtr
->nItemHeight
= max(tm
.tmHeight
, nSmallIconHeight
) + 2;
2937 SelectObject(hdc
, hOldFont
);
2938 ReleaseDC(hwnd
, hdc
);
2941 infoPtr
->hwndHeader
= CreateWindowA(WC_HEADERA
, "", lStyle
, 0, 0, 0, 0,
2943 GetWindowLongA(hwnd
, GWL_HINSTANCE
),
2945 /* set header font */
2946 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)infoPtr
->hFont
,
2949 /* allocate memory */
2950 infoPtr
->hdpaItems
= DPA_Create (10);
2957 LISTVIEW_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2959 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2961 /* delete all items */
2962 LISTVIEW_DeleteAllItems(hwnd
);
2965 DPA_Destroy (infoPtr
->hdpaItems
);
2967 /* destroy header */
2968 if (infoPtr
->hwndHeader
)
2969 DestroyWindow (infoPtr
->hwndHeader
);
2972 infoPtr
->hFont
= (HFONT
)0;
2973 if (infoPtr
->hDefaultFont
)
2974 DeleteObject (infoPtr
->hDefaultFont
);
2976 infoPtr
->nColumnWidth
= 96;
2983 * Erases the background of the listview control
2986 * [I] HWND32 : window handle
2992 static LRESULT
LISTVIEW_EraseBackground(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
2994 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2997 if (infoPtr
->clrBk
== CLR_NONE
)
2998 bResult
= SendMessageA(GetParent(hwnd
), WM_ERASEBKGND
, wParam
, lParam
);
3001 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
3004 GetClientRect(hwnd
, &clientRect
);
3005 FillRect((HDC
)wParam
, &clientRect
, hBrush
);
3006 DeleteObject(hBrush
);
3015 * Gets the listview control font.
3018 * [I] HWND32 : window handle
3023 static LRESULT
LISTVIEW_GetFont(HWND hwnd
)
3025 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3027 return infoPtr
->hFont
;
3032 * Performs horizontal scrolling.
3035 * [I] HWND32 : window handle
3036 * [I] INT32 : scroll code
3037 * [I] INT32 : scroll position
3038 * [I] HWND32 : scrollbar control window handle
3043 static LRESULT
LISTVIEW_HScroll(HWND hwnd
, INT nScrollCode
,
3044 INT nScrollPos
, HWND hScrollWnd
)
3046 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3051 GetScrollRange(hwnd
, SB_HORZ
, &nMinRange
, &nMaxRange
);
3052 nHScrollPos
= GetScrollPos(hwnd
, SB_HORZ
);
3054 if (lStyle
& LVS_LIST
)
3056 switch (nScrollCode
)
3059 if (nHScrollPos
> nMinRange
)
3063 if (nHScrollPos
< nMaxRange
)
3067 if (nHScrollPos
> nMinRange
)
3071 if (nHScrollPos
< nMaxRange
)
3074 case SB_THUMBPOSITION
:
3075 nHScrollPos
= nScrollPos
;
3079 SetScrollPos(hwnd
, SB_HORZ
, nHScrollPos
, TRUE
);
3081 /* refresh client area */
3082 InvalidateRect(hwnd
, NULL
, TRUE
);
3094 * [I] HWND32 : window handle
3095 * [I] INT32 : virtual key
3096 * [I] LONG : key data
3101 static LRESULT
LISTVIEW_KeyDown(HWND hwnd
, INT nVirtualKey
, LONG lKeyData
)
3103 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3104 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3105 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3106 HWND hwndParent
= GetParent(hwnd
);
3107 INT nItemCountPerColumn
;
3108 INT nItemCountPerRow
;
3111 /* NMLVKEYDOWN nmKeyDown; */
3113 /* send LVN_KEYDOWN notification */
3114 /* nmh.hwndFrom = hwnd; */
3115 /* nmh.idFrom = lCtrlId; */
3116 /* nmh.code = LVN_KEYDOWN; */
3117 /* nmKeyDown.hdr = nmh; */
3118 /* nmKeyDown..wVKey = nVirtualKey; */
3119 /* nmKeyCode.flags = 0; */
3120 /* SendMessage32A(hwndParent, WM_NOTIFY, (WPARAM32)lCtrlId, (LPARAM)&nmKeyDown); */
3122 switch (nVirtualKey
)
3125 if ((infoPtr
->nItemCount
> 0) && (infoPtr
->nFocusedItem
!= -1))
3127 /* send NM_RETURN notification */
3128 nmh
.code
= NM_RETURN
;
3129 SendMessageA(hwndParent
, WM_NOTIFY
, (WPARAM
)lCtrlId
, (LPARAM
)&nmh
);
3131 /* send LVN_ITEMACTIVATE notification */
3132 nmh
.code
= LVN_ITEMACTIVATE
;
3133 SendMessageA(hwndParent
, WM_NOTIFY
, (WPARAM
)lCtrlId
, (LPARAM
)&nmh
);
3138 if (infoPtr
->nItemCount
> 0)
3140 /* set item state(s) */
3141 infoPtr
->nFocusedItem
= 0;
3142 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3144 /* make item visible */
3145 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3150 if (infoPtr
->nItemCount
> 0)
3152 /* set item state(s) */
3153 infoPtr
->nFocusedItem
= infoPtr
->nItemCount
- 1;
3154 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3156 /* make item visible */
3157 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3163 if (lStyle
& LVS_LIST
)
3165 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
3166 if (infoPtr
->nFocusedItem
>= nItemCountPerColumn
)
3168 /* set item state(s) */
3169 infoPtr
->nFocusedItem
-= nItemCountPerColumn
;
3170 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3172 /* make item visible */
3173 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3176 else if (lStyle
& LVS_REPORT
)
3178 /* TO DO ; does not affect the focused item, it only scrolls */
3180 else if ((lStyle
& LVS_SMALLICON
) || (lStyle
& LVS_ICON
))
3182 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
3183 nColumn
= infoPtr
->nFocusedItem
% nItemCountPerRow
;
3186 infoPtr
->nFocusedItem
-= 1;
3187 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3189 /* refresh display */
3190 InvalidateRect(hwnd
, NULL
, FALSE
);
3197 if ((lStyle
& LVS_LIST
) || (lStyle
& LVS_REPORT
))
3199 if (infoPtr
->nFocusedItem
> 0)
3201 infoPtr
->nFocusedItem
-= 1;
3202 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3204 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3207 else if ((lStyle
& LVS_SMALLICON
) || (lStyle
& LVS_ICON
))
3209 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
3210 if (infoPtr
->nFocusedItem
>= nItemCountPerRow
)
3212 infoPtr
->nFocusedItem
-= nItemCountPerRow
;
3213 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3215 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3221 if (lStyle
& LVS_LIST
)
3223 nItemCountPerColumn
= LISTVIEW_GetItemCountPerColumn(hwnd
);
3224 if (infoPtr
->nFocusedItem
< infoPtr
->nItemCount
- nItemCountPerColumn
)
3226 infoPtr
->nFocusedItem
+= nItemCountPerColumn
;
3227 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3229 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3232 else if (lStyle
& LVS_REPORT
)
3235 else if ((lStyle
& LVS_SMALLICON
) || (lStyle
& LVS_ICON
))
3237 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
3238 nColumn
= infoPtr
->nFocusedItem
% nItemCountPerRow
;
3239 if (nColumn
!= nItemCountPerRow
- 1)
3241 infoPtr
->nFocusedItem
+= 1;
3242 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3244 /* refresh display */
3245 InvalidateRect(hwnd
, NULL
, FALSE
);
3253 if ((lStyle
& LVS_LIST
) || (lStyle
& LVS_REPORT
))
3255 if (infoPtr
->nFocusedItem
< infoPtr
->nItemCount
- 1)
3257 infoPtr
->nFocusedItem
+= 1;
3258 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3260 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3263 else if ((lStyle
& LVS_SMALLICON
) || (lStyle
& LVS_ICON
))
3265 nItemCountPerRow
= LISTVIEW_GetItemCountPerRow(hwnd
);
3266 if (infoPtr
->nFocusedItem
< infoPtr
->nItemCount
- nItemCountPerRow
)
3268 infoPtr
->nFocusedItem
+= nItemCountPerRow
;
3269 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, FALSE
);
3271 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3291 * [I] HWND32 : window handle
3296 static LRESULT
LISTVIEW_KillFocus(HWND hwnd
)
3298 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3299 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3302 nmh
.hwndFrom
= hwnd
;
3303 nmh
.idFrom
= lCtrlId
;
3304 nmh
.code
= NM_KILLFOCUS
;
3305 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3308 /* set window focus flag */
3309 infoPtr
->bFocus
= FALSE
;
3316 * Left mouse button double click.
3319 * [I] HWND32 : window handle
3320 * [I] WORD : key flag
3321 * [I] WORD : x coordinate
3322 * [I] WORD : y coordinate
3327 static LRESULT
LISTVIEW_LButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
3330 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3333 /* send NM_DBLCLK notification */
3334 nmh
.hwndFrom
= hwnd
;
3335 nmh
.idFrom
= lCtrlId
;
3336 nmh
.code
= NM_DBLCLK
;
3337 SendMessageA(GetParent (hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3340 /* send LVN_ITEMACTIVATE notification */
3341 nmh
.code
= LVN_ITEMACTIVATE
;
3342 SendMessageA(GetParent (hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3350 * Left mouse button down.
3353 * [I] HWND32 : window handle
3354 * [I] WORD : key flag
3355 * [I] WORD : x coordinate
3356 * [I] WORD : y coordinate
3361 static LRESULT
LISTVIEW_LButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
3364 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3365 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3366 LVHITTESTINFO hitTestInfo
;
3371 /* send NM_RELEASEDCAPTURE notification */
3372 nmh
.hwndFrom
= hwnd
;
3373 nmh
.idFrom
= lCtrlId
;
3374 nmh
.code
= NM_RELEASEDCAPTURE
;
3375 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3378 if (infoPtr
->bFocus
== FALSE
)
3381 /* set left button down flag */
3382 infoPtr
->bLButtonDown
= TRUE
;
3384 /* set left button hit coordinates */
3385 hitTestInfo
.pt
.x
= wPosX
;
3386 hitTestInfo
.pt
.y
= wPosY
;
3388 /* perform hit test */
3389 nItem
= SendMessageA(hwnd
, LVM_HITTEST
, (WPARAM
)0, (LPARAM
)&hitTestInfo
);
3390 if ((nItem
>= 0) && (nItem
< infoPtr
->nItemCount
))
3392 /* perform state changes (selection and focus) */
3393 infoPtr
->nFocusedItem
= nItem
;
3394 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, TRUE
, TRUE
);
3396 /* scroll intem into view if doing a multiple selection */
3398 if ((wKey
& MK_CONTROL
) || (wKey
& MK_SHIFT
))
3400 LISTVIEW_SetVisible(hwnd
, infoPtr
->nFocusedItem
);
3404 /* refresh display */
3405 InvalidateRect(hwnd
, NULL
, FALSE
);
3411 /* clear selection(s) */
3412 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
3413 lvItem
.stateMask
= LVIS_SELECTED
;
3415 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)-1, (LPARAM
)&lvItem
);
3417 /* repaint everything */
3418 InvalidateRect(hwnd
, NULL
, FALSE
);
3427 * Left mouse button up.
3430 * [I] HWND32 : window handle
3431 * [I] WORD : key flag
3432 * [I] WORD : x coordinate
3433 * [I] WORD : y coordinate
3438 static LRESULT
LISTVIEW_LButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
3441 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3442 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3445 if (infoPtr
->bLButtonDown
== TRUE
)
3447 /* send NM_CLICK notification */
3448 nmh
.hwndFrom
= hwnd
;
3449 nmh
.idFrom
= lCtrlId
;
3450 nmh
.code
= NM_CLICK
;
3451 SendMessageA(GetParent (hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3455 /* set left button flag */
3456 infoPtr
->bLButtonDown
= FALSE
;
3463 * Creates the listview control (called before WM_CREATE).
3466 * [I] HWND32 : window handle
3467 * [I] WPARAM32 : unhandled
3468 * [I] LPARAM : widow creation info
3473 static LRESULT
LISTVIEW_NCCreate(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
3475 LISTVIEW_INFO
*infoPtr
;
3477 /* allocate memory for info structure */
3478 infoPtr
= (LISTVIEW_INFO
*)COMCTL32_Alloc (sizeof(LISTVIEW_INFO
));
3479 SetWindowLongA(hwnd
, 0, (LONG
)infoPtr
);
3480 if (infoPtr
== NULL
)
3482 ERR (listview
, "could not allocate info memory!\n");
3486 if ((LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0) != infoPtr
)
3488 ERR (listview
, "pointer assignment error!\n");
3492 return DefWindowProcA(hwnd
, WM_NCCREATE
, wParam
, lParam
);
3497 * Destroys the listview control (called after WM_DESTROY).
3500 * [I] HWND32 : window handle
3505 static LRESULT
LISTVIEW_NCDestroy(HWND hwnd
)
3507 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3509 /* free list view info data */
3510 COMCTL32_Free (infoPtr
);
3517 * Handles notification from children.
3520 * [I] HWND32 : window handle
3521 * [I] INT32 : control identifier
3522 * [I] LPNMHDR : notification information
3527 static LRESULT
LISTVIEW_Notify(HWND hwnd
, INT nCtrlId
, LPNMHDR lpnmh
)
3529 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3531 if (lpnmh
->hwndFrom
== infoPtr
->hwndHeader
)
3533 /* handle notification from header control */
3534 FIXME (listview
, "WM_NOTIFY from header!\n");
3538 /* handle notification from unknown source */
3539 FIXME (listview
, "WM_NOTIFY from unknown source!\n");
3547 * Draws the listview control.
3550 * [I] HWND32 : window handle
3551 * [I] HDC32 : device context handle
3556 static LRESULT
LISTVIEW_Paint(HWND hwnd
, HDC hdc
)
3562 hdc
= BeginPaint(hwnd
, &ps
);
3563 LISTVIEW_Refresh(hwnd
, hdc
);
3564 EndPaint(hwnd
, &ps
);
3567 LISTVIEW_Refresh(hwnd
, hdc
);
3574 * Right mouse button double clisk.
3577 * [I] HWND32 : window handle
3578 * [I] WORD : key flag
3579 * [I] WORD : x coordinate
3580 * [I] WORD : y coordinate
3585 static LRESULT
LISTVIEW_RButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
3588 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3591 /* send NM_RELEASEDCAPTURE notification */
3592 nmh
.hwndFrom
= hwnd
;
3593 nmh
.idFrom
= lCtrlId
;
3594 nmh
.code
= NM_RELEASEDCAPTURE
;
3595 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3598 /* send NM_RDBLCLK notification */
3599 nmh
.code
= NM_RDBLCLK
;
3600 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3608 * Right mouse button input.
3611 * [I] HWND32 : window handle
3612 * [I] WORD : key flag
3613 * [I] WORD : x coordinate
3614 * [I] WORD : y coordinate
3619 static LRESULT
LISTVIEW_RButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
3622 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3623 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3624 LVHITTESTINFO hitTestInfo
;
3629 /* The syslistview32 control sends a NM_RELEASEDCAPTURE notification.
3630 I do not know why, but I decided to send it as well for compatibility
3632 ZeroMemory(&nmh
, sizeof(NMHDR
));
3633 nmh
.hwndFrom
= hwnd
;
3634 nmh
.idFrom
= lCtrlId
;
3635 nmh
.code
= NM_RELEASEDCAPTURE
;
3636 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3639 /* make sure listview control has focus */
3640 if (infoPtr
->bFocus
== FALSE
)
3643 /* set left button down flag */
3644 infoPtr
->bRButtonDown
= TRUE
;
3646 /* set hit coordinates */
3647 hitTestInfo
.pt
.x
= wPosX
;
3648 hitTestInfo
.pt
.y
= wPosY
;
3650 /* perform hit test */
3651 nItem
= SendMessageA(hwnd
, LVM_HITTEST
, (WPARAM
)0, (LPARAM
)&hitTestInfo
);
3652 if ((nItem
>= 0) && (nItem
< infoPtr
->nItemCount
))
3654 /* perform state changes (selection and focus) */
3655 infoPtr
->nFocusedItem
= nItem
;
3656 LISTVIEW_SetItemStates(hwnd
, infoPtr
->nFocusedItem
, FALSE
, TRUE
);
3660 /* clear selection(s) */
3661 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
3662 lvItem
.stateMask
= LVIS_SELECTED
;
3664 SendMessageA(hwnd
, LVM_SETITEMSTATE
, (WPARAM
)-1, (LPARAM
)&lvItem
);
3667 /* repaint everything */
3668 InvalidateRect(hwnd
, NULL
, FALSE
);
3676 * Right mouse button up.
3679 * [I] HWND32 : window handle
3680 * [I] WORD : key flag
3681 * [I] WORD : x coordinate
3682 * [I] WORD : y coordinate
3687 static LRESULT
LISTVIEW_RButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
3690 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3691 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3694 if (infoPtr
->bRButtonDown
== TRUE
)
3696 /* initialize notification information */
3697 ZeroMemory(&nmh
, sizeof(NMHDR
));
3698 nmh
.hwndFrom
= hwnd
;
3699 nmh
.idFrom
= lCtrlId
;
3700 nmh
.code
= NM_RCLICK
;
3701 SendMessageA(GetParent (hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3705 /* set button flag */
3706 infoPtr
->bRButtonDown
= FALSE
;
3716 * [I] HWND32 : window handle
3717 * [I] HWND32 : window handle of previously focused window
3722 static LRESULT
LISTVIEW_SetFocus(HWND hwnd
, HWND hwndLoseFocus
)
3724 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3725 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3728 /* send NM_SETFOCUS notification */
3729 nmh
.hwndFrom
= hwnd
;
3730 nmh
.idFrom
= lCtrlId
;
3731 nmh
.code
= NM_SETFOCUS
;
3732 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
3735 /* set window focus flag */
3736 infoPtr
->bFocus
= TRUE
;
3746 * [I] HWND32 : window handle
3747 * [I] HFONT32 : font handle
3748 * [I] WORD : redraw flag
3753 static LRESULT
LISTVIEW_SetFont(HWND hwnd
, HFONT hFont
, WORD fRedraw
)
3755 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3756 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3760 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
3764 infoPtr
->hFont
= hFont
;
3767 if (lStyle
& LVS_REPORT
)
3769 /* set font of header */
3770 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)hFont
,
3771 MAKELPARAM(fRedraw
, 0));
3774 /* invalidate listview control client area */
3775 InvalidateRect(hwnd
, NULL
, FALSE
);
3777 if (fRedraw
== TRUE
)
3785 * Resizes the listview control.
3788 * [I] HWND32 : window handle
3789 * [I] WORD : new width
3790 * [I] WORD : new height
3795 static LRESULT
LISTVIEW_Size(HWND hwnd
, WORD wWidth
, WORD wHeight
)
3797 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3798 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3801 if (lStyle
& LVS_LIST
)
3803 if (!(lStyle
& WS_HSCROLL
))
3805 nHScrollHeight
= GetSystemMetrics(SM_CYHSCROLL
);
3806 if (wHeight
> nHScrollHeight
)
3807 wHeight
-= nHScrollHeight
;
3810 infoPtr
->nHeight
= (INT
)wHeight
;
3811 infoPtr
->nWidth
= (INT
)wWidth
;
3814 /* set scrollbar(s) if needed */
3815 LISTVIEW_SetScroll(hwnd
);
3817 /* refresh client area */
3818 InvalidateRect(hwnd
, NULL
, TRUE
);
3826 * Window procedure of the listview control.
3837 LRESULT WINAPI
LISTVIEW_WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
,
3842 case LVM_APPROXIMATEVIEWRECT
:
3843 return LISTVIEW_ApproximateViewRect(hwnd
, (INT
)wParam
,
3844 LOWORD(lParam
), HIWORD(lParam
));
3846 return LISTVIEW_Arrange(hwnd
, (INT
)wParam
);
3848 /* case LVM_CREATEDRAGIMAGE: */
3850 case LVM_DELETEALLITEMS
:
3851 return LISTVIEW_DeleteAllItems(hwnd
);
3853 case LVM_DELETECOLUMN
:
3854 return LISTVIEW_DeleteColumn(hwnd
, (INT
)wParam
);
3856 case LVM_DELETEITEM
:
3857 return LISTVIEW_DeleteItem(hwnd
, (INT
)wParam
);
3859 /* case LVM_EDITLABEL: */
3860 /* case LVM_ENSUREVISIBLE: */
3863 return LISTVIEW_FindItem(hwnd
, (INT
)wParam
, (LPLVFINDINFO
)lParam
);
3865 case LVM_GETBKCOLOR
:
3866 return LISTVIEW_GetBkColor(hwnd
);
3868 /* case LVM_GETBKIMAGE: */
3869 /* case LVM_GETCALLBACKMASK: */
3871 case LVM_GETCOLUMNA
:
3872 return LISTVIEW_GetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
3874 /* case LVM_GETCOLUMN32W: */
3875 /* case LVM_GETCOLUMNORDERARRAY: */
3877 case LVM_GETCOLUMNWIDTH
:
3878 return LISTVIEW_GetColumnWidth(hwnd
, (INT
)wParam
);
3880 case LVM_GETCOUNTPERPAGE
:
3881 return LISTVIEW_GetCountPerPage(hwnd
);
3883 /* case LVM_GETEDITCONTROL: */
3884 /* case LVM_GETEXTENDEDLISTVIEWSTYLE: */
3887 return LISTVIEW_GetHeader(hwnd
);
3889 /* case LVM_GETHOTCURSOR: */
3890 /* case LVM_GETHOTITEM: */
3891 /* case LVM_GETHOVERTIME: */
3893 case LVM_GETIMAGELIST
:
3894 return LISTVIEW_GetImageList(hwnd
, (INT
)wParam
);
3896 /* case LVM_GETISEARCHSTRING: */
3899 return LISTVIEW_GetItemA(hwnd
, (LPLVITEMA
)lParam
);
3901 /* case LVM_GETITEM32W: */
3903 case LVM_GETITEMCOUNT
:
3904 return LISTVIEW_GetItemCount(hwnd
);
3906 case LVM_GETITEMPOSITION
:
3907 return LISTVIEW_GetItemPosition(hwnd
, (INT
)wParam
, (LPPOINT
)lParam
);
3909 case LVM_GETITEMRECT
:
3910 return LISTVIEW_GetItemRect(hwnd
, (INT
)wParam
, (LPRECT
)lParam
);
3912 case LVM_GETITEMSPACING
:
3913 return LISTVIEW_GetItemSpacing(hwnd
, (BOOL
)wParam
);
3915 case LVM_GETITEMSTATE
:
3916 return LISTVIEW_GetItemState(hwnd
, (INT
)wParam
, (UINT
)lParam
);
3918 case LVM_GETITEMTEXTA
:
3919 LISTVIEW_GetItemTextA(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
3922 /* case LVM_GETITEMTEXT32W: */
3924 case LVM_GETNEXTITEM
:
3925 return LISTVIEW_GetNextItem(hwnd
, (INT
)wParam
, LOWORD(lParam
));
3927 /* case LVM_GETNUMBEROFWORKAREAS: */
3929 return LISTVIEW_GetOrigin(hwnd
, (LPPOINT
)lParam
);
3931 case LVM_GETSELECTEDCOUNT
:
3932 return LISTVIEW_GetSelectedCount(hwnd
);
3934 case LVM_GETSELECTIONMARK
:
3935 return LISTVIEW_GetSelectionMark(hwnd
);
3937 case LVM_GETSTRINGWIDTHA
:
3938 return LISTVIEW_GetStringWidthA (hwnd
, (LPCSTR
)lParam
);
3940 /* case LVM_GETSTRINGWIDTH32W: */
3941 /* case LVM_GETSUBITEMRECT: */
3943 case LVM_GETTEXTBKCOLOR
:
3944 return LISTVIEW_GetTextBkColor(hwnd
);
3946 case LVM_GETTEXTCOLOR
:
3947 return LISTVIEW_GetTextColor(hwnd
);
3949 /* case LVM_GETTOOLTIPS: */
3950 /* case LVM_GETTOPINDEX: */
3951 /* case LVM_GETUNICODEFORMAT: */
3953 case LVM_GETVIEWRECT
:
3954 return LISTVIEW_GetViewRect(hwnd
, (LPRECT
)lParam
);
3956 /* case LVM_GETWORKAREAS: */
3959 return LISTVIEW_HitTest(hwnd
, (LPLVHITTESTINFO
)lParam
);
3961 case LVM_INSERTCOLUMNA
:
3962 return LISTVIEW_InsertColumnA(hwnd
, (INT
)wParam
,
3963 (LPLVCOLUMNA
)lParam
);
3965 /* case LVM_INSERTCOLUMN32W: */
3967 case LVM_INSERTITEMA
:
3968 return LISTVIEW_InsertItemA(hwnd
, (LPLVITEMA
)lParam
);
3970 /* case LVM_INSERTITEM32W: */
3972 case LVM_REDRAWITEMS
:
3973 return LISTVIEW_RedrawItems(hwnd
, (INT
)wParam
, (INT
)lParam
);
3976 return LISTVIEW_Scroll(hwnd
, (INT
)wParam
, (INT
)lParam
);
3978 case LVM_SETBKCOLOR
:
3979 return LISTVIEW_SetBkColor(hwnd
, (COLORREF
)lParam
);
3981 /* case LVM_SETBKIMAGE: */
3982 /* case LVM_SETCALLBACKMASK: */
3984 case LVM_SETCOLUMNA
:
3985 return LISTVIEW_SetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
3987 /* case LVM_SETCOLUMN32W: */
3988 /* case LVM_SETCOLUMNORDERARRAY: */
3989 /* case LVM_SETCOLUMNWIDTH: */
3990 /* case LVM_SETEXTENDEDLISTVIEWSTYLE: */
3991 /* case LVM_SETHOTCURSOR: */
3992 /* case LVM_SETHOTITEM: */
3993 /* case LVM_SETHOVERTIME: */
3994 /* case LVM_SETICONSPACING: */
3996 case LVM_SETIMAGELIST
:
3997 return LISTVIEW_SetImageList(hwnd
, (INT
)wParam
, (HIMAGELIST
)lParam
);
4000 return LISTVIEW_SetItemA(hwnd
, (LPLVITEMA
)lParam
);
4002 /* case LVM_SETITEM32W: */
4003 /* case LVM_SETITEMCOUNT: */
4005 case LVM_SETITEMPOSITION16
:
4006 return LISTVIEW_SetItemPosition(hwnd
, (INT
)wParam
,
4007 (INT
)LOWORD(lParam
),
4008 (INT
) HIWORD(lParam
));
4010 /* case LVM_SETITEMPOSITION32: */
4012 case LVM_SETITEMSTATE
:
4013 return LISTVIEW_SetItemState(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
4015 /* case LVM_SETITEMTEXT: */
4016 /* case LVM_SETSELECTIONMARK: */
4018 case LVM_SETTEXTBKCOLOR
:
4019 return LISTVIEW_SetTextBkColor(hwnd
, (COLORREF
)lParam
);
4021 case LVM_SETTEXTCOLOR
:
4022 return LISTVIEW_SetTextColor(hwnd
, (COLORREF
)lParam
);
4024 /* case LVM_SETTOOLTIPS: */
4025 /* case LVM_SETUNICODEFORMAT: */
4026 /* case LVM_SETWORKAREAS: */
4029 return LISTVIEW_SortItems(hwnd
, wParam
, lParam
);
4031 /* case LVM_SUBITEMHITTEST: */
4034 return LISTVIEW_Update(hwnd
, (INT
)wParam
);
4037 /* case WM_COMMAND: */
4040 return LISTVIEW_Create(hwnd
, wParam
, lParam
);
4043 return LISTVIEW_Destroy(hwnd
, wParam
, lParam
);
4046 return LISTVIEW_EraseBackground (hwnd
, wParam
, lParam
);
4049 return DLGC_WANTTAB
| DLGC_WANTARROWS
;
4052 return LISTVIEW_GetFont(hwnd
);
4055 return LISTVIEW_HScroll(hwnd
, (INT
)LOWORD(wParam
),
4056 (INT
)HIWORD(wParam
), (HWND
)lParam
);
4059 return LISTVIEW_KeyDown(hwnd
, (INT
)wParam
, (LONG
)lParam
);
4062 return LISTVIEW_KillFocus(hwnd
);
4064 case WM_LBUTTONDBLCLK
:
4065 return LISTVIEW_LButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
4068 case WM_LBUTTONDOWN
:
4069 return LISTVIEW_LButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
4072 return LISTVIEW_LButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
4075 /* case WM_MOUSEMOVE: */
4076 /* return LISTVIEW_MouseMove (hwnd, wParam, lParam); */
4079 return LISTVIEW_NCCreate(hwnd
, wParam
, lParam
);
4082 return LISTVIEW_NCDestroy(hwnd
);
4085 return LISTVIEW_Notify(hwnd
, (INT
)wParam
, (LPNMHDR
)lParam
);
4088 return LISTVIEW_Paint(hwnd
, (HDC
)wParam
);
4090 case WM_RBUTTONDBLCLK
:
4091 return LISTVIEW_RButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
4094 case WM_RBUTTONDOWN
:
4095 return LISTVIEW_RButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
4099 return LISTVIEW_RButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
4103 return LISTVIEW_SetFocus(hwnd
, (HWND
)wParam
);
4106 return LISTVIEW_SetFont(hwnd
, (HFONT
)wParam
, (WORD
)lParam
);
4108 /* case WM_SETREDRAW: */
4111 return LISTVIEW_Size(hwnd
, LOWORD(lParam
), HIWORD(lParam
));
4113 /* case WM_TIMER: */
4114 /* case WM_VSCROLL: */
4115 /* case WM_WINDOWPOSCHANGED: */
4116 /* case WM_WININICHANGE: */
4119 if (uMsg
>= WM_USER
)
4120 ERR (listview
, "unknown msg %04x wp=%08x lp=%08lx\n",
4121 uMsg
, wParam
, lParam
);
4123 /* call default window procedure */
4124 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
4132 * Registers the window class.
4140 VOID
LISTVIEW_Register(VOID
)
4144 if (!GlobalFindAtomA(WC_LISTVIEWA
))
4146 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
4147 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
4148 wndClass
.lpfnWndProc
= (WNDPROC
)LISTVIEW_WindowProc
;
4149 wndClass
.cbClsExtra
= 0;
4150 wndClass
.cbWndExtra
= sizeof(LISTVIEW_INFO
*);
4151 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
4152 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
4153 wndClass
.lpszClassName
= WC_LISTVIEWA
;
4154 RegisterClassA (&wndClass
);
4160 * Unregisters the window class.
4168 VOID
LISTVIEW_Unregister(VOID
)
4170 if (GlobalFindAtomA (WC_LISTVIEWA
))
4171 UnregisterClassA (WC_LISTVIEWA
, (HINSTANCE
)NULL
);