4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999 Luc Tourangeau
6 * Copyright 2000 Jason Mawdsley
9 * Listview control implementation.
12 * 1. No horizontal scrolling when header is larger than the client area.
13 * 2. Drawing optimizations.
14 * 3. Hot item handling.
17 * LISTVIEW_Notify : most notifications from children (editbox and header)
20 * LISTVIEW_SetItemCount : not completed for non OWNERDATA
23 * LISTVIEW_SetItemW : no unicode support
24 * LISTVIEW_InsertItemW : no unicode support
25 * LISTVIEW_InsertColumnW : no unicode support
26 * LISTVIEW_GetColumnW : no unicode support
27 * LISTVIEW_SetColumnW : no unicode support
29 * Advanced functionality:
30 * LISTVIEW_GetNumberOfWorkAreas : not implemented
31 * LISTVIEW_GetHotCursor : not implemented
32 * LISTVIEW_GetISearchString : not implemented
33 * LISTVIEW_GetBkImage : not implemented
34 * LISTVIEW_SetBkImage : not implemented
35 * LISTVIEW_GetColumnOrderArray : simple hack only
36 * LISTVIEW_SetColumnOrderArray : simple hack only
37 * LISTVIEW_Arrange : empty stub
38 * LISTVIEW_ApproximateViewRect : incomplete
39 * LISTVIEW_Scroll : not implemented
40 * LISTVIEW_Update : not completed
50 #include "debugtools.h"
52 DEFAULT_DEBUG_CHANNEL(listview
);
54 /* Some definitions for inline edit control */
55 typedef BOOL (*EditlblCallback
)(HWND
, LPSTR
, DWORD
);
57 typedef struct tagEDITLABEL_ITEM
61 EditlblCallback EditLblCb
;
64 typedef struct tagLISTVIEW_SUBITEM
72 typedef struct tagLISTVIEW_ITEM
83 typedef struct tagLISTVIEW_SELECTION
89 typedef struct tagLISTVIEW_INFO
94 HIMAGELIST himlNormal
;
100 HDPA hdpaSelectionRanges
;
115 DWORD dwExStyle
; /* extended listview style */
117 PFNLVCOMPARE pfnCompare
;
121 EDITLABEL_ITEM
*pedititem
;
123 INT nColumnCount
; /* the number of columns in this control */
125 WPARAM charCode
; /* Added */
126 CHAR szSearchParam
[ MAX_PATH
]; /* Added */
127 DWORD timeSinceLastKeyPress
; /* Added */
128 INT nSearchParamLength
; /* Added */
135 /* maximum size of a label */
136 #define DISP_TEXT_SIZE 512
138 /* padding for items in list and small icon display modes */
139 #define WIDTH_PADDING 12
141 /* padding for items in list, report and small icon display modes */
142 #define HEIGHT_PADDING 1
144 /* offset of items in report display mode */
145 #define REPORT_MARGINX 2
147 /* padding for icon in large icon display mode */
148 #define ICON_TOP_PADDING 2
149 #define ICON_BOTTOM_PADDING 2
151 /* padding for label in large icon display mode */
152 #define LABEL_VERT_OFFSET 2
154 /* default label width for items in list and small icon display modes */
155 #define DEFAULT_LABEL_WIDTH 40
157 /* default column width for items in list display mode */
158 #define DEFAULT_COLUMN_WIDTH 96
160 /* Increment size of the horizontal scroll bar */
161 #define LISTVIEW_SCROLL_DIV_SIZE 10
163 /* Padding betwen image and label */
164 #define IMAGE_PADDING 2
166 /* Padding behind the label */
167 #define TRAILING_PADDING 5
169 /* Border for the icon caption */
170 #define CAPTION_BORDER 2
174 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
175 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
176 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
177 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
178 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
179 /* retrieve the number of items in the listview */
180 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
182 HWND
CreateEditLabel(LPCSTR text
, DWORD style
, INT x
, INT y
,
183 INT width
, INT height
, HWND parent
, HINSTANCE hinst
,
184 EditlblCallback EditLblCb
, DWORD param
);
187 * forward declarations
189 static LRESULT
LISTVIEW_GetItemA(HWND hwnd
, LPLVITEMA lpLVItem
, BOOL internal
);
190 static INT
LISTVIEW_HitTestItem(HWND
, LPLVHITTESTINFO
, BOOL
);
191 static INT
LISTVIEW_GetCountPerRow(HWND
);
192 static INT
LISTVIEW_GetCountPerColumn(HWND
);
193 static VOID
LISTVIEW_AlignLeft(HWND
);
194 static VOID
LISTVIEW_AlignTop(HWND
);
195 static VOID
LISTVIEW_AddGroupSelection(HWND
, INT
);
196 static VOID
LISTVIEW_AddSelection(HWND
, INT
);
197 static BOOL
LISTVIEW_AddSubItem(HWND
, LPLVITEMA
);
198 static INT
LISTVIEW_FindInsertPosition(HDPA
, INT
);
199 static INT
LISTVIEW_GetItemHeight(HWND
);
200 static BOOL
LISTVIEW_GetItemPosition(HWND
, INT
, LPPOINT
);
201 static LRESULT
LISTVIEW_GetItemRect(HWND
, INT
, LPRECT
);
202 static INT
LISTVIEW_GetItemWidth(HWND
);
203 static INT
LISTVIEW_GetLabelWidth(HWND
, INT
);
204 static LRESULT
LISTVIEW_GetOrigin(HWND
, LPPOINT
);
205 static INT
LISTVIEW_CalculateWidth(HWND hwnd
, INT nItem
);
206 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA
, INT
);
207 static LRESULT
LISTVIEW_GetViewRect(HWND
, LPRECT
);
208 static BOOL
LISTVIEW_InitItem(HWND
, LISTVIEW_ITEM
*, LPLVITEMA
);
209 static BOOL
LISTVIEW_InitSubItem(HWND
, LISTVIEW_SUBITEM
*, LPLVITEMA
);
210 static LRESULT
LISTVIEW_MouseSelection(HWND
, POINT
);
211 static BOOL
LISTVIEW_RemoveColumn(HDPA
, INT
);
212 static BOOL
LISTVIEW_RemoveSubItem(HDPA
, INT
);
213 static VOID
LISTVIEW_SetGroupSelection(HWND
, INT
);
214 static BOOL
LISTVIEW_SetItem(HWND
, LPLVITEMA
);
215 static BOOL
LISTVIEW_SetItemFocus(HWND
, INT
);
216 static BOOL
LISTVIEW_SetItemPosition(HWND
, INT
, LONG
, LONG
);
217 static VOID
LISTVIEW_UpdateScroll(HWND
);
218 static VOID
LISTVIEW_SetSelection(HWND
, INT
);
219 static VOID
LISTVIEW_UpdateSize(HWND
);
220 static BOOL
LISTVIEW_SetSubItem(HWND
, LPLVITEMA
);
221 static LRESULT
LISTVIEW_SetViewRect(HWND
, LPRECT
);
222 static BOOL
LISTVIEW_ToggleSelection(HWND
, INT
);
223 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
);
224 static HWND
LISTVIEW_EditLabelA(HWND hwnd
, INT nItem
);
225 static BOOL
LISTVIEW_EndEditLabel(HWND hwnd
, LPSTR pszText
, DWORD nItem
);
226 static LRESULT
LISTVIEW_Command(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
227 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, WPARAM wParam
, LPARAM lParam
);
228 static LRESULT
LISTVIEW_GetStringWidthA(HWND hwnd
, LPCSTR lpszText
);
229 static INT
LISTVIEW_ProcessLetterKeys( HWND hwnd
, WPARAM charCode
, LPARAM keyData
);
230 static BOOL
LISTVIEW_KeySelection(HWND hwnd
, INT nItem
);
231 static LRESULT
LISTVIEW_GetItemState(HWND hwnd
, INT nItem
, UINT uMask
);
232 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
);
233 static BOOL
LISTVIEW_IsSelected(HWND hwnd
, INT nItem
);
234 static VOID
LISTVIEW_RemoveSelectionRange(HWND hwnd
, INT lItem
, INT uItem
);
235 static void LISTVIEW_FillBackground(HWND hwnd
, HDC hdc
, LPRECT rc
);
237 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
238 #define KEY_DELAY 900
239 #define LISTVIEW_InitLvItemStruct(item,idx,TEXT) \
240 ZeroMemory(&(item), sizeof(LVITEMA)); \
241 (item).mask = LVIF_TEXT; \
242 (item).iItem = (idx); \
243 (item).iSubItem = 0; \
244 (item).pszText = (TEXT); \
245 (item).cchTextMax = MAX_PATH
248 LISTVIEW_SendCustomDrawNotify (HWND hwnd
, DWORD dwDrawStage
, HDC hdc
,
251 LISTVIEW_INFO
*infoPtr
;
252 NMLVCUSTOMDRAW nmcdhdr
;
255 TRACE("drawstage:%lx hdc:%x\n", dwDrawStage
, hdc
);
257 infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
259 nmcd
= & nmcdhdr
.nmcd
;
260 nmcd
->hdr
.hwndFrom
= hwnd
;
261 nmcd
->hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
262 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
263 nmcd
->dwDrawStage
= dwDrawStage
;
265 nmcd
->rc
.left
= rc
.left
;
266 nmcd
->rc
.right
= rc
.right
;
267 nmcd
->rc
.bottom
= rc
.bottom
;
268 nmcd
->rc
.top
= rc
.top
;
269 nmcd
->dwItemSpec
= 0;
270 nmcd
->uItemState
= 0;
271 nmcd
->lItemlParam
= 0;
272 nmcdhdr
.clrText
= infoPtr
->clrText
;
273 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
275 return (BOOL
)SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
276 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
280 LISTVIEW_SendCustomDrawItemNotify (HWND hwnd
, HDC hdc
,
281 UINT iItem
, UINT iSubItem
,
284 LISTVIEW_INFO
*infoPtr
;
285 NMLVCUSTOMDRAW nmcdhdr
;
287 DWORD dwDrawStage
,dwItemSpec
;
293 infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
295 ZeroMemory(&item
,sizeof(LVITEMA
));
297 item
.mask
= LVIF_PARAM
;
298 ListView_GetItemA(hwnd
,&item
);
300 dwDrawStage
=CDDS_ITEM
| uItemDrawState
;
304 if (LISTVIEW_IsSelected(hwnd
,iItem
)) uItemState
|=CDIS_SELECTED
;
305 if (iItem
==infoPtr
->nFocusedItem
) uItemState
|=CDIS_FOCUS
;
306 if (iItem
==infoPtr
->nHotItem
) uItemState
|=CDIS_HOT
;
308 itemRect
.left
= LVIR_BOUNDS
;
309 LISTVIEW_GetItemRect(hwnd
, iItem
, &itemRect
);
311 nmcd
= & nmcdhdr
.nmcd
;
312 nmcd
->hdr
.hwndFrom
= hwnd
;
313 nmcd
->hdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
314 nmcd
->hdr
.code
= NM_CUSTOMDRAW
;
315 nmcd
->dwDrawStage
= dwDrawStage
;
317 nmcd
->rc
.left
= itemRect
.left
;
318 nmcd
->rc
.right
= itemRect
.right
;
319 nmcd
->rc
.bottom
= itemRect
.bottom
;
320 nmcd
->rc
.top
= itemRect
.top
;
321 nmcd
->dwItemSpec
= dwItemSpec
;
322 nmcd
->uItemState
= uItemState
;
323 nmcd
->lItemlParam
= item
.lParam
;
324 nmcdhdr
.clrText
= infoPtr
->clrText
;
325 nmcdhdr
.clrTextBk
= infoPtr
->clrBk
;
326 nmcdhdr
.iSubItem
=iSubItem
;
328 TRACE("drawstage:%lx hdc:%x item:%lx, itemstate:%x, lItemlParam:%lx\n",
329 nmcd
->dwDrawStage
, nmcd
->hdc
, nmcd
->dwItemSpec
,
330 nmcd
->uItemState
, nmcd
->lItemlParam
);
332 retval
=SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
333 (WPARAM
) GetWindowLongA( hwnd
, GWL_ID
), (LPARAM
)&nmcdhdr
);
335 infoPtr
->clrText
=nmcdhdr
.clrText
;
336 infoPtr
->clrBk
=nmcdhdr
.clrTextBk
;
337 return (BOOL
) retval
;
341 /*************************************************************************
343 * Processes keyboard messages generated by pressing the letter keys on the keyboard.
344 * Assumes the list is sorted alphabetically, without regard to case.
347 * [I] HWND: handle to the window
348 * [I] WPARAM: the character code, the actual character
349 * [I] LPARAM: key data
359 static INT
LISTVIEW_ProcessLetterKeys( HWND hwnd
, WPARAM charCode
, LPARAM keyData
)
361 LISTVIEW_INFO
*infoPtr
= NULL
;
366 BOOL bFoundMatchingFiles
= FALSE
;
368 CHAR TEXT
[ MAX_PATH
];
369 CHAR szCharCode
[ 2 ];
370 DWORD timeSinceLastKeyPress
= 0;
372 szCharCode
[0] = charCode
;
375 /* simple parameter checking */
376 if ( !hwnd
|| !charCode
|| !keyData
)
379 infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
384 /* only allow the valid WM_CHARs through */
385 if ( isalnum( charCode
) || charCode
== '.' || charCode
== '`' || charCode
== '!'
386 || charCode
== '@' || charCode
== '#' || charCode
== '$' || charCode
== '%'
387 || charCode
== '^' || charCode
== '&' || charCode
== '*' || charCode
== '('
388 || charCode
== ')' || charCode
== '-' || charCode
== '_' || charCode
== '+'
389 || charCode
== '=' || charCode
== '\\'|| charCode
== ']' || charCode
== '}'
390 || charCode
== '[' || charCode
== '{' || charCode
== '/' || charCode
== '?'
391 || charCode
== '>' || charCode
== '<' || charCode
== ',' || charCode
== '~')
393 timeSinceLastKeyPress
= GetTickCount();
395 nSize
= GETITEMCOUNT( infoPtr
);
396 /* if there are 0 items, there is no where to go */
400 * If the last charCode equals the current charCode then look
401 * to the next element in list to see if it matches the previous
404 if ( infoPtr
->charCode
== charCode
)
406 if ( timeSinceLastKeyPress
- infoPtr
->timeSinceLastKeyPress
< KEY_DELAY
)
407 { /* append new character to search string */
408 strcat( infoPtr
->szSearchParam
, szCharCode
);
409 infoPtr
->nSearchParamLength
++;
411 /* loop from start of list view */
412 for( idx
= infoPtr
->nFocusedItem
; idx
< nSize
; idx
++ )
414 LISTVIEW_InitLvItemStruct( item
, idx
, TEXT
);
415 ListView_GetItemA( hwnd
, &item
);
418 if ( strncasecmp( item
.pszText
, infoPtr
->szSearchParam
,
419 infoPtr
->nSearchParamLength
) == 0 )
426 else if ( infoPtr
->timeSinceLastKeyPress
> timeSinceLastKeyPress
)
427 { /* The DWORD went over it's boundary?? Ergo assuming too slow??. */
428 for ( idx
= 0; idx
< nSize
; idx
++ )
430 LISTVIEW_InitLvItemStruct( item
, idx
, TEXT
);
431 ListView_GetItemA( hwnd
, &item
);
433 if ( strncasecmp( &( item
.pszText
[ 0 ] ), szCharCode
, 1 ) == 0 )
439 strcpy( infoPtr
->szSearchParam
, szCharCode
);
440 infoPtr
->nSearchParamLength
= 1;
443 { /* Save szCharCode for use in later searches */
444 strcpy( infoPtr
->szSearchParam
, szCharCode
);
445 infoPtr
->nSearchParamLength
= 1;
447 LISTVIEW_InitLvItemStruct( item
, infoPtr
->nFocusedItem
+ 1, TEXT
);
448 ListView_GetItemA( hwnd
, &item
);
450 if ( strncasecmp( &( item
.pszText
[ 0 ] ), szCharCode
, 1 ) == 0 )
451 nItem
= infoPtr
->nFocusedItem
+ 1;
454 * Ok so there are no more folders that match
455 * now we look for files.
457 for ( idx
= infoPtr
->nFocusedItem
+ 1; idx
< nSize
; idx
++ )
459 LISTVIEW_InitLvItemStruct( item
, idx
, TEXT
);
460 ListView_GetItemA( hwnd
, &item
);
462 if ( strncasecmp( &( item
.pszText
[ 0 ] ), szCharCode
, 1 ) == 0 )
465 bFoundMatchingFiles
= TRUE
;
469 if ( !bFoundMatchingFiles
)
470 { /* go back to first instance */
471 for ( idx
= 0; idx
< nSize
; idx
++ )
473 LISTVIEW_InitLvItemStruct( item
,idx
, TEXT
);
474 ListView_GetItemA( hwnd
, &item
);
476 if ( strncasecmp( &( item
.pszText
[ 0 ] ), szCharCode
, 1 ) == 0 )
485 } /*END: if ( infoPtr->charCode == charCode )*/
487 else /* different keypressed */
489 /* could be that they are spelling the file/directory for us */
490 if ( timeSinceLastKeyPress
- infoPtr
->timeSinceLastKeyPress
> KEY_DELAY
)
492 * Too slow, move to the first instance of the
495 for ( idx
= 0; idx
< nSize
; idx
++ )
497 LISTVIEW_InitLvItemStruct( item
,idx
, TEXT
);
498 ListView_GetItemA( hwnd
, &item
);
500 if ( strncasecmp( &( item
.pszText
[ 0 ] ), szCharCode
, 1 ) == 0 )
506 strcpy( infoPtr
->szSearchParam
, szCharCode
);
507 infoPtr
->nSearchParamLength
= 1;
509 else if ( infoPtr
->timeSinceLastKeyPress
> timeSinceLastKeyPress
)
510 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
511 for ( idx
= 0; idx
< nSize
; idx
++ )
513 LISTVIEW_InitLvItemStruct( item
,idx
, TEXT
);
514 ListView_GetItemA( hwnd
, &item
);
516 if ( strncasecmp( &( item
.pszText
[ 0 ] ), szCharCode
, 1 ) == 0 )
522 strcpy( infoPtr
->szSearchParam
, szCharCode
);
523 infoPtr
->nSearchParamLength
= 1;
525 else /* Search for the string the user is typing */
527 /* append new character to search string */
528 strcat( infoPtr
->szSearchParam
, szCharCode
);
529 infoPtr
->nSearchParamLength
++;
531 /* loop from start of list view */
532 for( idx
= 0; idx
< nSize
; idx
++ )
534 LISTVIEW_InitLvItemStruct( item
, idx
, TEXT
);
535 ListView_GetItemA( hwnd
, &item
);
538 if ( strncasecmp( item
.pszText
, infoPtr
->szSearchParam
,
539 infoPtr
->nSearchParamLength
) == 0 )
551 bRedraw
= LISTVIEW_KeySelection(hwnd
, nItem
);
552 if (bRedraw
!= FALSE
)
554 /* refresh client area */
555 InvalidateRect(hwnd
, NULL
, TRUE
);
559 /* Store the WM_CHAR for next time */
560 infoPtr
->charCode
= charCode
;
563 infoPtr
->timeSinceLastKeyPress
= timeSinceLastKeyPress
;
569 /*************************************************************************
570 * LISTVIEW_UpdateHeaderSize [Internal]
572 * Function to resize the header control
575 * hwnd [I] handle to a window
576 * nNewScrollPos [I] Scroll Pos to Set
583 static VOID
LISTVIEW_UpdateHeaderSize(HWND hwnd
, INT nNewScrollPos
)
585 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
589 GetWindowRect(infoPtr
->hwndHeader
, &winRect
);
590 point
[0].x
= winRect
.left
;
591 point
[0].y
= winRect
.top
;
592 point
[1].x
= winRect
.right
;
593 point
[1].y
= winRect
.bottom
;
595 MapWindowPoints(HWND_DESKTOP
, hwnd
, point
, 2);
596 point
[0].x
= -(nNewScrollPos
* LISTVIEW_SCROLL_DIV_SIZE
);
597 point
[1].x
+= (nNewScrollPos
* LISTVIEW_SCROLL_DIV_SIZE
);
599 SetWindowPos(infoPtr
->hwndHeader
,0,
600 point
[0].x
,point
[0].y
,point
[1].x
,point
[1].y
,
601 SWP_NOZORDER
| SWP_NOACTIVATE
);
606 * Update the scrollbars. This functions should be called whenever
607 * the content, size or view changes.
610 * [I] HWND : window handle
615 static VOID
LISTVIEW_UpdateScroll(HWND hwnd
)
617 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
618 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
619 UINT uView
= lStyle
& LVS_TYPEMASK
;
620 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
621 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
622 SCROLLINFO scrollInfo
;
624 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
625 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
627 if (uView
== LVS_LIST
)
629 /* update horizontal scrollbar */
631 INT nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
632 INT nCountPerRow
= LISTVIEW_GetCountPerRow(hwnd
);
633 INT nNumOfItems
= GETITEMCOUNT(infoPtr
);
635 scrollInfo
.nMax
= nNumOfItems
/ nCountPerColumn
;
636 if((nNumOfItems
% nCountPerColumn
) == 0)
640 scrollInfo
.nPos
= ListView_GetTopIndex(hwnd
) / nCountPerColumn
;
641 scrollInfo
.nPage
= nCountPerRow
;
642 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
643 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
644 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
646 else if (uView
== LVS_REPORT
)
648 /* update vertical scrollbar */
650 scrollInfo
.nMax
= GETITEMCOUNT(infoPtr
) - 1;
651 scrollInfo
.nPos
= ListView_GetTopIndex(hwnd
);
652 scrollInfo
.nPage
= LISTVIEW_GetCountPerColumn(hwnd
);
653 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
654 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
656 /* update horizontal scrollbar */
657 nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
658 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) == FALSE
659 || GETITEMCOUNT(infoPtr
) == 0)
664 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
665 scrollInfo
.nPage
= nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
;
666 scrollInfo
.nMax
= max(infoPtr
->nItemWidth
/ LISTVIEW_SCROLL_DIV_SIZE
, 0)-1;
667 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
669 /* Update the Header Control */
670 scrollInfo
.fMask
= SIF_POS
;
671 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
672 LISTVIEW_UpdateHeaderSize(hwnd
, scrollInfo
.nPos
);
679 if (LISTVIEW_GetViewRect(hwnd
, &rcView
) != FALSE
)
681 INT nViewWidth
= rcView
.right
- rcView
.left
;
682 INT nViewHeight
= rcView
.bottom
- rcView
.top
;
684 /* Update Horizontal Scrollbar */
685 scrollInfo
.fMask
= SIF_POS
;
686 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) == FALSE
687 || GETITEMCOUNT(infoPtr
) == 0)
691 scrollInfo
.nMax
= max(nViewWidth
/ LISTVIEW_SCROLL_DIV_SIZE
, 0)-1;
693 scrollInfo
.nPage
= nListWidth
/ LISTVIEW_SCROLL_DIV_SIZE
;
694 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
695 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
697 /* Update Vertical Scrollbar */
698 nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
699 scrollInfo
.fMask
= SIF_POS
;
700 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) == FALSE
701 || GETITEMCOUNT(infoPtr
) == 0)
705 scrollInfo
.nMax
= max(nViewHeight
/ LISTVIEW_SCROLL_DIV_SIZE
,0)-1;
707 scrollInfo
.nPage
= nListHeight
/ LISTVIEW_SCROLL_DIV_SIZE
;
708 scrollInfo
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
709 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
716 * Prints a message for unsupported window styles.
717 * A kind of TODO list for window styles.
720 * [I] LONG : window style
725 static VOID
LISTVIEW_UnsupportedStyles(LONG lStyle
)
727 if ((LVS_TYPEMASK
& lStyle
) == LVS_EDITLABELS
)
729 FIXME(" LVS_EDITLABELS\n");
732 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOLABELWRAP
)
734 FIXME(" LVS_NOLABELWRAP\n");
737 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOSCROLL
)
739 FIXME(" LVS_NOSCROLL\n");
742 if ((LVS_TYPEMASK
& lStyle
) == LVS_NOSORTHEADER
)
744 FIXME(" LVS_NOSORTHEADER\n");
747 if ((LVS_TYPEMASK
& lStyle
) == LVS_OWNERDRAWFIXED
)
749 FIXME(" LVS_OWNERDRAWFIXED\n");
752 if ((LVS_TYPEMASK
& lStyle
) == LVS_SHAREIMAGELISTS
)
754 FIXME(" LVS_SHAREIMAGELISTS\n");
757 if ((LVS_TYPEMASK
& lStyle
) == LVS_SORTASCENDING
)
759 FIXME(" LVS_SORTASCENDING\n");
762 if ((LVS_TYPEMASK
& lStyle
) == LVS_SORTDESCENDING
)
764 FIXME(" LVS_SORTDESCENDING\n");
770 * Aligns the items with the top edge of the window.
773 * [I] HWND : window handle
778 static VOID
LISTVIEW_AlignTop(HWND hwnd
)
780 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
781 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
782 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
787 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
789 ZeroMemory(&ptItem
, sizeof(POINT
));
790 ZeroMemory(&rcView
, sizeof(RECT
));
792 if (nListWidth
> infoPtr
->nItemWidth
)
794 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
796 if (ptItem
.x
+ infoPtr
->nItemWidth
> nListWidth
)
799 ptItem
.y
+= infoPtr
->nItemHeight
;
802 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
803 ptItem
.x
+= infoPtr
->nItemWidth
;
804 rcView
.right
= max(rcView
.right
, ptItem
.x
);
807 rcView
.bottom
= ptItem
.y
+ infoPtr
->nItemHeight
;
811 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
813 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
814 ptItem
.y
+= infoPtr
->nItemHeight
;
817 rcView
.right
= infoPtr
->nItemWidth
;
818 rcView
.bottom
= ptItem
.y
;
821 LISTVIEW_SetViewRect(hwnd
, &rcView
);
827 * Aligns the items with the left edge of the window.
830 * [I] HWND : window handle
835 static VOID
LISTVIEW_AlignLeft(HWND hwnd
)
837 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
838 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
839 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
844 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
846 ZeroMemory(&ptItem
, sizeof(POINT
));
847 ZeroMemory(&rcView
, sizeof(RECT
));
849 if (nListHeight
> infoPtr
->nItemHeight
)
851 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
853 if (ptItem
.y
+ infoPtr
->nItemHeight
> nListHeight
)
856 ptItem
.x
+= infoPtr
->nItemWidth
;
859 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
860 ptItem
.y
+= infoPtr
->nItemHeight
;
861 rcView
.bottom
= max(rcView
.bottom
, ptItem
.y
);
864 rcView
.right
= ptItem
.x
+ infoPtr
->nItemWidth
;
868 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
870 ListView_SetItemPosition(hwnd
, i
, ptItem
.x
, ptItem
.y
);
871 ptItem
.x
+= infoPtr
->nItemWidth
;
874 rcView
.bottom
= infoPtr
->nItemHeight
;
875 rcView
.right
= ptItem
.x
;
878 LISTVIEW_SetViewRect(hwnd
, &rcView
);
884 * Set the bounding rectangle of all the items.
887 * [I] HWND : window handle
888 * [I] LPRECT : bounding rectangle
894 static LRESULT
LISTVIEW_SetViewRect(HWND hwnd
, LPRECT lprcView
)
896 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
897 BOOL bResult
= FALSE
;
899 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd
,
900 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
902 if (lprcView
!= NULL
)
905 infoPtr
->rcView
.left
= lprcView
->left
;
906 infoPtr
->rcView
.top
= lprcView
->top
;
907 infoPtr
->rcView
.right
= lprcView
->right
;
908 infoPtr
->rcView
.bottom
= lprcView
->bottom
;
916 * Retrieves the bounding rectangle of all the items.
919 * [I] HWND : window handle
920 * [O] LPRECT : bounding rectangle
926 static LRESULT
LISTVIEW_GetViewRect(HWND hwnd
, LPRECT lprcView
)
928 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
929 BOOL bResult
= FALSE
;
932 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd
, lprcView
);
934 if (lprcView
!= NULL
)
936 bResult
= LISTVIEW_GetOrigin(hwnd
, &ptOrigin
);
937 if (bResult
!= FALSE
)
939 lprcView
->left
= infoPtr
->rcView
.left
+ ptOrigin
.x
;
940 lprcView
->top
= infoPtr
->rcView
.top
+ ptOrigin
.y
;
941 lprcView
->right
= infoPtr
->rcView
.right
+ ptOrigin
.x
;
942 lprcView
->bottom
= infoPtr
->rcView
.bottom
+ ptOrigin
.y
;
945 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
946 lprcView
->left
, lprcView
->top
, lprcView
->right
, lprcView
->bottom
);
954 * Retrieves the subitem pointer associated with the subitem index.
957 * [I] HDPA : DPA handle for a specific item
958 * [I] INT : index of subitem
961 * SUCCESS : subitem pointer
964 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems
,
967 LISTVIEW_SUBITEM
*lpSubItem
;
970 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
972 lpSubItem
= (LISTVIEW_SUBITEM
*) DPA_GetPtr(hdpaSubItems
, i
);
973 if (lpSubItem
!= NULL
)
975 if (lpSubItem
->iSubItem
== nSubItem
)
987 * Calculates the width of an item.
990 * [I] HWND : window handle
991 * [I] LONG : window style
994 * Returns item width.
996 static INT
LISTVIEW_GetItemWidth(HWND hwnd
)
998 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
999 LONG style
= GetWindowLongA(hwnd
, GWL_STYLE
);
1000 UINT uView
= style
& LVS_TYPEMASK
;
1001 INT nHeaderItemCount
;
1007 TRACE("(hwnd=%x)\n", hwnd
);
1009 if (uView
== LVS_ICON
)
1011 nItemWidth
= infoPtr
->iconSpacing
.cx
;
1013 else if (uView
== LVS_REPORT
)
1015 /* calculate width of header */
1016 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1017 for (i
= 0; i
< nHeaderItemCount
; i
++)
1019 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
1021 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
1027 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1029 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, i
);
1030 nItemWidth
= max(nItemWidth
, nLabelWidth
);
1033 /* default label size */
1034 if (GETITEMCOUNT(infoPtr
) == 0)
1036 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
1040 if (nItemWidth
== 0)
1042 nItemWidth
= DEFAULT_LABEL_WIDTH
;
1047 nItemWidth
+= WIDTH_PADDING
;
1049 if (infoPtr
->himlSmall
!= NULL
)
1051 nItemWidth
+= infoPtr
->iconSize
.cx
;
1054 if (infoPtr
->himlState
!= NULL
)
1056 nItemWidth
+= infoPtr
->iconSize
.cx
;
1063 /* nItemWidth Cannot be Zero */
1071 * Calculates the width of a specific item.
1074 * [I] HWND : window handle
1075 * [I] LPSTR : string
1078 * Returns the width of an item width a specified string.
1080 static INT
LISTVIEW_CalculateWidth(HWND hwnd
, INT nItem
)
1082 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1083 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
1084 INT nHeaderItemCount
;
1089 TRACE("(hwnd=%x)\n", hwnd
);
1091 if (uView
== LVS_ICON
)
1093 nItemWidth
= infoPtr
->iconSpacing
.cx
;
1095 else if (uView
== LVS_REPORT
)
1097 /* calculate width of header */
1098 nHeaderItemCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
1099 for (i
= 0; i
< nHeaderItemCount
; i
++)
1101 if (Header_GetItemRect(infoPtr
->hwndHeader
, i
, &rcHeaderItem
) != 0)
1103 nItemWidth
+= (rcHeaderItem
.right
- rcHeaderItem
.left
);
1109 /* get width of string */
1110 nItemWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
1112 /* default label size */
1113 if (GETITEMCOUNT(infoPtr
) == 0)
1115 nItemWidth
= DEFAULT_COLUMN_WIDTH
;
1119 if (nItemWidth
== 0)
1121 nItemWidth
= DEFAULT_LABEL_WIDTH
;
1126 nItemWidth
+= WIDTH_PADDING
;
1128 if (infoPtr
->himlSmall
!= NULL
)
1130 nItemWidth
+= infoPtr
->iconSize
.cx
;
1133 if (infoPtr
->himlState
!= NULL
)
1135 nItemWidth
+= infoPtr
->iconSize
.cx
;
1146 * Calculates the height of an item.
1149 * [I] HWND : window handle
1150 * [I] LONG : window style
1153 * Returns item height.
1155 static INT
LISTVIEW_GetItemHeight(HWND hwnd
)
1157 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1158 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
1159 INT nItemHeight
= 0;
1161 if (uView
== LVS_ICON
)
1163 nItemHeight
= infoPtr
->iconSpacing
.cy
;
1168 HDC hdc
= GetDC(hwnd
);
1169 HFONT hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
1170 GetTextMetricsA(hdc
, &tm
);
1172 if(infoPtr
->himlState
|| infoPtr
->himlSmall
)
1173 nItemHeight
= max(tm
.tmHeight
, infoPtr
->iconSize
.cy
) + HEIGHT_PADDING
;
1175 nItemHeight
= tm
.tmHeight
;
1177 SelectObject(hdc
, hOldFont
);
1178 ReleaseDC(hwnd
, hdc
);
1185 static void LISTVIEW_PrintSelectionRanges(HWND hwnd
)
1187 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1188 LISTVIEW_SELECTION
*selection
;
1189 INT topSelection
= infoPtr
->hdpaSelectionRanges
->nItemCount
;
1192 TRACE("Selections are:\n");
1193 for (i
= 0; i
< topSelection
; i
++)
1195 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,i
);
1196 TRACE(" %lu - %lu\n",selection
->lower
,selection
->upper
);
1202 * A compare function for selection ranges
1205 * [I] LPVOID : Item 1;
1206 * [I] LPVOID : Item 2;
1207 * [I] LPARAM : flags
1210 * >0 : if Item 1 > Item 2
1211 * <0 : if Item 2 > Item 1
1212 * 0 : if Item 1 == Item 2
1214 static INT CALLBACK
LISTVIEW_CompareSelectionRanges(LPVOID range1
, LPVOID range2
,
1217 int l1
= ((LISTVIEW_SELECTION
*)(range1
))->lower
;
1218 int l2
= ((LISTVIEW_SELECTION
*)(range2
))->lower
;
1219 int u1
= ((LISTVIEW_SELECTION
*)(range1
))->upper
;
1220 int u2
= ((LISTVIEW_SELECTION
*)(range2
))->upper
;
1234 * Adds a selection range.
1237 * [I] HWND : window handle
1238 * [I] INT : lower item index
1239 * [I] INT : upper item index
1244 static VOID
LISTVIEW_AddSelectionRange(HWND hwnd
, INT lItem
, INT uItem
)
1246 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1247 LISTVIEW_SELECTION
*selection
;
1248 INT topSelection
= infoPtr
->hdpaSelectionRanges
->nItemCount
;
1249 BOOL lowerzero
=FALSE
;
1251 selection
= (LISTVIEW_SELECTION
*)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION
));
1252 selection
->lower
= lItem
;
1253 selection
->upper
= uItem
;
1255 TRACE("Add range %i - %i\n",lItem
,uItem
);
1258 LISTVIEW_SELECTION
*checkselection
,*checkselection2
;
1259 INT index
,mergeindex
;
1261 /* find overlapping selections */
1262 /* we want to catch adjacent ranges so expand our range by 1 */
1265 if (selection
->lower
== 0)
1270 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, selection
, 0,
1271 LISTVIEW_CompareSelectionRanges
,
1273 selection
->upper
--;
1277 selection
->lower
++;
1281 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,index
);
1282 TRACE("Merge with index %i (%lu - %lu)\n",index
,checkselection
->lower
,
1283 checkselection
->upper
);
1285 checkselection
->lower
= min(selection
->lower
,checkselection
->lower
);
1286 checkselection
->upper
= max(selection
->upper
,checkselection
->upper
);
1288 TRACE("New range (%lu - %lu)\n", checkselection
->lower
,
1289 checkselection
->upper
);
1291 COMCTL32_Free(selection
);
1293 /* merge now common selection ranges in the lower group*/
1296 checkselection
->upper
++;
1297 if (checkselection
->lower
== 0)
1300 checkselection
->lower
--;
1302 TRACE("search lower range (%lu - %lu)\n", checkselection
->lower
,
1303 checkselection
->upper
);
1305 /* not sorted yet */
1306 mergeindex
= DPA_Search(infoPtr
->hdpaSelectionRanges
, checkselection
, 0,
1307 LISTVIEW_CompareSelectionRanges
, 0,
1310 checkselection
->upper
--;
1314 checkselection
->lower
++;
1316 if (mergeindex
>=0 && mergeindex
!= index
)
1318 TRACE("Merge with index %i\n",mergeindex
);
1319 checkselection2
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1321 checkselection
->lower
= min(checkselection
->lower
,
1322 checkselection2
->lower
);
1323 checkselection
->upper
= max(checkselection
->upper
,
1324 checkselection2
->upper
);
1325 COMCTL32_Free(checkselection2
);
1326 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,mergeindex
);
1330 while (mergeindex
> -1 && mergeindex
<index
);
1332 /* merge now common selection ranges in the upper group*/
1335 checkselection
->upper
++;
1336 if (checkselection
->lower
== 0)
1339 checkselection
->lower
--;
1341 TRACE("search upper range %i (%lu - %lu)\n",index
,
1342 checkselection
->lower
, checkselection
->upper
);
1344 /* not sorted yet */
1345 mergeindex
= DPA_Search(infoPtr
->hdpaSelectionRanges
, checkselection
,
1347 LISTVIEW_CompareSelectionRanges
, 0,
1350 checkselection
->upper
--;
1354 checkselection
->lower
++;
1356 if (mergeindex
>=0 && mergeindex
!=index
)
1358 TRACE("Merge with index %i\n",mergeindex
);
1359 checkselection2
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1361 checkselection
->lower
= min(checkselection
->lower
,
1362 checkselection2
->lower
);
1363 checkselection
->upper
= max(checkselection
->upper
,
1364 checkselection2
->upper
);
1365 COMCTL32_Free(checkselection2
);
1366 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,mergeindex
);
1369 while (mergeindex
> -1);
1374 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, selection
, 0,
1375 LISTVIEW_CompareSelectionRanges
, 0,
1378 TRACE("Insert before index %i\n",index
);
1381 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,index
,selection
);
1386 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,0,selection
);
1391 DPA_Sort(infoPtr
->hdpaSelectionRanges
,LISTVIEW_CompareSelectionRanges
,0);
1392 LISTVIEW_PrintSelectionRanges(hwnd
);
1397 * check if a specified index is selected.
1400 * [I] HWND : window handle
1401 * [I] INT : item index
1406 static BOOL
LISTVIEW_IsSelected(HWND hwnd
, INT nItem
)
1408 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1409 LISTVIEW_SELECTION selection
;
1412 selection
.upper
= nItem
;
1413 selection
.lower
= nItem
;
1415 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &selection
, 0,
1416 LISTVIEW_CompareSelectionRanges
,
1426 * Removes all selection ranges
1429 * HWND: window handle
1435 static LRESULT
LISTVIEW_RemoveAllSelections(HWND hwnd
)
1437 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1438 LISTVIEW_SELECTION
*selection
;
1442 TRACE("(0x%x)\n",hwnd
);
1444 ZeroMemory(&item
,sizeof(LVITEMA
));
1445 item
.stateMask
= LVIS_SELECTED
;
1449 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,0);
1452 TRACE("Removing %lu to %lu\n",selection
->lower
, selection
->upper
);
1453 for (i
= selection
->lower
; i
<=selection
->upper
; i
++)
1454 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1455 LISTVIEW_RemoveSelectionRange(hwnd
,selection
->lower
,selection
->upper
);
1458 while (infoPtr
->hdpaSelectionRanges
->nItemCount
>0);
1466 * Removes a range selections.
1469 * [I] HWND : window handle
1470 * [I] INT : lower item index
1471 * [I] INT : upper item index
1476 static VOID
LISTVIEW_RemoveSelectionRange(HWND hwnd
, INT lItem
, INT uItem
)
1478 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1479 LISTVIEW_SELECTION removeselection
,*checkselection
;
1482 removeselection
.lower
= lItem
;
1483 removeselection
.upper
= uItem
;
1485 TRACE("Remove range %lu - %lu\n",removeselection
.lower
,removeselection
.upper
);
1486 LISTVIEW_PrintSelectionRanges(hwnd
);
1488 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &removeselection
, 0,
1489 LISTVIEW_CompareSelectionRanges
,
1496 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,
1499 TRACE("Matches range index %i (%lu-%lu)\n",index
,checkselection
->lower
,
1500 checkselection
->upper
);
1503 if ((checkselection
->upper
== removeselection
.upper
) &&
1504 (checkselection
->lower
== removeselection
.lower
))
1506 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,index
);
1509 /* case 2: engulf */
1510 else if (((checkselection
->upper
< removeselection
.upper
) &&
1511 (checkselection
->lower
> removeselection
.lower
))||
1512 ((checkselection
->upper
<= removeselection
.upper
) &&
1513 (checkselection
->lower
> removeselection
.lower
)) ||
1514 ((checkselection
->upper
< removeselection
.upper
) &&
1515 (checkselection
->lower
>= removeselection
.lower
)))
1518 DPA_DeletePtr(infoPtr
->hdpaSelectionRanges
,index
);
1519 /* do it again because others may also get caught */
1521 LISTVIEW_RemoveSelectionRange(hwnd
,lItem
,uItem
);
1523 /* case 3: overlap upper */
1524 else if ((checkselection
->upper
< removeselection
.upper
) &&
1525 (checkselection
->lower
< removeselection
.lower
))
1527 checkselection
->upper
= removeselection
.lower
- 1;
1529 LISTVIEW_RemoveSelectionRange(hwnd
,lItem
,uItem
);
1531 /* case 4: overlap lower */
1532 else if ((checkselection
->upper
> removeselection
.upper
) &&
1533 (checkselection
->lower
> removeselection
.lower
))
1535 checkselection
->lower
= removeselection
.upper
+ 1;
1537 LISTVIEW_RemoveSelectionRange(hwnd
,lItem
,uItem
);
1539 /* case 5: fully internal */
1540 else if (checkselection
->upper
== removeselection
.upper
)
1541 checkselection
->upper
= removeselection
.lower
- 1;
1542 else if (checkselection
->lower
== removeselection
.lower
)
1543 checkselection
->lower
= removeselection
.upper
+ 1;
1546 /* bisect the range */
1547 LISTVIEW_SELECTION
*newselection
;
1549 newselection
= (LISTVIEW_SELECTION
*)
1550 COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION
));
1551 newselection
-> lower
= checkselection
->lower
;
1552 newselection
-> upper
= removeselection
.lower
- 1;
1553 checkselection
-> lower
= removeselection
.upper
+ 1;
1554 DPA_InsertPtr(infoPtr
->hdpaSelectionRanges
,index
,newselection
);
1556 DPA_Sort(infoPtr
->hdpaSelectionRanges
,LISTVIEW_CompareSelectionRanges
,0);
1558 LISTVIEW_PrintSelectionRanges(hwnd
);
1563 * shifts all selection indexs starting with the indesx specified
1564 * in the direction specified.
1567 * [I] HWND : window handle
1568 * [I] INT : item index
1569 * [I] INT : amount and direction of shift
1574 static VOID
LISTVIEW_ShiftSelections(HWND hwnd
, INT nItem
, INT direction
)
1576 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1577 LISTVIEW_SELECTION selection
,*checkselection
;
1580 TRACE("Shifting %iu, %i steps\n",nItem
,direction
);
1582 selection
.upper
= nItem
;
1583 selection
.lower
= nItem
;
1585 index
= DPA_Search(infoPtr
->hdpaSelectionRanges
, &selection
, 0,
1586 LISTVIEW_CompareSelectionRanges
,
1587 0,DPAS_SORTED
|DPAS_INSERTAFTER
);
1589 while ((index
< infoPtr
->hdpaSelectionRanges
->nItemCount
)&&(index
!= -1))
1591 checkselection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,index
);
1592 if ((checkselection
->lower
>= nItem
)&&
1593 (checkselection
->lower
+ direction
>= 0))
1594 checkselection
->lower
+= direction
;
1595 if ((checkselection
->upper
>= nItem
)&&
1596 (checkselection
->upper
+ direction
>=0))
1597 checkselection
->upper
+= direction
;
1605 * Adds a block of selections.
1608 * [I] HWND : window handle
1609 * [I] INT : item index
1614 static VOID
LISTVIEW_AddGroupSelection(HWND hwnd
, INT nItem
)
1616 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1617 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
1618 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
1622 ZeroMemory(&item
,sizeof(LVITEMA
));
1623 item
.stateMask
= LVIS_SELECTED
;
1624 item
.state
= LVIS_SELECTED
;
1626 for (i
= nFirst
; i
<= nLast
; i
++);
1628 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1631 LISTVIEW_SetItemFocus(hwnd
, nItem
);
1632 infoPtr
->nSelectionMark
= nItem
;
1638 * Adds a single selection.
1641 * [I] HWND : window handle
1642 * [I] INT : item index
1647 static VOID
LISTVIEW_AddSelection(HWND hwnd
, INT nItem
)
1649 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1652 ZeroMemory(&item
,sizeof(LVITEMA
));
1653 item
.state
= LVIS_SELECTED
;
1654 item
.stateMask
= LVIS_SELECTED
;
1656 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
1658 LISTVIEW_SetItemFocus(hwnd
, nItem
);
1659 infoPtr
->nSelectionMark
= nItem
;
1664 * Selects or unselects an item.
1667 * [I] HWND : window handle
1668 * [I] INT : item index
1674 static BOOL
LISTVIEW_ToggleSelection(HWND hwnd
, INT nItem
)
1676 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1680 ZeroMemory(&item
,sizeof(LVITEMA
));
1681 item
.stateMask
= LVIS_SELECTED
;
1683 if (LISTVIEW_IsSelected(hwnd
,nItem
))
1686 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
1691 item
.state
= LVIS_SELECTED
;
1692 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
1696 LISTVIEW_SetItemFocus(hwnd
, nItem
);
1697 infoPtr
->nSelectionMark
= nItem
;
1704 * Selects items based on view coordinates.
1707 * [I] HWND : window handle
1708 * [I] RECT : selection rectangle
1713 static VOID
LISTVIEW_SetSelectionRect(HWND hwnd
, RECT rcSelRect
)
1715 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1720 ZeroMemory(&item
,sizeof(LVITEMA
));
1721 item
.stateMask
= LVIS_SELECTED
;
1723 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
1725 LISTVIEW_GetItemPosition(hwnd
, i
, &ptItem
);
1727 if (PtInRect(&rcSelRect
, ptItem
) != FALSE
)
1729 item
.state
= LVIS_SELECTED
;
1730 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1735 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1742 * Sets a single group selection.
1745 * [I] HWND : window handle
1746 * [I] INT : item index
1751 static VOID
LISTVIEW_SetGroupSelection(HWND hwnd
, INT nItem
)
1753 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1754 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
1757 ZeroMemory(&item
,sizeof(LVITEMA
));
1758 item
.stateMask
= LVIS_SELECTED
;
1760 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
1763 INT nFirst
= min(infoPtr
->nSelectionMark
, nItem
);
1764 INT nLast
= max(infoPtr
->nSelectionMark
, nItem
);
1766 for (i
= 0; i
<= GETITEMCOUNT(infoPtr
); i
++)
1768 if ((i
< nFirst
) || (i
> nLast
))
1771 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1775 item
.state
= LVIS_SELECTED
;
1776 LISTVIEW_SetItemState(hwnd
,i
,&item
);
1785 LISTVIEW_GetItemPosition(hwnd
, nItem
, &ptItem
);
1786 LISTVIEW_GetItemPosition(hwnd
, infoPtr
->nSelectionMark
, &ptSelMark
);
1787 rcSel
.left
= min(ptSelMark
.x
, ptItem
.x
);
1788 rcSel
.top
= min(ptSelMark
.y
, ptItem
.y
);
1789 rcSel
.right
= max(ptSelMark
.x
, ptItem
.x
) + infoPtr
->nItemWidth
;
1790 rcSel
.bottom
= max(ptSelMark
.y
, ptItem
.y
) + infoPtr
->nItemHeight
;
1791 LISTVIEW_SetSelectionRect(hwnd
, rcSel
);
1794 LISTVIEW_SetItemFocus(hwnd
, nItem
);
1799 * Manages the item focus.
1802 * [I] HWND : window handle
1803 * [I] INT : item index
1806 * TRUE : focused item changed
1807 * FALSE : focused item has NOT changed
1809 static BOOL
LISTVIEW_SetItemFocus(HWND hwnd
, INT nItem
)
1811 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1812 BOOL bResult
= FALSE
;
1815 if (infoPtr
->nFocusedItem
!= nItem
)
1817 if (infoPtr
->nFocusedItem
>= 0)
1819 INT oldFocus
= infoPtr
->nFocusedItem
;
1821 infoPtr
->nFocusedItem
= -1;
1822 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
1823 lvItem
.stateMask
= LVIS_FOCUSED
;
1824 ListView_SetItemState(hwnd
, oldFocus
, &lvItem
);
1828 lvItem
.state
= LVIS_FOCUSED
;
1829 lvItem
.stateMask
= LVIS_FOCUSED
;
1830 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
1832 infoPtr
->nFocusedItem
= nItem
;
1833 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
1841 * Sets a single selection.
1844 * [I] HWND : window handle
1845 * [I] INT : item index
1850 static VOID
LISTVIEW_SetSelection(HWND hwnd
, INT nItem
)
1852 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1855 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
1856 lvItem
.stateMask
= LVIS_FOCUSED
;
1857 ListView_SetItemState(hwnd
, infoPtr
->nFocusedItem
, &lvItem
);
1859 LISTVIEW_RemoveAllSelections(hwnd
);
1861 lvItem
.state
= LVIS_FOCUSED
|LVIS_SELECTED
;
1862 lvItem
.stateMask
= LVIS_FOCUSED
|LVIS_SELECTED
;
1863 ListView_SetItemState(hwnd
, nItem
, &lvItem
);
1865 infoPtr
->nFocusedItem
= nItem
;
1866 infoPtr
->nSelectionMark
= nItem
;
1871 * Set selection(s) with keyboard.
1874 * [I] HWND : window handle
1875 * [I] INT : item index
1878 * SUCCESS : TRUE (needs to be repainted)
1879 * FAILURE : FALSE (nothing has changed)
1881 static BOOL
LISTVIEW_KeySelection(HWND hwnd
, INT nItem
)
1883 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1884 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1885 WORD wShift
= HIWORD(GetKeyState(VK_SHIFT
));
1886 WORD wCtrl
= HIWORD(GetKeyState(VK_CONTROL
));
1887 BOOL bResult
= FALSE
;
1889 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
1891 if (lStyle
& LVS_SINGLESEL
)
1894 LISTVIEW_SetSelection(hwnd
, nItem
);
1895 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
1902 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
1906 bResult
= LISTVIEW_SetItemFocus(hwnd
, nItem
);
1911 LISTVIEW_SetSelection(hwnd
, nItem
);
1912 ListView_EnsureVisible(hwnd
, nItem
, FALSE
);
1922 * Called when the mouse is being actively tracked and has hovered for a specified
1926 * [I] HWND : window handle
1927 * [I] wParam : key indicator
1928 * [I] lParam : mouse position
1931 * 0 if the message was processed, non-zero if there was an error
1934 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1935 * over the item for a certain period of time.
1938 static LRESULT
LISTVIEW_MouseHover(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1940 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1943 pt
.x
= (INT
)LOWORD(lParam
);
1944 pt
.y
= (INT
)HIWORD(lParam
);
1946 if(infoPtr
->dwExStyle
& LVS_EX_TRACKSELECT
) {
1947 /* select the item under the cursor */
1948 LISTVIEW_MouseSelection(hwnd
, pt
);
1956 * Called whenever WM_MOUSEMOVE is recieved.
1959 * [I] HWND : window handle
1960 * [I] wParam : key indicators
1961 * [I] lParam : cursor position
1964 * 0 if the message is processed, non-zero if there was an error
1966 static LRESULT
LISTVIEW_MouseMove(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1968 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
1969 TRACKMOUSEEVENT trackinfo
;
1971 /* see if we are supposed to be tracking mouse hovering */
1972 if(infoPtr
->dwExStyle
& LVS_EX_TRACKSELECT
) {
1973 /* fill in the trackinfo struct */
1974 trackinfo
.cbSize
= sizeof(TRACKMOUSEEVENT
);
1975 trackinfo
.dwFlags
= TME_QUERY
;
1976 trackinfo
.hwndTrack
= hwnd
;
1977 trackinfo
.dwHoverTime
= infoPtr
->dwHoverTime
;
1979 /* see if we are already tracking this hwnd */
1980 _TrackMouseEvent(&trackinfo
);
1982 if(!(trackinfo
.dwFlags
& TME_HOVER
)) {
1983 trackinfo
.dwFlags
= TME_HOVER
;
1985 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1986 _TrackMouseEvent(&trackinfo
);
1995 * Selects an item based on coordinates.
1998 * [I] HWND : window handle
1999 * [I] POINT : mouse click ccordinates
2002 * SUCCESS : item index
2005 static LRESULT
LISTVIEW_MouseSelection(HWND hwnd
, POINT pt
)
2007 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2009 INT i
,topindex
,bottomindex
;
2010 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2011 UINT uView
= lStyle
& LVS_TYPEMASK
;
2013 topindex
= ListView_GetTopIndex(hwnd
);
2014 if (uView
== LVS_REPORT
)
2016 bottomindex
= topindex
+ LISTVIEW_GetCountPerColumn(hwnd
) + 1;
2017 bottomindex
= min(bottomindex
,GETITEMCOUNT(infoPtr
));
2021 bottomindex
= GETITEMCOUNT(infoPtr
);
2024 for (i
= topindex
; i
< bottomindex
; i
++)
2026 rcItem
.left
= LVIR_SELECTBOUNDS
;
2027 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) == TRUE
)
2029 if (PtInRect(&rcItem
, pt
) != FALSE
)
2044 * [IO] HDPA : dynamic pointer array handle
2045 * [I] INT : column index (subitem index)
2051 static BOOL
LISTVIEW_RemoveColumn(HDPA hdpaItems
, INT nSubItem
)
2053 BOOL bResult
= TRUE
;
2057 for (i
= 0; i
< hdpaItems
->nItemCount
; i
++)
2059 hdpaSubItems
= (HDPA
)DPA_GetPtr(hdpaItems
, i
);
2060 if (hdpaSubItems
!= NULL
)
2062 if (LISTVIEW_RemoveSubItem(hdpaSubItems
, nSubItem
) == FALSE
)
2074 * Removes a subitem at a given position.
2077 * [IO] HDPA : dynamic pointer array handle
2078 * [I] INT : subitem index
2084 static BOOL
LISTVIEW_RemoveSubItem(HDPA hdpaSubItems
, INT nSubItem
)
2086 LISTVIEW_SUBITEM
*lpSubItem
;
2089 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2091 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2092 if (lpSubItem
!= NULL
)
2094 if (lpSubItem
->iSubItem
== nSubItem
)
2097 if ((lpSubItem
->pszText
!= NULL
) &&
2098 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2100 COMCTL32_Free(lpSubItem
->pszText
);
2104 COMCTL32_Free(lpSubItem
);
2106 /* free dpa memory */
2107 if (DPA_DeletePtr(hdpaSubItems
, i
) == NULL
)
2112 else if (lpSubItem
->iSubItem
> nSubItem
)
2124 * Compares the item information.
2127 * [I] LISTVIEW_ITEM *: destination item
2128 * [I] LPLVITEM : source item
2131 * SUCCCESS : TRUE (EQUAL)
2132 * FAILURE : FALSE (NOT EQUAL)
2134 static UINT
LISTVIEW_GetItemChanges(LISTVIEW_ITEM
*lpItem
, LPLVITEMA lpLVItem
)
2138 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
2140 if (lpLVItem
->mask
& LVIF_STATE
)
2142 if ((lpItem
->state
& lpLVItem
->stateMask
) !=
2143 (lpLVItem
->state
& lpLVItem
->stateMask
))
2145 uChanged
|= LVIF_STATE
;
2149 if (lpLVItem
->mask
& LVIF_IMAGE
)
2151 if (lpItem
->iImage
!= lpLVItem
->iImage
)
2153 uChanged
|= LVIF_IMAGE
;
2157 if (lpLVItem
->mask
& LVIF_PARAM
)
2159 if (lpItem
->lParam
!= lpLVItem
->lParam
)
2161 uChanged
|= LVIF_PARAM
;
2165 if (lpLVItem
->mask
& LVIF_INDENT
)
2167 if (lpItem
->iIndent
!= lpLVItem
->iIndent
)
2169 uChanged
|= LVIF_INDENT
;
2173 if (lpLVItem
->mask
& LVIF_TEXT
)
2175 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2177 if (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
)
2179 uChanged
|= LVIF_TEXT
;
2184 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2186 uChanged
|= LVIF_TEXT
;
2190 if (lpLVItem
->pszText
)
2192 if (lpItem
->pszText
)
2194 if (strcmp(lpLVItem
->pszText
, lpItem
->pszText
) != 0)
2196 uChanged
|= LVIF_TEXT
;
2201 uChanged
|= LVIF_TEXT
;
2206 if (lpItem
->pszText
)
2208 uChanged
|= LVIF_TEXT
;
2220 * Initializes item attributes.
2223 * [I] HWND : window handle
2224 * [O] LISTVIEW_ITEM *: destination item
2225 * [I] LPLVITEM : source item
2231 static BOOL
LISTVIEW_InitItem(HWND hwnd
, LISTVIEW_ITEM
*lpItem
,
2234 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2235 BOOL bResult
= FALSE
;
2237 if ((lpItem
!= NULL
) && (lpLVItem
!= NULL
))
2241 if (lpLVItem
->mask
& LVIF_STATE
)
2243 lpItem
->state
&= ~lpLVItem
->stateMask
;
2244 lpItem
->state
|= (lpLVItem
->state
& lpLVItem
->stateMask
);
2247 if (lpLVItem
->mask
& LVIF_IMAGE
)
2249 lpItem
->iImage
= lpLVItem
->iImage
;
2252 if (lpLVItem
->mask
& LVIF_PARAM
)
2254 lpItem
->lParam
= lpLVItem
->lParam
;
2257 if (lpLVItem
->mask
& LVIF_INDENT
)
2259 lpItem
->iIndent
= lpLVItem
->iIndent
;
2262 if (lpLVItem
->mask
& LVIF_TEXT
)
2264 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2266 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
2271 if ((lpItem
->pszText
!= NULL
) &&
2272 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2274 COMCTL32_Free(lpItem
->pszText
);
2277 lpItem
->pszText
= LPSTR_TEXTCALLBACKA
;
2281 if (lpItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2283 lpItem
->pszText
= NULL
;
2286 bResult
= Str_SetPtrA(&lpItem
->pszText
, lpLVItem
->pszText
);
2296 * Initializes subitem attributes.
2298 * NOTE: The documentation specifies that the operation fails if the user
2299 * tries to set the indent of a subitem.
2302 * [I] HWND : window handle
2303 * [O] LISTVIEW_SUBITEM *: destination subitem
2304 * [I] LPLVITEM : source subitem
2310 static BOOL
LISTVIEW_InitSubItem(HWND hwnd
, LISTVIEW_SUBITEM
*lpSubItem
,
2313 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2314 BOOL bResult
= FALSE
;
2316 if ((lpSubItem
!= NULL
) && (lpLVItem
!= NULL
))
2318 if (!(lpLVItem
->mask
& LVIF_INDENT
))
2322 lpSubItem
->iSubItem
= lpLVItem
->iSubItem
;
2324 if (lpLVItem
->mask
& LVIF_IMAGE
)
2326 lpSubItem
->iImage
= lpLVItem
->iImage
;
2329 if (lpLVItem
->mask
& LVIF_TEXT
)
2331 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2333 if ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
2338 if ((lpSubItem
->pszText
!= NULL
) &&
2339 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
2341 COMCTL32_Free(lpSubItem
->pszText
);
2344 lpSubItem
->pszText
= LPSTR_TEXTCALLBACKA
;
2348 if (lpSubItem
->pszText
== LPSTR_TEXTCALLBACKA
)
2350 lpSubItem
->pszText
= NULL
;
2353 bResult
= Str_SetPtrA(&lpSubItem
->pszText
, lpLVItem
->pszText
);
2364 * Adds a subitem at a given position (column index).
2367 * [I] HWND : window handle
2368 * [I] LPLVITEM : new subitem atttributes
2374 static BOOL
LISTVIEW_AddSubItem(HWND hwnd
, LPLVITEMA lpLVItem
)
2376 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2377 LISTVIEW_SUBITEM
*lpSubItem
= NULL
;
2378 BOOL bResult
= FALSE
;
2380 INT nPosition
, nItem
;
2381 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2383 if (lStyle
& LVS_OWNERDATA
)
2386 if (lpLVItem
!= NULL
)
2388 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2389 if (hdpaSubItems
!= NULL
)
2391 lpSubItem
= (LISTVIEW_SUBITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM
));
2392 if (lpSubItem
!= NULL
)
2394 ZeroMemory(lpSubItem
, sizeof(LISTVIEW_SUBITEM
));
2395 if (LISTVIEW_InitSubItem(hwnd
, lpSubItem
, lpLVItem
) != FALSE
)
2397 nPosition
= LISTVIEW_FindInsertPosition(hdpaSubItems
,
2398 lpSubItem
->iSubItem
);
2399 nItem
= DPA_InsertPtr(hdpaSubItems
, nPosition
, lpSubItem
);
2409 /* cleanup if unsuccessful */
2410 if ((bResult
== FALSE
) && (lpSubItem
!= NULL
))
2412 COMCTL32_Free(lpSubItem
);
2420 * Finds the dpa insert position (array index).
2423 * [I] HWND : window handle
2424 * [I] INT : subitem index
2430 static INT
LISTVIEW_FindInsertPosition(HDPA hdpaSubItems
, INT nSubItem
)
2432 LISTVIEW_SUBITEM
*lpSubItem
;
2435 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2437 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2438 if (lpSubItem
!= NULL
)
2440 if (lpSubItem
->iSubItem
> nSubItem
)
2447 return hdpaSubItems
->nItemCount
;
2452 * Retrieves a listview subitem at a given position (column index).
2455 * [I] HWND : window handle
2456 * [I] INT : subitem index
2462 static LISTVIEW_SUBITEM
* LISTVIEW_GetSubItem(HDPA hdpaSubItems
, INT nSubItem
)
2464 LISTVIEW_SUBITEM
*lpSubItem
;
2467 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
2469 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
2470 if (lpSubItem
!= NULL
)
2472 if (lpSubItem
->iSubItem
== nSubItem
)
2476 else if (lpSubItem
->iSubItem
> nSubItem
)
2488 * Sets item attributes.
2491 * [I] HWND : window handle
2492 * [I] LPLVITEM : new item atttributes
2498 static BOOL
LISTVIEW_SetItem(HWND hwnd
, LPLVITEMA lpLVItem
)
2500 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2501 BOOL bResult
= FALSE
;
2503 LISTVIEW_ITEM
*lpItem
;
2505 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
2506 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2508 UINT uView
= lStyle
& LVS_TYPEMASK
;
2512 if (lStyle
& LVS_OWNERDATA
)
2514 if ((lpLVItem
->iSubItem
== 0)&&(lpLVItem
->mask
== LVIF_STATE
))
2518 ZeroMemory(&itm
,sizeof(LVITEMA
));
2519 itm
.mask
= LVIF_STATE
| LVIF_PARAM
;
2520 itm
.stateMask
= LVIS_FOCUSED
| LVIS_SELECTED
;
2521 itm
.iItem
= lpLVItem
->iItem
;
2523 ListView_GetItemA(hwnd
,&itm
);
2526 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2527 nmlv
.hdr
.hwndFrom
= hwnd
;
2528 nmlv
.hdr
.idFrom
= lCtrlId
;
2529 nmlv
.hdr
.code
= LVN_ITEMCHANGING
;
2530 nmlv
.uNewState
= lpLVItem
->state
;
2531 nmlv
.uOldState
= itm
.state
;
2532 nmlv
.uChanged
= LVIF_STATE
;
2533 nmlv
.lParam
= itm
.lParam
;
2534 nmlv
.iItem
= lpLVItem
->iItem
;
2536 if ((itm
.state
& lpLVItem
->stateMask
) !=
2537 (lpLVItem
->state
& lpLVItem
->stateMask
))
2539 /* send LVN_ITEMCHANGING notification */
2540 if (!ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
))
2542 if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
2544 if (lpLVItem
->state
& LVIS_FOCUSED
)
2545 infoPtr
->nFocusedItem
= lpLVItem
->iItem
;
2546 else if (infoPtr
->nFocusedItem
== lpLVItem
->iItem
)
2547 infoPtr
->nFocusedItem
= -1;
2549 if (lpLVItem
->stateMask
& LVIS_SELECTED
)
2551 if (lpLVItem
->state
& LVIS_SELECTED
)
2553 if (lStyle
& LVS_SINGLESEL
)
2555 LISTVIEW_RemoveAllSelections(hwnd
);
2557 LISTVIEW_AddSelectionRange(hwnd
,lpLVItem
->iItem
,lpLVItem
->iItem
);
2560 LISTVIEW_RemoveSelectionRange(hwnd
,lpLVItem
->iItem
,
2564 nmlv
.hdr
.code
= LVN_ITEMCHANGED
;
2566 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
2568 rcItem
.left
= LVIR_BOUNDS
;
2569 LISTVIEW_GetItemRect(hwnd
, lpLVItem
->iItem
, &rcItem
);
2570 InvalidateRect(hwnd
, &rcItem
, TRUE
);
2578 if (lpLVItem
!= NULL
)
2580 if (lpLVItem
->iSubItem
== 0)
2582 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2583 if (hdpaSubItems
!= NULL
&& hdpaSubItems
!= (HDPA
)-1)
2585 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
2588 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
2589 nmlv
.hdr
.hwndFrom
= hwnd
;
2590 nmlv
.hdr
.idFrom
= lCtrlId
;
2591 nmlv
.hdr
.code
= LVN_ITEMCHANGING
;
2592 nmlv
.lParam
= lpItem
->lParam
;
2593 uChanged
= LISTVIEW_GetItemChanges(lpItem
, lpLVItem
);
2596 if (uChanged
& LVIF_STATE
)
2598 nmlv
.uNewState
= lpLVItem
->state
& lpLVItem
->stateMask
;
2599 nmlv
.uOldState
= lpItem
->state
& lpLVItem
->stateMask
;
2601 if (nmlv
.uNewState
& LVIS_SELECTED
)
2604 * This is redundant if called through SetSelection
2606 * however is required if the used directly calls SetItem
2607 * to set the selection.
2609 if (lStyle
& LVS_SINGLESEL
)
2611 LISTVIEW_RemoveAllSelections(hwnd
);
2614 LISTVIEW_AddSelectionRange(hwnd
,lpLVItem
->iItem
,
2617 else if (lpLVItem
->stateMask
& LVIS_SELECTED
)
2619 LISTVIEW_RemoveSelectionRange(hwnd
,lpLVItem
->iItem
,
2622 if (nmlv
.uNewState
& LVIS_FOCUSED
)
2625 * This is a fun hoop to jump to try to catch if
2626 * the user is calling us directly to call focus or if
2627 * this function is being called as a result of a
2628 * SetItemFocus call.
2630 if (infoPtr
->nFocusedItem
>= 0)
2631 LISTVIEW_SetItemFocus(hwnd
, lpLVItem
->iItem
);
2635 nmlv
.uChanged
= uChanged
;
2636 nmlv
.iItem
= lpLVItem
->iItem
;
2637 nmlv
.lParam
= lpItem
->lParam
;
2638 /* send LVN_ITEMCHANGING notification */
2639 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
2641 /* copy information */
2642 bResult
= LISTVIEW_InitItem(hwnd
, lpItem
, lpLVItem
);
2644 /* if LVS_LIST or LVS_SMALLICON, update the width of the items
2645 based on the width of the items text */
2646 if((uView
== LVS_LIST
) || (uView
== LVS_SMALLICON
))
2648 item_width
= LISTVIEW_GetStringWidthA(hwnd
, lpItem
->pszText
);
2650 if(item_width
> infoPtr
->nItemWidth
)
2651 infoPtr
->nItemWidth
= item_width
;
2654 /* send LVN_ITEMCHANGED notification */
2655 nmlv
.hdr
.code
= LVN_ITEMCHANGED
;
2656 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
2665 rcItem
.left
= LVIR_BOUNDS
;
2666 LISTVIEW_GetItemRect(hwnd
, lpLVItem
->iItem
, &rcItem
);
2667 InvalidateRect(hwnd
, &rcItem
, TRUE
);
2679 * Sets subitem attributes.
2682 * [I] HWND : window handle
2683 * [I] LPLVITEM : new subitem atttributes
2689 static BOOL
LISTVIEW_SetSubItem(HWND hwnd
, LPLVITEMA lpLVItem
)
2691 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2692 BOOL bResult
= FALSE
;
2694 LISTVIEW_SUBITEM
*lpSubItem
;
2695 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2698 if (lStyle
& LVS_OWNERDATA
)
2701 if (lpLVItem
!= NULL
)
2703 if (lpLVItem
->iSubItem
> 0)
2705 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
2706 if (hdpaSubItems
!= NULL
)
2708 /* set subitem only if column is present */
2709 if (Header_GetItemCount(infoPtr
->hwndHeader
) > lpLVItem
->iSubItem
)
2711 lpSubItem
= LISTVIEW_GetSubItem(hdpaSubItems
, lpLVItem
->iSubItem
);
2712 if (lpSubItem
!= NULL
)
2714 bResult
= LISTVIEW_InitSubItem(hwnd
, lpSubItem
, lpLVItem
);
2718 bResult
= LISTVIEW_AddSubItem(hwnd
, lpLVItem
);
2721 rcItem
.left
= LVIR_BOUNDS
;
2722 LISTVIEW_GetItemRect(hwnd
, lpLVItem
->iItem
, &rcItem
);
2723 InvalidateRect(hwnd
, &rcItem
, FALSE
);
2734 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2737 * [I] HWND : window handle
2742 static INT
LISTVIEW_GetTopIndex(HWND hwnd
)
2744 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
2745 UINT uView
= lStyle
& LVS_TYPEMASK
;
2747 SCROLLINFO scrollInfo
;
2749 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
2750 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
2751 scrollInfo
.fMask
= SIF_POS
;
2753 if (uView
== LVS_LIST
)
2755 if (lStyle
& WS_HSCROLL
)
2757 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
2759 nItem
= scrollInfo
.nPos
* LISTVIEW_GetCountPerColumn(hwnd
);
2763 else if (uView
== LVS_REPORT
)
2765 if (lStyle
& WS_VSCROLL
)
2767 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
2769 nItem
= scrollInfo
.nPos
;
2782 * [I] HWND : window handle
2783 * [I] HDC : device context handle
2784 * [I] INT : item index
2785 * [I] INT : subitem index
2786 * [I] RECT * : clipping rectangle
2791 static VOID
LISTVIEW_DrawSubItem(HWND hwnd
, HDC hdc
, INT nItem
, INT nSubItem
,
2792 RECT rcItem
, BOOL Selected
)
2794 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2795 CHAR szDispText
[DISP_TEXT_SIZE
];
2797 UINT textoutOptions
= ETO_CLIPPED
| ETO_OPAQUE
;
2800 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd
, hdc
,
2803 /* get information needed for drawing the item */
2804 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
2805 lvItem
.mask
= LVIF_TEXT
;
2806 lvItem
.iItem
= nItem
;
2807 lvItem
.iSubItem
= nSubItem
;
2808 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
2809 lvItem
.pszText
= szDispText
;
2810 LISTVIEW_GetItemA(hwnd
, &lvItem
, TRUE
);
2812 /* redraw the background of the item */
2814 if(infoPtr
->nColumnCount
== (nSubItem
+ 1))
2815 rcTemp
.right
= infoPtr
->rcList
.right
;
2817 rcTemp
.right
+=WIDTH_PADDING
;
2819 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
2821 /* set item colors */
2822 if (ListView_GetItemState(hwnd
,nItem
,LVIS_SELECTED
) && Selected
)
2824 if (infoPtr
->bFocus
)
2826 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2827 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2831 SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
2832 SetTextColor(hdc
, GetSysColor(COLOR_BTNTEXT
));
2837 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
2839 SetBkMode(hdc
, TRANSPARENT
);
2840 textoutOptions
&= ~ETO_OPAQUE
;
2844 SetBkMode(hdc
, OPAQUE
);
2845 SetBkColor(hdc
, infoPtr
->clrTextBk
);
2848 SetTextColor(hdc
, infoPtr
->clrText
);
2851 ExtTextOutA(hdc
, rcItem
.left
, rcItem
.top
, textoutOptions
,
2852 &rcItem
, lvItem
.pszText
, lstrlenA(lvItem
.pszText
), NULL
);
2856 /* fill in the gap */
2858 if (nSubItem
< Header_GetItemCount(infoPtr
->hwndHeader
)-1)
2860 CopyRect(&rec
,&rcItem
);
2861 rec
.left
= rec
.right
;
2862 rec
.right
= rec
.left
+REPORT_MARGINX
;
2863 ExtTextOutA(hdc
, rec
.left
, rec
.top
, textoutOptions
,
2864 &rec
, NULL
, 0, NULL
);
2866 CopyRect(&rec
,&rcItem
);
2867 rec
.right
= rec
.left
;
2868 rec
.left
= rec
.left
- REPORT_MARGINX
;
2869 ExtTextOutA(hdc
, rec
.left
, rec
.top
, textoutOptions
,
2870 &rec
, NULL
, 0, NULL
);
2880 * [I] HWND : window handle
2881 * [I] HDC : device context handle
2882 * [I] INT : item index
2883 * [I] RECT * : clipping rectangle
2888 static VOID
LISTVIEW_DrawItem(HWND hwnd
, HDC hdc
, INT nItem
, RECT rcItem
, BOOL FullSelect
, RECT
* SuggestedFocus
)
2890 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
2891 CHAR szDispText
[DISP_TEXT_SIZE
];
2896 DWORD dwTextColor
,dwTextX
;
2897 BOOL bImage
= FALSE
;
2899 UINT textoutOptions
= ETO_OPAQUE
| ETO_CLIPPED
;
2902 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd
, hdc
, nItem
);
2905 /* get information needed for drawing the item */
2906 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
2907 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
| LVIF_INDENT
;
2908 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_STATEIMAGEMASK
;
2909 lvItem
.iItem
= nItem
;
2910 lvItem
.iSubItem
= 0;
2911 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
2912 lvItem
.pszText
= szDispText
;
2913 LISTVIEW_GetItemA(hwnd
, &lvItem
, TRUE
);
2915 /* redraw the background of the item */
2917 if(infoPtr
->nColumnCount
== (nItem
+ 1))
2918 rcTemp
.right
= infoPtr
->rcList
.right
;
2920 rcTemp
.right
+=WIDTH_PADDING
;
2922 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
2925 if (lvItem
.iIndent
>0 && infoPtr
->iconSize
.cx
> 0)
2927 rcItem
.left
+= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
2930 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
2934 if (infoPtr
->himlState
!= NULL
)
2936 UINT uStateImage
= (lvItem
.state
& LVIS_STATEIMAGEMASK
) >> 12;
2937 if (uStateImage
> 0)
2939 ImageList_Draw(infoPtr
->himlState
, uStateImage
- 1, hdc
, rcItem
.left
,
2940 rcItem
.top
, ILD_NORMAL
);
2943 rcItem
.left
+= infoPtr
->iconSize
.cx
;
2945 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
;
2950 if (infoPtr
->himlSmall
!= NULL
)
2952 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
!= FALSE
) &&
2955 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
2956 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
2957 rcItem
.top
, ILD_SELECTED
);
2959 else if (lvItem
.iImage
>=0)
2961 ImageList_SetBkColor(infoPtr
->himlSmall
, CLR_NONE
);
2962 ImageList_Draw(infoPtr
->himlSmall
, lvItem
.iImage
, hdc
, rcItem
.left
,
2963 rcItem
.top
, ILD_NORMAL
);
2966 rcItem
.left
+= infoPtr
->iconSize
.cx
;
2969 SuggestedFocus
->left
+= infoPtr
->iconSize
.cx
;
2973 /* Don't bother painting item being edited */
2974 if (infoPtr
->hwndEdit
&& lvItem
.state
& LVIS_FOCUSED
&& !FullSelect
)
2977 if ((lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
!= FALSE
))
2979 /* set item colors */
2980 dwBkColor
= SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2981 dwTextColor
= SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2982 /* set raster mode */
2983 nMixMode
= SetROP2(hdc
, R2_XORPEN
);
2985 else if ((GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_SHOWSELALWAYS
) &&
2986 (lvItem
.state
& LVIS_SELECTED
) && (infoPtr
->bFocus
== FALSE
))
2988 dwBkColor
= SetBkColor(hdc
, GetSysColor(COLOR_3DFACE
));
2989 dwTextColor
= SetTextColor(hdc
, GetSysColor(COLOR_BTNTEXT
));
2990 /* set raster mode */
2991 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
2995 /* set item colors */
2996 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
2998 dwBkColor
= GetBkColor(hdc
);
2999 iBkMode
= SetBkMode(hdc
, TRANSPARENT
);
3000 textoutOptions
&= ~ETO_OPAQUE
;
3004 dwBkColor
= SetBkColor(hdc
, infoPtr
->clrTextBk
);
3005 iBkMode
= SetBkMode(hdc
, OPAQUE
);
3008 dwTextColor
= SetTextColor(hdc
, infoPtr
->clrText
);
3009 /* set raster mode */
3010 nMixMode
= SetROP2(hdc
, R2_COPYPEN
);
3013 nLabelWidth
= ListView_GetStringWidthA(hwnd
, lvItem
.pszText
);
3014 if (rcItem
.left
+ nLabelWidth
< rcItem
.right
)
3017 rcItem
.right
= rcItem
.left
+ nLabelWidth
+ TRAILING_PADDING
;
3019 rcItem
.right
+= IMAGE_PADDING
;
3023 dwTextX
= rcItem
.left
+ 1;
3025 dwTextX
+= IMAGE_PADDING
;
3028 ExtTextOutA(hdc
, dwTextX
, rcItem
.top
, textoutOptions
,
3029 &rcItem
, lvItem
.pszText
, lstrlenA(lvItem
.pszText
), NULL
);
3031 if ((FullSelect
)&&(Header_GetItemCount(infoPtr
->hwndHeader
) > 1))
3033 /* fill in the gap */
3035 CopyRect(&rec
,&rcItem
);
3036 rec
.left
= rec
.right
;
3037 rec
.right
= rec
.left
+REPORT_MARGINX
;
3038 ExtTextOutA(hdc
, rec
.left
, rec
.top
, textoutOptions
,
3039 &rec
, NULL
, 0, NULL
);
3043 CopyRect(SuggestedFocus
,&rcItem
);
3047 SetROP2(hdc
, R2_COPYPEN
);
3048 SetBkColor(hdc
, dwBkColor
);
3049 SetTextColor(hdc
, dwTextColor
);
3051 SetBkMode(hdc
, iBkMode
);
3057 * Draws an item when in large icon display mode.
3060 * [I] HWND : window handle
3061 * [I] HDC : device context handle
3062 * [I] LISTVIEW_ITEM * : item
3063 * [I] INT : item index
3064 * [I] RECT * : clipping rectangle
3069 static VOID
LISTVIEW_DrawLargeItem(HWND hwnd
, HDC hdc
, INT nItem
, RECT rcItem
,
3070 RECT
*SuggestedFocus
)
3072 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3073 CHAR szDispText
[DISP_TEXT_SIZE
];
3074 INT nDrawPosX
= rcItem
.left
;
3075 INT nLabelWidth
, rcWidth
;
3078 UINT textoutOptions
= ETO_CLIPPED
| ETO_OPAQUE
;
3081 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
3082 bottom=%d)\n", hwnd
, hdc
, nItem
, rcItem
.left
, rcItem
.top
, rcItem
.right
,
3085 /* get information needed for drawing the item */
3086 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
3087 lvItem
.mask
= LVIF_TEXT
| LVIF_IMAGE
| LVIF_STATE
;
3088 lvItem
.stateMask
= LVIS_SELECTED
| LVIS_FOCUSED
;
3089 lvItem
.iItem
= nItem
;
3090 lvItem
.iSubItem
= 0;
3091 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
3092 lvItem
.pszText
= szDispText
;
3093 LISTVIEW_GetItemA(hwnd
, &lvItem
, TRUE
);
3095 /* redraw the background of the item */
3097 if(infoPtr
->nColumnCount
== (nItem
+ 1))
3098 rcTemp
.right
= infoPtr
->rcList
.right
;
3100 rcTemp
.right
+=WIDTH_PADDING
;
3102 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3104 if (lvItem
.state
& LVIS_SELECTED
)
3106 /* set item colors */
3107 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
3108 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
3109 /* set raster mode */
3110 SetROP2(hdc
, R2_XORPEN
);
3114 /* set item colors */
3115 if ( (infoPtr
->clrTextBk
== CLR_DEFAULT
) || (infoPtr
->clrTextBk
== CLR_NONE
) )
3117 SetBkMode(hdc
, TRANSPARENT
);
3118 textoutOptions
&= ~ETO_OPAQUE
;
3122 SetBkMode(hdc
, OPAQUE
);
3123 SetBkColor(hdc
, infoPtr
->clrTextBk
);
3126 SetTextColor(hdc
, infoPtr
->clrText
);
3127 /* set raster mode */
3128 SetROP2(hdc
, R2_COPYPEN
);
3131 if (infoPtr
->himlNormal
!= NULL
)
3133 rcItem
.top
+= ICON_TOP_PADDING
;
3134 nDrawPosX
+= (infoPtr
->iconSpacing
.cx
- infoPtr
->iconSize
.cx
) / 2;
3135 if ((lvItem
.state
& LVIS_SELECTED
) && (lvItem
.iImage
>=0))
3137 ImageList_Draw(infoPtr
->himlNormal
, lvItem
.iImage
, hdc
, nDrawPosX
,
3138 rcItem
.top
, ILD_SELECTED
);
3140 else if (lvItem
.iImage
>=0)
3142 ImageList_Draw(infoPtr
->himlNormal
, lvItem
.iImage
, hdc
, nDrawPosX
,
3143 rcItem
.top
, ILD_NORMAL
);
3147 /* Don't bother painting item being edited */
3148 if (infoPtr
->hwndEdit
&& lvItem
.state
& LVIS_FOCUSED
)
3151 InflateRect(&rcItem
, -(2*CAPTION_BORDER
), 0);
3152 rcItem
.top
+= infoPtr
->iconSize
.cy
+ ICON_BOTTOM_PADDING
;
3153 nLabelWidth
= ListView_GetStringWidthA(hwnd
, lvItem
.pszText
);
3154 GetTextMetricsA(hdc
, &tm
);
3156 /* append an ellipse ('...') if the caption won't fit in the rect */
3157 rcWidth
= max(0, rcItem
.right
- rcItem
.left
);
3158 if (nLabelWidth
> rcWidth
)
3160 INT i
, len
, eos
, nCharsFit
;
3161 /* give or take a couple, how many average sized chars would fit? */
3162 nCharsFit
= tm
.tmAveCharWidth
> 0 ? (rcWidth
/tm
.tmAveCharWidth
)+2 : 0;
3163 /* place the ellipse accordingly, without overrunning the buffer */
3164 len
= strlen(szDispText
);
3165 eos
= min((nCharsFit
> 1 && nCharsFit
< len
) ? nCharsFit
+3 : len
+2,
3166 sizeof(szDispText
)-1);
3168 nLabelWidth
= ListView_GetStringWidthA(hwnd
, szDispText
);
3169 while ((nLabelWidth
> rcWidth
) && (eos
> 3))
3171 for (i
= 1; i
< 4; i
++)
3172 szDispText
[eos
-i
] = '.';
3173 /* shift the ellipse one char to the left for each iteration */
3174 szDispText
[eos
--] = '\0';
3175 nLabelWidth
= ListView_GetStringWidthA(hwnd
, szDispText
);
3179 InflateRect(&rcItem
, 2*CAPTION_BORDER
, 0);
3180 nDrawPosX
= infoPtr
->iconSpacing
.cx
- 2*CAPTION_BORDER
- nLabelWidth
;
3183 rcItem
.left
+= nDrawPosX
/ 2;
3184 rcItem
.right
= rcItem
.left
+ nLabelWidth
+ 2*CAPTION_BORDER
;
3189 rcItem
.right
= rcItem
.left
+ infoPtr
->iconSpacing
.cx
- 1;
3193 rcItem
.bottom
= rcItem
.top
+ tm
.tmHeight
+ HEIGHT_PADDING
;
3195 ExtTextOutA(hdc
, rcItem
.left
+ CAPTION_BORDER
, rcItem
.top
, textoutOptions
,
3196 &rcItem
, lvItem
.pszText
, lstrlenA(lvItem
.pszText
), NULL
);
3199 CopyRect(SuggestedFocus
,&rcItem
);
3204 * Draws listview items when in report display mode.
3207 * [I] HWND : window handle
3208 * [I] HDC : device context handle
3213 static VOID
LISTVIEW_RefreshReport(HWND hwnd
, HDC hdc
, DWORD cdmode
)
3215 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
3216 SCROLLINFO scrollInfo
;
3217 INT nDrawPosY
= infoPtr
->rcList
.top
;
3219 RECT rcItem
, rcTemp
;
3224 DWORD cditemmode
= CDRF_DODEFAULT
;
3225 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3228 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
3229 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
3230 scrollInfo
.fMask
= SIF_POS
;
3232 nItem
= ListView_GetTopIndex(hwnd
);
3234 /* add 1 for displaying a partial item at the bottom */
3235 nLast
= nItem
+ LISTVIEW_GetCountPerColumn(hwnd
) + 1;
3236 nLast
= min(nLast
, GETITEMCOUNT(infoPtr
));
3238 /* send cache hint notification */
3239 if (GetWindowLongA(hwnd
,GWL_STYLE
) & LVS_OWNERDATA
)
3243 nmlv
.hdr
.hwndFrom
= hwnd
;
3244 nmlv
.hdr
.idFrom
= GetWindowLongA(hwnd
,GWL_ID
);
3245 nmlv
.hdr
.code
= LVN_ODCACHEHINT
;
3249 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)nmlv
.hdr
.idFrom
,
3253 nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
3254 infoPtr
->nColumnCount
= nColumnCount
; /* update nColumnCount */
3255 FullSelected
= infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
;
3257 /* clear the background of any part of the control that doesn't contain items */
3258 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3259 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3261 /* nothing to draw */
3262 if(GETITEMCOUNT(infoPtr
) == 0)
3265 /* Get scroll bar info once before loop */
3266 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
3267 scrollOffset
= scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
3269 for (; nItem
< nLast
; nItem
++)
3271 RECT SuggestedFocusRect
;
3274 if (lStyle
& LVS_OWNERDRAWFIXED
)
3276 UINT uID
= GetWindowLongA( hwnd
, GWL_ID
);
3281 TRACE("Owner Drawn\n");
3282 dis
.CtlType
= ODT_LISTVIEW
;
3285 dis
.itemAction
= ODA_DRAWENTIRE
;
3288 if (LISTVIEW_IsSelected(hwnd
,nItem
)) dis
.itemState
|=ODS_SELECTED
;
3289 if (nItem
==infoPtr
->nFocusedItem
) dis
.itemState
|=ODS_FOCUS
;
3291 dis
.hwndItem
= hwnd
;
3294 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
3296 dis
.rcItem
.left
= -scrollOffset
;
3297 dis
.rcItem
.right
= max(dis
.rcItem
.left
, br
.right
- scrollOffset
);
3298 dis
.rcItem
.top
= nDrawPosY
;
3299 dis
.rcItem
.bottom
= dis
.rcItem
.top
+ infoPtr
->nItemHeight
;
3301 ZeroMemory(&item
,sizeof(LVITEMA
));
3303 item
.mask
= LVIF_PARAM
;
3304 ListView_GetItemA(hwnd
,&item
);
3306 dis
.itemData
= item
.lParam
;
3308 if (SendMessageA(GetParent(hwnd
),WM_DRAWITEM
,(WPARAM
)uID
,(LPARAM
)&dis
))
3310 nDrawPosY
+= infoPtr
->nItemHeight
;
3319 Header_GetItemRect(infoPtr
->hwndHeader
, 0, &ir
);
3320 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
3322 ir
.left
+= REPORT_MARGINX
;
3323 ir
.right
= max(ir
.left
, br
.right
- REPORT_MARGINX
);
3325 ir
.bottom
= ir
.top
+ infoPtr
->nItemHeight
;
3327 CopyRect(&SuggestedFocusRect
,&ir
);
3330 for (j
= 0; j
< nColumnCount
; j
++)
3332 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3333 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (hwnd
, hdc
, nItem
, j
,
3335 if (cditemmode
& CDRF_SKIPDEFAULT
)
3338 Header_GetItemRect(infoPtr
->hwndHeader
, j
, &rcItem
);
3340 rcItem
.left
+= REPORT_MARGINX
;
3341 rcItem
.right
= max(rcItem
.left
, rcItem
.right
- REPORT_MARGINX
);
3342 rcItem
.top
= nDrawPosY
;
3343 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3345 /* Offset the Scroll Bar Pos */
3346 rcItem
.left
-= scrollOffset
;
3347 rcItem
.right
-= scrollOffset
;
3351 LISTVIEW_DrawItem(hwnd
, hdc
, nItem
, rcItem
, FullSelected
,
3352 &SuggestedFocusRect
);
3356 LISTVIEW_DrawSubItem(hwnd
, hdc
, nItem
, j
, rcItem
,
3360 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3361 LISTVIEW_SendCustomDrawItemNotify(hwnd
, hdc
, nItem
, 0,
3362 CDDS_ITEMPOSTPAINT
);
3367 if (LISTVIEW_GetItemState(hwnd
,nItem
,LVIS_FOCUSED
) && infoPtr
->bFocus
)
3370 if (FullSelected
&& LISTVIEW_GetItemState(hwnd
,nItem
,LVIS_SELECTED
))
3371 rop
= SetROP2(hdc
, R2_XORPEN
);
3373 Rectangle(hdc
, SuggestedFocusRect
.left
, SuggestedFocusRect
.top
,
3374 SuggestedFocusRect
.right
,SuggestedFocusRect
.bottom
);
3377 SetROP2(hdc
, R2_COPYPEN
);
3379 nDrawPosY
+= infoPtr
->nItemHeight
;
3385 * Retrieves the number of items that can fit vertically in the client area.
3388 * [I] HWND : window handle
3391 * Number of items per row.
3393 static INT
LISTVIEW_GetCountPerRow(HWND hwnd
)
3395 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
3396 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3397 INT nListWidth
= infoPtr
->rcList
.right
- infoPtr
->rcList
.left
;
3398 INT nCountPerRow
= 1;
3402 if (uView
== LVS_REPORT
)
3408 nCountPerRow
= nListWidth
/ infoPtr
->nItemWidth
;
3409 if (nCountPerRow
== 0)
3416 return nCountPerRow
;
3421 * Retrieves the number of items that can fit horizontally in the client
3425 * [I] HWND : window handle
3428 * Number of items per column.
3430 static INT
LISTVIEW_GetCountPerColumn(HWND hwnd
)
3432 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
,0);
3433 INT nListHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
3434 INT nCountPerColumn
= 1;
3436 if (nListHeight
> 0)
3438 nCountPerColumn
= nListHeight
/ infoPtr
->nItemHeight
;
3439 if (nCountPerColumn
== 0)
3441 nCountPerColumn
= 1;
3445 return nCountPerColumn
;
3450 * Retrieves the number of columns needed to display all the items when in
3451 * list display mode.
3454 * [I] HWND : window handle
3457 * Number of columns.
3459 static INT
LISTVIEW_GetColumnCount(HWND hwnd
)
3461 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3462 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3463 INT nColumnCount
= 0;
3465 if ((lStyle
& LVS_TYPEMASK
) == LVS_LIST
)
3467 if (infoPtr
->rcList
.right
% infoPtr
->nItemWidth
== 0)
3469 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nItemWidth
;
3473 nColumnCount
= infoPtr
->rcList
.right
/ infoPtr
->nItemWidth
+ 1;
3477 return nColumnCount
;
3483 * Draws listview items when in list display mode.
3486 * [I] HWND : window handle
3487 * [I] HDC : device context handle
3492 static VOID
LISTVIEW_RefreshList(HWND hwnd
, HDC hdc
, DWORD cdmode
)
3494 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3495 RECT rcItem
, FocusRect
, rcTemp
;
3499 INT nCountPerColumn
;
3500 INT nItemWidth
= infoPtr
->nItemWidth
;
3501 INT nItemHeight
= infoPtr
->nItemHeight
;
3502 DWORD cditemmode
= CDRF_DODEFAULT
;
3504 /* get number of fully visible columns */
3505 nColumnCount
= LISTVIEW_GetColumnCount(hwnd
);
3506 infoPtr
->nColumnCount
= nColumnCount
;
3507 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
3508 nItem
= ListView_GetTopIndex(hwnd
);
3510 /* paint the background of the control that doesn't contain any items */
3511 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3512 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3514 /* nothing to draw, return here */
3515 if(GETITEMCOUNT(infoPtr
) == 0)
3518 for (i
= 0; i
< nColumnCount
; i
++)
3520 for (j
= 0; j
< nCountPerColumn
; j
++, nItem
++)
3522 if (nItem
>= GETITEMCOUNT(infoPtr
))
3525 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3526 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (hwnd
, hdc
, nItem
, 0,
3528 if (cditemmode
& CDRF_SKIPDEFAULT
)
3531 rcItem
.top
= j
* nItemHeight
;
3532 rcItem
.left
= i
* nItemWidth
;
3533 rcItem
.bottom
= rcItem
.top
+ nItemHeight
;
3534 rcItem
.right
= rcItem
.left
+ nItemWidth
;
3535 LISTVIEW_DrawItem(hwnd
, hdc
, nItem
, rcItem
, FALSE
, &FocusRect
);
3539 if (LISTVIEW_GetItemState(hwnd
,nItem
,LVIS_FOCUSED
) && infoPtr
->bFocus
)
3540 Rectangle(hdc
, FocusRect
.left
, FocusRect
.top
,
3541 FocusRect
.right
,FocusRect
.bottom
);
3543 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3544 LISTVIEW_SendCustomDrawItemNotify(hwnd
, hdc
, nItem
, 0,
3545 CDDS_ITEMPOSTPAINT
);
3553 * Draws listview items when in icon or small icon display mode.
3556 * [I] HWND : window handle
3557 * [I] HDC : device context handle
3562 static VOID
LISTVIEW_RefreshIcon(HWND hwnd
, HDC hdc
, BOOL bSmall
, DWORD cdmode
)
3564 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3567 RECT rcItem
, SuggestedFocus
, rcTemp
;
3569 DWORD cditemmode
= CDRF_DODEFAULT
;
3571 infoPtr
->nColumnCount
= 1; /* set this to an arbitrary value to prevent */
3572 /* DrawItem from erasing the incorrect background area */
3574 /* paint the background of the control that doesn't contain any items */
3575 SubtractRect(&rcTemp
, &infoPtr
->rcList
, &infoPtr
->rcView
);
3576 LISTVIEW_FillBackground(hwnd
, hdc
, &rcTemp
);
3578 /* nothing to draw, return here */
3579 if(GETITEMCOUNT(infoPtr
) == 0)
3582 LISTVIEW_GetOrigin(hwnd
, &ptOrigin
);
3583 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
3585 if (cdmode
& CDRF_NOTIFYITEMDRAW
)
3586 cditemmode
= LISTVIEW_SendCustomDrawItemNotify (hwnd
, hdc
, i
, 0,
3588 if (cditemmode
& CDRF_SKIPDEFAULT
)
3591 LISTVIEW_GetItemPosition(hwnd
, i
, &ptPosition
);
3592 ptPosition
.x
+= ptOrigin
.x
;
3593 ptPosition
.y
+= ptOrigin
.y
;
3595 if (ptPosition
.y
+ infoPtr
->nItemHeight
> infoPtr
->rcList
.top
)
3597 if (ptPosition
.x
+ infoPtr
->nItemWidth
> infoPtr
->rcList
.left
)
3599 if (ptPosition
.y
< infoPtr
->rcList
.bottom
)
3601 if (ptPosition
.x
< infoPtr
->rcList
.right
)
3603 rcItem
.top
= ptPosition
.y
;
3604 rcItem
.left
= ptPosition
.x
;
3605 rcItem
.bottom
= rcItem
.top
+ infoPtr
->nItemHeight
;
3606 rcItem
.right
= rcItem
.left
+ infoPtr
->nItemWidth
;
3607 if (bSmall
== FALSE
)
3609 LISTVIEW_DrawLargeItem(hwnd
, hdc
, i
, rcItem
, &SuggestedFocus
);
3613 LISTVIEW_DrawItem(hwnd
, hdc
, i
, rcItem
, FALSE
, &SuggestedFocus
);
3618 if (LISTVIEW_GetItemState(hwnd
,i
,LVIS_FOCUSED
) &&
3620 Rectangle(hdc
, SuggestedFocus
.left
, SuggestedFocus
.top
,
3621 SuggestedFocus
.right
,SuggestedFocus
.bottom
);
3626 if (cditemmode
& CDRF_NOTIFYPOSTPAINT
)
3627 LISTVIEW_SendCustomDrawItemNotify(hwnd
, hdc
, i
, 0,
3628 CDDS_ITEMPOSTPAINT
);
3634 * Draws listview items.
3637 * [I] HWND : window handle
3638 * [I] HDC : device context handle
3643 static VOID
LISTVIEW_Refresh(HWND hwnd
, HDC hdc
)
3645 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3646 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3652 GetClientRect(hwnd
, &rect
);
3653 cdmode
= LISTVIEW_SendCustomDrawNotify(hwnd
,CDDS_PREPAINT
,hdc
,rect
);
3655 if (cdmode
== CDRF_SKIPDEFAULT
) return;
3658 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
3660 /* select the dotted pen (for drawing the focus box) */
3661 hPen
= CreatePen(PS_ALTERNATE
, 1, 0);
3662 hOldPen
= SelectObject(hdc
, hPen
);
3664 /* select transparent brush (for drawing the focus box) */
3665 SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
3667 if (uView
== LVS_LIST
)
3669 LISTVIEW_RefreshList(hwnd
, hdc
, cdmode
);
3671 else if (uView
== LVS_REPORT
)
3673 LISTVIEW_RefreshReport(hwnd
, hdc
, cdmode
);
3675 else if (uView
== LVS_SMALLICON
)
3677 LISTVIEW_RefreshIcon(hwnd
, hdc
, TRUE
, cdmode
);
3679 else if (uView
== LVS_ICON
)
3681 LISTVIEW_RefreshIcon(hwnd
, hdc
, FALSE
, cdmode
);
3684 /* unselect objects */
3685 SelectObject(hdc
, hOldFont
);
3686 SelectObject(hdc
, hOldPen
);
3691 if (cdmode
& CDRF_NOTIFYPOSTPAINT
)
3692 LISTVIEW_SendCustomDrawNotify(hwnd
, CDDS_POSTPAINT
, hdc
, rect
);
3698 * Calculates the approximate width and height of a given number of items.
3701 * [I] HWND : window handle
3702 * [I] INT : number of items
3707 * Returns a DWORD. The width in the low word and the height in high word.
3709 static LRESULT
LISTVIEW_ApproximateViewRect(HWND hwnd
, INT nItemCount
,
3710 WORD wWidth
, WORD wHeight
)
3712 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3713 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3714 INT nItemCountPerColumn
= 1;
3715 INT nColumnCount
= 0;
3716 DWORD dwViewRect
= 0;
3718 if (nItemCount
== -1)
3720 nItemCount
= GETITEMCOUNT(infoPtr
);
3723 if (uView
== LVS_LIST
)
3725 if (wHeight
== 0xFFFF)
3727 /* use current height */
3728 wHeight
= infoPtr
->rcList
.bottom
- infoPtr
->rcList
.top
;
3731 if (wHeight
< infoPtr
->nItemHeight
)
3733 wHeight
= infoPtr
->nItemHeight
;
3738 if (infoPtr
->nItemHeight
> 0)
3740 nItemCountPerColumn
= wHeight
/ infoPtr
->nItemHeight
;
3741 if (nItemCountPerColumn
== 0)
3743 nItemCountPerColumn
= 1;
3746 if (nItemCount
% nItemCountPerColumn
!= 0)
3748 nColumnCount
= nItemCount
/ nItemCountPerColumn
;
3752 nColumnCount
= nItemCount
/ nItemCountPerColumn
+ 1;
3757 /* Microsoft padding magic */
3758 wHeight
= nItemCountPerColumn
* infoPtr
->nItemHeight
+ 2;
3759 wWidth
= nColumnCount
* infoPtr
->nItemWidth
+ 2;
3761 dwViewRect
= MAKELONG(wWidth
, wHeight
);
3763 else if (uView
== LVS_REPORT
)
3767 else if (uView
== LVS_SMALLICON
)
3771 else if (uView
== LVS_ICON
)
3781 * Arranges listview items in icon display mode.
3784 * [I] HWND : window handle
3785 * [I] INT : alignment code
3791 static LRESULT
LISTVIEW_Arrange(HWND hwnd
, INT nAlignCode
)
3793 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3794 BOOL bResult
= FALSE
;
3796 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
3809 case LVA_SNAPTOGRID
:
3818 /* << LISTVIEW_CreateDragImage >> */
3823 * Removes all listview items and subitems.
3826 * [I] HWND : window handle
3832 static LRESULT
LISTVIEW_DeleteAllItems(HWND hwnd
)
3834 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3835 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
3836 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
3837 UINT uView
= lStyle
& LVS_TYPEMASK
;
3838 LISTVIEW_ITEM
*lpItem
;
3839 LISTVIEW_SUBITEM
*lpSubItem
;
3842 BOOL bResult
= FALSE
;
3847 TRACE("(hwnd=%x,)\n", hwnd
);
3848 LISTVIEW_RemoveAllSelections(hwnd
);
3850 if (lStyle
& LVS_OWNERDATA
)
3852 infoPtr
->hdpaItems
->nItemCount
= 0;
3853 InvalidateRect(hwnd
, NULL
, TRUE
);
3857 if (GETITEMCOUNT(infoPtr
) > 0)
3859 /* initialize memory */
3860 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
3862 /* send LVN_DELETEALLITEMS notification */
3863 nmlv
.hdr
.hwndFrom
= hwnd
;
3864 nmlv
.hdr
.idFrom
= lCtrlId
;
3865 nmlv
.hdr
.code
= LVN_DELETEALLITEMS
;
3868 /* verify if subsequent LVN_DELETEITEM notifications should be
3870 bSuppress
= ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
3872 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
3874 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, i
);
3875 if (hdpaSubItems
!= NULL
)
3877 for (j
= 1; j
< hdpaSubItems
->nItemCount
; j
++)
3879 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, j
);
3880 if (lpSubItem
!= NULL
)
3882 /* free subitem string */
3883 if ((lpSubItem
->pszText
!= NULL
) &&
3884 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
3886 COMCTL32_Free(lpSubItem
->pszText
);
3890 COMCTL32_Free(lpSubItem
);
3894 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
3897 if (bSuppress
== FALSE
)
3899 /* send LVN_DELETEITEM notification */
3900 nmlv
.hdr
.code
= LVN_DELETEITEM
;
3902 nmlv
.lParam
= lpItem
->lParam
;
3903 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
3906 /* free item string */
3907 if ((lpItem
->pszText
!= NULL
) &&
3908 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
3910 COMCTL32_Free(lpItem
->pszText
);
3914 COMCTL32_Free(lpItem
);
3917 DPA_Destroy(hdpaSubItems
);
3921 /* reinitialize listview memory */
3922 bResult
= DPA_DeleteAllPtrs(infoPtr
->hdpaItems
);
3924 /* align items (set position of each item) */
3925 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
3927 if (lStyle
& LVS_ALIGNLEFT
)
3929 LISTVIEW_AlignLeft(hwnd
);
3933 LISTVIEW_AlignTop(hwnd
);
3937 LISTVIEW_UpdateScroll(hwnd
);
3939 /* invalidate client area (optimization needed) */
3940 InvalidateRect(hwnd
, NULL
, TRUE
);
3948 * Removes a column from the listview control.
3951 * [I] HWND : window handle
3952 * [I] INT : column index
3958 static LRESULT
LISTVIEW_DeleteColumn(HWND hwnd
, INT nColumn
)
3960 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
3961 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
3962 UINT uOwnerData
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_OWNERDATA
;
3963 BOOL bResult
= FALSE
;
3965 if (Header_DeleteItem(infoPtr
->hwndHeader
, nColumn
) != FALSE
)
3968 bResult
= LISTVIEW_RemoveColumn(infoPtr
->hdpaItems
, nColumn
);
3970 /* Need to reset the item width when deleting a column */
3971 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
3973 /* reset scroll parameters */
3974 if (uView
== LVS_REPORT
)
3976 /* update scrollbar(s) */
3977 LISTVIEW_UpdateScroll(hwnd
);
3979 /* refresh client area */
3980 InvalidateRect(hwnd
, NULL
, FALSE
);
3989 * Removes an item from the listview control.
3992 * [I] HWND : window handle
3993 * [I] INT : item index
3999 static LRESULT
LISTVIEW_DeleteItem(HWND hwnd
, INT nItem
)
4001 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4002 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4003 UINT uView
= lStyle
& LVS_TYPEMASK
;
4004 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4006 BOOL bResult
= FALSE
;
4008 LISTVIEW_ITEM
*lpItem
;
4009 LISTVIEW_SUBITEM
*lpSubItem
;
4013 TRACE("(hwnd=%x,nItem=%d)\n", hwnd
, nItem
);
4015 /* remove it from the selection range */
4016 ZeroMemory(&item
,sizeof(LVITEMA
));
4017 item
.stateMask
= LVIS_SELECTED
;
4018 LISTVIEW_SetItemState(hwnd
,nItem
,&item
);
4020 LISTVIEW_ShiftSelections(hwnd
,nItem
,-1);
4022 if (lStyle
& LVS_OWNERDATA
)
4024 infoPtr
->hdpaItems
->nItemCount
--;
4025 InvalidateRect(hwnd
, NULL
, TRUE
);
4029 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
4031 /* initialize memory */
4032 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
4034 hdpaSubItems
= (HDPA
)DPA_DeletePtr(infoPtr
->hdpaItems
, nItem
);
4035 if (hdpaSubItems
!= NULL
)
4037 for (i
= 1; i
< hdpaSubItems
->nItemCount
; i
++)
4039 lpSubItem
= (LISTVIEW_SUBITEM
*)DPA_GetPtr(hdpaSubItems
, i
);
4040 if (lpSubItem
!= NULL
)
4042 /* free item string */
4043 if ((lpSubItem
->pszText
!= NULL
) &&
4044 (lpSubItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
4046 COMCTL32_Free(lpSubItem
->pszText
);
4050 COMCTL32_Free(lpSubItem
);
4054 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
4057 /* send LVN_DELETEITEM notification */
4058 nmlv
.hdr
.hwndFrom
= hwnd
;
4059 nmlv
.hdr
.idFrom
= lCtrlId
;
4060 nmlv
.hdr
.code
= LVN_DELETEITEM
;
4062 nmlv
.lParam
= lpItem
->lParam
;
4063 SendMessageA(GetParent(hwnd
), WM_NOTIFY
, (WPARAM
)lCtrlId
,
4066 /* free item string */
4067 if ((lpItem
->pszText
!= NULL
) &&
4068 (lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
))
4070 COMCTL32_Free(lpItem
->pszText
);
4074 COMCTL32_Free(lpItem
);
4077 bResult
= DPA_Destroy(hdpaSubItems
);
4080 /* align items (set position of each item) */
4081 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4083 if (lStyle
& LVS_ALIGNLEFT
)
4085 LISTVIEW_AlignLeft(hwnd
);
4089 LISTVIEW_AlignTop(hwnd
);
4093 /* If this item had focus change focus to next or previous item */
4094 if (GETITEMCOUNT(infoPtr
) > 0)
4096 int sItem
= nItem
< GETITEMCOUNT(infoPtr
) ? nItem
: nItem
- 1;
4097 if (infoPtr
->nFocusedItem
== nItem
)
4098 LISTVIEW_SetItemFocus(hwnd
, sItem
);
4101 infoPtr
->nFocusedItem
= -1;
4103 LISTVIEW_UpdateScroll(hwnd
);
4105 /* refresh client area */
4106 InvalidateRect(hwnd
, NULL
, TRUE
);
4115 * Return edit control handle of current edit label
4118 * [I] HWND : window handle
4124 static LRESULT
LISTVIEW_GetEditControl(HWND hwnd
)
4126 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4127 return infoPtr
->hwndEdit
;
4133 * Callback implementation for editlabel control
4136 * [I] HWND : window handle
4137 * [I] LPSTR : modified text
4138 * [I] DWORD : item index
4145 static BOOL
LISTVIEW_EndEditLabel(HWND hwnd
, LPSTR pszText
, DWORD nItem
)
4147 NMLVDISPINFOA dispInfo
;
4148 LISTVIEW_ITEM
*lpItem
;
4149 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4150 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4151 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4153 BOOL bUpdateItemText
;
4154 LISTVIEW_ITEM lvItemRef
;
4157 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
4159 if (!(lStyle
& LVS_OWNERDATA
))
4161 if (NULL
== (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
4164 if (NULL
== (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
4169 ZeroMemory(&lvItemRef
,sizeof(LISTVIEW_ITEM
));
4170 ZeroMemory(&item
,sizeof(LVITEMA
));
4173 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
4174 ListView_GetItemA(hwnd
,&item
);
4175 lvItemRef
.state
= item
.state
;
4176 lvItemRef
.iImage
= item
.iImage
;
4177 lvItemRef
.lParam
= item
.lParam
;
4178 lpItem
= &lvItemRef
;
4181 dispInfo
.hdr
.hwndFrom
= hwnd
;
4182 dispInfo
.hdr
.idFrom
= nCtrlId
;
4183 dispInfo
.hdr
.code
= LVN_ENDLABELEDITA
;
4184 dispInfo
.item
.mask
= 0;
4185 dispInfo
.item
.iItem
= nItem
;
4186 dispInfo
.item
.state
= lpItem
->state
;
4187 dispInfo
.item
.stateMask
= 0;
4188 dispInfo
.item
.pszText
= pszText
;
4189 dispInfo
.item
.cchTextMax
= pszText
? strlen(pszText
) : 0;
4190 dispInfo
.item
.iImage
= lpItem
->iImage
;
4191 dispInfo
.item
.lParam
= lpItem
->lParam
;
4192 infoPtr
->hwndEdit
= 0;
4194 bUpdateItemText
= ListView_Notify(GetParent(hwnd
), nCtrlId
, &dispInfo
);
4196 /* Do we need to update the Item Text */
4199 if ((lpItem
->pszText
!= LPSTR_TEXTCALLBACKA
)&&(!(lStyle
& LVS_OWNERDATA
)))
4201 Str_SetPtrA(&lpItem
->pszText
, pszText
);
4210 * Begin in place editing of specified list view item
4213 * [I] HWND : window handle
4214 * [I] INT : item index
4221 static HWND
LISTVIEW_EditLabelA(HWND hwnd
, INT nItem
)
4223 NMLVDISPINFOA dispInfo
;
4225 LISTVIEW_ITEM
*lpItem
;
4227 HINSTANCE hinst
= GetWindowLongA(hwnd
, GWL_HINSTANCE
);
4228 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
4229 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4231 CHAR szDispText
[DISP_TEXT_SIZE
];
4232 LVITEMA lvItem
,item
;
4233 LISTVIEW_ITEM lvItemRef
;
4234 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
4236 if (~GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_EDITLABELS
)
4239 /* Is the EditBox still there, if so remove it */
4240 if(infoPtr
->hwndEdit
!= 0)
4245 LISTVIEW_SetSelection(hwnd
, nItem
);
4246 LISTVIEW_SetItemFocus(hwnd
, nItem
);
4248 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
4249 if (!(lStyle
& LVS_OWNERDATA
))
4251 if (NULL
== (hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
)))
4254 if (NULL
== (lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0)))
4259 ZeroMemory(&lvItemRef
,sizeof(LISTVIEW_ITEM
));
4260 ZeroMemory(&item
,sizeof(LVITEMA
));
4263 item
.mask
= LVIF_PARAM
| LVIF_STATE
;
4264 ListView_GetItemA(hwnd
,&item
);
4265 lvItemRef
.iImage
= item
.iImage
;
4266 lvItemRef
.state
= item
.state
;
4267 lvItemRef
.lParam
= item
.lParam
;
4268 lpItem
= &lvItemRef
;
4271 /* get information needed for drawing the item */
4272 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
4273 lvItem
.mask
= LVIF_TEXT
;
4274 lvItem
.iItem
= nItem
;
4275 lvItem
.iSubItem
= 0;
4276 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4277 lvItem
.pszText
= szDispText
;
4278 ListView_GetItemA(hwnd
, &lvItem
);
4280 dispInfo
.hdr
.hwndFrom
= hwnd
;
4281 dispInfo
.hdr
.idFrom
= nCtrlId
;
4282 dispInfo
.hdr
.code
= LVN_BEGINLABELEDITA
;
4283 dispInfo
.item
.mask
= 0;
4284 dispInfo
.item
.iItem
= nItem
;
4285 dispInfo
.item
.state
= lpItem
->state
;
4286 dispInfo
.item
.stateMask
= 0;
4287 dispInfo
.item
.pszText
= lvItem
.pszText
;
4288 dispInfo
.item
.cchTextMax
= strlen(lvItem
.pszText
);
4289 dispInfo
.item
.iImage
= lpItem
->iImage
;
4290 dispInfo
.item
.lParam
= lpItem
->lParam
;
4292 if (ListView_LVNotify(GetParent(hwnd
), nCtrlId
, &dispInfo
))
4295 rect
.left
= LVIR_LABEL
;
4296 if (!LISTVIEW_GetItemRect(hwnd
, nItem
, &rect
))
4299 if (!(hedit
= CreateEditLabel(szDispText
, WS_VISIBLE
,
4300 rect
.left
-2, rect
.top
-1, 0,
4301 rect
.bottom
- rect
.top
+2,
4302 hwnd
, hinst
, LISTVIEW_EndEditLabel
, nItem
)))
4305 infoPtr
->hwndEdit
= hedit
;
4307 SendMessageA(hedit
, EM_SETSEL
, 0, -1);
4315 * Ensures the specified item is visible, scrolling into view if necessary.
4318 * [I] HWND : window handle
4319 * [I] INT : item index
4320 * [I] BOOL : partially or entirely visible
4326 static BOOL
LISTVIEW_EnsureVisible(HWND hwnd
, INT nItem
, BOOL bPartial
)
4328 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4329 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
4330 INT nScrollPosHeight
= 0;
4331 INT nScrollPosWidth
= 0;
4332 SCROLLINFO scrollInfo
;
4334 BOOL bRedraw
= FALSE
;
4336 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
4337 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
4338 scrollInfo
.fMask
= SIF_POS
;
4340 /* ALWAYS bPartial == FALSE, FOR NOW! */
4342 rcItem
.left
= LVIR_BOUNDS
;
4343 if (LISTVIEW_GetItemRect(hwnd
, nItem
, &rcItem
) != FALSE
)
4345 if (rcItem
.left
< infoPtr
->rcList
.left
)
4347 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
4351 if (uView
== LVS_LIST
)
4353 nScrollPosWidth
= infoPtr
->nItemWidth
;
4354 rcItem
.left
+= infoPtr
->rcList
.left
;
4356 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4358 nScrollPosWidth
= LISTVIEW_SCROLL_DIV_SIZE
;
4359 rcItem
.left
+= infoPtr
->rcList
.left
;
4362 /* When in LVS_REPORT view, the scroll position should
4364 if (nScrollPosWidth
!= 0)
4366 if (rcItem
.left
% nScrollPosWidth
== 0)
4368 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
;
4372 scrollInfo
.nPos
+= rcItem
.left
/ nScrollPosWidth
- 1;
4375 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
4379 else if (rcItem
.right
> infoPtr
->rcList
.right
)
4381 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
4385 if (uView
== LVS_LIST
)
4387 rcItem
.right
-= infoPtr
->rcList
.right
;
4388 nScrollPosWidth
= infoPtr
->nItemWidth
;
4390 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
4392 rcItem
.right
-= infoPtr
->rcList
.right
;
4393 nScrollPosWidth
= LISTVIEW_SCROLL_DIV_SIZE
;
4396 /* When in LVS_REPORT view, the scroll position should
4398 if (nScrollPosWidth
!= 0)
4400 if (rcItem
.right
% nScrollPosWidth
== 0)
4402 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
;
4406 scrollInfo
.nPos
+= rcItem
.right
/ nScrollPosWidth
+ 1;
4409 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
4414 if (rcItem
.top
< infoPtr
->rcList
.top
)
4418 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
4420 if (uView
== LVS_REPORT
)
4422 rcItem
.top
-= infoPtr
->rcList
.top
;
4423 nScrollPosHeight
= infoPtr
->nItemHeight
;
4425 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4427 nScrollPosHeight
= LISTVIEW_SCROLL_DIV_SIZE
;
4428 rcItem
.top
+= infoPtr
->rcList
.top
;
4431 if (rcItem
.top
% nScrollPosHeight
== 0)
4433 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
;
4437 scrollInfo
.nPos
+= rcItem
.top
/ nScrollPosHeight
- 1;
4440 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
4443 else if (rcItem
.bottom
> infoPtr
->rcList
.bottom
)
4447 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
4449 if (uView
== LVS_REPORT
)
4451 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
4452 nScrollPosHeight
= infoPtr
->nItemHeight
;
4454 else if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
4456 nScrollPosHeight
= LISTVIEW_SCROLL_DIV_SIZE
;
4457 rcItem
.bottom
-= infoPtr
->rcList
.bottom
;
4460 if (rcItem
.bottom
% nScrollPosHeight
== 0)
4462 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
;
4466 scrollInfo
.nPos
+= rcItem
.bottom
/ nScrollPosHeight
+ 1;
4469 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
4475 InvalidateRect(hwnd
,NULL
,TRUE
);
4481 * Retrieves the nearest item, given a position and a direction.
4484 * [I] HWND : window handle
4485 * [I] POINT : start position
4486 * [I] UINT : direction
4489 * Item index if successdful, -1 otherwise.
4491 static INT
LISTVIEW_GetNearestItem(HWND hwnd
, POINT pt
, UINT vkDirection
)
4493 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4494 LVHITTESTINFO lvHitTestInfo
;
4498 if (LISTVIEW_GetViewRect(hwnd
, &rcView
) != FALSE
)
4500 ZeroMemory(&lvHitTestInfo
, sizeof(LVHITTESTINFO
));
4501 LISTVIEW_GetOrigin(hwnd
, &lvHitTestInfo
.pt
);
4502 lvHitTestInfo
.pt
.x
+= pt
.x
;
4503 lvHitTestInfo
.pt
.y
+= pt
.y
;
4507 if (vkDirection
== VK_DOWN
)
4509 lvHitTestInfo
.pt
.y
+= infoPtr
->nItemHeight
;
4511 else if (vkDirection
== VK_UP
)
4513 lvHitTestInfo
.pt
.y
-= infoPtr
->nItemHeight
;
4515 else if (vkDirection
== VK_LEFT
)
4517 lvHitTestInfo
.pt
.x
-= infoPtr
->nItemWidth
;
4519 else if (vkDirection
== VK_RIGHT
)
4521 lvHitTestInfo
.pt
.x
+= infoPtr
->nItemWidth
;
4524 if (PtInRect(&rcView
, lvHitTestInfo
.pt
) == FALSE
)
4530 nItem
= LISTVIEW_HitTestItem(hwnd
, &lvHitTestInfo
, TRUE
);
4534 while (nItem
== -1);
4542 * Searches for an item with specific characteristics.
4545 * [I] HWND : window handle
4546 * [I] INT : base item index
4547 * [I] LPLVFINDINFO : item information to look for
4550 * SUCCESS : index of item
4553 static LRESULT
LISTVIEW_FindItem(HWND hwnd
, INT nStart
,
4554 LPLVFINDINFO lpFindInfo
)
4556 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4558 CHAR szDispText
[DISP_TEXT_SIZE
];
4562 INT nLast
= GETITEMCOUNT(infoPtr
);
4564 if ((nItem
>= -1) && (lpFindInfo
!= NULL
))
4566 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
4568 if (lpFindInfo
->flags
& LVFI_PARAM
)
4570 lvItem
.mask
|= LVIF_PARAM
;
4573 if (lpFindInfo
->flags
& LVFI_STRING
)
4575 lvItem
.mask
|= LVIF_TEXT
;
4576 lvItem
.pszText
= szDispText
;
4577 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4580 if (lpFindInfo
->flags
& LVFI_PARTIAL
)
4582 lvItem
.mask
|= LVIF_TEXT
;
4583 lvItem
.pszText
= szDispText
;
4584 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
4587 if (lpFindInfo
->flags
& LVFI_WRAP
)
4592 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
4594 ptItem
.x
= lpFindInfo
->pt
.x
;
4595 ptItem
.y
= lpFindInfo
->pt
.y
;
4600 while (nItem
< nLast
)
4602 if (lpFindInfo
->flags
& LVFI_NEARESTXY
)
4604 nItem
= LISTVIEW_GetNearestItem(hwnd
, ptItem
,
4605 lpFindInfo
->vkDirection
);
4608 /* get position of the new item index */
4609 if (ListView_GetItemPosition(hwnd
, nItem
, &ptItem
) == FALSE
)
4620 lvItem
.iItem
= nItem
;
4621 lvItem
.iSubItem
= 0;
4622 if (LISTVIEW_GetItemA(hwnd
, &lvItem
, TRUE
) != FALSE
)
4624 if (lvItem
.mask
& LVIF_TEXT
)
4626 if (lpFindInfo
->flags
& LVFI_PARTIAL
)
4628 if (strstr(lvItem
.pszText
, lpFindInfo
->psz
) == NULL
)
4633 if (strcmp(lvItem
.pszText
, lpFindInfo
->psz
) != 0)
4638 if (lvItem
.mask
& LVIF_PARAM
)
4640 if (lpFindInfo
->lParam
!= lvItem
.lParam
)
4666 * Retrieves the background color of the listview control.
4669 * [I] HWND : window handle
4672 * COLORREF associated with the background.
4674 static LRESULT
LISTVIEW_GetBkColor(HWND hwnd
)
4676 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4678 return infoPtr
->clrBk
;
4683 * Retrieves the background image of the listview control.
4686 * [I] HWND : window handle
4687 * [O] LPLVMKBIMAGE : background image attributes
4693 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
4695 /* FIXME (listview, "empty stub!\n"); */
4701 * Retrieves the callback mask.
4704 * [I] HWND : window handle
4709 static UINT
LISTVIEW_GetCallbackMask(HWND hwnd
)
4711 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4713 return infoPtr
->uCallbackMask
;
4718 * Retrieves column attributes.
4721 * [I] HWND : window handle
4722 * [I] INT : column index
4723 * [IO] LPLVCOLUMNA : column information
4729 static LRESULT
LISTVIEW_GetColumnA(HWND hwnd
, INT nItem
, LPLVCOLUMNA lpColumn
)
4731 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4733 BOOL bResult
= FALSE
;
4735 if (lpColumn
!= NULL
)
4737 /* initialize memory */
4738 ZeroMemory(&hdi
, sizeof(HDITEMA
));
4740 if (lpColumn
->mask
& LVCF_FMT
)
4742 hdi
.mask
|= HDI_FORMAT
;
4745 if (lpColumn
->mask
& LVCF_WIDTH
)
4747 hdi
.mask
|= HDI_WIDTH
;
4750 if (lpColumn
->mask
& LVCF_TEXT
)
4752 hdi
.mask
|= HDI_TEXT
;
4753 hdi
.cchTextMax
= lpColumn
->cchTextMax
;
4754 hdi
.pszText
= lpColumn
->pszText
;
4757 if (lpColumn
->mask
& LVCF_IMAGE
)
4759 hdi
.mask
|= HDI_IMAGE
;
4762 if (lpColumn
->mask
& LVCF_ORDER
)
4764 hdi
.mask
|= HDI_ORDER
;
4767 bResult
= Header_GetItemA(infoPtr
->hwndHeader
, nItem
, &hdi
);
4768 if (bResult
!= FALSE
)
4770 if (lpColumn
->mask
& LVCF_FMT
)
4774 if (hdi
.fmt
& HDF_LEFT
)
4776 lpColumn
->fmt
|= LVCFMT_LEFT
;
4778 else if (hdi
.fmt
& HDF_RIGHT
)
4780 lpColumn
->fmt
|= LVCFMT_RIGHT
;
4782 else if (hdi
.fmt
& HDF_CENTER
)
4784 lpColumn
->fmt
|= LVCFMT_CENTER
;
4787 if (hdi
.fmt
& HDF_IMAGE
)
4789 lpColumn
->fmt
|= LVCFMT_COL_HAS_IMAGES
;
4792 if (hdi
.fmt
& HDF_BITMAP_ON_RIGHT
)
4794 lpColumn
->fmt
|= LVCFMT_BITMAP_ON_RIGHT
;
4798 if (lpColumn
->mask
& LVCF_WIDTH
)
4800 lpColumn
->cx
= hdi
.cxy
;
4803 if (lpColumn
->mask
& LVCF_IMAGE
)
4805 lpColumn
->iImage
= hdi
.iImage
;
4808 if (lpColumn
->mask
& LVCF_ORDER
)
4810 lpColumn
->iOrder
= hdi
.iOrder
;
4818 /* LISTVIEW_GetColumnW */
4821 static LRESULT
LISTVIEW_GetColumnOrderArray(HWND hwnd
, INT iCount
, LPINT lpiArray
)
4823 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
4830 for (i
= 0; i
< iCount
; i
++)
4838 * Retrieves the column width.
4841 * [I] HWND : window handle
4842 * [I] int : column index
4845 * SUCCESS : column width
4848 static LRESULT
LISTVIEW_GetColumnWidth(HWND hwnd
, INT nColumn
)
4850 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4851 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
4852 INT nColumnWidth
= 0;
4855 if (uView
== LVS_LIST
)
4857 nColumnWidth
= infoPtr
->nItemWidth
;
4859 else if (uView
== LVS_REPORT
)
4861 /* get column width from header */
4862 ZeroMemory(&hdi
, sizeof(HDITEMA
));
4863 hdi
.mask
= HDI_WIDTH
;
4864 if (Header_GetItemA(infoPtr
->hwndHeader
, nColumn
, &hdi
) != FALSE
)
4866 nColumnWidth
= hdi
.cxy
;
4870 return nColumnWidth
;
4875 * In list or report display mode, retrieves the number of items that can fit
4876 * vertically in the visible area. In icon or small icon display mode,
4877 * retrieves the total number of visible items.
4880 * [I] HWND : window handle
4883 * Number of fully visible items.
4885 static LRESULT
LISTVIEW_GetCountPerPage(HWND hwnd
)
4887 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4888 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
4891 if (uView
== LVS_LIST
)
4893 if (infoPtr
->rcList
.right
> infoPtr
->nItemWidth
)
4895 nItemCount
= LISTVIEW_GetCountPerRow(hwnd
) *
4896 LISTVIEW_GetCountPerColumn(hwnd
);
4899 else if (uView
== LVS_REPORT
)
4901 nItemCount
= LISTVIEW_GetCountPerColumn(hwnd
);
4905 nItemCount
= GETITEMCOUNT(infoPtr
);
4911 /* LISTVIEW_GetEditControl */
4915 * Retrieves the extended listview style.
4918 * [I] HWND : window handle
4921 * SUCCESS : previous style
4924 static LRESULT
LISTVIEW_GetExtendedListViewStyle(HWND hwnd
)
4926 LISTVIEW_INFO
*infoPtr
;
4928 /* make sure we can get the listview info */
4929 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
4932 return (infoPtr
->dwExStyle
);
4937 * Retrieves the handle to the header control.
4940 * [I] HWND : window handle
4945 static LRESULT
LISTVIEW_GetHeader(HWND hwnd
)
4947 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4949 return infoPtr
->hwndHeader
;
4952 /* LISTVIEW_GetHotCursor */
4956 * Returns the time that the mouse cursor must hover over an item
4957 * before it is selected.
4960 * [I] HWND : window handle
4963 * Returns the previously set hover time or (DWORD)-1 to indicate that the
4964 * hover time is set to the default hover time.
4966 static LRESULT
LISTVIEW_GetHoverTime(HWND hwnd
)
4968 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4970 return infoPtr
->dwHoverTime
;
4975 * Retrieves an image list handle.
4978 * [I] HWND : window handle
4979 * [I] INT : image list identifier
4982 * SUCCESS : image list handle
4985 static LRESULT
LISTVIEW_GetImageList(HWND hwnd
, INT nImageList
)
4987 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
4988 HIMAGELIST himl
= NULL
;
4993 himl
= infoPtr
->himlNormal
;
4996 himl
= infoPtr
->himlSmall
;
4999 himl
= infoPtr
->himlState
;
5003 return (LRESULT
)himl
;
5006 /* LISTVIEW_GetISearchString */
5010 * Retrieves item attributes.
5013 * [I] HWND : window handle
5014 * [IO] LPLVITEMA : item info
5015 * [I] internal : if true then we will use tricks that avoid copies
5016 * but are not compatible with the regular interface
5022 static LRESULT
LISTVIEW_GetItemA(HWND hwnd
, LPLVITEMA lpLVItem
, BOOL internal
)
5024 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5025 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
5026 NMLVDISPINFOA dispInfo
;
5027 LISTVIEW_SUBITEM
*lpSubItem
;
5028 LISTVIEW_ITEM
*lpItem
;
5032 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
5033 /* In the following:
5034 * lpLVItem describes the information requested by the user
5035 * lpItem/lpSubItem is what we have
5036 * dispInfo is a structure we use to request the missing
5037 * information from the application
5040 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd
, lpLVItem
);
5042 if ((lpLVItem
== NULL
) ||
5043 (lpLVItem
->iItem
< 0) ||
5044 (lpLVItem
->iItem
>= GETITEMCOUNT(infoPtr
))
5048 if (lStyle
& LVS_OWNERDATA
)
5050 if (lpLVItem
->mask
& ~LVIF_STATE
)
5052 dispInfo
.hdr
.hwndFrom
= hwnd
;
5053 dispInfo
.hdr
.idFrom
= lCtrlId
;
5054 dispInfo
.hdr
.code
= LVN_GETDISPINFOA
;
5055 memcpy(&dispInfo
.item
,lpLVItem
,sizeof(LVITEMA
));
5057 ListView_Notify(GetParent(hwnd
), lCtrlId
, &dispInfo
);
5058 memcpy(lpLVItem
,&dispInfo
.item
,sizeof(LVITEMA
));
5061 if ((lpLVItem
->mask
& LVIF_STATE
)&&(lpLVItem
->iSubItem
== 0))
5063 lpLVItem
->state
= 0;
5064 if (infoPtr
->nFocusedItem
== lpLVItem
->iItem
)
5065 lpLVItem
->state
|= LVIS_FOCUSED
;
5066 if (LISTVIEW_IsSelected(hwnd
,lpLVItem
->iItem
))
5067 lpLVItem
->state
|= LVIS_SELECTED
;
5074 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
);
5075 if (hdpaSubItems
== NULL
)
5078 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
5082 ZeroMemory(&dispInfo
, sizeof(NMLVDISPINFOA
));
5083 if (lpLVItem
->iSubItem
== 0)
5085 piImage
=&lpItem
->iImage
;
5086 ppszText
=&lpItem
->pszText
;
5087 if ((infoPtr
->uCallbackMask
!= 0) && (lpLVItem
->mask
& LVIF_STATE
))
5089 dispInfo
.item
.mask
|= LVIF_STATE
;
5090 dispInfo
.item
.stateMask
= infoPtr
->uCallbackMask
;
5095 lpSubItem
= LISTVIEW_GetSubItemPtr(hdpaSubItems
, lpLVItem
->iSubItem
);
5096 if (lpSubItem
!= NULL
)
5098 piImage
=&lpSubItem
->iImage
;
5099 ppszText
=&lpSubItem
->pszText
;
5108 if ((lpLVItem
->mask
& LVIF_IMAGE
) &&
5109 ((piImage
==NULL
) || (*piImage
== I_IMAGECALLBACK
)))
5111 dispInfo
.item
.mask
|= LVIF_IMAGE
;
5114 if ((lpLVItem
->mask
& LVIF_TEXT
) &&
5115 ((ppszText
==NULL
) || (*ppszText
== LPSTR_TEXTCALLBACKA
)))
5117 dispInfo
.item
.mask
|= LVIF_TEXT
;
5118 dispInfo
.item
.pszText
= lpLVItem
->pszText
;
5119 dispInfo
.item
.cchTextMax
= lpLVItem
->cchTextMax
;
5122 if (dispInfo
.item
.mask
!= 0)
5124 /* We don't have all the requested info, query the application */
5125 dispInfo
.hdr
.hwndFrom
= hwnd
;
5126 dispInfo
.hdr
.idFrom
= lCtrlId
;
5127 dispInfo
.hdr
.code
= LVN_GETDISPINFOA
;
5128 dispInfo
.item
.iItem
= lpLVItem
->iItem
;
5129 dispInfo
.item
.iSubItem
= lpLVItem
->iSubItem
;
5130 dispInfo
.item
.lParam
= lpItem
->lParam
;
5131 ListView_Notify(GetParent(hwnd
), lCtrlId
, &dispInfo
);
5134 if (dispInfo
.item
.mask
& LVIF_IMAGE
)
5136 lpLVItem
->iImage
= dispInfo
.item
.iImage
;
5138 else if (lpLVItem
->mask
& LVIF_IMAGE
)
5140 lpLVItem
->iImage
= *piImage
;
5143 if (dispInfo
.item
.mask
& LVIF_PARAM
)
5145 lpLVItem
->lParam
= dispInfo
.item
.lParam
;
5147 else if (lpLVItem
->mask
& LVIF_PARAM
)
5149 lpLVItem
->lParam
= lpItem
->lParam
;
5152 if (dispInfo
.item
.mask
& LVIF_TEXT
)
5154 if ((dispInfo
.item
.mask
& LVIF_DI_SETITEM
) && (ppszText
!= NULL
))
5156 Str_SetPtrA(ppszText
, dispInfo
.item
.pszText
);
5158 /* If lpLVItem->pszText==dispInfo.item.pszText a copy is unnecessary, but */
5159 /* some apps give a new pointer in ListView_Notify so we can't be sure. */
5160 if (lpLVItem
->pszText
!=dispInfo
.item
.pszText
) {
5161 lstrcpynA(lpLVItem
->pszText
, dispInfo
.item
.pszText
, lpLVItem
->cchTextMax
);
5164 else if (lpLVItem
->mask
& LVIF_TEXT
)
5168 lpLVItem
->pszText
=*ppszText
;
5170 lstrcpynA(lpLVItem
->pszText
, *ppszText
, lpLVItem
->cchTextMax
);
5174 if (lpLVItem
->iSubItem
== 0)
5176 if (dispInfo
.item
.mask
& LVIF_STATE
)
5178 lpLVItem
->state
= lpItem
->state
;
5179 lpLVItem
->state
&= ~dispInfo
.item
.stateMask
;
5180 lpLVItem
->state
|= (dispInfo
.item
.state
& dispInfo
.item
.stateMask
);
5182 lpLVItem
->state
&= ~LVIS_SELECTED
;
5183 if ((dispInfo
.item
.stateMask
& LVIS_SELECTED
) &&
5184 (LISTVIEW_IsSelected(hwnd
,dispInfo
.item
.iItem
)))
5185 lpLVItem
->state
|= LVIS_SELECTED
;
5187 else if (lpLVItem
->mask
& LVIF_STATE
)
5189 lpLVItem
->state
= lpItem
->state
& lpLVItem
->stateMask
;
5191 lpLVItem
->state
&= ~LVIS_SELECTED
;
5192 if ((lpLVItem
->stateMask
& LVIS_SELECTED
) &&
5193 (LISTVIEW_IsSelected(hwnd
,lpLVItem
->iItem
)))
5194 lpLVItem
->state
|= LVIS_SELECTED
;
5197 if (lpLVItem
->mask
& LVIF_PARAM
)
5199 lpLVItem
->lParam
= lpItem
->lParam
;
5202 if (lpLVItem
->mask
& LVIF_INDENT
)
5204 lpLVItem
->iIndent
= lpItem
->iIndent
;
5211 /* LISTVIEW_GetItemW */
5212 /* LISTVIEW_GetHotCursor */
5216 * Retrieves the index of the hot item.
5219 * [I] HWND : window handle
5222 * SUCCESS : hot item index
5223 * FAILURE : -1 (no hot item)
5225 static LRESULT
LISTVIEW_GetHotItem(HWND hwnd
)
5227 LISTVIEW_INFO
*infoPtr
;
5229 /* make sure we can get the listview info */
5230 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
5233 return (infoPtr
->nHotItem
);
5236 /* LISTVIEW_GetHoverTime */
5240 * Retrieves the number of items in the listview control.
5243 * [I] HWND : window handle
5248 static LRESULT
LISTVIEW_GetItemCount(HWND hwnd
)
5250 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5252 return GETITEMCOUNT(infoPtr
);
5257 * Retrieves the position (upper-left) of the listview control item.
5260 * [I] HWND : window handle
5261 * [I] INT : item index
5262 * [O] LPPOINT : coordinate information
5268 static BOOL
LISTVIEW_GetItemPosition(HWND hwnd
, INT nItem
,
5269 LPPOINT lpptPosition
)
5271 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5272 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5273 BOOL bResult
= FALSE
;
5275 LISTVIEW_ITEM
*lpItem
;
5276 INT nCountPerColumn
;
5279 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd
, nItem
,
5282 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) &&
5283 (lpptPosition
!= NULL
))
5285 if (uView
== LVS_LIST
)
5288 nItem
= nItem
- ListView_GetTopIndex(hwnd
);
5289 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
5292 nRow
= nItem
% nCountPerColumn
;
5295 lpptPosition
->x
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
5296 lpptPosition
->y
= 0;
5300 lpptPosition
->x
= (nItem
/ nCountPerColumn
-1) * infoPtr
->nItemWidth
;
5301 lpptPosition
->y
= (nRow
+ nCountPerColumn
) * infoPtr
->nItemHeight
;
5306 lpptPosition
->x
= nItem
/ nCountPerColumn
* infoPtr
->nItemWidth
;
5307 lpptPosition
->y
= nItem
% nCountPerColumn
* infoPtr
->nItemHeight
;
5310 else if (uView
== LVS_REPORT
)
5312 SCROLLINFO scrollInfo
;
5314 lpptPosition
->x
= REPORT_MARGINX
;
5315 lpptPosition
->y
= ((nItem
- ListView_GetTopIndex(hwnd
)) *
5316 infoPtr
->nItemHeight
) + infoPtr
->rcList
.top
;
5318 /* Adjust position by scrollbar offset */
5319 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
5320 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
5321 scrollInfo
.fMask
= SIF_POS
;
5322 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
5323 lpptPosition
->x
-= scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
5327 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
5328 if (hdpaSubItems
!= NULL
)
5330 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
5334 lpptPosition
->x
= lpItem
->ptPosition
.x
;
5335 lpptPosition
->y
= lpItem
->ptPosition
.y
;
5345 * Retrieves the bounding rectangle for a listview control item.
5348 * [I] HWND : window handle
5349 * [I] INT : item index
5350 * [IO] LPRECT : bounding rectangle coordinates
5351 * lprc->left specifies the portion of the item for which the bounding
5352 * rectangle will be retrieved.
5354 * LVIR_BOUNDS Returns the bounding rectangle of the entire item,
5355 * including the icon and label.
5356 * LVIR_ICON Returns the bounding rectangle of the icon or small icon.
5357 * LVIR_LABEL Returns the bounding rectangle of the item text.
5358 * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL
5359 * rectangles, but excludes columns in report view.
5365 static LRESULT
LISTVIEW_GetItemRect(HWND hwnd
, INT nItem
, LPRECT lprc
)
5367 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5368 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5369 BOOL bResult
= FALSE
;
5380 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd
, nItem
, lprc
);
5382 if (uView
& LVS_REPORT
)
5384 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
5385 lvItem
.mask
= LVIF_INDENT
;
5386 lvItem
.iItem
= nItem
;
5387 lvItem
.iSubItem
= 0;
5388 LISTVIEW_GetItemA(hwnd
, &lvItem
, TRUE
);
5391 if (lvItem
.iIndent
>0 && infoPtr
->iconSize
.cx
> 0)
5393 nIndent
= infoPtr
->iconSize
.cx
* lvItem
.iIndent
;
5401 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)) && (lprc
!= NULL
))
5403 if (ListView_GetItemPosition(hwnd
, nItem
, &ptItem
) != FALSE
)
5408 if (uView
== LVS_ICON
)
5410 if (infoPtr
->himlNormal
!= NULL
)
5412 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5415 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5416 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5417 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5418 lprc
->bottom
= (lprc
->top
+ infoPtr
->iconSize
.cy
+
5419 ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
);
5423 else if (uView
== LVS_SMALLICON
)
5425 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5428 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5429 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5430 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5432 if (infoPtr
->himlState
!= NULL
)
5433 lprc
->left
+= infoPtr
->iconSize
.cx
;
5435 if (infoPtr
->himlSmall
!= NULL
)
5436 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5438 lprc
->right
= lprc
->left
;
5444 lprc
->left
= ptItem
.x
;
5445 if (uView
& LVS_REPORT
)
5446 lprc
->left
+= nIndent
;
5447 lprc
->top
= ptItem
.y
;
5448 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5450 if (infoPtr
->himlState
!= NULL
)
5452 lprc
->left
+= infoPtr
->iconSize
.cx
;
5455 if (infoPtr
->himlSmall
!= NULL
)
5457 lprc
->right
= lprc
->left
+ infoPtr
->iconSize
.cx
;
5461 lprc
->right
= lprc
->left
;
5467 if (uView
== LVS_ICON
)
5469 if (infoPtr
->himlNormal
!= NULL
)
5471 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5474 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5475 lprc
->top
= (ptItem
.y
+ ptOrigin
.y
+ infoPtr
->iconSize
.cy
+
5476 ICON_BOTTOM_PADDING
+ ICON_TOP_PADDING
);
5477 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5478 if (infoPtr
->iconSpacing
.cx
- nLabelWidth
> 1)
5480 lprc
->left
+= (infoPtr
->iconSpacing
.cx
- nLabelWidth
) / 2;
5481 lprc
->right
= lprc
->left
+ nLabelWidth
;
5486 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
- 1;
5490 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
5491 GetTextMetricsA(hdc
, &tm
);
5492 lprc
->bottom
= lprc
->top
+ tm
.tmHeight
+ HEIGHT_PADDING
;
5493 SelectObject(hdc
, hOldFont
);
5494 ReleaseDC(hwnd
, hdc
);
5498 else if (uView
== LVS_SMALLICON
)
5500 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5503 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5504 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5505 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5507 if (infoPtr
->himlState
!= NULL
)
5509 lprc
->left
+= infoPtr
->iconSize
.cx
;
5512 if (infoPtr
->himlSmall
!= NULL
)
5514 lprc
->left
+= infoPtr
->iconSize
.cx
;
5517 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5518 nLabelWidth
+= TRAILING_PADDING
;
5519 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5521 lprc
->right
= lprc
->left
+ nLabelWidth
;
5525 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5532 if (uView
& LVS_REPORT
)
5533 nLeftPos
= lprc
->left
= ptItem
.x
+ nIndent
;
5535 nLeftPos
= lprc
->left
= ptItem
.x
;
5536 lprc
->top
= ptItem
.y
;
5537 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5539 if (infoPtr
->himlState
!= NULL
)
5541 lprc
->left
+= infoPtr
->iconSize
.cx
;
5544 if (infoPtr
->himlSmall
!= NULL
)
5546 lprc
->left
+= infoPtr
->iconSize
.cx
;
5549 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5550 nLabelWidth
+= TRAILING_PADDING
;
5551 if (infoPtr
->himlSmall
)
5552 nLabelWidth
+= IMAGE_PADDING
;
5553 if (lprc
->left
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5555 lprc
->right
= lprc
->left
+ nLabelWidth
;
5559 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5565 if (uView
== LVS_ICON
)
5567 if (infoPtr
->himlNormal
!= NULL
)
5569 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5572 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5573 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5574 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
;
5575 lprc
->bottom
= lprc
->top
+ infoPtr
->iconSpacing
.cy
;
5579 else if (uView
== LVS_SMALLICON
)
5581 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5584 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5585 lprc
->right
= lprc
->left
;
5586 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5587 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5588 if (infoPtr
->himlState
!= NULL
)
5589 lprc
->right
+= infoPtr
->iconSize
.cx
;
5590 if (infoPtr
->himlSmall
!= NULL
)
5591 lprc
->right
+= infoPtr
->iconSize
.cx
;
5593 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5594 nLabelWidth
+= TRAILING_PADDING
;
5595 if (infoPtr
->himlSmall
)
5596 nLabelWidth
+= IMAGE_PADDING
;
5597 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
5599 lprc
->right
+= nLabelWidth
;
5603 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
5610 lprc
->left
= ptItem
.x
;
5611 if (!(infoPtr
->dwExStyle
&LVS_EX_FULLROWSELECT
) && uView
&LVS_REPORT
)
5612 lprc
->left
+= nIndent
;
5613 lprc
->right
= lprc
->left
;
5614 lprc
->top
= ptItem
.y
;
5615 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5617 if (infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
)
5620 int nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
5621 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
5623 lprc
->right
= max(lprc
->left
, br
.right
- REPORT_MARGINX
);
5627 if (infoPtr
->himlState
!= NULL
)
5629 lprc
->right
+= infoPtr
->iconSize
.cx
;
5632 if (infoPtr
->himlSmall
!= NULL
)
5634 lprc
->right
+= infoPtr
->iconSize
.cx
;
5637 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5638 nLabelWidth
+= TRAILING_PADDING
;
5639 if (lprc
->right
+ nLabelWidth
< lprc
->left
+ infoPtr
->nItemWidth
)
5641 lprc
->right
+= nLabelWidth
;
5645 lprc
->right
= lprc
->left
+ infoPtr
->nItemWidth
;
5651 case LVIR_SELECTBOUNDS
:
5652 if (uView
== LVS_ICON
)
5654 if (infoPtr
->himlNormal
!= NULL
)
5656 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5659 lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5660 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5661 lprc
->right
= lprc
->left
+ infoPtr
->iconSpacing
.cx
;
5662 lprc
->bottom
= lprc
->top
+ infoPtr
->iconSpacing
.cy
;
5666 else if (uView
== LVS_SMALLICON
)
5668 if (LISTVIEW_GetOrigin(hwnd
, &ptOrigin
) != FALSE
)
5671 nLeftPos
= lprc
->left
= ptItem
.x
+ ptOrigin
.x
;
5672 lprc
->top
= ptItem
.y
+ ptOrigin
.y
;
5673 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5675 if (infoPtr
->himlState
!= NULL
)
5677 lprc
->left
+= infoPtr
->iconSize
.cx
;
5680 lprc
->right
= lprc
->left
;
5682 if (infoPtr
->himlSmall
!= NULL
)
5684 lprc
->right
+= infoPtr
->iconSize
.cx
;
5687 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5688 nLabelWidth
+= TRAILING_PADDING
;
5689 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5691 lprc
->right
+= nLabelWidth
;
5695 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5702 if (!(infoPtr
->dwExStyle
&LVS_EX_FULLROWSELECT
) && (uView
&LVS_REPORT
))
5703 nLeftPos
= lprc
->left
= ptItem
.x
+ nIndent
;
5705 nLeftPos
= lprc
->left
= ptItem
.x
;
5706 lprc
->top
= ptItem
.y
;
5707 lprc
->bottom
= lprc
->top
+ infoPtr
->nItemHeight
;
5709 if (infoPtr
->himlState
!= NULL
)
5711 lprc
->left
+= infoPtr
->iconSize
.cx
;
5714 lprc
->right
= lprc
->left
;
5716 if (infoPtr
->dwExStyle
& LVS_EX_FULLROWSELECT
)
5719 int nColumnCount
= Header_GetItemCount(infoPtr
->hwndHeader
);
5720 Header_GetItemRect(infoPtr
->hwndHeader
, nColumnCount
-1, &br
);
5722 lprc
->right
= max(lprc
->left
, br
.right
- REPORT_MARGINX
);
5726 if (infoPtr
->himlSmall
!= NULL
)
5728 lprc
->right
+= infoPtr
->iconSize
.cx
;
5731 nLabelWidth
= LISTVIEW_GetLabelWidth(hwnd
, nItem
);
5732 nLabelWidth
+= TRAILING_PADDING
;
5733 if (infoPtr
->himlSmall
)
5734 nLabelWidth
+= IMAGE_PADDING
;
5735 if (lprc
->right
+ nLabelWidth
< nLeftPos
+ infoPtr
->nItemWidth
)
5737 lprc
->right
+= nLabelWidth
;
5741 lprc
->right
= nLeftPos
+ infoPtr
->nItemWidth
;
5754 * Retrieves the width of a label.
5757 * [I] HWND : window handle
5760 * SUCCESS : string width (in pixels)
5763 static INT
LISTVIEW_GetLabelWidth(HWND hwnd
, INT nItem
)
5765 CHAR szDispText
[DISP_TEXT_SIZE
];
5766 INT nLabelWidth
= 0;
5769 TRACE("(hwnd=%x, nItem=%d)\n", hwnd
, nItem
);
5771 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
5772 lvItem
.mask
= LVIF_TEXT
;
5773 lvItem
.iItem
= nItem
;
5774 lvItem
.cchTextMax
= DISP_TEXT_SIZE
;
5775 lvItem
.pszText
= szDispText
;
5776 if (LISTVIEW_GetItemA(hwnd
, &lvItem
, TRUE
) != FALSE
)
5778 nLabelWidth
= ListView_GetStringWidthA(hwnd
, lvItem
.pszText
);
5786 * Retrieves the spacing between listview control items.
5789 * [I] HWND : window handle
5790 * [I] BOOL : flag for small or large icon
5793 * Horizontal + vertical spacing
5795 static LRESULT
LISTVIEW_GetItemSpacing(HWND hwnd
, BOOL bSmall
)
5797 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5800 if (bSmall
== FALSE
)
5802 lResult
= MAKELONG(infoPtr
->iconSpacing
.cx
, infoPtr
->iconSpacing
.cy
);
5806 /* TODO: need to store width of smallicon item */
5807 lResult
= MAKELONG(0, infoPtr
->nItemHeight
);
5815 * Retrieves the state of a listview control item.
5818 * [I] HWND : window handle
5819 * [I] INT : item index
5820 * [I] UINT : state mask
5823 * State specified by the mask.
5825 static LRESULT
LISTVIEW_GetItemState(HWND hwnd
, INT nItem
, UINT uMask
)
5827 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5831 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
5833 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
5834 lvItem
.iItem
= nItem
;
5835 lvItem
.stateMask
= uMask
;
5836 lvItem
.mask
= LVIF_STATE
;
5837 if (LISTVIEW_GetItemA(hwnd
, &lvItem
, TRUE
) != FALSE
)
5839 uState
= lvItem
.state
;
5848 * Retrieves the text of a listview control item or subitem.
5851 * [I] HWND : window handle
5852 * [I] INT : item index
5853 * [IO] LPLVITEMA : item information
5856 * SUCCESS : string length
5859 static LRESULT
LISTVIEW_GetItemTextA(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
5861 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5864 if (lpLVItem
!= NULL
)
5866 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
5868 lpLVItem
->mask
= LVIF_TEXT
;
5869 lpLVItem
->iItem
= nItem
;
5870 if (LISTVIEW_GetItemA(hwnd
, lpLVItem
, FALSE
) != FALSE
)
5872 nLength
= lstrlenA(lpLVItem
->pszText
);
5882 * Searches for an item based on properties + relationships.
5885 * [I] HWND : window handle
5886 * [I] INT : item index
5887 * [I] INT : relationship flag
5890 * SUCCESS : item index
5893 static LRESULT
LISTVIEW_GetNextItem(HWND hwnd
, INT nItem
, UINT uFlags
)
5895 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
5896 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
5898 LVFINDINFO lvFindInfo
;
5899 INT nCountPerColumn
;
5902 if ((nItem
>= -1) && (nItem
< GETITEMCOUNT(infoPtr
)))
5904 ZeroMemory(&lvFindInfo
, sizeof(LVFINDINFO
));
5906 if (uFlags
& LVNI_CUT
)
5909 if (uFlags
& LVNI_DROPHILITED
)
5910 uMask
|= LVIS_DROPHILITED
;
5912 if (uFlags
& LVNI_FOCUSED
)
5913 uMask
|= LVIS_FOCUSED
;
5915 if (uFlags
& LVNI_SELECTED
)
5916 uMask
|= LVIS_SELECTED
;
5918 if (uFlags
& LVNI_ABOVE
)
5920 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
5925 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
5931 lvFindInfo
.flags
= LVFI_NEARESTXY
;
5932 lvFindInfo
.vkDirection
= VK_UP
;
5933 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
5934 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
5936 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
5941 else if (uFlags
& LVNI_BELOW
)
5943 if ((uView
== LVS_LIST
) || (uView
== LVS_REPORT
))
5945 while (nItem
< GETITEMCOUNT(infoPtr
))
5948 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
5954 lvFindInfo
.flags
= LVFI_NEARESTXY
;
5955 lvFindInfo
.vkDirection
= VK_DOWN
;
5956 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
5957 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
5959 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
5964 else if (uFlags
& LVNI_TOLEFT
)
5966 if (uView
== LVS_LIST
)
5968 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
5969 while (nItem
- nCountPerColumn
>= 0)
5971 nItem
-= nCountPerColumn
;
5972 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
5976 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
5978 lvFindInfo
.flags
= LVFI_NEARESTXY
;
5979 lvFindInfo
.vkDirection
= VK_LEFT
;
5980 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
5981 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
5983 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
5988 else if (uFlags
& LVNI_TORIGHT
)
5990 if (uView
== LVS_LIST
)
5992 nCountPerColumn
= LISTVIEW_GetCountPerColumn(hwnd
);
5993 while (nItem
+ nCountPerColumn
< GETITEMCOUNT(infoPtr
))
5995 nItem
+= nCountPerColumn
;
5996 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6000 else if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6002 lvFindInfo
.flags
= LVFI_NEARESTXY
;
6003 lvFindInfo
.vkDirection
= VK_RIGHT
;
6004 ListView_GetItemPosition(hwnd
, nItem
, &lvFindInfo
.pt
);
6005 while ((nItem
= ListView_FindItem(hwnd
, nItem
, &lvFindInfo
)) != -1)
6007 if ((ListView_GetItemState(hwnd
, nItem
, uMask
) & uMask
) == uMask
)
6016 /* search by index */
6017 for (i
= nItem
; i
< GETITEMCOUNT(infoPtr
); i
++)
6019 if ((ListView_GetItemState(hwnd
, i
, uMask
) & uMask
) == uMask
)
6028 /* LISTVIEW_GetNumberOfWorkAreas */
6032 * Retrieves the origin coordinates when in icon or small icon display mode.
6035 * [I] HWND : window handle
6036 * [O] LPPOINT : coordinate information
6042 static LRESULT
LISTVIEW_GetOrigin(HWND hwnd
, LPPOINT lpptOrigin
)
6044 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
6045 UINT uView
= lStyle
& LVS_TYPEMASK
;
6046 BOOL bResult
= FALSE
;
6048 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd
, lpptOrigin
);
6050 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6052 SCROLLINFO scrollInfo
;
6053 ZeroMemory(lpptOrigin
, sizeof(POINT
));
6054 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
6055 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
6057 if (lStyle
& WS_HSCROLL
)
6059 scrollInfo
.fMask
= SIF_POS
;
6060 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
6062 lpptOrigin
->x
= -scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
6066 if (lStyle
& WS_VSCROLL
)
6068 scrollInfo
.fMask
= SIF_POS
;
6069 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
6071 lpptOrigin
->y
= -scrollInfo
.nPos
* LISTVIEW_SCROLL_DIV_SIZE
;
6083 * Retrieves the number of items that are marked as selected.
6086 * [I] HWND : window handle
6089 * Number of items selected.
6091 static LRESULT
LISTVIEW_GetSelectedCount(HWND hwnd
)
6094 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6095 INT nSelectedCount
= 0;
6098 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
6100 if (ListView_GetItemState(hwnd
, i
, LVIS_SELECTED
) & LVIS_SELECTED
)
6106 return nSelectedCount
;
6111 * Retrieves item index that marks the start of a multiple selection.
6114 * [I] HWND : window handle
6117 * Index number or -1 if there is no selection mark.
6119 static LRESULT
LISTVIEW_GetSelectionMark(HWND hwnd
)
6121 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6123 return infoPtr
->nSelectionMark
;
6128 * Retrieves the width of a string.
6131 * [I] HWND : window handle
6134 * SUCCESS : string width (in pixels)
6137 static LRESULT
LISTVIEW_GetStringWidthA(HWND hwnd
, LPCSTR lpszText
)
6139 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6140 HFONT hFont
, hOldFont
;
6144 ZeroMemory(&stringSize
, sizeof(SIZE
));
6145 if (lpszText
!= NULL
&& lpszText
!= LPSTR_TEXTCALLBACKA
)
6147 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: infoPtr
->hDefaultFont
;
6149 hOldFont
= SelectObject(hdc
, hFont
);
6150 GetTextExtentPointA(hdc
, lpszText
, lstrlenA(lpszText
), &stringSize
);
6151 SelectObject(hdc
, hOldFont
);
6152 ReleaseDC(hwnd
, hdc
);
6155 return stringSize
.cx
;
6160 * Retrieves the text backgound color.
6163 * [I] HWND : window handle
6166 * COLORREF associated with the the background.
6168 static LRESULT
LISTVIEW_GetTextBkColor(HWND hwnd
)
6170 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6172 return infoPtr
->clrTextBk
;
6177 * Retrieves the text color.
6180 * [I] HWND : window handle
6183 * COLORREF associated with the text.
6185 static LRESULT
LISTVIEW_GetTextColor(HWND hwnd
)
6187 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6189 return infoPtr
->clrText
;
6194 * Determines which section of the item was selected (if any).
6197 * [I] HWND : window handle
6198 * [IO] LPLVHITTESTINFO : hit test information
6199 * [I] subitem : fill out iSubItem.
6202 * SUCCESS : item index
6205 static INT
LISTVIEW_HitTestItem(
6206 HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
, BOOL subitem
6208 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6210 INT i
,topindex
,bottomindex
;
6211 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
6212 UINT uView
= lStyle
& LVS_TYPEMASK
;
6215 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd
, lpHitTestInfo
->pt
.x
,
6216 lpHitTestInfo
->pt
.y
);
6218 topindex
= ListView_GetTopIndex(hwnd
);
6219 if (uView
== LVS_REPORT
)
6221 bottomindex
= topindex
+ LISTVIEW_GetCountPerColumn(hwnd
) + 1;
6222 bottomindex
= min(bottomindex
,GETITEMCOUNT(infoPtr
));
6226 bottomindex
= GETITEMCOUNT(infoPtr
);
6229 for (i
= topindex
; i
< bottomindex
; i
++)
6231 rcItem
.left
= LVIR_BOUNDS
;
6232 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) != FALSE
)
6234 if (PtInRect(&rcItem
, lpHitTestInfo
->pt
) != FALSE
)
6236 rcItem
.left
= LVIR_ICON
;
6237 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) != FALSE
)
6239 if (PtInRect(&rcItem
, lpHitTestInfo
->pt
) != FALSE
)
6241 lpHitTestInfo
->flags
= LVHT_ONITEMICON
;
6242 lpHitTestInfo
->iItem
= i
;
6243 if (subitem
) lpHitTestInfo
->iSubItem
= 0;
6248 rcItem
.left
= LVIR_LABEL
;
6249 if (LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
) != FALSE
)
6251 if (PtInRect(&rcItem
, lpHitTestInfo
->pt
) != FALSE
)
6253 lpHitTestInfo
->flags
= LVHT_ONITEMLABEL
;
6254 lpHitTestInfo
->iItem
= i
;
6255 if (subitem
) lpHitTestInfo
->iSubItem
= 0;
6260 lpHitTestInfo
->flags
= LVHT_ONITEMSTATEICON
;
6261 lpHitTestInfo
->iItem
= i
;
6262 if (subitem
) lpHitTestInfo
->iSubItem
= 0;
6268 lpHitTestInfo
->flags
= LVHT_NOWHERE
;
6275 * Determines which listview item is located at the specified position.
6278 * [I] HWND : window handle
6279 * [IO} LPLVHITTESTINFO : hit test information
6282 * SUCCESS : item index
6285 static LRESULT
LISTVIEW_HitTest(HWND hwnd
, LPLVHITTESTINFO lpHitTestInfo
)
6287 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6290 lpHitTestInfo
->flags
= 0;
6292 if (infoPtr
->rcList
.left
> lpHitTestInfo
->pt
.x
)
6294 lpHitTestInfo
->flags
= LVHT_TOLEFT
;
6296 else if (infoPtr
->rcList
.right
< lpHitTestInfo
->pt
.x
)
6298 lpHitTestInfo
->flags
= LVHT_TORIGHT
;
6300 if (infoPtr
->rcList
.top
> lpHitTestInfo
->pt
.y
)
6302 lpHitTestInfo
->flags
|= LVHT_ABOVE
;
6304 else if (infoPtr
->rcList
.bottom
< lpHitTestInfo
->pt
.y
)
6306 lpHitTestInfo
->flags
|= LVHT_BELOW
;
6309 if (lpHitTestInfo
->flags
== 0)
6311 /* NOTE (mm 20001022): We must not allow iSubItem to be touched, for
6312 * an app might pass only a structure with space up to iItem!
6313 * (MS Office 97 does that for instance in the file open dialog)
6315 nItem
= LISTVIEW_HitTestItem(hwnd
, lpHitTestInfo
, FALSE
);
6323 * Inserts a new column.
6326 * [I] HWND : window handle
6327 * [I] INT : column index
6328 * [I] LPLVCOLUMNA : column information
6331 * SUCCESS : new column index
6334 static LRESULT
LISTVIEW_InsertColumnA(HWND hwnd
, INT nColumn
,
6335 LPLVCOLUMNA lpColumn
)
6337 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6339 INT nNewColumn
= -1;
6341 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd
, nColumn
,
6344 if (lpColumn
!= NULL
)
6346 /* initialize memory */
6347 ZeroMemory(&hdi
, sizeof(HDITEMA
));
6349 if (lpColumn
->mask
& LVCF_FMT
)
6351 /* format member is valid */
6352 hdi
.mask
|= HDI_FORMAT
;
6354 /* set text alignment (leftmost column must be left-aligned) */
6357 hdi
.fmt
|= HDF_LEFT
;
6361 if (lpColumn
->fmt
& LVCFMT_LEFT
)
6363 hdi
.fmt
|= HDF_LEFT
;
6365 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
6367 hdi
.fmt
|= HDF_RIGHT
;
6369 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
6371 hdi
.fmt
|= HDF_CENTER
;
6375 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
6377 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
6381 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
6386 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
6388 hdi
.fmt
|= HDF_IMAGE
;
6389 hdi
.iImage
= I_IMAGECALLBACK
;
6393 if (lpColumn
->mask
& LVCF_WIDTH
)
6395 hdi
.mask
|= HDI_WIDTH
;
6396 hdi
.cxy
= lpColumn
->cx
;
6399 if (lpColumn
->mask
& LVCF_TEXT
)
6401 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
6402 hdi
.pszText
= lpColumn
->pszText
;
6403 hdi
.cchTextMax
= ((lpColumn
->pszText
!=NULL
) && (lpColumn
->pszText
!=LPSTR_TEXTCALLBACKA
) ? strlen(lpColumn
->pszText
) : 0);
6404 hdi
.fmt
|= HDF_STRING
;
6407 if (lpColumn
->mask
& LVCF_IMAGE
)
6409 hdi
.mask
|= HDI_IMAGE
;
6410 hdi
.iImage
= lpColumn
->iImage
;
6413 if (lpColumn
->mask
& LVCF_ORDER
)
6415 hdi
.mask
|= HDI_ORDER
;
6416 hdi
.iOrder
= lpColumn
->iOrder
;
6419 /* insert item in header control */
6420 nNewColumn
= SendMessageA(infoPtr
->hwndHeader
, HDM_INSERTITEMA
,
6421 (WPARAM
)nColumn
, (LPARAM
)&hdi
);
6423 /* Need to reset the item width when inserting a new column */
6424 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
6426 LISTVIEW_UpdateScroll(hwnd
);
6427 InvalidateRect(hwnd
, NULL
, FALSE
);
6433 static LRESULT
LISTVIEW_InsertColumnW(HWND hwnd
, INT nColumn
,
6434 LPLVCOLUMNW lpColumn
)
6439 memcpy(&lvca
,lpColumn
,sizeof(lvca
));
6440 if (lpColumn
->mask
& LVCF_TEXT
) {
6441 if (lpColumn
->pszText
== LPSTR_TEXTCALLBACKW
)
6442 lvca
.pszText
= LPSTR_TEXTCALLBACKA
;
6444 lvca
.pszText
= HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn
->pszText
);
6446 lres
= LISTVIEW_InsertColumnA(hwnd
,nColumn
,&lvca
);
6447 if (lpColumn
->mask
& LVCF_TEXT
) {
6448 if (lpColumn
->pszText
!= LPSTR_TEXTCALLBACKW
)
6449 HeapFree(GetProcessHeap(),0,lvca
.pszText
);
6454 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
6455 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
6456 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
6457 and not during the processing of a LVM_SORTITEMS message. Applications should provide
6458 their own sort proc. when sending LVM_SORTITEMS.
6461 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
6463 LVS_SORTXXX must be specified,
6464 LVS_OWNERDRAW is not set,
6465 <item>.pszText is not LPSTR_TEXTCALLBACK.
6467 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
6468 are sorted based on item text..."
6470 static INT WINAPI
LISTVIEW_InsertCompare( LPVOID first
, LPVOID second
, LPARAM lParam
)
6472 HDPA hdpa_first
= (HDPA
) first
;
6473 HDPA hdpa_second
= (HDPA
) second
;
6474 LISTVIEW_ITEM
* lv_first
= (LISTVIEW_ITEM
*) DPA_GetPtr( hdpa_first
, 0 );
6475 LISTVIEW_ITEM
* lv_second
= (LISTVIEW_ITEM
*) DPA_GetPtr( hdpa_second
, 0 );
6476 LONG lStyle
= GetWindowLongA((HWND
) lParam
, GWL_STYLE
);
6477 INT cmpv
= lstrcmpA( lv_first
->pszText
, lv_second
->pszText
);
6478 /* if we're sorting descending, negate the return value */
6479 return (lStyle
& LVS_SORTDESCENDING
) ? -cmpv
: cmpv
;
6484 * Inserts a new item in the listview control.
6487 * [I] HWND : window handle
6488 * [I] LPLVITEMA : item information
6491 * SUCCESS : new item index
6494 static LRESULT
LISTVIEW_InsertItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
6496 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6497 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
6498 UINT uView
= lStyle
& LVS_TYPEMASK
;
6499 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
6504 LISTVIEW_ITEM
*lpItem
= NULL
;
6506 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd
, lpLVItem
);
6508 if (lStyle
& LVS_OWNERDATA
)
6510 nItem
= infoPtr
->hdpaItems
->nItemCount
;
6511 infoPtr
->hdpaItems
->nItemCount
++;
6515 if (lpLVItem
!= NULL
)
6517 /* make sure it's not a subitem; cannot insert a subitem */
6518 if (lpLVItem
->iSubItem
== 0)
6520 lpItem
= (LISTVIEW_ITEM
*)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM
));
6523 ZeroMemory(lpItem
, sizeof(LISTVIEW_ITEM
));
6524 if (LISTVIEW_InitItem(hwnd
, lpItem
, lpLVItem
) != FALSE
)
6526 /* insert item in listview control data structure */
6527 hdpaSubItems
= DPA_Create(8);
6528 if (hdpaSubItems
!= NULL
)
6530 nItem
= DPA_InsertPtr(hdpaSubItems
, 0, lpItem
);
6533 if ( ((lStyle
& LVS_SORTASCENDING
) || (lStyle
& LVS_SORTDESCENDING
))
6534 && !(lStyle
& LVS_OWNERDRAWFIXED
)
6535 && (LPSTR_TEXTCALLBACKA
!= lpLVItem
->pszText
) )
6537 /* Insert the item in the proper sort order based on the pszText
6538 member. See comments for LISTVIEW_InsertCompare() for greater detail */
6539 nItem
= DPA_InsertPtr( infoPtr
->hdpaItems
,
6540 GETITEMCOUNT( infoPtr
) + 1, hdpaSubItems
);
6541 DPA_Sort( infoPtr
->hdpaItems
, LISTVIEW_InsertCompare
, hwnd
);
6542 nItem
= DPA_GetPtrIndex( infoPtr
->hdpaItems
, hdpaSubItems
);
6546 nItem
= DPA_InsertPtr(infoPtr
->hdpaItems
, lpLVItem
->iItem
,
6551 LISTVIEW_ShiftSelections(hwnd
,nItem
,1);
6553 /* manage item focus */
6554 if (lpLVItem
->mask
& LVIF_STATE
)
6556 lpItem
->state
&= ~(LVIS_FOCUSED
|LVIS_SELECTED
);
6557 if (lpLVItem
->stateMask
& LVIS_SELECTED
)
6559 LISTVIEW_SetSelection(hwnd
, nItem
);
6561 else if (lpLVItem
->stateMask
& LVIS_FOCUSED
)
6563 LISTVIEW_SetItemFocus(hwnd
, nItem
);
6567 /* send LVN_INSERTITEM notification */
6568 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
6569 nmlv
.hdr
.hwndFrom
= hwnd
;
6570 nmlv
.hdr
.idFrom
= lCtrlId
;
6571 nmlv
.hdr
.code
= LVN_INSERTITEM
;
6573 nmlv
.lParam
= lpItem
->lParam
;;
6574 ListView_LVNotify(GetParent(hwnd
), lCtrlId
, &nmlv
);
6576 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_LIST
))
6578 nItemWidth
= LISTVIEW_CalculateWidth(hwnd
, lpLVItem
->iItem
);
6579 if (nItemWidth
> infoPtr
->nItemWidth
)
6581 infoPtr
->nItemWidth
= nItemWidth
;
6585 /* align items (set position of each item) */
6586 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
6588 if (lStyle
& LVS_ALIGNLEFT
)
6590 LISTVIEW_AlignLeft(hwnd
);
6594 LISTVIEW_AlignTop(hwnd
);
6598 LISTVIEW_UpdateScroll(hwnd
);
6599 /* refresh client area */
6600 InvalidateRect(hwnd
, NULL
, FALSE
);
6609 /* free memory if unsuccessful */
6610 if ((nItem
== -1) && (lpItem
!= NULL
))
6612 COMCTL32_Free(lpItem
);
6618 static LRESULT
LISTVIEW_InsertItemW(HWND hwnd
, LPLVITEMW lpLVItem
) {
6622 memcpy(&lvia
,lpLVItem
,sizeof(LVITEMA
));
6623 if (lvia
.mask
& LVIF_TEXT
) {
6624 if (lpLVItem
->pszText
== LPSTR_TEXTCALLBACKW
)
6625 lvia
.pszText
= LPSTR_TEXTCALLBACKA
;
6627 lvia
.pszText
= HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem
->pszText
);
6629 lres
= LISTVIEW_InsertItemA(hwnd
, &lvia
);
6630 if (lvia
.mask
& LVIF_TEXT
) {
6631 if (lpLVItem
->pszText
!= LPSTR_TEXTCALLBACKW
)
6632 HeapFree(GetProcessHeap(),0,lvia
.pszText
);
6637 /* LISTVIEW_InsertItemW */
6641 * Redraws a range of items.
6644 * [I] HWND : window handle
6645 * [I] INT : first item
6646 * [I] INT : last item
6652 static LRESULT
LISTVIEW_RedrawItems(HWND hwnd
, INT nFirst
, INT nLast
)
6654 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6655 BOOL bResult
= FALSE
;
6658 if (nFirst
<= nLast
)
6660 if ((nFirst
>= 0) && (nFirst
< GETITEMCOUNT(infoPtr
)))
6662 if ((nLast
>= 0) && (nLast
< GETITEMCOUNT(infoPtr
)))
6665 for (i
= nFirst
; i
<= nLast
; i
++)
6667 rcItem
.left
= LVIR_BOUNDS
;
6668 LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
);
6669 InvalidateRect(hwnd
, &rcItem
, TRUE
);
6678 /* LISTVIEW_Scroll */
6682 * Sets the background color.
6685 * [I] HWND : window handle
6686 * [I] COLORREF : background color
6692 static LRESULT
LISTVIEW_SetBkColor(HWND hwnd
, COLORREF clrBk
)
6694 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6696 infoPtr
->clrBk
= clrBk
;
6697 InvalidateRect(hwnd
, NULL
, TRUE
);
6702 /* LISTVIEW_SetBkImage */
6706 * Sets the callback mask. This mask will be used when the parent
6707 * window stores state information (some or all).
6710 * [I] HWND : window handle
6711 * [I] UINT : state mask
6717 static BOOL
LISTVIEW_SetCallbackMask(HWND hwnd
, UINT uMask
)
6719 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6721 infoPtr
->uCallbackMask
= uMask
;
6728 * Sets the attributes of a header item.
6731 * [I] HWND : window handle
6732 * [I] INT : column index
6733 * [I] LPLVCOLUMNA : column attributes
6739 static LRESULT
LISTVIEW_SetColumnA(HWND hwnd
, INT nColumn
,
6740 LPLVCOLUMNA lpColumn
)
6742 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
6743 BOOL bResult
= FALSE
;
6744 HDITEMA hdi
, hdiget
;
6746 if ((lpColumn
!= NULL
) && (nColumn
>= 0) &&
6747 (nColumn
< Header_GetItemCount(infoPtr
->hwndHeader
)))
6749 /* initialize memory */
6750 ZeroMemory(&hdi
, sizeof(HDITEMA
));
6752 if (lpColumn
->mask
& LVCF_FMT
)
6754 /* format member is valid */
6755 hdi
.mask
|= HDI_FORMAT
;
6757 /* get current format first */
6758 hdiget
.mask
= HDI_FORMAT
;
6759 if (Header_GetItemA(infoPtr
->hwndHeader
, nColumn
, &hdiget
))
6760 /* preserve HDF_STRING if present */
6761 hdi
.fmt
= hdiget
.fmt
& HDF_STRING
;
6763 /* set text alignment (leftmost column must be left-aligned) */
6766 hdi
.fmt
|= HDF_LEFT
;
6770 if (lpColumn
->fmt
& LVCFMT_LEFT
)
6772 hdi
.fmt
|= HDF_LEFT
;
6774 else if (lpColumn
->fmt
& LVCFMT_RIGHT
)
6776 hdi
.fmt
|= HDF_RIGHT
;
6778 else if (lpColumn
->fmt
& LVCFMT_CENTER
)
6780 hdi
.fmt
|= HDF_CENTER
;
6784 if (lpColumn
->fmt
& LVCFMT_BITMAP_ON_RIGHT
)
6786 hdi
.fmt
|= HDF_BITMAP_ON_RIGHT
;
6789 if (lpColumn
->fmt
& LVCFMT_COL_HAS_IMAGES
)
6791 hdi
.fmt
|= HDF_IMAGE
;
6794 if (lpColumn
->fmt
& LVCFMT_IMAGE
)
6796 hdi
.fmt
|= HDF_IMAGE
;
6797 hdi
.iImage
= I_IMAGECALLBACK
;
6801 if (lpColumn
->mask
& LVCF_WIDTH
)
6803 hdi
.mask
|= HDI_WIDTH
;
6804 hdi
.cxy
= lpColumn
->cx
;
6807 if (lpColumn
->mask
& LVCF_TEXT
)
6809 hdi
.mask
|= HDI_TEXT
| HDI_FORMAT
;
6810 hdi
.pszText
= lpColumn
->pszText
;
6811 hdi
.cchTextMax
= ((lpColumn
->pszText
!=NULL
) && (lpColumn
->pszText
!=LPSTR_TEXTCALLBACKA
) ? strlen(lpColumn
->pszText
) : 0);
6812 hdi
.fmt
|= HDF_STRING
;
6815 if (lpColumn
->mask
& LVCF_IMAGE
)
6817 hdi
.mask
|= HDI_IMAGE
;
6818 hdi
.iImage
= lpColumn
->iImage
;
6821 if (lpColumn
->mask
& LVCF_ORDER
)
6823 hdi
.mask
|= HDI_ORDER
;
6824 hdi
.iOrder
= lpColumn
->iOrder
;
6827 /* set header item attributes */
6828 bResult
= Header_SetItemA(infoPtr
->hwndHeader
, nColumn
, &hdi
);
6834 /* LISTVIEW_SetColumnW */
6838 * Sets the column order array
6841 * [I] HWND : window handle
6842 * [I] INT : number of elements in column order array
6843 * [I] INT : pointer to column order array
6849 static LRESULT
LISTVIEW_SetColumnOrderArray(HWND hwnd
, INT iCount
, LPINT lpiArray
)
6851 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
6853 FIXME("iCount %d lpiArray %p\n", iCount
, lpiArray
);
6864 * Sets the width of a column
6867 * [I] HWND : window handle
6868 * [I] INT : column index
6869 * [I] INT : column width
6875 static LRESULT
LISTVIEW_SetColumnWidth(HWND hwnd
, INT iCol
, INT cx
)
6877 LISTVIEW_INFO
*infoPtr
;
6880 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
6881 UINT uView
= lStyle
& LVS_TYPEMASK
;
6886 CHAR text_buffer
[DISP_TEXT_SIZE
];
6887 INT header_item_count
;
6892 /* make sure we can get the listview info */
6893 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
6896 if (!infoPtr
->hwndHeader
) /* make sure we have a header */
6899 /* set column width only if in report or list mode */
6900 if ((uView
!= LVS_REPORT
) && (uView
!= LVS_LIST
))
6903 /* take care of invalid cx values */
6904 if((uView
== LVS_REPORT
) && (cx
< -2))
6905 cx
= LVSCW_AUTOSIZE
;
6906 else if (uView
== LVS_LIST
&& (cx
< 1))
6909 /* resize all columns if in LVS_LIST mode */
6910 if(uView
== LVS_LIST
) {
6911 infoPtr
->nItemWidth
= cx
;
6912 InvalidateRect(hwnd
, NULL
, TRUE
); /* force redraw of the listview */
6916 /* autosize based on listview items width */
6917 if(cx
== LVSCW_AUTOSIZE
)
6919 /* set the width of the header to the width of the widest item */
6920 for(item_index
= 0; item_index
< GETITEMCOUNT(infoPtr
); item_index
++)
6922 if(cx
< LISTVIEW_GetLabelWidth(hwnd
, item_index
))
6923 cx
= LISTVIEW_GetLabelWidth(hwnd
, item_index
);
6925 } /* autosize based on listview header width */
6926 else if(cx
== LVSCW_AUTOSIZE_USEHEADER
)
6928 header_item_count
= Header_GetItemCount(infoPtr
->hwndHeader
);
6930 /* if iCol is the last column make it fill the remainder of the controls width */
6931 if(iCol
== (header_item_count
- 1)) {
6932 /* get the width of every item except the current one */
6933 hdi
.mask
= HDI_WIDTH
;
6936 for(item_index
= 0; item_index
< (header_item_count
- 1); item_index
++) {
6937 Header_GetItemA(infoPtr
->hwndHeader
, item_index
, (LPARAM
)(&hdi
));
6941 /* retrieve the layout of the header */
6942 GetWindowRect(infoPtr
->hwndHeader
, &rcHeader
);
6944 cx
= (rcHeader
.right
- rcHeader
.left
) - cx
;
6948 /* retrieve header font */
6949 header_font
= SendMessageA(infoPtr
->hwndHeader
, WM_GETFONT
, 0L, 0L);
6951 /* retrieve header text */
6952 hdi
.mask
= HDI_TEXT
;
6953 hdi
.cchTextMax
= sizeof(text_buffer
);
6954 hdi
.pszText
= text_buffer
;
6956 Header_GetItemA(infoPtr
->hwndHeader
, iCol
, (LPARAM
)(&hdi
));
6958 /* determine the width of the text in the header */
6960 old_font
= SelectObject(hdc
, header_font
); /* select the font into hdc */
6962 GetTextExtentPoint32A(hdc
, text_buffer
, strlen(text_buffer
), &size
);
6964 SelectObject(hdc
, old_font
); /* restore the old font */
6965 ReleaseDC(hwnd
, hdc
);
6967 /* set the width of this column to the width of the text */
6972 /* call header to update the column change */
6973 hdi
.mask
= HDI_WIDTH
;
6976 lret
= Header_SetItemA(infoPtr
->hwndHeader
, (WPARAM
)iCol
, (LPARAM
)&hdi
);
6978 InvalidateRect(hwnd
, NULL
, TRUE
); /* force redraw of the listview */
6985 * Sets the extended listview style.
6988 * [I] HWND : window handle
6993 * SUCCESS : previous style
6996 static LRESULT
LISTVIEW_SetExtendedListViewStyle(HWND hwnd
, DWORD dwMask
, DWORD dwStyle
)
6998 LISTVIEW_INFO
*infoPtr
;
7001 /* make sure we can get the listview info */
7002 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
7005 /* store previous style */
7006 dwOldStyle
= infoPtr
->dwExStyle
;
7010 infoPtr
->dwExStyle
= (dwOldStyle
& ~dwMask
) | (dwStyle
& dwMask
);
7012 infoPtr
->dwExStyle
= dwStyle
;
7014 return (dwOldStyle
);
7017 /* LISTVIEW_SetHotCursor */
7021 * Sets the hot item index.
7024 * [I] HWND : window handle
7028 * SUCCESS : previous hot item index
7029 * FAILURE : -1 (no hot item)
7031 static LRESULT
LISTVIEW_SetHotItem(HWND hwnd
, INT iIndex
)
7033 LISTVIEW_INFO
*infoPtr
;
7036 /* make sure we can get the listview info */
7037 if (!(infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0)))
7040 /* store previous index */
7041 iOldIndex
= infoPtr
->nHotItem
;
7044 infoPtr
->nHotItem
= iIndex
;
7051 * Sets the amount of time the cursor must hover over an item before it is selected.
7054 * [I] HWND : window handle
7055 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
7058 * Returns the previous hover time
7060 static LRESULT
LISTVIEW_SetHoverTime(HWND hwnd
, DWORD dwHoverTime
)
7062 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7063 DWORD oldHoverTime
= infoPtr
->dwHoverTime
;
7065 infoPtr
->dwHoverTime
= dwHoverTime
;
7067 return oldHoverTime
;
7070 /* LISTVIEW_SetIconSpacing */
7077 * [I] HWND : window handle
7078 * [I] INT : image list type
7079 * [I] HIMAGELIST : image list handle
7082 * SUCCESS : old image list
7085 static LRESULT
LISTVIEW_SetImageList(HWND hwnd
, INT nType
, HIMAGELIST himl
)
7087 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7088 HIMAGELIST himlOld
= 0;
7094 himlOld
= infoPtr
->himlNormal
;
7095 infoPtr
->himlNormal
= himl
;
7099 himlOld
= infoPtr
->himlSmall
;
7100 infoPtr
->himlSmall
= himl
;
7104 himlOld
= infoPtr
->himlState
;
7105 infoPtr
->himlState
= himl
;
7106 ImageList_SetBkColor(infoPtr
->himlState
, CLR_NONE
);
7110 oldHeight
= infoPtr
->nItemHeight
;
7111 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
7112 if (infoPtr
->nItemHeight
!= oldHeight
)
7113 LISTVIEW_UpdateScroll(hwnd
);
7115 return (LRESULT
)himlOld
;
7121 * Sets the attributes of an item.
7124 * [I] HWND : window handle
7125 * [I] LPLVITEM : item information
7131 static LRESULT
LISTVIEW_SetItemA(HWND hwnd
, LPLVITEMA lpLVItem
)
7133 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7134 BOOL bResult
= FALSE
;
7136 if (lpLVItem
!= NULL
)
7138 if ((lpLVItem
->iItem
>= 0) && (lpLVItem
->iItem
< GETITEMCOUNT(infoPtr
)))
7140 if (lpLVItem
->iSubItem
== 0)
7142 bResult
= LISTVIEW_SetItem(hwnd
, lpLVItem
);
7146 bResult
= LISTVIEW_SetSubItem(hwnd
, lpLVItem
);
7155 /* LISTVIEW_SetItemW */
7159 * Preallocates memory (does *not* set the actual count of items !)
7162 * [I] HWND : window handle
7163 * [I] INT : item count (projected number of items to allocate)
7164 * [I] DWORD : update flags
7170 static BOOL
LISTVIEW_SetItemCount(HWND hwnd
, INT nItems
, DWORD dwFlags
)
7172 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7174 if (GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_OWNERDATA
)
7176 int precount
,topvisible
;
7177 TRACE("LVS_OWNERDATA is set!\n");
7180 * Internally remove all the selections.
7184 LISTVIEW_SELECTION
*selection
;
7185 selection
= DPA_GetPtr(infoPtr
->hdpaSelectionRanges
,0);
7187 LISTVIEW_RemoveSelectionRange(hwnd
,selection
->lower
,
7190 while (infoPtr
->hdpaSelectionRanges
->nItemCount
>0);
7192 precount
= infoPtr
->hdpaItems
->nItemCount
;
7193 topvisible
= ListView_GetTopIndex(hwnd
) +
7194 LISTVIEW_GetCountPerColumn(hwnd
) + 1;
7196 infoPtr
->hdpaItems
->nItemCount
= nItems
;
7198 LISTVIEW_UpdateSize(hwnd
);
7199 LISTVIEW_UpdateScroll(hwnd
);
7200 if (min(precount
,infoPtr
->hdpaItems
->nItemCount
)<topvisible
)
7201 InvalidateRect(hwnd
, NULL
, TRUE
);
7205 FIXME("setitemcount not done for non-ownerdata\n");
7213 * Sets the position of an item.
7216 * [I] HWND : window handle
7217 * [I] INT : item index
7218 * [I] LONG : x coordinate
7219 * [I] LONG : y coordinate
7225 static BOOL
LISTVIEW_SetItemPosition(HWND hwnd
, INT nItem
,
7226 LONG nPosX
, LONG nPosY
)
7228 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7229 UINT lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
7230 UINT uView
= lStyle
& LVS_TYPEMASK
;
7231 LISTVIEW_ITEM
*lpItem
;
7233 BOOL bResult
= FALSE
;
7235 TRACE("(hwnd=%x,nItem=%d,X=%ld,Y=%ld)\n", hwnd
, nItem
, nPosX
, nPosY
);
7237 if (lStyle
& LVS_OWNERDATA
)
7240 if ((nItem
>= 0) || (nItem
< GETITEMCOUNT(infoPtr
)))
7242 if ((uView
== LVS_ICON
) || (uView
== LVS_SMALLICON
))
7244 hdpaSubItems
= (HDPA
)DPA_GetPtr(infoPtr
->hdpaItems
, nItem
);
7245 if (hdpaSubItems
!= NULL
)
7247 lpItem
= (LISTVIEW_ITEM
*)DPA_GetPtr(hdpaSubItems
, 0);
7251 lpItem
->ptPosition
.x
= nPosX
;
7252 lpItem
->ptPosition
.y
= nPosY
;
7263 * Sets the state of one or many items.
7266 * [I] HWND : window handle
7267 * [I]INT : item index
7268 * [I] LPLVITEM : item or subitem info
7274 static LRESULT
LISTVIEW_SetItemState(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
7276 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7277 BOOL bResult
= FALSE
;
7284 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
7285 lvItem
.mask
= LVIF_STATE
;
7286 lvItem
.state
= lpLVItem
->state
;
7287 lvItem
.stateMask
= lpLVItem
->stateMask
;
7289 /* apply to all items */
7290 for (i
= 0; i
< GETITEMCOUNT(infoPtr
); i
++)
7293 if (ListView_SetItemA(hwnd
, &lvItem
) == FALSE
)
7301 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
7302 lvItem
.mask
= LVIF_STATE
;
7303 lvItem
.state
= lpLVItem
->state
;
7304 lvItem
.stateMask
= lpLVItem
->stateMask
;
7305 lvItem
.iItem
= nItem
;
7306 bResult
= ListView_SetItemA(hwnd
, &lvItem
);
7314 * Sets the text of an item or subitem.
7317 * [I] HWND : window handle
7318 * [I] INT : item index
7319 * [I] LPLVITEMA : item or subitem info
7325 static BOOL
LISTVIEW_SetItemTextA(HWND hwnd
, INT nItem
, LPLVITEMA lpLVItem
)
7327 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7328 BOOL bResult
= FALSE
;
7331 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
7333 ZeroMemory(&lvItem
, sizeof(LVITEMA
));
7334 lvItem
.mask
= LVIF_TEXT
;
7335 lvItem
.pszText
= lpLVItem
->pszText
;
7336 lvItem
.iItem
= nItem
;
7337 lvItem
.iSubItem
= lpLVItem
->iSubItem
;
7338 bResult
= ListView_SetItemA(hwnd
, &lvItem
);
7344 /* LISTVIEW_SetItemTextW */
7348 * Set item index that marks the start of a multiple selection.
7351 * [I] HWND : window handle
7355 * Index number or -1 if there is no selection mark.
7357 static LRESULT
LISTVIEW_SetSelectionMark(HWND hwnd
, INT nIndex
)
7359 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7360 INT nOldIndex
= infoPtr
->nSelectionMark
;
7362 infoPtr
->nSelectionMark
= nIndex
;
7369 * Sets the text background color.
7372 * [I] HWND : window handle
7373 * [I] COLORREF : text background color
7379 static LRESULT
LISTVIEW_SetTextBkColor(HWND hwnd
, COLORREF clrTextBk
)
7381 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7383 infoPtr
->clrTextBk
= clrTextBk
;
7384 InvalidateRect(hwnd
, NULL
, TRUE
);
7391 * Sets the text foreground color.
7394 * [I] HWND : window handle
7395 * [I] COLORREF : text color
7401 static LRESULT
LISTVIEW_SetTextColor (HWND hwnd
, COLORREF clrText
)
7403 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7405 infoPtr
->clrText
= clrText
;
7406 InvalidateRect(hwnd
, NULL
, TRUE
);
7411 /* LISTVIEW_SetToolTips */
7412 /* LISTVIEW_SetUnicodeFormat */
7413 /* LISTVIEW_SetWorkAreas */
7417 * Callback internally used by LISTVIEW_SortItems()
7420 * [I] LPVOID : first LISTVIEW_ITEM to compare
7421 * [I] LPVOID : second LISTVIEW_ITEM to compare
7422 * [I] LPARAM : HWND of control
7425 * if first comes before second : negative
7426 * if first comes after second : positive
7427 * if first and second are equivalent : zero
7429 static INT WINAPI
LISTVIEW_CallBackCompare(
7434 /* Forward the call to the client defined callback */
7436 HWND hwnd
= (HWND
)lParam
;
7437 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7438 HDPA hdpa_first
= (HDPA
) first
;
7439 HDPA hdpa_second
= (HDPA
) second
;
7440 LISTVIEW_ITEM
* lv_first
= (LISTVIEW_ITEM
*) DPA_GetPtr( hdpa_first
, 0 );
7441 LISTVIEW_ITEM
* lv_second
= (LISTVIEW_ITEM
*) DPA_GetPtr( hdpa_second
, 0 );
7443 rv
= (infoPtr
->pfnCompare
)( lv_first
->lParam
, lv_second
->lParam
, infoPtr
->lParamSort
);
7450 * Sorts the listview items.
7453 * [I] HWND : window handle
7454 * [I] WPARAM : application-defined value
7455 * [I] LPARAM : pointer to comparision callback
7461 static LRESULT
LISTVIEW_SortItems(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
7463 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7465 UINT lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
7467 if (lStyle
& LVS_OWNERDATA
)
7470 if (!infoPtr
|| !infoPtr
->hdpaItems
)
7473 nCount
= GETITEMCOUNT(infoPtr
);
7474 /* if there are 0 or 1 items, there is no need to sort */
7477 infoPtr
->pfnCompare
= (PFNLVCOMPARE
)lParam
;
7478 infoPtr
->lParamSort
= (LPARAM
)wParam
;
7480 DPA_Sort(infoPtr
->hdpaItems
, LISTVIEW_CallBackCompare
, hwnd
);
7483 /* align the items */
7484 LISTVIEW_AlignTop(hwnd
);
7486 /* refresh the display */
7487 InvalidateRect(hwnd
, NULL
, TRUE
);
7492 /* LISTVIEW_SubItemHitTest */
7496 * Updates an items or rearranges the listview control.
7499 * [I] HWND : window handle
7500 * [I] INT : item index
7506 static LRESULT
LISTVIEW_Update(HWND hwnd
, INT nItem
)
7508 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7509 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
7510 BOOL bResult
= FALSE
;
7513 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
7517 /* rearrange with default alignment style */
7518 if ((lStyle
& LVS_AUTOARRANGE
) && (((lStyle
& LVS_TYPEMASK
) == LVS_ICON
) ||
7519 ((lStyle
& LVS_TYPEMASK
) == LVS_SMALLICON
)))
7521 ListView_Arrange(hwnd
, 0);
7525 /* get item bounding rectangle */
7526 rc
.left
= LVIR_BOUNDS
;
7527 ListView_GetItemRect(hwnd
, nItem
, &rc
, rc
.left
);
7528 InvalidateRect(hwnd
, &rc
, TRUE
);
7537 * Creates the listview control.
7540 * [I] HWND : window handle
7545 static LRESULT
LISTVIEW_Create(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
7547 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7548 LPCREATESTRUCTA lpcs
= (LPCREATESTRUCTA
)lParam
;
7549 UINT uView
= lpcs
->style
& LVS_TYPEMASK
;
7552 /* initialize info pointer */
7553 ZeroMemory(infoPtr
, sizeof(LISTVIEW_INFO
));
7555 /* determine the type of structures to use */
7556 infoPtr
->notifyFormat
= SendMessageA(GetParent(hwnd
), WM_NOTIFYFORMAT
,
7557 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
7558 if (infoPtr
->notifyFormat
!= NFR_ANSI
)
7560 FIXME("ANSI notify format is NOT used\n");
7563 /* initialize color information */
7564 infoPtr
->clrBk
= GetSysColor(COLOR_WINDOW
);
7565 infoPtr
->clrText
= GetSysColor(COLOR_WINDOWTEXT
);
7566 infoPtr
->clrTextBk
= CLR_DEFAULT
;
7568 /* set default values */
7569 infoPtr
->uCallbackMask
= 0;
7570 infoPtr
->nFocusedItem
= -1;
7571 infoPtr
->nSelectionMark
= -1;
7572 infoPtr
->nHotItem
= -1;
7573 infoPtr
->iconSpacing
.cx
= GetSystemMetrics(SM_CXICONSPACING
);
7574 infoPtr
->iconSpacing
.cy
= GetSystemMetrics(SM_CYICONSPACING
);
7575 ZeroMemory(&infoPtr
->rcList
, sizeof(RECT
));
7576 infoPtr
->hwndEdit
= 0;
7577 infoPtr
->pedititem
= NULL
;
7578 infoPtr
->nEditLabelItem
= -1;
7580 /* get default font (icon title) */
7581 SystemParametersInfoA(SPI_GETICONTITLELOGFONT
, 0, &logFont
, 0);
7582 infoPtr
->hDefaultFont
= CreateFontIndirectA(&logFont
);
7583 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
7586 infoPtr
->hwndHeader
= CreateWindowA(WC_HEADERA
, (LPCSTR
)NULL
,
7587 WS_CHILD
| HDS_HORZ
| HDS_BUTTONS
,
7588 0, 0, 0, 0, hwnd
, (HMENU
)0,
7589 lpcs
->hInstance
, NULL
);
7591 /* set header font */
7592 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)infoPtr
->hFont
,
7595 if (uView
== LVS_ICON
)
7597 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
7598 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
7600 else if (uView
== LVS_REPORT
)
7602 if (!(LVS_NOCOLUMNHEADER
& lpcs
->style
))
7604 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
7608 /* set HDS_HIDDEN flag to hide the header bar */
7609 SetWindowLongA(infoPtr
->hwndHeader
, GWL_STYLE
,
7610 GetWindowLongA(infoPtr
->hwndHeader
, GWL_STYLE
) | HDS_HIDDEN
);
7614 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
7615 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
7619 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
7620 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
7623 /* display unsupported listview window styles */
7624 LISTVIEW_UnsupportedStyles(lpcs
->style
);
7626 /* allocate memory for the data structure */
7627 infoPtr
->hdpaItems
= DPA_Create(10);
7629 /* allocate memory for the selection ranges */
7630 infoPtr
->hdpaSelectionRanges
= DPA_Create(10);
7632 /* initialize size of items */
7633 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
7634 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
7636 /* initialize the hover time to -1(indicating the default system hover time) */
7637 infoPtr
->dwHoverTime
= -1;
7644 * Erases the background of the listview control.
7647 * [I] HWND : window handle
7648 * [I] WPARAM : device context handle
7649 * [I] LPARAM : not used
7655 static LRESULT
LISTVIEW_EraseBackground(HWND hwnd
, WPARAM wParam
,
7658 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7661 if (infoPtr
->clrBk
== CLR_NONE
)
7663 bResult
= SendMessageA(GetParent(hwnd
), WM_ERASEBKGND
, wParam
, lParam
);
7668 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
7669 GetClientRect(hwnd
, &rc
);
7670 FillRect((HDC
)wParam
, &rc
, hBrush
);
7671 DeleteObject(hBrush
);
7679 static void LISTVIEW_FillBackground(HWND hwnd
, HDC hdc
, LPRECT rc
)
7681 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7683 if (infoPtr
->clrBk
!= CLR_NONE
)
7685 HBRUSH hBrush
= CreateSolidBrush(infoPtr
->clrBk
);
7686 FillRect(hdc
, rc
, hBrush
);
7687 DeleteObject(hBrush
);
7693 * Retrieves the listview control font.
7696 * [I] HWND : window handle
7701 static LRESULT
LISTVIEW_GetFont(HWND hwnd
)
7703 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7705 return infoPtr
->hFont
;
7710 * Performs vertical scrolling.
7713 * [I] HWND : window handle
7714 * [I] INT : scroll code
7715 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
7717 * [I] HWND : scrollbar control window handle
7722 static LRESULT
LISTVIEW_VScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
7725 SCROLLINFO scrollInfo
;
7727 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7728 SendMessageA(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
7730 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
7731 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
7732 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
7734 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
7736 INT nOldScrollPos
= scrollInfo
.nPos
;
7737 switch (nScrollCode
)
7740 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
7747 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
7754 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
7756 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
7758 scrollInfo
.nPos
-= scrollInfo
.nPage
;
7762 scrollInfo
.nPos
= scrollInfo
.nMin
;
7768 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
7770 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
7772 scrollInfo
.nPos
+= scrollInfo
.nPage
;
7776 scrollInfo
.nPos
= scrollInfo
.nMax
;
7782 scrollInfo
.nPos
= nCurrentPos
;
7783 if (scrollInfo
.nPos
> scrollInfo
.nMax
)
7784 scrollInfo
.nPos
=scrollInfo
.nMax
;
7786 if (scrollInfo
.nPos
< scrollInfo
.nMin
)
7787 scrollInfo
.nPos
=scrollInfo
.nMin
;
7792 if (nOldScrollPos
!= scrollInfo
.nPos
)
7794 scrollInfo
.fMask
= SIF_POS
;
7795 SetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
, TRUE
);
7796 InvalidateRect(hwnd
, NULL
, TRUE
);
7805 * Performs horizontal scrolling.
7808 * [I] HWND : window handle
7809 * [I] INT : scroll code
7810 * [I] SHORT : current scroll position if scroll code is SB_THUMBPOSITION
7812 * [I] HWND : scrollbar control window handle
7817 static LRESULT
LISTVIEW_HScroll(HWND hwnd
, INT nScrollCode
, SHORT nCurrentPos
,
7820 SCROLLINFO scrollInfo
;
7822 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7823 SendMessageA(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
7826 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
7827 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
7828 scrollInfo
.fMask
= SIF_PAGE
| SIF_POS
| SIF_RANGE
;
7830 if (GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
) != FALSE
)
7832 INT nOldScrollPos
= scrollInfo
.nPos
;
7834 switch (nScrollCode
)
7837 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
7844 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
7851 if (scrollInfo
.nPos
> scrollInfo
.nMin
)
7853 if (scrollInfo
.nPos
>= scrollInfo
.nPage
)
7855 scrollInfo
.nPos
-= scrollInfo
.nPage
;
7859 scrollInfo
.nPos
= scrollInfo
.nMin
;
7865 if (scrollInfo
.nPos
< scrollInfo
.nMax
)
7867 if (scrollInfo
.nPos
<= scrollInfo
.nMax
- scrollInfo
.nPage
)
7869 scrollInfo
.nPos
+= scrollInfo
.nPage
;
7873 scrollInfo
.nPos
= scrollInfo
.nMax
;
7879 scrollInfo
.nPos
= nCurrentPos
;
7881 if (scrollInfo
.nPos
> scrollInfo
.nMax
)
7882 scrollInfo
.nPos
=scrollInfo
.nMax
;
7884 if (scrollInfo
.nPos
< scrollInfo
.nMin
)
7885 scrollInfo
.nPos
=scrollInfo
.nMin
;
7889 if (nOldScrollPos
!= scrollInfo
.nPos
)
7891 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
7892 scrollInfo
.fMask
= SIF_POS
;
7893 SetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
, TRUE
);
7894 if(uView
== LVS_REPORT
)
7896 scrollInfo
.fMask
= SIF_POS
;
7897 GetScrollInfo(hwnd
, SB_HORZ
, &scrollInfo
);
7898 LISTVIEW_UpdateHeaderSize(hwnd
, scrollInfo
.nPos
);
7900 InvalidateRect(hwnd
, NULL
, TRUE
);
7907 static LRESULT
LISTVIEW_MouseWheel(HWND hwnd
, INT wheelDelta
)
7909 INT gcWheelDelta
= 0;
7910 UINT pulScrollLines
= 3;
7911 SCROLLINFO scrollInfo
;
7913 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
7915 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES
,0, &pulScrollLines
, 0);
7916 gcWheelDelta
-= wheelDelta
;
7918 ZeroMemory(&scrollInfo
, sizeof(SCROLLINFO
));
7919 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
7920 scrollInfo
.fMask
= SIF_POS
| SIF_RANGE
;
7927 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
7928 * should be fixed in the future.
7930 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
7931 LISTVIEW_VScroll(hwnd
, SB_THUMBPOSITION
, scrollInfo
.nPos
+ (gcWheelDelta
< 0) ? 37 : -37, 0);
7935 if (abs(gcWheelDelta
) >= WHEEL_DELTA
&& pulScrollLines
)
7937 if (GetScrollInfo(hwnd
, SB_VERT
, &scrollInfo
) != FALSE
)
7939 int cLineScroll
= min(LISTVIEW_GetCountPerColumn(hwnd
), pulScrollLines
);
7940 cLineScroll
*= (gcWheelDelta
/ WHEEL_DELTA
);
7941 LISTVIEW_VScroll(hwnd
, SB_THUMBPOSITION
, scrollInfo
.nPos
+ cLineScroll
, 0);
7947 LISTVIEW_HScroll(hwnd
, (gcWheelDelta
< 0) ? SB_LINELEFT
: SB_LINERIGHT
, 0, 0);
7958 * [I] HWND : window handle
7959 * [I] INT : virtual key
7960 * [I] LONG : key data
7965 static LRESULT
LISTVIEW_KeyDown(HWND hwnd
, INT nVirtualKey
, LONG lKeyData
)
7967 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
7968 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
7969 HWND hwndParent
= GetParent(hwnd
);
7970 NMLVKEYDOWN nmKeyDown
;
7973 BOOL bRedraw
= FALSE
;
7974 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
7975 UINT uView
= lStyle
& LVS_TYPEMASK
;
7977 /* send LVN_KEYDOWN notification */
7978 ZeroMemory(&nmKeyDown
, sizeof(NMLVKEYDOWN
));
7979 nmKeyDown
.hdr
.hwndFrom
= hwnd
;
7980 nmKeyDown
.hdr
.idFrom
= nCtrlId
;
7981 nmKeyDown
.hdr
.code
= LVN_KEYDOWN
;
7982 nmKeyDown
.wVKey
= nVirtualKey
;
7983 nmKeyDown
.flags
= 0;
7984 SendMessageA(hwndParent
, WM_NOTIFY
, (WPARAM
)nCtrlId
, (LPARAM
)&nmKeyDown
);
7987 nmh
.hwndFrom
= hwnd
;
7988 nmh
.idFrom
= nCtrlId
;
7990 switch (nVirtualKey
)
7993 if ((GETITEMCOUNT(infoPtr
) > 0) && (infoPtr
->nFocusedItem
!= -1))
7995 /* send NM_RETURN notification */
7996 nmh
.code
= NM_RETURN
;
7997 ListView_Notify(hwndParent
, nCtrlId
, &nmh
);
7999 /* send LVN_ITEMACTIVATE notification */
8000 nmh
.code
= LVN_ITEMACTIVATE
;
8001 ListView_Notify(hwndParent
, nCtrlId
, &nmh
);
8006 if (GETITEMCOUNT(infoPtr
) > 0)
8013 if (GETITEMCOUNT(infoPtr
) > 0)
8015 nItem
= GETITEMCOUNT(infoPtr
) - 1;
8020 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TOLEFT
);
8024 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_ABOVE
);
8028 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_TORIGHT
);
8032 nItem
= ListView_GetNextItem(hwnd
, infoPtr
->nFocusedItem
, LVNI_BELOW
);
8036 if (uView
== LVS_REPORT
)
8038 nItem
= infoPtr
->nFocusedItem
- LISTVIEW_GetCountPerColumn(hwnd
);
8042 nItem
= infoPtr
->nFocusedItem
- LISTVIEW_GetCountPerColumn(hwnd
)
8043 * LISTVIEW_GetCountPerRow(hwnd
);
8045 if(nItem
< 0) nItem
= 0;
8049 if (uView
== LVS_REPORT
)
8051 nItem
= infoPtr
->nFocusedItem
+ LISTVIEW_GetCountPerColumn(hwnd
);
8055 nItem
= infoPtr
->nFocusedItem
+ LISTVIEW_GetCountPerColumn(hwnd
)
8056 * LISTVIEW_GetCountPerRow(hwnd
);
8058 if(nItem
>= GETITEMCOUNT(infoPtr
)) nItem
= GETITEMCOUNT(infoPtr
) - 1;
8062 if ((nItem
!= -1) && (nItem
!= infoPtr
->nFocusedItem
))
8064 bRedraw
= LISTVIEW_KeySelection(hwnd
, nItem
);
8065 if (bRedraw
!= FALSE
)
8067 /* refresh client area */
8080 * [I] HWND : window handle
8085 static LRESULT
LISTVIEW_KillFocus(HWND hwnd
)
8087 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8088 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8092 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
8093 UINT uView
= lStyle
& LVS_TYPEMASK
;
8095 TRACE("(hwnd=%x)\n", hwnd
);
8097 /* send NM_KILLFOCUS notification */
8098 nmh
.hwndFrom
= hwnd
;
8099 nmh
.idFrom
= nCtrlId
;
8100 nmh
.code
= NM_KILLFOCUS
;
8101 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
8103 /* set window focus flag */
8104 infoPtr
->bFocus
= FALSE
;
8106 /* NEED drawing optimization ; redraw the selected items */
8107 if (uView
& LVS_REPORT
)
8109 nTop
= LISTVIEW_GetTopIndex(hwnd
);
8111 LISTVIEW_GetCountPerColumn(hwnd
) + 1;
8116 nBottom
= GETITEMCOUNT(infoPtr
);
8118 for (i
= nTop
; i
<nBottom
; i
++)
8120 if (LISTVIEW_IsSelected(hwnd
,i
))
8122 rcItem
.left
= LVIR_BOUNDS
;
8123 LISTVIEW_GetItemRect(hwnd
, i
, &rcItem
);
8124 InvalidateRect(hwnd
, &rcItem
, FALSE
);
8133 * Processes double click messages (left mouse button).
8136 * [I] HWND : window handle
8137 * [I] WORD : key flag
8138 * [I] WORD : x coordinate
8139 * [I] WORD : y coordinate
8144 static LRESULT
LISTVIEW_LButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
8147 LONG nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8148 LVHITTESTINFO htInfo
;
8153 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8155 htInfo
.pt
.x
= wPosX
;
8156 htInfo
.pt
.y
= wPosY
;
8158 /* send NM_DBLCLK notification */
8159 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8160 nmlv
.hdr
.hwndFrom
= hwnd
;
8161 nmlv
.hdr
.idFrom
= nCtrlId
;
8162 nmlv
.hdr
.code
= NM_DBLCLK
;
8163 ret
= LISTVIEW_HitTestItem(hwnd
, &htInfo
, TRUE
);
8166 nmlv
.iItem
= htInfo
.iItem
;
8167 nmlv
.iSubItem
= htInfo
.iSubItem
;
8174 nmlv
.ptAction
.x
= wPosX
;
8175 nmlv
.ptAction
.y
= wPosY
;
8176 ListView_LVNotify(GetParent(hwnd
), nCtrlId
, &nmlv
);
8179 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
8182 /* send LVN_ITEMACTIVATE notification */
8183 nmh
.hwndFrom
= hwnd
;
8184 nmh
.idFrom
= nCtrlId
;
8185 nmh
.code
= LVN_ITEMACTIVATE
;
8186 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
8194 * Processes mouse down messages (left mouse button).
8197 * [I] HWND : window handle
8198 * [I] WORD : key flag
8199 * [I] WORD : x coordinate
8200 * [I] WORD : y coordinate
8205 static LRESULT
LISTVIEW_LButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
8208 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8209 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
8210 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8211 static BOOL bGroupSelect
= TRUE
;
8216 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd
, wKey
, wPosX
,
8219 /* send NM_RELEASEDCAPTURE notification */
8220 nmh
.hwndFrom
= hwnd
;
8221 nmh
.idFrom
= nCtrlId
;
8222 nmh
.code
= NM_RELEASEDCAPTURE
;
8223 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
8225 if (infoPtr
->bFocus
== FALSE
)
8230 /* set left button down flag */
8231 infoPtr
->bLButtonDown
= TRUE
;
8233 ptPosition
.x
= wPosX
;
8234 ptPosition
.y
= wPosY
;
8235 nItem
= LISTVIEW_MouseSelection(hwnd
, ptPosition
);
8236 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
8238 if (lStyle
& LVS_SINGLESEL
)
8240 if ((ListView_GetItemState(hwnd
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
)
8241 && infoPtr
->nEditLabelItem
== -1)
8243 infoPtr
->nEditLabelItem
= nItem
;
8247 LISTVIEW_SetSelection(hwnd
, nItem
);
8252 if ((wKey
& MK_CONTROL
) && (wKey
& MK_SHIFT
))
8254 if (bGroupSelect
!= FALSE
)
8256 LISTVIEW_AddGroupSelection(hwnd
, nItem
);
8260 LISTVIEW_AddSelection(hwnd
, nItem
);
8263 else if (wKey
& MK_CONTROL
)
8265 bGroupSelect
= LISTVIEW_ToggleSelection(hwnd
, nItem
);
8267 else if (wKey
& MK_SHIFT
)
8269 LISTVIEW_SetGroupSelection(hwnd
, nItem
);
8274 (ListView_GetItemState(hwnd
, nItem
, LVIS_SELECTED
) & LVIS_SELECTED
);
8276 /* set selection (clears other pre-existing selections) */
8277 LISTVIEW_SetSelection(hwnd
, nItem
);
8279 if (was_selected
&& infoPtr
->nEditLabelItem
== -1)
8281 infoPtr
->nEditLabelItem
= nItem
;
8288 /* remove all selections */
8289 LISTVIEW_RemoveAllSelections(hwnd
);
8292 /* redraw if we could have possibly selected something */
8293 if(!GETITEMCOUNT(infoPtr
)) InvalidateRect(hwnd
, NULL
, TRUE
);
8300 * Processes mouse up messages (left mouse button).
8303 * [I] HWND : window handle
8304 * [I] WORD : key flag
8305 * [I] WORD : x coordinate
8306 * [I] WORD : y coordinate
8311 static LRESULT
LISTVIEW_LButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
8314 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8316 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8318 if (infoPtr
->bLButtonDown
!= FALSE
)
8320 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8322 LVHITTESTINFO lvHitTestInfo
;
8325 lvHitTestInfo
.pt
.x
= wPosX
;
8326 lvHitTestInfo
.pt
.y
= wPosY
;
8328 /* send NM_CLICK notification */
8329 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8330 nmlv
.hdr
.hwndFrom
= hwnd
;
8331 nmlv
.hdr
.idFrom
= nCtrlId
;
8332 nmlv
.hdr
.code
= NM_CLICK
;
8333 ret
= LISTVIEW_HitTestItem(hwnd
, &lvHitTestInfo
, TRUE
);
8336 nmlv
.iItem
= lvHitTestInfo
.iItem
;
8337 nmlv
.iSubItem
= lvHitTestInfo
.iSubItem
;
8344 nmlv
.ptAction
.x
= wPosX
;
8345 nmlv
.ptAction
.y
= wPosY
;
8346 ListView_LVNotify(GetParent(hwnd
), nCtrlId
, &nmlv
);
8349 /* set left button flag */
8350 infoPtr
->bLButtonDown
= FALSE
;
8352 if(infoPtr
->nEditLabelItem
!= -1)
8354 if(lvHitTestInfo
.iItem
== infoPtr
->nEditLabelItem
)
8356 LISTVIEW_EditLabelA(hwnd
, lvHitTestInfo
.iItem
);
8358 infoPtr
->nEditLabelItem
= -1;
8367 * Creates the listview control (called before WM_CREATE).
8370 * [I] HWND : window handle
8371 * [I] WPARAM : unhandled
8372 * [I] LPARAM : widow creation info
8377 static LRESULT
LISTVIEW_NCCreate(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
8379 LISTVIEW_INFO
*infoPtr
;
8381 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd
, wParam
, lParam
);
8383 /* allocate memory for info structure */
8384 infoPtr
= (LISTVIEW_INFO
*)COMCTL32_Alloc(sizeof(LISTVIEW_INFO
));
8385 SetWindowLongA(hwnd
, 0, (LONG
)infoPtr
);
8386 if (infoPtr
== NULL
)
8388 ERR("could not allocate info memory!\n");
8392 if ((LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0) != infoPtr
)
8394 ERR("pointer assignment error!\n");
8398 return DefWindowProcA(hwnd
, WM_NCCREATE
, wParam
, lParam
);
8403 * Destroys the listview control (called after WM_DESTROY).
8406 * [I] HWND : window handle
8411 static LRESULT
LISTVIEW_NCDestroy(HWND hwnd
)
8413 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8415 TRACE("(hwnd=%x)\n", hwnd
);
8417 /* delete all items */
8418 LISTVIEW_DeleteAllItems(hwnd
);
8420 /* destroy data structure */
8421 DPA_Destroy(infoPtr
->hdpaItems
);
8422 DPA_Destroy(infoPtr
->hdpaSelectionRanges
);
8425 infoPtr
->hFont
= (HFONT
)0;
8426 if (infoPtr
->hDefaultFont
)
8428 DeleteObject(infoPtr
->hDefaultFont
);
8431 /* free listview info pointer*/
8432 COMCTL32_Free(infoPtr
);
8434 SetWindowLongA(hwnd
, 0, 0);
8440 * Handles notifications from children.
8443 * [I] HWND : window handle
8444 * [I] INT : control identifier
8445 * [I] LPNMHDR : notification information
8450 static LRESULT
LISTVIEW_Notify(HWND hwnd
, INT nCtrlId
, LPNMHDR lpnmh
)
8452 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8454 if (lpnmh
->hwndFrom
== infoPtr
->hwndHeader
)
8456 /* handle notification from header control */
8457 if (lpnmh
->code
== HDN_ENDTRACKA
)
8459 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8460 InvalidateRect(hwnd
, NULL
, TRUE
);
8462 else if(lpnmh
->code
== HDN_ITEMCLICKA
)
8464 /* Handle sorting by Header Column */
8466 LPNMHEADERA pnmHeader
= (LPNMHEADERA
) lpnmh
;
8467 LONG lCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8469 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8470 nmlv
.hdr
.hwndFrom
= hwnd
;
8471 nmlv
.hdr
.idFrom
= lCtrlId
;
8472 nmlv
.hdr
.code
= LVN_COLUMNCLICK
;
8474 nmlv
.iSubItem
= pnmHeader
->iItem
;
8476 ListView_LVNotify(GetParent(hwnd
),lCtrlId
, &nmlv
);
8479 else if(lpnmh
->code
== NM_RELEASEDCAPTURE
)
8481 /* Idealy this should be done in HDN_ENDTRACKA
8482 * but since SetItemBounds in Header.c is called after
8483 * the notification is sent, it is neccessary to handle the
8484 * update of the scroll bar here (Header.c works fine as it is,
8485 * no need to disturb it)
8487 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8488 LISTVIEW_UpdateScroll(hwnd
);
8489 InvalidateRect(hwnd
, NULL
, TRUE
);
8499 * Determines the type of structure to use.
8502 * [I] HWND : window handle of the sender
8503 * [I] HWND : listview window handle
8504 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
8509 static LRESULT
LISTVIEW_NotifyFormat(HWND hwndFrom
, HWND hwnd
, INT nCommand
)
8511 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8513 if (nCommand
== NF_REQUERY
)
8515 /* determine the type of structure to use */
8516 infoPtr
->notifyFormat
= SendMessageA(hwndFrom
, WM_NOTIFYFORMAT
,
8517 (WPARAM
)hwnd
, (LPARAM
)NF_QUERY
);
8518 if (infoPtr
->notifyFormat
== NFR_UNICODE
)
8520 FIXME("NO support for unicode structures");
8529 * Paints/Repaints the listview control.
8532 * [I] HWND : window handle
8533 * [I] HDC : device context handle
8538 static LRESULT
LISTVIEW_Paint(HWND hwnd
, HDC hdc
)
8542 TRACE("(hwnd=%x,hdc=%x)\n", hwnd
, hdc
);
8546 hdc
= BeginPaint(hwnd
, &ps
);
8547 LISTVIEW_Refresh(hwnd
, hdc
);
8548 EndPaint(hwnd
, &ps
);
8552 LISTVIEW_Refresh(hwnd
, hdc
);
8560 * Processes double click messages (right mouse button).
8563 * [I] HWND : window handle
8564 * [I] WORD : key flag
8565 * [I] WORD : x coordinate
8566 * [I] WORD : y coordinate
8571 static LRESULT
LISTVIEW_RButtonDblClk(HWND hwnd
, WORD wKey
, WORD wPosX
,
8574 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8577 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8579 /* send NM_RELEASEDCAPTURE notification */
8580 nmh
.hwndFrom
= hwnd
;
8581 nmh
.idFrom
= nCtrlId
;
8582 nmh
.code
= NM_RELEASEDCAPTURE
;
8583 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
8585 /* send NM_RDBLCLK notification */
8586 nmh
.code
= NM_RDBLCLK
;
8587 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
8594 * Processes mouse down messages (right mouse button).
8597 * [I] HWND : window handle
8598 * [I] WORD : key flag
8599 * [I] WORD : x coordinate
8600 * [I] WORD : y coordinate
8605 static LRESULT
LISTVIEW_RButtonDown(HWND hwnd
, WORD wKey
, WORD wPosX
,
8608 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8609 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8614 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8616 /* send NM_RELEASEDCAPTURE notification */
8617 nmh
.hwndFrom
= hwnd
;
8618 nmh
.idFrom
= nCtrlId
;
8619 nmh
.code
= NM_RELEASEDCAPTURE
;
8620 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
8622 /* make sure the listview control window has the focus */
8623 if (infoPtr
->bFocus
== FALSE
)
8628 /* set right button down flag */
8629 infoPtr
->bRButtonDown
= TRUE
;
8631 /* determine the index of the selected item */
8632 ptPosition
.x
= wPosX
;
8633 ptPosition
.y
= wPosY
;
8634 nItem
= LISTVIEW_MouseSelection(hwnd
, ptPosition
);
8635 if ((nItem
>= 0) && (nItem
< GETITEMCOUNT(infoPtr
)))
8637 if (!((wKey
& MK_SHIFT
) || (wKey
& MK_CONTROL
)))
8639 LISTVIEW_SetSelection(hwnd
, nItem
);
8644 LISTVIEW_RemoveAllSelections(hwnd
);
8652 * Processes mouse up messages (right mouse button).
8655 * [I] HWND : window handle
8656 * [I] WORD : key flag
8657 * [I] WORD : x coordinate
8658 * [I] WORD : y coordinate
8663 static LRESULT
LISTVIEW_RButtonUp(HWND hwnd
, WORD wKey
, WORD wPosX
,
8666 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8667 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8669 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd
, wKey
, wPosX
, wPosY
);
8671 if (infoPtr
->bRButtonDown
!= FALSE
)
8674 LVHITTESTINFO lvHitTestInfo
;
8678 lvHitTestInfo
.pt
.x
= wPosX
;
8679 lvHitTestInfo
.pt
.y
= wPosY
;
8681 /* Send NM_RClICK notification */
8682 ZeroMemory(&nmlv
, sizeof(NMLISTVIEW
));
8683 nmlv
.hdr
.hwndFrom
= hwnd
;
8684 nmlv
.hdr
.idFrom
= nCtrlId
;
8685 nmlv
.hdr
.code
= NM_RCLICK
;
8686 ret
= LISTVIEW_HitTestItem(hwnd
, &lvHitTestInfo
, TRUE
);
8689 nmlv
.iItem
= lvHitTestInfo
.iItem
;
8690 nmlv
.iSubItem
= lvHitTestInfo
.iSubItem
;
8697 nmlv
.ptAction
.x
= wPosX
;
8698 nmlv
.ptAction
.y
= wPosY
;
8699 ListView_LVNotify(GetParent(hwnd
), nCtrlId
, &nmlv
);
8704 /* set button flag */
8705 infoPtr
->bRButtonDown
= FALSE
;
8707 /* Change to screen coordinate for WM_CONTEXTMENU */
8708 ClientToScreen(hwnd
, &pt
);
8710 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
8711 SendMessageA( hwnd
, WM_CONTEXTMENU
, (WPARAM
) hwnd
, MAKELPARAM(pt
.x
, pt
.y
));
8722 * [I] HWND : window handle
8723 * [I] HWND : window handle of previously focused window
8728 static LRESULT
LISTVIEW_SetFocus(HWND hwnd
, HWND hwndLoseFocus
)
8730 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8731 INT nCtrlId
= GetWindowLongA(hwnd
, GWL_ID
);
8734 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd
, hwndLoseFocus
);
8736 /* send NM_SETFOCUS notification */
8737 nmh
.hwndFrom
= hwnd
;
8738 nmh
.idFrom
= nCtrlId
;
8739 nmh
.code
= NM_SETFOCUS
;
8740 ListView_Notify(GetParent(hwnd
), nCtrlId
, &nmh
);
8742 /* set window focus flag */
8743 infoPtr
->bFocus
= TRUE
;
8755 * [I] HWND : window handle
8756 * [I] HFONT : font handle
8757 * [I] WORD : redraw flag
8762 static LRESULT
LISTVIEW_SetFont(HWND hwnd
, HFONT hFont
, WORD fRedraw
)
8764 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8765 UINT uView
= GetWindowLongA(hwnd
, GWL_STYLE
) & LVS_TYPEMASK
;
8767 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd
, hFont
, fRedraw
);
8771 infoPtr
->hFont
= infoPtr
->hDefaultFont
;
8775 infoPtr
->hFont
= hFont
;
8778 if (uView
== LVS_REPORT
)
8780 /* set header font */
8781 SendMessageA(infoPtr
->hwndHeader
, WM_SETFONT
, (WPARAM
)hFont
,
8782 MAKELPARAM(fRedraw
, 0));
8785 /* invalidate listview control client area */
8786 InvalidateRect(hwnd
, NULL
, TRUE
);
8788 if (fRedraw
!= FALSE
)
8798 * Message handling for WM_SETREDRAW.
8799 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
8802 * [I] HWND : window handle
8803 * [I] bRedraw: state of redraw flag
8806 * DefWinProc return value
8808 static LRESULT
LISTVIEW_SetRedraw(HWND hwnd
, BOOL bRedraw
)
8811 lResult
= DefWindowProcA(hwnd
, WM_SETREDRAW
, bRedraw
, 0);
8814 RedrawWindow(hwnd
, NULL
, 0,
8815 RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ALLCHILDREN
| RDW_ERASENOW
);
8822 * Resizes the listview control. This function processes WM_SIZE
8823 * messages. At this time, the width and height are not used.
8826 * [I] HWND : window handle
8827 * [I] WORD : new width
8828 * [I] WORD : new height
8833 static LRESULT
LISTVIEW_Size(HWND hwnd
, int Width
, int Height
)
8835 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
8836 UINT uView
= lStyle
& LVS_TYPEMASK
;
8838 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd
, Width
, Height
);
8840 LISTVIEW_UpdateSize(hwnd
);
8842 if ((uView
== LVS_SMALLICON
) || (uView
== LVS_ICON
))
8844 if (lStyle
& LVS_ALIGNLEFT
)
8846 LISTVIEW_AlignLeft(hwnd
);
8850 LISTVIEW_AlignTop(hwnd
);
8854 LISTVIEW_UpdateScroll(hwnd
);
8856 /* invalidate client area + erase background */
8857 InvalidateRect(hwnd
, NULL
, TRUE
);
8864 * Sets the size information.
8867 * [I] HWND : window handle
8872 static VOID
LISTVIEW_UpdateSize(HWND hwnd
)
8874 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8875 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
8876 UINT uView
= lStyle
& LVS_TYPEMASK
;
8879 GetClientRect(hwnd
, &rcList
);
8880 infoPtr
->rcList
.left
= 0;
8881 infoPtr
->rcList
.right
= max(rcList
.right
- rcList
.left
, 1);
8882 infoPtr
->rcList
.top
= 0;
8883 infoPtr
->rcList
.bottom
= max(rcList
.bottom
- rcList
.top
, 1);
8885 if (uView
== LVS_LIST
)
8887 if (lStyle
& WS_HSCROLL
)
8889 INT nHScrollHeight
= GetSystemMetrics(SM_CYHSCROLL
);
8890 if (infoPtr
->rcList
.bottom
> nHScrollHeight
)
8892 infoPtr
->rcList
.bottom
-= nHScrollHeight
;
8896 else if (uView
== LVS_REPORT
)
8903 Header_Layout(infoPtr
->hwndHeader
, &hl
);
8905 SetWindowPos(wp
.hwnd
, wp
.hwndInsertAfter
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
, wp
.flags
);
8907 if (!(LVS_NOCOLUMNHEADER
& lStyle
))
8909 infoPtr
->rcList
.top
= max(wp
.cy
, 0);
8916 * Processes WM_STYLECHANGED messages.
8919 * [I] HWND : window handle
8920 * [I] WPARAM : window style type (normal or extended)
8921 * [I] LPSTYLESTRUCT : window style information
8926 static INT
LISTVIEW_StyleChanged(HWND hwnd
, WPARAM wStyleType
,
8929 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
8930 UINT uNewView
= lpss
->styleNew
& LVS_TYPEMASK
;
8931 UINT uOldView
= lpss
->styleOld
& LVS_TYPEMASK
;
8932 RECT rcList
= infoPtr
->rcList
;
8934 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
8935 hwnd
, wStyleType
, lpss
);
8937 if (wStyleType
== GWL_STYLE
)
8939 if (uOldView
== LVS_REPORT
)
8941 ShowWindow(infoPtr
->hwndHeader
, SW_HIDE
);
8944 if ((lpss
->styleOld
& WS_HSCROLL
) != 0)
8946 ShowScrollBar(hwnd
, SB_HORZ
, FALSE
);
8949 if ((lpss
->styleOld
& WS_VSCROLL
) != 0)
8951 ShowScrollBar(hwnd
, SB_VERT
, FALSE
);
8954 if (uNewView
== LVS_ICON
)
8956 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXICON
);
8957 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYICON
);
8958 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8959 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
8960 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
8962 LISTVIEW_AlignLeft(hwnd
);
8966 LISTVIEW_AlignTop(hwnd
);
8969 else if (uNewView
== LVS_REPORT
)
8976 Header_Layout(infoPtr
->hwndHeader
, &hl
);
8977 SetWindowPos(infoPtr
->hwndHeader
, hwnd
, wp
.x
, wp
.y
, wp
.cx
, wp
.cy
,
8979 if (!(LVS_NOCOLUMNHEADER
& lpss
->styleNew
))
8980 ShowWindow(infoPtr
->hwndHeader
, SW_SHOWNORMAL
);
8982 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
8983 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
8984 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8985 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
8987 else if (uNewView
== LVS_LIST
)
8989 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
8990 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
8991 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8992 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
8996 infoPtr
->iconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
8997 infoPtr
->iconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
8998 infoPtr
->nItemWidth
= LISTVIEW_GetItemWidth(hwnd
);
8999 infoPtr
->nItemHeight
= LISTVIEW_GetItemHeight(hwnd
);
9000 if (lpss
->styleNew
& LVS_ALIGNLEFT
)
9002 LISTVIEW_AlignLeft(hwnd
);
9006 LISTVIEW_AlignTop(hwnd
);
9010 /* update the size of the client area */
9011 LISTVIEW_UpdateSize(hwnd
);
9013 /* add scrollbars if needed */
9014 LISTVIEW_UpdateScroll(hwnd
);
9016 /* invalidate client area + erase background */
9017 InvalidateRect(hwnd
, NULL
, TRUE
);
9019 /* print the list of unsupported window styles */
9020 LISTVIEW_UnsupportedStyles(lpss
->styleNew
);
9023 /* If they change the view and we have an active edit control
9024 we will need to kill the control since the redraw will
9025 misplace the edit control.
9027 if (infoPtr
->hwndEdit
&&
9028 ((uNewView
& (LVS_ICON
|LVS_LIST
|LVS_SMALLICON
)) !=
9029 ((LVS_ICON
|LVS_LIST
|LVS_SMALLICON
) & uOldView
)))
9031 SendMessageA(infoPtr
->hwndEdit
, WM_KILLFOCUS
, 0, 0);
9039 * Window procedure of the listview control.
9042 static LRESULT WINAPI
LISTVIEW_WindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
,
9045 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd
, uMsg
, wParam
, lParam
);
9046 if (!GetWindowLongA(hwnd
, 0) && (uMsg
!= WM_NCCREATE
))
9047 return DefWindowProcA( hwnd
, uMsg
, wParam
, lParam
);
9050 case LVM_APPROXIMATEVIEWRECT
:
9051 return LISTVIEW_ApproximateViewRect(hwnd
, (INT
)wParam
,
9052 LOWORD(lParam
), HIWORD(lParam
));
9054 return LISTVIEW_Arrange(hwnd
, (INT
)wParam
);
9056 /* case LVM_CREATEDRAGIMAGE: */
9058 case LVM_DELETEALLITEMS
:
9059 return LISTVIEW_DeleteAllItems(hwnd
);
9061 case LVM_DELETECOLUMN
:
9062 return LISTVIEW_DeleteColumn(hwnd
, (INT
)wParam
);
9064 case LVM_DELETEITEM
:
9065 return LISTVIEW_DeleteItem(hwnd
, (INT
)wParam
);
9067 case LVM_EDITLABELW
:
9068 case LVM_EDITLABELA
:
9069 return LISTVIEW_EditLabelA(hwnd
, (INT
)wParam
);
9071 case LVM_ENSUREVISIBLE
:
9072 return LISTVIEW_EnsureVisible(hwnd
, (INT
)wParam
, (BOOL
)lParam
);
9075 return LISTVIEW_FindItem(hwnd
, (INT
)wParam
, (LPLVFINDINFO
)lParam
);
9077 case LVM_GETBKCOLOR
:
9078 return LISTVIEW_GetBkColor(hwnd
);
9080 /* case LVM_GETBKIMAGE: */
9082 case LVM_GETCALLBACKMASK
:
9083 return LISTVIEW_GetCallbackMask(hwnd
);
9085 case LVM_GETCOLUMNA
:
9086 return LISTVIEW_GetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
9088 /* case LVM_GETCOLUMNW: */
9090 case LVM_GETCOLUMNORDERARRAY
:
9091 return LISTVIEW_GetColumnOrderArray(hwnd
, (INT
)wParam
, (LPINT
)lParam
);
9093 case LVM_GETCOLUMNWIDTH
:
9094 return LISTVIEW_GetColumnWidth(hwnd
, (INT
)wParam
);
9096 case LVM_GETCOUNTPERPAGE
:
9097 return LISTVIEW_GetCountPerPage(hwnd
);
9099 case LVM_GETEDITCONTROL
:
9100 return LISTVIEW_GetEditControl(hwnd
);
9102 case LVM_GETEXTENDEDLISTVIEWSTYLE
:
9103 return LISTVIEW_GetExtendedListViewStyle(hwnd
);
9106 return LISTVIEW_GetHeader(hwnd
);
9108 /* case LVM_GETHOTCURSOR: */
9110 case LVM_GETHOTITEM
:
9111 return LISTVIEW_GetHotItem(hwnd
);
9113 case LVM_GETHOVERTIME
:
9114 return LISTVIEW_GetHoverTime(hwnd
);
9116 case LVM_GETIMAGELIST
:
9117 return LISTVIEW_GetImageList(hwnd
, (INT
)wParam
);
9119 /* case LVM_GETISEARCHSTRING: */
9122 return LISTVIEW_GetItemA(hwnd
, (LPLVITEMA
)lParam
, FALSE
);
9124 /* case LVM_GETITEMW: */
9126 case LVM_GETITEMCOUNT
:
9127 return LISTVIEW_GetItemCount(hwnd
);
9129 case LVM_GETITEMPOSITION
:
9130 return LISTVIEW_GetItemPosition(hwnd
, (INT
)wParam
, (LPPOINT
)lParam
);
9132 case LVM_GETITEMRECT
:
9133 return LISTVIEW_GetItemRect(hwnd
, (INT
)wParam
, (LPRECT
)lParam
);
9135 case LVM_GETITEMSPACING
:
9136 return LISTVIEW_GetItemSpacing(hwnd
, (BOOL
)wParam
);
9138 case LVM_GETITEMSTATE
:
9139 return LISTVIEW_GetItemState(hwnd
, (INT
)wParam
, (UINT
)lParam
);
9141 case LVM_GETITEMTEXTA
:
9142 LISTVIEW_GetItemTextA(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
9145 /* case LVM_GETITEMTEXTW: */
9147 case LVM_GETNEXTITEM
:
9148 return LISTVIEW_GetNextItem(hwnd
, (INT
)wParam
, LOWORD(lParam
));
9150 /* case LVM_GETNUMBEROFWORKAREAS: */
9153 return LISTVIEW_GetOrigin(hwnd
, (LPPOINT
)lParam
);
9155 case LVM_GETSELECTEDCOUNT
:
9156 return LISTVIEW_GetSelectedCount(hwnd
);
9158 case LVM_GETSELECTIONMARK
:
9159 return LISTVIEW_GetSelectionMark(hwnd
);
9161 case LVM_GETSTRINGWIDTHA
:
9162 return LISTVIEW_GetStringWidthA (hwnd
, (LPCSTR
)lParam
);
9164 /* case LVM_GETSTRINGWIDTHW: */
9165 /* case LVM_GETSUBITEMRECT: */
9167 case LVM_GETTEXTBKCOLOR
:
9168 return LISTVIEW_GetTextBkColor(hwnd
);
9170 case LVM_GETTEXTCOLOR
:
9171 return LISTVIEW_GetTextColor(hwnd
);
9173 /* case LVM_GETTOOLTIPS: */
9175 case LVM_GETTOPINDEX
:
9176 return LISTVIEW_GetTopIndex(hwnd
);
9178 /* case LVM_GETUNICODEFORMAT: */
9180 case LVM_GETVIEWRECT
:
9181 return LISTVIEW_GetViewRect(hwnd
, (LPRECT
)lParam
);
9183 /* case LVM_GETWORKAREAS: */
9186 return LISTVIEW_HitTest(hwnd
, (LPLVHITTESTINFO
)lParam
);
9188 case LVM_INSERTCOLUMNA
:
9189 return LISTVIEW_InsertColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
9191 case LVM_INSERTCOLUMNW
:
9192 return LISTVIEW_InsertColumnW(hwnd
, (INT
)wParam
, (LPLVCOLUMNW
)lParam
);
9194 case LVM_INSERTITEMA
:
9195 return LISTVIEW_InsertItemA(hwnd
, (LPLVITEMA
)lParam
);
9197 case LVM_INSERTITEMW
:
9198 return LISTVIEW_InsertItemW(hwnd
, (LPLVITEMW
)lParam
);
9200 case LVM_REDRAWITEMS
:
9201 return LISTVIEW_RedrawItems(hwnd
, (INT
)wParam
, (INT
)lParam
);
9203 /* case LVM_SCROLL: */
9204 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
9206 case LVM_SETBKCOLOR
:
9207 return LISTVIEW_SetBkColor(hwnd
, (COLORREF
)lParam
);
9209 /* case LVM_SETBKIMAGE: */
9211 case LVM_SETCALLBACKMASK
:
9212 return LISTVIEW_SetCallbackMask(hwnd
, (UINT
)wParam
);
9214 case LVM_SETCOLUMNA
:
9215 return LISTVIEW_SetColumnA(hwnd
, (INT
)wParam
, (LPLVCOLUMNA
)lParam
);
9217 case LVM_SETCOLUMNW
:
9218 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
9221 case LVM_SETCOLUMNORDERARRAY
:
9222 return LISTVIEW_SetColumnOrderArray(hwnd
, (INT
)wParam
, (LPINT
)lParam
);
9224 case LVM_SETCOLUMNWIDTH
:
9225 return LISTVIEW_SetColumnWidth(hwnd
, (INT
)wParam
, SLOWORD(lParam
));
9227 case LVM_SETEXTENDEDLISTVIEWSTYLE
:
9228 return LISTVIEW_SetExtendedListViewStyle(hwnd
, (DWORD
)wParam
, (DWORD
)lParam
);
9230 /* case LVM_SETHOTCURSOR: */
9232 case LVM_SETHOTITEM
:
9233 return LISTVIEW_SetHotItem(hwnd
, (INT
)wParam
);
9235 case LVM_SETHOVERTIME
:
9236 return LISTVIEW_SetHoverTime(hwnd
, (DWORD
)wParam
);
9238 /* case LVM_SETICONSPACING: */
9240 case LVM_SETIMAGELIST
:
9241 return LISTVIEW_SetImageList(hwnd
, (INT
)wParam
, (HIMAGELIST
)lParam
);
9244 return LISTVIEW_SetItemA(hwnd
, (LPLVITEMA
)lParam
);
9246 /* case LVM_SETITEMW: */
9248 case LVM_SETITEMCOUNT
:
9249 return LISTVIEW_SetItemCount(hwnd
, (INT
)wParam
, (DWORD
)lParam
);
9251 case LVM_SETITEMPOSITION
:
9252 return LISTVIEW_SetItemPosition(hwnd
, (INT
)wParam
, (INT
)LOWORD(lParam
),
9253 (INT
)HIWORD(lParam
));
9255 case LVM_SETITEMPOSITION32
:
9256 return LISTVIEW_SetItemPosition(hwnd
, (INT
)wParam
, ((POINT
*)lParam
)->x
,
9257 ((POINT
*)lParam
)->y
);
9259 case LVM_SETITEMSTATE
:
9260 return LISTVIEW_SetItemState(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
9262 case LVM_SETITEMTEXTA
:
9263 return LISTVIEW_SetItemTextA(hwnd
, (INT
)wParam
, (LPLVITEMA
)lParam
);
9265 /* case LVM_SETITEMTEXTW: */
9267 case LVM_SETSELECTIONMARK
:
9268 return LISTVIEW_SetSelectionMark(hwnd
, (INT
)lParam
);
9270 case LVM_SETTEXTBKCOLOR
:
9271 return LISTVIEW_SetTextBkColor(hwnd
, (COLORREF
)lParam
);
9273 case LVM_SETTEXTCOLOR
:
9274 return LISTVIEW_SetTextColor(hwnd
, (COLORREF
)lParam
);
9276 /* case LVM_SETTOOLTIPS: */
9277 /* case LVM_SETUNICODEFORMAT: */
9278 /* case LVM_SETWORKAREAS: */
9281 return LISTVIEW_SortItems(hwnd
, wParam
, lParam
);
9283 /* case LVM_SUBITEMHITTEST: */
9286 return LISTVIEW_Update(hwnd
, (INT
)wParam
);
9290 return LISTVIEW_ProcessLetterKeys( hwnd
, wParam
, lParam
);
9293 return LISTVIEW_Command(hwnd
, wParam
, lParam
);
9296 return LISTVIEW_Create(hwnd
, wParam
, lParam
);
9299 return LISTVIEW_EraseBackground(hwnd
, wParam
, lParam
);
9302 return DLGC_WANTCHARS
| DLGC_WANTARROWS
;
9305 return LISTVIEW_GetFont(hwnd
);
9308 return LISTVIEW_HScroll(hwnd
, (INT
)LOWORD(wParam
),
9309 (INT
)HIWORD(wParam
), (HWND
)lParam
);
9312 return LISTVIEW_KeyDown(hwnd
, (INT
)wParam
, (LONG
)lParam
);
9315 return LISTVIEW_KillFocus(hwnd
);
9317 case WM_LBUTTONDBLCLK
:
9318 return LISTVIEW_LButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9321 case WM_LBUTTONDOWN
:
9322 return LISTVIEW_LButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9325 return LISTVIEW_LButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9328 return LISTVIEW_MouseMove (hwnd
, wParam
, lParam
);
9331 return LISTVIEW_MouseHover(hwnd
, wParam
, lParam
);
9334 return LISTVIEW_NCCreate(hwnd
, wParam
, lParam
);
9337 return LISTVIEW_NCDestroy(hwnd
);
9340 return LISTVIEW_Notify(hwnd
, (INT
)wParam
, (LPNMHDR
)lParam
);
9342 case WM_NOTIFYFORMAT
:
9343 return LISTVIEW_NotifyFormat(hwnd
, (HWND
)wParam
, (INT
)lParam
);
9346 return LISTVIEW_Paint(hwnd
, (HDC
)wParam
);
9348 case WM_RBUTTONDBLCLK
:
9349 return LISTVIEW_RButtonDblClk(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9352 case WM_RBUTTONDOWN
:
9353 return LISTVIEW_RButtonDown(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9357 return LISTVIEW_RButtonUp(hwnd
, (WORD
)wParam
, LOWORD(lParam
),
9361 return LISTVIEW_SetFocus(hwnd
, (HWND
)wParam
);
9364 return LISTVIEW_SetFont(hwnd
, (HFONT
)wParam
, (WORD
)lParam
);
9367 return LISTVIEW_SetRedraw(hwnd
, (BOOL
)wParam
);
9370 return LISTVIEW_Size(hwnd
, (int)SLOWORD(lParam
), (int)SHIWORD(lParam
));
9372 case WM_STYLECHANGED
:
9373 return LISTVIEW_StyleChanged(hwnd
, wParam
, (LPSTYLESTRUCT
)lParam
);
9375 /* case WM_TIMER: */
9378 return LISTVIEW_VScroll(hwnd
, (INT
)LOWORD(wParam
),
9379 (INT
)HIWORD(wParam
), (HWND
)lParam
);
9382 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
9383 return DefWindowProcA( hwnd
, uMsg
, wParam
, lParam
);
9384 return LISTVIEW_MouseWheel(hwnd
, (short int)HIWORD(wParam
));/* case WM_WINDOWPOSCHANGED: */
9386 /* case WM_WININICHANGE: */
9389 if (uMsg
>= WM_USER
)
9391 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg
, wParam
,
9395 /* call default window procedure */
9396 return DefWindowProcA(hwnd
, uMsg
, wParam
, lParam
);
9404 * Registers the window class.
9412 VOID
LISTVIEW_Register(void)
9416 ZeroMemory(&wndClass
, sizeof(WNDCLASSA
));
9417 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
;
9418 wndClass
.lpfnWndProc
= (WNDPROC
)LISTVIEW_WindowProc
;
9419 wndClass
.cbClsExtra
= 0;
9420 wndClass
.cbWndExtra
= sizeof(LISTVIEW_INFO
*);
9421 wndClass
.hCursor
= LoadCursorA(0, IDC_ARROWA
);
9422 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
9423 wndClass
.lpszClassName
= WC_LISTVIEWA
;
9424 RegisterClassA(&wndClass
);
9429 * Unregisters the window class.
9437 VOID
LISTVIEW_Unregister(void)
9439 UnregisterClassA(WC_LISTVIEWA
, (HINSTANCE
)NULL
);
9444 * Handle any WM_COMMAND messages
9450 static LRESULT
LISTVIEW_Command(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
9452 switch (HIWORD(wParam
))
9457 * Adjust the edit window size
9460 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(hwnd
, 0);
9461 HDC hdc
= GetDC(infoPtr
->hwndEdit
);
9462 HFONT hFont
, hOldFont
= 0;
9467 len
= GetWindowTextA(infoPtr
->hwndEdit
, buffer
, 1023);
9468 GetWindowRect(infoPtr
->hwndEdit
, &rect
);
9470 /* Select font to get the right dimension of the string */
9471 hFont
= SendMessageA(infoPtr
->hwndEdit
, WM_GETFONT
, 0, 0);
9474 hOldFont
= SelectObject(hdc
, hFont
);
9477 if (GetTextExtentPoint32A(hdc
, buffer
, strlen(buffer
), &sz
))
9479 TEXTMETRICA textMetric
;
9481 /* Add Extra spacing for the next character */
9482 GetTextMetricsA(hdc
, &textMetric
);
9483 sz
.cx
+= (textMetric
.tmMaxCharWidth
* 2);
9491 rect
.bottom
- rect
.top
,
9492 SWP_DRAWFRAME
|SWP_NOMOVE
);
9496 SelectObject(hdc
, hOldFont
);
9499 ReleaseDC(hwnd
, hdc
);
9505 return SendMessageA (GetParent (hwnd
), WM_COMMAND
, wParam
, lParam
);
9514 * Subclassed edit control windproc function
9520 LRESULT CALLBACK
EditLblWndProc(HWND hwnd
, UINT uMsg
,
9521 WPARAM wParam
, LPARAM lParam
)
9523 BOOL cancel
= FALSE
;
9524 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(GetParent(hwnd
), 0);
9525 EDITLABEL_ITEM
*einfo
= infoPtr
->pedititem
;
9526 static BOOL bIgnoreKillFocus
= FALSE
;
9530 return DLGC_WANTARROWS
| DLGC_WANTALLKEYS
;
9533 if(bIgnoreKillFocus
)
9541 WNDPROC editProc
= einfo
->EditWndProc
;
9542 SetWindowLongA(hwnd
, GWL_WNDPROC
, (LONG
)editProc
);
9543 COMCTL32_Free(einfo
);
9544 infoPtr
->pedititem
= NULL
;
9545 return CallWindowProcA(editProc
, hwnd
, uMsg
, wParam
, lParam
);
9549 if (VK_ESCAPE
== (INT
)wParam
)
9555 else if (VK_RETURN
== (INT
)wParam
)
9559 return CallWindowProcA(einfo
->EditWndProc
, hwnd
,
9560 uMsg
, wParam
, lParam
);
9563 if (einfo
->EditLblCb
)
9565 char *buffer
= NULL
;
9570 int len
= 1 + GetWindowTextLengthA(hwnd
);
9574 if (NULL
!= (buffer
= (char *)COMCTL32_Alloc(len
*sizeof(char))))
9576 GetWindowTextA(hwnd
, buffer
, len
);
9580 /* Processing LVN_ENDLABELEDIT message could kill the focus */
9581 /* eg. Using a messagebox */
9582 bIgnoreKillFocus
= TRUE
;
9583 einfo
->EditLblCb(GetParent(hwnd
), buffer
, einfo
->param
);
9586 COMCTL32_Free(buffer
);
9588 einfo
->EditLblCb
= NULL
;
9589 bIgnoreKillFocus
= FALSE
;
9592 SendMessageA(hwnd
, WM_CLOSE
, 0, 0);
9599 * Creates a subclassed edit cotrol
9605 HWND
CreateEditLabel(LPCSTR text
, DWORD style
, INT x
, INT y
,
9606 INT width
, INT height
, HWND parent
, HINSTANCE hinst
,
9607 EditlblCallback EditLblCb
, DWORD param
)
9613 TEXTMETRICA textMetric
;
9614 LISTVIEW_INFO
*infoPtr
= (LISTVIEW_INFO
*)GetWindowLongA(parent
, 0);
9616 if (NULL
== (infoPtr
->pedititem
= COMCTL32_Alloc(sizeof(EDITLABEL_ITEM
))))
9619 style
|= WS_CHILDWINDOW
|WS_CLIPSIBLINGS
|ES_LEFT
|WS_BORDER
;
9620 hdc
= GetDC(parent
);
9622 /* Select the font to get appropriate metric dimensions */
9623 if(infoPtr
->hFont
!= 0)
9625 hOldFont
= SelectObject(hdc
, infoPtr
->hFont
);
9628 /*Get String Lenght in pixels */
9629 GetTextExtentPoint32A(hdc
, text
, strlen(text
), &sz
);
9631 /*Add Extra spacing for the next character */
9632 GetTextMetricsA(hdc
, &textMetric
);
9633 sz
.cx
+= (textMetric
.tmMaxCharWidth
* 2);
9635 if(infoPtr
->hFont
!= 0)
9637 SelectObject(hdc
, hOldFont
);
9640 ReleaseDC(parent
, hdc
);
9641 if (!(hedit
= CreateWindowA("Edit", text
, style
, x
, y
, sz
.cx
, height
,
9642 parent
, 0, hinst
, 0)))
9644 COMCTL32_Free(infoPtr
->pedititem
);
9648 infoPtr
->pedititem
->param
= param
;
9649 infoPtr
->pedititem
->EditLblCb
= EditLblCb
;
9650 infoPtr
->pedititem
->EditWndProc
= (WNDPROC
)SetWindowLongA(hedit
,
9651 GWL_WNDPROC
, (LONG
) EditLblWndProc
);
9653 SendMessageA(hedit
, WM_SETFONT
, infoPtr
->hFont
, FALSE
);