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
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_GetColumnOrderArray : simple hack only
35 * LISTVIEW_SetColumnOrderArray : simple hack only
36 * LISTVIEW_Arrange : empty stub
37 * LISTVIEW_ApproximateViewRect : incomplete
38 * LISTVIEW_Scroll : not implemented
39 * LISTVIEW_RedrawItems : empty stub
40 * LISTVIEW_Update : not completed
50 #include "debugtools.h"
52 DEFAULT_DEBUG_CHANNEL(listview);
58 /* maximum size of a label */
59 #define DISP_TEXT_SIZE 512
61 /* padding for items in list and small icon display modes */
62 #define WIDTH_PADDING 12
64 /* padding for items in list, report and small icon display modes */
65 #define HEIGHT_PADDING 1
67 /* offset of items in report display mode */
68 #define REPORT_MARGINX 2
70 /* padding for icon in large icon display mode */
71 #define ICON_TOP_PADDING 2
72 #define ICON_BOTTOM_PADDING 2
74 /* padding for label in large icon display mode */
75 #define LABEL_VERT_OFFSET 2
77 /* default label width for items in list and small icon display modes */
78 #define DEFAULT_LABEL_WIDTH 40
80 /* default column width for items in list display mode */
81 #define DEFAULT_COLUMN_WIDTH 96
83 /* Increment size of the horizontal scroll bar */
84 #define LISTVIEW_SCROLL_DIV_SIZE 10
89 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
90 #define ListView_LVNotify(hwnd,lCtrlId,plvnm) \
91 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMLISTVIEW)(plvnm))
92 #define ListView_Notify(hwnd,lCtrlId,pnmh) \
93 (BOOL)SendMessageA((hwnd),WM_NOTIFY,(WPARAM)(INT)lCtrlId,(LPARAM)(LPNMHDR)(pnmh))
94 /* retrieve the number of items in the listview */
95 #define GETITEMCOUNT(infoPtr) ((infoPtr)->hdpaItems->nItemCount)
97 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
98 INT width, INT height, HWND parent, HINSTANCE hinst,
99 EditlblCallback EditLblCb, DWORD param);
102 * forward declarations
104 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal);
105 static INT LISTVIEW_HitTestItem(HWND, LPLVHITTESTINFO);
106 static INT LISTVIEW_GetCountPerRow(HWND);
107 static INT LISTVIEW_GetCountPerColumn(HWND);
108 static VOID LISTVIEW_AlignLeft(HWND);
109 static VOID LISTVIEW_AlignTop(HWND);
110 static VOID LISTVIEW_AddGroupSelection(HWND, INT);
111 static VOID LISTVIEW_AddSelection(HWND, INT);
112 static BOOL LISTVIEW_AddSubItem(HWND, LPLVITEMA);
113 static INT LISTVIEW_FindInsertPosition(HDPA, INT);
114 static INT LISTVIEW_GetItemHeight(HWND);
115 static BOOL LISTVIEW_GetItemPosition(HWND, INT, LPPOINT);
116 static LRESULT LISTVIEW_GetItemRect(HWND, INT, LPRECT);
117 static INT LISTVIEW_GetItemWidth(HWND);
118 static INT LISTVIEW_GetLabelWidth(HWND, INT);
119 static LRESULT LISTVIEW_GetOrigin(HWND, LPPOINT);
120 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem);
121 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA, INT);
122 static LRESULT LISTVIEW_GetViewRect(HWND, LPRECT);
123 static BOOL LISTVIEW_InitItem(HWND, LISTVIEW_ITEM *, LPLVITEMA);
124 static BOOL LISTVIEW_InitSubItem(HWND, LISTVIEW_SUBITEM *, LPLVITEMA);
125 static LRESULT LISTVIEW_MouseSelection(HWND, POINT);
126 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
127 static VOID LISTVIEW_RemoveSelections(HWND, INT, INT);
128 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
129 static VOID LISTVIEW_SetGroupSelection(HWND, INT);
130 static BOOL LISTVIEW_SetItem(HWND, LPLVITEMA);
131 static BOOL LISTVIEW_SetItemFocus(HWND, INT);
132 static BOOL LISTVIEW_SetItemPosition(HWND, INT, INT, INT);
133 static VOID LISTVIEW_UpdateScroll(HWND);
134 static VOID LISTVIEW_SetSelection(HWND, INT);
135 static VOID LISTVIEW_UpdateSize(HWND);
136 static BOOL LISTVIEW_SetSubItem(HWND, LPLVITEMA);
137 static LRESULT LISTVIEW_SetViewRect(HWND, LPRECT);
138 static BOOL LISTVIEW_ToggleSelection(HWND, INT);
139 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle);
140 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem);
141 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem);
142 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam);
143 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam);
144 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText);
145 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData );
146 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem);
149 /******** Defines that LISTVIEW_ProcessLetterKeys uses ****************/
150 #define KEY_DELAY 900
151 #define LISTVIEW_InitLvItemStruct(item,idx,TEXT) \
152 ZeroMemory(&(item), sizeof(LVITEMA)); \
153 (item).mask = LVIF_TEXT; \
154 (item).iItem = (idx); \
155 (item).iSubItem = 0; \
156 (item).pszText = (TEXT); \
157 (item).cchTextMax = MAX_PATH
159 /*************************************************************************
161 * Processes keyboard messages generated by pressing the letter keys on the keyboard.
162 * Assumes the list is sorted alphabetically, without regard to case.
165 * [I] HWND: handle to the window
166 * [I] WPARAM: the character code, the actual character
167 * [I] LPARAM: key data
177 static INT LISTVIEW_ProcessLetterKeys( HWND hwnd, WPARAM charCode, LPARAM keyData )
179 LISTVIEW_INFO *infoPtr = NULL;
184 BOOL bFoundMatchingFiles = FALSE;
186 CHAR TEXT[ MAX_PATH ];
187 CHAR szCharCode[ 2 ];
188 DWORD timeSinceLastKeyPress = 0;
190 szCharCode[0] = charCode;
193 /* simple parameter checking */
194 if ( !hwnd || !charCode || !keyData )
197 infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
202 /* only allow the valid WM_CHARs through */
203 if ( isalnum( charCode ) || charCode == '.' || charCode == '`' || charCode == '!'
204 || charCode == '@' || charCode == '#' || charCode == '$' || charCode == '%'
205 || charCode == '^' || charCode == '&' || charCode == '*' || charCode == '('
206 || charCode == ')' || charCode == '-' || charCode == '_' || charCode == '+'
207 || charCode == '=' || charCode == '\\'|| charCode == ']' || charCode == '}'
208 || charCode == '[' || charCode == '{' || charCode == '/' || charCode == '?'
209 || charCode == '>' || charCode == '<' || charCode == ',' || charCode == '~')
211 timeSinceLastKeyPress = GetTickCount();
213 nSize = GETITEMCOUNT( infoPtr );
214 /* if there are 0 items, there is no where to go */
218 * If the last charCode equals the current charCode then look
219 * to the next element in list to see if it matches the previous
222 if ( infoPtr->charCode == charCode )
224 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress < KEY_DELAY )
225 { /* append new character to search string */
226 strcat( infoPtr->szSearchParam, szCharCode );
227 infoPtr->nSearchParamLength++;
229 /* loop from start of list view */
230 for( idx = infoPtr->nFocusedItem; idx < nSize; idx++ )
232 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
233 ListView_GetItemA( hwnd, &item );
236 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
237 infoPtr->nSearchParamLength ) == 0 )
244 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
245 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
246 for ( idx = 0; idx < nSize; idx++ )
248 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
249 ListView_GetItemA( hwnd, &item );
251 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
257 strcpy( infoPtr->szSearchParam, szCharCode );
258 infoPtr->nSearchParamLength = 1;
261 { /* Save szCharCode for use in later searches */
262 strcpy( infoPtr->szSearchParam, szCharCode );
263 infoPtr->nSearchParamLength = 1;
265 LISTVIEW_InitLvItemStruct( item, infoPtr->nFocusedItem + 1, TEXT );
266 ListView_GetItemA( hwnd, &item );
268 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
269 nItem = infoPtr->nFocusedItem + 1;
272 * Ok so there are no more folders that match
273 * now we look for files.
275 for ( idx = infoPtr->nFocusedItem + 1; idx < nSize; idx ++ )
277 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
278 ListView_GetItemA( hwnd, &item );
280 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
283 bFoundMatchingFiles = TRUE;
287 if ( !bFoundMatchingFiles )
288 { /* go back to first instance */
289 for ( idx = 0; idx < nSize; idx ++ )
291 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
292 ListView_GetItemA( hwnd, &item );
294 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
303 } /*END: if ( infoPtr->charCode == charCode )*/
305 else /* different keypressed */
307 /* could be that they are spelling the file/directory for us */
308 if ( timeSinceLastKeyPress - infoPtr->timeSinceLastKeyPress > KEY_DELAY )
310 * Too slow, move to the first instance of the
313 for ( idx = 0; idx < nSize; idx++ )
315 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
316 ListView_GetItemA( hwnd, &item );
318 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
324 strcpy( infoPtr->szSearchParam, szCharCode );
325 infoPtr->nSearchParamLength = 1;
327 else if ( infoPtr->timeSinceLastKeyPress > timeSinceLastKeyPress )
328 { /* The DWORD went over it's boundery?? Ergo assuming too slow??. */
329 for ( idx = 0; idx < nSize; idx++ )
331 LISTVIEW_InitLvItemStruct( item,idx, TEXT );
332 ListView_GetItemA( hwnd, &item );
334 if ( strncasecmp( &( item.pszText[ 0 ] ), szCharCode, 1 ) == 0 )
340 strcpy( infoPtr->szSearchParam, szCharCode );
341 infoPtr->nSearchParamLength = 1;
343 else /* Search for the string the user is typing */
345 /* append new character to search string */
346 strcat( infoPtr->szSearchParam, szCharCode );
347 infoPtr->nSearchParamLength++;
349 /* loop from start of list view */
350 for( idx = 0; idx < nSize; idx++ )
352 LISTVIEW_InitLvItemStruct( item, idx, TEXT );
353 ListView_GetItemA( hwnd, &item );
356 if ( strncasecmp( item.pszText, infoPtr->szSearchParam,
357 infoPtr->nSearchParamLength ) == 0 )
369 bRedraw = LISTVIEW_KeySelection(hwnd, nItem );
370 if (bRedraw != FALSE)
372 /* refresh client area */
373 InvalidateRect(hwnd, NULL, TRUE);
377 /* Store the WM_CHAR for next time */
378 infoPtr->charCode = charCode;
381 infoPtr->timeSinceLastKeyPress = timeSinceLastKeyPress;
387 /*************************************************************************
388 * LISTVIEW_UpdateHeaderSize [Internal]
390 * Function to resize the header control
393 * hwnd [I] handle to a window
394 * nNewScrollPos [I] Scroll Pos to Set
401 static VOID LISTVIEW_UpdateHeaderSize(HWND hwnd, INT nNewScrollPos)
403 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
407 GetWindowRect(infoPtr->hwndHeader, &winRect);
408 point[0].x = winRect.left;
409 point[0].y = winRect.top;
410 point[1].x = winRect.right;
411 point[1].y = winRect.bottom;
413 MapWindowPoints(HWND_DESKTOP, hwnd, point, 2);
414 point[0].x = -(nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
415 point[1].x += (nNewScrollPos * LISTVIEW_SCROLL_DIV_SIZE);
417 SetWindowPos(infoPtr->hwndHeader,0,
418 point[0].x,point[0].y,point[1].x,point[1].y,
419 SWP_NOZORDER | SWP_NOACTIVATE);
424 * Update the scrollbars. This functions should be called whenever
425 * the content, size or view changes.
428 * [I] HWND : window handle
433 static VOID LISTVIEW_UpdateScroll(HWND hwnd)
435 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
436 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
437 UINT uView = lStyle & LVS_TYPEMASK;
438 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
439 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
440 SCROLLINFO scrollInfo;
442 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
443 scrollInfo.cbSize = sizeof(SCROLLINFO);
445 if (uView == LVS_LIST)
447 /* update horizontal scrollbar */
449 INT nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
450 INT nCountPerRow = LISTVIEW_GetCountPerRow(hwnd);
451 INT nNumOfItems = GETITEMCOUNT(infoPtr);
453 scrollInfo.nMax = nNumOfItems / nCountPerColumn;
454 if((nNumOfItems % nCountPerColumn) == 0)
458 scrollInfo.nPos = ListView_GetTopIndex(hwnd) / nCountPerColumn;
459 scrollInfo.nPage = nCountPerRow;
460 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
461 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
463 else if (uView == LVS_REPORT)
465 /* update vertical scrollbar */
467 scrollInfo.nMax = GETITEMCOUNT(infoPtr) - 1;
468 scrollInfo.nPos = ListView_GetTopIndex(hwnd);
469 scrollInfo.nPage = LISTVIEW_GetCountPerColumn(hwnd);
470 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
471 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
473 /* update horizontal scrollbar */
474 nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
475 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
476 || GETITEMCOUNT(infoPtr) == 0)
481 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE ;
482 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
483 scrollInfo.nMax = max(infoPtr->nItemWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
484 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
486 /* Update the Header Control */
487 scrollInfo.fMask = SIF_POS;
488 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
489 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
496 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
498 INT nViewWidth = rcView.right - rcView.left;
499 INT nViewHeight = rcView.bottom - rcView.top;
501 /* Update Horizontal Scrollbar */
502 scrollInfo.fMask = SIF_POS;
503 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) == FALSE
504 || GETITEMCOUNT(infoPtr) == 0)
508 scrollInfo.nMax = max(nViewWidth / LISTVIEW_SCROLL_DIV_SIZE, 0)-1;
510 scrollInfo.nPage = nListWidth / LISTVIEW_SCROLL_DIV_SIZE;
511 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
512 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
514 /* Update Vertical Scrollbar */
515 nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
516 scrollInfo.fMask = SIF_POS;
517 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) == FALSE
518 || GETITEMCOUNT(infoPtr) == 0)
522 scrollInfo.nMax = max(nViewHeight / LISTVIEW_SCROLL_DIV_SIZE,0)-1;
524 scrollInfo.nPage = nListHeight / LISTVIEW_SCROLL_DIV_SIZE;
525 scrollInfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
526 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
533 * Prints a message for unsupported window styles.
534 * A kind of TODO list for window styles.
537 * [I] LONG : window style
542 static VOID LISTVIEW_UnsupportedStyles(LONG lStyle)
544 if ((LVS_TYPEMASK & lStyle) == LVS_EDITLABELS)
546 FIXME(" LVS_EDITLABELS\n");
549 if ((LVS_TYPEMASK & lStyle) == LVS_NOLABELWRAP)
551 FIXME(" LVS_NOLABELWRAP\n");
554 if ((LVS_TYPEMASK & lStyle) == LVS_NOSCROLL)
556 FIXME(" LVS_NOSCROLL\n");
559 if ((LVS_TYPEMASK & lStyle) == LVS_NOSORTHEADER)
561 FIXME(" LVS_NOSORTHEADER\n");
564 if ((LVS_TYPEMASK & lStyle) == LVS_OWNERDRAWFIXED)
566 FIXME(" LVS_OWNERDRAWFIXED\n");
569 if ((LVS_TYPEMASK & lStyle) == LVS_SHAREIMAGELISTS)
571 FIXME(" LVS_SHAREIMAGELISTS\n");
574 if ((LVS_TYPEMASK & lStyle) == LVS_SORTASCENDING)
576 FIXME(" LVS_SORTASCENDING\n");
579 if ((LVS_TYPEMASK & lStyle) == LVS_SORTDESCENDING)
581 FIXME(" LVS_SORTDESCENDING\n");
587 * Aligns the items with the top edge of the window.
590 * [I] HWND : window handle
595 static VOID LISTVIEW_AlignTop(HWND hwnd)
597 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
598 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
599 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
604 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
606 ZeroMemory(&ptItem, sizeof(POINT));
607 ZeroMemory(&rcView, sizeof(RECT));
609 if (nListWidth > infoPtr->nItemWidth)
611 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
613 if (ptItem.x + infoPtr->nItemWidth > nListWidth)
616 ptItem.y += infoPtr->nItemHeight;
619 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
620 ptItem.x += infoPtr->nItemWidth;
621 rcView.right = max(rcView.right, ptItem.x);
624 rcView.bottom = ptItem.y + infoPtr->nItemHeight;
628 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
630 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
631 ptItem.y += infoPtr->nItemHeight;
634 rcView.right = infoPtr->nItemWidth;
635 rcView.bottom = ptItem.y;
638 LISTVIEW_SetViewRect(hwnd, &rcView);
644 * Aligns the items with the left edge of the window.
647 * [I] HWND : window handle
652 static VOID LISTVIEW_AlignLeft(HWND hwnd)
654 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
655 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
656 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
661 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
663 ZeroMemory(&ptItem, sizeof(POINT));
664 ZeroMemory(&rcView, sizeof(RECT));
666 if (nListHeight > infoPtr->nItemHeight)
668 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
670 if (ptItem.y + infoPtr->nItemHeight > nListHeight)
673 ptItem.x += infoPtr->nItemWidth;
676 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
677 ptItem.y += infoPtr->nItemHeight;
678 rcView.bottom = max(rcView.bottom, ptItem.y);
681 rcView.right = ptItem.x + infoPtr->nItemWidth;
685 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
687 ListView_SetItemPosition(hwnd, i, ptItem.x, ptItem.y);
688 ptItem.x += infoPtr->nItemWidth;
691 rcView.bottom = infoPtr->nItemHeight;
692 rcView.right = ptItem.x;
695 LISTVIEW_SetViewRect(hwnd, &rcView);
701 * Set the bounding rectangle of all the items.
704 * [I] HWND : window handle
705 * [I] LPRECT : bounding rectangle
711 static LRESULT LISTVIEW_SetViewRect(HWND hwnd, LPRECT lprcView)
713 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
714 BOOL bResult = FALSE;
716 TRACE("(hwnd=%x, left=%d, top=%d, right=%d, bottom=%d)\n", hwnd,
717 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
719 if (lprcView != NULL)
722 infoPtr->rcView.left = lprcView->left;
723 infoPtr->rcView.top = lprcView->top;
724 infoPtr->rcView.right = lprcView->right;
725 infoPtr->rcView.bottom = lprcView->bottom;
733 * Retrieves the bounding rectangle of all the items.
736 * [I] HWND : window handle
737 * [O] LPRECT : bounding rectangle
743 static LRESULT LISTVIEW_GetViewRect(HWND hwnd, LPRECT lprcView)
745 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
746 BOOL bResult = FALSE;
749 TRACE("(hwnd=%x, lprcView=%p)\n", hwnd, lprcView);
751 if (lprcView != NULL)
753 bResult = LISTVIEW_GetOrigin(hwnd, &ptOrigin);
754 if (bResult != FALSE)
756 lprcView->left = infoPtr->rcView.left + ptOrigin.x;
757 lprcView->top = infoPtr->rcView.top + ptOrigin.y;
758 lprcView->right = infoPtr->rcView.right + ptOrigin.x;
759 lprcView->bottom = infoPtr->rcView.bottom + ptOrigin.y;
762 TRACE("(left=%d, top=%d, right=%d, bottom=%d)\n",
763 lprcView->left, lprcView->top, lprcView->right, lprcView->bottom);
771 * Retrieves the subitem pointer associated with the subitem index.
774 * [I] HDPA : DPA handle for a specific item
775 * [I] INT : index of subitem
778 * SUCCESS : subitem pointer
781 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems,
784 LISTVIEW_SUBITEM *lpSubItem;
787 for (i = 1; i < hdpaSubItems->nItemCount; i++)
789 lpSubItem = (LISTVIEW_SUBITEM *) DPA_GetPtr(hdpaSubItems, i);
790 if (lpSubItem != NULL)
792 if (lpSubItem->iSubItem == nSubItem)
804 * Calculates the width of an item.
807 * [I] HWND : window handle
808 * [I] LONG : window style
811 * Returns item width.
813 static INT LISTVIEW_GetItemWidth(HWND hwnd)
815 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
816 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
817 UINT uView = style & LVS_TYPEMASK;
818 INT nHeaderItemCount;
824 TRACE("(hwnd=%x)\n", hwnd);
826 if (uView == LVS_ICON)
828 nItemWidth = infoPtr->iconSpacing.cx;
830 else if (uView == LVS_REPORT && (!(LVS_NOCOLUMNHEADER & style)) )
832 /* calculate width of header */
833 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
834 for (i = 0; i < nHeaderItemCount; i++)
836 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
838 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
844 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
846 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, i);
847 nItemWidth = max(nItemWidth, nLabelWidth);
850 /* default label size */
851 if (GETITEMCOUNT(infoPtr) == 0)
853 nItemWidth = DEFAULT_COLUMN_WIDTH;
859 nItemWidth = DEFAULT_LABEL_WIDTH;
864 nItemWidth += WIDTH_PADDING;
866 if (infoPtr->himlSmall != NULL)
868 nItemWidth += infoPtr->iconSize.cx;
871 if (infoPtr->himlState != NULL)
873 nItemWidth += infoPtr->iconSize.cx;
880 /* nItemWidth Cannot be Zero */
888 * Calculates the width of a specific item.
891 * [I] HWND : window handle
895 * Returns the width of an item width a specified string.
897 static INT LISTVIEW_CalculateWidth(HWND hwnd, INT nItem)
899 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
900 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
901 INT nHeaderItemCount;
906 TRACE("(hwnd=%x)\n", hwnd);
908 if (uView == LVS_ICON)
910 nItemWidth = infoPtr->iconSpacing.cx;
912 else if (uView == LVS_REPORT)
914 /* calculate width of header */
915 nHeaderItemCount = Header_GetItemCount(infoPtr->hwndHeader);
916 for (i = 0; i < nHeaderItemCount; i++)
918 if (Header_GetItemRect(infoPtr->hwndHeader, i, &rcHeaderItem) != 0)
920 nItemWidth += (rcHeaderItem.right - rcHeaderItem.left);
926 /* get width of string */
927 nItemWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
929 /* default label size */
930 if (GETITEMCOUNT(infoPtr) == 0)
932 nItemWidth = DEFAULT_COLUMN_WIDTH;
938 nItemWidth = DEFAULT_LABEL_WIDTH;
943 nItemWidth += WIDTH_PADDING;
945 if (infoPtr->himlSmall != NULL)
947 nItemWidth += infoPtr->iconSize.cx;
950 if (infoPtr->himlState != NULL)
952 nItemWidth += infoPtr->iconSize.cx;
963 * Calculates the height of an item.
966 * [I] HWND : window handle
967 * [I] LONG : window style
970 * Returns item height.
972 static INT LISTVIEW_GetItemHeight(HWND hwnd)
974 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
975 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
978 if (uView == LVS_ICON)
980 nItemHeight = infoPtr->iconSpacing.cy;
985 HDC hdc = GetDC(hwnd);
986 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont);
987 GetTextMetricsA(hdc, &tm);
989 if(infoPtr->himlState || infoPtr->himlSmall)
990 nItemHeight = max(tm.tmHeight, infoPtr->iconSize.cy) + HEIGHT_PADDING;
992 nItemHeight = tm.tmHeight;
994 SelectObject(hdc, hOldFont);
995 ReleaseDC(hwnd, hdc);
1003 * Adds a block of selections.
1006 * [I] HWND : window handle
1007 * [I] INT : item index
1012 static VOID LISTVIEW_AddGroupSelection(HWND hwnd, INT nItem)
1014 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1015 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1016 INT nLast = max(infoPtr->nSelectionMark, nItem);
1020 lvItem.state = LVIS_SELECTED;
1021 lvItem.stateMask= LVIS_SELECTED;
1023 for (i = nFirst; i <= nLast; i++)
1025 ListView_SetItemState(hwnd, i, &lvItem);
1028 LISTVIEW_SetItemFocus(hwnd, nItem);
1029 infoPtr->nSelectionMark = nItem;
1034 * Adds a single selection.
1037 * [I] HWND : window handle
1038 * [I] INT : item index
1043 static VOID LISTVIEW_AddSelection(HWND hwnd, INT nItem)
1045 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1048 lvItem.state = LVIS_SELECTED;
1049 lvItem.stateMask= LVIS_SELECTED;
1051 ListView_SetItemState(hwnd, nItem, &lvItem);
1053 LISTVIEW_SetItemFocus(hwnd, nItem);
1054 infoPtr->nSelectionMark = nItem;
1059 * Selects or unselects an item.
1062 * [I] HWND : window handle
1063 * [I] INT : item index
1069 static BOOL LISTVIEW_ToggleSelection(HWND hwnd, INT nItem)
1071 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1075 lvItem.stateMask= LVIS_SELECTED;
1077 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
1080 ListView_SetItemState(hwnd, nItem, &lvItem);
1085 lvItem.state = LVIS_SELECTED;
1086 ListView_SetItemState(hwnd, nItem, &lvItem);
1090 LISTVIEW_SetItemFocus(hwnd, nItem);
1091 infoPtr->nSelectionMark = nItem;
1098 * Selects items based on view coorddiantes.
1101 * [I] HWND : window handle
1102 * [I] RECT : selection rectangle
1107 static VOID LISTVIEW_SetSelectionRect(HWND hwnd, RECT rcSelRect)
1109 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1114 lvItem.stateMask = LVIS_SELECTED;
1116 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1118 LISTVIEW_GetItemPosition(hwnd, i, &ptItem);
1119 if (PtInRect(&rcSelRect, ptItem) != FALSE)
1121 lvItem.state = LVIS_SELECTED;
1128 ListView_SetItemState(hwnd, i, &lvItem);
1134 * Sets a single group selection.
1137 * [I] HWND : window handle
1138 * [I] INT : item index
1143 static VOID LISTVIEW_SetGroupSelection(HWND hwnd, INT nItem)
1145 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1146 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
1149 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
1152 INT nFirst = min(infoPtr->nSelectionMark, nItem);
1153 INT nLast = max(infoPtr->nSelectionMark, nItem);
1154 lvItem.stateMask = LVIS_SELECTED;
1156 for (i = 0; i <= GETITEMCOUNT(infoPtr); i++)
1158 if ((i < nFirst) || (i > nLast))
1164 lvItem.state = LVIS_SELECTED;
1167 ListView_SetItemState(hwnd, i, &lvItem);
1175 LISTVIEW_GetItemPosition(hwnd, nItem, &ptItem);
1176 LISTVIEW_GetItemPosition(hwnd, infoPtr->nSelectionMark, &ptSelMark);
1177 rcSel.left = min(ptSelMark.x, ptItem.x);
1178 rcSel.top = min(ptSelMark.y, ptItem.y);
1179 rcSel.right = max(ptSelMark.x, ptItem.x) + infoPtr->nItemWidth;
1180 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
1181 LISTVIEW_SetSelectionRect(hwnd, rcSel);
1184 LISTVIEW_SetItemFocus(hwnd, nItem);
1189 * Manages the item focus.
1192 * [I] HWND : window handle
1193 * [I] INT : item index
1196 * TRUE : focused item changed
1197 * FALSE : focused item has NOT changed
1199 static BOOL LISTVIEW_SetItemFocus(HWND hwnd, INT nItem)
1201 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1202 BOOL bResult = FALSE;
1205 if (infoPtr->nFocusedItem != nItem)
1208 ZeroMemory(&lvItem, sizeof(LVITEMA));
1209 lvItem.stateMask = LVIS_FOCUSED;
1210 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1212 lvItem.state = LVIS_FOCUSED;
1213 lvItem.stateMask = LVIS_FOCUSED;
1214 ListView_SetItemState(hwnd, nItem, &lvItem);
1216 infoPtr->nFocusedItem = nItem;
1217 ListView_EnsureVisible(hwnd, nItem, FALSE);
1225 * Sets a single selection.
1228 * [I] HWND : window handle
1229 * [I] INT : item index
1234 static VOID LISTVIEW_SetSelection(HWND hwnd, INT nItem)
1236 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1241 LISTVIEW_RemoveSelections(hwnd, 0, nItem - 1);
1244 if (nItem < GETITEMCOUNT(infoPtr))
1246 LISTVIEW_RemoveSelections(hwnd, nItem + 1, GETITEMCOUNT(infoPtr));
1249 ZeroMemory(&lvItem, sizeof(LVITEMA));
1250 lvItem.stateMask = LVIS_FOCUSED;
1251 ListView_SetItemState(hwnd, infoPtr->nFocusedItem, &lvItem);
1253 lvItem.state = LVIS_SELECTED | LVIS_FOCUSED;
1254 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
1255 ListView_SetItemState(hwnd, nItem, &lvItem);
1257 infoPtr->nFocusedItem = nItem;
1258 infoPtr->nSelectionMark = nItem;
1263 * Set selection(s) with keyboard.
1266 * [I] HWND : window handle
1267 * [I] INT : item index
1270 * SUCCESS : TRUE (needs to be repainted)
1271 * FAILURE : FALSE (nothing has changed)
1273 static BOOL LISTVIEW_KeySelection(HWND hwnd, INT nItem)
1275 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1276 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1277 WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
1278 WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
1279 BOOL bResult = FALSE;
1281 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
1283 if (lStyle & LVS_SINGLESEL)
1286 LISTVIEW_SetSelection(hwnd, nItem);
1287 ListView_EnsureVisible(hwnd, nItem, FALSE);
1294 LISTVIEW_SetGroupSelection(hwnd, nItem);
1298 bResult = LISTVIEW_SetItemFocus(hwnd, nItem);
1303 LISTVIEW_SetSelection(hwnd, nItem);
1304 ListView_EnsureVisible(hwnd, nItem, FALSE);
1314 * Called when the mouse is being actively tracked and has hovered for a specified
1318 * [I] HWND : window handle
1319 * [I] wParam : key indicator
1320 * [I] lParam : mouse position
1323 * 0 if the message was processed, non-zero if there was an error
1326 * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains
1327 * over the item for a certain period of time.
1330 static LRESULT LISTVIEW_MouseHover(hwnd, wParam, lParam)
1332 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1335 pt.x = (INT)LOWORD(lParam);
1336 pt.y = (INT)HIWORD(lParam);
1338 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1339 /* select the item under the cursor */
1340 LISTVIEW_MouseSelection(hwnd, pt);
1348 * Called whenever WM_MOUSEMOVE is recieved.
1351 * [I] HWND : window handle
1352 * [I] wParam : key indicators
1353 * [I] lParam : cursor position
1356 * 0 if the message is processed, non-zero if there was an error
1358 static LRESULT LISTVIEW_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1360 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1361 TRACKMOUSEEVENT trackinfo;
1363 /* see if we are supposed to be tracking mouse hovering */
1364 if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
1365 /* fill in the trackinfo struct */
1366 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1367 trackinfo.dwFlags = TME_QUERY;
1368 trackinfo.hwndTrack = hwnd;
1369 trackinfo.dwHoverTime = infoPtr->dwHoverTime;
1371 /* see if we are already tracking this hwnd */
1372 _TrackMouseEvent(&trackinfo);
1374 if(!(trackinfo.dwFlags & TME_HOVER)) {
1375 trackinfo.dwFlags = TME_HOVER;
1377 /* call TRACKMOUSEEVENT so we recieve WM_MOUSEHOVER messages */
1378 _TrackMouseEvent(&trackinfo);
1387 * Selects an item based on coordinates.
1390 * [I] HWND : window handle
1391 * [I] POINT : mouse click ccordinates
1394 * SUCCESS : item index
1397 static LRESULT LISTVIEW_MouseSelection(HWND hwnd, POINT pt)
1399 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1403 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
1405 rcItem.left = LVIR_SELECTBOUNDS;
1406 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) == TRUE)
1408 if (PtInRect(&rcItem, pt) != FALSE)
1420 * Removes all selection states.
1423 * [I] HWND : window handle
1424 * [I] INT : item index
1430 static VOID LISTVIEW_RemoveSelections(HWND hwnd, INT nFirst, INT nLast)
1436 lvItem.stateMask = LVIS_SELECTED;
1438 for (i = nFirst; i <= nLast; i++)
1440 ListView_SetItemState(hwnd, i, &lvItem);
1449 * [IO] HDPA : dynamic pointer array handle
1450 * [I] INT : column index (subitem index)
1456 static BOOL LISTVIEW_RemoveColumn(HDPA hdpaItems, INT nSubItem)
1458 BOOL bResult = TRUE;
1462 for (i = 0; i < hdpaItems->nItemCount; i++)
1464 hdpaSubItems = (HDPA)DPA_GetPtr(hdpaItems, i);
1465 if (hdpaSubItems != NULL)
1467 if (LISTVIEW_RemoveSubItem(hdpaSubItems, nSubItem) == FALSE)
1479 * Removes a subitem at a given position.
1482 * [IO] HDPA : dynamic pointer array handle
1483 * [I] INT : subitem index
1489 static BOOL LISTVIEW_RemoveSubItem(HDPA hdpaSubItems, INT nSubItem)
1491 LISTVIEW_SUBITEM *lpSubItem;
1494 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1496 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1497 if (lpSubItem != NULL)
1499 if (lpSubItem->iSubItem == nSubItem)
1502 if ((lpSubItem->pszText != NULL) &&
1503 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1505 COMCTL32_Free(lpSubItem->pszText);
1509 COMCTL32_Free(lpSubItem);
1511 /* free dpa memory */
1512 if (DPA_DeletePtr(hdpaSubItems, i) == NULL)
1517 else if (lpSubItem->iSubItem > nSubItem)
1529 * Compares the item information.
1532 * [I] LISTVIEW_ITEM *: destination item
1533 * [I] LPLVITEM : source item
1536 * SUCCCESS : TRUE (EQUAL)
1537 * FAILURE : FALSE (NOT EQUAL)
1539 static UINT LISTVIEW_GetItemChanges(LISTVIEW_ITEM *lpItem, LPLVITEMA lpLVItem)
1543 if ((lpItem != NULL) && (lpLVItem != NULL))
1545 if (lpLVItem->mask & LVIF_STATE)
1547 if ((lpItem->state & lpLVItem->stateMask) !=
1548 (lpLVItem->state & lpLVItem->stateMask))
1550 uChanged |= LVIF_STATE;
1554 if (lpLVItem->mask & LVIF_IMAGE)
1556 if (lpItem->iImage != lpLVItem->iImage)
1558 uChanged |= LVIF_IMAGE;
1562 if (lpLVItem->mask & LVIF_PARAM)
1564 if (lpItem->lParam != lpLVItem->lParam)
1566 uChanged |= LVIF_PARAM;
1570 if (lpLVItem->mask & LVIF_INDENT)
1572 if (lpItem->iIndent != lpLVItem->iIndent)
1574 uChanged |= LVIF_INDENT;
1578 if (lpLVItem->mask & LVIF_TEXT)
1580 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1582 if (lpItem->pszText != LPSTR_TEXTCALLBACKA)
1584 uChanged |= LVIF_TEXT;
1589 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1591 uChanged |= LVIF_TEXT;
1595 if (lpLVItem->pszText)
1597 if (lpItem->pszText)
1599 if (strcmp(lpLVItem->pszText, lpItem->pszText) != 0)
1601 uChanged |= LVIF_TEXT;
1606 uChanged |= LVIF_TEXT;
1611 if (lpItem->pszText)
1613 uChanged |= LVIF_TEXT;
1625 * Initializes item attributes.
1628 * [I] HWND : window handle
1629 * [O] LISTVIEW_ITEM *: destination item
1630 * [I] LPLVITEM : source item
1636 static BOOL LISTVIEW_InitItem(HWND hwnd, LISTVIEW_ITEM *lpItem,
1639 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1640 BOOL bResult = FALSE;
1642 if ((lpItem != NULL) && (lpLVItem != NULL))
1646 if (lpLVItem->mask & LVIF_STATE)
1648 lpItem->state &= ~lpLVItem->stateMask;
1649 lpItem->state |= (lpLVItem->state & lpLVItem->stateMask);
1652 if (lpLVItem->mask & LVIF_IMAGE)
1654 lpItem->iImage = lpLVItem->iImage;
1657 if (lpLVItem->mask & LVIF_PARAM)
1659 lpItem->lParam = lpLVItem->lParam;
1662 if (lpLVItem->mask & LVIF_INDENT)
1664 lpItem->iIndent = lpLVItem->iIndent;
1667 if (lpLVItem->mask & LVIF_TEXT)
1669 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1671 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1676 if ((lpItem->pszText != NULL) &&
1677 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
1679 COMCTL32_Free(lpItem->pszText);
1682 lpItem->pszText = LPSTR_TEXTCALLBACKA;
1686 if (lpItem->pszText == LPSTR_TEXTCALLBACKA)
1688 lpItem->pszText = NULL;
1691 bResult = Str_SetPtrA(&lpItem->pszText, lpLVItem->pszText);
1701 * Initializes subitem attributes.
1703 * NOTE: The documentation specifies that the operation fails if the user
1704 * tries to set the indent of a subitem.
1707 * [I] HWND : window handle
1708 * [O] LISTVIEW_SUBITEM *: destination subitem
1709 * [I] LPLVITEM : source subitem
1715 static BOOL LISTVIEW_InitSubItem(HWND hwnd, LISTVIEW_SUBITEM *lpSubItem,
1718 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1719 BOOL bResult = FALSE;
1721 if ((lpSubItem != NULL) && (lpLVItem != NULL))
1723 if (!(lpLVItem->mask & LVIF_INDENT))
1726 ZeroMemory(lpSubItem, sizeof(LISTVIEW_SUBITEM));
1728 lpSubItem->iSubItem = lpLVItem->iSubItem;
1730 if (lpLVItem->mask & LVIF_IMAGE)
1732 lpSubItem->iImage = lpLVItem->iImage;
1735 if (lpLVItem->mask & LVIF_TEXT)
1737 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKA)
1739 if ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
1744 if ((lpSubItem->pszText != NULL) &&
1745 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
1747 COMCTL32_Free(lpSubItem->pszText);
1750 lpSubItem->pszText = LPSTR_TEXTCALLBACKA;
1754 if (lpSubItem->pszText == LPSTR_TEXTCALLBACKA)
1756 lpSubItem->pszText = NULL;
1759 bResult = Str_SetPtrA(&lpSubItem->pszText, lpLVItem->pszText);
1770 * Adds a subitem at a given position (column index).
1773 * [I] HWND : window handle
1774 * [I] LPLVITEM : new subitem atttributes
1780 static BOOL LISTVIEW_AddSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1782 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1783 LISTVIEW_SUBITEM *lpSubItem = NULL;
1784 BOOL bResult = FALSE;
1786 INT nPosition, nItem;
1788 if (lpLVItem != NULL)
1790 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1791 if (hdpaSubItems != NULL)
1793 lpSubItem = (LISTVIEW_SUBITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_SUBITEM));
1794 if (lpSubItem != NULL)
1796 if (LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem) != FALSE)
1798 nPosition = LISTVIEW_FindInsertPosition(hdpaSubItems,
1799 lpSubItem->iSubItem);
1800 nItem = DPA_InsertPtr(hdpaSubItems, nPosition, lpSubItem);
1810 /* cleanup if unsuccessful */
1811 if ((bResult == FALSE) && (lpSubItem != NULL))
1813 COMCTL32_Free(lpSubItem);
1821 * Finds the dpa insert position (array index).
1824 * [I] HWND : window handle
1825 * [I] INT : subitem index
1831 static INT LISTVIEW_FindInsertPosition(HDPA hdpaSubItems, INT nSubItem)
1833 LISTVIEW_SUBITEM *lpSubItem;
1836 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1838 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1839 if (lpSubItem != NULL)
1841 if (lpSubItem->iSubItem > nSubItem)
1848 return hdpaSubItems->nItemCount;
1853 * Retrieves a listview subitem at a given position (column index).
1856 * [I] HWND : window handle
1857 * [I] INT : subitem index
1863 static LISTVIEW_SUBITEM* LISTVIEW_GetSubItem(HDPA hdpaSubItems, INT nSubItem)
1865 LISTVIEW_SUBITEM *lpSubItem;
1868 for (i = 1; i < hdpaSubItems->nItemCount; i++)
1870 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
1871 if (lpSubItem != NULL)
1873 if (lpSubItem->iSubItem == nSubItem)
1877 else if (lpSubItem->iSubItem > nSubItem)
1889 * Sets item attributes.
1892 * [I] HWND : window handle
1893 * [I] LPLVITEM : new item atttributes
1899 static BOOL LISTVIEW_SetItem(HWND hwnd, LPLVITEMA lpLVItem)
1901 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1902 BOOL bResult = FALSE;
1904 LISTVIEW_ITEM *lpItem;
1906 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
1907 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1909 UINT uView = lStyle & LVS_TYPEMASK;
1912 if (lpLVItem != NULL)
1914 if (lpLVItem->iSubItem == 0)
1916 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1917 if (hdpaSubItems != NULL)
1919 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, lpLVItem->iSubItem);
1922 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
1923 nmlv.hdr.hwndFrom = hwnd;
1924 nmlv.hdr.idFrom = lCtrlId;
1925 nmlv.hdr.code = LVN_ITEMCHANGING;
1926 nmlv.lParam = lpItem->lParam;
1927 uChanged = LISTVIEW_GetItemChanges(lpItem, lpLVItem);
1930 if (uChanged & LVIF_STATE)
1932 nmlv.uNewState = lpLVItem->state & lpLVItem->stateMask;
1933 nmlv.uOldState = lpItem->state & lpLVItem->stateMask;
1936 nmlv.uChanged = uChanged;
1937 nmlv.iItem = lpLVItem->iItem;
1938 nmlv.lParam = lpItem->lParam;
1939 /* send LVN_ITEMCHANGING notification */
1940 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1942 /* copy information */
1943 bResult = LISTVIEW_InitItem(hwnd, lpItem, lpLVItem);
1945 /* if LVS_LIST or LVS_SMALLICON, update the width of the items based on */
1946 /* the width of the items text */
1947 if((uView == LVS_LIST) || (uView == LVS_SMALLICON))
1949 item_width = LISTVIEW_GetStringWidthA(hwnd, lpItem->pszText);
1951 if(item_width > infoPtr->nItemWidth)
1952 infoPtr->nItemWidth = item_width;
1955 /* send LVN_ITEMCHANGED notification */
1956 nmlv.hdr.code = LVN_ITEMCHANGED;
1957 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
1964 InvalidateRect(hwnd, NULL, FALSE);
1975 * Sets subitem attributes.
1978 * [I] HWND : window handle
1979 * [I] LPLVITEM : new subitem atttributes
1985 static BOOL LISTVIEW_SetSubItem(HWND hwnd, LPLVITEMA lpLVItem)
1987 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
1988 BOOL bResult = FALSE;
1990 LISTVIEW_SUBITEM *lpSubItem;
1992 if (lpLVItem != NULL)
1994 if (lpLVItem->iSubItem > 0)
1996 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
1997 if (hdpaSubItems != NULL)
1999 /* set subitem only if column is present */
2000 if (Header_GetItemCount(infoPtr->hwndHeader) > lpLVItem->iSubItem)
2002 lpSubItem = LISTVIEW_GetSubItem(hdpaSubItems, lpLVItem->iSubItem);
2003 if (lpSubItem != NULL)
2005 bResult = LISTVIEW_InitSubItem(hwnd, lpSubItem, lpLVItem);
2009 bResult = LISTVIEW_AddSubItem(hwnd, lpLVItem);
2012 InvalidateRect(hwnd, NULL, FALSE);
2023 * Retrieves the index of the item at coordinate (0, 0) of the client area.
2026 * [I] HWND : window handle
2031 static INT LISTVIEW_GetTopIndex(HWND hwnd)
2033 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2034 UINT uView = lStyle & LVS_TYPEMASK;
2036 SCROLLINFO scrollInfo;
2038 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2039 scrollInfo.cbSize = sizeof(SCROLLINFO);
2040 scrollInfo.fMask = SIF_POS;
2042 if (uView == LVS_LIST)
2044 if (lStyle & WS_HSCROLL)
2046 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2048 nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(hwnd);
2052 else if (uView == LVS_REPORT)
2054 if (lStyle & WS_VSCROLL)
2056 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
2058 nItem = scrollInfo.nPos;
2071 * [I] HWND : window handle
2072 * [I] HDC : device context handle
2073 * [I] INT : item index
2074 * [I] INT : subitem index
2075 * [I] RECT * : clipping rectangle
2080 static VOID LISTVIEW_DrawSubItem(HWND hwnd, HDC hdc, INT nItem, INT nSubItem,
2083 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2084 CHAR szDispText[DISP_TEXT_SIZE];
2087 TRACE("(hwnd=%x, hdc=%x, nItem=%d, nSubItem=%d)\n", hwnd, hdc,
2090 /* get information needed for drawing the item */
2091 ZeroMemory(&lvItem, sizeof(LVITEMA));
2092 lvItem.mask = LVIF_TEXT;
2093 lvItem.iItem = nItem;
2094 lvItem.iSubItem = nSubItem;
2095 lvItem.cchTextMax = DISP_TEXT_SIZE;
2096 lvItem.pszText = szDispText;
2097 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2099 /* set item colors */
2100 SetBkColor(hdc, infoPtr->clrTextBk);
2101 SetTextColor(hdc, infoPtr->clrText);
2103 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2104 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2113 * [I] HWND : window handle
2114 * [I] HDC : device context handle
2115 * [I] INT : item index
2116 * [I] RECT * : clipping rectangle
2121 static VOID LISTVIEW_DrawItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
2123 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2124 CHAR szDispText[DISP_TEXT_SIZE];
2131 TRACE("(hwnd=%x, hdc=%x, nItem=%d)\n", hwnd, hdc, nItem);
2133 /* get information needed for drawing the item */
2134 ZeroMemory(&lvItem, sizeof(LVITEMA));
2135 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
2136 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK;
2137 lvItem.iItem = nItem;
2138 lvItem.iSubItem = 0;
2139 lvItem.cchTextMax = DISP_TEXT_SIZE;
2140 lvItem.pszText = szDispText;
2141 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2144 if (infoPtr->himlState != NULL)
2146 UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
2147 if (uStateImage != 0)
2149 ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
2150 rcItem.top, ILD_NORMAL);
2153 rcItem.left += infoPtr->iconSize.cx;
2157 if (infoPtr->himlSmall != NULL)
2159 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2161 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2162 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2163 rcItem.top, ILD_SELECTED);
2167 ImageList_SetBkColor(infoPtr->himlSmall, CLR_NONE);
2168 ImageList_Draw(infoPtr->himlSmall, lvItem.iImage, hdc, rcItem.left,
2169 rcItem.top, ILD_NORMAL);
2172 rcItem.left += infoPtr->iconSize.cx;
2175 /* Don't bother painting item being edited */
2176 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
2179 if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus != FALSE))
2181 /* set item colors */
2182 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2183 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2184 /* set raster mode */
2185 nMixMode = SetROP2(hdc, R2_XORPEN);
2187 else if ((GetWindowLongA(hwnd, GWL_STYLE) & LVS_SHOWSELALWAYS) &&
2188 (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus == FALSE))
2190 dwBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
2191 dwTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
2192 /* set raster mode */
2193 nMixMode = SetROP2(hdc, R2_COPYPEN);
2197 /* set item colors */
2198 dwBkColor = SetBkColor(hdc, infoPtr->clrTextBk);
2199 dwTextColor = SetTextColor(hdc, infoPtr->clrText);
2200 /* set raster mode */
2201 nMixMode = SetROP2(hdc, R2_COPYPEN);
2204 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2205 if (rcItem.left + nLabelWidth < rcItem.right)
2207 rcItem.right = rcItem.left + nLabelWidth;
2211 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2212 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2214 if ((lvItem.state & LVIS_FOCUSED) && (infoPtr->bFocus == TRUE))
2216 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2221 SetROP2(hdc, R2_COPYPEN);
2222 SetBkColor(hdc, infoPtr->clrTextBk);
2223 SetTextColor(hdc, infoPtr->clrText);
2229 * Draws an item when in large icon display mode.
2232 * [I] HWND : window handle
2233 * [I] HDC : device context handle
2234 * [I] LISTVIEW_ITEM * : item
2235 * [I] INT : item index
2236 * [I] RECT * : clipping rectangle
2241 static VOID LISTVIEW_DrawLargeItem(HWND hwnd, HDC hdc, INT nItem, RECT rcItem)
2243 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2244 CHAR szDispText[DISP_TEXT_SIZE];
2245 INT nDrawPosX = rcItem.left;
2250 TRACE("(hwnd=%x, hdc=%x, nItem=%d, left=%d, top=%d, right=%d, \
2251 bottom=%d)\n", hwnd, hdc, nItem, rcItem.left, rcItem.top, rcItem.right,
2254 /* get information needed for drawing the item */
2255 ZeroMemory(&lvItem, sizeof(LVITEMA));
2256 lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
2257 lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
2258 lvItem.iItem = nItem;
2259 lvItem.iSubItem = 0;
2260 lvItem.cchTextMax = DISP_TEXT_SIZE;
2261 lvItem.pszText = szDispText;
2262 LISTVIEW_GetItemA(hwnd, &lvItem, TRUE);
2264 if (lvItem.state & LVIS_SELECTED)
2266 /* set item colors */
2267 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
2268 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2269 /* set raster mode */
2270 SetROP2(hdc, R2_XORPEN);
2274 /* set item colors */
2275 SetBkColor(hdc, infoPtr->clrTextBk);
2276 SetTextColor(hdc, infoPtr->clrText);
2277 /* set raster mode */
2278 SetROP2(hdc, R2_COPYPEN);
2281 if (infoPtr->himlNormal != NULL)
2283 rcItem.top += ICON_TOP_PADDING;
2284 nDrawPosX += (infoPtr->iconSpacing.cx - infoPtr->iconSize.cx) / 2;
2285 if (lvItem.state & LVIS_SELECTED)
2287 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2288 rcItem.top, ILD_SELECTED);
2292 ImageList_Draw(infoPtr->himlNormal, lvItem.iImage, hdc, nDrawPosX,
2293 rcItem.top, ILD_NORMAL);
2297 /* Don't bother painting item being edited */
2298 if (infoPtr->hwndEdit && lvItem.state & LVIS_FOCUSED)
2301 rcItem.top += infoPtr->iconSize.cy + ICON_BOTTOM_PADDING;
2302 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
2303 nDrawPosX = infoPtr->iconSpacing.cx - nLabelWidth;
2306 rcItem.left += nDrawPosX / 2;
2307 rcItem.right = rcItem.left + nLabelWidth;
2312 rcItem.right = rcItem.left + infoPtr->iconSpacing.cx - 1;
2316 GetTextMetricsA(hdc, &tm);
2317 rcItem.bottom = rcItem.top + tm.tmHeight + HEIGHT_PADDING;
2318 ExtTextOutA(hdc, rcItem.left, rcItem.top, ETO_OPAQUE | ETO_CLIPPED,
2319 &rcItem, lvItem.pszText, lstrlenA(lvItem.pszText), NULL);
2321 if (lvItem.state & LVIS_FOCUSED)
2323 Rectangle(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
2329 * Draws listview items when in report display mode.
2332 * [I] HWND : window handle
2333 * [I] HDC : device context handle
2338 static VOID LISTVIEW_RefreshReport(HWND hwnd, HDC hdc)
2340 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2341 SCROLLINFO scrollInfo;
2342 INT nDrawPosY = infoPtr->rcList.top;
2349 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
2350 scrollInfo.cbSize = sizeof(SCROLLINFO);
2351 scrollInfo.fMask = SIF_POS;
2353 nItem = ListView_GetTopIndex(hwnd);
2355 /* add 1 for displaying a partial item at the bottom */
2356 nLast = nItem + LISTVIEW_GetCountPerColumn(hwnd) + 1;
2357 nLast = min(nLast, GETITEMCOUNT(infoPtr));
2359 /* send cache hint notification */
2360 if (GetWindowLongA(hwnd,GWL_STYLE) & LVS_OWNERDATA)
2364 nmlv.hdr.hwndFrom = hwnd;
2365 nmlv.hdr.idFrom = GetWindowLongA(hwnd,GWL_ID);
2366 nmlv.hdr.code = LVN_ODCACHEHINT;
2370 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)nmlv.hdr.idFrom,
2374 for (; nItem < nLast; nItem++)
2376 nColumnCount = Header_GetItemCount(infoPtr->hwndHeader);
2377 for (j = 0; j < nColumnCount; j++)
2379 Header_GetItemRect(infoPtr->hwndHeader, j, &rcItem);
2380 rcItem.left += REPORT_MARGINX;
2381 rcItem.right = max(rcItem.left, rcItem.right - REPORT_MARGINX);
2382 rcItem.top = nDrawPosY;
2383 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2385 /* Offset the Scroll Bar Pos */
2386 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
2388 rcItem.left -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2389 rcItem.right -= (scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE);
2394 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2398 LISTVIEW_DrawSubItem(hwnd, hdc, nItem, j, rcItem);
2402 nDrawPosY += infoPtr->nItemHeight;
2408 * Retrieves the number of items that can fit vertically in the client area.
2411 * [I] HWND : window handle
2414 * Number of items per row.
2416 static INT LISTVIEW_GetCountPerRow(HWND hwnd)
2418 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2419 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2420 INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
2421 INT nCountPerRow = 1;
2425 if (uView == LVS_REPORT)
2431 nCountPerRow = nListWidth / infoPtr->nItemWidth;
2432 if (nCountPerRow == 0)
2439 return nCountPerRow;
2444 * Retrieves the number of items that can fit horizontally in the client
2448 * [I] HWND : window handle
2451 * Number of items per column.
2453 static INT LISTVIEW_GetCountPerColumn(HWND hwnd)
2455 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd,0);
2456 INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2457 INT nCountPerColumn = 1;
2459 if (nListHeight > 0)
2461 nCountPerColumn = nListHeight / infoPtr->nItemHeight;
2462 if (nCountPerColumn == 0)
2464 nCountPerColumn = 1;
2468 return nCountPerColumn;
2473 * Retrieves the number of columns needed to display all the items when in
2474 * list display mode.
2477 * [I] HWND : window handle
2480 * Number of columns.
2482 static INT LISTVIEW_GetColumnCount(HWND hwnd)
2484 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2485 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2486 INT nColumnCount = 0;
2488 if ((lStyle & LVS_TYPEMASK) == LVS_LIST)
2490 if (infoPtr->rcList.right % infoPtr->nItemWidth == 0)
2492 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
2496 nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth + 1;
2500 return nColumnCount;
2506 * Draws listview items when in list display mode.
2509 * [I] HWND : window handle
2510 * [I] HDC : device context handle
2515 static VOID LISTVIEW_RefreshList(HWND hwnd, HDC hdc)
2517 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2522 INT nCountPerColumn;
2523 INT nItemWidth = infoPtr->nItemWidth;
2524 INT nItemHeight = infoPtr->nItemHeight;
2526 /* get number of fully visible columns */
2527 nColumnCount = LISTVIEW_GetColumnCount(hwnd);
2528 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
2529 nItem = ListView_GetTopIndex(hwnd);
2531 for (i = 0; i < nColumnCount; i++)
2533 for (j = 0; j < nCountPerColumn; j++, nItem++)
2535 if (nItem >= GETITEMCOUNT(infoPtr))
2538 rcItem.top = j * nItemHeight;
2539 rcItem.left = i * nItemWidth;
2540 rcItem.bottom = rcItem.top + nItemHeight;
2541 rcItem.right = rcItem.left + nItemWidth;
2542 LISTVIEW_DrawItem(hwnd, hdc, nItem, rcItem);
2549 * Draws listview items when in icon or small icon display mode.
2552 * [I] HWND : window handle
2553 * [I] HDC : device context handle
2558 static VOID LISTVIEW_RefreshIcon(HWND hwnd, HDC hdc, BOOL bSmall)
2560 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2566 LISTVIEW_GetOrigin(hwnd, &ptOrigin);
2567 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2569 LISTVIEW_GetItemPosition(hwnd, i, &ptPosition);
2570 ptPosition.x += ptOrigin.x;
2571 ptPosition.y += ptOrigin.y;
2573 if (ptPosition.y + infoPtr->nItemHeight > infoPtr->rcList.top)
2575 if (ptPosition.x + infoPtr->nItemWidth > infoPtr->rcList.left)
2577 if (ptPosition.y < infoPtr->rcList.bottom)
2579 if (ptPosition.x < infoPtr->rcList.right)
2581 rcItem.top = ptPosition.y;
2582 rcItem.left = ptPosition.x;
2583 rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
2584 rcItem.right = rcItem.left + infoPtr->nItemWidth;
2585 if (bSmall == FALSE)
2587 LISTVIEW_DrawLargeItem(hwnd, hdc, i, rcItem);
2591 LISTVIEW_DrawItem(hwnd, hdc, i, rcItem);
2602 * Draws listview items.
2605 * [I] HWND : window handle
2606 * [I] HDC : device context handle
2611 static VOID LISTVIEW_Refresh(HWND hwnd, HDC hdc)
2613 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2614 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2619 hOldFont = SelectObject(hdc, infoPtr->hFont);
2621 /* select the doted pen (for drawing the focus box) */
2622 hPen = CreatePen(PS_DOT, 1, 0);
2623 hOldPen = SelectObject(hdc, hPen);
2625 /* select transparent brush (for drawing the focus box) */
2626 SelectObject(hdc, GetStockObject(NULL_BRUSH));
2628 if (uView == LVS_LIST)
2630 LISTVIEW_RefreshList(hwnd, hdc);
2632 else if (uView == LVS_REPORT)
2634 LISTVIEW_RefreshReport(hwnd, hdc);
2636 else if (uView == LVS_SMALLICON)
2638 LISTVIEW_RefreshIcon(hwnd, hdc, TRUE);
2640 else if (uView == LVS_ICON)
2642 LISTVIEW_RefreshIcon(hwnd, hdc, FALSE);
2645 /* unselect objects */
2646 SelectObject(hdc, hOldFont);
2647 SelectObject(hdc, hOldPen);
2656 * Calculates the approximate width and height of a given number of items.
2659 * [I] HWND : window handle
2660 * [I] INT : number of items
2665 * Returns a DWORD. The width in the low word and the height in high word.
2667 static LRESULT LISTVIEW_ApproximateViewRect(HWND hwnd, INT nItemCount,
2668 WORD wWidth, WORD wHeight)
2670 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2671 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2672 INT nItemCountPerColumn = 1;
2673 INT nColumnCount = 0;
2674 DWORD dwViewRect = 0;
2676 if (nItemCount == -1)
2678 nItemCount = GETITEMCOUNT(infoPtr);
2681 if (uView == LVS_LIST)
2683 if (wHeight == 0xFFFF)
2685 /* use current height */
2686 wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
2689 if (wHeight < infoPtr->nItemHeight)
2691 wHeight = infoPtr->nItemHeight;
2696 if (infoPtr->nItemHeight > 0)
2698 nItemCountPerColumn = wHeight / infoPtr->nItemHeight;
2699 if (nItemCountPerColumn == 0)
2701 nItemCountPerColumn = 1;
2704 if (nItemCount % nItemCountPerColumn != 0)
2706 nColumnCount = nItemCount / nItemCountPerColumn;
2710 nColumnCount = nItemCount / nItemCountPerColumn + 1;
2715 /* Microsoft padding magic */
2716 wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2;
2717 wWidth = nColumnCount * infoPtr->nItemWidth + 2;
2719 dwViewRect = MAKELONG(wWidth, wHeight);
2721 else if (uView == LVS_REPORT)
2725 else if (uView == LVS_SMALLICON)
2729 else if (uView == LVS_ICON)
2739 * Arranges listview items in icon display mode.
2742 * [I] HWND : window handle
2743 * [I] INT : alignment code
2749 static LRESULT LISTVIEW_Arrange(HWND hwnd, INT nAlignCode)
2751 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2752 BOOL bResult = FALSE;
2754 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2767 case LVA_SNAPTOGRID:
2776 /* << LISTVIEW_CreateDragImage >> */
2780 * Removes all listview items and subitems.
2783 * [I] HWND : window handle
2789 static LRESULT LISTVIEW_DeleteAllItems(HWND hwnd)
2791 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2792 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2793 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2794 UINT uView = lStyle & LVS_TYPEMASK;
2795 LISTVIEW_ITEM *lpItem;
2796 LISTVIEW_SUBITEM *lpSubItem;
2799 BOOL bResult = FALSE;
2804 TRACE("(hwnd=%x,)\n", hwnd);
2806 if (GETITEMCOUNT(infoPtr) > 0)
2808 /* initialize memory */
2809 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2811 /* send LVN_DELETEALLITEMS notification */
2812 nmlv.hdr.hwndFrom = hwnd;
2813 nmlv.hdr.idFrom = lCtrlId;
2814 nmlv.hdr.code = LVN_DELETEALLITEMS;
2817 /* verify if subsequent LVN_DELETEITEM notifications should be
2819 bSuppress = ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2821 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
2823 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
2824 if (hdpaSubItems != NULL)
2826 for (j = 1; j < hdpaSubItems->nItemCount; j++)
2828 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, j);
2829 if (lpSubItem != NULL)
2831 /* free subitem string */
2832 if ((lpSubItem->pszText != NULL) &&
2833 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2835 COMCTL32_Free(lpSubItem->pszText);
2839 COMCTL32_Free(lpSubItem);
2843 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2846 if (bSuppress == FALSE)
2848 /* send LVN_DELETEITEM notification */
2849 nmlv.hdr.code = LVN_DELETEITEM;
2851 nmlv.lParam = lpItem->lParam;
2852 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
2855 /* free item string */
2856 if ((lpItem->pszText != NULL) &&
2857 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
2859 COMCTL32_Free(lpItem->pszText);
2863 COMCTL32_Free(lpItem);
2866 DPA_Destroy(hdpaSubItems);
2870 /* reinitialize listview memory */
2871 bResult = DPA_DeleteAllPtrs(infoPtr->hdpaItems);
2873 /* align items (set position of each item) */
2874 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
2876 if (lStyle & LVS_ALIGNLEFT)
2878 LISTVIEW_AlignLeft(hwnd);
2882 LISTVIEW_AlignTop(hwnd);
2886 LISTVIEW_UpdateScroll(hwnd);
2888 /* invalidate client area (optimization needed) */
2889 InvalidateRect(hwnd, NULL, TRUE);
2897 * Removes a column from the listview control.
2900 * [I] HWND : window handle
2901 * [I] INT : column index
2907 static LRESULT LISTVIEW_DeleteColumn(HWND hwnd, INT nColumn)
2909 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2910 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
2911 BOOL bResult = FALSE;
2913 if (Header_DeleteItem(infoPtr->hwndHeader, nColumn) != FALSE)
2915 bResult = LISTVIEW_RemoveColumn(infoPtr->hdpaItems, nColumn);
2917 /* Need to reset the item width when deleting a column */
2918 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
2920 /* reset scroll parameters */
2921 if (uView == LVS_REPORT)
2923 /* update scrollbar(s) */
2924 LISTVIEW_UpdateScroll(hwnd);
2926 /* refresh client area */
2927 InvalidateRect(hwnd, NULL, FALSE);
2936 * Removes an item from the listview control.
2939 * [I] HWND : window handle
2940 * [I] INT : item index
2946 static LRESULT LISTVIEW_DeleteItem(HWND hwnd, INT nItem)
2948 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
2949 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
2950 UINT uView = lStyle & LVS_TYPEMASK;
2951 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
2953 BOOL bResult = FALSE;
2955 LISTVIEW_ITEM *lpItem;
2956 LISTVIEW_SUBITEM *lpSubItem;
2959 TRACE("(hwnd=%x,nItem=%d)\n", hwnd, nItem);
2961 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
2963 /* initialize memory */
2964 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
2966 hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem);
2967 if (hdpaSubItems != NULL)
2969 for (i = 1; i < hdpaSubItems->nItemCount; i++)
2971 lpSubItem = (LISTVIEW_SUBITEM *)DPA_GetPtr(hdpaSubItems, i);
2972 if (lpSubItem != NULL)
2974 /* free item string */
2975 if ((lpSubItem->pszText != NULL) &&
2976 (lpSubItem->pszText != LPSTR_TEXTCALLBACKA))
2978 COMCTL32_Free(lpSubItem->pszText);
2982 COMCTL32_Free(lpSubItem);
2986 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
2989 /* send LVN_DELETEITEM notification */
2990 nmlv.hdr.hwndFrom = hwnd;
2991 nmlv.hdr.idFrom = lCtrlId;
2992 nmlv.hdr.code = LVN_DELETEITEM;
2994 nmlv.lParam = lpItem->lParam;
2995 SendMessageA(GetParent(hwnd), WM_NOTIFY, (WPARAM)lCtrlId,
2998 /* free item string */
2999 if ((lpItem->pszText != NULL) &&
3000 (lpItem->pszText != LPSTR_TEXTCALLBACKA))
3002 COMCTL32_Free(lpItem->pszText);
3006 COMCTL32_Free(lpItem);
3009 bResult = DPA_Destroy(hdpaSubItems);
3012 /* align items (set position of each item) */
3013 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3015 if (lStyle & LVS_ALIGNLEFT)
3017 LISTVIEW_AlignLeft(hwnd);
3021 LISTVIEW_AlignTop(hwnd);
3025 /* If this item had focus change focus to next or previous item */
3026 if (GETITEMCOUNT(infoPtr) > 0)
3028 int sItem = nItem < GETITEMCOUNT(infoPtr) ? nItem : nItem - 1;
3029 if (infoPtr->nFocusedItem == nItem)
3030 LISTVIEW_SetItemFocus(hwnd, sItem);
3033 infoPtr->nFocusedItem = -1;
3035 LISTVIEW_UpdateScroll(hwnd);
3037 /* refresh client area */
3038 InvalidateRect(hwnd, NULL, TRUE);
3047 * Return edit control handle of current edit label
3050 * [I] HWND : window handle
3056 static LRESULT LISTVIEW_GetEditControl(hwnd)
3058 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3059 return infoPtr->hwndEdit;
3065 * Callback implementation for editlabel control
3068 * [I] HWND : window handle
3069 * [I] LPSTR : modified text
3070 * [I] DWORD : item index
3077 static BOOL LISTVIEW_EndEditLabel(HWND hwnd, LPSTR pszText, DWORD nItem)
3079 NMLVDISPINFOA dispInfo;
3080 LISTVIEW_ITEM *lpItem;
3081 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
3082 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3084 BOOL bUpdateItemText;
3086 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3088 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
3091 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
3094 dispInfo.hdr.hwndFrom = hwnd;
3095 dispInfo.hdr.idFrom = nCtrlId;
3096 dispInfo.hdr.code = LVN_ENDLABELEDITA;
3097 dispInfo.item.mask = 0;
3098 dispInfo.item.iItem = nItem;
3099 dispInfo.item.state = lpItem->state;
3100 dispInfo.item.stateMask = 0;
3101 dispInfo.item.pszText = pszText;
3102 dispInfo.item.cchTextMax = pszText ? strlen(pszText) : 0;
3103 dispInfo.item.iImage = lpItem->iImage;
3104 dispInfo.item.lParam = lpItem->lParam;
3105 infoPtr->hwndEdit = 0;
3107 bUpdateItemText = ListView_Notify(GetParent(hwnd), nCtrlId, &dispInfo);
3109 /* Do we need to update the Item Text */
3112 if(lpItem->pszText != LPSTR_TEXTCALLBACKA)
3114 Str_SetPtrA(&lpItem->pszText, pszText);
3123 * Begin in place editing of specified list view item
3126 * [I] HWND : window handle
3127 * [I] INT : item index
3134 static HWND LISTVIEW_EditLabelA(HWND hwnd, INT nItem)
3136 NMLVDISPINFOA dispInfo;
3138 LISTVIEW_ITEM *lpItem;
3140 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE);
3141 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
3142 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3144 CHAR szDispText[DISP_TEXT_SIZE];
3147 if (~GetWindowLongA(hwnd, GWL_STYLE) & LVS_EDITLABELS)
3150 /* Is the EditBox still there, if so remove it */
3151 if(infoPtr->hwndEdit != 0)
3156 LISTVIEW_SetSelection(hwnd, nItem);
3157 LISTVIEW_SetItemFocus(hwnd, nItem);
3159 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3160 if (NULL == (hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem)))
3163 if (NULL == (lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0)))
3167 /* get information needed for drawing the item */
3168 ZeroMemory(&lvItem, sizeof(LVITEMA));
3169 lvItem.mask = LVIF_TEXT;
3170 lvItem.iItem = nItem;
3171 lvItem.iSubItem = 0;
3172 lvItem.cchTextMax = DISP_TEXT_SIZE;
3173 lvItem.pszText = szDispText;
3174 ListView_GetItemA(hwnd, &lvItem);
3176 dispInfo.hdr.hwndFrom = hwnd;
3177 dispInfo.hdr.idFrom = nCtrlId;
3178 dispInfo.hdr.code = LVN_BEGINLABELEDITA;
3179 dispInfo.item.mask = 0;
3180 dispInfo.item.iItem = nItem;
3181 dispInfo.item.state = lpItem->state;
3182 dispInfo.item.stateMask = 0;
3183 dispInfo.item.pszText = lvItem.pszText;
3184 dispInfo.item.cchTextMax = strlen(lvItem.pszText);
3185 dispInfo.item.iImage = lpItem->iImage;
3186 dispInfo.item.lParam = lpItem->lParam;
3188 if (ListView_LVNotify(GetParent(hwnd), nCtrlId, &dispInfo))
3191 rect.left = LVIR_LABEL;
3192 if (!LISTVIEW_GetItemRect(hwnd, nItem, &rect))
3195 if (!(hedit = CreateEditLabel(szDispText , WS_VISIBLE,
3196 rect.left-2, rect.top-1, 0,
3197 rect.bottom - rect.top+2,
3198 hwnd, hinst, LISTVIEW_EndEditLabel, nItem)))
3201 infoPtr->hwndEdit = hedit;
3203 SendMessageA(hedit, EM_SETSEL, 0, -1);
3211 * Ensures the specified item is visible, scrolling into view if necessary.
3214 * [I] HWND : window handle
3215 * [I] INT : item index
3216 * [I] BOOL : partially or entirely visible
3222 static BOOL LISTVIEW_EnsureVisible(HWND hwnd, INT nItem, BOOL bPartial)
3224 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3225 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3226 INT nScrollPosHeight = 0;
3227 INT nScrollPosWidth = 0;
3228 SCROLLINFO scrollInfo;
3231 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
3232 scrollInfo.cbSize = sizeof(SCROLLINFO);
3233 scrollInfo.fMask = SIF_POS;
3235 /* ALWAYS bPartial == FALSE, FOR NOW! */
3237 rcItem.left = LVIR_BOUNDS;
3238 if (LISTVIEW_GetItemRect(hwnd, nItem, &rcItem) != FALSE)
3240 if (rcItem.left < infoPtr->rcList.left)
3242 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3245 if (uView == LVS_LIST)
3247 nScrollPosWidth = infoPtr->nItemWidth;
3248 rcItem.left += infoPtr->rcList.left;
3250 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3252 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
3253 rcItem.left += infoPtr->rcList.left;
3256 /* When in LVS_REPORT view, the scroll position should
3258 if (nScrollPosWidth != 0)
3260 if (rcItem.left % nScrollPosWidth == 0)
3262 scrollInfo.nPos += rcItem.left / nScrollPosWidth;
3266 scrollInfo.nPos += rcItem.left / nScrollPosWidth - 1;
3269 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3273 else if (rcItem.right > infoPtr->rcList.right)
3275 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
3278 if (uView == LVS_LIST)
3280 rcItem.right -= infoPtr->rcList.right;
3281 nScrollPosWidth = infoPtr->nItemWidth;
3283 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
3285 rcItem.right -= infoPtr->rcList.right;
3286 nScrollPosWidth = LISTVIEW_SCROLL_DIV_SIZE;
3289 /* When in LVS_REPORT view, the scroll position should
3291 if (nScrollPosWidth != 0)
3293 if (rcItem.right % nScrollPosWidth == 0)
3295 scrollInfo.nPos += rcItem.right / nScrollPosWidth;
3299 scrollInfo.nPos += rcItem.right / nScrollPosWidth + 1;
3302 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
3307 if (rcItem.top < infoPtr->rcList.top)
3310 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3312 if (uView == LVS_REPORT)
3314 rcItem.top -= infoPtr->rcList.top;
3315 nScrollPosHeight = infoPtr->nItemHeight;
3317 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3319 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3320 rcItem.top += infoPtr->rcList.top;
3323 if (rcItem.top % nScrollPosHeight == 0)
3325 scrollInfo.nPos += rcItem.top / nScrollPosHeight;
3329 scrollInfo.nPos += rcItem.top / nScrollPosHeight - 1;
3332 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3335 else if (rcItem.bottom > infoPtr->rcList.bottom)
3338 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
3340 if (uView == LVS_REPORT)
3342 rcItem.bottom -= infoPtr->rcList.bottom;
3343 nScrollPosHeight = infoPtr->nItemHeight;
3345 else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
3347 nScrollPosHeight = LISTVIEW_SCROLL_DIV_SIZE;
3348 rcItem.bottom -= infoPtr->rcList.bottom;
3351 if (rcItem.bottom % nScrollPosHeight == 0)
3353 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight;
3357 scrollInfo.nPos += rcItem.bottom / nScrollPosHeight + 1;
3360 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
3370 * Retrieves the nearest item, given a position and a direction.
3373 * [I] HWND : window handle
3374 * [I] POINT : start position
3375 * [I] UINT : direction
3378 * Item index if successdful, -1 otherwise.
3380 static INT LISTVIEW_GetNearestItem(HWND hwnd, POINT pt, UINT vkDirection)
3382 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3383 LVHITTESTINFO lvHitTestInfo;
3387 if (LISTVIEW_GetViewRect(hwnd, &rcView) != FALSE)
3389 ZeroMemory(&lvHitTestInfo, sizeof(LVHITTESTINFO));
3390 LISTVIEW_GetOrigin(hwnd, &lvHitTestInfo.pt);
3391 lvHitTestInfo.pt.x += pt.x;
3392 lvHitTestInfo.pt.y += pt.y;
3396 if (vkDirection == VK_DOWN)
3398 lvHitTestInfo.pt.y += infoPtr->nItemHeight;
3400 else if (vkDirection == VK_UP)
3402 lvHitTestInfo.pt.y -= infoPtr->nItemHeight;
3404 else if (vkDirection == VK_LEFT)
3406 lvHitTestInfo.pt.x -= infoPtr->nItemWidth;
3408 else if (vkDirection == VK_RIGHT)
3410 lvHitTestInfo.pt.x += infoPtr->nItemWidth;
3413 if (PtInRect(&rcView, lvHitTestInfo.pt) == FALSE)
3419 nItem = LISTVIEW_HitTestItem(hwnd, &lvHitTestInfo);
3423 while (nItem == -1);
3431 * Searches for an item with specific characteristics.
3434 * [I] HWND : window handle
3435 * [I] INT : base item index
3436 * [I] LPLVFINDINFO : item information to look for
3439 * SUCCESS : index of item
3442 static LRESULT LISTVIEW_FindItem(HWND hwnd, INT nStart,
3443 LPLVFINDINFO lpFindInfo)
3445 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3447 CHAR szDispText[DISP_TEXT_SIZE];
3451 INT nLast = GETITEMCOUNT(infoPtr);
3453 if ((nItem >= -1) && (lpFindInfo != NULL))
3455 ZeroMemory(&lvItem, sizeof(LVITEMA));
3457 if (lpFindInfo->flags & LVFI_PARAM)
3459 lvItem.mask |= LVIF_PARAM;
3462 if (lpFindInfo->flags & LVFI_STRING)
3464 lvItem.mask |= LVIF_TEXT;
3465 lvItem.pszText = szDispText;
3466 lvItem.cchTextMax = DISP_TEXT_SIZE;
3469 if (lpFindInfo->flags & LVFI_PARTIAL)
3471 lvItem.mask |= LVIF_TEXT;
3472 lvItem.pszText = szDispText;
3473 lvItem.cchTextMax = DISP_TEXT_SIZE;
3476 if (lpFindInfo->flags & LVFI_WRAP)
3481 if (lpFindInfo->flags & LVFI_NEARESTXY)
3483 ptItem.x = lpFindInfo->pt.x;
3484 ptItem.y = lpFindInfo->pt.y;
3489 while (nItem < nLast)
3491 if (lpFindInfo->flags & LVFI_NEARESTXY)
3493 nItem = LISTVIEW_GetNearestItem(hwnd, ptItem,
3494 lpFindInfo->vkDirection);
3497 /* get position of the new item index */
3498 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) == FALSE)
3509 lvItem.iItem = nItem;
3510 lvItem.iSubItem = 0;
3511 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
3513 if (lvItem.mask & LVIF_TEXT)
3515 if (lpFindInfo->flags & LVFI_PARTIAL)
3517 if (strstr(lvItem.pszText, lpFindInfo->psz) == NULL)
3522 if (strcmp(lvItem.pszText, lpFindInfo->psz) != 0)
3527 if (lvItem.mask & LVIF_PARAM)
3529 if (lpFindInfo->lParam != lvItem.lParam)
3555 * Retrieves the background color of the listview control.
3558 * [I] HWND : window handle
3561 * COLORREF associated with the background.
3563 static LRESULT LISTVIEW_GetBkColor(HWND hwnd)
3565 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3567 return infoPtr->clrBk;
3572 * Retrieves the background image of the listview control.
3575 * [I] HWND : window handle
3576 * [O] LPLVMKBIMAGE : background image attributes
3582 /* static LRESULT LISTVIEW_GetBkImage(HWND hwnd, LPLVBKIMAGE lpBkImage) */
3584 /* FIXME (listview, "empty stub!\n"); */
3590 * Retrieves the callback mask.
3593 * [I] HWND : window handle
3598 static UINT LISTVIEW_GetCallbackMask(HWND hwnd)
3600 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3602 return infoPtr->uCallbackMask;
3607 * Retrieves column attributes.
3610 * [I] HWND : window handle
3611 * [I] INT : column index
3612 * [IO] LPLVCOLUMNA : column information
3618 static LRESULT LISTVIEW_GetColumnA(HWND hwnd, INT nItem, LPLVCOLUMNA lpColumn)
3620 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3622 BOOL bResult = FALSE;
3624 if (lpColumn != NULL)
3626 /* initialize memory */
3627 ZeroMemory(&hdi, sizeof(HDITEMA));
3629 if (lpColumn->mask & LVCF_FMT)
3631 hdi.mask |= HDI_FORMAT;
3634 if (lpColumn->mask & LVCF_WIDTH)
3636 hdi.mask |= HDI_WIDTH;
3639 if (lpColumn->mask & LVCF_TEXT)
3641 hdi.mask |= HDI_TEXT;
3642 hdi.cchTextMax = lpColumn->cchTextMax;
3643 hdi.pszText = lpColumn->pszText;
3646 if (lpColumn->mask & LVCF_IMAGE)
3648 hdi.mask |= HDI_IMAGE;
3651 if (lpColumn->mask & LVCF_ORDER)
3653 hdi.mask |= HDI_ORDER;
3656 bResult = Header_GetItemA(infoPtr->hwndHeader, nItem, &hdi);
3657 if (bResult != FALSE)
3659 if (lpColumn->mask & LVCF_FMT)
3663 if (hdi.fmt & HDF_LEFT)
3665 lpColumn->fmt |= LVCFMT_LEFT;
3667 else if (hdi.fmt & HDF_RIGHT)
3669 lpColumn->fmt |= LVCFMT_RIGHT;
3671 else if (hdi.fmt & HDF_CENTER)
3673 lpColumn->fmt |= LVCFMT_CENTER;
3676 if (hdi.fmt & HDF_IMAGE)
3678 lpColumn->fmt |= LVCFMT_COL_HAS_IMAGES;
3681 if (hdi.fmt & HDF_BITMAP_ON_RIGHT)
3683 lpColumn->fmt |= LVCFMT_BITMAP_ON_RIGHT;
3687 if (lpColumn->mask & LVCF_WIDTH)
3689 lpColumn->cx = hdi.cxy;
3692 if (lpColumn->mask & LVCF_IMAGE)
3694 lpColumn->iImage = hdi.iImage;
3697 if (lpColumn->mask & LVCF_ORDER)
3699 lpColumn->iOrder = hdi.iOrder;
3707 /* LISTVIEW_GetColumnW */
3710 static LRESULT LISTVIEW_GetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
3712 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
3719 for (i = 0; i < iCount; i++)
3727 * Retrieves the column width.
3730 * [I] HWND : window handle
3731 * [I] int : column index
3734 * SUCCESS : column width
3737 static LRESULT LISTVIEW_GetColumnWidth(HWND hwnd, INT nColumn)
3739 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3740 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3741 INT nColumnWidth = 0;
3744 if (uView == LVS_LIST)
3746 nColumnWidth = infoPtr->nItemWidth;
3748 else if (uView == LVS_REPORT)
3750 /* get column width from header */
3751 ZeroMemory(&hdi, sizeof(HDITEMA));
3752 hdi.mask = HDI_WIDTH;
3753 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdi) != FALSE)
3755 nColumnWidth = hdi.cxy;
3759 return nColumnWidth;
3764 * In list or report display mode, retrieves the number of items that can fit
3765 * vertically in the visible area. In icon or small icon display mode,
3766 * retrieves the total number of visible items.
3769 * [I] HWND : window handle
3772 * Number of fully visible items.
3774 static LRESULT LISTVIEW_GetCountPerPage(HWND hwnd)
3776 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3777 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
3780 if (uView == LVS_LIST)
3782 if (infoPtr->rcList.right > infoPtr->nItemWidth)
3784 nItemCount = LISTVIEW_GetCountPerRow(hwnd) *
3785 LISTVIEW_GetCountPerColumn(hwnd);
3788 else if (uView == LVS_REPORT)
3790 nItemCount = LISTVIEW_GetCountPerColumn(hwnd);
3794 nItemCount = GETITEMCOUNT(infoPtr);
3800 /* LISTVIEW_GetEditControl */
3804 * Retrieves the extended listview style.
3807 * [I] HWND : window handle
3810 * SUCCESS : previous style
3813 static LRESULT LISTVIEW_GetExtendedListViewStyle(HWND hwnd)
3815 LISTVIEW_INFO *infoPtr;
3817 /* make sure we can get the listview info */
3818 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
3821 return (infoPtr->dwExStyle);
3826 * Retrieves the handle to the header control.
3829 * [I] HWND : window handle
3834 static LRESULT LISTVIEW_GetHeader(HWND hwnd)
3836 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3838 return infoPtr->hwndHeader;
3841 /* LISTVIEW_GetHotCursor */
3845 * Returns the time that the mouse cursor must hover over an item
3846 * before it is selected.
3849 * [I] HWND : window handle
3852 * Returns the previously set hover time or (DWORD)-1 to indicate that the
3853 * hover time is set to the default hover time.
3855 static LRESULT LISTVIEW_GetHoverTime(HWND hwnd)
3857 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3859 return infoPtr->dwHoverTime;
3864 * Retrieves an image list handle.
3867 * [I] HWND : window handle
3868 * [I] INT : image list identifier
3871 * SUCCESS : image list handle
3874 static LRESULT LISTVIEW_GetImageList(HWND hwnd, INT nImageList)
3876 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3877 HIMAGELIST himl = NULL;
3882 himl = infoPtr->himlNormal;
3885 himl = infoPtr->himlSmall;
3888 himl = infoPtr->himlState;
3892 return (LRESULT)himl;
3895 /* LISTVIEW_GetISearchString */
3899 * Retrieves item attributes.
3902 * [I] HWND : window handle
3903 * [IO] LPLVITEMA : item info
3904 * [I] internal : if true then we will use tricks that avoid copies
3905 * but are not compatible with the regular interface
3911 static LRESULT LISTVIEW_GetItemA(HWND hwnd, LPLVITEMA lpLVItem, BOOL internal)
3913 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
3914 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
3915 NMLVDISPINFOA dispInfo;
3916 LISTVIEW_SUBITEM *lpSubItem;
3917 LISTVIEW_ITEM *lpItem;
3921 /* In the following:
3922 * lpLVItem describes the information requested by the user
3923 * lpItem/lpSubItem is what we have
3924 * dispInfo is a structure we use to request the missing
3925 * information from the application
3928 TRACE("(hwnd=%x, lpLVItem=%p)\n", hwnd, lpLVItem);
3930 if ((lpLVItem == NULL) ||
3931 (lpLVItem->iItem < 0) ||
3932 (lpLVItem->iItem >= GETITEMCOUNT(infoPtr))
3936 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem);
3937 if (hdpaSubItems == NULL)
3940 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
3944 ZeroMemory(&dispInfo, sizeof(NMLVDISPINFOA));
3945 if (lpLVItem->iSubItem == 0)
3947 piImage=&lpItem->iImage;
3948 ppszText=&lpItem->pszText;
3949 if ((infoPtr->uCallbackMask != 0) && (lpLVItem->mask & LVIF_STATE))
3951 dispInfo.item.mask |= LVIF_STATE;
3952 dispInfo.item.stateMask = infoPtr->uCallbackMask;
3957 lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem);
3958 if (lpSubItem != NULL)
3960 piImage=&lpSubItem->iImage;
3961 ppszText=&lpSubItem->pszText;
3970 if ((lpLVItem->mask & LVIF_IMAGE) &&
3971 ((piImage==NULL) || (*piImage == I_IMAGECALLBACK)))
3973 dispInfo.item.mask |= LVIF_IMAGE;
3976 if ((lpLVItem->mask & LVIF_TEXT) &&
3977 ((ppszText==NULL) || (*ppszText == LPSTR_TEXTCALLBACKA)))
3979 dispInfo.item.mask |= LVIF_TEXT;
3980 dispInfo.item.pszText = lpLVItem->pszText;
3981 dispInfo.item.cchTextMax = lpLVItem->cchTextMax;
3984 if (dispInfo.item.mask != 0)
3986 /* We don't have all the requested info, query the application */
3987 dispInfo.hdr.hwndFrom = hwnd;
3988 dispInfo.hdr.idFrom = lCtrlId;
3989 dispInfo.hdr.code = LVN_GETDISPINFOA;
3990 dispInfo.item.iItem = lpLVItem->iItem;
3991 dispInfo.item.iSubItem = lpLVItem->iSubItem;
3992 dispInfo.item.lParam = lpItem->lParam;
3993 ListView_Notify(GetParent(hwnd), lCtrlId, &dispInfo);
3996 if (dispInfo.item.mask & LVIF_IMAGE)
3998 lpLVItem->iImage = dispInfo.item.iImage;
4000 else if (lpLVItem->mask & LVIF_IMAGE)
4002 lpLVItem->iImage = *piImage;
4005 if (dispInfo.item.mask & LVIF_PARAM)
4007 lpLVItem->lParam = dispInfo.item.lParam;
4009 else if (lpLVItem->mask & LVIF_PARAM)
4011 lpLVItem->lParam = lpItem->lParam;
4014 if (dispInfo.item.mask & LVIF_TEXT)
4016 if ((dispInfo.item.mask & LVIF_DI_SETITEM) && (ppszText != NULL))
4018 Str_SetPtrA(ppszText, dispInfo.item.pszText);
4020 /* Here lpLVItem->pszText==dispInfo.item.pszText so a copy is unnecessary */
4022 else if (lpLVItem->mask & LVIF_TEXT)
4026 lpLVItem->pszText=*ppszText;
4028 lstrcpynA(lpLVItem->pszText, *ppszText, lpLVItem->cchTextMax);
4032 if (lpLVItem->iSubItem == 0)
4034 if (dispInfo.item.mask & LVIF_STATE)
4036 lpLVItem->state = lpItem->state;
4037 lpLVItem->state &= ~dispInfo.item.stateMask;
4038 lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask);
4040 else if (lpLVItem->mask & LVIF_STATE)
4042 lpLVItem->state = lpItem->state & lpLVItem->stateMask;
4045 if (lpLVItem->mask & LVIF_PARAM)
4047 lpLVItem->lParam = lpItem->lParam;
4050 if (lpLVItem->mask & LVIF_INDENT)
4052 lpLVItem->iIndent = lpItem->iIndent;
4059 /* LISTVIEW_GetItemW */
4060 /* LISTVIEW_GetHotCursor */
4064 * Retrieves the index of the hot item.
4067 * [I] HWND : window handle
4070 * SUCCESS : hot item index
4071 * FAILURE : -1 (no hot item)
4073 static LRESULT LISTVIEW_GetHotItem(HWND hwnd)
4075 LISTVIEW_INFO *infoPtr;
4077 /* make sure we can get the listview info */
4078 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
4081 return (infoPtr->nHotItem);
4084 /* LISTVIEW_GetHoverTime */
4088 * Retrieves the number of items in the listview control.
4091 * [I] HWND : window handle
4096 static LRESULT LISTVIEW_GetItemCount(HWND hwnd)
4098 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4100 return GETITEMCOUNT(infoPtr);
4105 * Retrieves the position (upper-left) of the listview control item.
4108 * [I] HWND : window handle
4109 * [I] INT : item index
4110 * [O] LPPOINT : coordinate information
4116 static BOOL LISTVIEW_GetItemPosition(HWND hwnd, INT nItem,
4117 LPPOINT lpptPosition)
4119 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4120 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4121 BOOL bResult = FALSE;
4123 LISTVIEW_ITEM *lpItem;
4124 INT nCountPerColumn;
4127 TRACE("(hwnd=%x,nItem=%d,lpptPosition=%p)\n", hwnd, nItem,
4130 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) &&
4131 (lpptPosition != NULL))
4133 if (uView == LVS_LIST)
4136 nItem = nItem - ListView_GetTopIndex(hwnd);
4137 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4140 nRow = nItem % nCountPerColumn;
4143 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
4144 lpptPosition->y = 0;
4148 lpptPosition->x = (nItem / nCountPerColumn -1) * infoPtr->nItemWidth;
4149 lpptPosition->y = (nRow + nCountPerColumn) * infoPtr->nItemHeight;
4154 lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth;
4155 lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight;
4158 else if (uView == LVS_REPORT)
4161 lpptPosition->x = REPORT_MARGINX;
4162 lpptPosition->y = ((nItem - ListView_GetTopIndex(hwnd)) *
4163 infoPtr->nItemHeight) + infoPtr->rcList.top;
4167 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
4168 if (hdpaSubItems != NULL)
4170 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
4174 lpptPosition->x = lpItem->ptPosition.x;
4175 lpptPosition->y = lpItem->ptPosition.y;
4186 * Retrieves the bounding rectangle for a listview control item.
4189 * [I] HWND : window handle
4190 * [I] INT : item index
4191 * [IO] LPRECT : bounding rectangle coordinates
4197 static LRESULT LISTVIEW_GetItemRect(HWND hwnd, INT nItem, LPRECT lprc)
4199 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4200 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4201 BOOL bResult = FALSE;
4210 TRACE("(hwnd=%x, nItem=%d, lprc=%p)\n", hwnd, nItem, lprc);
4212 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)) && (lprc != NULL))
4214 if (ListView_GetItemPosition(hwnd, nItem, &ptItem) != FALSE)
4219 if (uView == LVS_ICON)
4221 if (infoPtr->himlNormal != NULL)
4223 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4226 lprc->left = ptItem.x + ptOrigin.x;
4227 lprc->top = ptItem.y + ptOrigin.y;
4228 lprc->right = lprc->left + infoPtr->iconSize.cx;
4229 lprc->bottom = (lprc->top + infoPtr->iconSize.cy +
4230 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
4234 else if (uView == LVS_SMALLICON)
4236 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4239 lprc->left = ptItem.x + ptOrigin.x;
4240 lprc->top = ptItem.y + ptOrigin.y;
4241 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4243 if (infoPtr->himlState != NULL)
4244 lprc->left += infoPtr->iconSize.cx;
4246 if (infoPtr->himlSmall != NULL)
4247 lprc->right = lprc->left + infoPtr->iconSize.cx;
4249 lprc->right = lprc->left;
4255 lprc->left = ptItem.x;
4256 lprc->top = ptItem.y;
4257 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4259 if (infoPtr->himlState != NULL)
4261 lprc->left += infoPtr->iconSize.cx;
4264 if (infoPtr->himlSmall != NULL)
4266 lprc->right = lprc->left + infoPtr->iconSize.cx;
4270 lprc->right = lprc->left;
4276 if (uView == LVS_ICON)
4278 if (infoPtr->himlNormal != NULL)
4280 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4283 lprc->left = ptItem.x + ptOrigin.x;
4284 lprc->top = (ptItem.y + ptOrigin.y + infoPtr->iconSize.cy +
4285 ICON_BOTTOM_PADDING + ICON_TOP_PADDING);
4286 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4287 if (infoPtr->iconSpacing.cx - nLabelWidth > 1)
4289 lprc->left += (infoPtr->iconSpacing.cx - nLabelWidth) / 2;
4290 lprc->right = lprc->left + nLabelWidth;
4295 lprc->right = lprc->left + infoPtr->iconSpacing.cx - 1;
4299 hOldFont = SelectObject(hdc, infoPtr->hFont);
4300 GetTextMetricsA(hdc, &tm);
4301 lprc->bottom = lprc->top + tm.tmHeight + HEIGHT_PADDING;
4302 SelectObject(hdc, hOldFont);
4303 ReleaseDC(hwnd, hdc);
4307 else if (uView == LVS_SMALLICON)
4309 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4312 nLeftPos = lprc->left = ptItem.x + ptOrigin.x;
4313 lprc->top = ptItem.y + ptOrigin.y;
4314 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4316 if (infoPtr->himlState != NULL)
4318 lprc->left += infoPtr->iconSize.cx;
4321 if (infoPtr->himlSmall != NULL)
4323 lprc->left += infoPtr->iconSize.cx;
4326 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4327 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4329 lprc->right = lprc->left + nLabelWidth;
4333 lprc->right = nLeftPos + infoPtr->nItemWidth;
4340 nLeftPos = lprc->left = ptItem.x;
4341 lprc->top = ptItem.y;
4342 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4344 if (infoPtr->himlState != NULL)
4346 lprc->left += infoPtr->iconSize.cx;
4349 if (infoPtr->himlSmall != NULL)
4351 lprc->left += infoPtr->iconSize.cx;
4354 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4355 if (lprc->left + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4357 lprc->right = lprc->left + nLabelWidth;
4361 lprc->right = nLeftPos + infoPtr->nItemWidth;
4367 if (uView == LVS_ICON)
4369 if (infoPtr->himlNormal != NULL)
4371 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4374 lprc->left = ptItem.x + ptOrigin.x;
4375 lprc->top = ptItem.y + ptOrigin.y;
4376 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4377 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4381 else if (uView == LVS_SMALLICON)
4383 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4386 lprc->left = ptItem.x + ptOrigin.x;
4387 lprc->right = lprc->left;
4388 lprc->top = ptItem.y + ptOrigin.y;
4389 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4390 if (infoPtr->himlState != NULL)
4391 lprc->right += infoPtr->iconSize.cx;
4392 if (infoPtr->himlSmall != NULL)
4393 lprc->right += infoPtr->iconSize.cx;
4395 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4396 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4398 lprc->right += nLabelWidth;
4402 lprc->right = lprc->left + infoPtr->nItemWidth;
4409 lprc->left = ptItem.x;
4410 lprc->right = lprc->left;
4411 lprc->top = ptItem.y;
4412 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4414 if (infoPtr->himlState != NULL)
4416 lprc->right += infoPtr->iconSize.cx;
4419 if (infoPtr->himlSmall != NULL)
4421 lprc->right += infoPtr->iconSize.cx;
4424 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4425 if (lprc->right + nLabelWidth < lprc->left + infoPtr->nItemWidth)
4427 lprc->right += nLabelWidth;
4431 lprc->right = lprc->left + infoPtr->nItemWidth;
4436 case LVIR_SELECTBOUNDS:
4437 if (uView == LVS_ICON)
4439 if (infoPtr->himlNormal != NULL)
4441 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4444 lprc->left = ptItem.x + ptOrigin.x;
4445 lprc->top = ptItem.y + ptOrigin.y;
4446 lprc->right = lprc->left + infoPtr->iconSpacing.cx;
4447 lprc->bottom = lprc->top + infoPtr->iconSpacing.cy;
4451 else if (uView == LVS_SMALLICON)
4453 if (LISTVIEW_GetOrigin(hwnd, &ptOrigin) != FALSE)
4456 nLeftPos= lprc->left = ptItem.x + ptOrigin.x;
4457 lprc->top = ptItem.y + ptOrigin.y;
4458 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4460 if (infoPtr->himlState != NULL)
4462 lprc->left += infoPtr->iconSize.cx;
4465 lprc->right = lprc->left;
4467 if (infoPtr->himlSmall != NULL)
4469 lprc->right += infoPtr->iconSize.cx;
4472 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4473 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4475 lprc->right += nLabelWidth;
4479 lprc->right = nLeftPos + infoPtr->nItemWidth;
4486 nLeftPos = lprc->left = ptItem.x;
4487 lprc->top = ptItem.y;
4488 lprc->bottom = lprc->top + infoPtr->nItemHeight;
4490 if (infoPtr->himlState != NULL)
4492 lprc->left += infoPtr->iconSize.cx;
4495 lprc->right = lprc->left;
4497 if (infoPtr->himlSmall != NULL)
4499 lprc->right += infoPtr->iconSize.cx;
4502 nLabelWidth = LISTVIEW_GetLabelWidth(hwnd, nItem);
4503 if (lprc->right + nLabelWidth < nLeftPos + infoPtr->nItemWidth)
4505 lprc->right += nLabelWidth;
4509 lprc->right = nLeftPos + infoPtr->nItemWidth;
4522 * Retrieves the width of a label.
4525 * [I] HWND : window handle
4528 * SUCCESS : string width (in pixels)
4531 static INT LISTVIEW_GetLabelWidth(HWND hwnd, INT nItem)
4533 CHAR szDispText[DISP_TEXT_SIZE];
4534 INT nLabelWidth = 0;
4537 TRACE("(hwnd=%x, nItem=%d)\n", hwnd, nItem);
4539 ZeroMemory(&lvItem, sizeof(LVITEMA));
4540 lvItem.mask = LVIF_TEXT;
4541 lvItem.iItem = nItem;
4542 lvItem.cchTextMax = DISP_TEXT_SIZE;
4543 lvItem.pszText = szDispText;
4544 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4546 nLabelWidth = ListView_GetStringWidthA(hwnd, lvItem.pszText);
4554 * Retrieves the spacing between listview control items.
4557 * [I] HWND : window handle
4558 * [I] BOOL : flag for small or large icon
4561 * Horizontal + vertical spacing
4563 static LRESULT LISTVIEW_GetItemSpacing(HWND hwnd, BOOL bSmall)
4565 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4568 if (bSmall == FALSE)
4570 lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy);
4574 /* TODO: need to store width of smallicon item */
4575 lResult = MAKELONG(0, infoPtr->nItemHeight);
4583 * Retrieves the state of a listview control item.
4586 * [I] HWND : window handle
4587 * [I] INT : item index
4588 * [I] UINT : state mask
4591 * State specified by the mask.
4593 static LRESULT LISTVIEW_GetItemState(HWND hwnd, INT nItem, UINT uMask)
4595 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4599 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4601 ZeroMemory(&lvItem, sizeof(LVITEMA));
4602 lvItem.iItem = nItem;
4603 lvItem.stateMask = uMask;
4604 lvItem.mask = LVIF_STATE;
4605 if (LISTVIEW_GetItemA(hwnd, &lvItem, TRUE) != FALSE)
4607 uState = lvItem.state;
4616 * Retrieves the text of a listview control item or subitem.
4619 * [I] HWND : window handle
4620 * [I] INT : item index
4621 * [IO] LPLVITEMA : item information
4624 * SUCCESS : string length
4627 static LRESULT LISTVIEW_GetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
4629 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4632 if (lpLVItem != NULL)
4634 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
4636 lpLVItem->mask = LVIF_TEXT;
4637 lpLVItem->iItem = nItem;
4638 if (LISTVIEW_GetItemA(hwnd, lpLVItem, FALSE) != FALSE)
4640 nLength = lstrlenA(lpLVItem->pszText);
4650 * Searches for an item based on properties + relationships.
4653 * [I] HWND : window handle
4654 * [I] INT : item index
4655 * [I] INT : relationship flag
4658 * SUCCESS : item index
4661 static LRESULT LISTVIEW_GetNextItem(HWND hwnd, INT nItem, UINT uFlags)
4663 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4664 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
4666 LVFINDINFO lvFindInfo;
4667 INT nCountPerColumn;
4670 if ((nItem >= -1) && (nItem < GETITEMCOUNT(infoPtr)))
4672 ZeroMemory(&lvFindInfo, sizeof(LVFINDINFO));
4674 if (uFlags & LVNI_CUT)
4677 if (uFlags & LVNI_DROPHILITED)
4678 uMask |= LVIS_DROPHILITED;
4680 if (uFlags & LVNI_FOCUSED)
4681 uMask |= LVIS_FOCUSED;
4683 if (uFlags & LVNI_SELECTED)
4684 uMask |= LVIS_SELECTED;
4686 if (uFlags & LVNI_ABOVE)
4688 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4693 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4699 lvFindInfo.flags = LVFI_NEARESTXY;
4700 lvFindInfo.vkDirection = VK_UP;
4701 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4702 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4704 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4709 else if (uFlags & LVNI_BELOW)
4711 if ((uView == LVS_LIST) || (uView == LVS_REPORT))
4713 while (nItem < GETITEMCOUNT(infoPtr))
4716 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4722 lvFindInfo.flags = LVFI_NEARESTXY;
4723 lvFindInfo.vkDirection = VK_DOWN;
4724 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4725 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4727 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4732 else if (uFlags & LVNI_TOLEFT)
4734 if (uView == LVS_LIST)
4736 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4737 while (nItem - nCountPerColumn >= 0)
4739 nItem -= nCountPerColumn;
4740 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4744 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4746 lvFindInfo.flags = LVFI_NEARESTXY;
4747 lvFindInfo.vkDirection = VK_LEFT;
4748 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4749 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4751 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4756 else if (uFlags & LVNI_TORIGHT)
4758 if (uView == LVS_LIST)
4760 nCountPerColumn = LISTVIEW_GetCountPerColumn(hwnd);
4761 while (nItem + nCountPerColumn < GETITEMCOUNT(infoPtr))
4763 nItem += nCountPerColumn;
4764 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4768 else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4770 lvFindInfo.flags = LVFI_NEARESTXY;
4771 lvFindInfo.vkDirection = VK_RIGHT;
4772 ListView_GetItemPosition(hwnd, nItem, &lvFindInfo.pt);
4773 while ((nItem = ListView_FindItem(hwnd, nItem, &lvFindInfo)) != -1)
4775 if ((ListView_GetItemState(hwnd, nItem, uMask) & uMask) == uMask)
4784 /* search by index */
4785 for (i = nItem; i < GETITEMCOUNT(infoPtr); i++)
4787 if ((ListView_GetItemState(hwnd, i, uMask) & uMask) == uMask)
4796 /* LISTVIEW_GetNumberOfWorkAreas */
4800 * Retrieves the origin coordinates when in icon or small icon display mode.
4803 * [I] HWND : window handle
4804 * [O] LPPOINT : coordinate information
4810 static LRESULT LISTVIEW_GetOrigin(HWND hwnd, LPPOINT lpptOrigin)
4812 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
4813 UINT uView = lStyle & LVS_TYPEMASK;
4814 BOOL bResult = FALSE;
4816 TRACE("(hwnd=%x, lpptOrigin=%p)\n", hwnd, lpptOrigin);
4818 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
4820 SCROLLINFO scrollInfo;
4821 ZeroMemory(lpptOrigin, sizeof(POINT));
4822 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
4823 scrollInfo.cbSize = sizeof(SCROLLINFO);
4825 if (lStyle & WS_HSCROLL)
4827 scrollInfo.fMask = SIF_POS;
4828 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
4830 lpptOrigin->x = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4834 if (lStyle & WS_VSCROLL)
4836 scrollInfo.fMask = SIF_POS;
4837 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
4839 lpptOrigin->y = -scrollInfo.nPos * LISTVIEW_SCROLL_DIV_SIZE;
4851 * Retrieves the number of items that are marked as selected.
4854 * [I] HWND : window handle
4857 * Number of items selected.
4859 static LRESULT LISTVIEW_GetSelectedCount(HWND hwnd)
4861 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4862 INT nSelectedCount = 0;
4865 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4867 if (ListView_GetItemState(hwnd, i, LVIS_SELECTED) & LVIS_SELECTED)
4873 return nSelectedCount;
4878 * Retrieves item index that marks the start of a multiple selection.
4881 * [I] HWND : window handle
4884 * Index number or -1 if there is no selection mark.
4886 static LRESULT LISTVIEW_GetSelectionMark(HWND hwnd)
4888 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4890 return infoPtr->nSelectionMark;
4895 * Retrieves the width of a string.
4898 * [I] HWND : window handle
4901 * SUCCESS : string width (in pixels)
4904 static LRESULT LISTVIEW_GetStringWidthA(HWND hwnd, LPCSTR lpszText)
4906 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4907 HFONT hFont, hOldFont;
4911 ZeroMemory(&stringSize, sizeof(SIZE));
4912 if (lpszText != NULL)
4914 hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont;
4916 hOldFont = SelectObject(hdc, hFont);
4917 GetTextExtentPointA(hdc, lpszText, lstrlenA(lpszText), &stringSize);
4918 SelectObject(hdc, hOldFont);
4919 ReleaseDC(hwnd, hdc);
4922 return stringSize.cx;
4927 * Retrieves the text backgound color.
4930 * [I] HWND : window handle
4933 * COLORREF associated with the the background.
4935 static LRESULT LISTVIEW_GetTextBkColor(HWND hwnd)
4937 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4939 return infoPtr->clrTextBk;
4944 * Retrieves the text color.
4947 * [I] HWND : window handle
4950 * COLORREF associated with the text.
4952 static LRESULT LISTVIEW_GetTextColor(HWND hwnd)
4954 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
4956 return infoPtr->clrText;
4961 * Determines which section of the item was selected (if any).
4964 * [I] HWND : window handle
4965 * [IO] LPLVHITTESTINFO : hit test information
4968 * SUCCESS : item index
4971 static INT LISTVIEW_HitTestItem(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
4973 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
4977 TRACE("(hwnd=%x, x=%ld, y=%ld)\n", hwnd, lpHitTestInfo->pt.x,
4978 lpHitTestInfo->pt.y);
4980 for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
4982 rcItem.left = LVIR_BOUNDS;
4983 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4985 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4987 rcItem.left = LVIR_ICON;
4988 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
4990 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
4992 lpHitTestInfo->flags = LVHT_ONITEMICON;
4993 lpHitTestInfo->iItem = i;
4994 lpHitTestInfo->iSubItem = 0;
4999 rcItem.left = LVIR_LABEL;
5000 if (LISTVIEW_GetItemRect(hwnd, i, &rcItem) != FALSE)
5002 if (PtInRect(&rcItem, lpHitTestInfo->pt) != FALSE)
5004 lpHitTestInfo->flags = LVHT_ONITEMLABEL;
5005 lpHitTestInfo->iItem = i;
5006 lpHitTestInfo->iSubItem = 0;
5011 lpHitTestInfo->flags = LVHT_ONITEMSTATEICON;
5012 lpHitTestInfo->iItem = i;
5013 lpHitTestInfo->iSubItem = 0;
5019 lpHitTestInfo->flags = LVHT_NOWHERE;
5026 * Determines which listview item is located at the specified position.
5029 * [I] HWND : window handle
5030 * [IO} LPLVHITTESTINFO : hit test information
5033 * SUCCESS : item index
5036 static LRESULT LISTVIEW_HitTest(HWND hwnd, LPLVHITTESTINFO lpHitTestInfo)
5038 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5041 lpHitTestInfo->flags = 0;
5043 if (infoPtr->rcList.left > lpHitTestInfo->pt.x)
5045 lpHitTestInfo->flags = LVHT_TOLEFT;
5047 else if (infoPtr->rcList.right < lpHitTestInfo->pt.x)
5049 lpHitTestInfo->flags = LVHT_TORIGHT;
5051 if (infoPtr->rcList.top > lpHitTestInfo->pt.y)
5053 lpHitTestInfo->flags |= LVHT_ABOVE;
5055 else if (infoPtr->rcList.bottom < lpHitTestInfo->pt.y)
5057 lpHitTestInfo->flags |= LVHT_BELOW;
5060 if (lpHitTestInfo->flags == 0)
5062 nItem = LISTVIEW_HitTestItem(hwnd, lpHitTestInfo);
5070 * Inserts a new column.
5073 * [I] HWND : window handle
5074 * [I] INT : column index
5075 * [I] LPLVCOLUMNA : column information
5078 * SUCCESS : new column index
5081 static LRESULT LISTVIEW_InsertColumnA(HWND hwnd, INT nColumn,
5082 LPLVCOLUMNA lpColumn)
5084 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5086 INT nNewColumn = -1;
5088 TRACE("(hwnd=%x, nColumn=%d, lpColumn=%p)\n",hwnd, nColumn,
5091 if (lpColumn != NULL)
5093 /* initialize memory */
5094 ZeroMemory(&hdi, sizeof(HDITEMA));
5096 if (lpColumn->mask & LVCF_FMT)
5098 /* format member is valid */
5099 hdi.mask |= HDI_FORMAT;
5101 /* set text alignment (leftmost column must be left-aligned) */
5104 hdi.fmt |= HDF_LEFT;
5108 if (lpColumn->fmt & LVCFMT_LEFT)
5110 hdi.fmt |= HDF_LEFT;
5112 else if (lpColumn->fmt & LVCFMT_RIGHT)
5114 hdi.fmt |= HDF_RIGHT;
5116 else if (lpColumn->fmt & LVCFMT_CENTER)
5118 hdi.fmt |= HDF_CENTER;
5122 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5124 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5128 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5133 if (lpColumn->fmt & LVCFMT_IMAGE)
5135 hdi.fmt |= HDF_IMAGE;
5136 hdi.iImage = I_IMAGECALLBACK;
5140 if (lpColumn->mask & LVCF_WIDTH)
5142 hdi.mask |= HDI_WIDTH;
5143 hdi.cxy = lpColumn->cx;
5146 if (lpColumn->mask & LVCF_TEXT)
5148 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5149 hdi.pszText = lpColumn->pszText;
5150 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5151 hdi.fmt |= HDF_STRING;
5154 if (lpColumn->mask & LVCF_IMAGE)
5156 hdi.mask |= HDI_IMAGE;
5157 hdi.iImage = lpColumn->iImage;
5160 if (lpColumn->mask & LVCF_ORDER)
5162 hdi.mask |= HDI_ORDER;
5163 hdi.iOrder = lpColumn->iOrder;
5166 /* insert item in header control */
5167 nNewColumn = SendMessageA(infoPtr->hwndHeader, HDM_INSERTITEMA,
5168 (WPARAM)nColumn, (LPARAM)&hdi);
5170 /* Need to reset the item width when inserting a new column */
5171 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
5173 LISTVIEW_UpdateScroll(hwnd);
5174 InvalidateRect(hwnd, NULL, FALSE);
5180 static LRESULT LISTVIEW_InsertColumnW(HWND hwnd, INT nColumn,
5181 LPLVCOLUMNW lpColumn)
5186 memcpy(&lvca,lpColumn,sizeof(lvca));
5187 if (lpColumn->mask & LVCF_TEXT)
5188 lvca.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpColumn->pszText);
5189 lres = LISTVIEW_InsertColumnA(hwnd,nColumn,&lvca);
5190 if (lpColumn->mask & LVCF_TEXT)
5191 HeapFree(GetProcessHeap(),0,lvca.pszText);
5195 /* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS
5196 in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem.
5197 This function should only be used for inserting items into a sorted list (LVM_INSERTITEM)
5198 and not during the processing of a LVM_SORTITEMS message. Applications should provide
5199 their own sort proc. when sending LVM_SORTITEMS.
5202 (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion...
5204 LVS_SORTXXX must be specified,
5205 LVS_OWNERDRAW is not set,
5206 <item>.pszText is not LPSTR_TEXTCALLBACK.
5208 (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices
5209 are sorted based on item text..."
5211 static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam)
5213 HDPA hdpa_first = (HDPA) first;
5214 HDPA hdpa_second = (HDPA) second;
5215 LISTVIEW_ITEM* lv_first = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_first, 0 );
5216 LISTVIEW_ITEM* lv_second = (LISTVIEW_ITEM*) DPA_GetPtr( hdpa_second, 0 );
5217 LONG lStyle = GetWindowLongA((HWND) lParam, GWL_STYLE);
5218 INT cmpv = lstrcmpA( lv_first->pszText, lv_second->pszText );
5219 /* if we're sorting descending, negate the return value */
5220 return (lStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv;
5225 * Inserts a new item in the listview control.
5228 * [I] HWND : window handle
5229 * [I] LPLVITEMA : item information
5232 * SUCCESS : new item index
5235 static LRESULT LISTVIEW_InsertItemA(HWND hwnd, LPLVITEMA lpLVItem)
5237 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5238 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5239 UINT uView = lStyle & LVS_TYPEMASK;
5240 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
5245 LISTVIEW_ITEM *lpItem = NULL;
5247 TRACE("(hwnd=%x,lpLVItem=%p)\n", hwnd, lpLVItem);
5249 if (lpLVItem != NULL)
5251 /* make sure it's not a subitem; cannot insert a subitem */
5252 if (lpLVItem->iSubItem == 0)
5254 lpItem = (LISTVIEW_ITEM *)COMCTL32_Alloc(sizeof(LISTVIEW_ITEM));
5257 ZeroMemory(lpItem, sizeof(LISTVIEW_ITEM));
5258 if (LISTVIEW_InitItem(hwnd, lpItem, lpLVItem) != FALSE)
5260 /* insert item in listview control data structure */
5261 hdpaSubItems = DPA_Create(8);
5262 if (hdpaSubItems != NULL)
5264 nItem = DPA_InsertPtr(hdpaSubItems, 0, lpItem);
5267 if ( ((lStyle & LVS_SORTASCENDING) || (lStyle & LVS_SORTDESCENDING))
5268 && !(lStyle & LVS_OWNERDRAWFIXED)
5269 && (LPSTR_TEXTCALLBACKA != lpLVItem->pszText) )
5271 /* Insert the item in the proper sort order based on the pszText
5272 member. See comments for LISTVIEW_InsertCompare() for greater detail */
5273 nItem = DPA_InsertPtr( infoPtr->hdpaItems,
5274 GETITEMCOUNT( infoPtr ) + 1, hdpaSubItems );
5275 DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, hwnd );
5276 nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems );
5280 nItem = DPA_InsertPtr(infoPtr->hdpaItems, lpLVItem->iItem,
5285 /* manage item focus */
5286 if (lpLVItem->mask & LVIF_STATE)
5288 lpItem->state &= ~(LVIS_FOCUSED|LVIS_SELECTED);
5289 if (lpLVItem->stateMask & LVIS_SELECTED)
5291 LISTVIEW_SetSelection(hwnd, nItem);
5293 else if (lpLVItem->stateMask & LVIS_FOCUSED)
5295 LISTVIEW_SetItemFocus(hwnd, nItem);
5299 /* send LVN_INSERTITEM notification */
5300 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
5301 nmlv.hdr.hwndFrom = hwnd;
5302 nmlv.hdr.idFrom = lCtrlId;
5303 nmlv.hdr.code = LVN_INSERTITEM;
5305 nmlv.lParam = lpItem->lParam;;
5306 ListView_LVNotify(GetParent(hwnd), lCtrlId, &nmlv);
5308 if ((uView == LVS_SMALLICON) || (uView == LVS_LIST))
5310 nItemWidth = LISTVIEW_CalculateWidth(hwnd, lpLVItem->iItem);
5311 if (nItemWidth > infoPtr->nItemWidth)
5313 infoPtr->nItemWidth = nItemWidth;
5317 /* align items (set position of each item) */
5318 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
5320 if (lStyle & LVS_ALIGNLEFT)
5322 LISTVIEW_AlignLeft(hwnd);
5326 LISTVIEW_AlignTop(hwnd);
5330 LISTVIEW_UpdateScroll(hwnd);
5331 /* refresh client area */
5332 InvalidateRect(hwnd, NULL, FALSE);
5341 /* free memory if unsuccessful */
5342 if ((nItem == -1) && (lpItem != NULL))
5344 COMCTL32_Free(lpItem);
5350 static LRESULT LISTVIEW_InsertItemW(HWND hwnd, LPLVITEMW lpLVItem) {
5354 memcpy(&lvia,lpLVItem,sizeof(LVITEMA));
5355 if (lvia.mask & LVIF_TEXT) {
5356 if (lpLVItem->pszText == LPSTR_TEXTCALLBACKW)
5357 lvia.pszText = LPSTR_TEXTCALLBACKA;
5359 lvia.pszText = HEAP_strdupWtoA(GetProcessHeap(),0,lpLVItem->pszText);
5361 lres = LISTVIEW_InsertItemA(hwnd, &lvia);
5362 if (lvia.mask & LVIF_TEXT) {
5363 if (lpLVItem->pszText != LPSTR_TEXTCALLBACKW)
5364 HeapFree(GetProcessHeap(),0,lvia.pszText);
5369 /* LISTVIEW_InsertItemW */
5373 * Redraws a range of items.
5376 * [I] HWND : window handle
5377 * [I] INT : first item
5378 * [I] INT : last item
5384 static LRESULT LISTVIEW_RedrawItems(HWND hwnd, INT nFirst, INT nLast)
5386 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5387 BOOL bResult = FALSE;
5390 if (nFirst <= nLast)
5392 if ((nFirst >= 0) && (nFirst < GETITEMCOUNT(infoPtr)))
5394 if ((nLast >= 0) && (nLast < GETITEMCOUNT(infoPtr)))
5397 InvalidateRect(hwnd, &rc, FALSE);
5405 /* LISTVIEW_Scroll */
5409 * Sets the background color.
5412 * [I] HWND : window handle
5413 * [I] COLORREF : background color
5419 static LRESULT LISTVIEW_SetBkColor(HWND hwnd, COLORREF clrBk)
5421 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5423 infoPtr->clrBk = clrBk;
5424 InvalidateRect(hwnd, NULL, TRUE);
5429 /* LISTVIEW_SetBkImage */
5433 * Sets the callback mask. This mask will be used when the parent
5434 * window stores state information (some or all).
5437 * [I] HWND : window handle
5438 * [I] UINT : state mask
5444 static BOOL LISTVIEW_SetCallbackMask(HWND hwnd, UINT uMask)
5446 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5448 infoPtr->uCallbackMask = uMask;
5455 * Sets the attributes of a header item.
5458 * [I] HWND : window handle
5459 * [I] INT : column index
5460 * [I] LPLVCOLUMNA : column attributes
5466 static LRESULT LISTVIEW_SetColumnA(HWND hwnd, INT nColumn,
5467 LPLVCOLUMNA lpColumn)
5469 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5470 BOOL bResult = FALSE;
5471 HDITEMA hdi, hdiget;
5473 if ((lpColumn != NULL) && (nColumn >= 0) &&
5474 (nColumn < Header_GetItemCount(infoPtr->hwndHeader)))
5476 /* initialize memory */
5477 ZeroMemory(&hdi, sizeof(HDITEMA));
5479 if (lpColumn->mask & LVCF_FMT)
5481 /* format member is valid */
5482 hdi.mask |= HDI_FORMAT;
5484 /* get current format first */
5485 hdiget.mask = HDI_FORMAT;
5486 if (Header_GetItemA(infoPtr->hwndHeader, nColumn, &hdiget))
5487 /* preserve HDF_STRING if present */
5488 hdi.fmt = hdiget.fmt & HDF_STRING;
5490 /* set text alignment (leftmost column must be left-aligned) */
5493 hdi.fmt |= HDF_LEFT;
5497 if (lpColumn->fmt & LVCFMT_LEFT)
5499 hdi.fmt |= HDF_LEFT;
5501 else if (lpColumn->fmt & LVCFMT_RIGHT)
5503 hdi.fmt |= HDF_RIGHT;
5505 else if (lpColumn->fmt & LVCFMT_CENTER)
5507 hdi.fmt |= HDF_CENTER;
5511 if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT)
5513 hdi.fmt |= HDF_BITMAP_ON_RIGHT;
5516 if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES)
5518 hdi.fmt |= HDF_IMAGE;
5521 if (lpColumn->fmt & LVCFMT_IMAGE)
5523 hdi.fmt |= HDF_IMAGE;
5524 hdi.iImage = I_IMAGECALLBACK;
5528 if (lpColumn->mask & LVCF_WIDTH)
5530 hdi.mask |= HDI_WIDTH;
5531 hdi.cxy = lpColumn->cx;
5534 if (lpColumn->mask & LVCF_TEXT)
5536 hdi.mask |= HDI_TEXT | HDI_FORMAT;
5537 hdi.pszText = lpColumn->pszText;
5538 hdi.cchTextMax = lstrlenA(lpColumn->pszText);
5539 hdi.fmt |= HDF_STRING;
5542 if (lpColumn->mask & LVCF_IMAGE)
5544 hdi.mask |= HDI_IMAGE;
5545 hdi.iImage = lpColumn->iImage;
5548 if (lpColumn->mask & LVCF_ORDER)
5550 hdi.mask |= HDI_ORDER;
5551 hdi.iOrder = lpColumn->iOrder;
5554 /* set header item attributes */
5555 bResult = Header_SetItemA(infoPtr->hwndHeader, nColumn, &hdi);
5561 /* LISTVIEW_SetColumnW */
5565 * Sets the column order array
5568 * [I] HWND : window handle
5569 * [I] INT : number of elements in column order array
5570 * [I] INT : pointer to column order array
5576 static LRESULT LISTVIEW_SetColumnOrderArray(HWND hwnd, INT iCount, LPINT lpiArray)
5578 /* LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0); */
5580 FIXME("iCount %d lpiArray %p\n", iCount, lpiArray);
5591 * Sets the width of a column
5594 * [I] HWND : window handle
5595 * [I] INT : column index
5596 * [I] INT : column width
5602 static LRESULT LISTVIEW_SetColumnWidth(HWND hwnd, INT iCol, INT cx)
5604 LISTVIEW_INFO *infoPtr;
5607 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
5608 UINT uView = lStyle & LVS_TYPEMASK;
5613 CHAR text_buffer[DISP_TEXT_SIZE];
5614 INT header_item_count;
5619 /* make sure we can get the listview info */
5620 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5623 if (!infoPtr->hwndHeader) /* make sure we have a header */
5626 /* set column width only if in report or list mode */
5627 if ((uView != LVS_REPORT) && (uView != LVS_LIST))
5630 /* take care of invalid cx values */
5631 if((uView == LVS_REPORT) && (cx < -2))
5632 cx = LVSCW_AUTOSIZE;
5633 else if (uView == LVS_LIST && (cx < 1))
5636 /* resize all columns if in LVS_LIST mode */
5637 if(uView == LVS_LIST) {
5638 infoPtr->nItemWidth = cx;
5639 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5643 /* autosize based on listview items width */
5644 if(cx == LVSCW_AUTOSIZE)
5646 /* set the width of the header to the width of the widest item */
5647 for(item_index = 0; item_index < GETITEMCOUNT(infoPtr); item_index++)
5649 if(cx < LISTVIEW_GetLabelWidth(hwnd, item_index))
5650 cx = LISTVIEW_GetLabelWidth(hwnd, item_index);
5652 } /* autosize based on listview header width */
5653 else if(cx == LVSCW_AUTOSIZE_USEHEADER)
5655 header_item_count = Header_GetItemCount(infoPtr->hwndHeader);
5657 /* if iCol is the last column make it fill the remainder of the controls width */
5658 if(iCol == (header_item_count - 1)) {
5659 /* get the width of every item except the current one */
5660 hdi.mask = HDI_WIDTH;
5663 for(item_index = 0; item_index < (header_item_count - 1); item_index++) {
5664 Header_GetItemA(infoPtr->hwndHeader, item_index, (LPARAM)(&hdi));
5668 /* retrieve the layout of the header */
5669 GetWindowRect(infoPtr->hwndHeader, &rcHeader);
5671 cx = (rcHeader.right - rcHeader.left) - cx;
5675 /* retrieve header font */
5676 header_font = SendMessageA(infoPtr->hwndHeader, WM_GETFONT, 0L, 0L);
5678 /* retrieve header text */
5679 hdi.mask = HDI_TEXT;
5680 hdi.cchTextMax = sizeof(text_buffer);
5681 hdi.pszText = text_buffer;
5683 Header_GetItemA(infoPtr->hwndHeader, iCol, (LPARAM)(&hdi));
5685 /* determine the width of the text in the header */
5687 old_font = SelectObject(hdc, header_font); /* select the font into hdc */
5689 GetTextExtentPoint32A(hdc, text_buffer, strlen(text_buffer), &size);
5691 SelectObject(hdc, old_font); /* restore the old font */
5692 ReleaseDC(hwnd, hdc);
5694 /* set the width of this column to the width of the text */
5699 /* call header to update the column change */
5700 hdi.mask = HDI_WIDTH;
5703 lret = Header_SetItemA(infoPtr->hwndHeader, (WPARAM)iCol, (LPARAM)&hdi);
5705 InvalidateRect(hwnd, NULL, TRUE); /* force redraw of the listview */
5712 * Sets the extended listview style.
5715 * [I] HWND : window handle
5720 * SUCCESS : previous style
5723 static LRESULT LISTVIEW_SetExtendedListViewStyle(HWND hwnd, DWORD dwMask, DWORD dwStyle)
5725 LISTVIEW_INFO *infoPtr;
5728 /* make sure we can get the listview info */
5729 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5732 /* store previous style */
5733 dwOldStyle = infoPtr->dwExStyle;
5736 infoPtr->dwExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask);
5738 return (dwOldStyle);
5741 /* LISTVIEW_SetHotCursor */
5745 * Sets the hot item index.
5748 * [I] HWND : window handle
5752 * SUCCESS : previous hot item index
5753 * FAILURE : -1 (no hot item)
5755 static LRESULT LISTVIEW_SetHotItem(HWND hwnd, INT iIndex)
5757 LISTVIEW_INFO *infoPtr;
5760 /* make sure we can get the listview info */
5761 if (!(infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0)))
5764 /* store previous index */
5765 iOldIndex = infoPtr->nHotItem;
5768 infoPtr->nHotItem = iIndex;
5775 * Sets the amount of time the cursor must hover over an item before it is selected.
5778 * [I] HWND : window handle
5779 * [I] DWORD : dwHoverTime, if -1 the hover time is set to the default
5782 * Returns the previous hover time
5784 static LRESULT LISTVIEW_SetHoverTime(HWND hwnd, DWORD dwHoverTime)
5786 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5787 DWORD oldHoverTime = infoPtr->dwHoverTime;
5789 infoPtr->dwHoverTime = dwHoverTime;
5791 return oldHoverTime;
5794 /* LISTVIEW_SetIconSpacing */
5801 * [I] HWND : window handle
5802 * [I] INT : image list type
5803 * [I] HIMAGELIST : image list handle
5806 * SUCCESS : old image list
5809 static LRESULT LISTVIEW_SetImageList(HWND hwnd, INT nType, HIMAGELIST himl)
5811 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5812 HIMAGELIST himlTemp = 0;
5817 himlTemp = infoPtr->himlNormal;
5818 infoPtr->himlNormal = himl;
5819 return (LRESULT)himlTemp;
5822 himlTemp = infoPtr->himlSmall;
5823 infoPtr->himlSmall = himl;
5824 return (LRESULT)himlTemp;
5827 himlTemp = infoPtr->himlState;
5828 infoPtr->himlState = himl;
5829 ImageList_SetBkColor(infoPtr->himlState, CLR_NONE);
5830 return (LRESULT)himlTemp;
5833 return (LRESULT)NULL;
5839 * Sets the attributes of an item.
5842 * [I] HWND : window handle
5843 * [I] LPLVITEM : item information
5849 static LRESULT LISTVIEW_SetItemA(HWND hwnd, LPLVITEMA lpLVItem)
5851 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5852 BOOL bResult = FALSE;
5854 if (lpLVItem != NULL)
5856 if ((lpLVItem->iItem >= 0) && (lpLVItem->iItem < GETITEMCOUNT(infoPtr)))
5858 if (lpLVItem->iSubItem == 0)
5860 bResult = LISTVIEW_SetItem(hwnd, lpLVItem);
5864 bResult = LISTVIEW_SetSubItem(hwnd, lpLVItem);
5873 /* LISTVIEW_SetItemW */
5877 * Preallocates memory.
5880 * [I] HWND : window handle
5881 * [I] INT : item count (projected number of items)
5882 * [I] DWORD : update flags
5888 static BOOL LISTVIEW_SetItemCount(HWND hwnd, INT nItems, DWORD dwFlags)
5890 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5892 FIXME("(%d %08lx)stub!\n", nItems, dwFlags);
5895 return LISTVIEW_DeleteAllItems (hwnd);
5897 if (GetWindowLongA(hwnd, GWL_STYLE) & LVS_OWNERDATA)
5899 FIXME("LVS_OWNERDATA is set!\n");
5903 if (nItems > GETITEMCOUNT(infoPtr))
5906 FIXME("append items\n");
5909 else if (nItems < GETITEMCOUNT(infoPtr))
5912 while(nItems < GETITEMCOUNT(infoPtr)) {
5913 LISTVIEW_DeleteItem(hwnd, GETITEMCOUNT(infoPtr) - 1);
5923 * Sets the position of an item.
5926 * [I] HWND : window handle
5927 * [I] INT : item index
5928 * [I] INT : x coordinate
5929 * [I] INT : y coordinate
5935 static BOOL LISTVIEW_SetItemPosition(HWND hwnd, INT nItem,
5936 INT nPosX, INT nPosY)
5938 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
5939 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
5940 LISTVIEW_ITEM *lpItem;
5942 BOOL bResult = FALSE;
5944 TRACE("(hwnd=%x,nItem=%d,X=%d,Y=%d)\n", hwnd, nItem, nPosX, nPosY);
5946 if ((nItem >= 0) || (nItem < GETITEMCOUNT(infoPtr)))
5948 if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
5950 hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem);
5951 if (hdpaSubItems != NULL)
5953 lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
5957 lpItem->ptPosition.x = nPosX;
5958 lpItem->ptPosition.y = nPosY;
5967 /* LISTVIEW_SetItemPosition32 */
5971 * Sets the state of one or many items.
5974 * [I] HWND : window handle
5975 * [I]INT : item index
5976 * [I] LPLVITEM : item or subitem info
5982 static LRESULT LISTVIEW_SetItemState(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
5984 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
5985 BOOL bResult = FALSE;
5992 ZeroMemory(&lvItem, sizeof(LVITEMA));
5993 lvItem.mask = LVIF_STATE;
5994 lvItem.state = lpLVItem->state;
5995 lvItem.stateMask = lpLVItem->stateMask ;
5997 /* apply to all items */
5998 for (i = 0; i< GETITEMCOUNT(infoPtr); i++)
6001 if (ListView_SetItemA(hwnd, &lvItem) == FALSE)
6009 ZeroMemory(&lvItem, sizeof(LVITEMA));
6010 lvItem.mask = LVIF_STATE;
6011 lvItem.state = lpLVItem->state;
6012 lvItem.stateMask = lpLVItem->stateMask;
6013 lvItem.iItem = nItem;
6014 bResult = ListView_SetItemA(hwnd, &lvItem);
6022 * Sets the text of an item or subitem.
6025 * [I] HWND : window handle
6026 * [I] INT : item index
6027 * [I] LPLVITEMA : item or subitem info
6033 static BOOL LISTVIEW_SetItemTextA(HWND hwnd, INT nItem, LPLVITEMA lpLVItem)
6035 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6036 BOOL bResult = FALSE;
6039 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6041 ZeroMemory(&lvItem, sizeof(LVITEMA));
6042 lvItem.mask = LVIF_TEXT;
6043 lvItem.pszText = lpLVItem->pszText;
6044 lvItem.iItem = nItem;
6045 lvItem.iSubItem = lpLVItem->iSubItem;
6046 bResult = ListView_SetItemA(hwnd, &lvItem);
6052 /* LISTVIEW_SetItemTextW */
6056 * Set item index that marks the start of a multiple selection.
6059 * [I] HWND : window handle
6063 * Index number or -1 if there is no selection mark.
6065 static LRESULT LISTVIEW_SetSelectionMark(HWND hwnd, INT nIndex)
6067 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6068 INT nOldIndex = infoPtr->nSelectionMark;
6070 infoPtr->nSelectionMark = nIndex;
6077 * Sets the text background color.
6080 * [I] HWND : window handle
6081 * [I] COLORREF : text background color
6087 static LRESULT LISTVIEW_SetTextBkColor(HWND hwnd, COLORREF clrTextBk)
6089 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6091 infoPtr->clrTextBk = clrTextBk;
6092 InvalidateRect(hwnd, NULL, TRUE);
6099 * Sets the text foreground color.
6102 * [I] HWND : window handle
6103 * [I] COLORREF : text color
6109 static LRESULT LISTVIEW_SetTextColor (HWND hwnd, COLORREF clrText)
6111 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6113 infoPtr->clrText = clrText;
6114 InvalidateRect(hwnd, NULL, TRUE);
6119 /* LISTVIEW_SetToolTips */
6120 /* LISTVIEW_SetUnicodeFormat */
6121 /* LISTVIEW_SetWorkAreas */
6125 * Callback internally used by LISTVIEW_SortItems()
6128 * [I] LPVOID : first LISTVIEW_ITEM to compare
6129 * [I] LPVOID : second LISTVIEW_ITEM to compare
6130 * [I] LPARAM : HWND of control
6133 * if first comes before second : negative
6134 * if first comes after second : positive
6135 * if first and second are equivalent : zero
6137 static INT WINAPI LISTVIEW_CallBackCompare(
6142 /* Forward the call to the client defined callback */
6144 HWND hwnd = (HWND)lParam;
6145 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6147 rv = (infoPtr->pfnCompare)( ((LISTVIEW_ITEM*) first)->lParam,
6148 ((LISTVIEW_ITEM*) second)->lParam, infoPtr->lParamSort );
6155 * Sorts the listview items.
6158 * [I] HWND : window handle
6159 * [I] WPARAM : application-defined value
6160 * [I] LPARAM : pointer to comparision callback
6166 static LRESULT LISTVIEW_SortItems(HWND hwnd, WPARAM wParam, LPARAM lParam)
6168 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6170 LISTVIEW_ITEM *lpItem;
6174 if (!infoPtr || !infoPtr->hdpaItems)
6177 nCount = GETITEMCOUNT(infoPtr);
6178 /* if there are 0 or 1 items, there is no need to sort */
6181 sortList = DPA_Create(nCount);
6183 infoPtr->pfnCompare = (PFNLVCOMPARE)lParam;
6184 infoPtr->lParamSort = (LPARAM)wParam;
6186 /* append pointers one by one to sortList */
6187 for (i = 0; i < nCount; i++)
6189 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)))
6190 if ((lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(hdpaSubItems, 0)))
6191 DPA_InsertPtr(sortList, nCount + 1, lpItem);
6194 /* sort the sortList */
6195 DPA_Sort(sortList, LISTVIEW_CallBackCompare, hwnd);
6197 /* copy the pointers back */
6198 for (i = 0; i < nCount; i++)
6200 if ((hdpaSubItems = (HDPA) DPA_GetPtr(infoPtr->hdpaItems, i)) &&
6201 (lpItem = (LISTVIEW_ITEM *) DPA_GetPtr(sortList, i)))
6202 DPA_SetPtr(hdpaSubItems, 0, lpItem);
6205 DPA_Destroy(sortList);
6211 /* LISTVIEW_SubItemHitTest */
6215 * Updates an items or rearranges the listview control.
6218 * [I] HWND : window handle
6219 * [I] INT : item index
6225 static LRESULT LISTVIEW_Update(HWND hwnd, INT nItem)
6227 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6228 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6229 BOOL bResult = FALSE;
6232 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6236 /* rearrange with default alignment style */
6237 if ((lStyle & LVS_AUTOARRANGE) && (((lStyle & LVS_TYPEMASK) == LVS_ICON) ||
6238 ((lStyle & LVS_TYPEMASK) == LVS_SMALLICON)))
6240 ListView_Arrange(hwnd, 0);
6244 /* get item bounding rectangle */
6245 rc.left = LVIR_BOUNDS;
6246 ListView_GetItemRect(hwnd, nItem, &rc);
6247 InvalidateRect(hwnd, &rc, TRUE);
6256 * Creates the listview control.
6259 * [I] HWND : window handle
6264 static LRESULT LISTVIEW_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
6266 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6267 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam;
6268 UINT uView = lpcs->style & LVS_TYPEMASK;
6271 /* initialize info pointer */
6272 ZeroMemory(infoPtr, sizeof(LISTVIEW_INFO));
6274 /* determine the type of structures to use */
6275 infoPtr->notifyFormat = SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT,
6276 (WPARAM)hwnd, (LPARAM)NF_QUERY);
6277 if (infoPtr->notifyFormat != NFR_ANSI)
6279 FIXME("ANSI notify format is NOT used\n");
6282 /* initialize color information */
6283 infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
6284 infoPtr->clrText = GetSysColor(COLOR_WINDOWTEXT);
6285 infoPtr->clrTextBk = GetSysColor(COLOR_WINDOW);
6287 /* set default values */
6288 infoPtr->uCallbackMask = 0;
6289 infoPtr->nFocusedItem = -1;
6290 infoPtr->nSelectionMark = -1;
6291 infoPtr->nHotItem = -1;
6292 infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING);
6293 infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING);
6294 ZeroMemory(&infoPtr->rcList, sizeof(RECT));
6295 infoPtr->hwndEdit = 0;
6296 infoPtr->pedititem = NULL;
6297 infoPtr->bDoEditLabel = FALSE;
6299 /* get default font (icon title) */
6300 SystemParametersInfoA(SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
6301 infoPtr->hDefaultFont = CreateFontIndirectA(&logFont);
6302 infoPtr->hFont = infoPtr->hDefaultFont;
6305 infoPtr->hwndHeader = CreateWindowA(WC_HEADERA, (LPCSTR)NULL,
6306 WS_CHILD | HDS_HORZ | HDS_BUTTONS,
6307 0, 0, 0, 0, hwnd, (HMENU)0,
6308 lpcs->hInstance, NULL);
6310 /* set header font */
6311 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont,
6314 if (uView == LVS_ICON)
6316 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
6317 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
6319 else if (uView == LVS_REPORT)
6321 if (!(LVS_NOCOLUMNHEADER & lpcs->style))
6323 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
6327 /* resize our header to nothing */
6331 memset(&zeroRect,0,sizeof(RECT));
6335 Header_Layout(infoPtr->hwndHeader,&hd);
6339 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6340 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6344 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
6345 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
6348 /* display unsupported listview window styles */
6349 LISTVIEW_UnsupportedStyles(lpcs->style);
6351 /* allocate memory for the data structure */
6352 infoPtr->hdpaItems = DPA_Create(10);
6354 /* initialize size of items */
6355 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
6356 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
6358 /* initialize the hover time to -1(indicating the default system hover time) */
6359 infoPtr->dwHoverTime = -1;
6366 * Erases the background of the listview control.
6369 * [I] HWND : window handle
6370 * [I] WPARAM : device context handle
6371 * [I] LPARAM : not used
6377 static LRESULT LISTVIEW_EraseBackground(HWND hwnd, WPARAM wParam,
6380 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6383 if (infoPtr->clrBk == CLR_NONE)
6385 bResult = SendMessageA(GetParent(hwnd), WM_ERASEBKGND, wParam, lParam);
6390 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
6391 GetClientRect(hwnd, &rc);
6392 FillRect((HDC)wParam, &rc, hBrush);
6393 DeleteObject(hBrush);
6402 * Retrieves the listview control font.
6405 * [I] HWND : window handle
6410 static LRESULT LISTVIEW_GetFont(HWND hwnd)
6412 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6414 return infoPtr->hFont;
6419 * Performs vertical scrolling.
6422 * [I] HWND : window handle
6423 * [I] INT : scroll code
6424 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6426 * [I] HWND : scrollbar control window handle
6431 static LRESULT LISTVIEW_VScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6434 SCROLLINFO scrollInfo;
6436 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6437 scrollInfo.cbSize = sizeof(SCROLLINFO);
6438 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6440 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6442 INT nOldScrollPos = scrollInfo.nPos;
6443 switch (nScrollCode)
6446 if (scrollInfo.nPos > scrollInfo.nMin)
6453 if (scrollInfo.nPos < scrollInfo.nMax)
6460 if (scrollInfo.nPos > scrollInfo.nMin)
6462 if (scrollInfo.nPos >= scrollInfo.nPage)
6464 scrollInfo.nPos -= scrollInfo.nPage;
6468 scrollInfo.nPos = scrollInfo.nMin;
6474 if (scrollInfo.nPos < scrollInfo.nMax)
6476 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6478 scrollInfo.nPos += scrollInfo.nPage;
6482 scrollInfo.nPos = scrollInfo.nMax;
6488 scrollInfo.nPos = nCurrentPos;
6489 if (scrollInfo.nPos > scrollInfo.nMax)
6490 scrollInfo.nPos=scrollInfo.nMax;
6492 if (scrollInfo.nPos < scrollInfo.nMin)
6493 scrollInfo.nPos=scrollInfo.nMin;
6498 if (nOldScrollPos != scrollInfo.nPos)
6500 scrollInfo.fMask = SIF_POS;
6501 SetScrollInfo(hwnd, SB_VERT, &scrollInfo, TRUE);
6502 InvalidateRect(hwnd, NULL, TRUE);
6511 * Performs horizontal scrolling.
6514 * [I] HWND : window handle
6515 * [I] INT : scroll code
6516 * [I] SHORT : current scroll position if scroll code is SB_THIMBPOSITION
6518 * [I] HWND : scrollbar control window handle
6523 static LRESULT LISTVIEW_HScroll(HWND hwnd, INT nScrollCode, SHORT nCurrentPos,
6526 SCROLLINFO scrollInfo;
6528 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6529 scrollInfo.cbSize = sizeof(SCROLLINFO);
6530 scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
6532 if (GetScrollInfo(hwnd, SB_HORZ, &scrollInfo) != FALSE)
6534 INT nOldScrollPos = scrollInfo.nPos;
6536 switch (nScrollCode)
6539 if (scrollInfo.nPos > scrollInfo.nMin)
6546 if (scrollInfo.nPos < scrollInfo.nMax)
6553 if (scrollInfo.nPos > scrollInfo.nMin)
6555 if (scrollInfo.nPos >= scrollInfo.nPage)
6557 scrollInfo.nPos -= scrollInfo.nPage;
6561 scrollInfo.nPos = scrollInfo.nMin;
6567 if (scrollInfo.nPos < scrollInfo.nMax)
6569 if (scrollInfo.nPos <= scrollInfo.nMax - scrollInfo.nPage)
6571 scrollInfo.nPos += scrollInfo.nPage;
6575 scrollInfo.nPos = scrollInfo.nMax;
6581 scrollInfo.nPos = nCurrentPos;
6583 if (scrollInfo.nPos > scrollInfo.nMax)
6584 scrollInfo.nPos=scrollInfo.nMax;
6586 if (scrollInfo.nPos < scrollInfo.nMin)
6587 scrollInfo.nPos=scrollInfo.nMin;
6591 if (nOldScrollPos != scrollInfo.nPos)
6593 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6594 scrollInfo.fMask = SIF_POS;
6595 SetScrollInfo(hwnd, SB_HORZ, &scrollInfo, TRUE);
6596 if(uView == LVS_REPORT)
6598 scrollInfo.fMask = SIF_POS;
6599 GetScrollInfo(hwnd, SB_HORZ, &scrollInfo);
6600 LISTVIEW_UpdateHeaderSize(hwnd, scrollInfo.nPos);
6602 InvalidateRect(hwnd, NULL, TRUE);
6609 static LRESULT LISTVIEW_MouseWheel(HWND hwnd, INT wheelDelta)
6611 INT gcWheelDelta = 0;
6612 UINT pulScrollLines = 3;
6613 SCROLLINFO scrollInfo;
6615 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
6617 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
6618 gcWheelDelta -= wheelDelta;
6620 ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
6621 scrollInfo.cbSize = sizeof(SCROLLINFO);
6622 scrollInfo.fMask = SIF_POS | SIF_RANGE;
6629 * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number
6630 * should be fixed in the future.
6632 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6633 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + (gcWheelDelta < 0) ? 37 : -37, 0);
6637 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
6639 if (GetScrollInfo(hwnd, SB_VERT, &scrollInfo) != FALSE)
6641 int cLineScroll = min(LISTVIEW_GetCountPerColumn(hwnd), pulScrollLines);
6642 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
6643 LISTVIEW_VScroll(hwnd, SB_THUMBPOSITION, scrollInfo.nPos + cLineScroll, 0);
6649 LISTVIEW_HScroll(hwnd, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0);
6660 * [I] HWND : window handle
6661 * [I] INT : virtual key
6662 * [I] LONG : key data
6667 static LRESULT LISTVIEW_KeyDown(HWND hwnd, INT nVirtualKey, LONG lKeyData)
6669 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6670 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6671 HWND hwndParent = GetParent(hwnd);
6672 NMLVKEYDOWN nmKeyDown;
6675 BOOL bRedraw = FALSE;
6677 /* send LVN_KEYDOWN notification */
6678 ZeroMemory(&nmKeyDown, sizeof(NMLVKEYDOWN));
6679 nmKeyDown.hdr.hwndFrom = hwnd;
6680 nmKeyDown.hdr.idFrom = nCtrlId;
6681 nmKeyDown.hdr.code = LVN_KEYDOWN;
6682 nmKeyDown.wVKey = nVirtualKey;
6683 nmKeyDown.flags = 0;
6684 SendMessageA(hwndParent, WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)&nmKeyDown);
6687 nmh.hwndFrom = hwnd;
6688 nmh.idFrom = nCtrlId;
6690 switch (nVirtualKey)
6693 if ((GETITEMCOUNT(infoPtr) > 0) && (infoPtr->nFocusedItem != -1))
6695 /* send NM_RETURN notification */
6696 nmh.code = NM_RETURN;
6697 ListView_Notify(hwndParent, nCtrlId, &nmh);
6699 /* send LVN_ITEMACTIVATE notification */
6700 nmh.code = LVN_ITEMACTIVATE;
6701 ListView_Notify(hwndParent, nCtrlId, &nmh);
6706 if (GETITEMCOUNT(infoPtr) > 0)
6713 if (GETITEMCOUNT(infoPtr) > 0)
6715 nItem = GETITEMCOUNT(infoPtr) - 1;
6720 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TOLEFT);
6724 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_ABOVE);
6728 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_TORIGHT);
6732 nItem = ListView_GetNextItem(hwnd, infoPtr->nFocusedItem, LVNI_BELOW);
6744 if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
6746 bRedraw = LISTVIEW_KeySelection(hwnd, nItem);
6747 if (bRedraw != FALSE)
6749 /* refresh client area */
6750 InvalidateRect(hwnd, NULL, TRUE);
6763 * [I] HWND : window handle
6768 static LRESULT LISTVIEW_KillFocus(HWND hwnd)
6770 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)GetWindowLongA(hwnd, 0);
6771 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6774 TRACE("(hwnd=%x)\n", hwnd);
6776 /* send NM_KILLFOCUS notification */
6777 nmh.hwndFrom = hwnd;
6778 nmh.idFrom = nCtrlId;
6779 nmh.code = NM_KILLFOCUS;
6780 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6782 /* set window focus flag */
6783 infoPtr->bFocus = FALSE;
6785 /* NEED drawing optimization ; redraw the selected items */
6786 InvalidateRect(hwnd, NULL, FALSE);
6793 * Processes double click messages (left mouse button).
6796 * [I] HWND : window handle
6797 * [I] WORD : key flag
6798 * [I] WORD : x coordinate
6799 * [I] WORD : y coordinate
6804 static LRESULT LISTVIEW_LButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
6807 LONG nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6809 LVHITTESTINFO htInfo;
6811 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6813 /* send NM_DBLCLK notification */
6814 nmh.hwndFrom = hwnd;
6815 nmh.idFrom = nCtrlId;
6816 nmh.code = NM_DBLCLK;
6817 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6819 /* To send the LVN_ITEMACTIVATE, it must be on an Item */
6820 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6821 htInfo.pt.x = wPosX;
6822 htInfo.pt.y = wPosY;
6823 if(LISTVIEW_HitTest(hwnd, &htInfo) != -1)
6825 /* send LVN_ITEMACTIVATE notification */
6826 nmh.code = LVN_ITEMACTIVATE;
6827 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6835 * Processes mouse down messages (left mouse button).
6838 * [I] HWND : window handle
6839 * [I] WORD : key flag
6840 * [I] WORD : x coordinate
6841 * [I] WORD : y coordinate
6846 static LRESULT LISTVIEW_LButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
6849 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6850 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
6851 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6852 static BOOL bGroupSelect = TRUE;
6857 TRACE("(hwnd=%x, key=%hu, X=%hu, Y=%hu)\n", hwnd, wKey, wPosX,
6860 /* send NM_RELEASEDCAPTURE notification */
6861 nmh.hwndFrom = hwnd;
6862 nmh.idFrom = nCtrlId;
6863 nmh.code = NM_RELEASEDCAPTURE;
6864 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6866 if (infoPtr->bFocus == FALSE)
6871 /* set left button down flag */
6872 infoPtr->bLButtonDown = TRUE;
6874 ptPosition.x = wPosX;
6875 ptPosition.y = wPosY;
6876 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
6877 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
6879 if (lStyle & LVS_SINGLESEL)
6881 if ((ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED)
6882 && infoPtr->bDoEditLabel != TRUE)
6884 infoPtr->bDoEditLabel = TRUE;
6888 LISTVIEW_SetSelection(hwnd, nItem);
6893 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
6895 if (bGroupSelect != FALSE)
6897 LISTVIEW_AddGroupSelection(hwnd, nItem);
6901 LISTVIEW_AddSelection(hwnd, nItem);
6904 else if (wKey & MK_CONTROL)
6906 bGroupSelect = LISTVIEW_ToggleSelection(hwnd, nItem);
6908 else if (wKey & MK_SHIFT)
6910 LISTVIEW_SetGroupSelection(hwnd, nItem);
6914 if (ListView_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED
6915 && infoPtr->bDoEditLabel != TRUE)
6917 infoPtr->bDoEditLabel = TRUE;
6921 LISTVIEW_SetSelection(hwnd, nItem);
6929 /* remove all selections */
6930 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
6933 InvalidateRect(hwnd, NULL, TRUE);
6940 * Processes mouse up messages (left mouse button).
6943 * [I] HWND : window handle
6944 * [I] WORD : key flag
6945 * [I] WORD : x coordinate
6946 * [I] WORD : y coordinate
6951 static LRESULT LISTVIEW_LButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
6954 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
6956 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
6958 if (infoPtr->bLButtonDown != FALSE)
6960 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
6963 /* send NM_CLICK notification */
6964 nmh.hwndFrom = hwnd;
6965 nmh.idFrom = nCtrlId;
6966 nmh.code = NM_CLICK;
6967 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
6969 /* set left button flag */
6970 infoPtr->bLButtonDown = FALSE;
6972 if(infoPtr->bDoEditLabel)
6974 LVHITTESTINFO htInfo;
6976 ZeroMemory(&htInfo, sizeof(LVHITTESTINFO));
6977 htInfo.pt.x = wPosX;
6978 htInfo.pt.y = wPosY;
6979 nItem = LISTVIEW_HitTest(hwnd, &htInfo);
6980 if(nItem != -1 && htInfo.flags == LVHT_ONITEMLABEL)
6982 LISTVIEW_EditLabelA(hwnd, nItem);
6984 infoPtr->bDoEditLabel = FALSE;
6993 * Creates the listview control (called before WM_CREATE).
6996 * [I] HWND : window handle
6997 * [I] WPARAM : unhandled
6998 * [I] LPARAM : widow creation info
7003 static LRESULT LISTVIEW_NCCreate(HWND hwnd, WPARAM wParam, LPARAM lParam)
7005 LISTVIEW_INFO *infoPtr;
7007 TRACE("(hwnd=%x,wParam=%x,lParam=%lx)\n", hwnd, wParam, lParam);
7009 /* allocate memory for info structure */
7010 infoPtr = (LISTVIEW_INFO *)COMCTL32_Alloc(sizeof(LISTVIEW_INFO));
7011 SetWindowLongA(hwnd, 0, (LONG)infoPtr);
7012 if (infoPtr == NULL)
7014 ERR("could not allocate info memory!\n");
7018 if ((LISTVIEW_INFO *)GetWindowLongA(hwnd, 0) != infoPtr)
7020 ERR("pointer assignment error!\n");
7024 return DefWindowProcA(hwnd, WM_NCCREATE, wParam, lParam);
7029 * Destroys the listview control (called after WM_DESTROY).
7032 * [I] HWND : window handle
7037 static LRESULT LISTVIEW_NCDestroy(HWND hwnd)
7039 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7041 TRACE("(hwnd=%x)\n", hwnd);
7043 /* delete all items */
7044 LISTVIEW_DeleteAllItems(hwnd);
7046 /* destroy data structure */
7047 DPA_Destroy(infoPtr->hdpaItems);
7050 infoPtr->hFont = (HFONT)0;
7051 if (infoPtr->hDefaultFont)
7053 DeleteObject(infoPtr->hDefaultFont);
7056 /* free listview info pointer*/
7057 COMCTL32_Free(infoPtr);
7059 SetWindowLongA(hwnd, 0, 0);
7065 * Handles notifications from children.
7068 * [I] HWND : window handle
7069 * [I] INT : control identifier
7070 * [I] LPNMHDR : notification information
7075 static LRESULT LISTVIEW_Notify(HWND hwnd, INT nCtrlId, LPNMHDR lpnmh)
7077 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7079 if (lpnmh->hwndFrom == infoPtr->hwndHeader)
7081 /* handle notification from header control */
7082 if (lpnmh->code == HDN_ENDTRACKA)
7084 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7085 InvalidateRect(hwnd, NULL, TRUE);
7087 else if(lpnmh->code == HDN_ITEMCLICKA)
7089 /* Handle sorting by Header Column */
7091 LPNMHEADERA pnmHeader = (LPNMHEADERA) lpnmh;
7092 LONG lCtrlId = GetWindowLongA(hwnd, GWL_ID);
7094 ZeroMemory(&nmlv, sizeof(NMLISTVIEW));
7095 nmlv.hdr.hwndFrom = hwnd;
7096 nmlv.hdr.idFrom = lCtrlId;
7097 nmlv.hdr.code = LVN_COLUMNCLICK;
7099 nmlv.iSubItem = pnmHeader->iItem;
7101 ListView_LVNotify(GetParent(hwnd),lCtrlId, &nmlv);
7104 else if(lpnmh->code == NM_RELEASEDCAPTURE)
7106 /* Idealy this should be done in HDN_ENDTRACKA
7107 * but since SetItemBounds in Header.c is called after
7108 * the notification is sent, it is neccessary to handle the
7109 * update of the scroll bar here (Header.c works fine as it is,
7110 * no need to disturb it)
7112 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7113 LISTVIEW_UpdateScroll(hwnd);
7114 InvalidateRect(hwnd, NULL, TRUE);
7124 * Determines the type of structure to use.
7127 * [I] HWND : window handle of the sender
7128 * [I] HWND : listview window handle
7129 * [I] INT : command specifying the nature of the WM_NOTIFYFORMAT
7134 static LRESULT LISTVIEW_NotifyFormat(HWND hwndFrom, HWND hwnd, INT nCommand)
7136 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7138 if (nCommand == NF_REQUERY)
7140 /* determine the type of structure to use */
7141 infoPtr->notifyFormat = SendMessageA(hwndFrom, WM_NOTIFYFORMAT,
7142 (WPARAM)hwnd, (LPARAM)NF_QUERY);
7143 if (infoPtr->notifyFormat == NFR_UNICODE)
7145 FIXME("NO support for unicode structures");
7154 * Paints/Repaints the listview control.
7157 * [I] HWND : window handle
7158 * [I] HDC : device context handle
7163 static LRESULT LISTVIEW_Paint(HWND hwnd, HDC hdc)
7167 TRACE("(hwnd=%x,hdc=%x)\n", hwnd, hdc);
7171 hdc = BeginPaint(hwnd, &ps);
7172 LISTVIEW_Refresh(hwnd, hdc);
7173 EndPaint(hwnd, &ps);
7177 LISTVIEW_Refresh(hwnd, hdc);
7185 * Processes double click messages (right mouse button).
7188 * [I] HWND : window handle
7189 * [I] WORD : key flag
7190 * [I] WORD : x coordinate
7191 * [I] WORD : y coordinate
7196 static LRESULT LISTVIEW_RButtonDblClk(HWND hwnd, WORD wKey, WORD wPosX,
7199 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7202 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
7204 /* send NM_RELEASEDCAPTURE notification */
7205 nmh.hwndFrom = hwnd;
7206 nmh.idFrom = nCtrlId;
7207 nmh.code = NM_RELEASEDCAPTURE;
7208 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7210 /* send NM_RDBLCLK notification */
7211 nmh.code = NM_RDBLCLK;
7212 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7219 * Processes mouse down messages (right mouse button).
7222 * [I] HWND : window handle
7223 * [I] WORD : key flag
7224 * [I] WORD : x coordinate
7225 * [I] WORD : y coordinate
7230 static LRESULT LISTVIEW_RButtonDown(HWND hwnd, WORD wKey, WORD wPosX,
7233 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7234 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7239 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
7241 /* send NM_RELEASEDCAPTURE notification */
7242 nmh.hwndFrom = hwnd;
7243 nmh.idFrom = nCtrlId;
7244 nmh.code = NM_RELEASEDCAPTURE;
7245 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7247 /* make sure the listview control window has the focus */
7248 if (infoPtr->bFocus == FALSE)
7253 /* set right button down flag */
7254 infoPtr->bRButtonDown = TRUE;
7256 /* determine the index of the selected item */
7257 ptPosition.x = wPosX;
7258 ptPosition.y = wPosY;
7259 nItem = LISTVIEW_MouseSelection(hwnd, ptPosition);
7260 if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
7262 if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)))
7264 LISTVIEW_SetSelection(hwnd, nItem);
7269 LISTVIEW_RemoveSelections(hwnd, 0, GETITEMCOUNT(infoPtr));
7277 * Processes mouse up messages (right mouse button).
7280 * [I] HWND : window handle
7281 * [I] WORD : key flag
7282 * [I] WORD : x coordinate
7283 * [I] WORD : y coordinate
7288 static LRESULT LISTVIEW_RButtonUp(HWND hwnd, WORD wKey, WORD wPosX,
7291 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7292 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7295 TRACE("(hwnd=%x,key=%hu,X=%hu,Y=%hu)\n", hwnd, wKey, wPosX, wPosY);
7297 if (infoPtr->bRButtonDown != FALSE)
7303 /* Send NM_RClICK notification */
7304 ZeroMemory(&nmh, sizeof(NMHDR));
7305 nmh.hwndFrom = hwnd;
7306 nmh.idFrom = nCtrlId;
7307 nmh.code = NM_RCLICK;
7308 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7310 /* set button flag */
7311 infoPtr->bRButtonDown = FALSE;
7313 /* Change to screen coordinate for WM_CONTEXTMENU */
7314 ClientToScreen(hwnd, &pt);
7316 /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
7317 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
7328 * [I] HWND : window handle
7329 * [I] HWND : window handle of previously focused window
7334 static LRESULT LISTVIEW_SetFocus(HWND hwnd, HWND hwndLoseFocus)
7336 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7337 INT nCtrlId = GetWindowLongA(hwnd, GWL_ID);
7340 TRACE("(hwnd=%x, hwndLoseFocus=%x)\n", hwnd, hwndLoseFocus);
7342 /* send NM_SETFOCUS notification */
7343 nmh.hwndFrom = hwnd;
7344 nmh.idFrom = nCtrlId;
7345 nmh.code = NM_SETFOCUS;
7346 ListView_Notify(GetParent(hwnd), nCtrlId, &nmh);
7348 /* set window focus flag */
7349 infoPtr->bFocus = TRUE;
7351 InvalidateRect(hwnd, NULL, TRUE);
7362 * [I] HWND : window handle
7363 * [I] HFONT : font handle
7364 * [I] WORD : redraw flag
7369 static LRESULT LISTVIEW_SetFont(HWND hwnd, HFONT hFont, WORD fRedraw)
7371 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7372 UINT uView = GetWindowLongA(hwnd, GWL_STYLE) & LVS_TYPEMASK;
7374 TRACE("(hwnd=%x,hfont=%x,redraw=%hu)\n", hwnd, hFont, fRedraw);
7378 infoPtr->hFont = infoPtr->hDefaultFont;
7382 infoPtr->hFont = hFont;
7385 if (uView == LVS_REPORT)
7387 /* set header font */
7388 SendMessageA(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont,
7389 MAKELPARAM(fRedraw, 0));
7392 /* invalidate listview control client area */
7393 InvalidateRect(hwnd, NULL, TRUE);
7395 if (fRedraw != FALSE)
7405 * Message handling for WM_SETREDRAW.
7406 * For the Listview, it invalidates the entire window (the doc specifies otherwise)
7409 * [I] HWND : window handle
7410 * [I] bRedraw: state of redraw flag
7413 * DefWinProc return value
7415 static LRESULT LISTVIEW_SetRedraw(HWND hwnd, BOOL bRedraw)
7418 lResult = DefWindowProcA(hwnd, WM_SETREDRAW, bRedraw, 0);
7421 RedrawWindow(hwnd, NULL, 0,
7422 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN | RDW_ERASENOW);
7429 * Resizes the listview control. This function processes WM_SIZE
7430 * messages. At this time, the width and height are not used.
7433 * [I] HWND : window handle
7434 * [I] WORD : new width
7435 * [I] WORD : new height
7440 static LRESULT LISTVIEW_Size(HWND hwnd, int Width, int Height)
7442 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7443 UINT uView = lStyle & LVS_TYPEMASK;
7445 TRACE("(hwnd=%x, width=%d, height=%d)\n",hwnd, Width, Height);
7447 LISTVIEW_UpdateSize(hwnd);
7449 if ((uView == LVS_SMALLICON) || (uView == LVS_ICON))
7451 if (lStyle & LVS_ALIGNLEFT)
7453 LISTVIEW_AlignLeft(hwnd);
7457 LISTVIEW_AlignTop(hwnd);
7461 LISTVIEW_UpdateScroll(hwnd);
7463 /* invalidate client area + erase background */
7464 InvalidateRect(hwnd, NULL, TRUE);
7471 * Sets the size information.
7474 * [I] HWND : window handle
7479 static VOID LISTVIEW_UpdateSize(HWND hwnd)
7481 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7482 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
7483 UINT uView = lStyle & LVS_TYPEMASK;
7486 GetClientRect(hwnd, &rcList);
7487 infoPtr->rcList.left = 0;
7488 infoPtr->rcList.right = max(rcList.right - rcList.left, 1);
7489 infoPtr->rcList.top = 0;
7490 infoPtr->rcList.bottom = max(rcList.bottom - rcList.top, 1);
7492 if (uView == LVS_LIST)
7494 if ((lStyle & WS_HSCROLL) == 0)
7496 INT nHScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
7497 if (infoPtr->rcList.bottom > nHScrollHeight)
7499 infoPtr->rcList.bottom -= nHScrollHeight;
7503 else if ((uView == LVS_REPORT)&&(!(LVS_NOCOLUMNHEADER & lStyle)))
7510 Header_Layout(infoPtr->hwndHeader, &hl);
7512 SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags);
7514 if (!(LVS_NOCOLUMNHEADER & lStyle))
7516 infoPtr->rcList.top = max(wp.cy, 0);
7523 * Processes WM_STYLECHANGED messages.
7526 * [I] HWND : window handle
7527 * [I] WPARAM : window style type (normal or extended)
7528 * [I] LPSTYLESTRUCT : window style information
7533 static INT LISTVIEW_StyleChanged(HWND hwnd, WPARAM wStyleType,
7536 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
7537 UINT uNewView = lpss->styleNew & LVS_TYPEMASK;
7538 UINT uOldView = lpss->styleOld & LVS_TYPEMASK;
7539 RECT rcList = infoPtr->rcList;
7541 TRACE("(hwnd=%x, styletype=%x, stylestruct=%p)\n",
7542 hwnd, wStyleType, lpss);
7544 if (wStyleType == GWL_STYLE)
7546 if (uOldView == LVS_REPORT)
7548 ShowWindow(infoPtr->hwndHeader, SW_HIDE);
7551 if ((lpss->styleOld & WS_HSCROLL) != 0)
7553 ShowScrollBar(hwnd, SB_HORZ, FALSE);
7556 if ((lpss->styleOld & WS_VSCROLL) != 0)
7558 ShowScrollBar(hwnd, SB_VERT, FALSE);
7561 if (uNewView == LVS_ICON)
7563 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXICON);
7564 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYICON);
7565 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7566 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7567 if (lpss->styleNew & LVS_ALIGNLEFT)
7569 LISTVIEW_AlignLeft(hwnd);
7573 LISTVIEW_AlignTop(hwnd);
7576 else if (uNewView == LVS_REPORT)
7581 if (!(LVS_NOCOLUMNHEADER & lpss->styleNew))
7585 Header_Layout(infoPtr->hwndHeader, &hl);
7586 SetWindowPos(infoPtr->hwndHeader, hwnd, wp.x, wp.y, wp.cx, wp.cy,
7588 ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL);
7593 ZeroMemory(&zeroRect,sizeof(RECT));
7597 Header_Layout(infoPtr->hwndHeader, &hl);
7600 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7601 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7602 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7603 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7605 else if (uNewView == LVS_LIST)
7607 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7608 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7609 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7610 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7614 infoPtr->iconSize.cx = GetSystemMetrics(SM_CXSMICON);
7615 infoPtr->iconSize.cy = GetSystemMetrics(SM_CYSMICON);
7616 infoPtr->nItemWidth = LISTVIEW_GetItemWidth(hwnd);
7617 infoPtr->nItemHeight = LISTVIEW_GetItemHeight(hwnd);
7618 if (lpss->styleNew & LVS_ALIGNLEFT)
7620 LISTVIEW_AlignLeft(hwnd);
7624 LISTVIEW_AlignTop(hwnd);
7628 /* update the size of the client area */
7629 LISTVIEW_UpdateSize(hwnd);
7631 /* add scrollbars if needed */
7632 LISTVIEW_UpdateScroll(hwnd);
7634 /* invalidate client area + erase background */
7635 InvalidateRect(hwnd, NULL, TRUE);
7637 /* print the list of unsupported window styles */
7638 LISTVIEW_UnsupportedStyles(lpss->styleNew);
7641 /* If they change the view and we have an active edit control
7642 we will need to kill the control since the redraw will
7643 misplace the edit control.
7645 if (infoPtr->hwndEdit &&
7646 ((uNewView & (LVS_ICON|LVS_LIST|LVS_SMALLICON)) !=
7647 ((LVS_ICON|LVS_LIST|LVS_SMALLICON) & uOldView)))
7649 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
7657 * Window procedure of the listview control.
7660 static LRESULT WINAPI LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
7663 TRACE("hwnd=%x uMsg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
7664 if (!GetWindowLongA(hwnd, 0) && (uMsg != WM_NCCREATE))
7665 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
7668 case LVM_APPROXIMATEVIEWRECT:
7669 return LISTVIEW_ApproximateViewRect(hwnd, (INT)wParam,
7670 LOWORD(lParam), HIWORD(lParam));
7672 return LISTVIEW_Arrange(hwnd, (INT)wParam);
7674 /* case LVM_CREATEDRAGIMAGE: */
7676 case LVM_DELETEALLITEMS:
7677 return LISTVIEW_DeleteAllItems(hwnd);
7679 case LVM_DELETECOLUMN:
7680 return LISTVIEW_DeleteColumn(hwnd, (INT)wParam);
7682 case LVM_DELETEITEM:
7683 return LISTVIEW_DeleteItem(hwnd, (INT)wParam);
7685 case LVM_EDITLABELW:
7686 case LVM_EDITLABELA:
7687 return LISTVIEW_EditLabelA(hwnd, (INT)wParam);
7689 case LVM_ENSUREVISIBLE:
7690 return LISTVIEW_EnsureVisible(hwnd, (INT)wParam, (BOOL)lParam);
7693 return LISTVIEW_FindItem(hwnd, (INT)wParam, (LPLVFINDINFO)lParam);
7695 case LVM_GETBKCOLOR:
7696 return LISTVIEW_GetBkColor(hwnd);
7698 /* case LVM_GETBKIMAGE: */
7700 case LVM_GETCALLBACKMASK:
7701 return LISTVIEW_GetCallbackMask(hwnd);
7703 case LVM_GETCOLUMNA:
7704 return LISTVIEW_GetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7706 /* case LVM_GETCOLUMNW: */
7708 case LVM_GETCOLUMNORDERARRAY:
7709 return LISTVIEW_GetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7711 case LVM_GETCOLUMNWIDTH:
7712 return LISTVIEW_GetColumnWidth(hwnd, (INT)wParam);
7714 case LVM_GETCOUNTPERPAGE:
7715 return LISTVIEW_GetCountPerPage(hwnd);
7717 case LVM_GETEDITCONTROL:
7718 return LISTVIEW_GetEditControl(hwnd);
7720 case LVM_GETEXTENDEDLISTVIEWSTYLE:
7721 return LISTVIEW_GetExtendedListViewStyle(hwnd);
7724 return LISTVIEW_GetHeader(hwnd);
7726 /* case LVM_GETHOTCURSOR: */
7728 case LVM_GETHOTITEM:
7729 return LISTVIEW_GetHotItem(hwnd);
7731 case LVM_GETHOVERTIME:
7732 return LISTVIEW_GetHoverTime(hwnd);
7734 case LVM_GETIMAGELIST:
7735 return LISTVIEW_GetImageList(hwnd, (INT)wParam);
7737 /* case LVM_GETISEARCHSTRING: */
7740 return LISTVIEW_GetItemA(hwnd, (LPLVITEMA)lParam, FALSE);
7742 /* case LVM_GETITEMW: */
7744 case LVM_GETITEMCOUNT:
7745 return LISTVIEW_GetItemCount(hwnd);
7747 case LVM_GETITEMPOSITION:
7748 return LISTVIEW_GetItemPosition(hwnd, (INT)wParam, (LPPOINT)lParam);
7750 case LVM_GETITEMRECT:
7751 return LISTVIEW_GetItemRect(hwnd, (INT)wParam, (LPRECT)lParam);
7753 case LVM_GETITEMSPACING:
7754 return LISTVIEW_GetItemSpacing(hwnd, (BOOL)wParam);
7756 case LVM_GETITEMSTATE:
7757 return LISTVIEW_GetItemState(hwnd, (INT)wParam, (UINT)lParam);
7759 case LVM_GETITEMTEXTA:
7760 LISTVIEW_GetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7763 /* case LVM_GETITEMTEXTW: */
7765 case LVM_GETNEXTITEM:
7766 return LISTVIEW_GetNextItem(hwnd, (INT)wParam, LOWORD(lParam));
7768 /* case LVM_GETNUMBEROFWORKAREAS: */
7771 return LISTVIEW_GetOrigin(hwnd, (LPPOINT)lParam);
7773 case LVM_GETSELECTEDCOUNT:
7774 return LISTVIEW_GetSelectedCount(hwnd);
7776 case LVM_GETSELECTIONMARK:
7777 return LISTVIEW_GetSelectionMark(hwnd);
7779 case LVM_GETSTRINGWIDTHA:
7780 return LISTVIEW_GetStringWidthA (hwnd, (LPCSTR)lParam);
7782 /* case LVM_GETSTRINGWIDTHW: */
7783 /* case LVM_GETSUBITEMRECT: */
7785 case LVM_GETTEXTBKCOLOR:
7786 return LISTVIEW_GetTextBkColor(hwnd);
7788 case LVM_GETTEXTCOLOR:
7789 return LISTVIEW_GetTextColor(hwnd);
7791 /* case LVM_GETTOOLTIPS: */
7793 case LVM_GETTOPINDEX:
7794 return LISTVIEW_GetTopIndex(hwnd);
7796 /* case LVM_GETUNICODEFORMAT: */
7798 case LVM_GETVIEWRECT:
7799 return LISTVIEW_GetViewRect(hwnd, (LPRECT)lParam);
7801 /* case LVM_GETWORKAREAS: */
7804 return LISTVIEW_HitTest(hwnd, (LPLVHITTESTINFO)lParam);
7806 case LVM_INSERTCOLUMNA:
7807 return LISTVIEW_InsertColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7809 case LVM_INSERTCOLUMNW:
7810 return LISTVIEW_InsertColumnW(hwnd, (INT)wParam, (LPLVCOLUMNW)lParam);
7812 case LVM_INSERTITEMA:
7813 return LISTVIEW_InsertItemA(hwnd, (LPLVITEMA)lParam);
7815 case LVM_INSERTITEMW:
7816 return LISTVIEW_InsertItemW(hwnd, (LPLVITEMW)lParam);
7818 case LVM_REDRAWITEMS:
7819 return LISTVIEW_RedrawItems(hwnd, (INT)wParam, (INT)lParam);
7821 /* case LVM_SCROLL: */
7822 /* return LISTVIEW_Scroll(hwnd, (INT)wParam, (INT)lParam); */
7824 case LVM_SETBKCOLOR:
7825 return LISTVIEW_SetBkColor(hwnd, (COLORREF)lParam);
7827 /* case LVM_SETBKIMAGE: */
7829 case LVM_SETCALLBACKMASK:
7830 return LISTVIEW_SetCallbackMask(hwnd, (UINT)wParam);
7832 case LVM_SETCOLUMNA:
7833 return LISTVIEW_SetColumnA(hwnd, (INT)wParam, (LPLVCOLUMNA)lParam);
7835 case LVM_SETCOLUMNW:
7836 FIXME("Unimplemented msg LVM_SETCOLUMNW\n");
7839 case LVM_SETCOLUMNORDERARRAY:
7840 return LISTVIEW_SetColumnOrderArray(hwnd, (INT)wParam, (LPINT)lParam);
7842 case LVM_SETCOLUMNWIDTH:
7843 return LISTVIEW_SetColumnWidth(hwnd, (INT)wParam, SLOWORD(lParam));
7845 case LVM_SETEXTENDEDLISTVIEWSTYLE:
7846 return LISTVIEW_SetExtendedListViewStyle(hwnd, (DWORD)wParam, (DWORD)lParam);
7848 /* case LVM_SETHOTCURSOR: */
7850 case LVM_SETHOTITEM:
7851 return LISTVIEW_SetHotItem(hwnd, (INT)wParam);
7853 case LVM_SETHOVERTIME:
7854 return LISTVIEW_SetHoverTime(hwnd, (DWORD)wParam);
7856 /* case LVM_SETICONSPACING: */
7858 case LVM_SETIMAGELIST:
7859 return LISTVIEW_SetImageList(hwnd, (INT)wParam, (HIMAGELIST)lParam);
7862 return LISTVIEW_SetItemA(hwnd, (LPLVITEMA)lParam);
7864 /* case LVM_SETITEMW: */
7866 case LVM_SETITEMCOUNT:
7867 return LISTVIEW_SetItemCount(hwnd, (INT)wParam, (DWORD)lParam);
7869 case LVM_SETITEMPOSITION:
7870 return LISTVIEW_SetItemPosition(hwnd, (INT)wParam, (INT)LOWORD(lParam),
7871 (INT)HIWORD(lParam));
7873 /* case LVM_SETITEMPOSITION32: */
7875 case LVM_SETITEMSTATE:
7876 return LISTVIEW_SetItemState(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7878 case LVM_SETITEMTEXTA:
7879 return LISTVIEW_SetItemTextA(hwnd, (INT)wParam, (LPLVITEMA)lParam);
7881 /* case LVM_SETITEMTEXTW: */
7883 case LVM_SETSELECTIONMARK:
7884 return LISTVIEW_SetSelectionMark(hwnd, (INT)lParam);
7886 case LVM_SETTEXTBKCOLOR:
7887 return LISTVIEW_SetTextBkColor(hwnd, (COLORREF)lParam);
7889 case LVM_SETTEXTCOLOR:
7890 return LISTVIEW_SetTextColor(hwnd, (COLORREF)lParam);
7892 /* case LVM_SETTOOLTIPS: */
7893 /* case LVM_SETUNICODEFORMAT: */
7894 /* case LVM_SETWORKAREAS: */
7897 return LISTVIEW_SortItems(hwnd, wParam, lParam);
7899 /* case LVM_SUBITEMHITTEST: */
7902 return LISTVIEW_Update(hwnd, (INT)wParam);
7906 return LISTVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
7909 return LISTVIEW_Command(hwnd, wParam, lParam);
7912 return LISTVIEW_Create(hwnd, wParam, lParam);
7915 return LISTVIEW_EraseBackground(hwnd, wParam, lParam);
7918 return DLGC_WANTCHARS | DLGC_WANTARROWS;
7921 return LISTVIEW_GetFont(hwnd);
7924 return LISTVIEW_HScroll(hwnd, (INT)LOWORD(wParam),
7925 (INT)HIWORD(wParam), (HWND)lParam);
7928 return LISTVIEW_KeyDown(hwnd, (INT)wParam, (LONG)lParam);
7931 return LISTVIEW_KillFocus(hwnd);
7933 case WM_LBUTTONDBLCLK:
7934 return LISTVIEW_LButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7937 case WM_LBUTTONDOWN:
7938 return LISTVIEW_LButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7941 return LISTVIEW_LButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7944 return LISTVIEW_MouseMove (hwnd, wParam, lParam);
7947 return LISTVIEW_MouseHover(hwnd, wParam, lParam);
7950 return LISTVIEW_NCCreate(hwnd, wParam, lParam);
7953 return LISTVIEW_NCDestroy(hwnd);
7956 return LISTVIEW_Notify(hwnd, (INT)wParam, (LPNMHDR)lParam);
7958 case WM_NOTIFYFORMAT:
7959 return LISTVIEW_NotifyFormat(hwnd, (HWND)wParam, (INT)lParam);
7962 return LISTVIEW_Paint(hwnd, (HDC)wParam);
7964 case WM_RBUTTONDBLCLK:
7965 return LISTVIEW_RButtonDblClk(hwnd, (WORD)wParam, LOWORD(lParam),
7968 case WM_RBUTTONDOWN:
7969 return LISTVIEW_RButtonDown(hwnd, (WORD)wParam, LOWORD(lParam),
7973 return LISTVIEW_RButtonUp(hwnd, (WORD)wParam, LOWORD(lParam),
7977 return LISTVIEW_SetFocus(hwnd, (HWND)wParam);
7980 return LISTVIEW_SetFont(hwnd, (HFONT)wParam, (WORD)lParam);
7983 return LISTVIEW_SetRedraw(hwnd, (BOOL)wParam);
7986 return LISTVIEW_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
7988 case WM_STYLECHANGED:
7989 return LISTVIEW_StyleChanged(hwnd, wParam, (LPSTYLESTRUCT)lParam);
7991 /* case WM_TIMER: */
7994 return LISTVIEW_VScroll(hwnd, (INT)LOWORD(wParam),
7995 (INT)HIWORD(wParam), (HWND)lParam);
7998 if (wParam & (MK_SHIFT | MK_CONTROL))
7999 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
8000 return LISTVIEW_MouseWheel(hwnd, (short int)HIWORD(wParam));/* case WM_WINDOWPOSCHANGED: */
8002 /* case WM_WININICHANGE: */
8005 if (uMsg >= WM_USER)
8007 ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam,
8011 /* call default window procedure */
8012 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
8020 * Registers the window class.
8028 VOID LISTVIEW_Register(void)
8032 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
8033 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
8034 wndClass.lpfnWndProc = (WNDPROC)LISTVIEW_WindowProc;
8035 wndClass.cbClsExtra = 0;
8036 wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *);
8037 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
8038 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
8039 wndClass.lpszClassName = WC_LISTVIEWA;
8040 RegisterClassA(&wndClass);
8045 * Unregisters the window class.
8053 VOID LISTVIEW_Unregister(void)
8055 UnregisterClassA(WC_LISTVIEWA, (HINSTANCE)NULL);
8060 * Handle any WM_COMMAND messages
8066 static LRESULT LISTVIEW_Command(HWND hwnd, WPARAM wParam, LPARAM lParam)
8068 switch (HIWORD(wParam))
8073 * Adjust the edit window size
8076 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(hwnd, 0);
8077 HDC hdc = GetDC(infoPtr->hwndEdit);
8078 HFONT hFont, hOldFont = 0;
8083 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1023);
8084 GetWindowRect(infoPtr->hwndEdit, &rect);
8086 /* Select font to get the right dimension of the string */
8087 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
8090 hOldFont = SelectObject(hdc, hFont);
8093 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz))
8095 TEXTMETRICA textMetric;
8097 /* Add Extra spacing for the next character */
8098 GetTextMetricsA(hdc, &textMetric);
8099 sz.cx += (textMetric.tmMaxCharWidth * 2);
8107 rect.bottom - rect.top,
8108 SWP_DRAWFRAME|SWP_NOMOVE);
8112 SelectObject(hdc, hOldFont);
8115 ReleaseDC(hwnd, hdc);
8121 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam);
8130 * Subclassed edit control windproc function
8136 LRESULT CALLBACK EditLblWndProc(HWND hwnd, UINT uMsg,
8137 WPARAM wParam, LPARAM lParam)
8139 BOOL cancel = FALSE;
8140 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(GetParent(hwnd), 0);
8141 EDITLABEL_ITEM *einfo = infoPtr->pedititem;
8142 static BOOL bIgnoreKillFocus = FALSE;
8146 return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
8149 if(bIgnoreKillFocus)
8157 WNDPROC editProc = einfo->EditWndProc;
8158 SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)editProc);
8159 COMCTL32_Free(einfo);
8160 infoPtr->pedititem = NULL;
8161 return CallWindowProcA(editProc, hwnd, uMsg, wParam, lParam);
8165 if (VK_ESCAPE == (INT)wParam)
8171 else if (VK_RETURN == (INT)wParam)
8175 return CallWindowProcA(einfo->EditWndProc, hwnd,
8176 uMsg, wParam, lParam);
8179 if (einfo->EditLblCb)
8181 char *buffer = NULL;
8186 int len = 1 + GetWindowTextLengthA(hwnd);
8190 if (NULL != (buffer = (char *)COMCTL32_Alloc(len*sizeof(char))))
8192 GetWindowTextA(hwnd, buffer, len);
8196 /* Processing LVN_ENDLABELEDIT message could kill the focus */
8197 /* eg. Using a messagebox */
8198 bIgnoreKillFocus = TRUE;
8199 einfo->EditLblCb(GetParent(hwnd), buffer, einfo->param);
8202 COMCTL32_Free(buffer);
8204 einfo->EditLblCb = NULL;
8205 bIgnoreKillFocus = FALSE;
8208 SendMessageA(hwnd, WM_CLOSE, 0, 0);
8215 * Creates a subclassed edit cotrol
8221 HWND CreateEditLabel(LPCSTR text, DWORD style, INT x, INT y,
8222 INT width, INT height, HWND parent, HINSTANCE hinst,
8223 EditlblCallback EditLblCb, DWORD param)
8229 TEXTMETRICA textMetric;
8230 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongA(parent, 0);
8232 if (NULL == (infoPtr->pedititem = COMCTL32_Alloc(sizeof(EDITLABEL_ITEM))))
8235 style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|WS_BORDER;
8236 hdc = GetDC(parent);
8238 /* Select the font to get appropriate metric dimensions */
8239 if(infoPtr->hFont != 0)
8241 hOldFont = SelectObject(hdc, infoPtr->hFont);
8244 /*Get String Lenght in pixels */
8245 GetTextExtentPoint32A(hdc, text, strlen(text), &sz);
8247 /*Add Extra spacing for the next character */
8248 GetTextMetricsA(hdc, &textMetric);
8249 sz.cx += (textMetric.tmMaxCharWidth * 2);
8251 if(infoPtr->hFont != 0)
8253 SelectObject(hdc, hOldFont);
8256 ReleaseDC(parent, hdc);
8257 if (!(hedit = CreateWindowA("Edit", text, style, x, y, sz.cx, height,
8258 parent, 0, hinst, 0)))
8260 COMCTL32_Free(infoPtr->pedititem);
8264 infoPtr->pedititem->param = param;
8265 infoPtr->pedititem->EditLblCb = EditLblCb;
8266 infoPtr->pedititem->EditWndProc = (WNDPROC)SetWindowLongA(hedit,
8267 GWL_WNDPROC, (LONG) EditLblWndProc);
8269 SendMessageA(hedit, WM_SETFONT, infoPtr->hFont, FALSE);